aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmldesigner')
-rw-r--r--src/plugins/qmldesigner/.clang-format2
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt42
-rw-r--r--src/plugins/qmldesigner/QmlDesigner.json.in2
-rw-r--r--src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp2
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp3
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h3
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp82
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h27
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp61
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h5
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp1
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.cpp87
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.h34
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp1011
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h152
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp621
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h102
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp157
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.h57
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h19
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp340
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h46
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp521
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h79
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp469
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionview.h120
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp296
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h71
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp511
-rw-r--r--src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h63
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractaction.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractaction.h5
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp10
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractactiongroup.h5
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore_constants.h3
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp30
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/dialogutils.cpp32
-rw-r--r--src/plugins/qmldesigner/components/componentcore/dialogutils.h17
-rw-r--r--src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h49
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp123
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h1
-rw-r--r--src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.cpp7
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h1
-rw-r--r--src/plugins/qmldesigner/components/componentcore/viewmanager.cpp41
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp28
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h3
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectioneditorutils.cpp3
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp31
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h3
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp161
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h38
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.cpp78
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.cpp10
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.h12
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.cpp156
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.h35
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.cpp76
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.h (renamed from src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.h)18
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp7
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h14
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp192
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h47
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp54
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h28
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp10
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h2
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp34
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h4
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp686
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h135
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp646
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h35
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp282
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h53
-rw-r--r--src/plugins/qmldesigner/components/createtexture.cpp3
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp2
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.cpp10
-rw-r--r--src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.h1
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp48
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h3
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp220
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h15
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp72
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.h1
-rw-r--r--src/plugins/qmldesigner/components/edit3d/snapconfiguration.cpp10
-rw-r--r--src/plugins/qmldesigner/components/edit3d/snapconfiguration.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp23
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp12
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp9
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp22
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditortoolbutton.cpp2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp4
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.cpp32
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.h14
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocumentview.cpp10
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp82
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h37
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp47
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h28
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp330
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h33
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui76
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp117
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h36
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp82
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp16
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h11
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp11
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h5
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp2
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp5
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp20
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h5
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp4
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp19
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.h11
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp101
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp6
-rw-r--r--src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp5
-rw-r--r--src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp6
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp8
-rw-r--r--src/plugins/qmldesigner/components/navigator/previewtooltip.cpp3
-rw-r--r--src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp3
-rw-r--r--src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp13
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp8
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp58
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h31
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp326
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h45
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp208
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h10
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp236
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h35
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp3
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorview.cpp3
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/texttool/textedititemwidget.cpp24
-rw-r--r--src/plugins/qmldesigner/components/texttool/textedititemwidget.h7
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp4
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp38
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h15
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp9
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineanimationform.cpp10
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp8
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp7
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinesettingsmodel.cpp2
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp7
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp23
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.h4
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp7
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp4
-rw-r--r--src/plugins/qmldesigner/componentsplugin/components.metainfo6
-rw-r--r--src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp291
-rw-r--r--src/plugins/qmldesigner/designercore/generatedcomponentutils.h55
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h2
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/taskqueue.h41
-rw-r--r--src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/itemlibraryentry.h13
-rw-r--r--src/plugins/qmldesigner/designercore/include/model.h19
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelfwd.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodehints.h9
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodemetainfo.h17
-rw-r--r--src/plugins/qmldesigner/designercore/include/projectstorageids.h8
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlitemnode.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h13
-rw-r--r--src/plugins/qmldesigner/designercore/include/subcomponentmanager.h2
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp92
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp23
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp35
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp1491
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp17
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/model/bindingproperty.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/model.cpp156
-rw-r--r--src/plugins/qmldesigner/designercore/model/model_p.h2
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelutils.cpp18
-rw-r--r--src/plugins/qmldesigner/designercore/model/propertycontainer.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/propertyparser.cpp7
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp8
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp27
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriterview.cpp117
-rw-r--r--src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp16
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp310
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.h6
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h248
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/filestatus.h12
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp13
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/filesystem.h7
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h1
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp4892
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h3817
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp17
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h25
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h27
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp120
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h33
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h1
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h221
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h28
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h43
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h474
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp758
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h63
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp49
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp115
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h9
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h11
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/storagecache.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp30
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h4
-rw-r--r--src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp63
-rw-r--r--src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h34
-rw-r--r--src/plugins/qmldesigner/designercore/uniquename.cpp165
-rw-r--r--src/plugins/qmldesigner/designercore/uniquename.h17
-rw-r--r--src/plugins/qmldesigner/designmodecontext.cpp12
-rw-r--r--src/plugins/qmldesigner/designmodecontext.h9
-rw-r--r--src/plugins/qmldesigner/designmodewidget.h1
-rw-r--r--src/plugins/qmldesigner/documentmanager.cpp18
-rw-r--r--src/plugins/qmldesigner/documentmanager.h6
-rw-r--r--src/plugins/qmldesigner/documentwarningwidget.cpp9
-rw-r--r--src/plugins/qmldesigner/puppetenvironmentbuilder.cpp2
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h26
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp5
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.h1
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp18
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.cpp175
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.h5
-rw-r--r--src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp2
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/frame-animation-16px.pngbin0 -> 319 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px.pngbin0 -> 403 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px@2x.pngbin0 -> 496 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc3
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/quick.metainfo22
-rw-r--r--src/plugins/qmldesigner/settingspage.cpp7
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.cpp9
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.h1
-rw-r--r--src/plugins/qmldesigner/utils/asset.cpp26
-rw-r--r--src/plugins/qmldesigner/utils/asset.h6
-rw-r--r--src/plugins/qmldesigner/utils/imageutils.cpp12
-rw-r--r--src/plugins/qmldesigner/utils/imageutils.h5
265 files changed, 14271 insertions, 11267 deletions
diff --git a/src/plugins/qmldesigner/.clang-format b/src/plugins/qmldesigner/.clang-format
index d3695ac298..366f82f76f 100644
--- a/src/plugins/qmldesigner/.clang-format
+++ b/src/plugins/qmldesigner/.clang-format
@@ -2,6 +2,7 @@ Language: Cpp
AccessModifierOffset: -4
AlignEscapedNewlines: DontAlign
AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakTemplateDeclarations: true # use with clang 19
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
@@ -15,6 +16,7 @@ BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: AfterComma
+# BreakTemplateDeclarations: Yes # use with clang 19
ColumnLimit: 100
IncludeCategories:
- Regex: 'Q.*'
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index b5b64bebbc..c29017523d 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -8,7 +8,6 @@ if (APPLE)
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
endif()
-add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>")
set(BUILD_NOT_DESIGNSTUDIO NOT ${BUILD_NOT_DESIGNSTUDIO})
option(QTC_USE_QML_DESIGNER_LITE "Use Qml Designer Lite" ${BUILD_NOT_DESIGNSTUDIO})
@@ -28,6 +27,10 @@ env_with_default("QTC_ENABLE_MODEL_TRACING" ENV_QTC_ENABLE_MODEL_TRACING OFF)
option(ENABLE_MODEL_TRACING "Enable model tracing" ${ENV_QTC_ENABLE_MODEL_TRACING})
add_feature_info("Model tracing" ${ENABLE_MODEL_TRACING} "")
+env_with_default("QTC_ENABLE_METAINFO_TRACING" ENV_QTC_ENABLE_METAINFO_TRACING OFF)
+option(ENABLE_METAINFO_TRACING "Enable meta info tracing" ${ENV_QTC_ENABLE_METAINFO_TRACING})
+add_feature_info("Meta info tracing" ${ENABLE_METAINFO_TRACING} "")
+
add_qtc_library(QmlDesignerUtils STATIC
DEPENDS
Qt::Gui Utils Qt::QmlPrivate
@@ -46,6 +49,11 @@ add_qtc_library(QmlDesignerUtils STATIC
qmldesignerutils_global.h
)
+if (TARGET QmlDesignerUtils)
+ target_compile_options(QmlDesignerUtils PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,Clang,GNU>:-Wno-error=maybe-uninitialized>)
+ target_compile_options(QmlDesignerUtils PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,Clang>:-Wno-unneeded-internal-declaration>)
+endif()
+
extend_qtc_library(QmlDesignerUtils
CONDITION ENABLE_COMPILE_WARNING_AS_ERROR
PROPERTIES COMPILE_WARNING_AS_ERROR ON
@@ -89,12 +97,13 @@ add_qtc_library(QmlDesignerCore STATIC
${CMAKE_CURRENT_LIST_DIR}/designercore/include
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore
SOURCES
- rewritertransaction.cpp
- rewritertransaction.h
+ rewritertransaction.cpp rewritertransaction.h
+ generatedcomponentutils.cpp generatedcomponentutils.h
+ uniquename.cpp uniquename.h
)
extend_qtc_library(QmlDesignerCore
- CONDITION ENABLE_PROJECT_STORAGE_TRACING OR ENABLE_IMAGE_CACHE_TRACING OR ENABLE_MODEL_TRACING
+ CONDITION ENABLE_PROJECT_STORAGE_TRACING OR ENABLE_IMAGE_CACHE_TRACING OR ENABLE_MODEL_TRACING OR ENABLE_METAINFO_TRACING
PUBLIC_DEPENDS Nanotrace
PUBLIC_DEFINES
ENABLE_QMLDESIGNER_TRACING
@@ -102,6 +111,7 @@ extend_qtc_library(QmlDesignerCore
$<$<BOOL:${ENABLE_PROJECT_STORAGE_TRACING}>:ENABLE_PROJECT_STORAGE_TRACING>
$<$<BOOL:${ENABLE_IMAGE_CACHE_TRACING}>:ENABLE_IMAGE_CACHE_TRACING>
$<$<BOOL:${ENABLE_MODEL_TRACING}>:ENABLE_MODEL_TRACING>
+ $<$<BOOL:${ENABLE_METAINFO_TRACING}>:ENABLE_METAINFO_TRACING>
)
extend_qtc_library(QmlDesignerCore
@@ -457,6 +467,8 @@ extend_qtc_library(QmlDesignerCore
projectstoragetypes.h
projectstorageupdater.cpp projectstorageupdater.h
projectstorage.cpp projectstorage.h
+ projectstorageerrornotifierinterface.h
+ projectstorageerrornotifier.cpp projectstorageerrornotifier.h
sourcepath.h
sourcepathcache.h
sourcepathcacheinterface.h
@@ -492,7 +504,6 @@ add_qtc_plugin(QmlDesigner
INCLUDES
${CMAKE_CURRENT_LIST_DIR}/components
${CMAKE_CURRENT_LIST_DIR}/components/assetslibrary
- ${CMAKE_CURRENT_LIST_DIR}/components/collectioneditor
${CMAKE_CURRENT_LIST_DIR}/components/debugview
${CMAKE_CURRENT_LIST_DIR}/components/edit3d
${CMAKE_CURRENT_LIST_DIR}/components/formeditor
@@ -631,6 +642,7 @@ extend_qtc_plugin(QmlDesigner
svgpasteaction.cpp svgpasteaction.h
viewmanager.cpp viewmanager.h
utils3d.cpp utils3d.h
+ dialogutils.cpp dialogutils.h
)
extend_qtc_plugin(QmlDesigner
@@ -732,6 +744,8 @@ extend_qtc_plugin(QmlDesigner
assetimportupdatetreeitemdelegate.cpp assetimportupdatetreeitemdelegate.h
assetimportupdatetreemodel.cpp assetimportupdatetreemodel.h
assetimportupdatetreeview.cpp assetimportupdatetreeview.h
+ import3dcanvas.cpp import3dcanvas.h
+ import3dconnectionmanager.cpp import3dconnectionmanager.h
itemlibrary.qrc
itemlibraryconstants.h
itemlibraryimageprovider.cpp itemlibraryimageprovider.h
@@ -819,9 +833,10 @@ extend_qtc_plugin(QmlDesigner
contentlibrarymaterialscategory.cpp contentlibrarymaterialscategory.h
contentlibrarymaterial.cpp contentlibrarymaterial.h
contentlibraryiconprovider.cpp contentlibraryiconprovider.h
- contentlibraryeffect.cpp contentlibraryeffect.h
+ contentlibraryitem.cpp contentlibraryitem.h
contentlibraryeffectscategory.cpp contentlibraryeffectscategory.h
contentlibraryeffectsmodel.cpp contentlibraryeffectsmodel.h
+ contentlibraryusermodel.cpp contentlibraryusermodel.h
)
extend_qtc_plugin(QmlDesigner
@@ -836,21 +851,6 @@ extend_qtc_plugin(QmlDesigner
)
extend_qtc_plugin(QmlDesigner
- SOURCES_PREFIX components/collectioneditor
- SOURCES
- collectiondatatypemodel.cpp collectiondatatypemodel.h
- collectiondetails.cpp collectiondetails.h
- collectiondetailsmodel.cpp collectiondetailsmodel.h
- collectiondetailssortfiltermodel.cpp collectiondetailssortfiltermodel.h
- collectioneditorconstants.h
- collectioneditorutils.cpp collectioneditorutils.h
- collectionlistmodel.cpp collectionlistmodel.h
- collectionview.cpp collectionview.h
- collectionwidget.cpp collectionwidget.h
- datastoremodelnode.cpp datastoremodelnode.h
-)
-
-extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/textureeditor
SOURCES
textureeditorcontextobject.cpp textureeditorcontextobject.h
diff --git a/src/plugins/qmldesigner/QmlDesigner.json.in b/src/plugins/qmldesigner/QmlDesigner.json.in
index 4b5682f485..e96f2f8513 100644
--- a/src/plugins/qmldesigner/QmlDesigner.json.in
+++ b/src/plugins/qmldesigner/QmlDesigner.json.in
@@ -15,7 +15,7 @@
"Category" : "Qt Quick",
"Description" : "Visual Designer for QML files.",
"Deprecated" : true,
- "Url" : "http://www.qt.io",
+ "Url" : "https://www.qt.io",
"Arguments" : [
{
"Name" : "-capture-puppet-stream",
diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp
index a4509c38a6..cee25240cf 100644
--- a/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp
+++ b/src/plugins/qmldesigner/assetexporterplugin/assetexportdialog.cpp
@@ -143,7 +143,7 @@ AssetExportDialog::AssetExportDialog(const FilePath &exportPath,
m_exportAssetsCheck,
m_perComponentExportCheck,
st,
- noMargin(),
+ noMargin,
}.attachTo(optionsWidget);
Column {
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
index dc5a1c9741..b821cc6595 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
@@ -2,9 +2,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "assetslibraryiconprovider.h"
-#include "asset.h"
-#include "modelnodeoperations.h"
+#include <modelnodeoperations.h>
#include <theme.h>
#include <utils/hdrimage.h>
#include <utils/ktximage.h>
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
index fb38605ea6..d52779232f 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
@@ -3,12 +3,11 @@
#pragma once
+#include <asset.h>
#include <synchronousimagecache.h>
#include <QQuickImageProvider>
-#include "asset.h"
-
namespace QmlDesigner {
struct Thumbnail
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
index c2359409eb..7f488bd615 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
@@ -1,21 +1,22 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include <QCheckBox>
-#include <QFileInfo>
-#include <QFileSystemModel>
-#include <QMessageBox>
-#include <QSortFilterProxyModel>
-
-#include "asset.h"
#include "assetslibrarymodel.h"
#include <modelnodeoperations.h>
#include <qmldesignerplugin.h>
+#include <uniquename.h>
#include <coreplugin/icore.h>
+
#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
+#include <utils/asset.h>
+#include <utils/filepath.h>
+#include <utils/filesystemwatcher.h>
+
+#include <QFileInfo>
+#include <QFileSystemModel>
+#include <QMessageBox>
namespace QmlDesigner {
@@ -38,7 +39,7 @@ void AssetsLibraryModel::createBackendModel()
QObject::connect(m_sourceFsModel, &QFileSystemModel::directoryLoaded, this,
[this]([[maybe_unused]] const QString &dir) {
- syncHaveFiles();
+ syncHasFiles();
});
m_fileWatcher = new Utils::FileSystemWatcher(parent());
@@ -153,16 +154,15 @@ bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &
QString AssetsLibraryModel::addNewFolder(const QString &folderPath)
{
- QString iterPath = folderPath;
- QDir dir{folderPath};
-
- while (dir.exists()) {
- iterPath = getUniqueName(iterPath);
+ Utils::FilePath uniqueDirPath = Utils::FilePath::fromString(UniqueName::generatePath(folderPath));
- dir.setPath(iterPath);
+ auto res = uniqueDirPath.ensureWritableDir();
+ if (!res.has_value()) {
+ qWarning() << __FUNCTION__ << res.error();
+ return {};
}
- return dir.mkpath(iterPath) ? iterPath : "";
+ return uniqueDirPath.path();
}
bool AssetsLibraryModel::urlPathExistsInModel(const QUrl &url) const
@@ -207,7 +207,7 @@ bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
}
}
-bool AssetsLibraryModel::checkHaveFiles(const QModelIndex &parentIdx) const
+bool AssetsLibraryModel::checkHasFiles(const QModelIndex &parentIdx) const
{
if (!parentIdx.isValid())
return false;
@@ -218,60 +218,30 @@ bool AssetsLibraryModel::checkHaveFiles(const QModelIndex &parentIdx) const
if (!isDirectory(newIdx))
return true;
- if (checkHaveFiles(newIdx))
+ if (checkHasFiles(newIdx))
return true;
}
return false;
}
-void AssetsLibraryModel::setHaveFiles(bool value)
+void AssetsLibraryModel::setHasFiles(bool value)
{
- if (m_haveFiles != value) {
- m_haveFiles = value;
- emit haveFilesChanged();
+ if (m_hasFiles != value) {
+ m_hasFiles = value;
+ emit hasFilesChanged();
}
}
-bool AssetsLibraryModel::checkHaveFiles() const
+bool AssetsLibraryModel::checkHasFiles() const
{
auto rootIdx = indexForPath(m_rootPath);
- return checkHaveFiles(rootIdx);
+ return checkHasFiles(rootIdx);
}
-void AssetsLibraryModel::syncHaveFiles()
+void AssetsLibraryModel::syncHasFiles()
{
- setHaveFiles(checkHaveFiles());
-}
-
-QString AssetsLibraryModel::getUniqueName(const QString &oldName) {
- static QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
-
- QString uniqueName = oldName;
- // if the folder name ends with a number, increment it
- QRegularExpressionMatch match = rgx.match(uniqueName);
- if (match.hasMatch()) { // ends with a number
- QString numStr = match.captured(0);
- int num = match.captured(0).toInt();
-
- // get number of padding zeros, ex: for "005" = 2
- int nPaddingZeros = 0;
- for (; nPaddingZeros < numStr.size() && numStr[nPaddingZeros] == '0'; ++nPaddingZeros);
-
- ++num;
-
- // if the incremented number's digits increased, decrease the padding zeros
- if (std::fmod(std::log10(num), 1.0) == 0)
- --nPaddingZeros;
-
- uniqueName = oldName.mid(0, match.capturedStart())
- + QString('0').repeated(nPaddingZeros)
- + QString::number(num);
- } else {
- uniqueName = oldName + '1';
- }
-
- return uniqueName;
+ setHasFiles(checkHasFiles());
}
void AssetsLibraryModel::setRootPath(const QString &newPath)
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
index 9334e86e9b..f08578651a 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
@@ -3,12 +3,13 @@
#pragma once
-#include <QFileInfo>
-#include <QFileSystemModel>
#include <QSortFilterProxyModel>
-#include <utils/filesystemwatcher.h>
-#include <utils/qtcassert.h>
+namespace Utils {
+class FileSystemWatcher;
+}
+
+QT_FORWARD_DECLARE_CLASS(QFileSystemModel)
namespace QmlDesigner {
@@ -22,7 +23,7 @@ public:
void setRootPath(const QString &newPath);
void setSearchText(const QString &searchText);
- Q_PROPERTY(bool haveFiles READ haveFiles NOTIFY haveFilesChanged);
+ Q_PROPERTY(bool hasFiles READ hasFiles NOTIFY hasFilesChanged)
Q_INVOKABLE QString rootPath() const;
Q_INVOKABLE QString filePath(const QModelIndex &index) const;
@@ -35,7 +36,7 @@ public:
Q_INVOKABLE QModelIndex parentDirIndex(const QString &path) const;
Q_INVOKABLE QModelIndex parentDirIndex(const QModelIndex &index) const;
Q_INVOKABLE QString parentDirPath(const QString &path) const;
- Q_INVOKABLE void syncHaveFiles();
+ Q_INVOKABLE void syncHasFiles();
Q_INVOKABLE QList<QModelIndex> parentIndices(const QModelIndex &index) const;
Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const;
@@ -55,30 +56,28 @@ public:
return std::min(result, 1);
}
- bool haveFiles() const { return m_haveFiles; }
-
- QString getUniqueName(const QString &oldName);
+ bool hasFiles() const { return m_hasFiles; }
signals:
void directoryLoaded(const QString &path);
void rootPathChanged();
- void haveFilesChanged();
+ void hasFilesChanged();
void fileChanged(const QString &path);
void effectsDeleted(const QStringList &effectNames);
private:
- void setHaveFiles(bool value);
+ void setHasFiles(bool value);
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
void resetModel();
void createBackendModel();
void destroyBackendModel();
- bool checkHaveFiles(const QModelIndex &parentIdx) const;
- bool checkHaveFiles() const;
+ bool checkHasFiles(const QModelIndex &parentIdx) const;
+ bool checkHasFiles() const;
QString m_searchText;
QString m_rootPath;
QFileSystemModel *m_sourceFsModel = nullptr;
- bool m_haveFiles = false;
+ bool m_hasFiles = false;
Utils::FileSystemWatcher *m_fileWatcher = nullptr;
};
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
index 3b98eb6baf..5e2211ce0d 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
@@ -3,26 +3,29 @@
#include "assetslibrarywidget.h"
-#include "asset.h"
#include "assetslibraryiconprovider.h"
#include "assetslibrarymodel.h"
#include "assetslibraryview.h"
-#include "designeractionmanager.h"
-#include "import.h"
-#include "modelnodeoperations.h"
-#include "nodemetainfo.h"
-#include "qmldesignerconstants.h"
-#include "qmldesignerplugin.h"
-#include "theme.h"
-#include <utils3d.h>
+#include <designeractionmanager.h>
+#include <designerpaths.h>
+#include <hdrimage.h>
+#include <import.h>
+#include <modelnodeoperations.h>
+#include <nodemetainfo.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
#include <studioquickwidget.h>
+#include <theme.h>
+#include <uniquename.h>
+#include <utils3d.h>
#include <coreplugin/fileutils.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <utils/algorithm.h>
+#include <utils/asset.h>
#include <utils/environment.h>
#include <utils/filepath.h>
#include <utils/qtcassert.h>
@@ -92,7 +95,7 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
, m_assetsModel{new AssetsLibraryModel(this)}
, m_assetsView{view}
, m_createTextures{view}
- , m_assetsWidget{new StudioQuickWidget(this)}
+ , m_assetsWidget{Utils::makeUniqueObjectPtr<StudioQuickWidget>(this)}
{
setWindowTitle(tr("Assets Library", "Title of assets library widget"));
setMinimumWidth(250);
@@ -128,7 +131,7 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
- layout->addWidget(m_assetsWidget.data());
+ layout->addWidget(m_assetsWidget.get());
updateSearch();
@@ -172,23 +175,10 @@ void AssetsLibraryWidget::deleteSelectedAssets()
QString AssetsLibraryWidget::getUniqueEffectPath(const QString &parentFolder, const QString &effectName)
{
- auto genEffectPath = [&parentFolder](const QString &name) {
- QString effectsDir = ModelNodeOperations::getEffectsDefaultDirectory(parentFolder);
- return QLatin1String("%1/%2.qep").arg(effectsDir, name);
- };
-
- QString uniqueName = effectName;
- QString path = genEffectPath(uniqueName);
- QFileInfo file{path};
+ QString effectsDir = ModelNodeOperations::getEffectsDefaultDirectory(parentFolder);
+ QString effectPath = QLatin1String("%1/%2.qep").arg(effectsDir, effectName);
- while (file.exists()) {
- uniqueName = m_assetsModel->getUniqueName(uniqueName);
-
- path = genEffectPath(uniqueName);
- file.setFile(path);
- }
-
- return path;
+ return UniqueName::generatePath(effectPath);
}
bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openInEffectComposer)
@@ -287,14 +277,16 @@ void AssetsLibraryWidget::handleDeleteEffects([[maybe_unused]] const QStringList
// Remove usages of deleted effects from the current document
m_assetsView->executeInTransaction(__FUNCTION__, [&]() {
QList<ModelNode> allNodes = m_assetsView->allModelNodes();
- const QString typeTemplate = "Effects.%1.%1";
- const QString importUrlTemplate = "Effects.%1";
+ const QString typeTemplate = "%1.%2.%2";
+ const QString importUrlTemplate = "%1.%2";
const Imports imports = m_assetsView->model()->imports();
Imports removedImports;
+ const QString typePrefix = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().composedEffectsTypePrefix();
for (const QString &effectName : effectNames) {
if (effectName.isEmpty())
continue;
- const TypeName type = typeTemplate.arg(effectName).toUtf8();
+ const TypeName type = typeTemplate.arg(typePrefix, effectName).toUtf8();
for (ModelNode &node : allNodes) {
if (node.metaInfo().typeName() == type) {
clearStacks = true;
@@ -302,7 +294,7 @@ void AssetsLibraryWidget::handleDeleteEffects([[maybe_unused]] const QStringList
}
}
- const QString importPath = importUrlTemplate.arg(effectName);
+ const QString importPath = importUrlTemplate.arg(typePrefix, effectName);
Import removedImport = Utils::findOrDefault(imports, [&importPath](const Import &import) {
return import.url() == importPath;
});
@@ -374,7 +366,7 @@ QList<QToolButton *> AssetsLibraryWidget::createToolBarWidgets()
void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText)
{
- if (filterText == m_filterText || (!m_assetsModel->haveFiles()
+ if (filterText == m_filterText || (!m_assetsModel->hasFiles()
&& filterText.contains(m_filterText, Qt::CaseInsensitive)))
return;
@@ -643,4 +635,9 @@ void AssetsLibraryWidget::addResources(const QStringList &files, bool showDialog
}
}
+void AssetsLibraryWidget::addAssetsToContentLibrary(const QStringList &assetPaths)
+{
+ m_assetsView->emitCustomNotification("add_assets_to_content_lib", {}, {assetPaths});
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
index ed987d14de..f2d476c842 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
@@ -8,6 +8,8 @@
#include <coreplugin/icontext.h>
+#include <utils/uniqueobjectptr.h>
+
#include <QFrame>
#include <QQmlPropertyMap>
#include <QQuickWidget>
@@ -98,6 +100,7 @@ public:
Q_INVOKABLE void showInGraphicalShell(const QString &path);
Q_INVOKABLE QString showInGraphicalShellMsg() const;
+ Q_INVOKABLE void addAssetsToContentLibrary(const QStringList &assetPaths);
signals:
void itemActivated(const QString &itemName);
@@ -135,7 +138,7 @@ private:
AssetsLibraryView *m_assetsView = nullptr;
CreateTextures m_createTextures = nullptr;
- QScopedPointer<StudioQuickWidget> m_assetsWidget;
+ Utils::UniqueObjectPtr<StudioQuickWidget> m_assetsWidget;
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp
index ff2361aa36..b067dc8d46 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp
@@ -147,7 +147,6 @@ BindingEditorFactory::BindingEditorFactory()
{
setId(BINDINGEDITOR_CONTEXT_ID);
setDisplayName(::Core::Tr::tr("Binding Editor"));
- setEditorActionHandlers(0);
addMimeType(BINDINGEDITOR_CONTEXT_ID);
addMimeType(Utils::Constants::QML_MIMETYPE);
addMimeType(Utils::Constants::QMLTYPES_MIMETYPE);
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.cpp
deleted file mode 100644
index cb306c58cb..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "collectiondatatypemodel.h"
-
-#include <QHash>
-#include <QtQml/QmlTypeAndRevisionsRegistration>
-
-namespace QmlDesigner {
-
-struct CollectionDataTypeModel::Details
-{
- CollectionDetails::DataType type;
- QString name;
- QString description;
-};
-
-const QList<CollectionDataTypeModel::Details> CollectionDataTypeModel::m_orderedDetails{
- {DataType::String, "String", "Text"},
- {DataType::Integer, "Integer", "Whole number that can be positive, negative, or zero"},
- {DataType::Real, "Real", "Number with a decimal"},
- {DataType::Image, "Image", "Image resource"},
- {DataType::Color, "Color", "HEX value"},
- {DataType::Url, "Url", "Resource locator"},
- {DataType::Boolean, "Boolean", "True/false"},
- {DataType::Unknown, "Unknown", "Unknown data type"},
-};
-
-CollectionDataTypeModel::CollectionDataTypeModel(QObject *parent)
- : QAbstractListModel(parent)
-{
-}
-
-int CollectionDataTypeModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
-{
- return m_orderedDetails.size();
-}
-
-QVariant CollectionDataTypeModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return {};
-
- if (role == Qt::DisplayRole)
- return m_orderedDetails.at(index.row()).name;
- if (role == Qt::ToolTipRole)
- return m_orderedDetails.at(index.row()).description;
-
- return {};
-}
-
-QString CollectionDataTypeModel::dataTypeToString(DataType dataType)
-{
- static const QHash<DataType, QString> dataTypeHash = []() -> QHash<DataType, QString> {
- QHash<DataType, QString> result;
- for (const Details &details : m_orderedDetails)
- result.insert(details.type, details.name);
- return result;
- }();
-
- if (dataTypeHash.contains(dataType))
- return dataTypeHash.value(dataType);
-
- return "Unknown";
-}
-
-CollectionDetails::DataType CollectionDataTypeModel::dataTypeFromString(const QString &dataType)
-{
- static const QHash<QString, DataType> stringTypeHash = []() -> QHash<QString, DataType> {
- QHash<QString, DataType> result;
- for (const Details &details : m_orderedDetails)
- result.insert(details.name, details.type);
- return result;
- }();
-
- if (stringTypeHash.contains(dataType))
- return stringTypeHash.value(dataType);
-
- return DataType::Unknown;
-}
-
-void CollectionDataTypeModel::registerDeclarativeType()
-{
- qmlRegisterType<CollectionDataTypeModel>("CollectionDetails", 1, 0, "CollectionDataTypeModel");
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.h
deleted file mode 100644
index 1f91aecbff..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondatatypemodel.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2024 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "collectiondetails.h"
-
-#include <QAbstractListModel>
-#include <QList>
-
-namespace QmlDesigner {
-
-class CollectionDataTypeModel : public QAbstractListModel
-{
- Q_OBJECT
-
-public:
- using DataType = CollectionDetails::DataType;
- CollectionDataTypeModel(QObject *parent = nullptr);
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
-
- static Q_INVOKABLE QString dataTypeToString(DataType dataType);
- static Q_INVOKABLE DataType dataTypeFromString(const QString &dataType);
-
- static void registerDeclarativeType();
-
-private:
- struct Details;
- static const QList<Details> m_orderedDetails;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp
deleted file mode 100644
index ddfb82746c..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp
+++ /dev/null
@@ -1,1011 +0,0 @@
-// 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 "collectiondetails.h"
-
-#include "collectiondatatypemodel.h"
-#include "collectioneditorutils.h"
-
-#include <utils/span.h>
-#include <qmljs/parser/qmljsast_p.h>
-#include <qmljs/parser/qmljsastvisitor_p.h>
-#include <qmljs/qmljsdocument.h>
-#include <qqml.h>
-
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QRegularExpression>
-#include <QTextStream>
-#include <QUrl>
-#include <QVariant>
-
-namespace QmlDesigner {
-#define COLLERR_OK QT_TRANSLATE_NOOP("CollectioParseError", "no error occurred")
-#define COLLERR_MAINOBJECT QT_TRANSLATE_NOOP("CollectioParseError", "Document object not found")
-#define COLLERR_COLLECTIONNAME QT_TRANSLATE_NOOP("CollectioParseError", "Model name not found")
-#define COLLERR_COLLECTIONOBJ QT_TRANSLATE_NOOP("CollectioParseError", "Model is not an object")
-#define COLLERR_COLUMNARRAY QT_TRANSLATE_NOOP("CollectioParseError", "Column is not an array")
-#define COLLERR_UNKNOWN QT_TRANSLATE_NOOP("CollectioParseError", "Unknown error")
-
-struct CollectionProperty
-{
- using DataType = CollectionDetails::DataType;
-
- QString name;
- DataType type;
-};
-
-const QMap<DataTypeWarning::Warning, QString> DataTypeWarning::dataTypeWarnings = {
- {DataTypeWarning::CellDataTypeMismatch, "Cell and column data types do not match."}
-};
-
-class CollectionDetails::Private
-{
-public:
- QList<CollectionProperty> properties;
- QList<QJsonArray> dataRecords;
- CollectionReference reference;
- bool isChanged = false;
-
- bool isValidColumnId(int column) const { return column > -1 && column < properties.size(); }
-
- bool isValidRowId(int row) const { return row > -1 && row < dataRecords.size(); }
-};
-
-inline static bool isValidColorName(const QString &colorName)
-{
- return QColor::isValidColorName(colorName);
-}
-
-/**
- * @brief getCustomUrl
- * MimeType = <MainType/SubType>
- * Address = <Url|LocalFile>
- *
- * @param value The input value to be evaluated
- * @param dataType if the value is a valid url or image, the data type
- * will be stored to this parameter, otherwise, it will be Unknown
- * @param urlResult if the value is a valid url or image, the address
- * will be stored in this parameter, otherwise it will be empty.
- * @param subType if the value is a valid image, the image subtype
- * will be stored in this parameter, otherwise it will be empty.
- * @return true if the result is either url or image
- */
-static bool getCustomUrl(const QString &value,
- CollectionDetails::DataType &dataType,
- QUrl *urlResult = nullptr,
- QString *subType = nullptr)
-{
- static const QRegularExpression urlRegex{
- "^(?<MimeType>"
- "(?<MainType>image)\\/"
- "(?<SubType>apng|avif|gif|jpeg|png|(?:svg\\+xml)|webp|xyz)\\:)?" // end of MimeType
- "(?<Address>"
- "(?<Url>https?:\\/\\/"
- "(?:www\\.|(?!www))[A-z0-9][A-z0-9-]+[A-z0-9]\\.[^\\s]{2,}|www\\.[A-z0-9][A-z0-9-]+"
- "[A-z0-9]\\.[^\\s]{2,}|https?:\\/\\/"
- "(?:www\\.|(?!www))[A-z0-9]+\\.[^\\s]{2,}|www\\.[A-z0-9]+\\.[^\\s]{2,})|" // end of Url
- "(?<LocalFile>("
- "?:(?:[A-z]:)|(?:(?:\\\\|\\/){1,2}\\w+)\\$?)(?:(?:\\\\|\\/)(?:\\w[\\w ]*.*))+)" // end of LocalFile
- "){1}$" // end of Address
- };
-
- const QRegularExpressionMatch match = urlRegex.match(value.trimmed());
- if (match.hasMatch()) {
- if (match.hasCaptured("Address")) {
- if (match.hasCaptured("MimeType") && match.captured("MainType") == "image")
- dataType = CollectionDetails::DataType::Image;
- else
- dataType = CollectionDetails::DataType::Url;
-
- if (urlResult)
- urlResult->setUrl(match.captured("Address"));
-
- if (subType)
- *subType = match.captured("SubType");
-
- return true;
- }
- }
-
- if (urlResult)
- urlResult->clear();
-
- if (subType)
- subType->clear();
-
- dataType = CollectionDetails::DataType::Unknown;
- return false;
-}
-
-/**
- * @brief dataTypeFromString
- * @param value The string value to be evaluated
- * @return Unknown if the string is empty, But returns Bool, Color, Integer,
- * Real, Url, Image if these types are detected within the non-empty string,
- * Otherwise it returns String.
- * If the value is integer, but it's out of the int range, it will be
- * considered as a Real.
- */
-static CollectionDetails::DataType dataTypeFromString(const QString &value)
-{
- using DataType = CollectionDetails::DataType;
- static const QRegularExpression validator{
- "(?<boolean>^(?:true|false)$)|"
- "(?<color>^(?:#(?:(?:[0-9a-fA-F]{2}){3,4}|(?:[0-9a-fA-F]){3,4}))$)|"
- "(?<integer>^\\d+$)|"
- "(?<real>^(?:-?(?:0|[1-9]\\d*)?(?:\\.\\d*)?(?<=\\d|\\.)"
- "(?:e-?(?:0|[1-9]\\d*))?|0x[0-9a-f]+)$)"};
- static const int boolIndex = validator.namedCaptureGroups().indexOf("boolean");
- static const int colorIndex = validator.namedCaptureGroups().indexOf("color");
- static const int integerIndex = validator.namedCaptureGroups().indexOf("integer");
- static const int realIndex = validator.namedCaptureGroups().indexOf("real");
-
- [[maybe_unused]] static const bool allIndexesFound =
- [](const std::initializer_list<int> &captureIndexes) {
- QTC_ASSERT(Utils::allOf(captureIndexes, [](int val) { return val > -1; }), return false);
- return true;
- }({boolIndex, colorIndex, integerIndex, realIndex});
-
- if (value.isEmpty())
- return DataType::Unknown;
-
- const QString trimmedValue = value.trimmed();
- QRegularExpressionMatch match = validator.match(trimmedValue);
-
- if (match.hasCaptured(boolIndex))
- return DataType::Boolean;
- if (match.hasCaptured(colorIndex))
- return DataType::Color;
- if (match.hasCaptured(integerIndex)) {
- bool isInt = false;
- trimmedValue.toInt(&isInt);
- return isInt ? DataType::Integer : DataType::Real;
- }
- if (match.hasCaptured(realIndex))
- return DataType::Real;
-
- DataType urlType;
- if (getCustomUrl(trimmedValue, urlType))
- return urlType;
-
- return DataType::String;
-}
-
-static CollectionProperty::DataType dataTypeFromJsonValue(const QJsonValue &value)
-{
- using DataType = CollectionDetails::DataType;
- using JsonType = QJsonValue::Type;
-
- switch (value.type()) {
- case JsonType::Null:
- case JsonType::Undefined:
- return DataType::Unknown;
- case JsonType::Bool:
- return DataType::Boolean;
- case JsonType::Double: {
- if (qFuzzyIsNull(std::remainder(value.toDouble(), 1)))
- return DataType::Integer;
- return DataType::Real;
- }
- case JsonType::String:
- return dataTypeFromString(value.toString());
- default:
- return DataType::Unknown;
- }
-}
-
-static QList<CollectionProperty> getColumnsFromImportedJsonArray(const QJsonArray &importedArray)
-{
- using DataType = CollectionDetails::DataType;
-
- QHash<QString, int> resultSet;
- QList<CollectionProperty> result;
-
- for (const QJsonValue &value : importedArray) {
- if (value.isObject()) {
- const QJsonObject object = value.toObject();
- QJsonObject::ConstIterator element = object.constBegin();
- const QJsonObject::ConstIterator stopItem = object.constEnd();
-
- while (element != stopItem) {
- const QString propertyName = element.key();
- if (resultSet.contains(propertyName)) {
- CollectionProperty &property = result[resultSet.value(propertyName)];
- if (property.type == DataType::Unknown) {
- property.type = dataTypeFromJsonValue(element.value());
- } else if (property.type == DataType::Integer) {
- const DataType currentCellDataType = dataTypeFromJsonValue(element.value());
- if (currentCellDataType == DataType::Real)
- property.type = currentCellDataType;
- }
- } else {
- result.append({propertyName, dataTypeFromJsonValue(element.value())});
- resultSet.insert(propertyName, resultSet.size());
- }
- ++element;
- }
- }
- }
-
- return result;
-}
-
-static QVariant valueToVariant(const QJsonValue &value, CollectionDetails::DataType type)
-{
- using DataType = CollectionDetails::DataType;
- QVariant variantValue = value.toVariant();
-
- switch (type) {
- case DataType::String:
- return variantValue.toString();
- case DataType::Integer:
- return variantValue.toInt();
- case DataType::Real:
- return variantValue.toDouble();
- case DataType::Boolean:
- return variantValue.toBool();
- case DataType::Color:
- return variantValue.value<QColor>();
- case DataType::Image: {
- DataType type;
- QUrl url;
- if (getCustomUrl(variantValue.toString(), type, &url))
- return url;
- return variantValue.toString();
- }
- case DataType::Url:
- return variantValue.value<QUrl>();
- default:
- return variantValue;
- }
-}
-
-static QJsonValue variantToJsonValue(
- const QVariant &variant, CollectionDetails::DataType type = CollectionDetails::DataType::Unknown)
-{
- using VariantType = QVariant::Type;
- using DataType = CollectionDetails::DataType;
-
- if (type == CollectionDetails::DataType::Unknown) {
- static const QHash<VariantType, DataType> typeMap = {{VariantType::Bool, DataType::Boolean},
- {VariantType::Double, DataType::Real},
- {VariantType::Int, DataType::Integer},
- {VariantType::String, DataType::String},
- {VariantType::Color, DataType::Color},
- {VariantType::Url, DataType::Url}};
- type = typeMap.value(variant.type(), DataType::Unknown);
- }
-
- switch (type) {
- case DataType::Boolean:
- return variant.toBool();
- case DataType::Real:
- return variant.toDouble();
- case DataType::Integer:
- return variant.toInt();
- case DataType::Image: {
- const QUrl url(variant.toUrl());
- if (url.isValid())
- return QString("image/xyz:%1").arg(url.toString());
- return {};
- }
- case DataType::String:
- case DataType::Color:
- case DataType::Url:
- default:
- return variant.toString();
- }
-}
-
-inline static bool isEmptyJsonValue(const QJsonValue &value)
-{
- return value.isNull() || value.isUndefined() || (value.isString() && value.toString().isEmpty());
-}
-
-QStringList csvReadLine(const QString &line)
-{
- static const QRegularExpression lineRegex{
- "(?:,\\\"|^\\\")(?<value>\\\"\\\"|[\\w\\W]*?)(?=\\\",|\\\"$)"
- "|(?:,(?!\\\")|^(?!\\\"))(?<quote>[^,]*?)(?=$|,)|(\\\\r\\\\n|\\\\n)"};
- static const int valueIndex = lineRegex.namedCaptureGroups().indexOf("value");
- static const int quoteIndex = lineRegex.namedCaptureGroups().indexOf("quote");
- Q_ASSERT(valueIndex > 0 && quoteIndex > 0);
-
- QStringList result;
- QRegularExpressionMatchIterator iterator = lineRegex.globalMatch(line, 0);
- while (iterator.hasNext()) {
- const QRegularExpressionMatch match = iterator.next();
-
- if (match.hasCaptured(valueIndex))
- result.append(match.captured(valueIndex));
- else if (match.hasCaptured(quoteIndex))
- result.append(match.captured(quoteIndex));
- }
- return result;
-}
-
-class PropertyOrderFinder : public QmlJS::AST::Visitor
-{
-public:
- static QStringList parse(const QString &jsonContent)
- {
- PropertyOrderFinder finder;
- QmlJS::Document::MutablePtr jsonDoc = QmlJS::Document::create(Utils::FilePath::fromString(
- "<expression>"),
- QmlJS::Dialect::Json);
-
- jsonDoc->setSource(jsonContent);
- jsonDoc->parseJavaScript();
-
- if (!jsonDoc->isParsedCorrectly())
- return {};
-
- jsonDoc->ast()->accept(&finder);
- return finder.m_orderedList;
- }
-
-protected:
- bool visit(QmlJS::AST::PatternProperty *patternProperty) override
- {
- const QString propertyName = patternProperty->name->asString();
- if (!m_propertySet.contains(propertyName)) {
- m_propertySet.insert(propertyName);
- m_orderedList.append(propertyName);
- }
- return true;
- }
-
- void throwRecursionDepthError() override
- {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Recursion depth error";
- };
-
-private:
- QSet<QString> m_propertySet;
- QStringList m_orderedList;
-};
-
-QString CollectionParseError::errorString() const
-{
- switch (errorNo) {
- case NoError:
- return COLLERR_OK;
- case MainObjectMissing:
- return COLLERR_MAINOBJECT;
- case CollectionNameNotFound:
- return COLLERR_COLLECTIONNAME;
- case CollectionIsNotObject:
- return COLLERR_COLLECTIONOBJ;
- case ColumnsBlockIsNotArray:
- return COLLERR_COLUMNARRAY;
- case UnknownError:
- default:
- return COLLERR_UNKNOWN;
- }
-}
-
-CollectionDetails::CollectionDetails()
- : d(new Private())
-{}
-
-CollectionDetails::CollectionDetails(const CollectionReference &reference)
- : CollectionDetails()
-{
- d->reference = reference;
-}
-
-void CollectionDetails::resetData(const QJsonDocument &localDocument,
- const QString &collectionToImport,
- CollectionParseError *error)
-{
- CollectionDetails importedCollection = fromLocalJson(localDocument, collectionToImport, error);
- d->properties.swap(importedCollection.d->properties);
- d->dataRecords.swap(importedCollection.d->dataRecords);
-}
-
-CollectionDetails::CollectionDetails(const CollectionDetails &other) = default;
-
-CollectionDetails::~CollectionDetails() = default;
-
-void CollectionDetails::insertColumn(const QString &propertyName,
- int colIdx,
- const QVariant &defaultValue,
- DataType type)
-{
- if (containsPropertyName(propertyName))
- return;
-
- CollectionProperty property = {propertyName, type};
- if (d->isValidColumnId(colIdx)) {
- d->properties.insert(colIdx, property);
- } else {
- colIdx = d->properties.size();
- d->properties.append(property);
- }
-
- const QJsonValue defaultJsonValue = QJsonValue::fromVariant(defaultValue);
- for (QJsonArray &record : d->dataRecords)
- record.insert(colIdx, defaultJsonValue);
-
- markChanged();
-}
-
-bool CollectionDetails::removeColumns(int colIdx, int count)
-{
- if (!d->isValidColumnId(colIdx))
- return false;
-
- int maxCount = d->properties.count() - colIdx;
- count = std::min(maxCount, count);
-
- if (count < 1)
- return false;
-
- d->properties.remove(colIdx, count);
-
- for (QJsonArray &record : d->dataRecords) {
- QJsonArray newElement;
-
- auto elementItr = record.constBegin();
- auto elementEnd = elementItr + colIdx;
- while (elementItr != elementEnd)
- newElement.append(*(elementItr++));
-
- elementItr += count;
- elementEnd = record.constEnd();
-
- while (elementItr != elementEnd)
- newElement.append(*(elementItr++));
-
- record = newElement;
- }
-
- markChanged();
-
- return true;
-}
-
-void CollectionDetails::insertEmptyRows(int row, int count)
-{
- if (count < 1)
- return;
-
- row = qBound(0, row, rows());
-
- insertRecords({}, row, count);
-
- markChanged();
-}
-
-bool CollectionDetails::removeRows(int row, int count)
-{
- if (!d->isValidRowId(row))
- return false;
-
- int maxCount = d->dataRecords.count() - row;
- count = std::min(maxCount, count);
-
- if (count < 1)
- return false;
-
- d->dataRecords.remove(row, count);
- markChanged();
- return true;
-}
-
-bool CollectionDetails::setPropertyValue(int row, int column, const QVariant &value)
-{
- if (!d->isValidRowId(row) || !d->isValidColumnId(column))
- return false;
-
- QVariant currentValue = data(row, column);
- if (value == currentValue)
- return false;
-
- QJsonArray &record = d->dataRecords[row];
- record.replace(column, variantToJsonValue(value, typeAt(column)));
- markChanged();
- return true;
-}
-
-bool CollectionDetails::setPropertyName(int column, const QString &value)
-{
- if (!d->isValidColumnId(column))
- return false;
-
- const CollectionProperty &oldProperty = d->properties.at(column);
- if (oldProperty.name == value)
- return false;
-
- d->properties.replace(column, {value, oldProperty.type});
-
- markChanged();
- return true;
-}
-
-bool CollectionDetails::setPropertyType(int column, DataType type)
-{
- if (!d->isValidColumnId(column))
- return false;
-
- bool changed = false;
- CollectionProperty &property = d->properties[column];
- if (property.type != type)
- changed = true;
-
- const DataType formerType = property.type;
- property.type = type;
-
- for (QJsonArray &rowData : d->dataRecords) {
- if (column < rowData.size()) {
- const QJsonValue value = rowData.at(column);
- const QVariant properTypedValue = valueToVariant(value, formerType);
- const QJsonValue properTypedJsonValue = variantToJsonValue(properTypedValue, type);
- rowData.replace(column, properTypedJsonValue);
- changed = true;
- }
- }
-
- if (changed)
- markChanged();
-
- return changed;
-}
-
-CollectionReference CollectionDetails::reference() const
-{
- return d->reference;
-}
-
-QVariant CollectionDetails::data(int row, int column) const
-{
- if (!d->isValidRowId(row))
- return {};
-
- if (!d->isValidColumnId(column))
- return {};
-
- const QJsonValue cellValue = d->dataRecords.at(row).at(column);
-
- if (typeAt(column) == DataType::Image) {
- const QUrl imageUrl = valueToVariant(cellValue, DataType::Image).toUrl();
-
- if (imageUrl.isValid())
- return imageUrl;
- }
-
- return cellValue.toVariant();
-}
-
-QString CollectionDetails::propertyAt(int column) const
-{
- if (!d->isValidColumnId(column))
- return {};
-
- return d->properties.at(column).name;
-}
-
-CollectionDetails::DataType CollectionDetails::typeAt(int column) const
-{
- if (!d->isValidColumnId(column))
- return {};
-
- return d->properties.at(column).type;
-}
-
-CollectionDetails::DataType CollectionDetails::typeAt(int row, int column) const
-{
- if (!d->isValidRowId(row) || !d->isValidColumnId(column))
- return {};
-
- const QJsonValue cellData = d->dataRecords.at(row).at(column);
- return dataTypeFromJsonValue(cellData);
-}
-
-DataTypeWarning::Warning CollectionDetails::cellWarningCheck(int row, int column) const
-{
- const QJsonValue cellValue = d->dataRecords.at(row).at(column);
-
- const DataType columnType = typeAt(column);
- const DataType cellType = typeAt(row, column);
-
- if (columnType == DataType::Unknown || isEmptyJsonValue(cellValue))
- return DataTypeWarning::Warning::None;
-
- if (columnType == DataType::Real && cellType == DataType::Integer)
- return DataTypeWarning::Warning::None;
-
- if (columnType != cellType)
- return DataTypeWarning::Warning::CellDataTypeMismatch;
-
- return DataTypeWarning::Warning::None;
-}
-
-bool CollectionDetails::containsPropertyName(const QString &propertyName) const
-{
- return Utils::anyOf(d->properties, [&propertyName](const CollectionProperty &property) {
- return property.name == propertyName;
- });
-}
-
-bool CollectionDetails::hasValidReference() const
-{
- return d->reference.node.isValid() && d->reference.name.size();
-}
-
-bool CollectionDetails::isChanged() const
-{
- return d->isChanged;
-}
-
-int CollectionDetails::columns() const
-{
- return d->properties.size();
-}
-
-int CollectionDetails::rows() const
-{
- return d->dataRecords.size();
-}
-
-bool CollectionDetails::markSaved()
-{
- if (d->isChanged) {
- d->isChanged = false;
- return true;
- }
- return false;
-}
-
-void CollectionDetails::swap(CollectionDetails &other)
-{
- d.swap(other.d);
-}
-
-void CollectionDetails::resetReference(const CollectionReference &reference)
-{
- if (d->reference != reference) {
- d->reference = reference;
- markChanged();
- }
-}
-
-QString CollectionDetails::toJson() const
-{
- QJsonArray exportedArray;
- const int propertyCount = d->properties.count();
-
- for (const QJsonArray &record : std::as_const(d->dataRecords)) {
- const int valueCount = std::min(int(record.count()), propertyCount);
-
- QJsonObject exportedElement;
- for (int i = 0; i < valueCount; ++i) {
- const QJsonValue &value = record.at(i);
- if (isEmptyJsonValue(value))
- exportedElement.insert(d->properties.at(i).name, QJsonValue::Null);
- else
- exportedElement.insert(d->properties.at(i).name, value);
- }
-
- exportedArray.append(exportedElement);
- }
-
- return QString::fromUtf8(QJsonDocument(exportedArray).toJson());
-}
-
-QString CollectionDetails::toCsv() const
-{
- QString content;
-
- auto gotoNextLine = [&content]() {
- if (content.size() && content.back() == ',')
- content.back() = '\n';
- else
- content += "\n";
- };
-
- const int propertyCount = d->properties.count();
- if (propertyCount <= 0)
- return "";
-
- for (const CollectionProperty &property : std::as_const(d->properties))
- content += property.name + ',';
-
- gotoNextLine();
-
- for (const QJsonArray &record : std::as_const(d->dataRecords)) {
- const int valueCount = std::min(int(record.count()), propertyCount);
- int i = 0;
- for (; i < valueCount; ++i) {
- const QJsonValue &value = record.at(i);
-
- if (value.isDouble())
- content += QString::number(value.toDouble()) + ',';
- else if (value.isBool())
- content += value.toBool() ? QString("true,") : QString("false,");
- else
- content += value.toString() + ',';
- }
-
- for (; i < propertyCount; ++i)
- content += ',';
-
- gotoNextLine();
- }
-
- return content;
-}
-
-QJsonObject CollectionDetails::toLocalJson() const
-{
- QJsonObject collectionObject;
- QJsonArray columnsArray;
- QJsonArray dataArray;
-
- for (const CollectionProperty &property : std::as_const(d->properties)) {
- QJsonObject columnObject;
- columnObject.insert("name", property.name);
- columnObject.insert("type", CollectionDataTypeModel::dataTypeToString(property.type));
- columnsArray.append(columnObject);
- }
-
- for (const QJsonArray &record : std::as_const(d->dataRecords))
- dataArray.append(record);
-
- collectionObject.insert("columns", columnsArray);
- collectionObject.insert("data", dataArray);
-
- return collectionObject;
-}
-
-void CollectionDetails::registerDeclarativeType()
-{
- typedef CollectionDetails::DataType DataType;
- qRegisterMetaType<DataType>("DataType");
- qmlRegisterUncreatableType<CollectionDetails>("CollectionDetails", 1, 0, "DataType", "Enum type");
-
- qRegisterMetaType<DataTypeWarning::Warning>("Warning");
- qmlRegisterUncreatableType<DataTypeWarning>("CollectionDetails", 1, 0, "Warning", "Enum type");
-}
-
-CollectionDetails CollectionDetails::fromImportedCsv(const QByteArray &document,
- const bool &firstRowIsHeader)
-{
- QStringList headers;
- QJsonArray importedArray;
-
- QTextStream stream(document);
- stream.setEncoding(QStringConverter::Latin1);
-
- if (firstRowIsHeader && !stream.atEnd()) {
- headers = Utils::transform(csvReadLine(stream.readLine()),
- [](const QString &value) -> QString { return value.trimmed(); });
- }
-
- while (!stream.atEnd()) {
- const QStringList recordDataList = csvReadLine(stream.readLine());
- int column = -1;
- QJsonObject recordData;
- for (const QString &cellData : recordDataList) {
- if (++column == headers.size()) {
- QString proposalName;
- int proposalId = column;
- do
- proposalName = QString("Column %1").arg(++proposalId);
- while (headers.contains(proposalName));
- headers.append(proposalName);
- }
- recordData.insert(headers.at(column), cellData);
- }
- importedArray.append(recordData);
- }
-
- return fromImportedJson(importedArray, headers);
-}
-
-CollectionDetails CollectionDetails::fromImportedJson(const QByteArray &json, QJsonParseError *error)
-{
- QJsonArray importedCollection;
- auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray {
- QJsonArray resultArray;
- for (const QJsonValue &collectionData : array) {
- if (collectionData.isObject()) {
- QJsonObject rowObject = collectionData.toObject();
- const QStringList rowKeys = rowObject.keys();
- for (const QString &key : rowKeys) {
- const QJsonValue cellValue = rowObject.value(key);
- if (cellValue.isArray())
- rowObject.remove(key);
- }
- resultArray.push_back(rowObject);
- }
- }
- return resultArray;
- };
-
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(json, &parseError);
- if (error)
- *error = parseError;
-
- if (parseError.error != QJsonParseError::NoError)
- return CollectionDetails{};
-
- if (document.isArray()) {
- importedCollection = refineJsonArray(document.array());
- } else if (document.isObject()) {
- QJsonObject documentObject = document.object();
- const QStringList mainKeys = documentObject.keys();
-
- bool arrayFound = false;
- for (const QString &key : mainKeys) {
- const QJsonValue value = documentObject.value(key);
- if (value.isArray()) {
- arrayFound = true;
- importedCollection = refineJsonArray(value.toArray());
- break;
- }
- }
-
- if (!arrayFound) {
- QJsonObject singleObject;
- for (const QString &key : mainKeys) {
- const QJsonValue value = documentObject.value(key);
-
- if (!value.isObject())
- singleObject.insert(key, value);
- }
- importedCollection.push_back(singleObject);
- }
- }
-
- return fromImportedJson(importedCollection, PropertyOrderFinder::parse(QLatin1String(json)));
-}
-
-CollectionDetails CollectionDetails::fromLocalJson(const QJsonDocument &document,
- const QString &collectionName,
- CollectionParseError *error)
-{
- auto setError = [&error](CollectionParseError::ParseError parseError) {
- if (error)
- error->errorNo = parseError;
- };
-
- setError(CollectionParseError::NoError);
-
- if (document.isObject()) {
- QJsonObject collectionMap = document.object();
- if (collectionMap.contains(collectionName)) {
- QJsonValue collectionValue = collectionMap.value(collectionName);
- if (collectionValue.isObject())
- return fromLocalCollection(collectionValue.toObject());
- else
- setError(CollectionParseError::CollectionIsNotObject);
- } else {
- setError(CollectionParseError::CollectionNameNotFound);
- }
- } else {
- setError(CollectionParseError::MainObjectMissing);
- }
-
- return CollectionDetails{};
-}
-
-CollectionDetails &CollectionDetails::operator=(const CollectionDetails &other)
-{
- CollectionDetails value(other);
- swap(value);
- return *this;
-}
-
-void CollectionDetails::markChanged()
-{
- d->isChanged = true;
-}
-
-void CollectionDetails::insertRecords(const QJsonArray &record, int idx, int count)
-{
- if (count < 1)
- return;
-
- QJsonArray localRecord;
- const int columnsCount = columns();
- for (int i = 0; i < columnsCount; i++) {
- const QJsonValue originalCellData = record.at(i);
- if (originalCellData.isArray())
- localRecord.append({});
- else
- localRecord.append(originalCellData);
- }
-
- if (idx > d->dataRecords.size() || idx < 0)
- idx = d->dataRecords.size();
-
- d->dataRecords.insert(idx, count, localRecord);
-}
-
-CollectionDetails CollectionDetails::fromImportedJson(const QJsonArray &importedArray,
- const QStringList &propertyPriority)
-{
- QList<CollectionProperty> columnData = getColumnsFromImportedJsonArray(importedArray);
- if (!propertyPriority.isEmpty()) {
- QMap<QString, int> priorityMap;
- for (const QString &propertyName : propertyPriority) {
- if (!priorityMap.contains(propertyName))
- priorityMap.insert(propertyName, priorityMap.size());
- }
- const int lowestPriority = priorityMap.size();
-
- Utils::sort(columnData, [&](const CollectionProperty &a, const CollectionProperty &b) {
- return priorityMap.value(a.name, lowestPriority)
- < priorityMap.value(b.name, lowestPriority);
- });
- }
-
- QList<QJsonArray> localJsonArray;
- for (const QJsonValue &importedRowValue : importedArray) {
- QJsonObject importedRowObject = importedRowValue.toObject();
- QJsonArray localRow;
- for (const CollectionProperty &property : columnData)
- localRow.append(importedRowObject.value(property.name));
- localJsonArray.append(localRow);
- }
- CollectionDetails result;
- result.d->properties = columnData;
- result.d->dataRecords = localJsonArray;
- result.markSaved();
-
- return result;
-}
-
-CollectionDetails CollectionDetails::fromLocalCollection(const QJsonObject &localCollection,
- CollectionParseError *error)
-{
- auto setError = [&error](CollectionParseError::ParseError parseError) {
- if (error)
- error->errorNo = parseError;
- };
-
- CollectionDetails result;
- setError(CollectionParseError::NoError);
-
- if (localCollection.contains("columns")) {
- const QJsonValue columnsValue = localCollection.value("columns");
- if (columnsValue.isArray()) {
- const QJsonArray columns = columnsValue.toArray();
- for (const QJsonValue &columnValue : columns) {
- if (columnValue.isObject()) {
- const QJsonObject column = columnValue.toObject();
- const QString columnName = column.value("name").toString();
- if (!columnName.isEmpty()) {
- result.insertColumn(columnName,
- -1,
- {},
- CollectionDataTypeModel::dataTypeFromString(
- column.value("type").toString()));
- }
- }
- }
-
- if (int columnsCount = result.columns()) {
- const QJsonArray dataRecords = localCollection.value("data").toArray();
- for (const QJsonValue &dataRecordValue : dataRecords) {
- QJsonArray dataRecord = dataRecordValue.toArray();
- while (dataRecord.count() > columnsCount)
- dataRecord.removeLast();
-
- result.insertRecords(dataRecord);
- }
- }
- } else {
- setError(CollectionParseError::ColumnsBlockIsNotArray);
- return result;
- }
- }
-
- return result;
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h
deleted file mode 100644
index b84c214570..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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 "modelnode.h"
-
-#include <QSharedPointer>
-
-QT_BEGIN_NAMESPACE
-class QJsonObject;
-struct QJsonParseError;
-class QVariant;
-QT_END_NAMESPACE
-
-namespace QmlDesigner {
-
-struct CollectionReference
-{
- ModelNode node;
- QString name;
-
- friend auto qHash(const CollectionReference &collection)
- {
- return qHash(collection.node) ^ ::qHash(collection.name);
- }
-
- bool operator==(const CollectionReference &other) const
- {
- return node == other.node && name == other.name;
- }
-
- bool operator!=(const CollectionReference &other) const { return !(*this == other); }
-};
-
-struct CollectionProperty;
-
-struct DataTypeWarning {
-public:
- enum Warning { None, CellDataTypeMismatch };
- Q_ENUM(Warning)
-
- Warning warning = None;
- DataTypeWarning(Warning warning)
- : warning(warning)
- {}
-
- static QString getDataTypeWarningString(Warning warning)
- {
- return dataTypeWarnings.value(warning);
- }
-
-private:
- Q_GADGET
- static const QMap<Warning, QString> dataTypeWarnings;
-};
-
-struct CollectionParseError
-{
- enum ParseError {
- NoError,
- MainObjectMissing,
- CollectionNameNotFound,
- CollectionIsNotObject,
- ColumnsBlockIsNotArray,
- UnknownError
- };
-
- ParseError errorNo = ParseError::NoError;
- QString errorString() const;
-};
-
-class CollectionDetails
-{
- Q_GADGET
-
-public:
- enum class DataType { Unknown, String, Url, Integer, Real, Boolean, Image, Color };
- Q_ENUM(DataType)
-
- explicit CollectionDetails();
- CollectionDetails(const CollectionReference &reference);
- CollectionDetails(const CollectionDetails &other);
- ~CollectionDetails();
-
- void resetData(const QJsonDocument &localDocument,
- const QString &collectionToImport,
- CollectionParseError *error = nullptr);
-
- void insertColumn(const QString &propertyName,
- int colIdx = -1,
- const QVariant &defaultValue = {},
- DataType type = DataType::Unknown);
- bool removeColumns(int colIdx, int count = 1);
-
- void insertEmptyRows(int row = 0, int count = 1);
- bool removeRows(int row, int count = 1);
- bool setPropertyValue(int row, int column, const QVariant &value);
-
- bool setPropertyName(int column, const QString &value);
- bool setPropertyType(int column, DataType type);
-
- CollectionReference reference() const;
- QVariant data(int row, int column) const;
- QString propertyAt(int column) const;
- DataType typeAt(int column) const;
- DataType typeAt(int row, int column) const;
- DataTypeWarning::Warning cellWarningCheck(int row, int column) const;
- bool containsPropertyName(const QString &propertyName) const;
-
- bool hasValidReference() const;
- bool isChanged() const;
-
- int columns() const;
- int rows() const;
-
- bool markSaved();
-
- void swap(CollectionDetails &other);
- void resetReference(const CollectionReference &reference);
-
- QString toJson() const;
- QString toCsv() const;
- QJsonObject toLocalJson() const;
-
- static void registerDeclarativeType();
-
- static CollectionDetails fromImportedCsv(const QByteArray &document,
- const bool &firstRowIsHeader = true);
- static CollectionDetails fromImportedJson(const QByteArray &json,
- QJsonParseError *error = nullptr);
- static CollectionDetails fromLocalJson(const QJsonDocument &document,
- const QString &collectionName,
- CollectionParseError *error = nullptr);
-
- CollectionDetails &operator=(const CollectionDetails &other);
-
-private:
- void markChanged();
- void insertRecords(const QJsonArray &record, int idx = -1, int count = 1);
-
- static CollectionDetails fromImportedJson(const QJsonArray &importedArray,
- const QStringList &propertyPriority = {});
- static CollectionDetails fromLocalCollection(const QJsonObject &localCollection,
- CollectionParseError *error = nullptr);
-
- // The private data is supposed to be shared between the copies
- class Private;
- QSharedPointer<Private> d;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp
deleted file mode 100644
index b26b1a845e..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-// 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 "collectiondetailsmodel.h"
-
-#include "collectiondatatypemodel.h"
-#include "collectioneditorutils.h"
-#include "modelnode.h"
-
-#include <coreplugin/editormanager/editormanager.h>
-
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-#include <utils/textfileformat.h>
-
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-
-namespace QmlDesigner {
-
-CollectionDetailsModel::CollectionDetailsModel(QObject *parent)
- : QAbstractTableModel(parent)
-{
- connect(this, &CollectionDetailsModel::modelReset, this, &CollectionDetailsModel::updateEmpty);
- connect(this, &CollectionDetailsModel::rowsInserted, this, &CollectionDetailsModel::updateEmpty);
- connect(this, &CollectionDetailsModel::rowsRemoved, this, &CollectionDetailsModel::updateEmpty);
-}
-
-QHash<int, QByteArray> CollectionDetailsModel::roleNames() const
-{
- static QHash<int, QByteArray> roles;
- if (roles.isEmpty()) {
- roles.insert(QAbstractTableModel::roleNames());
- roles.insert(SelectedRole, "itemSelected");
- roles.insert(DataTypeRole, "dataType");
- roles.insert(ColumnDataTypeRole, "columnType");
- roles.insert(DataTypeWarningRole, "dataTypeWarning");
- }
- return roles;
-}
-
-int CollectionDetailsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
-{
- return m_currentCollection.rows();
-}
-
-int CollectionDetailsModel::columnCount([[maybe_unused]] const QModelIndex &parent) const
-{
- return m_currentCollection.columns();
-}
-
-QVariant CollectionDetailsModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return {};
-
- QTC_ASSERT(m_currentCollection.hasValidReference(), return {});
-
- if (role == SelectedRole)
- return (index.column() == m_selectedColumn || index.row() == m_selectedRow);
-
- if (role == DataTypeRole)
- return QVariant::fromValue(m_currentCollection.typeAt(index.row(), index.column()));
-
- if (role == ColumnDataTypeRole)
- return QVariant::fromValue(m_currentCollection.typeAt(index.column()));
-
- if (role == Qt::EditRole)
- return m_currentCollection.data(index.row(), index.column());
-
- if (role == DataTypeWarningRole )
- return QVariant::fromValue(m_currentCollection.cellWarningCheck(index.row(), index.column()));
-
- return m_currentCollection.data(index.row(), index.column()).toString();
-}
-
-bool CollectionDetailsModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (!index.isValid())
- return {};
-
- if (role == Qt::EditRole) {
- DataTypeWarning::Warning prevWarning = m_currentCollection.cellWarningCheck(index.row(), index.column());
- bool changed = m_currentCollection.setPropertyValue(index.row(), index.column(), value);
-
- if (changed) {
- QList<int> roles = {Qt::DisplayRole, Qt::EditRole};
-
- if (prevWarning != m_currentCollection.cellWarningCheck(index.row(), index.column()))
- roles << DataTypeWarningRole;
-
- emit dataChanged(index, index, roles);
- }
-
- return true;
- }
-
- return false;
-}
-
-bool CollectionDetailsModel::setHeaderData(int section,
- Qt::Orientation orientation,
- const QVariant &value,
- [[maybe_unused]] int role)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (orientation == Qt::Vertical)
- return false;
-
- bool headerChanged = m_currentCollection.setPropertyName(section, value.toString());
- if (headerChanged)
- emit this->headerDataChanged(orientation, section, section);
-
- return headerChanged;
-}
-
-bool CollectionDetailsModel::insertRows(int row, int count, [[maybe_unused]] const QModelIndex &parent)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (count < 1)
- return false;
-
- row = qBound(0, row, rowCount());
-
- beginResetModel();
- m_currentCollection.insertEmptyRows(row, count);
- endResetModel();
-
- selectRow(row);
- return true;
-}
-
-bool CollectionDetailsModel::removeColumns(int column, int count, const QModelIndex &parent)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (column < 0 || column >= columnCount(parent) || count < 1)
- return false;
-
- count = std::min(count, columnCount(parent) - column);
- beginRemoveColumns(parent, column, column + count - 1);
- bool columnsRemoved = m_currentCollection.removeColumns(column, count);
- endRemoveColumns();
-
- if (!columnCount(parent))
- removeRows(0, rowCount(parent), parent);
-
- int nextColumn = column - 1;
- if (nextColumn < 0 && columnCount(parent) > 0)
- nextColumn = 0;
-
- selectColumn(nextColumn);
-
- ensureSingleCell();
- return columnsRemoved;
-}
-
-bool CollectionDetailsModel::removeRows(int row, int count, const QModelIndex &parent)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (row < 0 || row >= rowCount(parent) || count < 1)
- return false;
-
- count = std::min(count, rowCount(parent) - row);
- beginRemoveRows(parent, row, row + count - 1);
- bool rowsRemoved = m_currentCollection.removeRows(row, count);
- endRemoveRows();
-
- ensureSingleCell();
- return rowsRemoved;
-}
-
-Qt::ItemFlags CollectionDetailsModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid())
- return {};
-
- return {Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable};
-}
-
-QVariant CollectionDetailsModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation == Qt::Horizontal) {
- if (role == DataTypeRole)
- return CollectionDataTypeModel::dataTypeToString(m_currentCollection.typeAt(section));
- else
- return m_currentCollection.propertyAt(section);
- }
-
- if (orientation == Qt::Vertical)
- return section + 1;
-
- return {};
-}
-
-CollectionDetails::DataType CollectionDetailsModel::propertyDataType(int column) const
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return CollectionDetails::DataType::Unknown);
-
- return m_currentCollection.typeAt(column);
-}
-
-int CollectionDetailsModel::selectedColumn() const
-{
- return m_selectedColumn;
-}
-
-int CollectionDetailsModel::selectedRow() const
-{
- return m_selectedRow;
-}
-
-QString CollectionDetailsModel::propertyName(int column) const
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return {});
-
- return m_currentCollection.propertyAt(column);
-}
-
-QString CollectionDetailsModel::propertyType(int column) const
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return {});
-
- return CollectionDataTypeModel::dataTypeToString(m_currentCollection.typeAt(column));
-}
-
-bool CollectionDetailsModel::isPropertyAvailable(const QString &name)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- return m_currentCollection.containsPropertyName(name);
-}
-
-bool CollectionDetailsModel::addColumn(int column, const QString &name, const QString &propertyType)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- if (m_currentCollection.containsPropertyName(name))
- return false;
-
- if (column < 0 || column > columnCount())
- column = columnCount();
-
- beginInsertColumns({}, column, column);
- m_currentCollection.insertColumn(name,
- column,
- {},
- CollectionDataTypeModel::dataTypeFromString(propertyType));
- endInsertColumns();
- return m_currentCollection.containsPropertyName(name);
-}
-
-bool CollectionDetailsModel::selectColumn(int section)
-{
- if (m_selectedColumn == section)
- return false;
-
- const int columns = columnCount();
-
- if (section >= columns)
- section = columns - 1;
-
- selectRow(-1);
-
- const int rows = rowCount();
- const int previousColumn = m_selectedColumn;
-
- m_selectedColumn = section;
- emit this->selectedColumnChanged(m_selectedColumn);
-
- auto notifySelectedDataChanged = [this, columns, rows](int notifyingColumn) {
- if (notifyingColumn > -1 && notifyingColumn < columns && rows) {
- emit dataChanged(index(0, notifyingColumn),
- index(rows - 1, notifyingColumn),
- {SelectedRole});
- }
- };
-
- notifySelectedDataChanged(previousColumn);
- notifySelectedDataChanged(m_selectedColumn);
-
- return true;
-}
-
-bool CollectionDetailsModel::renameColumn(int section, const QString &newValue)
-{
- return setHeaderData(section, Qt::Horizontal, newValue);
-}
-
-bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue)
-{
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- bool changed = m_currentCollection.setPropertyType(column,
- CollectionDataTypeModel::dataTypeFromString(
- newValue));
- if (changed) {
- emit headerDataChanged(Qt::Horizontal, column, column);
- emit dataChanged(
- index(0, column),
- index(rowCount() - 1, column),
- {Qt::DisplayRole, Qt::EditRole, DataTypeRole, DataTypeWarningRole, ColumnDataTypeRole});
- }
-
- return changed;
-}
-
-bool CollectionDetailsModel::selectRow(int row)
-{
- if (m_selectedRow == row)
- return false;
-
- const int rows = rowCount();
-
- if (row >= rows)
- row = rows - 1;
-
- selectColumn(-1);
-
- const int columns = columnCount();
- const int previousRow = m_selectedRow;
-
- m_selectedRow = row;
- emit this->selectedRowChanged(m_selectedRow);
-
- auto notifySelectedDataChanged = [this, rows, columns](int notifyingRow) {
- if (notifyingRow > -1 && notifyingRow < rows && columns)
- emit dataChanged(index(notifyingRow, 0), index(notifyingRow, columns - 1), {SelectedRole});
- };
-
- notifySelectedDataChanged(previousRow);
- notifySelectedDataChanged(m_selectedRow);
-
- return true;
-}
-
-void CollectionDetailsModel::deselectAll()
-{
- selectColumn(-1);
- selectRow(-1);
-}
-
-void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const QString &collection)
-{
- QString fileName = CollectionEditorUtils::getSourceCollectionPath(sourceNode);
-
- CollectionReference newReference{sourceNode, collection};
- bool alreadyOpen = m_openedCollections.contains(newReference);
-
- if (alreadyOpen) {
- if (m_currentCollection.reference() != newReference) {
- deselectAll();
- beginResetModel();
- switchToCollection(newReference);
- ensureSingleCell();
- endResetModel();
- }
- } else {
- deselectAll();
- switchToCollection(newReference);
- loadJsonCollection(fileName, collection);
- }
-}
-
-void CollectionDetailsModel::removeCollection(const ModelNode &sourceNode, const QString &collection)
-{
- CollectionReference collectionRef{sourceNode, collection};
- if (!m_openedCollections.contains(collectionRef))
- return;
-
- if (m_currentCollection.reference() == collectionRef)
- loadCollection({}, {});
-
- m_openedCollections.remove(collectionRef);
-}
-
-void CollectionDetailsModel::removeAllCollections()
-{
- loadCollection({}, {});
- m_openedCollections.clear();
-}
-
-void CollectionDetailsModel::renameCollection(const ModelNode &sourceNode,
- const QString &oldName,
- const QString &newName)
-{
- CollectionReference oldRef{sourceNode, oldName};
- if (!m_openedCollections.contains(oldRef))
- return;
-
- CollectionReference newReference{sourceNode, newName};
- bool collectionIsSelected = m_currentCollection.reference() == oldRef;
- CollectionDetails collection = m_openedCollections.take(oldRef);
- collection.resetReference(newReference);
- m_openedCollections.insert(newReference, collection);
-
- if (collectionIsSelected)
- setCollectionName(newName);
-}
-
-bool CollectionDetailsModel::saveDataStoreCollections()
-{
- const ModelNode node = m_currentCollection.reference().node;
- const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath();
- Utils::FileReader fileData;
-
- if (!fileData.fetch(path)) {
- qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString();
- return false;
- }
-
- QJsonParseError jpe;
- QJsonDocument document = QJsonDocument::fromJson(fileData.data(), &jpe);
-
- if (jpe.error == QJsonParseError::NoError) {
- QJsonObject obj = document.object();
-
- QList<CollectionDetails> collectionsToBeSaved;
- for (CollectionDetails &openedCollection : m_openedCollections) {
- const CollectionReference reference = openedCollection.reference();
- if (reference.node == node) {
- obj.insert(reference.name, openedCollection.toLocalJson());
- collectionsToBeSaved << openedCollection;
- }
- }
-
- document.setObject(obj);
-
- if (CollectionEditorUtils::writeToJsonDocument(path, document)) {
- const CollectionReference currentReference = m_currentCollection.reference();
- for (CollectionDetails &collection : collectionsToBeSaved) {
- collection.markSaved();
- const CollectionReference reference = collection.reference();
- if (reference != currentReference)
- closeCollectionIfSaved(reference);
- }
- return true;
- }
- }
- return false;
-}
-
-bool CollectionDetailsModel::exportCollection(const QUrl &url)
-{
- using Core::EditorManager;
- using Utils::FilePath;
- using Utils::TextFileFormat;
-
- QTC_ASSERT(m_currentCollection.hasValidReference(), return false);
-
- bool saved = false;
- const FilePath filePath = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
- : url.toString());
- const QString saveFormat = filePath.toFileInfo().suffix().toLower();
- const QString content = saveFormat == "csv" ? m_currentCollection.toCsv()
- : m_currentCollection.toJson();
-
- TextFileFormat textFileFormat;
- textFileFormat.codec = EditorManager::defaultTextCodec();
- textFileFormat.lineTerminationMode = EditorManager::defaultLineEnding();
- QString errorMessage;
- saved = textFileFormat.writeFile(filePath, content, &errorMessage);
-
- if (!saved)
- qWarning() << Q_FUNC_INFO << "Unable to write file" << errorMessage;
-
- return saved;
-}
-
-const CollectionDetails CollectionDetailsModel::upToDateConstCollection(
- const CollectionReference &reference) const
-{
- using Utils::FilePath;
- using Utils::FileReader;
- CollectionDetails collection;
-
- if (m_openedCollections.contains(reference)) {
- collection = m_openedCollections.value(reference);
- } else {
- QUrl url = CollectionEditorUtils::getSourceCollectionPath(reference.node);
- FilePath path = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
- : url.toString());
- FileReader file;
-
- if (!file.fetch(path))
- return collection;
-
- QJsonParseError jpe;
- QJsonDocument document = QJsonDocument::fromJson(file.data(), &jpe);
-
- if (jpe.error != QJsonParseError::NoError)
- return collection;
-
- collection = CollectionDetails::fromLocalJson(document, reference.name);
- collection.resetReference(reference);
- }
- return collection;
-}
-
-bool CollectionDetailsModel::collectionHasColumn(const CollectionReference &reference,
- const QString &columnName) const
-{
- const CollectionDetails collection = upToDateConstCollection(reference);
- return collection.containsPropertyName(columnName);
-}
-
-QString CollectionDetailsModel::getFirstColumnName(const CollectionReference &reference) const
-{
- const CollectionDetails collection = upToDateConstCollection(reference);
- return collection.propertyAt(0);
-}
-
-void CollectionDetailsModel::updateEmpty()
-{
- bool isEmptyNow = rowCount() == 0;
- if (m_isEmpty != isEmptyNow) {
- m_isEmpty = isEmptyNow;
- emit isEmptyChanged(m_isEmpty);
- }
-}
-
-void CollectionDetailsModel::switchToCollection(const CollectionReference &collection)
-{
- if (m_currentCollection.reference() == collection)
- return;
-
- closeCurrentCollectionIfSaved();
-
- if (!m_openedCollections.contains(collection))
- m_openedCollections.insert(collection, CollectionDetails(collection));
-
- m_currentCollection = m_openedCollections.value(collection);
-
- setCollectionName(collection.name);
-}
-
-void CollectionDetailsModel::closeCollectionIfSaved(const CollectionReference &collection)
-{
- if (!m_openedCollections.contains(collection))
- return;
-
- const CollectionDetails &collectionDetails = m_openedCollections.value(collection);
-
- if (!collectionDetails.isChanged())
- m_openedCollections.remove(collection);
-}
-
-void CollectionDetailsModel::closeCurrentCollectionIfSaved()
-{
- if (m_currentCollection.hasValidReference()) {
- closeCollectionIfSaved(m_currentCollection.reference());
- m_currentCollection = CollectionDetails{};
- }
-}
-
-void CollectionDetailsModel::loadJsonCollection(const QString &filePath, const QString &collection)
-{
- QJsonDocument document = readJsonFile(filePath);
-
- beginResetModel();
- m_currentCollection.resetData(document, collection);
- ensureSingleCell();
- endResetModel();
-}
-
-void CollectionDetailsModel::ensureSingleCell()
-{
- if (!m_currentCollection.hasValidReference())
- return;
-
- if (!columnCount())
- addColumn(0, "Column 1", "String");
-
- if (!rowCount())
- insertRow(0);
-
- updateEmpty();
-}
-
-QJsonDocument CollectionDetailsModel::readJsonFile(const QUrl &url)
-{
- using Utils::FilePath;
- using Utils::FileReader;
- FilePath path = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile() : url.toString());
- FileReader file;
-
- if (!file.fetch(path)) {
- emit warning(tr("File reading problem"), file.errorString());
- return {};
- }
-
- QJsonParseError jpe;
- QJsonDocument document = QJsonDocument::fromJson(file.data(), &jpe);
-
- if (jpe.error != QJsonParseError::NoError)
- emit warning(tr("Json parse error"), jpe.errorString());
-
- return document;
-}
-
-void CollectionDetailsModel::setCollectionName(const QString &newCollectionName)
-{
- if (m_collectionName != newCollectionName) {
- m_collectionName = newCollectionName;
- emit this->collectionNameChanged(m_collectionName);
- }
-}
-
-QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning) const
-{
- return DataTypeWarning::getDataTypeWarningString(warning);
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h
deleted file mode 100644
index 24a040cce6..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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 "collectiondetails.h"
-
-#include <QAbstractTableModel>
-#include <QHash>
-
-namespace QmlDesigner {
-
-class ModelNode;
-
-class CollectionDetailsModel : public QAbstractTableModel
-{
- Q_OBJECT
-
- Q_PROPERTY(QString collectionName MEMBER m_collectionName NOTIFY collectionNameChanged)
- Q_PROPERTY(int selectedColumn READ selectedColumn WRITE selectColumn NOTIFY selectedColumnChanged)
- Q_PROPERTY(int selectedRow READ selectedRow WRITE selectRow NOTIFY selectedRowChanged)
- Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
-
-public:
- enum DataRoles { SelectedRole = Qt::UserRole + 1, DataTypeRole, ColumnDataTypeRole, DataTypeWarningRole };
- explicit CollectionDetailsModel(QObject *parent = nullptr);
-
- QHash<int, QByteArray> roleNames() const override;
- int rowCount(const QModelIndex &parent = {}) const override;
- int columnCount(const QModelIndex &parent = {}) const override;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- bool setHeaderData(int section,
- Qt::Orientation orientation,
- const QVariant &value,
- int role = Qt::EditRole) override;
- bool insertRows(int row, int count, const QModelIndex &parent = {}) override;
- bool removeColumns(int column, int count, const QModelIndex &parent = {}) override;
- bool removeRows(int row, int count, const QModelIndex &parent = {}) override;
-
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- QVariant headerData(int section,
- Qt::Orientation orientation,
- int role = Qt::DisplayRole) const override;
-
- CollectionDetails::DataType propertyDataType(int column) const;
-
- int selectedColumn() const;
- int selectedRow() const;
- Q_INVOKABLE QString propertyName(int column) const;
- Q_INVOKABLE QString propertyType(int column) const;
-
- Q_INVOKABLE bool isPropertyAvailable(const QString &name);
- Q_INVOKABLE bool addColumn(int column, const QString &name, const QString &propertyType = {});
- Q_INVOKABLE bool selectColumn(int section);
- Q_INVOKABLE bool renameColumn(int section, const QString &newValue);
- Q_INVOKABLE bool setPropertyType(int column, const QString &newValue);
- Q_INVOKABLE bool selectRow(int row);
- Q_INVOKABLE void deselectAll();
- Q_INVOKABLE QString warningToString(DataTypeWarning::Warning warning) const;
-
- void loadCollection(const ModelNode &sourceNode, const QString &collection);
- void removeCollection(const ModelNode &sourceNode, const QString &collection);
- void removeAllCollections();
- void renameCollection(const ModelNode &sourceNode, const QString &oldName, const QString &newName);
-
- Q_INVOKABLE bool saveDataStoreCollections();
- Q_INVOKABLE bool exportCollection(const QUrl &url);
-
- const CollectionDetails upToDateConstCollection(const CollectionReference &reference) const;
- bool collectionHasColumn(const CollectionReference &reference, const QString &columnName) const;
- QString getFirstColumnName(const CollectionReference &reference) const;
-
-signals:
- void collectionNameChanged(const QString &collectionName);
- void selectedColumnChanged(int);
- void selectedRowChanged(int);
- void isEmptyChanged(bool);
- void warning(const QString &title, const QString &body);
-
-private slots:
- void updateEmpty();
-
-private:
- void switchToCollection(const CollectionReference &collection);
- void closeCollectionIfSaved(const CollectionReference &collection);
- void closeCurrentCollectionIfSaved();
- void setCollectionName(const QString &newCollectionName);
- void loadJsonCollection(const QString &filePath, const QString &collection);
- void ensureSingleCell();
- QJsonDocument readJsonFile(const QUrl &url);
-
- QHash<CollectionReference, CollectionDetails> m_openedCollections;
- CollectionDetails m_currentCollection;
- bool m_isEmpty = true;
- int m_selectedColumn = -1;
- int m_selectedRow = -1;
-
- QString m_collectionName;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp
deleted file mode 100644
index f56bb36e88..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-// 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 "collectiondetailssortfiltermodel.h"
-
-#include "collectiondetailsmodel.h"
-#include "collectioneditorutils.h"
-
-#include <utils/qtcassert.h>
-
-namespace QmlDesigner {
-
-CollectionDetailsSortFilterModel::CollectionDetailsSortFilterModel(QObject *parent)
- : QSortFilterProxyModel(parent)
-{
- connect(this, &CollectionDetailsSortFilterModel::rowsInserted,
- this, &CollectionDetailsSortFilterModel::updateRowCountChanges);
- connect(this, &CollectionDetailsSortFilterModel::rowsRemoved,
- this, &CollectionDetailsSortFilterModel::updateRowCountChanges);
- connect(this, &CollectionDetailsSortFilterModel::modelReset,
- this, &CollectionDetailsSortFilterModel::updateRowCountChanges);
-
- setDynamicSortFilter(true);
-}
-
-void CollectionDetailsSortFilterModel::setSourceModel(CollectionDetailsModel *model)
-{
- m_source = model;
- Super::setSourceModel(model);
- connect(m_source, &CollectionDetailsModel::selectedColumnChanged,
- this, &CollectionDetailsSortFilterModel::updateSelectedColumn);
-
- connect(m_source, &CollectionDetailsModel::selectedRowChanged,
- this, &CollectionDetailsSortFilterModel::updateSelectedRow);
-}
-
-int CollectionDetailsSortFilterModel::selectedRow() const
-{
- QTC_ASSERT(m_source, return -1);
-
- return mapFromSource(m_source->index(m_source->selectedRow(), 0)).row();
-}
-
-int CollectionDetailsSortFilterModel::selectedColumn() const
-{
- QTC_ASSERT(m_source, return -1);
-
- return mapFromSource(m_source->index(0, m_source->selectedColumn())).column();
-}
-
-bool CollectionDetailsSortFilterModel::selectRow(int row)
-{
- QTC_ASSERT(m_source, return false);
-
- return m_source->selectRow(mapToSource(index(row, 0)).row());
-}
-
-bool CollectionDetailsSortFilterModel::selectColumn(int column)
-{
- QTC_ASSERT(m_source, return false);
-
- return m_source->selectColumn(mapToSource(index(0, column)).column());
-}
-
-CollectionDetailsSortFilterModel::~CollectionDetailsSortFilterModel() = default;
-
-bool CollectionDetailsSortFilterModel::filterAcceptsRow(int sourceRow,
- const QModelIndex &sourceParent) const
-{
- QTC_ASSERT(m_source, return false);
- QModelIndex sourceIndex(m_source->index(sourceRow, 0, sourceParent));
- return sourceIndex.isValid();
-}
-
-bool CollectionDetailsSortFilterModel::lessThan(const QModelIndex &sourceleft,
- const QModelIndex &sourceRight) const
-{
- QTC_ASSERT(m_source, return false);
-
- if (sourceleft.column() == sourceRight.column()) {
- int column = sourceleft.column();
- CollectionDetails::DataType columnType = m_source->propertyDataType(column);
- return CollectionEditorUtils::variantIslessThan(sourceleft.data(),
- sourceRight.data(),
- columnType);
- }
-
- return false;
-}
-
-void CollectionDetailsSortFilterModel::updateEmpty()
-{
- bool newValue = rowCount() == 0;
- if (m_isEmpty != newValue) {
- m_isEmpty = newValue;
- emit isEmptyChanged(m_isEmpty);
- }
-}
-
-void CollectionDetailsSortFilterModel::updateSelectedRow()
-{
- const int upToDateSelectedRow = selectedRow();
- if (m_selectedRow == upToDateSelectedRow)
- return;
-
- const int rows = rowCount();
- const int columns = columnCount();
- const int previousRow = m_selectedRow;
-
- m_selectedRow = upToDateSelectedRow;
- emit this->selectedRowChanged(m_selectedRow);
-
- auto notifySelectedDataChanged = [this, rows, columns](int notifyingRow) {
- if (notifyingRow > -1 && notifyingRow < rows && columns) {
- emit dataChanged(index(notifyingRow, 0),
- index(notifyingRow, columns - 1),
- {CollectionDetailsModel::SelectedRole});
- }
- };
-
- notifySelectedDataChanged(previousRow);
- notifySelectedDataChanged(m_selectedRow);
-}
-
-void CollectionDetailsSortFilterModel::updateSelectedColumn()
-{
- const int upToDateSelectedColumn = selectedColumn();
- if (m_selectedColumn == upToDateSelectedColumn)
- return;
-
- const int rows = rowCount();
- const int columns = columnCount();
- const int previousColumn = m_selectedColumn;
-
- m_selectedColumn = upToDateSelectedColumn;
- emit this->selectedColumnChanged(m_selectedColumn);
-
- auto notifySelectedDataChanged = [this, rows, columns](int notifyingCol) {
- if (notifyingCol > -1 && notifyingCol < columns && rows) {
- emit dataChanged(index(0, notifyingCol),
- index(rows - 1, notifyingCol),
- {CollectionDetailsModel::SelectedRole});
- }
- };
-
- notifySelectedDataChanged(previousColumn);
- notifySelectedDataChanged(m_selectedColumn);
-}
-
-void CollectionDetailsSortFilterModel::updateRowCountChanges()
-{
- updateEmpty();
- updateSelectedRow();
- invalidate();
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.h
deleted file mode 100644
index 93305f3ca2..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailssortfiltermodel.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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 <QSortFilterProxyModel>
-
-namespace QmlDesigner {
-
-class CollectionDetailsModel;
-
-class CollectionDetailsSortFilterModel : public QSortFilterProxyModel
-{
- Q_OBJECT
-
- Q_PROPERTY(int selectedColumn READ selectedColumn WRITE selectColumn NOTIFY selectedColumnChanged)
- Q_PROPERTY(int selectedRow READ selectedRow WRITE selectRow NOTIFY selectedRowChanged)
- Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
-
- using Super = QSortFilterProxyModel;
-
-public:
- explicit CollectionDetailsSortFilterModel(QObject *parent = nullptr);
- virtual ~CollectionDetailsSortFilterModel();
-
- void setSourceModel(CollectionDetailsModel *model);
-
- int selectedRow() const;
- int selectedColumn() const;
-
- Q_INVOKABLE bool selectRow(int row);
- Q_INVOKABLE bool selectColumn(int column);
-
-signals:
- void selectedColumnChanged(int);
- void selectedRowChanged(int);
- void isEmptyChanged(bool);
-
-protected:
- using Super::setSourceModel;
- bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
- bool lessThan(const QModelIndex &sourceleft, const QModelIndex &sourceRight) const override;
-
-private:
- void updateEmpty();
- void updateSelectedRow();
- void updateSelectedColumn();
- void updateRowCountChanges();
-
- QPointer<CollectionDetailsModel> m_source;
- int m_selectedColumn = -1;
- int m_selectedRow = -1;
- bool m_isEmpty = true;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h
deleted file mode 100644
index 76524762ed..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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
-
-namespace QmlDesigner::CollectionEditorConstants {
-
-enum class SourceFormat { Unknown, Json };
-
-inline constexpr char SOURCEFILE_PROPERTY[] = "source";
-inline constexpr char ALLMODELS_PROPERTY[] = "allModels";
-inline constexpr char JSONCHILDMODELNAME_PROPERTY[] = "modelName";
-
-inline constexpr char COLLECTIONMODEL_IMPORT[] = "QtQuick.Studio.Utils";
-inline constexpr char JSONCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Utils.JsonListModel";
-inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel";
-inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData";
-
-} // namespace QmlDesigner::CollectionEditorConstants
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp
deleted file mode 100644
index 4725987f12..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-// 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 "collectioneditorutils.h"
-
-#include "model.h"
-#include "nodemetainfo.h"
-#include "propertymetainfo.h"
-
-#include <coreplugin/documentmanager.h>
-#include <coreplugin/icore.h>
-#include <projectexplorer/project.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectmanager.h>
-#include <qmljs/qmljsmodelmanagerinterface.h>
-#include <utils/qtcassert.h>
-
-#include <variant>
-
-#include <QColor>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QJsonValue>
-#include <QUrl>
-
-using DataType = QmlDesigner::CollectionDetails::DataType;
-
-namespace {
-
-using CollectionDataVariant = std::variant<QString, bool, double, int, QUrl, QColor>;
-
-inline bool operator<(const QColor &a, const QColor &b)
-{
- return a.name(QColor::HexArgb) < b.name(QColor::HexArgb);
-}
-
-inline CollectionDataVariant valueToVariant(const QVariant &value, DataType type)
-{
- switch (type) {
- case DataType::String:
- return value.toString();
- case DataType::Real:
- return value.toDouble();
- case DataType::Integer:
- return value.toInt();
- case DataType::Boolean:
- return value.toBool();
- case DataType::Color:
- return value.value<QColor>();
- case DataType::Image:
- case DataType::Url:
- return value.value<QUrl>();
- default:
- return false;
- }
-}
-
-struct LessThanVisitor
-{
- template<typename T1, typename T2>
- bool operator()(const T1 &a, const T2 &b) const
- {
- return CollectionDataVariant(a).index() < CollectionDataVariant(b).index();
- }
-
- template<typename T>
- bool operator()(const T &a, const T &b) const
- {
- return a < b;
- }
-};
-
-Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName)
-{
- QDirIterator it(path.toString(), QDirIterator::Subdirectories);
-
- while (it.hasNext()) {
- QFileInfo file(it.next());
- if (file.isDir())
- continue;
-
- if (file.fileName() == fileName)
- return Utils::FilePath::fromFileInfo(file);
- }
- return {};
-}
-
-Utils::FilePath dataStoreDir()
-{
- using Utils::FilePath;
- ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject();
-
- if (!currentProject)
- return {};
-
- return currentProject->projectDirectory().pathAppended("/imports/"
- + currentProject->displayName());
-}
-
-inline Utils::FilePath collectionPath(const QString &filePath)
-{
- return dataStoreDir().pathAppended("/" + filePath);
-}
-
-inline Utils::FilePath qmlDirFilePath()
-{
- return collectionPath("qmldir");
-}
-
-} // namespace
-
-namespace QmlDesigner::CollectionEditorUtils {
-
-bool variantIslessThan(const QVariant &a, const QVariant &b, DataType type)
-{
- return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type));
-}
-
-QString getSourceCollectionType(const ModelNode &node)
-{
- using namespace QmlDesigner;
- if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
- return "json";
-
- return {};
-}
-
-Utils::FilePath dataStoreJsonFilePath()
-{
- return collectionPath("models.json");
-}
-
-Utils::FilePath dataStoreQmlFilePath()
-{
- return collectionPath("DataStore.qml");
-}
-
-bool canAcceptCollectionAsModel(const ModelNode &node)
-{
- const NodeMetaInfo nodeMetaInfo = node.metaInfo();
- if (!nodeMetaInfo.isValid())
- return false;
-
- const PropertyMetaInfo modelProperty = nodeMetaInfo.property("model");
- if (!modelProperty.isValid())
- return false;
-
- return modelProperty.isWritable() && !modelProperty.isPrivate()
- && modelProperty.propertyType().isVariant();
-}
-
-bool hasTextRoleProperty(const ModelNode &node)
-{
- const NodeMetaInfo nodeMetaInfo = node.metaInfo();
- if (!nodeMetaInfo.isValid())
- return false;
-
- const PropertyMetaInfo textRoleProperty = nodeMetaInfo.property("textRole");
- if (!textRoleProperty.isValid())
- return false;
-
- return textRoleProperty.isWritable() && !textRoleProperty.isPrivate()
- && textRoleProperty.propertyType().isString();
-}
-
-QString getSourceCollectionPath(const ModelNode &dataStoreNode)
-{
- using Utils::FilePath;
- if (!dataStoreNode.isValid())
- return {};
-
- const FilePath expectedFile = dataStoreJsonFilePath();
-
- if (expectedFile.exists())
- return expectedFile.toFSPathString();
-
- return {};
-}
-
-bool isDataStoreNode(const ModelNode &dataStoreNode)
-{
- using Utils::FilePath;
-
- if (!dataStoreNode.isValid())
- return false;
-
- const FilePath expectedFile = dataStoreQmlFilePath();
-
- if (!expectedFile.exists())
- return false;
-
- FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile());
-
- return modelPath.isSameFile(expectedFile);
-}
-
-bool ensureDataStoreExists(bool &justCreated)
-{
- using Utils::FilePath;
- using Utils::FileReader;
- using Utils::FileSaver;
-
- FilePath qmlDestinationPath = dataStoreQmlFilePath();
- justCreated = false;
-
- auto extractDependency = [&justCreated](const FilePath &filePath) -> bool {
- if (filePath.exists())
- return true;
-
- const QString templateFileName = filePath.fileName() + u".tpl";
- const FilePath templatePath = findFile(Core::ICore::resourcePath(), templateFileName);
- if (!templatePath.exists()) {
- qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist";
- return false;
- }
-
- if (!filePath.parentDir().ensureWritableDir()) {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot create directory"
- << filePath.parentDir();
- return false;
- }
-
- if (templatePath.copyFile(filePath)) {
- justCreated = true;
- return true;
- }
-
- qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath;
- return false;
- };
-
- if (!extractDependency(dataStoreJsonFilePath()))
- return false;
-
- if (!extractDependency(collectionPath("data.json")))
- return false;
-
- if (!extractDependency(collectionPath("JsonData.qml")))
- return false;
-
- if (!qmlDestinationPath.exists()) {
- if (qmlDestinationPath.ensureExistingFile()) {
- justCreated = true;
- } else {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File";
- return false;
- }
- }
-
- FilePath qmlDirPath = qmlDirFilePath();
- qmlDirPath.ensureExistingFile();
-
- FileReader qmlDirReader;
- if (!qmlDirReader.fetch(qmlDirPath)) {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the qmldir";
- return false;
- }
-
- QByteArray qmlDirContent = qmlDirReader.data();
- const QList<QByteArray> qmlDirLines = qmlDirContent.split('\n');
- for (const QByteArray &line : qmlDirLines) {
- if (line.startsWith("singleton DataStore "))
- return true;
- }
-
- if (!qmlDirContent.isEmpty() && qmlDirContent.back() != '\n')
- qmlDirContent.append("\n");
- qmlDirContent.append("singleton DataStore 1.0 DataStore.qml\n");
-
- FileSaver qmlDirSaver(qmlDirPath);
- qmlDirSaver.write(qmlDirContent);
-
- if (qmlDirSaver.finalize()) {
- justCreated = true;
- return true;
- }
-
- qWarning() << Q_FUNC_INFO << __LINE__ << "Can't write to the qmldir file";
- return false;
-}
-
-QJsonObject defaultCollection()
-{
- QJsonObject collectionObject;
-
- QJsonArray columns;
- QJsonObject defaultColumn;
- defaultColumn.insert("name", "Column 1");
- defaultColumn.insert("type", "string");
- columns.append(defaultColumn);
-
- QJsonArray collectionData;
- QJsonArray cellData;
- cellData.append(QString{});
- collectionData.append(cellData);
-
- collectionObject.insert("columns", columns);
- collectionObject.insert("data", collectionData);
-
- return collectionObject;
-}
-
-QJsonObject defaultColorCollection()
-{
- using Utils::FilePath;
- using Utils::FileReader;
- const FilePath templatePath = findFile(Core::ICore::resourcePath(), "Colors.json.tpl");
-
- FileReader fileReader;
- if (!fileReader.fetch(templatePath)) {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the file" << templatePath;
- return {};
- }
-
- QJsonParseError parseError;
- const CollectionDetails collection = CollectionDetails::fromImportedJson(fileReader.data(),
- &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- qWarning() << Q_FUNC_INFO << __LINE__ << "Error in template file" << parseError.errorString();
- return {};
- }
-
- return collection.toLocalJson();
-}
-
-bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString)
-{
- Core::FileChangeBlocker fileBlocker(path);
- Utils::FileSaver jsonFile(path);
- if (jsonFile.write(document.toJson()))
- jsonFile.finalize();
- if (errorString)
- *errorString = jsonFile.errorString();
-
- return !jsonFile.hasError();
-}
-
-} // namespace QmlDesigner::CollectionEditorUtils
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h
deleted file mode 100644
index 355addf59b..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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 "collectiondetails.h"
-#include "collectioneditorconstants.h"
-
-QT_BEGIN_NAMESPACE
-class QJsonArray;
-class QJsonObject;
-QT_END_NAMESPACE
-
-namespace Utils {
-class FilePath;
-}
-
-namespace QmlDesigner::CollectionEditorUtils {
-
-bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type);
-
-QString getSourceCollectionType(const QmlDesigner::ModelNode &node);
-
-QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode);
-
-Utils::FilePath dataStoreJsonFilePath();
-
-Utils::FilePath dataStoreQmlFilePath();
-
-bool writeToJsonDocument(const Utils::FilePath &path,
- const QJsonDocument &document,
- QString *errorString = nullptr);
-
-bool isDataStoreNode(const ModelNode &dataStoreNode);
-
-bool ensureDataStoreExists(bool &justCreated);
-
-bool canAcceptCollectionAsModel(const ModelNode &node);
-
-bool hasTextRoleProperty(const ModelNode &node);
-
-QJsonObject defaultCollection();
-
-QJsonObject defaultColorCollection();
-
-} // namespace QmlDesigner::CollectionEditorUtils
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp
deleted file mode 100644
index d27a077d2a..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp
+++ /dev/null
@@ -1,521 +0,0 @@
-// 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 "collectionlistmodel.h"
-
-#include "collectioneditorutils.h"
-
-#include <utils/algorithm.h>
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-
-namespace {
-
-template<typename ValueType>
-bool containsItem(const std::initializer_list<ValueType> &container, const ValueType &value)
-{
- auto begin = std::cbegin(container);
- auto end = std::cend(container);
-
- auto it = std::find(begin, end, value);
- return it != end;
-}
-
-bool sameCollectionNames(QStringList a, QStringList b)
-{
- if (a.size() != b.size())
- return false;
-
- a.sort(Qt::CaseSensitive);
- b.sort(Qt::CaseSensitive);
-
- return a == b;
-}
-
-} // namespace
-
-namespace QmlDesigner {
-
-CollectionListModel::CollectionListModel()
- : QAbstractListModel()
-{
- connect(this, &CollectionListModel::modelReset, this, &CollectionListModel::updateEmpty);
- connect(this, &CollectionListModel::rowsRemoved, this, &CollectionListModel::updateEmpty);
- connect(this, &CollectionListModel::rowsInserted, this, &CollectionListModel::updateEmpty);
-}
-
-QHash<int, QByteArray> CollectionListModel::roleNames() const
-{
- static QHash<int, QByteArray> roles;
- if (roles.isEmpty()) {
- roles.insert(Super::roleNames());
- roles.insert({
- {IdRole, "collectionId"},
- {NameRole, "collectionName"},
- {SelectedRole, "collectionIsSelected"},
- });
- }
- return roles;
-}
-
-int CollectionListModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
-{
- return m_data.count();
-}
-
-bool CollectionListModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (!index.isValid())
- return false;
-
- if (containsItem<int>({Qt::EditRole, Qt::DisplayRole, NameRole}, role)) {
- if (collectionExists(value.toString()))
- return false;
-
- QString oldName = collectionNameAt(index.row());
- bool nameChanged = value != data(index);
- if (nameChanged) {
- QString newName = value.toString();
- QString errorString;
- if (renameCollectionInDataStore(oldName, newName, errorString)) {
- m_data.replace(index.row(), newName);
- emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, NameRole});
- emit this->collectionNameChanged(oldName, newName);
- if (m_selectedCollectionName == oldName)
- updateSelectedCollectionName();
- return true;
- } else {
- emit warning("Rename Model", errorString);
- return false;
- }
- }
- } else if (role == SelectedRole) {
- if (value.toBool() != index.data(SelectedRole).toBool()) {
- setSelectedIndex(value.toBool() ? index.row() : -1);
- return true;
- }
- }
- return false;
-}
-
-bool CollectionListModel::removeRows(int row, int count, const QModelIndex &parent)
-{
- const int rows = rowCount(parent);
- if (row >= rows)
- return false;
-
- row = qBound(0, row, rows - 1);
- count = qBound(0, count, rows - row);
-
- if (count < 1)
- return false;
-
- QString errorString;
- QStringList removedCollections = m_data.mid(row, count);
- if (removeCollectionsFromDataStore(removedCollections, errorString)) {
- beginRemoveRows(parent, row, row + count - 1);
- m_data.remove(row, count);
- endRemoveRows();
-
- emit collectionsRemoved(removedCollections);
- if (m_selectedIndex >= row) {
- int preferredIndex = m_selectedIndex - count;
- if (preferredIndex < 0) // If the selected item is deleted, reset selection
- selectCollectionIndex(-1);
- selectCollectionIndex(preferredIndex, true);
- }
-
- updateSelectedCollectionName();
- return true;
- } else {
- emit warning("Remove Model", errorString);
- return false;
- }
-}
-
-QVariant CollectionListModel::data(const QModelIndex &index, int role) const
-{
- QTC_ASSERT(index.isValid(), return {});
-
- switch (role) {
- case IdRole:
- return index.row();
- case SelectedRole:
- return index.row() == m_selectedIndex;
- case NameRole:
- default:
- return m_data.at(index.row());
- }
-}
-
-void CollectionListModel::setDataStoreNode(const ModelNode &dataStoreNode)
-{
- m_dataStoreNode = dataStoreNode;
- update();
-}
-
-int CollectionListModel::selectedIndex() const
-{
- return m_selectedIndex;
-}
-
-ModelNode CollectionListModel::sourceNode() const
-{
- return m_dataStoreNode;
-}
-
-bool CollectionListModel::collectionExists(const QString &collectionName) const
-{
- return m_data.contains(collectionName);
-}
-
-QStringList CollectionListModel::collections() const
-{
- return m_data;
-}
-
-QString CollectionListModel::getUniqueCollectionName(const QString &baseName) const
-{
- QString name = baseName.isEmpty() ? "Model" : baseName;
- QString nameTemplate = name + "%1";
-
- int num = 0;
-
- while (collectionExists(name))
- name = nameTemplate.arg(++num, 2, 10, QChar('0'));
-
- return name;
-}
-
-void CollectionListModel::selectCollectionIndex(int idx, bool selectAtLeastOne)
-{
- int collectionCount = m_data.size();
- int preferredIndex = -1;
- if (collectionCount) {
- if (selectAtLeastOne)
- preferredIndex = std::max(0, std::min(idx, collectionCount - 1));
- else if (idx > -1 && idx < collectionCount)
- preferredIndex = idx;
- }
-
- setSelectedIndex(preferredIndex);
-}
-
-void CollectionListModel::selectCollectionName(QString collectionName, bool selectAtLeastOne)
-{
- int idx = m_data.indexOf(collectionName);
- if (idx > -1)
- selectCollectionIndex(idx);
- else
- selectCollectionIndex(selectedIndex(), selectAtLeastOne);
-
- collectionName = collectionNameAt(selectedIndex());
- if (m_selectedCollectionName == collectionName)
- return;
-
- m_selectedCollectionName = collectionName;
- emit selectedCollectionNameChanged(m_selectedCollectionName);
-}
-
-QString CollectionListModel::collectionNameAt(int idx) const
-{
- return index(idx).data(NameRole).toString();
-}
-
-QString CollectionListModel::selectedCollectionName() const
-{
- return m_selectedCollectionName;
-}
-
-void CollectionListModel::update()
-{
- using Utils::FilePath;
- using Utils::FileReader;
-
- FileReader sourceFile;
- QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(m_dataStoreNode);
- FilePath path = FilePath::fromUserInput(sourceFileAddress);
- bool fileRead = false;
- if (path.exists()) {
- fileRead = sourceFile.fetch(path);
- if (!fileRead)
- emit this->warning(tr("Model Editor"),
- tr("Cannot read the dataStore file\n%1").arg(sourceFile.errorString()));
- }
-
- QStringList collectionNames;
- if (fileRead) {
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(sourceFile.data(), &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- emit this->warning(tr("Model Editor"),
- tr("There is an error in the JSON file.\n%1")
- .arg(parseError.errorString()));
- } else {
- if (document.isObject())
- collectionNames = document.object().toVariantMap().keys();
- else
- emit this->warning(tr("Model Editor"), tr("The JSON document be an object."));
- }
- }
-
- if (!sameCollectionNames(m_data, collectionNames)) {
- QString prevSelectedCollection = selectedIndex() > -1 ? m_data.at(selectedIndex())
- : QString();
- beginResetModel();
- m_data = collectionNames;
- endResetModel();
- emit this->collectionNamesChanged(collections());
- selectCollectionName(prevSelectedCollection, true);
- }
-}
-
-bool CollectionListModel::addCollection(const QString &collectionName,
- const QJsonObject &localCollection)
-{
- if (collectionExists(collectionName)) {
- emit warning(tr("Add Model"), tr("Model \"%1\" already exists.").arg(collectionName));
- return false;
- }
-
- QString errorMessage;
- if (addCollectionToDataStore(collectionName, localCollection, errorMessage)) {
- int row = rowCount();
- beginInsertRows({}, row, row);
- m_data.append(collectionName);
- endInsertRows();
-
- selectCollectionName(collectionName);
- emit collectionAdded(collectionName);
- return true;
- } else {
- emit warning(tr("Add Collection"), errorMessage);
- }
- return false;
-}
-
-void CollectionListModel::setSelectedIndex(int idx)
-{
- idx = (idx > -1 && idx < rowCount()) ? idx : -1;
-
- if (m_selectedIndex != idx) {
- QModelIndex previousIndex = index(m_selectedIndex);
- QModelIndex newIndex = index(idx);
-
- m_selectedIndex = idx;
-
- if (previousIndex.isValid())
- emit dataChanged(previousIndex, previousIndex, {SelectedRole});
-
- if (newIndex.isValid())
- emit dataChanged(newIndex, newIndex, {SelectedRole});
-
- emit selectedIndexChanged(idx);
- updateSelectedCollectionName();
- }
-}
-
-bool CollectionListModel::removeCollectionsFromDataStore(const QStringList &removedCollections,
- QString &error) const
-{
- using Utils::FilePath;
- using Utils::FileReader;
- auto setErrorAndReturn = [&error](const QString &msg) -> bool {
- error = msg;
- return false;
- };
-
- if (m_dataStoreNode.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
- return setErrorAndReturn(tr("Invalid node type"));
-
- QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(m_dataStoreNode);
-
- QFileInfo sourceFileInfo(sourceFileAddress);
- if (!sourceFileInfo.isFile())
- return setErrorAndReturn(tr("The selected node has an invalid source address"));
-
- FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
- FileReader jsonFile;
- if (!jsonFile.fetch(jsonPath)) {
- return setErrorAndReturn(tr("Can't read file \"%1\".\n%2")
- .arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
- }
-
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- return setErrorAndReturn(tr("\"%1\" is corrupted.\n%2")
- .arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
- }
-
- if (document.isObject()) {
- QJsonObject rootObject = document.object();
-
- for (const QString &collectionName : removedCollections) {
- bool sourceContainsCollection = rootObject.contains(collectionName);
- if (sourceContainsCollection) {
- rootObject.remove(collectionName);
- } else {
- setErrorAndReturn(tr("The model group doesn't contain the model name (%1).")
- .arg(sourceContainsCollection));
- }
- }
-
- document.setObject(rootObject);
-
- if (CollectionEditorUtils::writeToJsonDocument(jsonPath, document)) {
- error.clear();
- return true;
- } else {
- return setErrorAndReturn(
- tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
- }
- } else {
- return setErrorAndReturn(tr("Local Json Document should be an object"));
- }
-
- return false;
-}
-
-bool CollectionListModel::renameCollectionInDataStore(const QString &oldName,
- const QString &newName,
- QString &error)
-{
- using Utils::FilePath;
- using Utils::FileReader;
- using Utils::FileSaver;
-
- auto setErrorAndReturn = [&error](const QString &msg) -> bool {
- error = msg;
- return false;
- };
-
- if (m_dataStoreNode.type() != CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
- return setErrorAndReturn(tr("Invalid node type"));
-
- QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(m_dataStoreNode);
-
- QFileInfo sourceFileInfo(sourceFileAddress);
- if (!sourceFileInfo.isFile())
- return setErrorAndReturn(tr("Selected node must have a valid source file address"));
-
- FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
- FileReader jsonFile;
- if (!jsonFile.fetch(jsonPath)) {
- return setErrorAndReturn(
- tr("Can't read \"%1\".\n%2").arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
- }
-
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- return setErrorAndReturn(tr("\"%1\" is corrupted.\n%2")
- .arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
- }
-
- if (document.isObject()) {
- QJsonObject rootObject = document.object();
-
- bool collectionContainsOldName = rootObject.contains(oldName);
- bool collectionContainsNewName = rootObject.contains(newName);
-
- if (!collectionContainsOldName) {
- return setErrorAndReturn(
- tr("The model group doesn't contain the old model name (%1).").arg(oldName));
- }
-
- if (collectionContainsNewName) {
- return setErrorAndReturn(
- tr("The model name \"%1\" already exists in the model group.").arg(newName));
- }
-
- QJsonValue oldValue = rootObject.value(oldName);
- rootObject.insert(newName, oldValue);
- rootObject.remove(oldName);
-
- document.setObject(rootObject);
-
- if (CollectionEditorUtils::writeToJsonDocument(jsonPath, document)) {
- error.clear();
- return true;
- } else {
- return setErrorAndReturn(
- tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
- }
- } else {
- return setErrorAndReturn(tr("Local Json Document should be an object"));
- }
- return false;
-}
-
-bool CollectionListModel::addCollectionToDataStore(const QString &collectionName,
- const QJsonObject &localCollection,
- QString &errorString) const
-{
- using Utils::FilePath;
- using Utils::FileReader;
- auto returnError = [&errorString](const QString &msg) -> bool {
- errorString = msg;
- return false;
- };
-
- if (collectionExists(collectionName))
- return returnError(tr("A model with the identical name already exists."));
-
- QString sourceFileAddress = CollectionEditorUtils::getSourceCollectionPath(m_dataStoreNode);
-
- QFileInfo sourceFileInfo(sourceFileAddress);
- if (!sourceFileInfo.isFile())
- return returnError(tr("Selected node must have a valid source file address"));
-
- FilePath jsonPath = FilePath::fromUserInput(sourceFileAddress);
- FileReader jsonFile;
- if (!jsonFile.fetch(jsonPath)) {
- return returnError(
- tr("Can't read \"%1\".\n%2").arg(sourceFileInfo.absoluteFilePath(), jsonFile.errorString()));
- }
-
- QJsonParseError parseError;
- QJsonDocument document = QJsonDocument::fromJson(jsonFile.data(), &parseError);
- if (parseError.error != QJsonParseError::NoError)
- return returnError(tr("\"%1\" is corrupted.\n%2")
- .arg(sourceFileInfo.absoluteFilePath(), parseError.errorString()));
-
- if (document.isObject()) {
- QJsonObject sourceObject = document.object();
- sourceObject.insert(collectionName, localCollection);
- document.setObject(sourceObject);
-
- if (CollectionEditorUtils::writeToJsonDocument(jsonPath, document))
- return true;
- else
- return returnError(tr("Can't write to \"%1\".").arg(sourceFileInfo.absoluteFilePath()));
- } else {
- return returnError(tr("JSON document type should be an object containing models."));
- }
-}
-
-void CollectionListModel::updateEmpty()
-{
- bool isEmptyNow = m_data.isEmpty();
- if (m_isEmpty != isEmptyNow) {
- m_isEmpty = isEmptyNow;
- emit isEmptyChanged(m_isEmpty);
-
- if (m_isEmpty)
- setSelectedIndex(-1);
- }
-}
-
-void CollectionListModel::updateSelectedCollectionName()
-{
- QString selectedCollectionByIndex = collectionNameAt(selectedIndex());
- if (selectedCollectionByIndex != selectedCollectionName())
- selectCollectionName(selectedCollectionByIndex);
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h
deleted file mode 100644
index 7902fd5909..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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 <QAbstractListModel>
-#include <QHash>
-
-#include "modelnode.h"
-
-namespace QmlDesigner {
-
-class CollectionListModel : public QAbstractListModel
-{
- Q_OBJECT
-
- Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
- Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
- Q_PROPERTY(QString selectedCollectionName
- READ selectedCollectionName
- WRITE selectCollectionName
- NOTIFY selectedCollectionNameChanged)
-
-public:
- enum Roles { IdRole = Qt::UserRole + 1, NameRole, SelectedRole };
-
- explicit CollectionListModel();
- QHash<int, QByteArray> roleNames() const override;
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role) override;
- bool removeRows(int row, int count, const QModelIndex &parent = {}) override;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- void setDataStoreNode(const ModelNode &dataStoreNode = {});
-
- Q_INVOKABLE int selectedIndex() const;
- Q_INVOKABLE ModelNode sourceNode() const;
- Q_INVOKABLE bool collectionExists(const QString &collectionName) const;
- Q_INVOKABLE QStringList collections() const;
- Q_INVOKABLE QString getUniqueCollectionName(const QString &baseName = {}) const;
-
- void selectCollectionIndex(int idx, bool selectAtLeastOne = false);
- void selectCollectionName(QString collectionName, bool selectAtLeastOne = false);
- QString collectionNameAt(int idx) const;
- QString selectedCollectionName() const;
-
- void update();
- bool addCollection(const QString &collectionName, const QJsonObject &localCollection);
-
-signals:
- void selectedIndexChanged(int idx);
- void isEmptyChanged(bool);
- void collectionNameChanged(const QString &oldName, const QString &newName);
- void collectionNamesChanged(const QStringList &collectionNames);
- void collectionsRemoved(const QStringList &names);
- void collectionAdded(const QString &name);
- void selectedCollectionNameChanged(const QString &selectedCollectionName);
- void warning(const QString &title, const QString &body);
-
-private:
- void setSelectedIndex(int idx);
- bool removeCollectionsFromDataStore(const QStringList &removedCollections, QString &error) const;
- bool renameCollectionInDataStore(const QString &oldName, const QString &newName, QString &error);
- bool addCollectionToDataStore(const QString &collectionName,
- const QJsonObject &localCollection,
- QString &errorString) const;
-
- void updateEmpty();
- void updateSelectedCollectionName();
-
- using Super = QAbstractListModel;
- int m_selectedIndex = -1;
- bool m_isEmpty = false;
- ModelNode m_dataStoreNode;
- QString m_selectedCollectionName;
- QStringList m_data;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp
deleted file mode 100644
index f6ec821fde..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp
+++ /dev/null
@@ -1,469 +0,0 @@
-// 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 "collectionview.h"
-
-#include "collectiondatatypemodel.h"
-#include "collectiondetailsmodel.h"
-#include "collectioneditorconstants.h"
-#include "collectioneditorutils.h"
-#include "collectionlistmodel.h"
-#include "collectionwidget.h"
-#include "datastoremodelnode.h"
-#include "designmodecontext.h"
-#include "nodeabstractproperty.h"
-#include "nodemetainfo.h"
-#include "nodeproperty.h"
-#include "qmldesignerplugin.h"
-#include "variantproperty.h"
-
-#include <projectexplorer/project.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectmanager.h>
-#include <qmljs/qmljsmodelmanagerinterface.h>
-
-#include <coreplugin/icore.h>
-#include <utils/algorithm.h>
-#include <utils/qtcassert.h>
-
-#include <QTimer>
-
-namespace {
-
-bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
-{
- return node.metaInfo().isQtQuickStudioUtilsJsonListModel();
-}
-
-inline void setVariantPropertyValue(const QmlDesigner::ModelNode &node,
- const QmlDesigner::PropertyName &propertyName,
- const QVariant &value)
-{
- QmlDesigner::VariantProperty property = node.variantProperty(propertyName);
- property.setValue(value);
-}
-
-inline void setBindingPropertyExpression(const QmlDesigner::ModelNode &node,
- const QmlDesigner::PropertyName &propertyName,
- const QString &expression)
-{
- QmlDesigner::BindingProperty property = node.bindingProperty(propertyName);
- property.setExpression(expression);
-}
-
-} // namespace
-
-namespace QmlDesigner {
-
-CollectionView::CollectionView(ExternalDependenciesInterface &externalDependencies)
- : AbstractView(externalDependencies)
- , m_dataStore(std::make_unique<DataStoreModelNode>())
-
-{
- connect(ProjectExplorer::ProjectManager::instance(),
- &ProjectExplorer::ProjectManager::startupProjectChanged, this, [this] {
- resetDataStoreNode();
- if (m_widget.get())
- m_widget->collectionDetailsModel()->removeAllCollections();
- });
-}
-
-bool CollectionView::hasWidget() const
-{
- return true;
-}
-
-QmlDesigner::WidgetInfo CollectionView::widgetInfo()
-{
- if (m_widget.isNull()) {
- m_widget = new CollectionWidget(this);
- m_widget->setMinimumSize(m_widget->minimumSizeHint());
-
- auto collectionEditorContext = new Internal::CollectionEditorContext(m_widget.data());
- Core::ICore::addContextObject(collectionEditorContext);
- CollectionListModel *listModel = m_widget->listModel().data();
-
- connect(listModel,
- &CollectionListModel::selectedCollectionNameChanged,
- this,
- [this](const QString &collection) {
- m_widget->collectionDetailsModel()->loadCollection(dataStoreNode(), collection);
- });
-
- connect(listModel, &CollectionListModel::isEmptyChanged, this, [this](bool isEmpty) {
- if (isEmpty)
- m_widget->collectionDetailsModel()->loadCollection({}, {});
- });
-
- connect(listModel, &CollectionListModel::modelReset, this, [this] {
- CollectionListModel *listModel = m_widget->listModel().data();
- if (listModel->sourceNode() == m_dataStore->modelNode())
- m_dataStore->setCollectionNames(listModel->collections());
- });
-
- connect(listModel,
- &CollectionListModel::collectionAdded,
- this,
- [this](const QString &collectionName) { m_dataStore->addCollection(collectionName); });
-
- connect(listModel,
- &CollectionListModel::collectionNameChanged,
- this,
- [this](const QString &oldName, const QString &newName) {
- m_dataStore->renameCollection(oldName, newName);
- m_widget->collectionDetailsModel()->renameCollection(dataStoreNode(),
- oldName,
- newName);
- });
-
- connect(listModel,
- &CollectionListModel::collectionsRemoved,
- this,
- [this](const QStringList &collectionNames) {
- m_dataStore->removeCollections(collectionNames);
- for (const QString &collectionName : collectionNames) {
- m_widget->collectionDetailsModel()->removeCollection(dataStoreNode(),
- collectionName);
- }
- });
- }
-
- return createWidgetInfo(m_widget.data(),
- "CollectionEditor",
- WidgetInfo::LeftPane,
- 0,
- tr("Model Editor [beta]"),
- tr("Model Editor view"));
-}
-
-void CollectionView::modelAttached(Model *model)
-{
- AbstractView::modelAttached(model);
- resetDataStoreNode();
-}
-
-void CollectionView::modelAboutToBeDetached([[maybe_unused]] Model *model)
-{
- m_libraryInfoIsUpdated = false;
- m_reloadCounter = 0;
- m_rewriterAmended = false;
- m_dataStoreTypeFound = false;
- disconnect(m_documentUpdateConnection);
- QTC_ASSERT(m_delayedTasks.isEmpty(), m_delayedTasks.clear());
- m_widget->listModel()->setDataStoreNode();
-}
-
-void CollectionView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
- [[maybe_unused]] const QList<ModelNode> &lastSelectedNodeList)
-{
- QList<ModelNode> selectedCollectionNodes = Utils::filtered(selectedNodeList,
- &isStudioCollectionModel);
-
- bool singleNonCollectionNodeSelected = selectedNodeList.size() == 1
- && selectedCollectionNodes.isEmpty();
-
- bool singleSelectedHasModelProperty = false;
- if (singleNonCollectionNodeSelected) {
- const ModelNode selectedNode = selectedNodeList.first();
- singleSelectedHasModelProperty = CollectionEditorUtils::canAcceptCollectionAsModel(
- selectedNode);
- }
-
- m_widget->setTargetNodeSelected(singleSelectedHasModelProperty);
-
- // More than one model is selected. So ignore them
- if (selectedCollectionNodes.size() > 1)
- return;
-}
-
-void CollectionView::customNotification(const AbstractView *,
- const QString &identifier,
- const QList<ModelNode> &nodeList,
- const QList<QVariant> &data)
-{
- if (identifier == QLatin1String("item_library_created_by_drop") && !nodeList.isEmpty())
- onItemLibraryNodeCreated(nodeList.first());
- else if (identifier == QLatin1String("open_collection_by_id") && !data.isEmpty())
- m_widget->openCollection(collectionNameFromDataStoreChildren(data.first().toByteArray()));
- else if (identifier == "delete_selected_collection")
- m_widget->deleteSelectedCollection();
-}
-
-void CollectionView::addResource(const QUrl &url, const QString &name)
-{
- executeInTransaction(Q_FUNC_INFO, [this, &url, &name]() {
- ensureStudioModelImport();
- QString sourceAddress;
- if (url.isLocalFile()) {
- Utils::FilePath fp = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName().parentDir();
- sourceAddress = Utils::FilePath::calcRelativePath(url.toLocalFile(),
- fp.absoluteFilePath().toString());
- } else {
- sourceAddress = url.toString();
- }
-#ifdef QDS_USE_PROJECTSTORAGE
- ModelNode resourceNode = createModelNode("JsonListModel");
-#else
- const NodeMetaInfo resourceMetaInfo = jsonCollectionMetaInfo();
- ModelNode resourceNode = createModelNode(resourceMetaInfo.typeName(),
- resourceMetaInfo.majorVersion(),
- resourceMetaInfo.minorVersion());
-#endif
- VariantProperty sourceProperty = resourceNode.variantProperty(
- CollectionEditorConstants::SOURCEFILE_PROPERTY);
- VariantProperty nameProperty = resourceNode.variantProperty("objectName");
- sourceProperty.setValue(sourceAddress);
- nameProperty.setValue(name);
- resourceNode.setIdWithoutRefactoring(model()->generateIdFromName(name, "model"));
- rootModelNode().defaultNodeAbstractProperty().reparentHere(resourceNode);
- });
-}
-
-void CollectionView::assignCollectionToNode(const QString &collectionName, const ModelNode &node)
-{
- using DataType = CollectionDetails::DataType;
- executeInTransaction("CollectionView::assignCollectionToNode", [&]() {
- m_dataStore->assignCollectionToNode(
- this,
- node,
- collectionName,
- [&](const QString &collectionName, const QString &columnName) -> bool {
- const CollectionReference reference{dataStoreNode(), collectionName};
- return m_widget->collectionDetailsModel()->collectionHasColumn(reference, columnName);
- },
- [&](const QString &collectionName) -> QString {
- const CollectionReference reference{dataStoreNode(), collectionName};
- return m_widget->collectionDetailsModel()->getFirstColumnName(reference);
- });
-
- // Create and assign a delegate to the list view item
- if (node.metaInfo().isQtQuickListView()) {
- CollectionDetails collection = m_widget->collectionDetailsModel()->upToDateConstCollection(
- {dataStoreNode(), collectionName});
-
- ModelNode rowItem(createModelNode("QtQuick.Row"));
- ::setVariantPropertyValue(rowItem, "spacing", 5);
-
- const int columnsCount = collection.columns();
- for (int column = 0; column < columnsCount; ++column) {
- const DataType dataType = collection.typeAt(column);
- const QString columnName = collection.propertyAt(column);
- ModelNode cellItem;
- if (dataType == DataType::Color) {
- cellItem = createModelNode("QtQuick.Rectangle");
- ::setBindingPropertyExpression(cellItem, "color", columnName);
- ::setVariantPropertyValue(cellItem, "height", 20);
- } else {
- cellItem = createModelNode("QtQuick.Text");
- ::setBindingPropertyExpression(cellItem, "text", columnName);
- }
- ::setVariantPropertyValue(cellItem, "width", 100);
- rowItem.defaultNodeAbstractProperty().reparentHere(cellItem);
- }
-
- NodeProperty delegateProperty = node.nodeProperty("delegate");
- // Remove the old model node if is available
- if (delegateProperty.modelNode())
- delegateProperty.modelNode().destroy();
-
- delegateProperty.setModelNode(rowItem);
- }
- });
-}
-
-void CollectionView::assignCollectionToSelectedNode(const QString &collectionName)
-{
- QTC_ASSERT(dataStoreNode() && hasSingleSelectedModelNode(), return);
- assignCollectionToNode(collectionName, singleSelectedModelNode());
-}
-
-void CollectionView::addNewCollection(const QString &collectionName, const QJsonObject &localCollection)
-{
- addTask(QSharedPointer<CollectionTask>(
- new AddCollectionTask(this, m_widget->listModel(), localCollection, collectionName)));
-}
-
-void CollectionView::openCollection(const QString &collectionName)
-{
- m_widget->openCollection(collectionName);
-}
-
-void CollectionView::registerDeclarativeType()
-{
- CollectionDetails::registerDeclarativeType();
- CollectionDataTypeModel::registerDeclarativeType();
-}
-
-void CollectionView::resetDataStoreNode()
-{
- m_dataStore->reloadModel();
-
- ModelNode dataStore = m_dataStore->modelNode();
- if (!dataStore || m_widget->listModel()->sourceNode() == dataStore)
- return;
-
- bool dataStoreSingletonFound = m_dataStoreTypeFound;
- if (!dataStoreSingletonFound && rewriterView() && rewriterView()->isAttached()) {
- const QList<QmlTypeData> types = rewriterView()->getQMLTypes();
- for (const QmlTypeData &cppTypeData : types) {
- if (cppTypeData.isSingleton && cppTypeData.typeName == "DataStore") {
- dataStoreSingletonFound = true;
- break;
- }
- }
- if (!dataStoreSingletonFound && !m_rewriterAmended) {
- rewriterView()->forceAmend();
- m_rewriterAmended = true;
- }
- }
-
- if (dataStoreSingletonFound) {
- m_widget->listModel()->setDataStoreNode(dataStore);
- m_dataStoreTypeFound = true;
-
- while (!m_delayedTasks.isEmpty())
- m_delayedTasks.takeFirst()->process();
- } else if (++m_reloadCounter < 50) {
- QTimer::singleShot(200, this, &CollectionView::resetDataStoreNode);
- } else {
- QTC_ASSERT(false, m_delayedTasks.clear());
- }
-}
-
-ModelNode CollectionView::dataStoreNode() const
-{
- return m_dataStore->modelNode();
-}
-
-void CollectionView::ensureDataStoreExists()
-{
- bool filesJustCreated = false;
- bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated);
- if (filesExist) {
- if (filesJustCreated) {
- // Force code model reset to notice changes to existing module
- auto modelManager = QmlJS::ModelManagerInterface::instance();
- if (modelManager) {
- m_libraryInfoIsUpdated = false;
-
- m_expectedDocumentUpdates.clear();
- m_expectedDocumentUpdates << CollectionEditorUtils::dataStoreQmlFilePath()
- << CollectionEditorUtils::dataStoreJsonFilePath();
-
- m_documentUpdateConnection = connect(modelManager,
- &QmlJS::ModelManagerInterface::documentUpdated,
- this,
- &CollectionView::onDocumentUpdated);
-
- modelManager->resetCodeModel();
- }
- resetDataStoreNode();
- } else {
- m_libraryInfoIsUpdated = true;
- }
- }
-}
-
-QString CollectionView::collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const
-{
- return dataStoreNode()
- .nodeProperty(childPropertyName)
- .modelNode()
- .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)
- .toVariantProperty()
- .value()
- .toString();
-}
-
-NodeMetaInfo CollectionView::jsonCollectionMetaInfo() const
-{
- return model()->metaInfo(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME);
-}
-
-void CollectionView::ensureStudioModelImport()
-{
- executeInTransaction(__FUNCTION__, [&] {
- Import import = Import::createLibraryImport(CollectionEditorConstants::COLLECTIONMODEL_IMPORT);
- try {
- if (!model()->hasImport(import, true, true))
- model()->changeImports({import}, {});
- } catch (const Exception &) {
- QTC_ASSERT(false, return);
- }
- });
-}
-
-void CollectionView::onItemLibraryNodeCreated(const ModelNode &node)
-{
- if (node.metaInfo().isQtQuickListView()) {
- addTask(QSharedPointer<CollectionTask>(
- new DropListViewTask(this, m_widget->listModel(), node)));
- }
-}
-
-void CollectionView::onDocumentUpdated(const QSharedPointer<const QmlJS::Document> &doc)
-{
- if (m_expectedDocumentUpdates.contains(doc->fileName()))
- m_expectedDocumentUpdates.remove(doc->fileName());
-
- if (m_expectedDocumentUpdates.isEmpty()) {
- disconnect(m_documentUpdateConnection);
- m_libraryInfoIsUpdated = true;
- }
-}
-
-void CollectionView::addTask(QSharedPointer<CollectionTask> task)
-{
- ensureDataStoreExists();
- if (m_dataStoreTypeFound)
- task->process();
- else if (m_dataStore->modelNode())
- m_delayedTasks << task;
-}
-
-CollectionTask::CollectionTask(CollectionView *view, CollectionListModel *listModel)
- : m_collectionView(view)
- , m_listModel(listModel)
-{}
-
-DropListViewTask::DropListViewTask(CollectionView *view,
- CollectionListModel *listModel,
- const ModelNode &node)
- : CollectionTask(view, listModel)
- , m_node(node)
-{}
-
-void DropListViewTask::process()
-{
- AbstractView *view = m_node.view();
- if (!m_node || !m_collectionView || !m_listModel || !view)
- return;
-
- const QString newCollectionName = m_listModel->getUniqueCollectionName("ListModel");
- m_listModel->addCollection(newCollectionName, CollectionEditorUtils::defaultColorCollection());
- m_collectionView->openCollection(newCollectionName);
- m_collectionView->assignCollectionToNode(newCollectionName, m_node);
-}
-
-AddCollectionTask::AddCollectionTask(CollectionView *view,
- CollectionListModel *listModel,
- const QJsonObject &localJsonObject,
- const QString &collectionName)
- : CollectionTask(view, listModel)
- , m_localJsonObject(localJsonObject)
- , m_name(collectionName)
-{}
-
-void AddCollectionTask::process()
-{
- if (!m_listModel)
- return;
-
- const QString newCollectionName = m_listModel->collectionExists(m_name)
- ? m_listModel->getUniqueCollectionName(m_name)
- : m_name;
-
- m_listModel->addCollection(newCollectionName, m_localJsonObject);
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h
deleted file mode 100644
index a4b16c4c27..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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 "abstractview.h"
-#include "datastoremodelnode.h"
-#include "modelnode.h"
-
-#include <QJsonObject>
-
-namespace QmlJS {
-class Document;
-}
-
-namespace QmlDesigner {
-
-class CollectionDetails;
-class CollectionListModel;
-class CollectionTask;
-class CollectionWidget;
-class DataStoreModelNode;
-
-class CollectionView : public AbstractView
-{
- Q_OBJECT
-
-public:
- explicit CollectionView(ExternalDependenciesInterface &externalDependencies);
-
- bool hasWidget() const override;
- WidgetInfo widgetInfo() override;
-
- void modelAttached(Model *model) override;
- void modelAboutToBeDetached(Model *model) override;
-
- void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
- const QList<ModelNode> &lastSelectedNodeList) override;
-
- void customNotification(const AbstractView *view,
- const QString &identifier,
- const QList<ModelNode> &nodeList,
- const QList<QVariant> &data) override;
-
- void addResource(const QUrl &url, const QString &name);
-
- void assignCollectionToNode(const QString &collectionName, const ModelNode &node);
- void assignCollectionToSelectedNode(const QString &collectionName);
- void addNewCollection(const QString &collectionName, const QJsonObject &localCollection);
-
- void openCollection(const QString &collectionName);
-
- static void registerDeclarativeType();
-
- void resetDataStoreNode();
- ModelNode dataStoreNode() const;
- void ensureDataStoreExists();
- QString collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const;
-
-private:
- friend class CollectionTask;
-
- NodeMetaInfo jsonCollectionMetaInfo() const;
- void ensureStudioModelImport();
- void onItemLibraryNodeCreated(const ModelNode &node);
- void onDocumentUpdated(const QSharedPointer<const QmlJS::Document> &doc);
- void addTask(QSharedPointer<CollectionTask> task);
-
- QPointer<CollectionWidget> m_widget;
- std::unique_ptr<DataStoreModelNode> m_dataStore;
- QSet<Utils::FilePath> m_expectedDocumentUpdates;
- QList<QSharedPointer<CollectionTask>> m_delayedTasks;
- QMetaObject::Connection m_documentUpdateConnection;
- bool m_libraryInfoIsUpdated = false;
- bool m_dataStoreTypeFound = false;
- bool m_rewriterAmended = false;
- int m_reloadCounter = 0;
-};
-
-class CollectionTask
-{
-public:
- CollectionTask(CollectionView *view, CollectionListModel *listModel);
- CollectionTask() = delete;
- virtual ~CollectionTask() = default;
-
- virtual void process() = 0;
-
-protected:
- QPointer<CollectionView> m_collectionView;
- QPointer<CollectionListModel> m_listModel;
-};
-
-class DropListViewTask : public CollectionTask
-{
-public:
- DropListViewTask(CollectionView *view, CollectionListModel *listModel, const ModelNode &node);
-
- void process() override;
-
-private:
- ModelNode m_node;
-};
-
-class AddCollectionTask : public CollectionTask
-{
-public:
- AddCollectionTask(CollectionView *view,
- CollectionListModel *listModel,
- const QJsonObject &localJsonObject,
- const QString &collectionName);
-
- void process() override;
-
-private:
- QJsonObject m_localJsonObject;
- QString m_name;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp
deleted file mode 100644
index 093729dc67..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-// 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 "collectionwidget.h"
-
-#include "collectiondetails.h"
-#include "collectiondetailsmodel.h"
-#include "collectiondetailssortfiltermodel.h"
-#include "collectioneditorutils.h"
-#include "collectionlistmodel.h"
-#include "collectionview.h"
-#include "designmodewidget.h"
-#include "qmldesignerconstants.h"
-#include "qmldesignerplugin.h"
-#include "theme.h"
-
-#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
-#include <studioquickwidget.h>
-
-#include <QFileInfo>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QMetaObject>
-#include <QQmlEngine>
-#include <QQuickItem>
-#include <QShortcut>
-#include <QVBoxLayout>
-
-namespace {
-
-QString collectionViewResourcesPath()
-{
-#ifdef SHARE_QML_PATH
- if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
- return QLatin1String(SHARE_QML_PATH) + "/collectionEditorQmlSource";
-#endif
- return Core::ICore::resourcePath("qmldesigner/collectionEditorQmlSource").toString();
-}
-
-QString getPreferredCollectionName(const QUrl &url, const QString &collectionName)
-{
- if (collectionName.isEmpty()) {
- QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString());
- return fileInfo.completeBaseName();
- }
-
- return collectionName;
-}
-
-} // namespace
-
-namespace QmlDesigner {
-CollectionWidget::CollectionWidget(CollectionView *view)
- : QFrame()
- , m_view(view)
- , m_listModel(new CollectionListModel)
- , m_collectionDetailsModel(new CollectionDetailsModel)
- , m_collectionDetailsSortFilterModel(std::make_unique<CollectionDetailsSortFilterModel>())
- , m_quickWidget(new StudioQuickWidget(this))
-{
- setWindowTitle(tr("Model Editor", "Title of model editor widget"));
-
- Core::IContext *icontext = nullptr;
- Core::Context context(Constants::C_QMLCOLLECTIONEDITOR);
- icontext = new Core::IContext(this);
- icontext->setContext(context);
- icontext->setWidget(this);
-
- connect(m_listModel, &CollectionListModel::warning, this, &CollectionWidget::warn);
-
- m_collectionDetailsSortFilterModel->setSourceModel(m_collectionDetailsModel);
-
- m_quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_COLLECTION_EDITOR);
- m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
- m_quickWidget->engine()->addImportPath(collectionViewResourcesPath() + "/imports");
- m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
-
- Theme::setupTheme(m_quickWidget->engine());
- m_quickWidget->quickWidget()->installEventFilter(this);
-
- auto layout = new QVBoxLayout(this);
- layout->setContentsMargins({});
- layout->setSpacing(0);
- layout->addWidget(m_quickWidget.data());
-
- qmlRegisterAnonymousType<CollectionWidget>("CollectionEditorBackend", 1);
- auto map = m_quickWidget->registerPropertyMap("CollectionEditorBackend");
- map->setProperties({
- {"rootView", QVariant::fromValue(this)},
- {"model", QVariant::fromValue(m_listModel.data())},
- {"collectionDetailsModel", QVariant::fromValue(m_collectionDetailsModel.data())},
- {"collectionDetailsSortFilterModel",
- QVariant::fromValue(m_collectionDetailsSortFilterModel.get())},
- });
-
- auto hotReloadShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F4), this);
- connect(hotReloadShortcut, &QShortcut::activated, this, &CollectionWidget::reloadQmlSource);
-
- reloadQmlSource();
-
- QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_MODELEDITOR_TIME);
-}
-
-void CollectionWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
-{
- if (m_view)
- QmlDesignerPlugin::contextHelp(callback, m_view->contextHelpId());
- else
- callback({});
-}
-
-QPointer<CollectionListModel> CollectionWidget::listModel() const
-{
- return m_listModel;
-}
-
-QPointer<CollectionDetailsModel> CollectionWidget::collectionDetailsModel() const
-{
- return m_collectionDetailsModel;
-}
-
-void CollectionWidget::reloadQmlSource()
-{
- const QString collectionViewQmlPath = collectionViewResourcesPath() + "/CollectionView.qml";
-
- QTC_ASSERT(QFileInfo::exists(collectionViewQmlPath), return);
-
- m_quickWidget->setSource(QUrl::fromLocalFile(collectionViewQmlPath));
-
- if (!m_quickWidget->rootObject()) {
- QString errorString;
- const auto errors = m_quickWidget->errors();
- for (const QQmlError &error : errors)
- errorString.append("\n" + error.toString());
-
- Core::AsynchronousMessageBox::warning(tr("Cannot Create QtQuick View"),
- tr("StatesEditorWidget: %1 cannot be created.%2")
- .arg(collectionViewQmlPath, errorString));
- return;
- }
-}
-
-QSize CollectionWidget::minimumSizeHint() const
-{
- return {300, 300};
-}
-
-bool CollectionWidget::loadJsonFile(const QUrl &url, const QString &collectionName)
-{
- if (!isJsonFile(url))
- return false;
-
- m_view->addResource(url, getPreferredCollectionName(url, collectionName));
-
- return true;
-}
-
-bool CollectionWidget::loadCsvFile(const QUrl &url, const QString &collectionName)
-{
- m_view->addResource(url, getPreferredCollectionName(url, collectionName));
-
- return true;
-}
-
-bool CollectionWidget::isJsonFile(const QUrl &url) const
-{
- Utils::FilePath filePath = Utils::FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
- : url.toString());
- Utils::FileReader file;
- if (!file.fetch(filePath))
- return false;
-
- QJsonParseError error;
- QJsonDocument::fromJson(file.data(), &error);
- if (error.error)
- return false;
-
- return true;
-}
-
-bool CollectionWidget::isCsvFile(const QUrl &url) const
-{
- QString filePath = url.isLocalFile() ? url.toLocalFile() : url.toString();
- QFileInfo fileInfo(filePath);
- return fileInfo.exists() && !fileInfo.suffix().compare("csv", Qt::CaseInsensitive);
-}
-
-bool CollectionWidget::isValidUrlToImport(const QUrl &url) const
-{
- using Utils::FilePath;
- FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
- : url.toString());
- if (fileInfo.suffix() == "json")
- return isJsonFile(url);
-
- if (fileInfo.suffix() == "csv")
- return isCsvFile(url);
-
- return false;
-}
-
-bool CollectionWidget::importFile(const QString &collectionName,
- const QUrl &url,
- const bool &firstRowIsHeader)
-{
- using Utils::FilePath;
-
- FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile()
- : url.toString());
- CollectionDetails loadedCollection;
- QByteArray fileContent;
-
- auto loadUrlContent = [&]() -> bool {
- Utils::FileReader file;
- if (file.fetch(fileInfo)) {
- fileContent = file.data();
- return true;
- }
-
- warn(tr("Import from file"), tr("Cannot import from file \"%1\"").arg(fileInfo.fileName()));
- return false;
- };
-
- if (fileInfo.suffix() == "json") {
- if (!loadUrlContent())
- return false;
-
- QJsonParseError parseError;
- loadedCollection = CollectionDetails::fromImportedJson(fileContent, &parseError);
- if (parseError.error != QJsonParseError::NoError) {
- warn(tr("Json file Import error"),
- tr("Cannot parse json content\n%1").arg(parseError.errorString()));
- }
- } else if (fileInfo.suffix() == "csv") {
- if (!loadUrlContent())
- return false;
- loadedCollection = CollectionDetails::fromImportedCsv(fileContent, firstRowIsHeader);
- }
-
- if (loadedCollection.columns()) {
- m_view->addNewCollection(collectionName, loadedCollection.toLocalJson());
- return true;
- } else {
- warn(tr("Can not add a model to the JSON file"),
- tr("The imported model is empty or is not supported."));
- }
- return false;
-}
-
-void CollectionWidget::addCollectionToDataStore(const QString &collectionName)
-{
- m_view->addNewCollection(collectionName, CollectionEditorUtils::defaultCollection());
-}
-
-void CollectionWidget::assignCollectionToSelectedNode(const QString collectionName)
-{
- m_view->assignCollectionToSelectedNode(collectionName);
-}
-
-void CollectionWidget::openCollection(const QString &collectionName)
-{
- m_listModel->selectCollectionName(collectionName);
- QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("CollectionEditor", true);
-}
-
-ModelNode CollectionWidget::dataStoreNode() const
-{
- return m_view->dataStoreNode();
-}
-
-void CollectionWidget::warn(const QString &title, const QString &body)
-{
- QMetaObject::invokeMethod(m_quickWidget->rootObject(),
- "showWarning",
- Q_ARG(QVariant, title),
- Q_ARG(QVariant, body));
-}
-
-void CollectionWidget::setTargetNodeSelected(bool selected)
-{
- if (m_targetNodeSelected == selected)
- return;
-
- m_targetNodeSelected = selected;
- emit targetNodeSelectedChanged(m_targetNodeSelected);
-}
-
-void CollectionWidget::deleteSelectedCollection()
-{
- QMetaObject::invokeMethod(m_quickWidget->quickWidget()->rootObject(), "deleteSelectedCollection");
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h
deleted file mode 100644
index 0957bd81e0..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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 <QFrame>
-
-#include <coreplugin/icontext.h>
-
-class StudioQuickWidget;
-
-namespace QmlDesigner {
-
-class CollectionDetailsModel;
-class CollectionDetailsSortFilterModel;
-class CollectionListModel;
-class CollectionView;
-class ModelNode;
-
-class CollectionWidget : public QFrame
-{
- Q_OBJECT
-
- Q_PROPERTY(bool targetNodeSelected MEMBER m_targetNodeSelected NOTIFY targetNodeSelectedChanged)
-
-public:
- CollectionWidget(CollectionView *view);
- void contextHelp(const Core::IContext::HelpCallback &callback) const;
-
- QPointer<CollectionListModel> listModel() const;
- QPointer<CollectionDetailsModel> collectionDetailsModel() const;
-
- void reloadQmlSource();
-
- virtual QSize minimumSizeHint() const;
-
- Q_INVOKABLE bool loadJsonFile(const QUrl &url, const QString &collectionName = {});
- Q_INVOKABLE bool loadCsvFile(const QUrl &url, const QString &collectionName = {});
- Q_INVOKABLE bool isJsonFile(const QUrl &url) const;
- Q_INVOKABLE bool isCsvFile(const QUrl &url) const;
- Q_INVOKABLE bool isValidUrlToImport(const QUrl &url) const;
-
- Q_INVOKABLE bool importFile(const QString &collectionName,
- const QUrl &url,
- const bool &firstRowIsHeader = true);
-
- Q_INVOKABLE void addCollectionToDataStore(const QString &collectionName);
- Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName);
- Q_INVOKABLE void openCollection(const QString &collectionName);
- Q_INVOKABLE ModelNode dataStoreNode() const;
-
- void warn(const QString &title, const QString &body);
- void setTargetNodeSelected(bool selected);
-
- void deleteSelectedCollection();
-
-signals:
- void targetNodeSelectedChanged(bool);
-
-private:
- QString generateUniqueCollectionName(const ModelNode &node, const QString &name);
-
- QPointer<CollectionView> m_view;
- QPointer<CollectionListModel> m_listModel;
- QPointer<CollectionDetailsModel> m_collectionDetailsModel;
- std::unique_ptr<CollectionDetailsSortFilterModel> m_collectionDetailsSortFilterModel;
- QScopedPointer<StudioQuickWidget> m_quickWidget;
- bool m_targetNodeSelected = false;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp
deleted file mode 100644
index 5be9c20f9e..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-// 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 "datastoremodelnode.h"
-
-#include "abstractview.h"
-#include "collectioneditorconstants.h"
-#include "collectioneditorutils.h"
-#include "model/qmltextgenerator.h"
-#include "plaintexteditmodifier.h"
-#include "qmldesignerbase/qmldesignerbaseplugin.h"
-#include "qmldesignerexternaldependencies.h"
-#include "rewriterview.h"
-
-#include <model.h>
-#include <nodemetainfo.h>
-#include <nodeproperty.h>
-#include <variantproperty.h>
-
-#include <qmljstools/qmljscodestylepreferences.h>
-#include <qmljstools/qmljstoolssettings.h>
-
-#include <coreplugin/documentmanager.h>
-#include <projectexplorer/project.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectmanager.h>
-
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-
-#include <QPlainTextEdit>
-#include <QRegularExpression>
-#include <QRegularExpressionMatch>
-#include <QScopedPointer>
-
-namespace {
-
-inline constexpr char CHILDLISTMODEL_TYPENAME[] = "ChildListModel";
-
-QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
-{
- using QmlDesigner::AbstractProperty;
- using QmlDesigner::PropertyName;
- using QmlDesigner::PropertyNameList;
- static PropertyNameList defaultsNodeProps = {
- "id",
- QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY,
- QmlDesigner::CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY,
- "backend"};
- PropertyNameList dynamicPropertyNames = Utils::transform(
- node.dynamicProperties(),
- [](const AbstractProperty &property) -> PropertyName { return property.name(); });
-
- Utils::sort(dynamicPropertyNames);
-
- return defaultsNodeProps + dynamicPropertyNames;
-}
-
-bool isValidCollectionPropertyName(const QString &collectionId)
-{
- static const QmlDesigner::PropertyNameList reservedKeywords = {
- QmlDesigner::CollectionEditorConstants::SOURCEFILE_PROPERTY,
- QmlDesigner::CollectionEditorConstants::JSONBACKEND_TYPENAME,
- "backend",
- "models",
- };
-
- return QmlDesigner::ModelNode::isValidId(collectionId)
- && !reservedKeywords.contains(collectionId.toLatin1());
-}
-
-QMap<QString, QmlDesigner::PropertyName> getModelIdMap(const QmlDesigner::ModelNode &rootNode)
-{
- using namespace QmlDesigner;
- QMap<QString, PropertyName> modelNameForId;
-
- const QList<AbstractProperty> propertyNames = rootNode.dynamicProperties();
-
- for (const AbstractProperty &property : std::as_const(propertyNames)) {
- if (!property.isNodeProperty())
- continue;
-
- NodeProperty nodeProperty = property.toNodeProperty();
- if (!nodeProperty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
- continue;
-
- ModelNode childNode = nodeProperty.modelNode();
- if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) {
- QString modelName = childNode
- .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)
- .toVariantProperty()
- .value()
- .toString();
-
- if (!modelName.isEmpty())
- modelNameForId.insert(modelName, property.name());
- }
- }
- return modelNameForId;
-}
-
-void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext)
-{
- using namespace QmlDesigner;
- Q_ASSERT(model);
-
- QScopedPointer<QPlainTextEdit> textEdit(new QPlainTextEdit);
- QScopedPointer<NotIndentingTextEditModifier> modifier(
- new NotIndentingTextEditModifier(textEdit.data()));
- textEdit->hide();
- textEdit->setPlainText(qmlContext);
- QmlDesigner::ExternalDependencies externalDependencies{QmlDesignerBasePlugin::settings()};
- QScopedPointer<RewriterView> rewriter(
- new RewriterView(externalDependencies, QmlDesigner::RewriterView::Validate));
-
- rewriter->setParent(model);
- rewriter->setTextModifier(modifier.get());
- rewriter->setCheckSemanticErrors(false);
-
- model->attachView(rewriter.get());
- model->detachView(rewriter.get());
-}
-
-} // namespace
-
-namespace QmlDesigner {
-
-DataStoreModelNode::DataStoreModelNode()
-{
- reloadModel();
-}
-
-void DataStoreModelNode::reloadModel()
-{
- using Utils::FilePath;
- if (!ProjectExplorer::ProjectManager::startupProject()) {
- reset();
- return;
- }
- bool forceUpdate = false;
-
- const FilePath dataStoreQmlPath = CollectionEditorUtils::dataStoreQmlFilePath();
- const FilePath dataStoreJsonPath = CollectionEditorUtils::dataStoreJsonFilePath();
- QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl();
-
- if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) {
- if (!m_model.get() || m_model->fileUrl() != dataStoreQmlUrl) {
-#ifdef QDS_USE_PROJECTSTORAGE
- m_model = model()->createModel("JsonListModel");
- forceUpdate = true;
- Import import = Import::createLibraryImport("QtQuick.Studio.Utils");
- m_model->changeImports({import}, {});
-#else
- m_model = Model::create(CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME, 1, 1);
- forceUpdate = true;
- Import import = Import::createLibraryImport(
- CollectionEditorConstants::COLLECTIONMODEL_IMPORT);
- try {
- if (!m_model->hasImport(import, true, true))
- m_model->changeImports({import}, {});
- } catch (const Exception &) {
- QTC_ASSERT(false, return);
- }
-#endif
- }
- } else {
- reset();
- }
-
- if (!m_model.get())
- return;
-
- if (forceUpdate) {
- m_model->setFileUrl(dataStoreQmlUrl);
- m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString();
- preloadFile();
- update();
- }
-}
-
-QStringList DataStoreModelNode::collectionNames() const
-{
- return m_collectionPropertyNames.keys();
-}
-
-Model *DataStoreModelNode::model() const
-{
- return m_model.get();
-}
-
-ModelNode DataStoreModelNode::modelNode() const
-{
- if (!m_model.get())
- return {};
- return m_model->rootModelNode();
-}
-
-QString DataStoreModelNode::getModelQmlText()
-{
- ModelNode node = modelNode();
- QTC_ASSERT(node, return {});
-
- Internal::QmlTextGenerator textGen(createNameList(node),
- QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->tabSettings());
-
- QString genText = textGen(node);
- return genText;
-}
-
-void DataStoreModelNode::reset()
-{
- if (m_model)
- m_model.reset();
-
- m_dataRelativePath.clear();
- setCollectionNames({});
-}
-
-void DataStoreModelNode::preloadFile()
-{
- using Utils::FilePath;
- using Utils::FileReader;
-
- if (!m_model)
- return;
-
- const FilePath dataStoreQmlPath = dataStoreQmlFilePath();
- FileReader dataStoreQmlFile;
- QString sourceQmlContext;
-
- if (dataStoreQmlFile.fetch(dataStoreQmlPath))
- sourceQmlContext = QString::fromLatin1(dataStoreQmlFile.data());
-
- setQmlContextToModel(m_model.get(), sourceQmlContext);
- m_collectionPropertyNames = getModelIdMap(m_model->rootModelNode());
-}
-
-void DataStoreModelNode::updateDataStoreProperties()
-{
- QTC_ASSERT(model(), return);
-
- ModelNode rootNode = modelNode();
- QTC_ASSERT(rootNode.isValid(), return);
-
- QSet<QString> collectionNamesToBeAdded;
- const QStringList allCollectionNames = m_collectionPropertyNames.keys();
- for (const QString &collectionName : allCollectionNames)
- collectionNamesToBeAdded << collectionName;
-
- const QList<AbstractProperty> formerPropertyNames = rootNode.dynamicProperties();
-
- // Remove invalid collection names from the properties
- for (const AbstractProperty &property : formerPropertyNames) {
- if (!property.isNodeProperty())
- continue;
-
- NodeProperty nodeProprty = property.toNodeProperty();
- if (!nodeProprty.hasDynamicTypeName(CHILDLISTMODEL_TYPENAME))
- continue;
-
- ModelNode childNode = nodeProprty.modelNode();
- if (childNode.hasProperty(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)) {
- QString modelName = childNode
- .property(CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY)
- .toVariantProperty()
- .value()
- .toString();
- if (collectionNamesToBeAdded.contains(modelName)) {
- m_collectionPropertyNames.insert(modelName, property.name());
- collectionNamesToBeAdded.remove(modelName);
- } else {
- rootNode.removeProperty(property.name());
- }
- } else {
- rootNode.removeProperty(property.name());
- }
- }
-
- rootNode.setIdWithoutRefactoring("models");
-
- QStringList collectionNamesLeft = collectionNamesToBeAdded.values();
- Utils::sort(collectionNamesLeft);
- for (const QString &collectionName : std::as_const(collectionNamesLeft))
- addCollectionNameToTheModel(collectionName, getUniquePropertyName(collectionName));
-
- // Backend Property
- ModelNode backendNode = model()->createModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME);
- NodeProperty backendProperty = rootNode.nodeProperty("backend");
- backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditorConstants::JSONBACKEND_TYPENAME,
- backendNode);
- // Source Property
- VariantProperty sourceProp = rootNode.variantProperty(
- CollectionEditorConstants::SOURCEFILE_PROPERTY);
- sourceProp.setValue(m_dataRelativePath);
-}
-
-void DataStoreModelNode::updateSingletonFile()
-{
- using Utils::FilePath;
- using Utils::FileSaver;
- QTC_ASSERT(m_model.get(), return);
-
- const QString pragmaSingleTone = "pragma Singleton\n";
- QString imports;
-
- for (const Import &import : m_model->imports())
- imports += QStringLiteral("import %1\n").arg(import.toString(true));
-
- QString content = pragmaSingleTone + imports + getModelQmlText();
- Core::DocumentManager::expectFileChange(dataStoreQmlFilePath());
- FileSaver file(dataStoreQmlFilePath());
- file.write(content.toLatin1());
- file.finalize();
-}
-
-void DataStoreModelNode::update()
-{
- if (!m_model.get())
- return;
-
- updateDataStoreProperties();
- updateSingletonFile();
-}
-
-void DataStoreModelNode::addCollectionNameToTheModel(const QString &collectionName,
- const PropertyName &dataStorePropertyName)
-{
- ModelNode rootNode = modelNode();
- QTC_ASSERT(rootNode.isValid(), return);
-
- if (dataStorePropertyName.isEmpty()) {
- qWarning() << __FUNCTION__ << __LINE__
- << QString("The property name cannot be generated from \"%1\"").arg(collectionName);
- return;
- }
-
- ModelNode collectionNode = model()->createModelNode(CHILDLISTMODEL_TYPENAME);
- VariantProperty modelNameProperty = collectionNode.variantProperty(
- CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY);
- modelNameProperty.setValue(collectionName);
-
- NodeProperty nodeProp = rootNode.nodeProperty(dataStorePropertyName);
- nodeProp.setDynamicTypeNameAndsetModelNode(CHILDLISTMODEL_TYPENAME, collectionNode);
-
- m_collectionPropertyNames.insert(collectionName, dataStorePropertyName);
-}
-
-Utils::FilePath DataStoreModelNode::dataStoreQmlFilePath() const
-{
- QUrl modelUrl = m_model->fileUrl();
- return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
- : modelUrl.toString());
-}
-
-PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName)
-{
- ModelNode dataStoreNode = modelNode();
- QTC_ASSERT(!collectionName.isEmpty() && dataStoreNode.isValid(), return {});
-
- QString newProperty;
-
- // convert to camel case
- QStringList nameWords = collectionName.split(' ');
- nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1);
- for (int i = 1; i < nameWords.size(); ++i)
- nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1);
- newProperty = nameWords.join("");
-
- // if id starts with a number prepend an underscore
- if (newProperty.at(0).isDigit())
- newProperty.prepend('_');
-
- // If the new id is not valid (e.g. qml keyword match), prepend an underscore
- if (!isValidCollectionPropertyName(newProperty))
- newProperty.prepend('_');
-
- static const QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
- while (dataStoreNode.hasProperty(newProperty.toLatin1())) { // id exists
- QRegularExpressionMatch match = rgx.match(newProperty);
- if (match.hasMatch()) { // ends with a number, increment it
- QString numStr = match.captured();
- int num = numStr.toInt() + 1;
- newProperty = newProperty.mid(0, match.capturedStart()) + QString::number(num);
- } else {
- newProperty.append('1');
- }
- }
-
- return newProperty.toLatin1();
-}
-
-void DataStoreModelNode::setCollectionNames(const QStringList &newCollectionNames)
-{
- m_collectionPropertyNames.clear();
- for (const QString &collectionName : newCollectionNames)
- m_collectionPropertyNames.insert(collectionName, {});
- update();
-}
-
-void DataStoreModelNode::addCollection(const QString &collectionName)
-{
- if (!m_collectionPropertyNames.contains(collectionName)) {
- m_collectionPropertyNames.insert(collectionName, {});
- update();
- }
-}
-
-void DataStoreModelNode::renameCollection(const QString &oldName, const QString &newName)
-{
- ModelNode dataStoreNode = modelNode();
- QTC_ASSERT(dataStoreNode.isValid(), return);
-
- if (m_collectionPropertyNames.contains(oldName)) {
- const PropertyName oldPropertyName = m_collectionPropertyNames.value(oldName);
- if (!oldPropertyName.isEmpty() && dataStoreNode.hasProperty(oldPropertyName)) {
- NodeProperty collectionNode = dataStoreNode.property(oldPropertyName).toNodeProperty();
- if (collectionNode.isValid()) {
- VariantProperty modelNameProperty = collectionNode.modelNode().variantProperty(
- CollectionEditorConstants::JSONCHILDMODELNAME_PROPERTY);
- modelNameProperty.setValue(newName);
- m_collectionPropertyNames.remove(oldName);
- m_collectionPropertyNames.insert(newName, collectionNode.name());
- update();
- return;
- }
- qWarning() << __FUNCTION__ << __LINE__
- << "There is no valid node for the old collection name";
- return;
- }
- qWarning() << __FUNCTION__ << __LINE__ << QString("Invalid old property name")
- << oldPropertyName;
- return;
- }
- qWarning() << __FUNCTION__ << __LINE__
- << QString("There is no old collection name registered with this name \"%1\"").arg(oldName);
-}
-
-void DataStoreModelNode::removeCollections(const QStringList &collectionNames)
-{
- bool updateRequired = false;
- for (const QString &collectionName : collectionNames) {
- if (m_collectionPropertyNames.contains(collectionName)) {
- m_collectionPropertyNames.remove(collectionName);
- updateRequired = true;
- }
- }
-
- if (updateRequired)
- update();
-}
-
-void DataStoreModelNode::assignCollectionToNode(AbstractView *view,
- const ModelNode &targetNode,
- const QString &collectionName,
- CollectionColumnFinder collectionHasColumn,
- FirstColumnProvider firstColumnProvider)
-{
- QTC_ASSERT(targetNode.isValid(), return);
-
- if (!CollectionEditorUtils::canAcceptCollectionAsModel(targetNode))
- return;
-
- if (!m_collectionPropertyNames.contains(collectionName)) {
- qWarning() << __FUNCTION__ << __LINE__ << "Collection doesn't exist in the DataStore"
- << collectionName;
- return;
- }
-
- PropertyName propertyName = m_collectionPropertyNames.value(collectionName);
-
- const ModelNode dataStore = modelNode();
- VariantProperty sourceProperty = dataStore.variantProperty(propertyName);
- if (!sourceProperty.exists()) {
- qWarning() << __FUNCTION__ << __LINE__
- << "The source property doesn't exist in the DataStore.";
- return;
- }
-
- view->executeInTransaction("assignCollectionToNode", [&]() {
- QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name()));
-
- // Remove the old model node property if exists
- NodeProperty modelNodeProperty = targetNode.nodeProperty("model");
- if (modelNodeProperty.modelNode())
- modelNodeProperty.modelNode().destroy();
-
- // Assign the collection to the node
- BindingProperty modelProperty = targetNode.bindingProperty("model");
- modelProperty.setExpression(identifier);
-
- if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) {
- VariantProperty textRoleProperty = targetNode.variantProperty("textRole");
- const QVariant currentTextRoleValue = textRoleProperty.value();
-
- if (currentTextRoleValue.isValid() && !currentTextRoleValue.isNull()) {
- if (currentTextRoleValue.type() == QVariant::String) {
- const QString currentTextRole = currentTextRoleValue.toString();
- if (collectionHasColumn(collectionName, currentTextRole))
- return;
- } else {
- return;
- }
- }
-
- QString textRoleValue = firstColumnProvider(collectionName);
- textRoleProperty.setValue(textRoleValue);
- }
- });
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h
deleted file mode 100644
index 6cd969edbe..0000000000
--- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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 <modelnode.h>
-
-#include <QMap>
-
-namespace Utils {
-class FilePath;
-}
-
-namespace QmlDesigner {
-
-class Model;
-
-class DataStoreModelNode
-{
-public:
- using CollectionColumnFinder = std::function<bool(const QString &collectionName,
- const QString &columnName)>;
- using FirstColumnProvider = std::function<QString(const QString &collectionName)>;
-
- DataStoreModelNode();
-
- void reloadModel();
- QStringList collectionNames() const;
-
- Model *model() const;
- ModelNode modelNode() const;
-
- void setCollectionNames(const QStringList &newCollectionNames);
- void addCollection(const QString &collectionName);
- void renameCollection(const QString &oldName, const QString &newName);
- void removeCollections(const QStringList &collectionNames);
-
- void assignCollectionToNode(AbstractView *view,
- const ModelNode &targetNode,
- const QString &collectionName,
- CollectionColumnFinder collectionHasColumn,
- FirstColumnProvider firstColumnProvider);
-
-private:
- QString getModelQmlText();
-
- void reset();
- void preloadFile();
- void updateDataStoreProperties();
- void updateSingletonFile();
- void update();
- void addCollectionNameToTheModel(const QString &collectionName,
- const PropertyName &dataStorePropertyName);
- Utils::FilePath dataStoreQmlFilePath() const;
-
- PropertyName getUniquePropertyName(const QString &collectionName);
-
- ModelPointer m_model;
- QMap<QString, PropertyName> m_collectionPropertyNames;
- QString m_dataRelativePath;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp b/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp
index 559e8ea69c..3379d99834 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp
@@ -8,7 +8,7 @@
namespace QmlDesigner {
AbstractAction::AbstractAction(const QString &description)
- : m_pureAction(new DefaultAction(description))
+ : m_pureAction(std::make_unique<DefaultAction>(description))
{
const Utils::Icon defaultIcon({
{":/utils/images/select.png", Utils::Theme::QmlDesigner_FormEditorForegroundColor}}, Utils::Icon::MenuTintedStyle);
@@ -56,7 +56,7 @@ void AbstractAction::setCheckable(bool checkable)
PureActionInterface *AbstractAction::pureAction() const
{
- return m_pureAction.data();
+ return m_pureAction.get();
}
SelectionContext AbstractAction::selectionContext() const
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractaction.h b/src/plugins/qmldesigner/components/componentcore/abstractaction.h
index ca4cc582ce..53b540cc7a 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractaction.h
+++ b/src/plugins/qmldesigner/components/componentcore/abstractaction.h
@@ -6,7 +6,8 @@
#include "actioninterface.h"
#include <QAction>
-#include <QScopedPointer>
+
+#include <memory>
namespace QmlDesigner {
@@ -58,7 +59,7 @@ protected:
SelectionContext selectionContext() const;
private:
- QScopedPointer<PureActionInterface> m_pureAction;
+ std::unique_ptr<PureActionInterface> m_pureAction;
SelectionContext m_selectionContext;
};
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp b/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp
index 288b8e409d..5b340343e7 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp
@@ -8,14 +8,14 @@
namespace QmlDesigner {
-AbstractActionGroup::AbstractActionGroup(const QString &displayName) :
- m_displayName(displayName),
- m_menu(new QmlEditorMenu)
+AbstractActionGroup::AbstractActionGroup(const QString &displayName)
+ : m_displayName(displayName)
+ , m_menu(Utils::makeUniqueObjectPtr<QmlEditorMenu>())
{
m_menu->setTitle(displayName);
m_action = m_menu->menuAction();
- QmlEditorMenu *qmlEditorMenu = qobject_cast<QmlEditorMenu *>(m_menu.data());
+ QmlEditorMenu *qmlEditorMenu = qobject_cast<QmlEditorMenu *>(m_menu.get());
if (qmlEditorMenu)
qmlEditorMenu->setIconsVisible(false);
}
@@ -32,7 +32,7 @@ QAction *AbstractActionGroup::action() const
QMenu *AbstractActionGroup::menu() const
{
- return m_menu.data();
+ return m_menu.get();
}
SelectionContext AbstractActionGroup::selectionContext() const
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.h b/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.h
index dd89849ecf..f239eeab3d 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.h
+++ b/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.h
@@ -5,9 +5,10 @@
#include "actioninterface.h"
+#include <utils/uniqueobjectptr.h>
+
#include <QAction>
#include <QMenu>
-#include <QScopedPointer>
namespace QmlDesigner {
@@ -29,7 +30,7 @@ public:
private:
const QString m_displayName;
SelectionContext m_selectionContext;
- QScopedPointer<QMenu> m_menu;
+ Utils::UniqueObjectPtr<QMenu> m_menu;
QAction *m_action;
};
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
index d992a6a5bf..da7c5bf72e 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
@@ -69,7 +69,6 @@ const char mergeTemplateCommandId[] = "MergeTemplate";
const char goToImplementationCommandId[] = "GoToImplementation";
const char makeComponentCommandId[] = "MakeComponent";
const char editMaterialCommandId[] = "EditMaterial";
-const char editCollectionCommandId[] = "EditCollection";
const char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer";
const char addTabBarToStackedContainerCommandId[] = "AddTabBarToStackedContainer";
const char increaseIndexOfStackedContainerCommandId[] = "IncreaseIndexOfStackedContainer";
@@ -128,7 +127,6 @@ const char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMen
const char goToImplementationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go to Implementation");
const char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Component");
const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material");
-const char editCollectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Model");
const char editAnnotationsDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotations");
const char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Mouse Area");
const char editIn3dViewDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit in 3D View");
@@ -214,7 +212,6 @@ enum PrioritiesEnum : int {
ArrangeCategory,
EditCategory,
EditListModel,
- EditCollection,
/******** Section *****************************/
PositionSection = 2000,
SnappingCategory,
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 4e32237ee9..bbe64935f6 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -61,11 +61,6 @@ inline static QString captionForModelNode(const ModelNode &modelNode)
return modelNode.id();
}
-inline static bool contains(const QmlItemNode &node, const QPointF &position)
-{
- return node.isValid() && node.instanceSceneTransform().mapRect(node.instanceBoundingRect()).contains(position);
-}
-
DesignerActionManagerView *DesignerActionManager::view()
{
return m_designerActionManagerView;
@@ -118,7 +113,6 @@ void DesignerActionManager::polishActions() const
Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR);
Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER);
Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY);
- Core::Context qmlDesignerCollectionEditorContext(Constants::C_QMLCOLLECTIONEDITOR);
Core::Context qmlDesignerUIContext;
qmlDesignerUIContext.add(qmlDesignerFormEditorContext);
@@ -126,7 +120,6 @@ void DesignerActionManager::polishActions() const
qmlDesignerUIContext.add(qmlDesignerNavigatorContext);
qmlDesignerUIContext.add(qmlDesignerMaterialBrowserContext);
qmlDesignerUIContext.add(qmlDesignerAssetsLibraryContext);
- qmlDesignerUIContext.add(qmlDesignerCollectionEditorContext);
for (auto *action : actions) {
if (!action->menuId().isEmpty()) {
@@ -438,8 +431,8 @@ public:
}
for (const ModelNode &node : selectionContext().view()->allModelNodes()) {
if (node != selectionContext().currentSingleSelectedNode() && node != parentNode
- && contains(node, selectionContext().scenePosition()) && !node.isRootNode()
- && !ModelUtils::isThisOrAncestorLocked(node)) {
+ && SelectionContextHelpers::contains(node, selectionContext().scenePosition())
+ && !node.isRootNode() && !ModelUtils::isThisOrAncestorLocked(node)) {
selectionContext().setTargetNode(node);
QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node));
ActionTemplate *selectionAction = new ActionTemplate("SELECT", what, &ModelNodeOperations::select);
@@ -1971,7 +1964,7 @@ void DesignerActionManager::createDefaultDesignerActions()
QKeySequence(),
Priorities::ComponentActions + 1,
&editIn3dView,
- &singleSelectionView3D,
+ &SelectionContextFunctors::always, // If action is visible, it is usable
&singleSelectionView3D));
addDesignerAction(new ModelNodeContextMenuAction(
@@ -1993,8 +1986,8 @@ void DesignerActionManager::createDefaultDesignerActions()
QKeySequence(),
44,
&editMaterial,
- &modelHasMaterial,
- &isModel));
+ &hasEditableMaterial,
+ &isModelOrMaterial));
addDesignerAction(new ModelNodeContextMenuAction(
mergeTemplateCommandId,
@@ -2016,16 +2009,6 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new EditListModelAction);
- addDesignerAction(new ModelNodeContextMenuAction(editCollectionCommandId,
- editCollectionDisplayName,
- contextIcon(DesignerIcons::EditIcon),
- rootCategory,
- QKeySequence("Alt+e"),
- ComponentCoreConstants::Priorities::EditCollection,
- &editCollection,
- &hasCollectionAsModel,
- &hasCollectionAsModel));
-
addDesignerAction(new ModelNodeContextMenuAction(openSignalDialogCommandId,
openSignalDialogDisplayName,
{},
@@ -2198,7 +2181,8 @@ void DesignerActionManager::addCustomTransitionEffectAction()
void DesignerActionManager::setupIcons()
{
- m_designerIcons.reset(new DesignerIcons("qtds_propertyIconFont.ttf", designerIconResourcesPath()));
+ m_designerIcons = std::make_unique<DesignerIcons>("qtds_propertyIconFont.ttf",
+ designerIconResourcesPath());
}
QString DesignerActionManager::designerIconResourcesPath() const
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
index 16d6219cd6..89505fcbe8 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
@@ -138,7 +138,7 @@ private:
QList<AddResourceHandler> m_addResourceHandler;
QList<ModelNodePreviewImageHandler> m_modelNodePreviewImageHandlers;
ExternalDependenciesInterface &m_externalDependencies;
- QScopedPointer<DesignerIcons> m_designerIcons;
+ std::unique_ptr<DesignerIcons> m_designerIcons;
QList<ActionAddedInterface> m_callBacks;
};
diff --git a/src/plugins/qmldesigner/components/componentcore/dialogutils.cpp b/src/plugins/qmldesigner/components/componentcore/dialogutils.cpp
new file mode 100644
index 0000000000..f882ae528d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/dialogutils.cpp
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <model.h>
+
+#include <coreplugin/messagebox.h>
+
+namespace QmlDesigner {
+
+namespace DialogUtils {
+
+void showWarningForInvalidId(const QString &id)
+{
+ constexpr char text[] = R"(
+The ID <b>'%1'</b> is invalid.
+
+Make sure the ID is:
+<ul>
+<li>Unique within the QML file.</li>
+<li>Beginning with a lowercase letter.</li>
+<li>Without any blank space or symbol.</li>
+<li>Not a reserved QML keyword. </li>
+</ul>
+)";
+
+ Core::AsynchronousMessageBox::warning(Model::tr("Invalid Id"),
+ Model::tr(text).arg(id));
+}
+
+} // namespace DialogUtils
+
+} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/dialogutils.h b/src/plugins/qmldesigner/components/componentcore/dialogutils.h
new file mode 100644
index 0000000000..3ca98016dd
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/dialogutils.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <qmldesignercomponents_global.h>
+
+#include <QString>
+
+namespace QmlDesigner {
+
+namespace DialogUtils {
+
+QMLDESIGNERCOMPONENTS_EXPORT void showWarningForInvalidId(const QString &id);
+
+} // namespace DialogUtils
+} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp b/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp
index 8d3412e0e8..89b50c4d1a 100644
--- a/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/layoutingridlayout.cpp
@@ -452,7 +452,9 @@ void LayoutInGridLayout::removeSpacersBySpanning(QList<ModelNode> &nodes)
{
for (const ModelNode &node : std::as_const(m_spacerNodes)) {
if (int index = nodes.indexOf(node)) {
- ModelNode before = nodes.at(index -1);
+ ModelNode before;
+ if (index > 0)
+ before = nodes.at(index - 1);
if (m_spacerNodes.contains(before)) {
m_spacerNodes.removeAll(node);
m_layoutedNodes.removeAll(node);
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp
index f6e18458b2..4cbebd738d 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp
@@ -105,8 +105,10 @@ bool selectionIsImported3DAsset(const SelectionContext &selectionState)
// Node is not a file component, so we have to check if the current doc itself is
fileName = node.model()->fileUrl().toLocalFile();
}
- if (fileName.contains(Constants::QUICK_3D_ASSETS_FOLDER))
+ if (QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().isImport3dPath(fileName)) {
return true;
+ }
}
return false;
}
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
index eb4915b1d0..6734bac568 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
@@ -25,6 +25,16 @@ namespace QmlDesigner {
using SelectionContextPredicate = std::function<bool (const SelectionContext&)>;
using SelectionContextOperation = std::function<void (const SelectionContext&)>;
+namespace SelectionContextHelpers {
+
+inline bool contains(const QmlItemNode &node, const QPointF &position)
+{
+ return node.isValid()
+ && node.instanceSceneTransform().mapRect(node.instanceBoundingRect()).contains(position);
+}
+
+} // namespace SelectionContextHelpers
+
namespace SelectionContextFunctors {
inline bool always(const SelectionContext &)
@@ -54,33 +64,24 @@ inline bool addMouseAreaFillCheck(const SelectionContext &selectionContext)
return false;
}
-inline bool isModel(const SelectionContext &selectionState)
+inline bool isModelOrMaterial(const SelectionContext &selectionState)
{
ModelNode node = selectionState.currentSingleSelectedNode();
- return node.metaInfo().isQtQuick3DModel();
+ return node.metaInfo().isQtQuick3DModel() || node.metaInfo().isQtQuick3DMaterial();
}
-inline bool modelHasMaterial(const SelectionContext &selectionState)
+inline bool hasEditableMaterial(const SelectionContext &selectionState)
{
ModelNode node = selectionState.currentSingleSelectedNode();
+ if (node.metaInfo().isQtQuick3DMaterial())
+ return true;
+
BindingProperty prop = node.bindingProperty("materials");
return prop.exists() && (!prop.expression().isEmpty() || !prop.resolveToModelNodeList().empty());
}
-inline bool hasCollectionAsModel(const SelectionContext &selectionState)
-{
- if (!selectionState.isInBaseState() || !selectionState.singleNodeIsSelected())
- return false;
-
- const ModelNode singleSelectedNode = selectionState.currentSingleSelectedNode();
-
- return singleSelectedNode.metaInfo().isQtQuickListView()
- && singleSelectedNode.property("model").toBindingProperty().expression().startsWith(
- "DataStore.");
-}
-
inline bool selectionEnabled(const SelectionContext &selectionState)
{
return selectionState.showSelectionTools();
@@ -99,8 +100,22 @@ inline bool singleSelectionNotRoot(const SelectionContext &selectionState)
inline bool singleSelectionView3D(const SelectionContext &selectionState)
{
- return selectionState.singleNodeIsSelected()
- && selectionState.currentSingleSelectedNode().metaInfo().isQtQuick3DView3D();
+ if (selectionState.singleNodeIsSelected()
+ && selectionState.currentSingleSelectedNode().metaInfo().isQtQuick3DView3D()) {
+ return true;
+ }
+
+ // If currently selected node is not View3D, check if there is a View3D under the cursor.
+ if (!selectionState.scenePosition().isNull()) {
+ // Assumption is that last match in allModelNodes() list is the topmost one.
+ const QList<ModelNode> allNodes = selectionState.view()->allModelNodes();
+ for (int i = allNodes.size() - 1; i >= 0; --i) {
+ if (SelectionContextHelpers::contains(allNodes[i], selectionState.scenePosition()))
+ return allNodes[i].metaInfo().isQtQuick3DView3D();
+ }
+ }
+
+ return false;
}
inline bool selectionHasProperty(const SelectionContext &selectionState, const char *property)
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index cebe7d7c53..bf8e78a2c7 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -817,21 +817,25 @@ void editMaterial(const SelectionContext &selectionContext)
QTC_ASSERT(modelNode.isValid(), return);
- BindingProperty prop = modelNode.bindingProperty("materials");
- if (!prop.exists())
- return;
-
AbstractView *view = selectionContext.view();
ModelNode material;
- if (view->hasId(prop.expression())) {
- material = view->modelNodeForId(prop.expression());
+ if (modelNode.metaInfo().isQtQuick3DMaterial()) {
+ material = modelNode;
} else {
- QList<ModelNode> materials = prop.resolveToModelNodeList();
+ BindingProperty prop = modelNode.bindingProperty("materials");
+ if (!prop.exists())
+ return;
+
+ if (view->hasId(prop.expression())) {
+ material = view->modelNodeForId(prop.expression());
+ } else {
+ QList<ModelNode> materials = prop.resolveToModelNodeList();
- if (materials.size() > 0)
- material = materials.first();
+ if (materials.size() > 0)
+ material = materials.first();
+ }
}
if (material.isValid()) {
@@ -842,30 +846,6 @@ void editMaterial(const SelectionContext &selectionContext)
}
}
-// Open a collection in the collection editor
-void editCollection(const SelectionContext &selectionContext)
-{
- ModelNode modelNode = selectionContext.targetNode();
-
- if (!modelNode)
- modelNode = selectionContext.currentSingleSelectedNode();
-
- if (!modelNode)
- return;
-
- const QString dataStoreExpression = "DataStore.";
-
- BindingProperty prop = modelNode.bindingProperty("model");
- if (!prop.exists() || !prop.expression().startsWith(dataStoreExpression))
- return;
-
- AbstractView *view = selectionContext.view();
- const QString collectionId = prop.expression().mid(dataStoreExpression.size());
-
- // to CollectionEditor...
- view->emitCustomNotification("open_collection_by_id", {}, {collectionId});
-}
-
void addItemToStackedContainer(const SelectionContext &selectionContext)
{
AbstractView *view = selectionContext.view();
@@ -1138,18 +1118,12 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString &
{
QString adjustedDefaultDirectory = defaultDirectory;
- Utils::FilePath contentPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
-
- if (contentPath.pathAppended("content").exists())
- contentPath = contentPath.pathAppended("content");
+ Utils::FilePath contentPath = QmlDesignerPlugin::instance()->documentManager().currentResourcePath();
Utils::FilePath assetPath = contentPath.pathAppended(assetDir);
- if (!assetPath.exists()) {
- // Create the default asset type directory if it doesn't exist
- QDir dir(contentPath.toString());
- dir.mkpath(assetDir);
- }
+ if (!assetPath.exists())
+ assetPath.createDir();
if (assetPath.exists() && assetPath.isDir())
adjustedDefaultDirectory = assetPath.toString();
@@ -1691,16 +1665,44 @@ void updateImported3DAsset(const SelectionContext &selectionContext)
void editIn3dView(const SelectionContext &selectionContext)
{
- if (selectionContext.view() && selectionContext.hasSingleSelectedModelNode()
+ if (!selectionContext.view())
+ return;
+
+ ModelNode targetNode;
+
+ if (selectionContext.hasSingleSelectedModelNode()
&& selectionContext.currentSingleSelectedNode().metaInfo().isQtQuick3DView3D()) {
+ targetNode = selectionContext.currentSingleSelectedNode();
+ }
+
+ const QPointF scenePos = selectionContext.scenePosition();
+ if (!targetNode.isValid() && !scenePos.isNull()) {
+ // If currently selected node is not View3D, check if there is a View3D under the cursor.
+ // Assumption is that last match in allModelNodes() list is the topmost one.
+ const QList<ModelNode> allNodes = selectionContext.view()->allModelNodes();
+ for (int i = allNodes.size() - 1; i >= 0; --i) {
+ if (SelectionContextHelpers::contains(allNodes[i], selectionContext.scenePosition())) {
+ if (allNodes[i].metaInfo().isQtQuick3DView3D())
+ targetNode = allNodes[i];
+ break;
+ }
+ }
+ }
+
+ if (targetNode.isValid()) {
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Editor3D", true);
- selectionContext.view()->emitView3DAction(View3DActionType::AlignViewToCamera, true);
+ if (scenePos.isNull()) {
+ selectionContext.view()->emitView3DAction(View3DActionType::AlignViewToCamera, true);
+ } else {
+ selectionContext.view()->emitCustomNotification("pick_3d_node_from_2d_scene",
+ {targetNode}, {scenePos});
+ }
}
}
bool isEffectComposerActivated()
{
- const QVector<ExtensionSystem::PluginSpec *> specs = ExtensionSystem::PluginManager::plugins();
+ const ExtensionSystem::PluginSpecs specs = ExtensionSystem::PluginManager::plugins();
return std::find_if(specs.begin(), specs.end(),
[](ExtensionSystem::PluginSpec *spec) {
return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled();
@@ -1727,13 +1729,12 @@ void openOldEffectMaker(const QString &filePath)
return;
}
- Utils::FilePath projectPath = target->project()->projectDirectory();
- QString effectName = QFileInfo(filePath).baseName();
- QString effectResDir = QLatin1String(Constants::DEFAULT_EFFECTS_IMPORT_FOLDER)
- + "/" + effectName;
- Utils::FilePath effectResPath = projectPath.pathAppended(effectResDir);
+ Utils::FilePath effectResPath = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().composedEffectsBasePath()
+ .pathAppended(QFileInfo(filePath).baseName());
+
if (!effectResPath.exists())
- QDir().mkpath(effectResPath.toString());
+ effectResPath.createDir();
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
@@ -1769,14 +1770,11 @@ void openOldEffectMaker(const QString &filePath)
Utils::FilePath getEffectsImportDirectory()
{
- QString defaultDir = QLatin1String(Constants::DEFAULT_EFFECTS_IMPORT_FOLDER);
- Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
- Utils::FilePath effectsPath = projectPath.pathAppended(defaultDir);
+ Utils::FilePath effectsPath = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().composedEffectsBasePath();
- if (!effectsPath.exists()) {
- QDir dir(projectPath.toString());
- dir.mkpath(effectsPath.toString());
- }
+ if (!effectsPath.exists())
+ effectsPath.createDir();
return effectsPath;
}
@@ -1794,12 +1792,9 @@ QString getEffectsDefaultDirectory(const QString &defaultDir)
QString getEffectIcon(const QString &effectPath)
{
- Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
- QString effectName = QFileInfo(effectPath).baseName();
- QString effectResDir = "asset_imports/Effects/" + effectName;
- Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir + "/" + effectName + ".qml");
-
- return effectResPath.exists() ? QString("effectExported") : QString("effectClass");
+ Utils::FilePath effectFile = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().composedEffectPath(effectPath);
+ return effectFile.exists() ? QString("effectExported") : QString("effectClass");
}
bool useLayerEffect()
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index a67cef4942..26562f429a 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -92,7 +92,6 @@ void layoutGridLayout(const SelectionContext &selectionState);
void goImplementation(const SelectionContext &selectionState);
void addNewSignalHandler(const SelectionContext &selectionState);
void editMaterial(const SelectionContext &selectionContext);
-void editCollection(const SelectionContext &selectionContext);
void addSignalHandlerOrGotoImplementation(const SelectionContext &selectionState, bool addAlwaysNewSlot);
void removeLayout(const SelectionContext &selectionContext);
void removePositioner(const SelectionContext &selectionContext);
diff --git a/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp b/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp
index 8cc84058d2..58326dc77a 100644
--- a/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp
@@ -37,7 +37,7 @@ Type getProperty(const QmlJS::SimpleReaderNode *node, const QString &name)
{
if (auto property = node->property(name)) {
const auto &value = property.value;
- if (value.type() == QVariant::List) {
+ if (value.typeId() == QMetaType::QVariantList) {
auto list = value.toList();
if (list.size())
return list.front().value<Type>();
@@ -179,7 +179,7 @@ std::optional<PropertyComponentGenerator::Entry> createEntry(QmlJS::SimpleReader
if (moduleName.isEmpty())
return {};
- auto module = model->module(moduleName);
+ auto module = model->module(moduleName, Storage::ModuleKind::QmlLibrary);
auto typeName = getProperty<QByteArray>(node, "typeNames");
diff --git a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp
index 4a229564c6..24047f650f 100644
--- a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp
@@ -222,6 +222,10 @@ bool createQmlrcFile(const FilePath &qmlrcFilePath)
rccProcess.setWorkingDirectory(project->projectDirectory());
const QStringList arguments = {"--binary",
+ "--compress",
+ "9",
+ "--threshold",
+ "30",
"--output",
qmlrcFilePath.toString(),
tempQrcFile.toString()};
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.cpp b/src/plugins/qmldesigner/components/componentcore/theme.cpp
index af495fd3b5..ef618447e7 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/theme.cpp
@@ -10,6 +10,7 @@
#include <utils/stylehelper.h>
+#include <qqml.h>
#include <QApplication>
#include <QMainWindow>
#include <QPointer>
@@ -18,7 +19,7 @@
#include <QQmlProperty>
#include <QRegularExpression>
#include <QScreen>
-#include <qqml.h>
+#include <QWindow>
static Q_LOGGING_CATEGORY(themeLog, "qtc.qmldesigner.theme", QtWarningMsg)
@@ -140,7 +141,9 @@ bool Theme::highPixelDensity() const
QWindow *Theme::mainWindowHandle() const
{
- return Core::ICore::mainWindow()->windowHandle();
+ QWindow *handle = Core::ICore::mainWindow()->windowHandle();
+ QQmlEngine::setObjectOwnership(handle, QJSEngine::CppOwnership);
+ return handle;
}
QPixmap Theme::getPixmap(const QString &id)
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index 73184d391c..392f6c94f6 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -83,6 +83,7 @@ public:
binding_medium,
bounds_small,
branch_medium,
+ cameraSpeed_medium,
camera_medium,
camera_small,
centerHorizontal,
diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
index 05d6f5fdf0..a56735862f 100644
--- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
@@ -7,7 +7,6 @@
#include <abstractview.h>
#include <assetslibraryview.h>
#include <capturingconnectionmanager.h>
-#include <collectionview.h>
#include <componentaction.h>
#include <componentview.h>
#include <contentlibraryview.h>
@@ -42,14 +41,6 @@
namespace QmlDesigner {
-static bool enableModelEditor()
-{
- Utils::QtcSettings *settings = Core::ICore::settings();
- const Utils::Key enableModelManagerKey = "QML/Designer/UseExperimentalFeatures44";
-
- return settings->value(enableModelManagerKey, false).toBool();
-}
-
static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg)
class ViewManagerData
@@ -64,19 +55,22 @@ public:
: connectionManager,
externalDependencies,
true)
- , collectionView{externalDependencies}
- , contentLibraryView{externalDependencies}
+ , contentLibraryView{imageCache, externalDependencies}
, componentView{externalDependencies}
+#ifndef QTC_USE_QML_DESIGNER_LITE
, edit3DView{externalDependencies}
+#endif
, formEditorView{externalDependencies}
, textEditorView{externalDependencies}
, assetsLibraryView{externalDependencies}
, itemLibraryView(imageCache, externalDependencies)
, navigatorView{externalDependencies}
, propertyEditorView(imageCache, externalDependencies)
+#ifndef QTC_USE_QML_DESIGNER_LITE
, materialEditorView{externalDependencies}
, materialBrowserView{imageCache, externalDependencies}
, textureEditorView{imageCache, externalDependencies}
+#endif
, statesEditorView{externalDependencies}
{}
@@ -86,19 +80,22 @@ public:
Internal::DebugView debugView;
DesignerActionManagerView designerActionManagerView;
NodeInstanceView nodeInstanceView;
- CollectionView collectionView;
ContentLibraryView contentLibraryView;
ComponentView componentView;
+#ifndef QTC_USE_QML_DESIGNER_LITE
Edit3DView edit3DView;
+#endif
FormEditorView formEditorView;
TextEditorView textEditorView;
AssetsLibraryView assetsLibraryView;
ItemLibraryView itemLibraryView;
NavigatorView navigatorView;
PropertyEditorView propertyEditorView;
+#ifndef QTC_USE_QML_DESIGNER_LITE
MaterialEditorView materialEditorView;
MaterialBrowserView materialBrowserView;
TextureEditorView textureEditorView;
+#endif
StatesEditorView statesEditorView;
std::vector<std::unique_ptr<AbstractView>> additionalViews;
@@ -203,6 +200,7 @@ QList<AbstractView *> ViewManager::views() const
QList<AbstractView *> ViewManager::standardViews() const
{
+#ifndef QTC_USE_QML_DESIGNER_LITE
QList<AbstractView *> list = {&d->edit3DView,
&d->formEditorView,
&d->textEditorView,
@@ -215,9 +213,16 @@ QList<AbstractView *> ViewManager::standardViews() const
&d->textureEditorView,
&d->statesEditorView,
&d->designerActionManagerView};
-
- if (enableModelEditor())
- list.append(&d->collectionView);
+#else
+ QList<AbstractView *> list = {&d->formEditorView,
+ &d->textEditorView,
+ &d->assetsLibraryView,
+ &d->itemLibraryView,
+ &d->navigatorView,
+ &d->propertyEditorView,
+ &d->statesEditorView,
+ &d->designerActionManagerView};
+#endif
if (QmlDesignerPlugin::instance()
->settings()
@@ -384,19 +389,21 @@ QList<WidgetInfo> ViewManager::widgetInfos() const
{
QList<WidgetInfo> widgetInfoList;
+#ifndef QTC_USE_QML_DESIGNER_LITE
widgetInfoList.append(d->edit3DView.widgetInfo());
+#endif
widgetInfoList.append(d->formEditorView.widgetInfo());
widgetInfoList.append(d->textEditorView.widgetInfo());
widgetInfoList.append(d->assetsLibraryView.widgetInfo());
widgetInfoList.append(d->itemLibraryView.widgetInfo());
widgetInfoList.append(d->navigatorView.widgetInfo());
widgetInfoList.append(d->propertyEditorView.widgetInfo());
+#ifndef QTC_USE_QML_DESIGNER_LITE
widgetInfoList.append(d->materialEditorView.widgetInfo());
widgetInfoList.append(d->materialBrowserView.widgetInfo());
widgetInfoList.append(d->textureEditorView.widgetInfo());
+#endif
widgetInfoList.append(d->statesEditorView.widgetInfo());
- if (enableModelEditor())
- widgetInfoList.append(d->collectionView.widgetInfo());
if (checkEnterpriseLicense())
widgetInfoList.append(d->contentLibraryView.widgetInfo());
diff --git a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
index f871bae84b..2cee7b0f97 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
@@ -22,6 +22,7 @@ namespace QmlDesigner {
BindingModel::BindingModel(ConnectionView *view)
: m_connectionView(view)
+ , m_delegate(*this)
{
setHorizontalHeaderLabels(BindingModelItem::headerLabels());
}
@@ -246,11 +247,8 @@ void BindingModel::addModelNode(const ModelNode &node)
appendRow(new BindingModelItem(property));
}
-BindingModelBackendDelegate::BindingModelBackendDelegate()
- : m_targetNode()
- , m_property()
- , m_sourceNode()
- , m_sourceNodeProperty()
+BindingModelBackendDelegate::BindingModelBackendDelegate(BindingModel &model)
+ : m_model{model}
{
connect(&m_sourceNode, &StudioQmlComboBoxBackend::activated, this, [this] {
sourceNodeChanged();
@@ -322,17 +320,14 @@ StudioQmlComboBoxBackend *BindingModelBackendDelegate::sourceProperty()
void BindingModelBackendDelegate::sourceNodeChanged()
{
- BindingModel *model = qobject_cast<BindingModel *>(parent());
- QTC_ASSERT(model, return);
-
- ConnectionView *view = model->connectionView();
+ ConnectionView *view = m_model.connectionView();
QTC_ASSERT(view, return);
QTC_ASSERT(view->isAttached(), return );
const QString sourceNode = m_sourceNode.currentText();
const QString sourceProperty = m_sourceNodeProperty.currentText();
- BindingProperty targetProperty = model->currentProperty();
+ BindingProperty targetProperty = m_model.currentProperty();
QStringList properties = availableSourceProperties(sourceNode, targetProperty, view);
if (!properties.contains(sourceProperty)) {
@@ -351,9 +346,6 @@ void BindingModelBackendDelegate::sourcePropertyNameChanged() const
return;
auto commit = [this, sourceProperty]() {
- BindingModel *model = qobject_cast<BindingModel *>(parent());
- QTC_ASSERT(model, return);
-
const QString sourceNode = m_sourceNode.currentText();
QString expression;
if (sourceProperty.isEmpty())
@@ -361,8 +353,8 @@ void BindingModelBackendDelegate::sourcePropertyNameChanged() const
else
expression = sourceNode + QLatin1String(".") + sourceProperty;
- int row = model->currentIndex();
- model->commitExpression(row, expression);
+ int row = m_model.currentIndex();
+ m_model.commitExpression(row, expression);
};
callLater(commit);
@@ -371,11 +363,9 @@ void BindingModelBackendDelegate::sourcePropertyNameChanged() const
void BindingModelBackendDelegate::targetPropertyNameChanged() const
{
auto commit = [this] {
- BindingModel *model = qobject_cast<BindingModel *>(parent());
- QTC_ASSERT(model, return);
const PropertyName propertyName = m_property.currentText().toUtf8();
- int row = model->currentIndex();
- model->commitPropertyName(row, propertyName);
+ int row = m_model.currentIndex();
+ m_model.commitPropertyName(row, propertyName);
};
callLater(commit);
diff --git a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
index b57cc5c958..69b137e78a 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
@@ -30,7 +30,7 @@ signals:
void targetNodeChanged();
public:
- BindingModelBackendDelegate();
+ BindingModelBackendDelegate(class BindingModel &model);
void update(const BindingProperty &property, AbstractView *view);
@@ -44,6 +44,7 @@ private:
StudioQmlComboBoxBackend *sourceNode();
StudioQmlComboBoxBackend *sourceProperty();
+ BindingModel &m_model;
QString m_targetNode;
StudioQmlComboBoxBackend m_property;
StudioQmlComboBoxBackend m_sourceNode;
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectioneditorutils.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectioneditorutils.cpp
index 57ca619a70..3cbfb8c038 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectioneditorutils.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectioneditorutils.cpp
@@ -212,7 +212,8 @@ bool isDynamicVariantPropertyType(const TypeName &type)
{
// "variant" is considered value type as it is initialized as one.
// This may need to change if we provide any kind of proper editor for it.
- static const QSet<TypeName> valueTypes{"int", "real", "color", "string", "bool", "url", "var", "variant"};
+ static const QSet<TypeName> valueTypes{
+ "int", "real", "double", "color", "string", "bool", "url", "var", "variant"};
return valueTypes.contains(type);
}
diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
index 9fdd3daec3..fa29c6c8a1 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
@@ -25,7 +25,7 @@ namespace QmlDesigner {
DynamicPropertiesModel::DynamicPropertiesModel(bool exSelection, AbstractView *view)
: m_view(view)
- , m_delegate(std::make_unique<DynamicPropertiesModelBackendDelegate>())
+ , m_delegate(std::make_unique<DynamicPropertiesModelBackendDelegate>(*this))
, m_explicitSelection(exSelection)
{
setHorizontalHeaderLabels(DynamicPropertiesItem::headerLabels());
@@ -382,8 +382,8 @@ void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
reset();
}
-DynamicPropertiesModelBackendDelegate::DynamicPropertiesModelBackendDelegate()
- : m_internalNodeId(std::nullopt)
+DynamicPropertiesModelBackendDelegate::DynamicPropertiesModelBackendDelegate(DynamicPropertiesModel &model)
+ : m_model(model)
{
m_type.setModel({"int", "bool", "var", "real", "string", "url", "color"});
connect(&m_type, &StudioQmlComboBoxBackend::activated, this, [this] { handleTypeChanged(); });
@@ -411,32 +411,26 @@ void DynamicPropertiesModelBackendDelegate::update(const AbstractProperty &prope
void DynamicPropertiesModelBackendDelegate::handleTypeChanged()
{
- DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
- QTC_ASSERT(model, return);
-
const PropertyName name = m_name.text().toUtf8();
- int current = model->currentIndex();
+ int current = m_model.currentIndex();
const TypeName type = m_type.currentText().toUtf8();
- model->commitPropertyType(current, type);
+ m_model.commitPropertyType(current, type);
// The order might have changed!
- model->setCurrent(m_internalNodeId.value_or(-1), name);
+ m_model.setCurrent(m_internalNodeId.value_or(-1), name);
}
void DynamicPropertiesModelBackendDelegate::handleNameChanged()
{
- DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
- QTC_ASSERT(model, return);
-
const PropertyName name = m_name.text().toUtf8();
QTC_ASSERT(!name.isEmpty(), return);
- int current = model->currentIndex();
- model->commitPropertyName(current, name);
+ int current = m_model.currentIndex();
+ m_model.commitPropertyName(current, name);
// The order might have changed!
- model->setCurrent(m_internalNodeId.value_or(-1), name);
+ m_model.setCurrent(m_internalNodeId.value_or(-1), name);
}
// TODO: Maybe replace with utils typeConvertVariant?
@@ -456,12 +450,9 @@ QVariant valueFromText(const QString &value, const QString &type)
void DynamicPropertiesModelBackendDelegate::handleValueChanged()
{
- DynamicPropertiesModel *model = qobject_cast<DynamicPropertiesModel *>(parent());
- QTC_ASSERT(model, return);
-
- int current = model->currentIndex();
+ int current = m_model.currentIndex();
QVariant value = valueFromText(m_value.text(), m_type.currentText());
- model->commitPropertyValue(current, value);
+ m_model.commitPropertyValue(current, value);
}
QString DynamicPropertiesModelBackendDelegate::targetNode() const
diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
index c2beed8730..071c72bef8 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
@@ -97,7 +97,7 @@ class DynamicPropertiesModelBackendDelegate : public QObject
Q_PROPERTY(StudioQmlTextBackend *value READ value CONSTANT)
public:
- DynamicPropertiesModelBackendDelegate();
+ DynamicPropertiesModelBackendDelegate(DynamicPropertiesModel &model);
void update(const AbstractProperty &property);
@@ -116,6 +116,7 @@ private:
StudioQmlTextBackend *value();
QString targetNode() const;
+ DynamicPropertiesModel &m_model;
std::optional<int> m_internalNodeId;
StudioQmlComboBoxBackend m_type;
StudioQmlTextBackend m_name;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp
index 9e6bdd03b9..6388c93fa9 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.cpp
@@ -3,83 +3,67 @@
#include "contentlibrarybundleimporter.h"
-#include "documentmanager.h"
-#include "import.h"
-#include "model.h"
-#include "qmldesignerconstants.h"
-#include "qmldesignerplugin.h"
-#include "rewritingexception.h"
+#include <documentmanager.h>
+#include <import.h>
+#include <model.h>
+#include <nodemetainfo.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+#include <rewritingexception.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
-#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStringList>
using namespace Utils;
-namespace QmlDesigner::Internal {
+namespace QmlDesigner {
-ContentLibraryBundleImporter::ContentLibraryBundleImporter(const QString &bundleDir,
- const QString &bundleId,
- const QStringList &sharedFiles,
- QObject *parent)
+ContentLibraryBundleImporter::ContentLibraryBundleImporter(QObject *parent)
: QObject(parent)
- , m_bundleDir(FilePath::fromString(bundleDir))
- , m_bundleId(bundleId)
- , m_sharedFiles(sharedFiles)
{
m_importTimer.setInterval(200);
connect(&m_importTimer, &QTimer::timeout, this, &ContentLibraryBundleImporter::handleImportTimer);
- m_moduleName = QStringLiteral("%1.%2").arg(
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
- m_bundleId).mid(1); // Chop leading slash
}
// Returns empty string on success or an error message on failure.
// Note that there is also an asynchronous portion to the import, which will only
// be done if this method returns success. Once the asynchronous portion of the
// import is completed, importFinished signal will be emitted.
-QString ContentLibraryBundleImporter::importComponent(const QString &qmlFile,
+QString ContentLibraryBundleImporter::importComponent(const QString &bundleDir,
+ const TypeName &type,
+ const QString &qmlFile,
const QStringList &files)
{
- FilePath bundleImportPath = resolveBundleImportPath();
+ QString module = QString::fromLatin1(type.left(type.lastIndexOf('.')));
+ m_bundleId = module.mid(module.lastIndexOf('.') + 1);
+
+ FilePath bundleDirPath = FilePath::fromString(bundleDir); // source dir
+ FilePath bundleImportPath = resolveBundleImportPath(m_bundleId); // target dir
+
if (bundleImportPath.isEmpty())
return "Failed to resolve bundle import folder";
- bool bundleImportPathExists = bundleImportPath.exists();
-
- if (!bundleImportPathExists && !bundleImportPath.createDir())
+ if (!bundleImportPath.exists() && !bundleImportPath.createDir())
return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toString());
- for (const QString &file : std::as_const(m_sharedFiles)) {
- FilePath target = bundleImportPath.resolvePath(file);
- if (!target.exists()) {
- FilePath parentDir = target.parentDir();
- if (!parentDir.exists() && !parentDir.createDir())
- return QStringLiteral("Failed to create folder for: '%1'").arg(target.toString());
- FilePath source = m_bundleDir.resolvePath(file);
- if (!source.copyFile(target))
- return QStringLiteral("Failed to copy shared file: '%1'").arg(source.toString());
- }
- }
-
- FilePath qmldirPath = bundleImportPath.resolvePath(QStringLiteral("qmldir"));
+ FilePath qmldirPath = bundleImportPath.pathAppended("qmldir");
QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray()));
if (qmldirContent.isEmpty()) {
qmldirContent.append("module ");
- qmldirContent.append(m_moduleName);
+ qmldirContent.append(module);
qmldirContent.append('\n');
}
- FilePath qmlSourceFile = bundleImportPath.resolvePath(FilePath::fromString(qmlFile));
+ FilePath qmlSourceFile = bundleImportPath.pathAppended(qmlFile);
const bool qmlFileExists = qmlSourceFile.exists();
const QString qmlType = qmlSourceFile.baseName();
- const QString fullTypeName = QStringLiteral("%1.%2.%3")
- .arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), m_bundleId, qmlType);
- if (m_pendingTypes.contains(fullTypeName) && !m_pendingTypes[fullTypeName])
- return QStringLiteral("Unable to import while unimporting the same type: '%1'").arg(fullTypeName);
+
+ if (m_pendingTypes.contains(type) && !m_pendingTypes.value(type))
+ return QStringLiteral("Unable to import while unimporting the same type: '%1'").arg(QLatin1String(type));
+
if (!qmldirContent.contains(qmlFile)) {
qmldirContent.append(qmlType);
qmldirContent.append(" 1.0 ");
@@ -92,12 +76,12 @@ QString ContentLibraryBundleImporter::importComponent(const QString &qmlFile,
allFiles.append(files);
allFiles.append(qmlFile);
for (const QString &file : std::as_const(allFiles)) {
- FilePath target = bundleImportPath.resolvePath(file);
+ FilePath target = bundleImportPath.pathAppended(file);
FilePath parentDir = target.parentDir();
if (!parentDir.exists() && !parentDir.createDir())
return QStringLiteral("Failed to create folder for: '%1'").arg(target.toString());
- FilePath source = m_bundleDir.resolvePath(file);
+ FilePath source = bundleDirPath.pathAppended(file);
if (target.exists()) {
if (source.lastModified() == target.lastModified())
continue;
@@ -126,23 +110,23 @@ QString ContentLibraryBundleImporter::importComponent(const QString &qmlFile,
if (!model)
return "Model not available, cannot add import statement or update code model";
- Import import = Import::createLibraryImport(m_moduleName, "1.0");
+ Import import = Import::createLibraryImport(module, "1.0");
if (!model->hasImport(import)) {
if (model->possibleImports().contains(import)) {
- m_importAddPending = false;
+ m_pendingImport.clear();
try {
model->changeImports({import}, {});
} catch (const RewritingException &) {
// No point in trying to add import asynchronously either, so just fail out
- return QStringLiteral("Failed to add import statement for: '%1'").arg(m_moduleName);
+ return QStringLiteral("Failed to add import statement for: '%1'").arg(module);
}
} else {
// If import is not yet possible, import statement needs to be added asynchronously to
// avoid errors, as code model update takes a while.
- m_importAddPending = true;
+ m_pendingImport = module;
}
}
- m_pendingTypes.insert(fullTypeName, true);
+ m_pendingTypes.insert(type, true);
m_importTimerCount = 0;
m_importTimer.start();
@@ -154,17 +138,19 @@ void ContentLibraryBundleImporter::handleImportTimer()
auto handleFailure = [this] {
m_importTimer.stop();
m_fullReset = false;
- m_importAddPending = false;
+ m_pendingImport.clear();
m_importTimerCount = 0;
// Emit dummy finished signals for all pending types
- const QStringList pendingTypes = m_pendingTypes.keys();
- for (const QString &pendingType : pendingTypes) {
+ const QList<TypeName> pendingTypes = m_pendingTypes.keys();
+ for (const TypeName &pendingType : pendingTypes) {
m_pendingTypes.remove(pendingType);
- if (m_pendingTypes[pendingType])
- emit importFinished({});
+ if (m_pendingTypes.value(pendingType))
+ emit importFinished({}, m_bundleId);
else
- emit unimportFinished({});
+ emit unimportFinished({}, m_bundleId);
+
+ m_bundleId.clear();
}
};
@@ -186,12 +172,12 @@ void ContentLibraryBundleImporter::handleImportTimer()
QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
- if (m_importAddPending) {
+ if (!m_pendingImport.isEmpty()) {
try {
- Import import = Import::createLibraryImport(m_moduleName, "1.0");
+ Import import = Import::createLibraryImport(m_pendingImport, "1.0");
if (model->possibleImports().contains(import)) {
model->changeImports({import}, {});
- m_importAddPending = false;
+ m_pendingImport.clear();
}
} catch (const RewritingException &) {
// Import adding is unlikely to succeed later, either, so just bail out
@@ -201,21 +187,23 @@ void ContentLibraryBundleImporter::handleImportTimer()
}
// Detect when the code model has the new material(s) fully available
- const QStringList pendingTypes = m_pendingTypes.keys();
- for (const QString &pendingType : pendingTypes) {
- NodeMetaInfo metaInfo = model->metaInfo(pendingType.toUtf8());
- const bool isImport = m_pendingTypes[pendingType];
+ const QList<TypeName> pendingTypes = m_pendingTypes.keys();
+ for (const TypeName &pendingType : pendingTypes) {
+ NodeMetaInfo metaInfo = model->metaInfo(pendingType);
+ const bool isImport = m_pendingTypes.value(pendingType);
const bool typeComplete = metaInfo.isValid() && !metaInfo.prototypes().empty();
if (isImport == typeComplete) {
m_pendingTypes.remove(pendingType);
if (isImport)
#ifdef QDS_USE_PROJECTSTORAGE
- emit importFinished(pendingType.toUtf8());
+ emit importFinished(pendingType, m_bundleId);
#else
- emit importFinished(metaInfo);
+ emit importFinished(metaInfo, m_bundleId);
#endif
else
- emit unimportFinished(metaInfo);
+ emit unimportFinished(metaInfo, m_bundleId);
+
+ m_bundleId.clear();
}
}
@@ -225,10 +213,10 @@ void ContentLibraryBundleImporter::handleImportTimer()
}
}
-QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const Utils::FilePath &bundlePath)
+QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const FilePath &bundlePath)
{
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
- const Utils::expected_str<QByteArray> content = assetRefPath.fileContents();
+ const expected_str<QByteArray> content = assetRefPath.fileContents();
if (content) {
QJsonParseError error;
QJsonDocument bundleDataJsonDoc = QJsonDocument::fromJson(*content, &error);
@@ -242,7 +230,7 @@ QVariantHash ContentLibraryBundleImporter::loadAssetRefMap(const Utils::FilePath
return {};
}
-void ContentLibraryBundleImporter::writeAssetRefMap(const Utils::FilePath &bundlePath,
+void ContentLibraryBundleImporter::writeAssetRefMap(const FilePath &bundlePath,
const QVariantHash &assetRefMap)
{
FilePath assetRefPath = bundlePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_ASSET_REF_FILE));
@@ -253,9 +241,14 @@ void ContentLibraryBundleImporter::writeAssetRefMap(const Utils::FilePath &bundl
}
}
-QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
+QString ContentLibraryBundleImporter::unimportComponent(const TypeName &type, const QString &qmlFile)
{
- FilePath bundleImportPath = resolveBundleImportPath();
+ QString module = QString::fromLatin1(type.left(type.lastIndexOf('.')));
+ m_bundleId = module.mid(module.lastIndexOf('.') + 1);
+
+ emit aboutToUnimport(type, m_bundleId);
+
+ FilePath bundleImportPath = resolveBundleImportPath(m_bundleId);
if (bundleImportPath.isEmpty())
return QStringLiteral("Failed to resolve bundle import folder for: '%1'").arg(qmlFile);
@@ -274,10 +267,10 @@ QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
QByteArray newContent;
QString qmlType = qmlFilePath.baseName();
- const QString fullTypeName = QStringLiteral("%1.%2.%3")
- .arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), m_bundleId, qmlType);
- if (m_pendingTypes.contains(fullTypeName) && m_pendingTypes[fullTypeName])
- return QStringLiteral("Unable to unimport while importing the same type: '%1'").arg(fullTypeName);
+ if (m_pendingTypes.contains(type) && m_pendingTypes.value(type)) {
+ return QStringLiteral("Unable to unimport while importing the same type: '%1'")
+ .arg(QString::fromLatin1(type));
+ }
if (qmldirContent) {
int typeIndex = qmldirContent->indexOf(qmlType.toUtf8());
@@ -293,7 +286,7 @@ QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
}
}
- m_pendingTypes.insert(fullTypeName, false);
+ m_pendingTypes.insert(type, false);
QVariantHash assetRefMap = loadAssetRefMap(bundleImportPath);
bool writeAssetRefs = false;
@@ -327,7 +320,7 @@ QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
Model *model = doc ? doc->currentModel() : nullptr;
if (model) {
- Import import = Import::createLibraryImport(m_moduleName, "1.0");
+ Import import = Import::createLibraryImport(module, "1.0");
if (model->imports().contains(import))
model->changeImports({}, {import});
}
@@ -340,18 +333,14 @@ QString ContentLibraryBundleImporter::unimportComponent(const QString &qmlFile)
return {};
}
-FilePath ContentLibraryBundleImporter::resolveBundleImportPath()
+FilePath ContentLibraryBundleImporter::resolveBundleImportPath(const QString &bundleId)
{
- FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
+ FilePath bundleImportPath = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().componentBundlesBasePath();
if (bundleImportPath.isEmpty())
- return bundleImportPath;
-
- const QString projectBundlePath = QStringLiteral("%1%2/%3").arg(
- QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER),
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER),
- m_bundleId).mid(1); // Chop leading slash
+ return {};
- return bundleImportPath.resolvePath(projectBundlePath);
+ return bundleImportPath.resolvePath(bundleId);
}
-} // namespace QmlDesigner::Internal
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h
index 3aff09fe34..8155311e3e 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarybundleimporter.h
@@ -3,59 +3,53 @@
#pragma once
-#include <utils/filepath.h>
+#include <modelfwd.h>
-#include "nodemetainfo.h"
+#include <utils/filepath.h>
#include <QTimer>
#include <QVariantHash>
-QT_BEGIN_NAMESPACE
-QT_END_NAMESPACE
+namespace QmlDesigner {
-namespace QmlDesigner::Internal {
+class NodeMetaInfo;
class ContentLibraryBundleImporter : public QObject
{
Q_OBJECT
public:
- ContentLibraryBundleImporter(const QString &bundleDir,
- const QString &bundleId,
- const QStringList &sharedFiles,
- QObject *parent = nullptr);
+ ContentLibraryBundleImporter(QObject *parent = nullptr);
~ContentLibraryBundleImporter() = default;
- QString importComponent(const QString &qmlFile,
+ QString importComponent(const QString &bundleDir, const TypeName &type, const QString &qmlFile,
const QStringList &files);
- QString unimportComponent(const QString &qmlFile);
- Utils::FilePath resolveBundleImportPath();
+ QString unimportComponent(const TypeName &type, const QString &qmlFile);
+ Utils::FilePath resolveBundleImportPath(const QString &bundleId);
signals:
// The metaInfo parameter will be invalid if an error was encountered during
// asynchronous part of the import. In this case all remaining pending imports have been
// terminated, and will not receive separate importFinished notifications.
#ifdef QDS_USE_PROJECTSTORAGE
- void importFinished(const QmlDesigner::TypeName &typeName);
+ void importFinished(const QmlDesigner::TypeName &typeName, const QString &bundleId);
#else
- void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo, const QString &bundleId);
#endif
- void unimportFinished(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void unimportFinished(const QmlDesigner::NodeMetaInfo &metaInfo, const QString &bundleId);
+ void aboutToUnimport(const TypeName &type, const QString &bundleId);
private:
void handleImportTimer();
QVariantHash loadAssetRefMap(const Utils::FilePath &bundlePath);
void writeAssetRefMap(const Utils::FilePath &bundlePath, const QVariantHash &assetRefMap);
- Utils::FilePath m_bundleDir;
- QString m_bundleId;
- QString m_moduleName;
- QStringList m_sharedFiles;
QTimer m_importTimer;
int m_importTimerCount = 0;
- bool m_importAddPending = false;
+ QString m_pendingImport;
+ QString m_bundleId;
bool m_fullReset = false;
- QHash<QString, bool> m_pendingTypes; // <type, isImport>
+ QHash<TypeName, bool> m_pendingTypes; // <type, isImport>
};
-} // namespace QmlDesigner::Internal
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.cpp
deleted file mode 100644
index f572fbe65f..0000000000
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 "contentlibraryeffect.h"
-
-#include <QFileInfo>
-
-namespace QmlDesigner {
-
-ContentLibraryEffect::ContentLibraryEffect(QObject *parent,
- const QString &name,
- const QString &qml,
- const TypeName &type,
- const QUrl &icon,
- const QStringList &files)
- : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files)
-{
- m_allFiles = m_files;
- m_allFiles.push_back(m_qml);
-}
-
-bool ContentLibraryEffect::filter(const QString &searchText)
-{
- if (m_visible != m_name.contains(searchText, Qt::CaseInsensitive)) {
- m_visible = !m_visible;
- emit itemVisibleChanged();
- }
-
- return m_visible;
-}
-
-QUrl ContentLibraryEffect::icon() const
-{
- return m_icon;
-}
-
-QString ContentLibraryEffect::qml() const
-{
- return m_qml;
-}
-
-TypeName ContentLibraryEffect::type() const
-{
- return m_type;
-}
-
-QStringList ContentLibraryEffect::files() const
-{
- return m_files;
-}
-
-bool ContentLibraryEffect::visible() const
-{
- return m_visible;
-}
-
-bool ContentLibraryEffect::setImported(bool imported)
-{
- if (m_imported != imported) {
- m_imported = imported;
- emit itemImportedChanged();
- return true;
- }
-
- return false;
-}
-
-bool ContentLibraryEffect::imported() const
-{
- return m_imported;
-}
-
-QStringList ContentLibraryEffect::allFiles() const
-{
- return m_allFiles;
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.cpp
index 38e6eed3da..f904775d52 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.cpp
@@ -3,14 +3,12 @@
#include "contentlibraryeffectscategory.h"
-#include "contentlibraryeffect.h"
-
namespace QmlDesigner {
ContentLibraryEffectsCategory::ContentLibraryEffectsCategory(QObject *parent, const QString &name)
: QObject(parent), m_name(name) {}
-void ContentLibraryEffectsCategory::addBundleItem(ContentLibraryEffect *bundleItem)
+void ContentLibraryEffectsCategory::addBundleItem(ContentLibraryItem *bundleItem)
{
m_categoryItems.append(bundleItem);
}
@@ -19,7 +17,7 @@ bool ContentLibraryEffectsCategory::updateImportedState(const QStringList &impor
{
bool changed = false;
- for (ContentLibraryEffect *item : std::as_const(m_categoryItems))
+ for (ContentLibraryItem *item : std::as_const(m_categoryItems))
changed |= item->setImported(importedItems.contains(item->qml().chopped(4)));
return changed;
@@ -28,7 +26,7 @@ bool ContentLibraryEffectsCategory::updateImportedState(const QStringList &impor
bool ContentLibraryEffectsCategory::filter(const QString &searchText)
{
bool visible = false;
- for (ContentLibraryEffect *item : std::as_const(m_categoryItems))
+ for (ContentLibraryItem *item : std::as_const(m_categoryItems))
visible |= item->filter(searchText);
if (visible != m_visible) {
@@ -55,7 +53,7 @@ bool ContentLibraryEffectsCategory::expanded() const
return m_expanded;
}
-QList<ContentLibraryEffect *> ContentLibraryEffectsCategory::categoryItems() const
+QList<ContentLibraryItem *> ContentLibraryEffectsCategory::categoryItems() const
{
return m_categoryItems;
}
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.h
index 79737c1ec2..9f56de3c6b 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectscategory.h
@@ -3,12 +3,12 @@
#pragma once
+#include "contentlibraryitem.h"
+
#include <QObject>
namespace QmlDesigner {
-class ContentLibraryEffect;
-
class ContentLibraryEffectsCategory : public QObject
{
Q_OBJECT
@@ -16,20 +16,20 @@ class ContentLibraryEffectsCategory : public QObject
Q_PROPERTY(QString bundleCategoryName MEMBER m_name CONSTANT)
Q_PROPERTY(bool bundleCategoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged)
Q_PROPERTY(bool bundleCategoryExpanded MEMBER m_expanded NOTIFY categoryExpandChanged)
- Q_PROPERTY(QList<ContentLibraryEffect *> bundleCategoryItems MEMBER m_categoryItems
+ Q_PROPERTY(QList<ContentLibraryItem *> bundleCategoryItems MEMBER m_categoryItems
NOTIFY categoryItemsChanged)
public:
ContentLibraryEffectsCategory(QObject *parent, const QString &name);
- void addBundleItem(ContentLibraryEffect *bundleItem);
+ void addBundleItem(ContentLibraryItem *bundleItem);
bool updateImportedState(const QStringList &importedMats);
bool filter(const QString &searchText);
QString name() const;
bool visible() const;
bool expanded() const;
- QList<ContentLibraryEffect *> categoryItems() const;
+ QList<ContentLibraryItem *> categoryItems() const;
signals:
void categoryVisibleChanged();
@@ -41,7 +41,7 @@ private:
bool m_visible = true;
bool m_expanded = true;
- QList<ContentLibraryEffect *> m_categoryItems;
+ QList<ContentLibraryItem *> m_categoryItems;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.cpp
index 6b1de2d2a7..e0fe2b6c54 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.cpp
@@ -4,11 +4,11 @@
#include "contentlibraryeffectsmodel.h"
#include "contentlibrarybundleimporter.h"
-#include "contentlibraryeffect.h"
#include "contentlibraryeffectscategory.h"
+#include "contentlibraryitem.h"
#include "contentlibrarywidget.h"
-#include "qmldesignerconstants.h"
+#include <qmldesignerplugin.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/hostosinfo.h>
@@ -63,6 +63,11 @@ bool ContentLibraryEffectsModel::isValidIndex(int idx) const
return idx > -1 && idx < rowCount();
}
+QString ContentLibraryEffectsModel::bundleId() const
+{
+ return m_bundleId;
+}
+
void ContentLibraryEffectsModel::updateIsEmpty()
{
bool anyCatVisible = Utils::anyOf(m_bundleCategories, [&](ContentLibraryEffectsCategory *cat) {
@@ -88,49 +93,23 @@ QHash<int, QByteArray> ContentLibraryEffectsModel::roleNames() const
return roles;
}
-void ContentLibraryEffectsModel::createImporter(const QString &bundlePath, const QString &bundleId,
- const QStringList &sharedFiles)
-{
- m_importer = new Internal::ContentLibraryBundleImporter(bundlePath, bundleId, sharedFiles);
-#ifdef QDS_USE_PROJECTSTORAGE
- connect(m_importer,
- &Internal::ContentLibraryBundleImporter::importFinished,
- this,
- [&](const QmlDesigner::TypeName &typeName) {
- m_importerRunning = false;
- emit importerRunningChanged();
- if (typeName.size())
- emit bundleItemImported(typeName);
- });
-#else
- connect(m_importer,
- &Internal::ContentLibraryBundleImporter::importFinished,
- this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- m_importerRunning = false;
- emit importerRunningChanged();
- if (metaInfo.isValid())
- emit bundleItemImported(metaInfo);
- });
-#endif
-
- connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- Q_UNUSED(metaInfo)
- m_importerRunning = false;
- emit importerRunningChanged();
- emit bundleItemUnimported(metaInfo);
- });
-
- resetModel();
- updateIsEmpty();
-}
-
void ContentLibraryEffectsModel::loadBundle()
{
- if (m_bundleExists || m_probeBundleDir)
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ if (m_probeBundleDir || (m_bundleExists && m_bundleId == compUtils.effectsBundleId()))
return;
+ // clean up
+ qDeleteAll(m_bundleCategories);
+ m_bundleCategories.clear();
+ m_bundleExists = false;
+ m_isEmpty = true;
+ m_probeBundleDir = false;
+ m_bundleObj = {};
+ m_bundleId.clear();
+ m_bundlePath.clear();
+
QDir bundleDir;
if (!qEnvironmentVariable("EFFECT_BUNDLE_PATH").isEmpty())
@@ -145,30 +124,32 @@ void ContentLibraryEffectsModel::loadBundle()
while (!bundleDir.cd("effect_bundle") && bundleDir.cdUp())
; // do nothing
- if (bundleDir.dirName() != "effect_bundle") // bundlePathDir not found
+ if (bundleDir.dirName() != "effect_bundle") { // bundlePathDir not found
+ resetModel();
return;
+ }
}
QString bundlePath = bundleDir.filePath("effect_bundle.json");
- if (m_bundleObj.isEmpty()) {
- QFile propsFile(bundlePath);
-
- if (!propsFile.open(QIODevice::ReadOnly)) {
- qWarning("Couldn't open effect_bundle.json");
- return;
- }
+ QFile bundleFile(bundlePath);
+ if (!bundleFile.open(QIODevice::ReadOnly)) {
+ qWarning("Couldn't open effect_bundle.json");
+ resetModel();
+ return;
+ }
- QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(propsFile.readAll());
- if (bundleJsonDoc.isNull()) {
- qWarning("Invalid effect_bundle.json file");
- return;
- } else {
- m_bundleObj = bundleJsonDoc.object();
- }
+ QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(bundleFile.readAll());
+ if (bundleJsonDoc.isNull()) {
+ qWarning("Invalid effect_bundle.json file");
+ resetModel();
+ return;
}
- QString bundleId = m_bundleObj.value("id").toString();
+ m_bundleObj = bundleJsonDoc.object();
+
+ QString bundleType = compUtils.effectsBundleType();
+ m_bundleId = compUtils.effectsBundleId();
const QJsonObject catsObj = m_bundleObj.value("categories").toObject();
const QStringList categories = catsObj.keys();
@@ -176,38 +157,36 @@ void ContentLibraryEffectsModel::loadBundle()
auto category = new ContentLibraryEffectsCategory(this, cat);
const QJsonObject itemsObj = catsObj.value(cat).toObject();
- const QStringList items = itemsObj.keys();
- for (const QString &item : items) {
- const QJsonObject itemObj = itemsObj.value(item).toObject();
+ const QStringList itemsNames = itemsObj.keys();
+ for (const QString &itemName : itemsNames) {
+ const QJsonObject itemObj = itemsObj.value(itemName).toObject();
QStringList files;
const QJsonArray assetsArr = itemObj.value("files").toArray();
- for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr)
+ for (const QJsonValueConstRef &asset : assetsArr)
files.append(asset.toString());
QUrl icon = QUrl::fromLocalFile(bundleDir.filePath(itemObj.value("icon").toString()));
QString qml = itemObj.value("qml").toString();
- TypeName type = QLatin1String("%1.%2.%3").arg(
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
- bundleId,
- qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
+ TypeName type = QLatin1String("%1.%2")
+ .arg(bundleType, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
- auto bundleItem = new ContentLibraryEffect(category, item, qml, type, icon, files);
+ auto bundleItem = new ContentLibraryItem(category, itemName, qml, type, icon, files);
category->addBundleItem(bundleItem);
}
m_bundleCategories.append(category);
}
- QStringList sharedFiles;
+ m_bundleSharedFiles.clear();
const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
- for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
- sharedFiles.append(file.toString());
-
- createImporter(bundleDir.path(), bundleId, sharedFiles);
+ for (const QJsonValueConstRef &file : sharedFilesArr)
+ m_bundleSharedFiles.append(file.toString());
+ m_bundlePath = bundleDir.path();
m_bundleExists = true;
- emit bundleExistsChanged();
+ updateIsEmpty();
+ resetModel();
}
bool ContentLibraryEffectsModel::hasRequiredQuick3DImport() const
@@ -220,11 +199,6 @@ bool ContentLibraryEffectsModel::bundleExists() const
return m_bundleExists;
}
-Internal::ContentLibraryBundleImporter *ContentLibraryEffectsModel::bundleImporter() const
-{
- return m_importer;
-}
-
void ContentLibraryEffectsModel::setSearchText(const QString &searchText)
{
QString lowerSearchText = searchText.toLower();
@@ -277,30 +251,26 @@ void ContentLibraryEffectsModel::resetModel()
endResetModel();
}
-void ContentLibraryEffectsModel::addInstance(ContentLibraryEffect *bundleItem)
+void ContentLibraryEffectsModel::addInstance(ContentLibraryItem *bundleItem)
{
- QString err = m_importer->importComponent(bundleItem->qml(), bundleItem->files());
+ QString err = m_widget->importer()->importComponent(m_bundlePath, bundleItem->type(),
+ bundleItem->qml(),
+ bundleItem->files() + m_bundleSharedFiles);
- if (err.isEmpty()) {
- m_importerRunning = true;
- emit importerRunningChanged();
- } else {
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
qWarning() << __FUNCTION__ << err;
- }
}
-void ContentLibraryEffectsModel::removeFromProject(ContentLibraryEffect *bundleItem)
+void ContentLibraryEffectsModel::removeFromProject(ContentLibraryItem *bundleItem)
{
- emit bundleItemAboutToUnimport(bundleItem->type());
+ QString err = m_widget->importer()->unimportComponent(bundleItem->type(), bundleItem->qml());
- QString err = m_importer->unimportComponent(bundleItem->qml());
-
- if (err.isEmpty()) {
- m_importerRunning = true;
- emit importerRunningChanged();
- } else {
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
qWarning() << __FUNCTION__ << err;
- }
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.h
index 5d67ac3da8..5bcb857fca 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffectsmodel.h
@@ -3,22 +3,15 @@
#pragma once
-#include "nodemetainfo.h"
-
#include <QAbstractListModel>
-#include <QDir>
#include <QJsonObject>
namespace QmlDesigner {
-class ContentLibraryEffect;
+class ContentLibraryItem;
class ContentLibraryEffectsCategory;
class ContentLibraryWidget;
-namespace Internal {
-class ContentLibraryBundleImporter;
-}
-
class ContentLibraryEffectsModel : public QAbstractListModel
{
Q_OBJECT
@@ -26,7 +19,6 @@ class ContentLibraryEffectsModel : public QAbstractListModel
Q_PROPERTY(bool bundleExists READ bundleExists NOTIFY bundleExistsChanged)
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
- Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
public:
ContentLibraryEffectsModel(ContentLibraryWidget *parent = nullptr);
@@ -49,46 +41,33 @@ public:
void resetModel();
void updateIsEmpty();
- Internal::ContentLibraryBundleImporter *bundleImporter() const;
+ Q_INVOKABLE void addInstance(QmlDesigner::ContentLibraryItem *bundleItem);
+ Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryItem *bundleItem);
- Q_INVOKABLE void addInstance(QmlDesigner::ContentLibraryEffect *bundleItem);
- Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryEffect *bundleItem);
+ QString bundleId() const;
signals:
void isEmptyChanged();
void hasRequiredQuick3DImportChanged();
-#ifdef QDS_USE_PROJECTSTORAGE
- void bundleItemImported(const QmlDesigner::TypeName &typeName);
-#else
- void bundleItemImported(const QmlDesigner::NodeMetaInfo &metaInfo);
-#endif
- void bundleItemAboutToUnimport(const QmlDesigner::TypeName &type);
- void bundleItemUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
- void importerRunningChanged();
void bundleExistsChanged();
private:
bool isValidIndex(int idx) const;
- void createImporter(const QString &bundlePath, const QString &bundleId,
- const QStringList &sharedFiles);
ContentLibraryWidget *m_widget = nullptr;
QString m_searchText;
+ QString m_bundlePath;
+ QString m_bundleId;
+ QStringList m_bundleSharedFiles;
QList<ContentLibraryEffectsCategory *> m_bundleCategories;
QJsonObject m_bundleObj;
- Internal::ContentLibraryBundleImporter *m_importer = nullptr;
bool m_isEmpty = true;
bool m_bundleExists = false;
bool m_probeBundleDir = false;
- bool m_importerRunning = false;
int m_quick3dMajorVersion = -1;
int m_quick3dMinorVersion = -1;
-
- QString m_importerBundlePath;
- QString m_importerBundleId;
- QStringList m_importerSharedFiles;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.cpp
new file mode 100644
index 0000000000..38fb69abbc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.cpp
@@ -0,0 +1,76 @@
+// 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 "contentlibraryitem.h"
+
+namespace QmlDesigner {
+
+ContentLibraryItem::ContentLibraryItem(QObject *parent,
+ const QString &name,
+ const QString &qml,
+ const TypeName &type,
+ const QUrl &icon,
+ const QStringList &files)
+ : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files)
+{
+ m_allFiles = m_files;
+ m_allFiles.push_back(m_qml);
+}
+
+bool ContentLibraryItem::filter(const QString &searchText)
+{
+ if (m_visible != m_name.contains(searchText, Qt::CaseInsensitive)) {
+ m_visible = !m_visible;
+ emit itemVisibleChanged();
+ }
+
+ return m_visible;
+}
+
+QUrl ContentLibraryItem::icon() const
+{
+ return m_icon;
+}
+
+QString ContentLibraryItem::qml() const
+{
+ return m_qml;
+}
+
+TypeName ContentLibraryItem::type() const
+{
+ return m_type;
+}
+
+QStringList ContentLibraryItem::files() const
+{
+ return m_files;
+}
+
+bool ContentLibraryItem::visible() const
+{
+ return m_visible;
+}
+
+bool ContentLibraryItem::setImported(bool imported)
+{
+ if (m_imported != imported) {
+ m_imported = imported;
+ emit itemImportedChanged();
+ return true;
+ }
+
+ return false;
+}
+
+bool ContentLibraryItem::imported() const
+{
+ return m_imported;
+}
+
+QStringList ContentLibraryItem::allFiles() const
+{
+ return m_allFiles;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.h
index fdb302b613..bdf8736728 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryeffect.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryitem.h
@@ -10,7 +10,7 @@
namespace QmlDesigner {
-class ContentLibraryEffect : public QObject
+class ContentLibraryItem : public QObject
{
Q_OBJECT
@@ -19,14 +19,15 @@ class ContentLibraryEffect : public QObject
Q_PROPERTY(QStringList bundleItemFiles READ allFiles CONSTANT)
Q_PROPERTY(bool bundleItemVisible MEMBER m_visible NOTIFY itemVisibleChanged)
Q_PROPERTY(bool bundleItemImported READ imported WRITE setImported NOTIFY itemImportedChanged)
+ Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
public:
- ContentLibraryEffect(QObject *parent,
- const QString &name,
- const QString &qml,
- const TypeName &type,
- const QUrl &icon,
- const QStringList &files);
+ ContentLibraryItem(QObject *parent,
+ const QString &name,
+ const QString &qml,
+ const TypeName &type,
+ const QUrl &icon,
+ const QStringList &files);
bool filter(const QString &searchText);
@@ -35,11 +36,9 @@ public:
TypeName type() const;
QStringList files() const;
bool visible() const;
- QString qmlFilePath() const;
bool setImported(bool imported);
bool imported() const;
- QString parentDirPath() const;
QStringList allFiles() const;
signals:
@@ -57,6 +56,7 @@ private:
bool m_imported = false;
QStringList m_allFiles;
+ const QString m_itemType = "item";
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
index 834bc8aa30..25d1523199 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
@@ -32,6 +32,11 @@ bool ContentLibraryMaterial::filter(const QString &searchText)
return m_visible;
}
+QString ContentLibraryMaterial::name() const
+{
+ return m_name;
+}
+
QUrl ContentLibraryMaterial::icon() const
{
return m_icon;
@@ -84,7 +89,7 @@ QString ContentLibraryMaterial::qmlFilePath() const
return m_downloadPath + "/" + m_qml;
}
-QString ContentLibraryMaterial::parentDirPath() const
+QString ContentLibraryMaterial::dirPath() const
{
return m_downloadPath;
}
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
index f546ea98cd..aaaf9517f9 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
@@ -3,9 +3,8 @@
#pragma once
-#include "qmldesignercorelib_global.h"
+#include "nodeinstanceglobal.h"
-#include <QDataStream>
#include <QObject>
#include <QUrl>
@@ -18,10 +17,11 @@ class ContentLibraryMaterial : public QObject
Q_PROPERTY(QString bundleMaterialName MEMBER m_name CONSTANT)
Q_PROPERTY(QUrl bundleMaterialIcon MEMBER m_icon CONSTANT)
Q_PROPERTY(bool bundleMaterialVisible MEMBER m_visible NOTIFY materialVisibleChanged)
- Q_PROPERTY(bool bundleMaterialImported READ imported WRITE setImported NOTIFY materialImportedChanged)
+ Q_PROPERTY(bool bundleItemImported READ imported WRITE setImported NOTIFY materialImportedChanged)
Q_PROPERTY(QString bundleMaterialBaseWebUrl MEMBER m_baseWebUrl CONSTANT)
- Q_PROPERTY(QString bundleMaterialParentPath READ parentDirPath CONSTANT)
+ Q_PROPERTY(QString bundleMaterialDirPath READ dirPath CONSTANT)
Q_PROPERTY(QStringList bundleMaterialFiles READ allFiles CONSTANT)
+ Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
public:
ContentLibraryMaterial(QObject *parent,
@@ -31,12 +31,13 @@ public:
const QUrl &icon,
const QStringList &files,
const QString &downloadPath,
- const QString &baseWebUrl);
+ const QString &baseWebUrl = {});
bool filter(const QString &searchText);
Q_INVOKABLE bool isDownloaded() const;
+ QString name() const;
QUrl icon() const;
QString qml() const;
TypeName type() const;
@@ -46,7 +47,7 @@ public:
bool setImported(bool imported);
bool imported() const;
- QString parentDirPath() const;
+ QString dirPath() const;
QStringList allFiles() const;
signals:
@@ -66,6 +67,7 @@ private:
QString m_downloadPath;
QString m_baseWebUrl;
QStringList m_allFiles;
+ const QString m_itemType = "material";
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
index 7594c691b5..adb47108a9 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
@@ -8,18 +8,19 @@
#include "contentlibrarymaterialscategory.h"
#include "contentlibrarywidget.h"
-#include <designerpaths.h>
+#include "designerpaths.h"
#include "filedownloader.h"
#include "fileextractor.h"
#include "multifiledownloader.h"
-#include "qmldesignerconstants.h"
-#include "qmldesignerplugin.h"
+
+#include <qmldesignerplugin.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QCoreApplication>
+#include <QDir>
#include <QJsonArray>
#include <QJsonDocument>
#include <QQmlEngine>
@@ -40,7 +41,10 @@ ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(ContentLibraryWidget
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
qmlRegisterType<QmlDesigner::MultiFileDownloader>("WebFetcher", 1, 0, "MultiFileDownloader");
+}
+void ContentLibraryMaterialsModel::loadBundle()
+{
QDir bundleDir{m_downloadPath};
if (fetchBundleMetadata(bundleDir) && fetchBundleIcons(bundleDir))
loadMaterialBundle(bundleDir);
@@ -192,11 +196,9 @@ void ContentLibraryMaterialsModel::downloadSharedFiles(const QDir &targetDir, co
extractor->setAlwaysCreateDir(false);
extractor->setClearTargetPathContents(false);
- QObject::connect(extractor, &FileExtractor::finishedChanged, this, [this, downloader, extractor]() {
+ QObject::connect(extractor, &FileExtractor::finishedChanged, this, [downloader, extractor]() {
downloader->deleteLater();
extractor->deleteLater();
-
- createImporter(m_importerBundlePath, m_importerBundleId, m_importerSharedFiles);
});
extractor->extract();
@@ -205,93 +207,68 @@ void ContentLibraryMaterialsModel::downloadSharedFiles(const QDir &targetDir, co
downloader->start();
}
-void ContentLibraryMaterialsModel::createImporter(const QString &bundlePath, const QString &bundleId,
- const QStringList &sharedFiles)
+QString ContentLibraryMaterialsModel::bundleId() const
{
- m_importer = new Internal::ContentLibraryBundleImporter(bundlePath, bundleId, sharedFiles);
-#ifdef QDS_USE_PROJECTSTORAGE
- connect(m_importer,
- &Internal::ContentLibraryBundleImporter::importFinished,
- this,
- [&](const QmlDesigner::TypeName &typeName) {
- m_importerRunning = false;
- emit importerRunningChanged();
- if (typeName.size())
- emit bundleMaterialImported(typeName);
- });
-#else
- connect(m_importer,
- &Internal::ContentLibraryBundleImporter::importFinished,
- this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- m_importerRunning = false;
- emit importerRunningChanged();
- if (metaInfo.isValid())
- emit bundleMaterialImported(metaInfo);
- });
-#endif
-
- connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- Q_UNUSED(metaInfo)
- m_importerRunning = false;
- emit importerRunningChanged();
- emit bundleMaterialUnimported(metaInfo);
- });
-
- resetModel();
- updateIsEmpty();
+ return m_bundleId;
}
-void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &matBundleDir)
+void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &bundleDir)
{
- if (m_matBundleExists)
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ if (m_bundleExists && m_bundleId == compUtils.materialsBundleId())
return;
- QString matBundlePath = matBundleDir.filePath("material_bundle.json");
+ // clean up
+ qDeleteAll(m_bundleCategories);
+ m_bundleCategories.clear();
+ m_bundleExists = false;
+ m_isEmpty = true;
+ m_bundleObj = {};
+ m_bundleId.clear();
- if (m_matBundleObj.isEmpty()) {
- QFile matPropsFile(matBundlePath);
+ QString bundlePath = bundleDir.filePath("material_bundle.json");
- if (!matPropsFile.open(QIODevice::ReadOnly)) {
- qWarning("Couldn't open material_bundle.json");
- return;
- }
+ QFile bundleFile(bundlePath);
+ if (!bundleFile.open(QIODevice::ReadOnly)) {
+ qWarning("Couldn't open material_bundle.json");
+ resetModel();
+ return;
+ }
- QJsonDocument matBundleJsonDoc = QJsonDocument::fromJson(matPropsFile.readAll());
- if (matBundleJsonDoc.isNull()) {
- qWarning("Invalid material_bundle.json file");
- return;
- } else {
- m_matBundleObj = matBundleJsonDoc.object();
- }
+ QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(bundleFile.readAll());
+ if (bundleJsonDoc.isNull()) {
+ qWarning("Invalid material_bundle.json file");
+ resetModel();
+ return;
}
- QString bundleId = m_matBundleObj.value("id").toString();
+ m_bundleObj = bundleJsonDoc.object();
- const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
+ QString bundleType = compUtils.materialsBundleType();
+ m_bundleId = compUtils.materialsBundleId();
+
+ const QJsonObject catsObj = m_bundleObj.value("categories").toObject();
const QStringList categories = catsObj.keys();
for (const QString &cat : categories) {
auto category = new ContentLibraryMaterialsCategory(this, cat);
const QJsonObject matsObj = catsObj.value(cat).toObject();
- const QStringList mats = matsObj.keys();
- for (const QString &mat : mats) {
- const QJsonObject matObj = matsObj.value(mat).toObject();
+ const QStringList matsNames = matsObj.keys();
+ for (const QString &matName : matsNames) {
+ const QJsonObject matObj = matsObj.value(matName).toObject();
QStringList files;
const QJsonArray assetsArr = matObj.value("files").toArray();
- for (const auto /*QJson{Const,}ValueRef*/ &asset : assetsArr)
+ for (const QJsonValueConstRef &asset : assetsArr)
files.append(asset.toString());
- QUrl icon = QUrl::fromLocalFile(matBundleDir.filePath(matObj.value("icon").toString()));
+ QUrl icon = QUrl::fromLocalFile(bundleDir.filePath(matObj.value("icon").toString()));
QString qml = matObj.value("qml").toString();
- TypeName type = QLatin1String("%1.%2.%3").arg(
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
- bundleId,
- qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
+ TypeName type = QLatin1String("%1.%2")
+ .arg(bundleType, qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
- auto bundleMat = new ContentLibraryMaterial(category, mat, qml, type, icon, files,
+ auto bundleMat = new ContentLibraryMaterial(category, matName, qml, type, icon, files,
m_downloadPath, m_baseUrl);
category->addBundleMaterial(bundleMat);
@@ -299,30 +276,23 @@ void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &matBundleDir)
m_bundleCategories.append(category);
}
- QStringList sharedFiles;
- const QJsonArray sharedFilesArr = m_matBundleObj.value("sharedFiles").toArray();
- for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
- sharedFiles.append(file.toString());
+ m_bundleSharedFiles.clear();
+ const QJsonArray sharedFilesArr = m_bundleObj.value("sharedFiles").toArray();
+ for (const QJsonValueConstRef &file : sharedFilesArr)
+ m_bundleSharedFiles.append(file.toString());
QStringList missingSharedFiles;
- for (const QString &s : std::as_const(sharedFiles)) {
- const QString fullSharedFilePath = matBundleDir.filePath(s);
-
- if (!QFileInfo::exists(fullSharedFilePath))
+ for (const QString &s : std::as_const(m_bundleSharedFiles)) {
+ if (!QFileInfo::exists(bundleDir.filePath(s)))
missingSharedFiles.push_back(s);
}
- if (missingSharedFiles.length() > 0) {
- m_importerBundlePath = matBundleDir.path();
- m_importerBundleId = bundleId;
- m_importerSharedFiles = sharedFiles;
- downloadSharedFiles(matBundleDir, missingSharedFiles);
- } else {
- createImporter(matBundleDir.path(), bundleId, sharedFiles);
- }
+ if (missingSharedFiles.length() > 0)
+ downloadSharedFiles(bundleDir, missingSharedFiles);
- m_matBundleExists = true;
- emit matBundleExistsChanged();
+ m_bundleExists = true;
+ updateIsEmpty();
+ resetModel();
}
bool ContentLibraryMaterialsModel::hasRequiredQuick3DImport() const
@@ -332,12 +302,7 @@ bool ContentLibraryMaterialsModel::hasRequiredQuick3DImport() const
bool ContentLibraryMaterialsModel::matBundleExists() const
{
- return m_matBundleExists;
-}
-
-Internal::ContentLibraryBundleImporter *ContentLibraryMaterialsModel::bundleImporter() const
-{
- return m_importer;
+ return m_bundleExists;
}
void ContentLibraryMaterialsModel::setSearchText(const QString &searchText)
@@ -359,11 +324,11 @@ void ContentLibraryMaterialsModel::setSearchText(const QString &searchText)
updateIsEmpty();
}
-void ContentLibraryMaterialsModel::updateImportedState(const QStringList &importedMats)
+void ContentLibraryMaterialsModel::updateImportedState(const QStringList &importedItems)
{
bool changed = false;
for (ContentLibraryMaterialsCategory *cat : std::as_const(m_bundleCategories))
- changed |= cat->updateImportedState(importedMats);
+ changed |= cat->updateImportedState(importedItems);
if (changed)
resetModel();
@@ -399,42 +364,23 @@ void ContentLibraryMaterialsModel::applyToSelected(ContentLibraryMaterial *mat,
void ContentLibraryMaterialsModel::addToProject(ContentLibraryMaterial *mat)
{
- QString err = m_importer->importComponent(mat->qml(), mat->files());
+ QString err = m_widget->importer()->importComponent(mat->dirPath(), mat->type(), mat->qml(),
+ mat->files() + m_bundleSharedFiles);
- if (err.isEmpty()) {
- m_importerRunning = true;
- emit importerRunningChanged();
- } else {
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
qWarning() << __FUNCTION__ << err;
- }
}
void ContentLibraryMaterialsModel::removeFromProject(ContentLibraryMaterial *mat)
{
- emit bundleMaterialAboutToUnimport(mat->type());
+ QString err = m_widget->importer()->unimportComponent(mat->type(), mat->qml());
- QString err = m_importer->unimportComponent(mat->qml());
-
- if (err.isEmpty()) {
- m_importerRunning = true;
- emit importerRunningChanged();
- } else {
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
qWarning() << __FUNCTION__ << err;
- }
-}
-
-bool ContentLibraryMaterialsModel::hasModelSelection() const
-{
- return m_hasModelSelection;
-}
-
-void ContentLibraryMaterialsModel::setHasModelSelection(bool b)
-{
- if (b == m_hasModelSelection)
- return;
-
- m_hasModelSelection = b;
- emit hasModelSelectionChanged();
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
index 21bd374137..c0840dc3cc 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
@@ -3,22 +3,17 @@
#pragma once
-#include "nodemetainfo.h"
-
#include <QAbstractListModel>
-#include <QDir>
#include <QJsonObject>
+QT_FORWARD_DECLARE_CLASS(QDir)
+
namespace QmlDesigner {
class ContentLibraryMaterial;
class ContentLibraryMaterialsCategory;
class ContentLibraryWidget;
-namespace Internal {
-class ContentLibraryBundleImporter;
-}
-
class ContentLibraryMaterialsModel : public QAbstractListModel
{
Q_OBJECT
@@ -26,8 +21,6 @@ class ContentLibraryMaterialsModel : public QAbstractListModel
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
- Q_PROPERTY(bool hasModelSelection READ hasModelSelection NOTIFY hasModelSelectionChanged)
- Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
public:
ContentLibraryMaterialsModel(ContentLibraryWidget *parent = nullptr);
@@ -38,40 +31,27 @@ public:
QHash<int, QByteArray> roleNames() const override;
void setSearchText(const QString &searchText);
- void updateImportedState(const QStringList &importedMats);
-
+ void updateImportedState(const QStringList &importedItems);
void setQuick3DImportVersion(int major, int minor);
bool hasRequiredQuick3DImport() const;
-
bool matBundleExists() const;
- bool hasModelSelection() const;
- void setHasModelSelection(bool b);
-
void resetModel();
void updateIsEmpty();
-
- Internal::ContentLibraryBundleImporter *bundleImporter() const;
+ void loadBundle();
Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
Q_INVOKABLE void addToProject(QmlDesigner::ContentLibraryMaterial *mat);
Q_INVOKABLE void removeFromProject(QmlDesigner::ContentLibraryMaterial *mat);
+ QString bundleId() const;
+
signals:
void isEmptyChanged();
void hasRequiredQuick3DImportChanged();
- void hasModelSelectionChanged();
void materialVisibleChanged();
void applyToSelectedTriggered(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
-#ifdef QDS_USE_PROJECTSTORAGE
- void bundleMaterialImported(const QmlDesigner::TypeName &typeName);
-#else
- void bundleMaterialImported(const QmlDesigner::NodeMetaInfo &metaInfo);
-#endif
- void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
- void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
- void importerRunningChanged();
void matBundleExistsChanged();
private:
@@ -80,29 +60,22 @@ private:
bool fetchBundleMetadata(const QDir &bundleDir);
bool isValidIndex(int idx) const;
void downloadSharedFiles(const QDir &targetDir, const QStringList &files);
- void createImporter(const QString &bundlePath, const QString &bundleId,
- const QStringList &sharedFiles);
ContentLibraryWidget *m_widget = nullptr;
QString m_searchText;
+ QString m_bundleId;
+ QStringList m_bundleSharedFiles;
QList<ContentLibraryMaterialsCategory *> m_bundleCategories;
- QJsonObject m_matBundleObj;
- Internal::ContentLibraryBundleImporter *m_importer = nullptr;
+ QJsonObject m_bundleObj;
bool m_isEmpty = true;
- bool m_matBundleExists = false;
- bool m_hasModelSelection = false;
- bool m_importerRunning = false;
+ bool m_bundleExists = false;
int m_quick3dMajorVersion = -1;
int m_quick3dMinorVersion = -1;
QString m_downloadPath;
QString m_baseUrl;
-
- QString m_importerBundlePath;
- QString m_importerBundleId;
- QStringList m_importerSharedFiles;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp
index 7ab239aab4..d2c2df2baa 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp
@@ -12,20 +12,19 @@
namespace QmlDesigner {
ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo,
- const QString &downloadPath, const QUrl &icon,
- const QString &key, const QString &webTextureUrl,
- const QString &webIconUrl, const QString &fileExt,
+ const QString &dirPath, const QString &suffix,
const QSize &dimensions, const qint64 sizeInBytes,
- bool hasUpdate, bool isNew)
+ const QString &key, const QString &textureUrl,
+ const QString &iconUrl, bool hasUpdate, bool isNew)
: QObject(parent)
, m_iconPath(iconFileInfo.filePath())
- , m_downloadPath(downloadPath)
- , m_webTextureUrl(webTextureUrl)
- , m_webIconUrl(webIconUrl)
+ , m_dirPath(dirPath)
+ , m_textureUrl(textureUrl)
+ , m_iconUrl(iconUrl)
, m_baseName{iconFileInfo.baseName()}
- , m_fileExt(fileExt)
+ , m_suffix(suffix)
, m_textureKey(key)
- , m_icon(icon)
+ , m_icon(QUrl::fromLocalFile(iconFileInfo.absoluteFilePath()))
, m_dimensions(dimensions)
, m_sizeInBytes(sizeInBytes)
, m_hasUpdate(hasUpdate)
@@ -54,9 +53,9 @@ QString ContentLibraryTexture::iconPath() const
return m_iconPath;
}
-QString ContentLibraryTexture::resolveFileExt()
+QString ContentLibraryTexture::resolveSuffix()
{
- const QFileInfoList files = QDir(m_downloadPath).entryInfoList(QDir::Files);
+ const QFileInfoList files = QDir(m_dirPath).entryInfoList(QDir::Files);
const QFileInfoList textureFiles = Utils::filtered(files, [this](const QFileInfo &fi) {
return fi.baseName() == m_baseName;
});
@@ -76,22 +75,20 @@ QString ContentLibraryTexture::resolveFileExt()
QString ContentLibraryTexture::resolveToolTipText()
{
- if (m_fileExt.isEmpty()) {
- // No supplied or resolved extension means we have just the icon and no other data
- return m_baseName;
- }
+ if (m_suffix.isEmpty())
+ return m_baseName; // empty suffix means we have just the icon and no other data
- QString fileName = m_baseName + m_fileExt;
+ QString fileName = m_baseName + m_suffix;
QString imageInfo;
if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) {
- imageInfo = ImageUtils::imageInfo(m_dimensions, m_sizeInBytes);
+ imageInfo = ImageUtils::imageInfoString(m_dimensions, m_sizeInBytes);
} else {
- QString fullDownloadPath = m_downloadPath + '/' + fileName;
- imageInfo = ImageUtils::imageInfo(fullDownloadPath);
+ QString fullDownloadPath = m_dirPath + '/' + fileName;
+ imageInfo = ImageUtils::imageInfoString(fullDownloadPath);
}
- return QStringLiteral("%1\n%2").arg(fileName, imageInfo);
+ return QString("%1\n%2").arg(fileName, imageInfo);
}
bool ContentLibraryTexture::isDownloaded() const
@@ -99,9 +96,9 @@ bool ContentLibraryTexture::isDownloaded() const
return m_isDownloaded;
}
-QString ContentLibraryTexture::downloadedTexturePath() const
+QString ContentLibraryTexture::texturePath() const
{
- return m_downloadPath + '/' + m_baseName + m_fileExt;
+ return m_dirPath + '/' + m_baseName + m_suffix;
}
void ContentLibraryTexture::setDownloaded()
@@ -116,16 +113,21 @@ void ContentLibraryTexture::setDownloaded()
void ContentLibraryTexture::doSetDownloaded()
{
- if (m_fileExt.isEmpty())
- m_fileExt = resolveFileExt();
+ if (m_suffix.isEmpty())
+ m_suffix = resolveSuffix();
- m_isDownloaded = QFileInfo::exists(downloadedTexturePath());
+ m_isDownloaded = QFileInfo::exists(texturePath());
m_toolTip = resolveToolTipText();
}
+bool ContentLibraryTexture::visible() const
+{
+ return m_visible;
+}
+
QString ContentLibraryTexture::parentDirPath() const
{
- return m_downloadPath;
+ return m_dirPath;
}
QString ContentLibraryTexture::textureKey() const
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
index 9f5b46630f..7f5db6d7d6 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
@@ -19,17 +19,18 @@ class ContentLibraryTexture : public QObject
Q_PROPERTY(QString textureToolTip MEMBER m_toolTip NOTIFY textureToolTipChanged)
Q_PROPERTY(QUrl textureIcon MEMBER m_icon CONSTANT)
Q_PROPERTY(bool textureVisible MEMBER m_visible NOTIFY textureVisibleChanged)
- Q_PROPERTY(QString textureWebUrl MEMBER m_webTextureUrl CONSTANT)
- Q_PROPERTY(QString textureWebIconUrl MEMBER m_webIconUrl CONSTANT)
+ Q_PROPERTY(QString textureUrl MEMBER m_textureUrl CONSTANT)
+ Q_PROPERTY(QString textureIconUrl MEMBER m_iconUrl CONSTANT)
Q_PROPERTY(bool textureHasUpdate WRITE setHasUpdate READ hasUpdate NOTIFY hasUpdateChanged)
Q_PROPERTY(bool textureIsNew MEMBER m_isNew CONSTANT)
Q_PROPERTY(QString textureKey MEMBER m_textureKey CONSTANT)
+ Q_PROPERTY(QString itemType MEMBER m_itemType CONSTANT)
public:
- ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, const QString &downloadPath,
- const QUrl &icon, const QString &key, const QString &webTextureUrl,
- const QString &webIconUrl, const QString &fileExt, const QSize &dimensions,
- const qint64 sizeInBytes, bool hasUpdate, bool isNew);
+ ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, const QString &dirPath,
+ const QString &suffix, const QSize &dimensions, const qint64 sizeInBytes,
+ const QString &key = {}, const QString &textureUrl = {},
+ const QString &iconUrl = {}, bool hasUpdate = false, bool isNew = false);
Q_INVOKABLE bool isDownloaded() const;
Q_INVOKABLE void setDownloaded();
@@ -38,30 +39,32 @@ public:
QUrl icon() const;
QString iconPath() const;
- QString downloadedTexturePath() const;
+ QString texturePath() const;
QString parentDirPath() const;
QString textureKey() const;
void setHasUpdate(bool value);
bool hasUpdate() const;
+ bool visible() const;
+
signals:
void textureVisibleChanged();
void textureToolTipChanged();
void hasUpdateChanged();
private:
- QString resolveFileExt();
+ QString resolveSuffix();
QString resolveToolTipText();
void doSetDownloaded();
QString m_iconPath;
- QString m_downloadPath;
- QString m_webTextureUrl;
- QString m_webIconUrl;
+ QString m_dirPath;
+ QString m_textureUrl;
+ QString m_iconUrl;
QString m_toolTip;
QString m_baseName;
- QString m_fileExt;
+ QString m_suffix;
QString m_textureKey;
QUrl m_icon;
QSize m_dimensions;
@@ -71,6 +74,7 @@ private:
bool m_visible = true;
bool m_hasUpdate = false;
bool m_isNew = false;
+ const QString m_itemType = "texture";
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
index 77519ad88f..0cafe8d138 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
@@ -14,17 +14,15 @@ namespace QmlDesigner {
ContentLibraryTexturesCategory::ContentLibraryTexturesCategory(QObject *parent, const QString &name)
: QObject(parent), m_name(name) {}
-void ContentLibraryTexturesCategory::addTexture(const QFileInfo &tex, const QString &downloadPath,
+void ContentLibraryTexturesCategory::addTexture(const QFileInfo &texIcon, const QString &downloadPath,
const QString &key, const QString &webTextureUrl,
- const QString &webIconUrl, const QString &fileExt,
+ const QString &iconUrl, const QString &suffix,
const QSize &dimensions, const qint64 sizeInBytes,
bool hasUpdate, bool isNew)
{
- QUrl icon = QUrl::fromLocalFile(tex.absoluteFilePath());
-
m_categoryTextures.append(new ContentLibraryTexture(
- this, tex, downloadPath, icon, key, webTextureUrl, webIconUrl,
- fileExt, dimensions, sizeInBytes, hasUpdate, isNew));
+ this, texIcon, downloadPath, suffix, dimensions, sizeInBytes,
+ key, webTextureUrl, iconUrl, hasUpdate, isNew));
}
bool ContentLibraryTexturesCategory::filter(const QString &searchText)
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h
index 166528f05a..857346df06 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h
@@ -28,7 +28,7 @@ public:
ContentLibraryTexturesCategory(QObject *parent, const QString &name);
void addTexture(const QFileInfo &tex, const QString &subPath, const QString &key,
- const QString &webTextureUrl, const QString &webIconUrl, const QString &fileExt,
+ const QString &webTextureUrl, const QString &iconUrl, const QString &suffix,
const QSize &dimensions, const qint64 sizeInBytes, bool hasUpdate, bool isNew);
bool filter(const QString &searchText);
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
index 319ca2686f..b575b6b9b2 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
@@ -95,37 +95,37 @@ QHash<int, QByteArray> ContentLibraryTexturesModel::roleNames() const
/**
* @brief Load the bundle categorized icons. Actual textures are downloaded on demand
*
- * @param bundlePath local path to the bundle folder and icons
- * @param metaData bundle textures metadata
+ * @param textureBundleUrl remote url to the texture bundle
+ * @param bundleIconPath local path to the texture bundle icons folder
+ * @param jsonData bundle textures information from the bundle json
*/
-void ContentLibraryTexturesModel::loadTextureBundle(const QString &remoteUrl, const QString &iconsUrl,
+void ContentLibraryTexturesModel::loadTextureBundle(const QString &textureBundleUrl,
const QString &bundleIconPath,
- const QVariantMap &metaData)
+ const QVariantMap &jsonData)
{
if (!m_bundleCategories.isEmpty())
return;
QDir bundleDir = QString("%1/%2").arg(bundleIconPath, m_category);
- if (!bundleDir.exists()) {
- qWarning() << __FUNCTION__ << "textures bundle folder doesn't exist." << bundleDir.absolutePath();
- return;
- }
+ QTC_ASSERT(bundleDir.exists(), return);
- const QVariantMap imageItems = metaData.value("image_items").toMap();
+ const QVariantMap imageItems = jsonData.value("image_items").toMap();
const QFileInfoList dirs = bundleDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &dir : dirs) {
auto category = new ContentLibraryTexturesCategory(this, dir.fileName());
- const QFileInfoList texFiles = QDir(dir.filePath()).entryInfoList(QDir::Files);
- for (const QFileInfo &tex : texFiles) {
- QString textureUrl = QString("%1/%2/%3.zip").arg(remoteUrl, dir.fileName(), tex.baseName());
- QString iconUrl = QString("%1/%2/%3.png").arg(iconsUrl, dir.fileName(), tex.baseName());
-
- QString localDownloadPath = QString("%1/%2/%3")
+ const QFileInfoList texIconFiles = QDir(dir.filePath()).entryInfoList(QDir::Files);
+ for (const QFileInfo &texIcon : texIconFiles) {
+ QString textureUrl = QString("%1/%2/%3/%4.zip").arg(textureBundleUrl, m_category,
+ dir.fileName(), texIcon.baseName());
+ QString iconUrl = QString("%1/icons/%2/%3/%4.png").arg(textureBundleUrl, m_category,
+ dir.fileName(), texIcon.baseName());
+
+ QString texturePath = 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 key = QString("%1/%2/%3").arg(m_category, dir.fileName(), texIcon.baseName());
QString fileExt;
QSize dimensions;
qint64 sizeInBytes = -1;
@@ -141,7 +141,7 @@ void ContentLibraryTexturesModel::loadTextureBundle(const QString &remoteUrl, co
isNew = m_newFiles.contains(key);
}
- category->addTexture(tex, localDownloadPath, key, textureUrl, iconUrl, fileExt,
+ category->addTexture(texIcon, texturePath, key, textureUrl, iconUrl, fileExt,
dimensions, sizeInBytes, hasUpdate, isNew);
}
m_bundleCategories.append(category);
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
index 92db4151a8..94e223a251 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
@@ -37,8 +37,8 @@ public:
void setHasSceneEnv(bool b);
void resetModel();
- void loadTextureBundle(const QString &remoteUrl, const QString &iconsUrl,
- const QString &bundlePath, const QVariantMap &metaData);
+ void loadTextureBundle(const QString &textureBundleUrl, const QString &bundlePath,
+ const QVariantMap &metaData);
signals:
void isEmptyChanged();
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp
new file mode 100644
index 0000000000..8dcf4575f7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp
@@ -0,0 +1,686 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "contentlibraryusermodel.h"
+
+#include "contentlibrarybundleimporter.h"
+#include "contentlibraryitem.h"
+#include "contentlibrarymaterial.h"
+#include "contentlibrarymaterialscategory.h"
+#include "contentlibrarytexture.h"
+#include "contentlibrarywidget.h"
+
+#include <designerpaths.h>
+#include <imageutils.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+#include <uniquename.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+#include <QFileInfo>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QUrl>
+
+namespace QmlDesigner {
+
+ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent)
+ : QAbstractListModel(parent)
+ , m_widget(parent)
+{
+ m_userCategories = {tr("Materials"), tr("Textures"), tr("3D"), /*tr("Effects"), tr("2D components")*/}; // TODO
+}
+
+int ContentLibraryUserModel::rowCount(const QModelIndex &) const
+{
+ return m_userCategories.size();
+}
+
+QVariant ContentLibraryUserModel::data(const QModelIndex &index, int role) const
+{
+ QTC_ASSERT(index.isValid() && index.row() < m_userCategories.size(), return {});
+ QTC_ASSERT(roleNames().contains(role), return {});
+
+ if (role == NameRole)
+ return m_userCategories.at(index.row());
+
+ if (role == ItemsRole) {
+ if (index.row() == MaterialsSectionIdx)
+ return QVariant::fromValue(m_userMaterials);
+ if (index.row() == TexturesSectionIdx)
+ return QVariant::fromValue(m_userTextures);
+ if (index.row() == Items3DSectionIdx)
+ return QVariant::fromValue(m_user3DItems);
+ if (index.row() == EffectsSectionIdx)
+ return QVariant::fromValue(m_userEffects);
+ }
+
+ if (role == NoMatchRole) {
+ if (index.row() == MaterialsSectionIdx)
+ return m_noMatchMaterials;
+ if (index.row() == TexturesSectionIdx)
+ return m_noMatchTextures;
+ if (index.row() == Items3DSectionIdx)
+ return m_noMatch3D;
+ if (index.row() == EffectsSectionIdx)
+ return m_noMatchEffects;
+ }
+
+ if (role == VisibleRole) {
+ if (index.row() == MaterialsSectionIdx)
+ return !m_userMaterials.isEmpty();
+ if (index.row() == TexturesSectionIdx)
+ return !m_userTextures.isEmpty();
+ if (index.row() == Items3DSectionIdx)
+ return !m_user3DItems.isEmpty();
+ if (index.row() == EffectsSectionIdx)
+ return !m_userEffects.isEmpty();
+ }
+
+ return {};
+}
+
+bool ContentLibraryUserModel::isValidIndex(int idx) const
+{
+ return idx > -1 && idx < rowCount();
+}
+
+void ContentLibraryUserModel::updateNoMatchMaterials()
+{
+ m_noMatchMaterials = Utils::allOf(m_userMaterials, [&](ContentLibraryMaterial *item) {
+ return !item->visible();
+ });
+}
+
+void ContentLibraryUserModel::updateNoMatchTextures()
+{
+ m_noMatchTextures = Utils::allOf(m_userTextures, [&](ContentLibraryTexture *item) {
+ return !item->visible();
+ });
+}
+
+void ContentLibraryUserModel::updateNoMatch3D()
+{
+ m_noMatch3D = Utils::allOf(m_user3DItems, [&](ContentLibraryItem *item) {
+ return !item->visible();
+ });
+}
+
+void ContentLibraryUserModel::addMaterial(const QString &name, const QString &qml,
+ const QUrl &icon, const QStringList &files)
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ QString typePrefix = compUtils.userMaterialsBundleType();
+ TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
+
+ auto libMat = new ContentLibraryMaterial(this, name, qml, type, icon, files,
+ Paths::bundlesPathSetting().append("/User/materials"));
+ m_userMaterials.append(libMat);
+
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+}
+
+void ContentLibraryUserModel::add3DItem(const QString &name, const QString &qml,
+ const QUrl &icon, const QStringList &files)
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ QString typePrefix = compUtils.user3DBundleType();
+ TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
+
+ m_user3DItems.append(new ContentLibraryItem(this, name, qml, type, icon, files));
+}
+
+void ContentLibraryUserModel::refresh3DSection()
+{
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+}
+
+void ContentLibraryUserModel::addTextures(const QStringList &paths)
+{
+ QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
+ bundleDir.mkpath(".");
+ bundleDir.mkdir("icons");
+
+ for (const QString &path : paths) {
+ QFileInfo fileInfo(path);
+ QString suffix = '.' + fileInfo.suffix();
+ auto iconFileInfo = QFileInfo(fileInfo.path().append("/icons/").append(fileInfo.baseName() + ".png"));
+ QPair<QSize, qint64> info = ImageUtils::imageInfo(path);
+ QString dirPath = fileInfo.path();
+ QSize imgDims = info.first;
+ qint64 imgFileSize = info.second;
+
+ auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
+ m_userTextures.append(tex);
+ }
+
+ emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
+}
+
+void ContentLibraryUserModel::add3DInstance(ContentLibraryItem *bundleItem)
+{
+ QString err = m_widget->importer()->importComponent(m_bundlePath3D.path(), bundleItem->type(),
+ bundleItem->qml(),
+ bundleItem->files() + m_bundle3DSharedFiles);
+
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
+ qWarning() << __FUNCTION__ << err;
+}
+
+void ContentLibraryUserModel::removeTexture(ContentLibraryTexture *tex)
+{
+ // remove resources
+ Utils::FilePath::fromString(tex->texturePath()).removeFile();
+ Utils::FilePath::fromString(tex->iconPath()).removeFile();
+
+ // remove from model
+ m_userTextures.removeOne(tex);
+ tex->deleteLater();
+
+ // update model
+ emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
+}
+
+void ContentLibraryUserModel::removeFromContentLib(QObject *item)
+{
+ if (auto mat = qobject_cast<ContentLibraryMaterial *>(item))
+ removeMaterialFromContentLib(mat);
+ else if (auto itm = qobject_cast<ContentLibraryItem *>(item))
+ remove3DFromContentLib(itm);
+}
+
+void ContentLibraryUserModel::removeMaterialFromContentLib(ContentLibraryMaterial *item)
+{
+ auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials/");
+
+ QJsonArray itemsArr = m_bundleObjMaterial.value("items").toArray();
+
+ // remove qml and icon files
+ Utils::FilePath::fromString(item->qmlFilePath()).removeFile();
+ Utils::FilePath::fromUrl(item->icon()).removeFile();
+
+ // remove from the bundle json file
+ for (int i = 0; i < itemsArr.size(); ++i) {
+ if (itemsArr.at(i).toObject().value("qml") == item->qml()) {
+ itemsArr.removeAt(i);
+ break;
+ }
+ }
+ m_bundleObjMaterial.insert("items", itemsArr);
+
+ auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
+ .writeFileContents(QJsonDocument(m_bundleObjMaterial).toJson());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ // delete dependency files if they are only used by the deleted material
+ QStringList allFiles;
+ for (const QJsonValueConstRef &itemRef : std::as_const(itemsArr))
+ allFiles.append(itemRef.toObject().value("files").toVariant().toStringList());
+
+ const QStringList itemFiles = item->files();
+ for (const QString &file : itemFiles) {
+ if (allFiles.count(file) == 0) // only used by the deleted item
+ bundlePath.pathAppended(file).removeFile();
+ }
+
+ // remove from model
+ m_userMaterials.removeOne(item);
+ item->deleteLater();
+
+ // update model
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+}
+
+void ContentLibraryUserModel::remove3DFromContentLibByName(const QString &qmlFileName)
+{
+ ContentLibraryItem *itemToRemove = Utils::findOr(m_user3DItems, nullptr,
+ [&qmlFileName](ContentLibraryItem *item) {
+ return item->qml() == qmlFileName;
+ });
+
+ if (itemToRemove)
+ remove3DFromContentLib(itemToRemove);
+}
+
+void ContentLibraryUserModel::remove3DFromContentLib(ContentLibraryItem *item)
+{
+ QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
+
+ // remove qml and icon files
+ m_bundlePath3D.pathAppended(item->qml()).removeFile();
+ Utils::FilePath::fromUrl(item->icon()).removeFile();
+
+ // remove from the bundle json file
+ for (int i = 0; i < itemsArr.size(); ++i) {
+ if (itemsArr.at(i).toObject().value("qml") == item->qml()) {
+ itemsArr.removeAt(i);
+ break;
+ }
+ }
+ m_bundleObj3D.insert("items", itemsArr);
+
+ auto result = m_bundlePath3D.pathAppended(Constants::BUNDLE_JSON_FILENAME)
+ .writeFileContents(QJsonDocument(m_bundleObj3D).toJson());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ // delete dependency files if they are only used by the deleted item
+ QStringList allFiles;
+ for (const QJsonValueConstRef &itemRef : std::as_const(itemsArr))
+ allFiles.append(itemRef.toObject().value("files").toVariant().toStringList());
+
+ const QStringList itemFiles = item->files();
+ for (const QString &file : itemFiles) {
+ if (allFiles.count(file) == 0) // only used by the deleted item
+ m_bundlePath3D.pathAppended(file).removeFile();
+ }
+
+ // remove from model
+ m_user3DItems.removeOne(item);
+ item->deleteLater();
+
+ // update model
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+}
+
+/**
+ * @brief Gets unique Qml component and icon file material names from a given name
+ * @param defaultName input name
+ * @return <Qml, icon> file names
+ */
+QPair<QString, QString> ContentLibraryUserModel::getUniqueLibMaterialNames(const QString &defaultName) const
+{
+ return getUniqueLibItemNames(defaultName, m_bundleObjMaterial);
+}
+
+/**
+ * @brief Gets unique Qml component and icon file 3d item names from a given name
+ * @param defaultName input name
+ * @return <Qml, icon> file names
+ */
+QPair<QString, QString> ContentLibraryUserModel::getUniqueLib3DNames(const QString &defaultName) const
+{
+ return getUniqueLibItemNames(defaultName, m_bundleObj3D);
+}
+
+QPair<QString, QString> ContentLibraryUserModel::getUniqueLibItemNames(const QString &defaultName,
+ const QJsonObject &bundleObj) const
+{
+ QTC_ASSERT(!bundleObj.isEmpty(), return {});
+
+ const QJsonArray itemsArr = bundleObj.value("items").toArray();
+
+ QStringList itemQmls, itemIcons;
+ for (const QJsonValueConstRef &itemRef : itemsArr) {
+ const QJsonObject &obj = itemRef.toObject();
+ itemQmls.append(obj.value("qml").toString().chopped(4)); // remove .qml
+ itemIcons.append(QFileInfo(obj.value("icon").toString()).baseName());
+ }
+
+ QString baseQml = UniqueName::generateId(defaultName);
+ baseQml[0] = baseQml.at(0).toUpper();
+ baseQml.prepend("My");
+
+ QString uniqueQml = UniqueName::generate(baseQml, [&] (const QString &name) {
+ return itemQmls.contains(name);
+ });
+
+ QString uniqueIcon = UniqueName::generate(defaultName, [&] (const QString &name) {
+ return itemIcons.contains(name);
+ });
+
+ return {uniqueQml + ".qml", uniqueIcon + ".png"};
+}
+
+QHash<int, QByteArray> ContentLibraryUserModel::roleNames() const
+{
+ static const QHash<int, QByteArray> roles {
+ {NameRole, "categoryName"},
+ {VisibleRole, "categoryVisible"},
+ {ItemsRole, "categoryItems"},
+ {NoMatchRole, "categoryNoMatch"}
+ };
+ return roles;
+}
+
+QJsonObject &ContentLibraryUserModel::bundleJsonMaterialObjectRef()
+{
+ return m_bundleObjMaterial;
+}
+
+QJsonObject &ContentLibraryUserModel::bundleJson3DObjectRef()
+{
+ return m_bundleObj3D;
+}
+
+void ContentLibraryUserModel::loadBundles()
+{
+ loadMaterialBundle();
+ load3DBundle();
+ loadTextureBundle();
+}
+
+void ContentLibraryUserModel::loadMaterialBundle()
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ if (m_matBundleExists && m_bundleIdMaterial == compUtils.userMaterialsBundleId())
+ return;
+
+ // clean up
+ qDeleteAll(m_userMaterials);
+ m_userMaterials.clear();
+ m_matBundleExists = false;
+ m_noMatchMaterials = true;
+ m_bundleObjMaterial = {};
+ m_bundleIdMaterial.clear();
+
+ m_bundlePathMaterial = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials");
+ m_bundlePathMaterial.ensureWritableDir();
+ m_bundlePathMaterial.pathAppended("icons").ensureWritableDir();
+
+ auto jsonFilePath = m_bundlePathMaterial.pathAppended(Constants::BUNDLE_JSON_FILENAME);
+ if (!jsonFilePath.exists()) {
+ QString jsonContent = "{\n";
+ jsonContent += " \"id\": \"UserMaterials\",\n";
+ jsonContent += " \"items\": []\n";
+ jsonContent += "}";
+ Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent.toLatin1());
+ if (!res.has_value()) {
+ qWarning() << __FUNCTION__ << res.error();
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+ return;
+ }
+ }
+
+ Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
+ if (!jsonContents.has_value()) {
+ qWarning() << __FUNCTION__ << jsonContents.error();
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+ return;
+ }
+
+ QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
+ if (bundleJsonDoc.isNull()) {
+ qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+ return;
+ }
+
+ m_bundleIdMaterial = compUtils.userMaterialsBundleId();
+ m_bundleObjMaterial = bundleJsonDoc.object();
+ m_bundleObjMaterial["id"] = m_bundleIdMaterial;
+
+ // parse items
+ QString typePrefix = compUtils.userMaterialsBundleType();
+ const QJsonArray itemsArr = m_bundleObjMaterial.value("items").toArray();
+ for (const QJsonValueConstRef &itemRef : itemsArr) {
+ const QJsonObject itemObj = itemRef.toObject();
+
+ QString name = itemObj.value("name").toString();
+ QString qml = itemObj.value("qml").toString();
+ TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
+ QUrl icon = m_bundlePathMaterial.pathAppended(itemObj.value("icon").toString()).toUrl();
+ QStringList files;
+ const QJsonArray assetsArr = itemObj.value("files").toArray();
+ for (const QJsonValueConstRef &asset : assetsArr)
+ files.append(asset.toString());
+
+ m_userMaterials.append(new ContentLibraryMaterial(this, name, qml, type, icon, files,
+ m_bundlePathMaterial.path(), ""));
+ }
+
+ m_bundleMaterialSharedFiles.clear();
+ const QJsonArray sharedFilesArr = m_bundleObjMaterial.value("sharedFiles").toArray();
+ for (const QJsonValueConstRef &file : sharedFilesArr)
+ m_bundleMaterialSharedFiles.append(file.toString());
+
+ m_matBundleExists = true;
+ updateNoMatchMaterials();
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+}
+
+void ContentLibraryUserModel::load3DBundle()
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ if (m_bundle3DExists && m_bundleId3D == compUtils.user3DBundleId())
+ return;
+
+ // clean up
+ qDeleteAll(m_user3DItems);
+ m_user3DItems.clear();
+ m_bundle3DExists = false;
+ m_noMatch3D = true;
+ m_bundleObj3D = {};
+ m_bundleId3D.clear();
+
+ m_bundlePath3D = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d");
+ m_bundlePath3D.ensureWritableDir();
+ m_bundlePath3D.pathAppended("icons").ensureWritableDir();
+
+ auto jsonFilePath = m_bundlePath3D.pathAppended(Constants::BUNDLE_JSON_FILENAME);
+ if (!jsonFilePath.exists()) {
+ QByteArray jsonContent = "{\n";
+ jsonContent += " \"id\": \"User3D\",\n";
+ jsonContent += " \"items\": []\n";
+ jsonContent += "}";
+ Utils::expected_str<qint64> res = jsonFilePath.writeFileContents(jsonContent);
+ if (!res.has_value()) {
+ qWarning() << __FUNCTION__ << res.error();
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+ return;
+ }
+ }
+
+ Utils::expected_str<QByteArray> jsonContents = jsonFilePath.fileContents();
+ if (!jsonContents.has_value()) {
+ qWarning() << __FUNCTION__ << jsonContents.error();
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+ return;
+ }
+
+ QJsonDocument bundleJsonDoc = QJsonDocument::fromJson(jsonContents.value());
+ if (bundleJsonDoc.isNull()) {
+ qWarning() << __FUNCTION__ << "Invalid json file" << jsonFilePath;
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+ return;
+ }
+
+ m_bundleId3D = compUtils.user3DBundleId();
+ m_bundleObj3D = bundleJsonDoc.object();
+ m_bundleObj3D["id"] = m_bundleId3D;
+
+ // parse items
+ QString typePrefix = compUtils.user3DBundleType();
+ const QJsonArray itemsArr = m_bundleObj3D.value("items").toArray();
+ for (const QJsonValueConstRef &itemRef : itemsArr) {
+ const QJsonObject itemObj = itemRef.toObject();
+
+ QString name = itemObj.value("name").toString();
+ QString qml = itemObj.value("qml").toString();
+ TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
+ QUrl icon = m_bundlePath3D.pathAppended(itemObj.value("icon").toString()).toUrl();
+ QStringList files;
+ const QJsonArray assetsArr = itemObj.value("files").toArray();
+ for (const QJsonValueConstRef &asset : assetsArr)
+ files.append(asset.toString());
+
+ m_user3DItems.append(new ContentLibraryItem(nullptr, name, qml, type, icon, files));
+ }
+
+ m_bundle3DSharedFiles.clear();
+ const QJsonArray sharedFilesArr = m_bundleObj3D.value("sharedFiles").toArray();
+ for (const QJsonValueConstRef &file : sharedFilesArr)
+ m_bundle3DSharedFiles.append(file.toString());
+
+ m_bundle3DExists = true;
+ updateNoMatch3D();
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+}
+
+void ContentLibraryUserModel::loadTextureBundle()
+{
+ if (!m_userTextures.isEmpty())
+ return;
+
+ QDir bundleDir{Paths::bundlesPathSetting() + "/User/textures"};
+ bundleDir.mkpath(".");
+ bundleDir.mkdir("icons");
+
+ const QFileInfoList fileInfos = bundleDir.entryInfoList(QDir::Files);
+ for (const QFileInfo &fileInfo : fileInfos) {
+ QString suffix = '.' + fileInfo.suffix();
+ auto iconFileInfo = QFileInfo(fileInfo.path().append("/icons/").append(fileInfo.baseName() + ".png"));
+ QPair<QSize, qint64> info = ImageUtils::imageInfo(fileInfo.path());
+ QString dirPath = fileInfo.path();
+ QSize imgDims = info.first;
+ qint64 imgFileSize = info.second;
+
+ auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize);
+ m_userTextures.append(tex);
+ }
+
+ updateNoMatchTextures();
+ emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx));
+}
+
+bool ContentLibraryUserModel::hasRequiredQuick3DImport() const
+{
+ return m_widget->hasQuick3DImport() && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
+}
+
+bool ContentLibraryUserModel::matBundleExists() const
+{
+ return m_matBundleExists;
+}
+
+void ContentLibraryUserModel::setSearchText(const QString &searchText)
+{
+ QString lowerSearchText = searchText.toLower();
+
+ if (m_searchText == lowerSearchText)
+ return;
+
+ m_searchText = lowerSearchText;
+
+ for (ContentLibraryMaterial *item : std::as_const(m_userMaterials))
+ item->filter(m_searchText);
+
+ for (ContentLibraryTexture *item : std::as_const(m_userTextures))
+ item->filter(m_searchText);
+
+ for (ContentLibraryItem *item : std::as_const(m_user3DItems))
+ item->filter(m_searchText);
+
+ updateNoMatchMaterials();
+ updateNoMatchTextures();
+ updateNoMatch3D();
+ resetModel();
+}
+
+void ContentLibraryUserModel::updateMaterialsImportedState(const QStringList &importedItems)
+{
+ bool changed = false;
+ for (ContentLibraryMaterial *mat : std::as_const(m_userMaterials))
+ changed |= mat->setImported(importedItems.contains(mat->qml().chopped(4)));
+
+ if (changed)
+ emit dataChanged(index(MaterialsSectionIdx), index(MaterialsSectionIdx));
+}
+
+void ContentLibraryUserModel::update3DImportedState(const QStringList &importedItems)
+{
+ bool changed = false;
+ for (ContentLibraryItem *item : std::as_const(m_user3DItems))
+ changed |= item->setImported(importedItems.contains(item->qml().chopped(4)));
+
+ if (changed)
+ emit dataChanged(index(Items3DSectionIdx), index(Items3DSectionIdx));
+}
+
+void ContentLibraryUserModel::setQuick3DImportVersion(int major, int minor)
+{
+ bool oldRequiredImport = hasRequiredQuick3DImport();
+
+ m_quick3dMajorVersion = major;
+ m_quick3dMinorVersion = minor;
+
+ bool newRequiredImport = hasRequiredQuick3DImport();
+
+ if (oldRequiredImport == newRequiredImport)
+ return;
+
+ emit hasRequiredQuick3DImportChanged();
+}
+
+void ContentLibraryUserModel::resetModel()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+void ContentLibraryUserModel::applyToSelected(ContentLibraryMaterial *mat, bool add)
+{
+ emit applyToSelectedTriggered(mat, add);
+}
+
+void ContentLibraryUserModel::addToProject(QObject *item)
+{
+ QString bundleDir;
+ TypeName type;
+ QString qmlFile;
+ QStringList files;
+ if (auto mat = qobject_cast<ContentLibraryMaterial *>(item)) {
+ bundleDir = mat->dirPath();
+ type = mat->type();
+ qmlFile = mat->qml();
+ files = mat->files() + m_bundleMaterialSharedFiles;
+ } else if (auto itm = qobject_cast<ContentLibraryItem *>(item)) {
+ bundleDir = m_bundlePath3D.toString();
+ type = itm->type();
+ qmlFile = itm->qml();
+ files = itm->files() + m_bundle3DSharedFiles;
+ } else {
+ qWarning() << __FUNCTION__ << "Unsupported Item";
+ return;
+ }
+
+ QString err = m_widget->importer()->importComponent(bundleDir, type, qmlFile, files);
+
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
+ qWarning() << __FUNCTION__ << err;
+}
+
+void ContentLibraryUserModel::removeFromProject(QObject *item)
+{
+ TypeName type;
+ QString qml;
+ if (auto mat = qobject_cast<ContentLibraryMaterial *>(item)) {
+ type = mat->type();
+ qml = mat->qml();
+ } else if (auto itm = qobject_cast<ContentLibraryItem *>(item)) {
+ type = itm->type();
+ qml = itm->qml();
+ } else {
+ qWarning() << __FUNCTION__ << "Unsupported Item";
+ return;
+ }
+
+ QString err = m_widget->importer()->unimportComponent(type, qml);
+
+ if (err.isEmpty())
+ m_widget->setImporterRunning(true);
+ else
+ qWarning() << __FUNCTION__ << err;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h
new file mode 100644
index 0000000000..2a7f9a66f3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h
@@ -0,0 +1,135 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <utils/filepath.h>
+
+#include <QAbstractListModel>
+#include <QJsonObject>
+
+QT_FORWARD_DECLARE_CLASS(QUrl)
+
+namespace QmlDesigner {
+
+class ContentLibraryItem;
+class ContentLibraryMaterial;
+class ContentLibraryTexture;
+class ContentLibraryWidget;
+class NodeMetaInfo;
+
+class ContentLibraryUserModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
+ Q_PROPERTY(bool bundle3DExists MEMBER m_bundle3DExists NOTIFY bundle3DExistsChanged)
+ Q_PROPERTY(bool hasRequiredQuick3DImport READ hasRequiredQuick3DImport NOTIFY hasRequiredQuick3DImportChanged)
+ Q_PROPERTY(QList<ContentLibraryMaterial *> userMaterials MEMBER m_userMaterials NOTIFY userMaterialsChanged)
+ Q_PROPERTY(QList<ContentLibraryTexture *> userTextures MEMBER m_userTextures NOTIFY userTexturesChanged)
+ Q_PROPERTY(QList<ContentLibraryItem *> user3DItems MEMBER m_user3DItems NOTIFY user3DItemsChanged)
+ Q_PROPERTY(QList<ContentLibraryItem *> userEffects MEMBER m_userEffects NOTIFY userEffectsChanged)
+
+public:
+ ContentLibraryUserModel(ContentLibraryWidget *parent = nullptr);
+
+ 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 setSearchText(const QString &searchText);
+ void updateMaterialsImportedState(const QStringList &importedItems);
+ void update3DImportedState(const QStringList &importedItems);
+
+ QPair<QString, QString> getUniqueLibMaterialNames(const QString &defaultName = "Material") const;
+ QPair<QString, QString> getUniqueLib3DNames(const QString &defaultName = "Item") const;
+
+ void setQuick3DImportVersion(int major, int minor);
+
+ bool hasRequiredQuick3DImport() const;
+
+ bool matBundleExists() const;
+
+ void resetModel();
+ void updateNoMatchMaterials();
+ void updateNoMatchTextures();
+ void updateNoMatch3D();
+
+ void addMaterial(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
+ void add3DItem(const QString &name, const QString &qml, const QUrl &icon, const QStringList &files);
+ void refresh3DSection();
+ void addTextures(const QStringList &paths);
+
+ void add3DInstance(ContentLibraryItem *bundleItem);
+
+ void remove3DFromContentLibByName(const QString &qmlFileName);
+
+ void setBundleObj(const QJsonObject &newBundleObj);
+ QJsonObject &bundleJsonMaterialObjectRef();
+ QJsonObject &bundleJson3DObjectRef();
+
+ void loadBundles();
+
+ Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
+ Q_INVOKABLE void addToProject(QObject *item);
+ Q_INVOKABLE void removeFromProject(QObject *item);
+ Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex);
+ Q_INVOKABLE void removeFromContentLib(QObject *item);
+
+signals:
+ void hasRequiredQuick3DImportChanged();
+ void userMaterialsChanged();
+ void userTexturesChanged();
+ void user3DItemsChanged();
+ void userEffectsChanged();
+ void applyToSelectedTriggered(QmlDesigner::ContentLibraryMaterial *mat, bool add = false);
+ void matBundleExistsChanged();
+ void bundle3DExistsChanged();
+
+private:
+ enum SectionIndex { MaterialsSectionIdx = 0,
+ TexturesSectionIdx,
+ Items3DSectionIdx,
+ EffectsSectionIdx };
+
+ void loadMaterialBundle();
+ void load3DBundle();
+ void loadTextureBundle();
+ bool isValidIndex(int idx) const;
+ void removeMaterialFromContentLib(ContentLibraryMaterial *mat);
+ void remove3DFromContentLib(ContentLibraryItem *item);
+ QPair<QString, QString> getUniqueLibItemNames(const QString &defaultName,
+ const QJsonObject &bundleObj) const;
+
+ ContentLibraryWidget *m_widget = nullptr;
+ QString m_searchText;
+ QString m_bundleIdMaterial;
+ QString m_bundleId3D;
+ QStringList m_bundleMaterialSharedFiles;
+ QStringList m_bundle3DSharedFiles;
+ Utils::FilePath m_bundlePathMaterial;
+ Utils::FilePath m_bundlePath3D;
+
+ QList<ContentLibraryMaterial *> m_userMaterials;
+ QList<ContentLibraryTexture *> m_userTextures;
+ QList<ContentLibraryItem *> m_userEffects;
+ QList<ContentLibraryItem *> m_user3DItems;
+ QStringList m_userCategories;
+
+ QJsonObject m_bundleObjMaterial;
+ QJsonObject m_bundleObj3D;
+
+ bool m_noMatchMaterials = true;
+ bool m_noMatchTextures = true;
+ bool m_noMatch3D = true;
+ bool m_noMatchEffects = true;
+ bool m_matBundleExists = false;
+ bool m_bundle3DExists = false;
+
+ int m_quick3dMajorVersion = -1;
+ int m_quick3dMinorVersion = -1;
+
+ enum Roles { NameRole = Qt::UserRole + 1, VisibleRole, ItemsRole, NoMatchRole };
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
index 61ae078ea8..9258faaf33 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
@@ -4,22 +4,29 @@
#include "contentlibraryview.h"
#include "contentlibrarybundleimporter.h"
-#include "contentlibraryeffect.h"
+#include "contentlibraryitem.h"
#include "contentlibraryeffectsmodel.h"
#include "contentlibrarymaterial.h"
#include "contentlibrarymaterialsmodel.h"
#include "contentlibrarytexture.h"
#include "contentlibrarytexturesmodel.h"
+#include "contentlibraryusermodel.h"
#include "contentlibrarywidget.h"
-#include "externaldependenciesinterface.h"
-#include "nodelistproperty.h"
-#include "qmldesignerconstants.h"
-#include "qmlobjectnode.h"
-#include "variantproperty.h"
-#include <utils3d.h>
-#include <coreplugin/messagebox.h>
+#include <asset.h>
+#include <bindingproperty.h>
+#include <designerpaths.h>
+#include <documentmanager.h>
#include <enumeration.h>
+#include <externaldependenciesinterface.h>
+#include <nodelistproperty.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+#include <qmlobjectnode.h>
+#include <uniquename.h>
+#include <utils3d.h>
+#include <variantproperty.h>
+
#include <utils/algorithm.h>
#ifndef QMLDESIGNER_TEST
@@ -30,12 +37,19 @@
#include <qtsupport/qtkitaspect.h>
#endif
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QMessageBox>
+#include <QPixmap>
#include <QVector3D>
namespace QmlDesigner {
-ContentLibraryView::ContentLibraryView(ExternalDependenciesInterface &externalDependencies)
+ContentLibraryView::ContentLibraryView(AsynchronousImageCache &imageCache,
+ ExternalDependenciesInterface &externalDependencies)
: AbstractView(externalDependencies)
+ , m_imageCache(imageCache)
, m_createTexture(this)
{}
@@ -60,9 +74,9 @@ WidgetInfo ContentLibraryView::widgetInfo()
[&] (QmlDesigner::ContentLibraryTexture *tex) {
m_draggedBundleTexture = tex;
});
- connect(m_widget, &ContentLibraryWidget::bundleEffectDragStarted, this,
- [&] (QmlDesigner::ContentLibraryEffect *eff) {
- m_draggedBundleEffect = eff;
+ connect(m_widget, &ContentLibraryWidget::bundleItemDragStarted, this,
+ [&] (QmlDesigner::ContentLibraryItem *item) {
+ m_draggedBundleItem = item;
});
connect(m_widget, &ContentLibraryWidget::addTextureRequested, this,
@@ -79,138 +93,150 @@ WidgetInfo ContentLibraryView::widgetInfo()
m_widget->environmentsModel()->setHasSceneEnv(sceneEnvExists);
});
- ContentLibraryMaterialsModel *materialsModel = m_widget->materialsModel().data();
-
- connect(materialsModel,
+ connect(m_widget->materialsModel(),
&ContentLibraryMaterialsModel::applyToSelectedTriggered,
this,
[&](ContentLibraryMaterial *bundleMat, bool add) {
- if (m_selectedModels.isEmpty())
- return;
+ if (m_selectedModels.isEmpty())
+ return;
- m_bundleMaterialTargets = m_selectedModels;
- m_bundleMaterialAddToSelected = add;
+ m_bundleMaterialTargets = m_selectedModels;
+ m_bundleMaterialAddToSelected = add;
- ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type());
- if (defaultMat.isValid())
- applyBundleMaterialToDropTarget(defaultMat);
- else
- m_widget->materialsModel()->addToProject(bundleMat);
- });
+ ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type());
+ if (defaultMat.isValid())
+ applyBundleMaterialToDropTarget(defaultMat);
+ else
+ m_widget->materialsModel()->addToProject(bundleMat);
+ });
-#ifdef QDS_USE_PROJECTSTORAGE
- connect(materialsModel,
- &ContentLibraryMaterialsModel::bundleMaterialImported,
- this,
- [&](const QmlDesigner::TypeName &typeName) {
- applyBundleMaterialToDropTarget({}, typeName);
- updateBundleMaterialsImportedState();
- });
-#else
- connect(materialsModel,
- &ContentLibraryMaterialsModel::bundleMaterialImported,
+ connect(m_widget->userModel(),
+ &ContentLibraryUserModel::applyToSelectedTriggered,
this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- applyBundleMaterialToDropTarget({}, metaInfo);
- updateBundleMaterialsImportedState();
- });
-#endif
+ [&](ContentLibraryMaterial *bundleMat, bool add) {
+ if (m_selectedModels.isEmpty())
+ return;
- connect(materialsModel, &ContentLibraryMaterialsModel::bundleMaterialAboutToUnimport, this,
- [&] (const QmlDesigner::TypeName &type) {
- // delete instances of the bundle material that is about to be unimported
- executeInTransaction("ContentLibraryView::widgetInfo", [&] {
- ModelNode matLib = Utils3D::materialLibraryNode(this);
- if (!matLib.isValid())
- return;
+ m_bundleMaterialTargets = m_selectedModels;
+ m_bundleMaterialAddToSelected = add;
- Utils::reverseForeach(matLib.directSubModelNodes(), [&](const ModelNode &mat) {
- if (mat.isValid() && mat.type() == type)
- QmlObjectNode(mat).destroy();
- });
- });
+ ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type());
+ if (defaultMat.isValid())
+ applyBundleMaterialToDropTarget(defaultMat);
+ else
+ m_widget->userModel()->addToProject(bundleMat);
});
- connect(materialsModel, &ContentLibraryMaterialsModel::bundleMaterialUnimported, this,
- &ContentLibraryView::updateBundleMaterialsImportedState);
+ connectImporter();
+ }
- ContentLibraryEffectsModel *effectsModel = m_widget->effectsModel().data();
+ return createWidgetInfo(m_widget.data(),
+ "ContentLibrary",
+ WidgetInfo::LeftPane,
+ 0,
+ tr("Content Library"));
+}
+void ContentLibraryView::connectImporter()
+{
#ifdef QDS_USE_PROJECTSTORAGE
- connect(effectsModel,
- &ContentLibraryEffectsModel::bundleItemImported,
- this,
- [&](const QmlDesigner::TypeName &typeName) {
- QTC_ASSERT(typeName.size(), return);
-
- if (!m_bundleEffectTarget)
- m_bundleEffectTarget = Utils3D::active3DSceneNode(this);
+ connect(m_widget->importer(),
+ &ContentLibraryBundleImporter::importFinished,
+ this,
+ [&](const QmlDesigner::TypeName &typeName, const QString &bundleId) {
+ QTC_ASSERT(typeName.size(), return);
+ if (isMaterialBundle(bundleId)) {
+ applyBundleMaterialToDropTarget({}, typeName);
+ } else if (isItemBundle(bundleId)) {
+ if (!m_bundleItemTarget)
+ m_bundleItemTarget = Utils3D::active3DSceneNode(this);
- QTC_ASSERT(m_bundleEffectTarget, return);
+ QTC_ASSERT(m_bundleItemTarget, return);
executeInTransaction("ContentLibraryView::widgetInfo", [&] {
- QVector3D pos = m_bundleEffectPos.value<QVector3D>();
- ModelNode newEffNode = createModelNode(
+ QVector3D pos = m_bundleItemPos.value<QVector3D>();
+ ModelNode newNode = createModelNode(
typeName, -1, -1, {{"x", pos.x()}, {"y", pos.y()}, {"z", pos.z()}});
- m_bundleEffectTarget.defaultNodeListProperty().reparentHere(newEffNode);
+ m_bundleItemTarget.defaultNodeListProperty().reparentHere(newNode);
clearSelectedModelNodes();
- selectModelNode(newEffNode);
+ selectModelNode(newNode);
});
- updateBundleEffectsImportedState();
- m_bundleEffectTarget = {};
- m_bundleEffectPos = {};
- });
+ m_bundleItemTarget = {};
+ m_bundleItemPos = {};
+ }
+ });
#else
- connect(effectsModel,
- &ContentLibraryEffectsModel::bundleItemImported,
- this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- QTC_ASSERT(metaInfo.isValid(), return);
-
- if (!m_bundleEffectTarget)
- m_bundleEffectTarget = Utils3D::active3DSceneNode(this);
+ connect(m_widget->importer(),
+ &ContentLibraryBundleImporter::importFinished,
+ this,
+ [&](const QmlDesigner::NodeMetaInfo &metaInfo, const QString &bundleId) {
+ QTC_ASSERT(metaInfo.isValid(), return);
+ if (isMaterialBundle(bundleId)) {
+ applyBundleMaterialToDropTarget({}, metaInfo);
+ } else if (isItemBundle(bundleId)) {
+ if (!m_bundleItemTarget)
+ m_bundleItemTarget = Utils3D::active3DSceneNode(this);
- QTC_ASSERT(m_bundleEffectTarget, return);
+ QTC_ASSERT(m_bundleItemTarget, return);
- executeInTransaction("ContentLibraryView::widgetInfo", [&] {
- QVector3D pos = m_bundleEffectPos.value<QVector3D>();
- ModelNode newEffNode = createModelNode(metaInfo.typeName(),
+ executeInTransaction("ContentLibraryView::connectImporter", [&] {
+ QVector3D pos = m_bundleItemPos.value<QVector3D>();
+ ModelNode newNode = createModelNode(metaInfo.typeName(),
metaInfo.majorVersion(),
metaInfo.minorVersion(),
{{"x", pos.x()},
{"y", pos.y()},
{"z", pos.z()}});
- m_bundleEffectTarget.defaultNodeListProperty().reparentHere(newEffNode);
+ m_bundleItemTarget.defaultNodeListProperty().reparentHere(newNode);
clearSelectedModelNodes();
- selectModelNode(newEffNode);
+ selectModelNode(newNode);
});
- updateBundleEffectsImportedState();
- m_bundleEffectTarget = {};
- m_bundleEffectPos = {};
- });
+ m_bundleItemTarget = {};
+ m_bundleItemPos = {};
+ }
+ });
#endif
- connect(effectsModel, &ContentLibraryEffectsModel::bundleItemAboutToUnimport, this,
- [&] (const QmlDesigner::TypeName &type) {
- // delete instances of the bundle effect that is about to be unimported
- executeInTransaction("ContentLibraryView::widgetInfo", [&] {
- NodeMetaInfo metaInfo = model()->metaInfo(type);
- QList<ModelNode> effects = allModelNodesOfType(metaInfo);
- for (ModelNode &eff : effects)
- eff.destroy();
- });
+
+ connect(m_widget->importer(), &ContentLibraryBundleImporter::aboutToUnimport, this,
+ [&] (const QmlDesigner::TypeName &type, const QString &bundleId) {
+ if (isMaterialBundle(bundleId)) {
+ // delete instances of the bundle material that is about to be unimported
+ executeInTransaction("ContentLibraryView::connectImporter", [&] {
+ ModelNode matLib = Utils3D::materialLibraryNode(this);
+ if (!matLib.isValid())
+ return;
+
+ Utils::reverseForeach(matLib.directSubModelNodes(), [&](const ModelNode &mat) {
+ if (mat.isValid() && mat.type() == type)
+ QmlObjectNode(mat).destroy();
});
+ });
+ } else if (isItemBundle(bundleId)) {
+ // delete instances of the bundle item that is about to be unimported
+ executeInTransaction("ContentLibraryView::connectImporter", [&] {
+ NodeMetaInfo metaInfo = model()->metaInfo(type);
+ QList<ModelNode> nodes = allModelNodesOfType(metaInfo);
+ for (ModelNode &node : nodes)
+ node.destroy();
+ });
+ }
+ });
+}
- connect(effectsModel, &ContentLibraryEffectsModel::bundleItemUnimported, this,
- &ContentLibraryView::updateBundleEffectsImportedState);
- }
+bool ContentLibraryView::isMaterialBundle(const QString &bundleId) const
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ return bundleId == compUtils.materialsBundleId() || bundleId == compUtils.userMaterialsBundleId();
+}
- return createWidgetInfo(m_widget.data(),
- "ContentLibrary",
- WidgetInfo::LeftPane,
- 0,
- tr("Content Library"));
+// item bundle includes effects and 3D components
+bool ContentLibraryView::isItemBundle(const QString &bundleId) const
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ return bundleId == compUtils.effectsBundleId() || bundleId == compUtils.userEffectsBundleId()
+ || bundleId == compUtils.user3DBundleId();
}
void ContentLibraryView::modelAttached(Model *model)
@@ -220,7 +246,6 @@ void ContentLibraryView::modelAttached(Model *model)
m_hasQuick3DImport = model->hasImport("QtQuick3D");
updateBundlesQuick3DVersion();
- updateBundleMaterialsImportedState();
const bool hasLibrary = Utils3D::materialLibraryNode(this).isValid();
m_widget->setHasMaterialLibrary(hasLibrary);
@@ -232,8 +257,17 @@ void ContentLibraryView::modelAttached(Model *model)
m_widget->setHasActive3DScene(m_sceneId != -1);
m_widget->clearSearchFilter();
+ // bundles loading has to happen here, otherwise project path is not ready which will
+ // cause bundle items types to resolve incorrectly
+ m_widget->materialsModel()->loadBundle();
m_widget->effectsModel()->loadBundle();
- updateBundleEffectsImportedState();
+ m_widget->userModel()->loadBundles();
+
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ m_widget->updateImportedState(compUtils.materialsBundleId());
+ m_widget->updateImportedState(compUtils.effectsBundleId());
+ m_widget->updateImportedState(compUtils.userMaterialsBundleId());
+ m_widget->updateImportedState(compUtils.user3DBundleId());
}
void ContentLibraryView::modelAboutToBeDetached(Model *model)
@@ -275,7 +309,7 @@ void ContentLibraryView::selectedNodesChanged(const QList<ModelNode> &selectedNo
return node.metaInfo().isQtQuick3DModel();
});
- m_widget->materialsModel()->setHasModelSelection(!m_selectedModels.isEmpty());
+ m_widget->setHasModelSelection(!m_selectedModels.isEmpty());
}
void ContentLibraryView::customNotification(const AbstractView *view,
@@ -283,8 +317,6 @@ void ContentLibraryView::customNotification(const AbstractView *view,
const QList<ModelNode> &nodeList,
const QList<QVariant> &data)
{
- Q_UNUSED(data)
-
if (view == this)
return;
@@ -318,12 +350,29 @@ void ContentLibraryView::customNotification(const AbstractView *view,
m_widget->addTexture(m_draggedBundleTexture);
m_draggedBundleTexture = nullptr;
- } else if (identifier == "drop_bundle_effect") {
+ } else if (identifier == "drop_bundle_item") {
QTC_ASSERT(nodeList.size() == 1, return);
- m_bundleEffectPos = data.size() == 1 ? data.first() : QVariant();
- m_widget->effectsModel()->addInstance(m_draggedBundleEffect);
- m_bundleEffectTarget = nodeList.first() ? nodeList.first() : Utils3D::active3DSceneNode(this);
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ bool is3D = m_draggedBundleItem->type().startsWith(compUtils.user3DBundleType().toLatin1());
+
+ m_bundleItemPos = data.size() == 1 ? data.first() : QVariant();
+ if (is3D)
+ m_widget->userModel()->add3DInstance(m_draggedBundleItem);
+ else
+ m_widget->effectsModel()->addInstance(m_draggedBundleItem);
+ m_bundleItemTarget = nodeList.first() ? nodeList.first() : Utils3D::active3DSceneNode(this);
+ } else if (identifier == "add_material_to_content_lib") {
+ QTC_ASSERT(nodeList.size() == 1 && data.size() == 1, return);
+
+ addLibMaterial(nodeList.first(), data.first().value<QPixmap>());
+ } else if (identifier == "add_assets_to_content_lib") {
+ addLibAssets(data.first().toStringList());
+ } else if (identifier == "add_3d_to_content_lib") {
+ if (nodeList.first().isComponent())
+ addLib3DComponent(nodeList.first());
+ else
+ addLib3DItem(nodeList.first());
}
}
@@ -452,6 +501,325 @@ void ContentLibraryView::applyBundleMaterialToDropTarget(const ModelNode &bundle
}
#endif
+// Add a project material to Content Library's user tab
+void ContentLibraryView::addLibMaterial(const ModelNode &node, const QPixmap &iconPixmap)
+{
+ auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/materials/");
+
+ QString name = node.variantProperty("objectName").value().toString();
+ auto [qml, icon] = m_widget->userModel()->getUniqueLibMaterialNames(node.id());
+
+ QString iconPath = QLatin1String("icons/%1").arg(icon);
+ QString fullIconPath = bundlePath.pathAppended(iconPath).toString();
+
+ // save icon
+ bool iconSaved = iconPixmap.save(fullIconPath);
+ if (!iconSaved)
+ qWarning() << __FUNCTION__ << "icon save failed";
+
+ // generate and save material Qml file
+ const QStringList depAssets = writeLibItemQml(node, qml);
+
+ // add the material to the bundle json
+ QJsonObject &jsonRef = m_widget->userModel()->bundleJsonMaterialObjectRef();
+ QJsonArray itemsArr = jsonRef.value("items").toArray();
+ QJsonObject itemObj;
+ itemObj.insert("name", name);
+ itemObj.insert("qml", qml);
+ itemObj.insert("icon", iconPath);
+ QJsonArray filesArr;
+ for (const QString &assetPath : depAssets)
+ filesArr.append(assetPath);
+ itemObj.insert("files", filesArr);
+
+ itemsArr.append(itemObj);
+ jsonRef["items"] = itemsArr;
+
+ auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
+ .writeFileContents(QJsonDocument(jsonRef).toJson());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ // copy material assets to bundle folder
+ for (const QString &assetPath : depAssets) {
+ Utils::FilePath assetPathSource = DocumentManager::currentResourcePath().pathAppended(assetPath);
+ Utils::FilePath assetPathTarget = bundlePath.pathAppended(assetPath);
+ assetPathTarget.parentDir().ensureWritableDir();
+
+ auto result = assetPathSource.copyFile(assetPathTarget);
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+ }
+
+ m_widget->userModel()->addMaterial(name, qml, QUrl::fromLocalFile(fullIconPath), depAssets);
+}
+
+QStringList ContentLibraryView::writeLibItemQml(const ModelNode &node, const QString &qml)
+{
+ QStringList depListIds;
+ auto [qmlString, assets] = modelNodeToQmlString(node, depListIds);
+
+ qmlString.prepend("import QtQuick\nimport QtQuick3D\n\n");
+
+ QString itemType = QLatin1String(node.metaInfo().isQtQuick3DMaterial() ? "materials" : "3d");
+ auto qmlPath = Utils::FilePath::fromString(QLatin1String("%1/User/%2/%3")
+ .arg(Paths::bundlesPathSetting(), itemType, qml));
+ auto result = qmlPath.writeFileContents(qmlString.toUtf8());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ return assets.values();
+}
+
+QPair<QString, QSet<QString>> ContentLibraryView::modelNodeToQmlString(const ModelNode &node,
+ QStringList &depListIds,
+ int depth)
+{
+ QString qml;
+ QSet<QString> assets;
+
+ QString indent = QString(" ").repeated(depth * 4);
+
+ qml += indent + node.simplifiedTypeName() + " {\n";
+
+ indent = QString(" ").repeated((depth + 1) * 4);
+
+ qml += indent + "id: " + (depth == 0 ? "root" : node.id()) + " \n\n";
+
+ const QList<PropertyName> excludedProps = {"x", "y", "z", "eulerRotation.x", "eulerRotation.y",
+ "eulerRotation.z", "scale.x", "scale.y", "scale.z",
+ "pivot.x", "pivot.y", "pivot.z"};
+ const QList<AbstractProperty> matProps = node.properties();
+ for (const AbstractProperty &p : matProps) {
+ if (excludedProps.contains(p.name()))
+ continue;
+
+ if (p.isVariantProperty()) {
+ QVariant pValue = p.toVariantProperty().value();
+ QString val;
+ if (strcmp(pValue.typeName(), "QString") == 0 || strcmp(pValue.typeName(), "QColor") == 0) {
+ val = QLatin1String("\"%1\"").arg(pValue.toString());
+ } else if (strcmp(pValue.typeName(), "QUrl") == 0) {
+ QString pValueStr = pValue.toString();
+ val = QLatin1String("\"%1\"").arg(pValueStr);
+ if (!pValueStr.startsWith("#"))
+ assets.insert(pValue.toString());
+ } else if (strcmp(pValue.typeName(), "QmlDesigner::Enumeration") == 0) {
+ val = pValue.value<QmlDesigner::Enumeration>().toString();
+ } else {
+ val = pValue.toString();
+ }
+
+ qml += indent + p.name() + ": " + val + "\n";
+ } else if (p.isBindingProperty()) {
+ qml += indent + p.name() + ": " + p.toBindingProperty().expression() + "\n";
+
+ ModelNode depNode = modelNodeForId(p.toBindingProperty().expression());
+
+ if (depNode && !depListIds.contains(depNode.id())) {
+ depListIds.append(depNode.id());
+ auto [depQml, depAssets] = modelNodeToQmlString(depNode, depListIds, depth + 1);
+ qml += "\n" + depQml + "\n";
+ assets.unite(depAssets);
+ }
+ }
+ }
+
+ indent = QString(" ").repeated(depth * 4);
+
+ qml += indent + "}\n";
+
+ return {qml, assets};
+}
+
+void ContentLibraryView::addLibAssets(const QStringList &paths)
+{
+ auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/textures");
+ QStringList pathsInBundle;
+
+ const QStringList existingTextures = Utils::transform(bundlePath.dirEntries(QDir::Files),
+ [](const Utils::FilePath &path) {
+ return path.fileName();
+ });
+
+ for (const QString &path : paths) {
+ auto assetFilePath = Utils::FilePath::fromString(path);
+ if (existingTextures.contains(assetFilePath.fileName()))
+ continue;
+
+ Asset asset(path);
+
+ // save icon
+ QString iconSavePath = bundlePath.pathAppended("icons/" + assetFilePath.baseName() + ".png")
+ .toString();
+ QPixmap icon = asset.pixmap({120, 120});
+ bool iconSaved = icon.save(iconSavePath);
+ if (!iconSaved)
+ qWarning() << __FUNCTION__ << "icon save failed";
+
+ // save asset
+ auto result = assetFilePath.copyFile(bundlePath.pathAppended(asset.fileName()));
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ pathsInBundle.append(bundlePath.pathAppended(asset.fileName()).toString());
+ }
+
+ m_widget->userModel()->addTextures(pathsInBundle);
+}
+
+void ContentLibraryView::addLib3DComponent(const ModelNode &node)
+{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
+ QString compBaseName = node.simplifiedTypeName();
+ QString compFileName = compBaseName + ".qml";
+
+ Utils::FilePath compDir = DocumentManager::currentProjectDirPath()
+ .pathAppended(compUtils.import3dTypePath() + '/' + compBaseName);
+
+ auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/");
+
+ // confirm overwrite if an item with same name exists
+ if (bundlePath.pathAppended(compFileName).exists()) {
+ // Show a QML confirmation dialog before proceeding
+ QMessageBox::StandardButton reply = QMessageBox::question(m_widget, tr("3D Item Exists"),
+ tr("A 3D item with the same name '%1' already exists in the Content Library, are you sure you want to overwrite it?")
+ .arg(compFileName), QMessageBox::Yes | QMessageBox::No);
+ if (reply == QMessageBox::No)
+ return;
+
+ // before overwriting remove old item (to avoid partial items and dangling assets)
+ m_widget->userModel()->remove3DFromContentLibByName(compFileName);
+ }
+
+ // generate and save icon
+ QString iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png");
+ QString fullIconPath = bundlePath.pathAppended(iconPath).toString();
+ genAndSaveIcon(compDir.pathAppended(compFileName).path(), fullIconPath);
+
+ const Utils::FilePaths sourceFiles = compDir.dirEntries({{}, QDir::Files, QDirIterator::Subdirectories});
+ const QStringList ignoreList {"_importdata.json", "qmldir", compBaseName + ".hints"};
+ QStringList filesList; // 3D component's assets (dependencies)
+
+ for (const Utils::FilePath &sourcePath : sourceFiles) {
+ Utils::FilePath relativePath = sourcePath.relativePathFrom(compDir);
+ if (ignoreList.contains(sourcePath.fileName()) || relativePath.startsWith("source scene"))
+ continue;
+
+ Utils::FilePath targetPath = bundlePath.pathAppended(relativePath.path());
+ targetPath.parentDir().ensureWritableDir();
+
+ // copy item from project to user bundle
+ auto result = sourcePath.copyFile(targetPath);
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ if (sourcePath.fileName() != compFileName) // skip component file (only collect dependencies)
+ filesList.append(relativePath.path());
+ }
+
+ // add the item to the bundle json
+ QJsonObject &jsonRef = m_widget->userModel()->bundleJson3DObjectRef();
+ QJsonArray itemsArr = jsonRef.value("items").toArray();
+ itemsArr.append(QJsonObject {
+ {"name", node.simplifiedTypeName()},
+ {"qml", compFileName},
+ {"icon", iconPath},
+ {"files", QJsonArray::fromStringList(filesList)}
+ });
+
+ jsonRef["items"] = itemsArr;
+
+ auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
+ .writeFileContents(QJsonDocument(jsonRef).toJson());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ m_widget->userModel()->add3DItem(compBaseName, compFileName, QUrl::fromLocalFile(fullIconPath),
+ filesList);
+}
+
+void ContentLibraryView::addLib3DItem(const ModelNode &node)
+{
+ auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/");
+
+ QString name = node.variantProperty("objectName").value().toString();
+ auto [qml, icon] = m_widget->userModel()->getUniqueLib3DNames(node.id());
+ QString iconPath = QLatin1String("icons/%1").arg(icon);
+
+ if (name.isEmpty())
+ name = node.id();
+
+ // generate and save item Qml file
+ const QStringList depAssets = writeLibItemQml(node, qml);
+
+ // generate and save icon
+ QString qmlPath = QLatin1String("%1/User/3d/%2").arg(Paths::bundlesPathSetting(), qml);
+ QString fullIconPath = bundlePath.pathAppended(iconPath).toString();
+ genAndSaveIcon(qmlPath, fullIconPath);
+
+ // add the item to the bundle json
+ QJsonObject &jsonRef = m_widget->userModel()->bundleJson3DObjectRef();
+ QJsonArray itemsArr = jsonRef.value("items").toArray();
+ itemsArr.append(QJsonObject {
+ {"name", name},
+ {"qml", qml},
+ {"icon", iconPath},
+ {"files", QJsonArray::fromStringList(depAssets)}
+ });
+
+ jsonRef["items"] = itemsArr;
+
+ auto result = bundlePath.pathAppended(Constants::BUNDLE_JSON_FILENAME)
+ .writeFileContents(QJsonDocument(jsonRef).toJson());
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+
+ // copy item's assets to bundle folder
+ for (const QString &assetPath : depAssets) {
+ Utils::FilePath assetPathSource = DocumentManager::currentResourcePath().pathAppended(assetPath);
+ Utils::FilePath assetPathTarget = bundlePath.pathAppended(assetPath);
+ assetPathTarget.parentDir().ensureWritableDir();
+
+ auto result = assetPathSource.copyFile(assetPathTarget);
+ if (!result)
+ qWarning() << __FUNCTION__ << result.error();
+ }
+
+ m_widget->userModel()->add3DItem(name, qml, QUrl::fromLocalFile(fullIconPath), depAssets);
+}
+
+/**
+ * @brief Generates an icon image from a qml component
+ * @param qmlPath path to the qml component file to be rendered
+ * @param iconPath output save path of the generated icon
+ */
+void ContentLibraryView::genAndSaveIcon(const QString &qmlPath, const QString &iconPath)
+{
+ m_imageCache.requestSmallImage(
+ Utils::PathString{qmlPath},
+ [&, qmlPath, iconPath](const QImage &image) {
+ bool iconSaved = image.save(iconPath);
+ if (iconSaved)
+ m_widget->userModel()->refresh3DSection();
+ else
+ qWarning() << "ContentLibraryView::genAndSaveIcon(): icon save failed";
+ },
+ [&](ImageCache::AbortReason abortReason) {
+ if (abortReason == ImageCache::AbortReason::Abort) {
+ qWarning() << QLatin1String("ContentLibraryView::genAndSaveIcon(): icon generation "
+ "failed for path %1, reason: Abort").arg(qmlPath);
+ } else if (abortReason == ImageCache::AbortReason::Failed) {
+ qWarning() << QLatin1String("ContentLibraryView::genAndSaveIcon(): icon generation "
+ "failed for path %1, reason: Failed").arg(qmlPath);
+ } else if (abortReason == ImageCache::AbortReason::NoEntry) {
+ qWarning() << QLatin1String("ContentLibraryView::genAndSaveIcon(): icon generation "
+ "failed for path %1, reason: NoEntry").arg(qmlPath);
+ }
+ });
+}
+
ModelNode ContentLibraryView::getBundleMaterialDefaultInstance(const TypeName &type)
{
ModelNode matLib = Utils3D::materialLibraryNode(this);
@@ -477,6 +845,7 @@ ModelNode ContentLibraryView::getBundleMaterialDefaultInstance(const TypeName &t
return {};
}
+
#ifdef QDS_USE_PROJECTSTORAGE
ModelNode ContentLibraryView::createMaterial(const TypeName &typeName)
{
@@ -491,7 +860,7 @@ ModelNode ContentLibraryView::createMaterial(const TypeName &typeName)
QString newName = QString::fromUtf8(typeName).replace(rgx, " \\1\\2").trimmed();
if (newName.endsWith(" Material"))
newName.chop(9); // remove trailing " Material"
- QString newId = model()->generateIdFromName(newName, "material");
+ QString newId = model()->generateNewId(newName, "material");
newMatNode.setIdWithRefactoring(newId);
VariantProperty objNameProp = newMatNode.variantProperty("objectName");
@@ -517,7 +886,7 @@ ModelNode ContentLibraryView::createMaterial(const NodeMetaInfo &metaInfo)
QString newName = QString::fromLatin1(metaInfo.simplifiedTypeName()).replace(rgx, " \\1\\2").trimmed();
if (newName.endsWith(" Material"))
newName.chop(9); // remove trailing " Material"
- QString newId = model()->generateIdFromName(newName, "material");
+ QString newId = model()->generateNewId(newName, "material");
newMatNode.setIdWithRefactoring(newId);
VariantProperty objNameProp = newMatNode.variantProperty("objectName");
@@ -529,44 +898,6 @@ ModelNode ContentLibraryView::createMaterial(const NodeMetaInfo &metaInfo)
}
#endif
-void ContentLibraryView::updateBundleMaterialsImportedState()
-{
- using namespace Utils;
-
- if (!m_widget->materialsModel()->bundleImporter())
- return;
-
- QStringList importedBundleMats;
-
- FilePath materialBundlePath = m_widget->materialsModel()->bundleImporter()->resolveBundleImportPath();
-
- if (materialBundlePath.exists()) {
- importedBundleMats = transform(materialBundlePath.dirEntries({{"*.qml"}, QDir::Files}),
- [](const FilePath &f) { return f.fileName().chopped(4); });
- }
-
- m_widget->materialsModel()->updateImportedState(importedBundleMats);
-}
-
-void ContentLibraryView::updateBundleEffectsImportedState()
-{
- using namespace Utils;
-
- if (!m_widget->effectsModel()->bundleImporter())
- return;
-
- QStringList importedBundleEffs;
-
- FilePath bundlePath = m_widget->effectsModel()->bundleImporter()->resolveBundleImportPath();
-
- if (bundlePath.exists()) {
- importedBundleEffs = transform(bundlePath.dirEntries({{"*.qml"}, QDir::Files}),
- [](const FilePath &f) { return f.fileName().chopped(4); });
- }
-
- m_widget->effectsModel()->updateImportedState(importedBundleEffs);
-}
-
void ContentLibraryView::updateBundlesQuick3DVersion()
{
bool hasImport = false;
@@ -601,6 +932,7 @@ void ContentLibraryView::updateBundlesQuick3DVersion()
#endif
m_widget->materialsModel()->setQuick3DImportVersion(major, minor);
m_widget->effectsModel()->setQuick3DImportVersion(major, minor);
+ m_widget->userModel()->setQuick3DImportVersion(major, minor);
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
index 3b57b7a4ab..914a8b8ea0 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
@@ -3,16 +3,19 @@
#pragma once
-#include "abstractview.h"
-#include "createtexture.h"
-#include "nodemetainfo.h"
+#include <asynchronousimagecache.h>
+#include <abstractview.h>
+#include <createtexture.h>
+#include <nodemetainfo.h>
#include <QObject>
#include <QPointer>
+QT_FORWARD_DECLARE_CLASS(QPixmap)
+
namespace QmlDesigner {
-class ContentLibraryEffect;
+class ContentLibraryItem;
class ContentLibraryMaterial;
class ContentLibraryTexture;
class ContentLibraryWidget;
@@ -23,7 +26,8 @@ class ContentLibraryView : public AbstractView
Q_OBJECT
public:
- ContentLibraryView(ExternalDependenciesInterface &externalDependencies);
+ ContentLibraryView(AsynchronousImageCache &imageCache,
+ ExternalDependenciesInterface &externalDependencies);
~ContentLibraryView() override;
bool hasWidget() const override;
@@ -46,10 +50,20 @@ public:
const QVariant &data) override;
private:
+ void connectImporter();
+ bool isMaterialBundle(const QString &bundleId) const;
+ bool isItemBundle(const QString &bundleId) const;
void active3DSceneChanged(qint32 sceneId);
- void updateBundleMaterialsImportedState();
- void updateBundleEffectsImportedState();
void updateBundlesQuick3DVersion();
+ void addLibMaterial(const ModelNode &node, const QPixmap &iconPixmap);
+ void addLibAssets(const QStringList &paths);
+ void addLib3DComponent(const ModelNode &node);
+ void addLib3DItem(const ModelNode &node);
+ void genAndSaveIcon(const QString &qmlPath, const QString &iconPath);
+ QStringList writeLibItemQml(const ModelNode &node, const QString &qml);
+ QPair<QString, QSet<QString>> modelNodeToQmlString(const ModelNode &node, QStringList &depListIds,
+ int depth = 0);
+
#ifdef QDS_USE_PROJECTSTORAGE
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const TypeName &typeName = {});
#else
@@ -64,12 +78,13 @@ private:
#endif
QPointer<ContentLibraryWidget> m_widget;
QList<ModelNode> m_bundleMaterialTargets;
- ModelNode m_bundleEffectTarget; // target of the dropped bundle effect
- QVariant m_bundleEffectPos; // pos of the dropped bundle effect
+ ModelNode m_bundleItemTarget; // target of the dropped bundle item
+ QVariant m_bundleItemPos; // pos of the dropped bundle item
QList<ModelNode> m_selectedModels; // selected 3D model nodes
ContentLibraryMaterial *m_draggedBundleMaterial = nullptr;
ContentLibraryTexture *m_draggedBundleTexture = nullptr;
- ContentLibraryEffect *m_draggedBundleEffect = nullptr;
+ ContentLibraryItem *m_draggedBundleItem = nullptr;
+ AsynchronousImageCache &m_imageCache;
bool m_bundleMaterialAddToSelected = false;
bool m_hasQuick3DImport = false;
qint32 m_sceneId = -1;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
index c885a76ba7..72bece4c98 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
@@ -3,13 +3,15 @@
#include "contentlibrarywidget.h"
-#include "contentlibraryeffect.h"
+#include "contentlibrarybundleimporter.h"
#include "contentlibraryeffectsmodel.h"
+#include "contentlibraryitem.h"
#include "contentlibrarymaterial.h"
#include "contentlibrarymaterialsmodel.h"
#include "contentlibrarytexture.h"
#include "contentlibrarytexturesmodel.h"
#include "contentlibraryiconprovider.h"
+#include "contentlibraryusermodel.h"
#include "utils/filedownloader.h"
#include "utils/fileextractor.h"
@@ -17,6 +19,7 @@
#include <coreplugin/icore.h>
#include <designerpaths.h>
+#include <nodemetainfo.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
@@ -39,7 +42,6 @@
#include <QQuickWidget>
#include <QRegularExpression>
#include <QShortcut>
-#include <QStandardPaths>
#include <QVBoxLayout>
namespace QmlDesigner {
@@ -66,18 +68,18 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
Model *model = document->currentModel();
QTC_ASSERT(model, return false);
- if (m_effectToDrag) {
+ if (m_itemToDrag) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) {
QByteArray data;
QMimeData *mimeData = new QMimeData;
QDataStream stream(&data, QIODevice::WriteOnly);
- stream << m_effectToDrag->type();
- mimeData->setData(Constants::MIME_TYPE_BUNDLE_EFFECT, data);
+ stream << m_itemToDrag->type();
+ mimeData->setData(Constants::MIME_TYPE_BUNDLE_ITEM, data);
- emit bundleEffectDragStarted(m_effectToDrag);
- model->startDrag(mimeData, m_effectToDrag->icon().toLocalFile());
- m_effectToDrag = nullptr;
+ emit bundleItemDragStarted(m_itemToDrag);
+ model->startDrag(mimeData, m_itemToDrag->icon().toLocalFile());
+ m_itemToDrag = nullptr;
}
} else if (m_materialToDrag) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
@@ -100,10 +102,10 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
&& m_textureToDrag->isDownloaded()) {
QMimeData *mimeData = new QMimeData;
mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE,
- {m_textureToDrag->downloadedTexturePath().toUtf8()});
+ {m_textureToDrag->texturePath().toUtf8()});
// Allows standard file drag-n-drop. As of now needed to drop on Assets view
- mimeData->setUrls({QUrl::fromLocalFile(m_textureToDrag->downloadedTexturePath())});
+ mimeData->setUrls({QUrl::fromLocalFile(m_textureToDrag->texturePath())});
emit bundleTextureDragStarted(m_textureToDrag);
model->startDrag(mimeData, m_textureToDrag->icon().toLocalFile());
@@ -111,7 +113,7 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
}
}
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
- m_effectToDrag = nullptr;
+ m_itemToDrag = nullptr;
m_materialToDrag = nullptr;
m_textureToDrag = nullptr;
setIsDragging(false);
@@ -121,11 +123,12 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
}
ContentLibraryWidget::ContentLibraryWidget()
- : m_quickWidget(new StudioQuickWidget(this))
+ : m_quickWidget(Utils::makeUniqueObjectPtr<StudioQuickWidget>(this))
, m_materialsModel(new ContentLibraryMaterialsModel(this))
, m_texturesModel(new ContentLibraryTexturesModel("Textures", this))
, m_environmentsModel(new ContentLibraryTexturesModel("Environments", this))
, m_effectsModel(new ContentLibraryEffectsModel(this))
+ , m_userModel(new ContentLibraryUserModel(this))
{
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
qmlRegisterType<QmlDesigner::FileExtractor>("WebFetcher", 1, 0, "FileExtractor");
@@ -140,18 +143,12 @@ ContentLibraryWidget::ContentLibraryWidget()
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
- m_baseUrl = QmlDesignerPlugin::settings()
- .value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString()
- + "/textures";
+ m_textureBundleUrl = QmlDesignerPlugin::settings()
+ .value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString() + "/textures";
- m_texturesUrl = m_baseUrl + "/Textures";
- m_textureIconsUrl = m_baseUrl + "/icons/Textures";
- m_environmentIconsUrl = m_baseUrl + "/icons/Environments";
- m_environmentsUrl = m_baseUrl + "/Environments";
+ m_bundlePath = Paths::bundlesPathSetting();
- m_downloadPath = Paths::bundlesPathSetting();
-
- loadTextureBundle();
+ loadTextureBundles();
Theme::setupTheme(m_quickWidget->engine());
m_quickWidget->quickWidget()->installEventFilter(this);
@@ -159,7 +156,7 @@ ContentLibraryWidget::ContentLibraryWidget()
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
- layout->addWidget(m_quickWidget.data());
+ layout->addWidget(m_quickWidget.get());
updateSearch();
@@ -177,38 +174,95 @@ ContentLibraryWidget::ContentLibraryWidget()
{"materialsModel", QVariant::fromValue(m_materialsModel.data())},
{"texturesModel", QVariant::fromValue(m_texturesModel.data())},
{"environmentsModel", QVariant::fromValue(m_environmentsModel.data())},
- {"effectsModel", QVariant::fromValue(m_effectsModel.data())}});
+ {"effectsModel", QVariant::fromValue(m_effectsModel.data())},
+ {"userModel", QVariant::fromValue(m_userModel.data())}});
reloadQmlSource();
+ createImporter();
+}
+
+void ContentLibraryWidget::createImporter()
+{
+ m_importer = new ContentLibraryBundleImporter();
+#ifdef QDS_USE_PROJECTSTORAGE
+ connect(m_importer,
+ &ContentLibraryBundleImporter::importFinished,
+ this,
+ [&](const QmlDesigner::TypeName &typeName, const QString &bundleId) {
+ setImporterRunning(false);
+ if (typeName.size())
+ updateImportedState(bundleId);
+ });
+#else
+ connect(m_importer,
+ &ContentLibraryBundleImporter::importFinished,
+ this,
+ [&](const QmlDesigner::NodeMetaInfo &metaInfo, const QString &bundleId) {
+ setImporterRunning(false);
+ if (metaInfo.isValid())
+ updateImportedState(bundleId);
+ });
+#endif
+
+ connect(m_importer, &ContentLibraryBundleImporter::unimportFinished, this,
+ [&](const QmlDesigner::NodeMetaInfo &metaInfo, const QString &bundleId) {
+ Q_UNUSED(metaInfo)
+ setImporterRunning(false);
+ updateImportedState(bundleId);
+ });
+}
+
+void ContentLibraryWidget::updateImportedState(const QString &bundleId)
+{
+ if (!m_importer)
+ return;
+
+ Utils::FilePath bundlePath = m_importer->resolveBundleImportPath(bundleId);
+
+ QStringList importedItems;
+ if (bundlePath.exists()) {
+ importedItems = transform(bundlePath.dirEntries({{"*.qml"}, QDir::Files}),
+ [](const Utils::FilePath &f) { return f.baseName(); });
+ }
+
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+ if (bundleId == compUtils.materialsBundleId())
+ m_materialsModel->updateImportedState(importedItems);
+ else if (bundleId == compUtils.effectsBundleId())
+ m_effectsModel->updateImportedState(importedItems);
+ else if (bundleId == compUtils.userMaterialsBundleId())
+ m_userModel->updateMaterialsImportedState(importedItems);
+ else if (bundleId == compUtils.user3DBundleId())
+ m_userModel->update3DImportedState(importedItems);
+}
+
+ContentLibraryBundleImporter *ContentLibraryWidget::importer() const
+{
+ return m_importer;
}
-QVariantMap ContentLibraryWidget::readBundleMetadata()
+QVariantMap ContentLibraryWidget::readTextureBundleJson()
{
- QVariantMap metaData;
- QFile jsonFile(m_downloadPath + "/texture_bundle.json");
+ QVariantMap jsonData;
+ QFile jsonFile(m_bundlePath + "/texture_bundle.json");
if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
- metaData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap();
+ jsonData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap();
- int version = metaData["version"].toInt();
+ int version = jsonData["version"].toInt();
if (version > TextureBundleMetadataVersion) {
qWarning() << "Unrecognized texture metadata file version: " << version;
return {};
}
- return metaData;
+ return jsonData;
}
-void ContentLibraryWidget::loadTextureBundle()
+void ContentLibraryWidget::loadTextureBundles()
{
- QDir bundleDir{m_downloadPath};
+ QDir bundleDir{m_bundlePath};
- if (fetchTextureBundleMetadata(bundleDir) && fetchTextureBundleIcons(bundleDir)) {
- QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
- QVariantMap metaData = readBundleMetadata();
- m_texturesModel->loadTextureBundle(m_texturesUrl, m_textureIconsUrl, bundleIconPath, metaData);
- m_environmentsModel->loadTextureBundle(m_environmentsUrl, m_environmentIconsUrl,
- bundleIconPath, metaData);
- }
+ if (fetchTextureBundleJson(bundleDir) && fetchTextureBundleIcons(bundleDir))
+ populateTextureBundleModels();
}
std::tuple<QVariantMap, QVariantMap, QVariantMap> ContentLibraryWidget::compareTextureMetaFiles(
@@ -272,9 +326,9 @@ void ContentLibraryWidget::fetchNewTextureIcons(const QVariantMap &existingFiles
});
auto multidownloader = new MultiFileDownloader(this);
- multidownloader->setBaseUrl(QString(m_baseUrl + "/icons"));
+ multidownloader->setBaseUrl(QString(m_textureBundleUrl + "/icons"));
multidownloader->setFiles(fileList);
- multidownloader->setTargetDirPath(m_downloadPath + "/TextureBundleIcons");
+ multidownloader->setTargetDirPath(m_bundlePath + "/TextureBundleIcons");
auto downloader = new FileDownloader(this);
downloader->setDownloadEnabled(true);
@@ -314,15 +368,8 @@ void ContentLibraryWidget::fetchNewTextureIcons(const QVariantMap &existingFiles
existingFile.flush();
}
- if (fetchTextureBundleIcons(bundleDir)) {
- QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
- QVariantMap metaData = readBundleMetadata();
- m_texturesModel->loadTextureBundle(m_texturesUrl, m_textureIconsUrl, bundleIconPath,
- metaData);
- m_environmentsModel->loadTextureBundle(m_environmentsUrl, m_environmentIconsUrl,
- bundleIconPath, metaData);
- }
-
+ if (fetchTextureBundleIcons(bundleDir))
+ populateTextureBundleModels();
});
multidownloader->start();
@@ -433,50 +480,45 @@ QStringList ContentLibraryWidget::saveNewTextures(const QDir &bundleDir, const Q
}
}
-bool ContentLibraryWidget::fetchTextureBundleMetadata(const QDir &bundleDir)
+bool ContentLibraryWidget::fetchTextureBundleJson(const QDir &bundleDir)
{
QString filePath = bundleDir.filePath("texture_bundle.json");
QFileInfo fi(filePath);
- bool metaFileExists = fi.exists() && fi.size() > 0;
+ bool jsonFileExists = fi.exists() && fi.size() > 0;
- QString metaFileUrl = m_baseUrl + "/texture_bundle.zip";
+ QString bundleZipUrl = m_textureBundleUrl + "/texture_bundle.zip";
FileDownloader *downloader = new FileDownloader(this);
- downloader->setUrl(metaFileUrl);
+ downloader->setUrl(bundleZipUrl);
downloader->setProbeUrl(false);
downloader->setDownloadEnabled(true);
+ downloader->start();
QObject::connect(downloader, &FileDownloader::downloadFailed, this,
- [this, metaFileExists, bundleDir] {
- if (metaFileExists) {
- if (fetchTextureBundleIcons(bundleDir)) {
- QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
- QVariantMap metaData = readBundleMetadata();
- m_texturesModel->loadTextureBundle(m_texturesUrl, m_textureIconsUrl, bundleIconPath,
- metaData);
- m_environmentsModel->loadTextureBundle(m_environmentsUrl, m_environmentIconsUrl,
- bundleIconPath, metaData);
- }
+ [this, jsonFileExists, bundleDir] {
+ if (jsonFileExists) {
+ if (fetchTextureBundleIcons(bundleDir))
+ populateTextureBundleModels();
}
});
QObject::connect(downloader, &FileDownloader::finishedChanged, this,
- [this, downloader, bundleDir, metaFileExists, filePath] {
+ [this, downloader, bundleDir, jsonFileExists, filePath] {
FileExtractor *extractor = new FileExtractor(this);
extractor->setArchiveName(downloader->completeBaseName());
extractor->setSourceFile(downloader->outputFile());
- if (!metaFileExists)
+ if (!jsonFileExists)
extractor->setTargetPath(bundleDir.absolutePath());
extractor->setAlwaysCreateDir(false);
extractor->setClearTargetPathContents(false);
QObject::connect(extractor, &FileExtractor::finishedChanged, this,
- [this, downloader, bundleDir, extractor, metaFileExists, filePath] {
+ [this, downloader, bundleDir, extractor, jsonFileExists, filePath] {
downloader->deleteLater();
extractor->deleteLater();
- if (metaFileExists) {
+ if (jsonFileExists) {
QVariantMap newFiles, existing;
QVariantMap modifiedFilesEntries;
@@ -498,32 +540,35 @@ bool ContentLibraryWidget::fetchTextureBundleMetadata(const QDir &bundleDir)
}
}
- if (fetchTextureBundleIcons(bundleDir)) {
- QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
- QVariantMap metaData = readBundleMetadata();
- m_texturesModel->loadTextureBundle(m_texturesUrl, m_textureIconsUrl, bundleIconPath,
- metaData);
- m_environmentsModel->loadTextureBundle(m_environmentsUrl, m_environmentIconsUrl,
- bundleIconPath, metaData);
- }
+ if (fetchTextureBundleIcons(bundleDir))
+ populateTextureBundleModels();
});
extractor->extract();
});
- downloader->start();
return false;
}
+void ContentLibraryWidget::populateTextureBundleModels()
+{
+ QVariantMap jsonData = readTextureBundleJson();
+
+ QString bundleIconPath = m_bundlePath + "/TextureBundleIcons";
+
+ m_texturesModel->loadTextureBundle(m_textureBundleUrl, bundleIconPath, jsonData);
+ m_environmentsModel->loadTextureBundle(m_textureBundleUrl, bundleIconPath, jsonData);
+}
+
bool ContentLibraryWidget::fetchTextureBundleIcons(const QDir &bundleDir)
{
QString iconsPath = bundleDir.filePath("TextureBundleIcons");
QDir iconsDir(iconsPath);
- if (iconsDir.exists() && iconsDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).length() > 0)
+ if (iconsDir.exists() && !iconsDir.isEmpty())
return true;
- QString zipFileUrl = m_baseUrl + "/icons.zip";
+ QString zipFileUrl = m_textureBundleUrl + "/icons.zip";
FileDownloader *downloader = new FileDownloader(this);
downloader->setUrl(zipFileUrl);
@@ -543,13 +588,7 @@ bool ContentLibraryWidget::fetchTextureBundleIcons(const QDir &bundleDir)
[this, downloader, extractor] {
downloader->deleteLater();
extractor->deleteLater();
-
- QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
- QVariantMap metaData = readBundleMetadata();
- m_texturesModel->loadTextureBundle(m_texturesUrl, m_textureIconsUrl, bundleIconPath,
- metaData);
- m_environmentsModel->loadTextureBundle(m_environmentsUrl, m_environmentIconsUrl,
- bundleIconPath, metaData);
+ populateTextureBundleModels();
});
extractor->extract();
@@ -572,7 +611,7 @@ void ContentLibraryWidget::markTextureUpdated(const QString &textureKey)
checksumOnServer = m_environmentsModel->removeModifiedFileEntry(textureKey);
QJsonObject metaDataObj;
- QFile jsonFile(m_downloadPath + "/texture_bundle.json");
+ QFile jsonFile(m_bundlePath + "/texture_bundle.json");
if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
metaDataObj = QJsonDocument::fromJson(jsonFile.readAll()).object();
jsonFile.close();
@@ -589,7 +628,7 @@ void ContentLibraryWidget::markTextureUpdated(const QString &textureKey)
QJsonDocument outDoc(metaDataObj);
QByteArray data = outDoc.toJson();
- QFile outFile(m_downloadPath + "/texture_bundle.json");
+ QFile outFile(m_bundlePath + "/texture_bundle.json");
if (outFile.open(QIODeviceBase::WriteOnly | QIODeviceBase::Text)) {
outFile.write(data);
outFile.flush();
@@ -700,6 +739,20 @@ void ContentLibraryWidget::setIsQt6Project(bool b)
emit isQt6ProjectChanged();
}
+bool ContentLibraryWidget::importerRunning() const
+{
+ return m_importerRunning;
+}
+
+void ContentLibraryWidget::setImporterRunning(bool b)
+{
+ if (m_importerRunning == b)
+ return;
+
+ m_importerRunning = b;
+ emit importerRunningChanged();
+}
+
void ContentLibraryWidget::reloadQmlSource()
{
const QString materialBrowserQmlPath = qmlSourcesPath() + "/ContentLibrary.qml";
@@ -715,6 +768,7 @@ void ContentLibraryWidget::updateSearch()
m_effectsModel->setSearchText(m_filterText);
m_texturesModel->setSearchText(m_filterText);
m_environmentsModel->setSearchText(m_filterText);
+ m_userModel->setSearchText(m_filterText);
m_quickWidget->update();
}
@@ -726,32 +780,9 @@ void ContentLibraryWidget::setIsDragging(bool val)
}
}
-QString ContentLibraryWidget::findTextureBundlePath()
-{
- QDir texBundleDir;
-
- if (!qEnvironmentVariable("TEXTURE_BUNDLE_PATH").isEmpty())
- texBundleDir.setPath(qEnvironmentVariable("TEXTURE_BUNDLE_PATH"));
- else if (Utils::HostOsInfo::isMacHost())
- texBundleDir.setPath(QCoreApplication::applicationDirPath() + "/../Resources/texture_bundle");
-
- // search for matBundleDir from exec dir and up
- if (texBundleDir.dirName() == ".") {
- texBundleDir.setPath(QCoreApplication::applicationDirPath());
- while (!texBundleDir.cd("texture_bundle") && texBundleDir.cdUp())
- ; // do nothing
-
- if (texBundleDir.dirName() != "texture_bundle") // bundlePathDir not found
- return {};
- }
-
- return texBundleDir.path();
-}
-
-void ContentLibraryWidget::startDragEffect(QmlDesigner::ContentLibraryEffect *eff,
- const QPointF &mousePos)
+void ContentLibraryWidget::startDragItem(QmlDesigner::ContentLibraryItem *item, const QPointF &mousePos)
{
- m_effectToDrag = eff;
+ m_itemToDrag = item;
m_dragStartPoint = mousePos.toPoint();
setIsDragging(true);
}
@@ -777,7 +808,7 @@ void ContentLibraryWidget::addImage(ContentLibraryTexture *tex)
if (!tex->isDownloaded())
return;
- emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Image);
+ emit addTextureRequested(tex->texturePath(), AddTextureMode::Image);
}
void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex)
@@ -785,7 +816,7 @@ void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex)
if (!tex->isDownloaded())
return;
- emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Texture);
+ emit addTextureRequested(tex->texturePath(), AddTextureMode::Texture);
}
void ContentLibraryWidget::addLightProbe(ContentLibraryTexture *tex)
@@ -793,7 +824,7 @@ void ContentLibraryWidget::addLightProbe(ContentLibraryTexture *tex)
if (!tex->isDownloaded())
return;
- emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::LightProbe);
+ emit addTextureRequested(tex->texturePath(), AddTextureMode::LightProbe);
}
void ContentLibraryWidget::updateSceneEnvState()
@@ -821,4 +852,23 @@ QPointer<ContentLibraryEffectsModel> ContentLibraryWidget::effectsModel() const
return m_effectsModel;
}
+QPointer<ContentLibraryUserModel> ContentLibraryWidget::userModel() const
+{
+ return m_userModel;
+}
+
+bool ContentLibraryWidget::hasModelSelection() const
+{
+ return m_hasModelSelection;
+}
+
+void ContentLibraryWidget::setHasModelSelection(bool b)
+{
+ if (b == m_hasModelSelection)
+ return;
+
+ m_hasModelSelection = b;
+ emit hasModelSelectionChanged();
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
index ab71a3dc79..8e96d9d2f3 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
@@ -5,6 +5,10 @@
#include "createtexture.h"
+#include <modelfwd.h>
+
+#include <utils/uniqueobjectptr.h>
+
#include <QFrame>
#include <QPointer>
@@ -18,12 +22,15 @@ class StudioQuickWidget;
namespace QmlDesigner {
-class ContentLibraryEffect;
+class ContentLibraryBundleImporter;
class ContentLibraryEffectsModel;
+class ContentLibraryItem;
class ContentLibraryMaterial;
class ContentLibraryMaterialsModel;
class ContentLibraryTexture;
class ContentLibraryTexturesModel;
+class ContentLibraryUserModel;
+class NodeMetaInfo;
class ContentLibraryWidget : public QFrame
{
@@ -33,6 +40,8 @@ class ContentLibraryWidget : public QFrame
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
Q_PROPERTY(bool hasActive3DScene READ hasActive3DScene WRITE setHasActive3DScene NOTIFY hasActive3DSceneChanged)
Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged)
+ Q_PROPERTY(bool importerRunning READ importerRunning WRITE setImporterRunning NOTIFY importerRunningChanged)
+ Q_PROPERTY(bool hasModelSelection READ hasModelSelection NOTIFY hasModelSelectionChanged)
// Needed for a workaround for a bug where after drag-n-dropping an item, the ScrollView scrolls to a random position
Q_PROPERTY(bool isDragging MEMBER m_isDragging NOTIFY isDraggingChanged)
@@ -57,16 +66,23 @@ public:
bool isQt6Project() const;
void setIsQt6Project(bool b);
- Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
+ bool importerRunning() const;
+ void setImporterRunning(bool b);
+
+ bool hasModelSelection() const;
+ void setHasModelSelection(bool b);
void setMaterialsModel(QPointer<ContentLibraryMaterialsModel> newMaterialsModel);
+ void updateImportedState(const QString &bundleId);
QPointer<ContentLibraryMaterialsModel> materialsModel() const;
QPointer<ContentLibraryTexturesModel> texturesModel() const;
QPointer<ContentLibraryTexturesModel> environmentsModel() const;
QPointer<ContentLibraryEffectsModel> effectsModel() const;
+ QPointer<ContentLibraryUserModel> userModel() const;
- Q_INVOKABLE void startDragEffect(QmlDesigner::ContentLibraryEffect *eff, const QPointF &mousePos);
+ Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
+ Q_INVOKABLE void startDragItem(QmlDesigner::ContentLibraryItem *item, const QPointF &mousePos);
Q_INVOKABLE void startDragMaterial(QmlDesigner::ContentLibraryMaterial *mat, const QPointF &mousePos);
Q_INVOKABLE void startDragTexture(QmlDesigner::ContentLibraryTexture *tex, const QPointF &mousePos);
Q_INVOKABLE void addImage(QmlDesigner::ContentLibraryTexture *tex);
@@ -77,8 +93,10 @@ public:
QSize sizeHint() const override;
+ ContentLibraryBundleImporter *importer() const;
+
signals:
- void bundleEffectDragStarted(QmlDesigner::ContentLibraryEffect *bundleEff);
+ void bundleItemDragStarted(QmlDesigner::ContentLibraryItem *item);
void bundleMaterialDragStarted(QmlDesigner::ContentLibraryMaterial *bundleMat);
void bundleTextureDragStarted(QmlDesigner::ContentLibraryTexture *bundleTex);
void addTextureRequested(const QString texPath, QmlDesigner::AddTextureMode mode);
@@ -88,6 +106,8 @@ signals:
void hasActive3DSceneChanged();
void isDraggingChanged();
void isQt6ProjectChanged();
+ void importerRunningChanged();
+ void hasModelSelectionChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -96,28 +116,31 @@ private:
void reloadQmlSource();
void updateSearch();
void setIsDragging(bool val);
- QString findTextureBundlePath();
- void loadTextureBundle();
- QVariantMap readBundleMetadata();
- bool fetchTextureBundleMetadata(const QDir &bundleDir);
+ void loadTextureBundles();
+ QVariantMap readTextureBundleJson();
+ bool fetchTextureBundleJson(const QDir &bundleDir);
bool fetchTextureBundleIcons(const QDir &bundleDir);
void fetchNewTextureIcons(const QVariantMap &existingFiles, const QVariantMap &newFiles,
const QString &existingMetaFilePath, const QDir &bundleDir);
std::tuple<QVariantMap, QVariantMap, QVariantMap> compareTextureMetaFiles(
const QString &existingMetaFile, const QString downloadedMetaFile);
QStringList saveNewTextures(const QDir &bundleDir, const QStringList &newFiles);
+ void populateTextureBundleModels();
+ void createImporter();
- QScopedPointer<StudioQuickWidget> m_quickWidget;
+ Utils::UniqueObjectPtr<StudioQuickWidget> m_quickWidget;
QPointer<ContentLibraryMaterialsModel> m_materialsModel;
QPointer<ContentLibraryTexturesModel> m_texturesModel;
QPointer<ContentLibraryTexturesModel> m_environmentsModel;
QPointer<ContentLibraryEffectsModel> m_effectsModel;
+ QPointer<ContentLibraryUserModel> m_userModel;
+ ContentLibraryBundleImporter *m_importer = nullptr;
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
QString m_filterText;
- ContentLibraryEffect *m_effectToDrag = nullptr;
+ ContentLibraryItem *m_itemToDrag = nullptr;
ContentLibraryMaterial *m_materialToDrag = nullptr;
ContentLibraryTexture *m_textureToDrag = nullptr;
QPoint m_dragStartPoint;
@@ -127,12 +150,10 @@ private:
bool m_hasQuick3DImport = false;
bool m_isDragging = false;
bool m_isQt6Project = false;
- QString m_baseUrl;
- QString m_texturesUrl;
- QString m_textureIconsUrl;
- QString m_environmentIconsUrl;
- QString m_environmentsUrl;
- QString m_downloadPath;
+ bool m_importerRunning = false;
+ bool m_hasModelSelection = false;
+ QString m_textureBundleUrl;
+ QString m_bundlePath;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/createtexture.cpp b/src/plugins/qmldesigner/components/createtexture.cpp
index b6e99ae972..56056e3fd2 100644
--- a/src/plugins/qmldesigner/components/createtexture.cpp
+++ b/src/plugins/qmldesigner/components/createtexture.cpp
@@ -17,6 +17,7 @@
#include <coreplugin/messagebox.h>
#include <QTimer>
+#include <QUrl>
namespace QmlDesigner {
@@ -94,7 +95,7 @@ ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPat
newTexNode.setIdWithoutRefactoring(m_view->model()->generateNewId(assetPath.baseName()));
VariantProperty sourceProp = newTexNode.variantProperty("source");
- sourceProp.setValue(textureSource);
+ sourceProp.setValue(QUrl(textureSource));
matLib.defaultNodeListProperty().reparentHere(newTexNode);
}
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
index e84623e26c..36ce3373e5 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
@@ -77,8 +77,8 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
connect(m_toolbar, &CurveEditorToolBar::currentFrameChanged, [this, model](int frame) {
model->setCurrentFrame(frame);
+ m_view->setCurrentFrame(frame, false);
updateStatusLine();
- m_view->viewport()->update();
});
connect(m_toolbar, &CurveEditorToolBar::zoomChanged, [this](double zoom) {
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
index 72410ffb07..8da87ce119 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
@@ -129,6 +129,8 @@ CurveEditorToolBar::CurveEditorToolBar(CurveEditorModel *model, QWidget* parent)
m_currentSpin->setFrame(false);
connect(m_currentSpin, &QSpinBox::valueChanged, this, &CurveEditorToolBar::currentFrameChanged);
+ connect(model, &CurveEditorModel::commitCurrentFrame,
+ this, [this](int frame) { m_currentSpin->setValue(frame); });
addSpacer();
diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp
index a1c229f57e..159e7c31ee 100644
--- a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp
@@ -422,7 +422,7 @@ QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons
rseg.moveLeftTo(position);
if (legalLeft() && legalRight()) {
- if (qApp->keyboardModifiers().testFlag(Qt::ShiftModifier) && m_validPos.has_value()) {
+ if (qApp->keyboardModifiers().testFlag(Qt::ShiftModifier) && m_validPos) {
if (m_firstPos) {
auto firstToNow = QLineF(*m_firstPos, position);
if (std::abs(firstToNow.dx()) > std::abs(firstToNow.dy()))
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp
index 95a260c26f..a1dfcc8f98 100644
--- a/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp
@@ -15,6 +15,8 @@
#include "qmlobjectnode.h"
#include "variantproperty.h"
+#include <model/modelutils.h>
+
#include <utils3d.h>
#include <utils/expected.h>
@@ -292,7 +294,7 @@ bool BakeLightsDataModel::reset()
if (!hasExposedProps && node.metaInfo().isFileComponent()
&& node.metaInfo().isQtQuick3DNode()) {
- const QString compFile = node.metaInfo().componentFileName();
+ const QString compFile = ModelUtils::componentFilePath(node);
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
diff --git a/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.cpp b/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.cpp
index 76560ac192..f5a74ee864 100644
--- a/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.cpp
@@ -66,9 +66,11 @@ void CameraSpeedConfiguration::resetDefaults()
void CameraSpeedConfiguration::hideCursor()
{
- if (QGuiApplication::overrideCursor())
+ if (m_cursorHidden)
return;
+ m_cursorHidden = true;
+
QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
if (QWindow *w = QGuiApplication::focusWindow())
@@ -77,9 +79,11 @@ void CameraSpeedConfiguration::hideCursor()
void CameraSpeedConfiguration::restoreCursor()
{
- if (!QGuiApplication::overrideCursor())
+ if (!m_cursorHidden)
return;
+ m_cursorHidden = false;
+
QGuiApplication::restoreOverrideCursor();
if (QWindow *w = QGuiApplication::focusWindow())
@@ -88,7 +92,7 @@ void CameraSpeedConfiguration::restoreCursor()
void CameraSpeedConfiguration::holdCursorInPlace()
{
- if (!QGuiApplication::overrideCursor())
+ if (!m_cursorHidden)
return;
if (QWindow *w = QGuiApplication::focusWindow())
diff --git a/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.h b/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.h
index 55256890cb..fef06efc49 100644
--- a/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.h
+++ b/src/plugins/qmldesigner/components/edit3d/cameraspeedconfiguration.h
@@ -71,6 +71,7 @@ private:
double m_multiplier = 0.;
bool m_changes = false;
QPoint m_lastPos;
+ bool m_cursorHidden = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
index 2e8ef8304f..63d5e958b1 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
@@ -51,6 +51,8 @@ Edit3DCanvas::Edit3DCanvas(Edit3DWidget *parent)
setAcceptDrops(true);
setFocusPolicy(Qt::ClickFocus);
m_busyIndicator->show();
+
+ installEventFilter(this);
}
void Edit3DCanvas::updateRenderImage(const QImage &img)
@@ -79,11 +81,20 @@ QWidget *Edit3DCanvas::busyIndicator() const
return m_busyIndicator;
}
+#ifdef Q_OS_MACOS
+extern "C" bool AXIsProcessTrusted();
+#endif
+
void Edit3DCanvas::setFlyMode(bool enabled, const QPoint &pos)
{
if (m_flyMode == enabled)
return;
+#ifdef Q_OS_MACOS
+ if (!AXIsProcessTrusted())
+ m_isTrusted = false;
+#endif
+
m_flyMode = enabled;
if (enabled) {
@@ -132,6 +143,23 @@ void Edit3DCanvas::setFlyMode(bool enabled, const QPoint &pos)
m_parent->view()->setFlyMode(enabled);
}
+bool Edit3DCanvas::eventFilter(QObject *obj, QEvent *event)
+{
+ if (m_flyMode && event->type() == QEvent::ShortcutOverride) {
+ // Suppress shortcuts that conflict with fly mode keys
+ const QList<int> controlKeys = { Qt::Key_W, Qt::Key_A, Qt::Key_S,
+ Qt::Key_D, Qt::Key_Q, Qt::Key_E,
+ Qt::Key_Up, Qt::Key_Down, Qt::Key_Left,
+ Qt::Key_Right, Qt::Key_PageDown, Qt::Key_PageUp,
+ Qt::Key_Alt, Qt::Key_Shift };
+ auto ke = static_cast<QKeyEvent *>(event);
+ if (controlKeys.contains(ke->key()))
+ event->accept();
+ }
+
+ return QObject::eventFilter(obj, event);
+}
+
void Edit3DCanvas::mousePressEvent(QMouseEvent *e)
{
m_contextMenuPending = false;
@@ -171,7 +199,8 @@ void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e)
// We notify explicit camera rotation need for puppet rather than rely in mouse events,
// as mouse isn't grabbed on puppet side and can't handle fast movements that go out of
// edit camera mouse area. This also simplifies split view handling.
- QPointF diff = m_hiddenCursorPos - e->globalPos();
+ QPointF diff = m_isTrusted ? (m_hiddenCursorPos - e->globalPos()) : (m_lastCursorPos - e->globalPos());
+
if (e->buttons() == (Qt::LeftButton | Qt::RightButton)) {
m_parent->view()->emitView3DAction(View3DActionType::EditCameraMove,
QVector3D{float(-diff.x()), float(-diff.y()), 0.f});
@@ -182,13 +211,26 @@ void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e)
// Skip first move to avoid undesirable jump occasionally when initiating flight mode
m_flyModeFirstUpdate = false;
}
- QCursor::setPos(m_hiddenCursorPos);
+
+ if (m_isTrusted)
+ QCursor::setPos(m_hiddenCursorPos);
+ else
+ m_lastCursorPos = e->globalPos();
}
}
void Edit3DCanvas::wheelEvent(QWheelEvent *e)
{
- m_parent->view()->sendInputEvent(e);
+ if (m_flyMode) {
+ // In fly mode, wheel controls the camera speed slider (value range 1-100)
+ double speed;
+ double mult;
+ m_parent->view()->getCameraSpeedAuxData(speed, mult);
+ speed = qMin(100., qMax(1., speed + double(e->angleDelta().y()) / 40.));
+ m_parent->view()->setCameraSpeedAuxData(speed, mult);
+ } else {
+ m_parent->view()->sendInputEvent(e);
+ }
QWidget::wheelEvent(e);
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h
index 39207554a7..16c1063dd6 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h
@@ -30,6 +30,7 @@ public:
bool isFlyMode() const { return m_flyMode; }
protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseDoubleClickEvent(QMouseEvent *e) override;
@@ -52,10 +53,12 @@ private:
qint32 m_activeScene = -1;
QElapsedTimer m_usageTimer;
qreal m_opacity = 1.0;
+ bool m_isTrusted = true;
QWidget *m_busyIndicator = nullptr;
bool m_flyMode = false;
QPoint m_flyModeStartCursorPos;
QPoint m_hiddenCursorPos;
+ QPoint m_lastCursorPos;
qint64 m_flyModeStartTime = 0;
bool m_flyModeFirstUpdate = false;
bool m_contextMenuPending = false;
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index 911ee1fb15..bb7404f252 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
@@ -20,9 +20,11 @@
#include "nodeinstanceview.h"
#include "qmldesignerconstants.h"
#include "qmldesignerplugin.h"
+#include "qmlitemnode.h"
#include "qmlvisualnode.h"
#include "seekerslider.h"
#include "snapconfiguration.h"
+#include "variantproperty.h"
#include <auxiliarydataproperties.h>
#include <model/modelutils.h>
@@ -133,6 +135,7 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
const QString orientationKey = QStringLiteral("globalOrientation");
const QString editLightKey = QStringLiteral("showEditLight");
const QString gridKey = QStringLiteral("showGrid");
+ const QString showLookAtKey = QStringLiteral("showLookAt");
const QString selectionBoxKey = QStringLiteral("showSelectionBox");
const QString iconGizmoKey = QStringLiteral("showIconGizmo");
const QString cameraFrustumKey = QStringLiteral("showCameraFrustum");
@@ -187,6 +190,11 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
else
m_showGridAction->action()->setChecked(false);
+ if (sceneState.contains(showLookAtKey))
+ m_showLookAtAction->action()->setChecked(sceneState[showLookAtKey].toBool());
+ else
+ m_showLookAtAction->action()->setChecked(false);
+
if (sceneState.contains(selectionBoxKey))
m_showSelectionBoxAction->action()->setChecked(sceneState[selectionBoxKey].toBool());
else
@@ -235,36 +243,10 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
state.showWireframe = false;
}
- // Syncing background color only makes sense for children of View3D instances
- bool syncValue = false;
- bool syncEnabled = false;
- bool desiredSyncValue = false;
if (sceneState.contains(syncEnvBgKey))
- desiredSyncValue = sceneState[syncEnvBgKey].toBool();
- ModelNode checkNode = Utils3D::active3DSceneNode(this);
- const bool activeSceneValid = checkNode.isValid();
-
- while (checkNode.isValid()) {
- if (checkNode.metaInfo().isQtQuick3DView3D()) {
- syncValue = desiredSyncValue;
- syncEnabled = true;
- break;
- }
- if (checkNode.hasParentProperty())
- checkNode = checkNode.parentProperty().parentModelNode();
- else
- break;
- }
-
- if (activeSceneValid && syncValue != desiredSyncValue) {
- // Update actual toolstate as well if we overrode it.
- QTimer::singleShot(0, this, [this, syncValue]() {
- emitView3DAction(View3DActionType::SyncEnvBackground, syncValue);
- });
- }
-
- m_syncEnvBackgroundAction->action()->setChecked(syncValue);
- m_syncEnvBackgroundAction->action()->setEnabled(syncEnabled);
+ m_syncEnvBackgroundAction->action()->setChecked(sceneState[syncEnvBgKey].toBool());
+ else
+ m_syncEnvBackgroundAction->action()->setChecked(false);
// Selection context change updates visible and enabled states
SelectionContext selectionContext(this);
@@ -273,12 +255,22 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
m_bakeLightsAction->currentContextChanged(selectionContext);
syncCameraSpeedToNewView();
+
+ storeCurrentSceneEnvironment();
}
void Edit3DView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
+ QString currProjectPath = QmlDesigner::DocumentManager::currentProjectDirPath().toString();
+ if (m_currProjectPath != currProjectPath) {
+ // Opening a new project -> reset camera speeds
+ m_currProjectPath = currProjectPath;
+ m_previousCameraSpeed = -1.;
+ m_previousCameraMultiplier = -1.;
+ }
+
syncSnapAuxPropsToSettings();
rootModelNode().setAuxiliaryData(edit3dGridColorProperty,
@@ -342,11 +334,10 @@ void Edit3DView::handleEntriesChanged()
{EK_importedModels, {tr("Imported Models"), contextIcon(DesignerIcons::ImportedModelsIcon)}}};
#ifdef QDS_USE_PROJECTSTORAGE
- const auto &projectStorage = *model()->projectStorage();
auto append = [&](const NodeMetaInfo &metaInfo, ItemLibraryEntryKeys key) {
auto entries = metaInfo.itemLibrariesEntries();
if (entries.size())
- entriesMap[key].entryList.append(toItemLibraryEntries(entries, projectStorage));
+ entriesMap[key].entryList.append(toItemLibraryEntries(entries));
};
append(model()->qtQuick3DModelMetaInfo(), EK_primitives);
@@ -356,7 +347,12 @@ void Edit3DView::handleEntriesChanged()
append(model()->qtQuick3DOrthographicCameraMetaInfo(), EK_cameras);
append(model()->qtQuick3DPerspectiveCameraMetaInfo(), EK_cameras);
- auto assetsModule = model()->module("Quick3DAssets");
+ Utils::PathString import3dTypePrefix = QmlDesignerPlugin::instance()
+ ->documentManager()
+ .generatedComponentUtils()
+ .import3dTypePrefix();
+
+ auto assetsModule = model()->module(import3dTypePrefix, Storage::ModuleKind::QmlLibrary);
for (const auto &metaInfo : model()->metaInfosForModule(assetsModule))
append(metaInfo, EK_importedModels);
@@ -373,8 +369,12 @@ void Edit3DView::handleEntriesChanged()
} else if (entry.typeName() == "QtQuick3D.OrthographicCamera"
|| entry.typeName() == "QtQuick3D.PerspectiveCamera") {
entryKey = EK_cameras;
- } else if (entry.typeName().startsWith("Quick3DAssets.")
- && NodeHints::fromItemLibraryEntry(entry).canBeDroppedInView3D()) {
+ } else if (entry.typeName().startsWith(QmlDesignerPlugin::instance()
+ ->documentManager()
+ .generatedComponentUtils()
+ .import3dTypePrefix()
+ .toUtf8())
+ && NodeHints::fromItemLibraryEntry(entry, model()).canBeDroppedInView3D()) {
entryKey = EK_importedModels;
} else {
continue;
@@ -448,6 +448,7 @@ void Edit3DView::customNotification([[maybe_unused]] const AbstractView *view,
self->emitView3DAction(View3DActionType::GetNodeAtMainScenePos,
QVariantList{data[0], nodeList[0].internalId()});
self->m_nodeAtPosReqType = NodeAtPosReqType::MainScenePick;
+ self->m_pickView3dNode = nodeList[0];
});
}
}
@@ -490,7 +491,7 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) {
emitCustomNotification("drop_bundle_material", {modelNode}); // To ContentLibraryView
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleEffectDrop) {
- emitCustomNotification("drop_bundle_effect", {modelNode}, {pos3d}); // To ContentLibraryView
+ emitCustomNotification("drop_bundle_item", {modelNode}, {pos3d}); // To ContentLibraryView
} else if (m_nodeAtPosReqType == NodeAtPosReqType::TextureDrop) {
emitCustomNotification("apply_texture_to_model3D", {modelNode, m_droppedModelNode});
} else if (m_nodeAtPosReqType == NodeAtPosReqType::AssetDrop) {
@@ -500,6 +501,8 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
} else if (m_nodeAtPosReqType == NodeAtPosReqType::MainScenePick) {
if (modelNode.isValid())
setSelectedModelNode(modelNode);
+ else if (m_pickView3dNode.isValid() && !m_pickView3dNode.isSelected())
+ setSelectedModelNode(m_pickView3dNode);
emitView3DAction(View3DActionType::AlignViewToCamera, true);
}
@@ -523,6 +526,21 @@ void Edit3DView::nodeRemoved(const ModelNode &,
updateAlignActionStates();
}
+void Edit3DView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
+{
+ maybeStoreCurrentSceneEnvironment(propertyList);
+}
+
+void Edit3DView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags)
+{
+ maybeStoreCurrentSceneEnvironment(propertyList);
+}
+
+void Edit3DView::variantPropertiesChanged(const QList<VariantProperty> &propertyList, PropertyChangeFlags)
+{
+ maybeStoreCurrentSceneEnvironment(propertyList);
+}
+
void Edit3DView::sendInputEvent(QEvent *e) const
{
if (nodeInstanceView())
@@ -699,6 +717,30 @@ QPoint Edit3DView::resolveToolbarPopupPos(Edit3DAction *action) const
return pos;
}
+template<typename T, typename>
+void Edit3DView::maybeStoreCurrentSceneEnvironment(const QList<T> &propertyList)
+{
+ QSet<qint32> handledNodes;
+ QmlObjectNode sceneEnv;
+ for (const AbstractProperty &prop : propertyList) {
+ ModelNode node = prop.parentModelNode();
+ const qint32 id = node.internalId();
+ if (handledNodes.contains(id))
+ continue;
+
+ handledNodes.insert(id);
+ if (!node.metaInfo().isQtQuick3DSceneEnvironment())
+ continue;
+
+ if (!sceneEnv.isValid())
+ sceneEnv = currentSceneEnv();
+ if (sceneEnv == node) {
+ storeCurrentSceneEnvironment();
+ break;
+ }
+ }
+}
+
void Edit3DView::showContextMenu()
{
// If request for context menu is still pending, skip for now
@@ -719,32 +761,6 @@ void Edit3DView::showContextMenu()
void Edit3DView::setFlyMode(bool enabled)
{
emitView3DAction(View3DActionType::FlyModeToggle, enabled);
-
- // Disable any actions with conflicting hotkeys
- if (enabled) {
- m_flyModeDisabledActions.clear();
- const QList<QKeySequence> controlKeys = { Qt::Key_W, Qt::Key_A, Qt::Key_S,
- Qt::Key_D, Qt::Key_Q, Qt::Key_E,
- Qt::Key_Up, Qt::Key_Down, Qt::Key_Left,
- Qt::Key_Right, Qt::Key_PageDown, Qt::Key_PageUp};
- for (auto i = m_edit3DActions.cbegin(), end = m_edit3DActions.cend(); i != end; ++i) {
- for (const QKeySequence &controlKey : controlKeys) {
- if (Core::Command *cmd = m_edit3DWidget->actionToCommandHash().value(i.value()->action())) {
- if (cmd->keySequence().matches(controlKey) == QKeySequence::ExactMatch) {
- if (i.value()->action()->isEnabled()) {
- m_flyModeDisabledActions.append(i.value());
- i.value()->action()->setEnabled(false);
- }
- break;
- }
- }
- }
- }
- } else {
- for (Edit3DAction *action : std::as_const(m_flyModeDisabledActions))
- action->action()->setEnabled(true);
- m_flyModeDisabledActions.clear();
- }
}
void Edit3DView::syncSnapAuxPropsToSettings()
@@ -814,6 +830,75 @@ void Edit3DView::syncCameraSpeedToNewView()
setCameraSpeedAuxData(speed, multiplier);
}
+QmlObjectNode Edit3DView::currentSceneEnv()
+{
+ PropertyName envProp{"environment"};
+ ModelNode checkNode = Utils3D::active3DSceneNode(this);
+ while (checkNode.isValid()) {
+ if (checkNode.metaInfo().isQtQuick3DView3D()) {
+ QmlObjectNode sceneEnvNode = QmlItemNode(checkNode).bindingProperty(envProp)
+ .resolveToModelNode();
+ if (sceneEnvNode.isValid())
+ return sceneEnvNode;
+ break;
+ }
+ if (checkNode.hasParentProperty())
+ checkNode = checkNode.parentProperty().parentModelNode();
+ else
+ break;
+ }
+ return {};
+}
+
+void Edit3DView::storeCurrentSceneEnvironment()
+{
+ // If current active scene has scene environment, store relevant properties
+ QmlObjectNode sceneEnvNode = currentSceneEnv();
+ if (sceneEnvNode.isValid()) {
+ QVariantMap lastSceneEnvData;
+
+ auto insertPropValue = [](const PropertyName prop, const QmlObjectNode &node,
+ QVariantMap &map) {
+ if (!node.hasProperty(prop))
+ return;
+
+ map.insert(QString::fromUtf8(prop), node.modelValue(prop));
+ };
+
+ auto insertTextureProps = [&](const PropertyName prop) {
+ // For now we just grab the absolute path of texture source for simplicity
+ if (!sceneEnvNode.hasProperty(prop))
+ return;
+
+ QmlObjectNode bindNode = QmlItemNode(sceneEnvNode).bindingProperty(prop)
+ .resolveToModelNode();
+ if (bindNode.isValid()) {
+ QVariantMap props;
+ const PropertyName sourceProp = "source";
+ if (bindNode.hasProperty(sourceProp)) {
+ Utils::FilePath qmlPath = Utils::FilePath::fromUrl(
+ model()->fileUrl()).absolutePath();
+ Utils::FilePath sourcePath = Utils::FilePath::fromUrl(
+ bindNode.modelValue(sourceProp).toUrl());
+
+ sourcePath = qmlPath.resolvePath(sourcePath);
+
+ props.insert(QString::fromUtf8(sourceProp),
+ sourcePath.absoluteFilePath().toUrl());
+ }
+ lastSceneEnvData.insert(QString::fromUtf8(prop), props);
+ }
+ };
+
+ insertPropValue("backgroundMode", sceneEnvNode, lastSceneEnvData);
+ insertPropValue("clearColor", sceneEnvNode, lastSceneEnvData);
+ insertTextureProps("lightProbe");
+ insertTextureProps("skyBoxCubeMap");
+
+ emitView3DAction(View3DActionType::SetLastSceneEnvData, lastSceneEnvData);
+ }
+}
+
const QList<Edit3DView::SplitToolState> &Edit3DView::splitToolStates() const
{
return m_splitToolStates;
@@ -961,6 +1046,18 @@ void Edit3DView::createEdit3DActions()
nullptr,
QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid."));
+ m_showLookAtAction = std::make_unique<Edit3DAction>(
+ QmlDesigner::Constants::EDIT3D_EDIT_SHOW_LOOKAT,
+ View3DActionType::ShowLookAt,
+ QCoreApplication::translate("ShowLookAtAction", "Show Look-at"),
+ QKeySequence(Qt::Key_L),
+ true,
+ true,
+ QIcon(),
+ this,
+ nullptr,
+ QCoreApplication::translate("ShowLookAtAction", "Toggle the visibility of the edit camera look-at indicator."));
+
m_showSelectionBoxAction = std::make_unique<Edit3DAction>(
QmlDesigner::Constants::EDIT3D_EDIT_SHOW_SELECTION_BOX,
View3DActionType::ShowSelectionBox,
@@ -1264,6 +1361,7 @@ void Edit3DView::createEdit3DActions()
m_rightActions << m_resetAction.get();
m_visibilityToggleActions << m_showGridAction.get();
+ m_visibilityToggleActions << m_showLookAtAction.get();
m_visibilityToggleActions << m_showSelectionBoxAction.get();
m_visibilityToggleActions << m_showIconGizmoAction.get();
m_visibilityToggleActions << m_showCameraFrustumAction.get();
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
index 781b26d8d8..755efc0ae3 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
@@ -8,6 +8,7 @@
#include <abstractview.h>
#include <modelcache.h>
+#include <qmlobjectnode.h>
#include <QImage>
#include <QPointer>
@@ -59,6 +60,11 @@ public:
PropertyChangeFlags propertyChange) override;
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange) override;
+ void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
+ void bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
+ PropertyChangeFlags propertyChange) override;
+ void variantPropertiesChanged(const QList<VariantProperty> &propertyList,
+ PropertyChangeFlags propertyChange) override;
void sendInputEvent(QEvent *e) const;
void edit3DViewResized(const QSize &size) const;
@@ -127,9 +133,14 @@ private:
void createSyncEnvBackgroundAction();
void createSeekerSliderAction();
void syncCameraSpeedToNewView();
+ QmlObjectNode currentSceneEnv();
+ void storeCurrentSceneEnvironment();
QPoint resolveToolbarPopupPos(Edit3DAction *action) const;
+ template<typename T, typename = typename std::enable_if<std::is_base_of<AbstractProperty , T>::value>::type>
+ void maybeStoreCurrentSceneEnvironment(const QList<T> &propertyList);
+
QPointer<Edit3DWidget> m_edit3DWidget;
QVector<Edit3DAction *> m_leftActions;
QVector<Edit3DAction *> m_rightActions;
@@ -148,6 +159,7 @@ private:
std::unique_ptr<Edit3DAction> m_orientationModeAction;
std::unique_ptr<Edit3DAction> m_editLightAction;
std::unique_ptr<Edit3DAction> m_showGridAction;
+ std::unique_ptr<Edit3DAction> m_showLookAtAction;
std::unique_ptr<Edit3DAction> m_showSelectionBoxAction;
std::unique_ptr<Edit3DAction> m_showIconGizmoAction;
std::unique_ptr<Edit3DAction> m_showCameraFrustumAction;
@@ -187,11 +199,12 @@ private:
int m_activeSplit = 0;
QList<SplitToolState> m_splitToolStates;
- QList<Edit3DAction *> m_flyModeDisabledActions;
ModelNode m_contextMenuPendingNode;
+ ModelNode m_pickView3dNode;
double m_previousCameraSpeed = -1.;
double m_previousCameraMultiplier = -1.;
+ QString m_currProjectPath;
friend class Edit3DAction;
};
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index 07102ae893..f6bbf8d794 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -2,37 +2,41 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "edit3dwidget.h"
-#include "designdocument.h"
-#include "designericons.h"
+
#include "edit3dactions.h"
#include "edit3dcanvas.h"
#include "edit3dtoolbarmenu.h"
#include "edit3dview.h"
-#include "externaldependenciesinterface.h"
-#include "materialutils.h"
-#include "metainfo.h"
-#include "modelnodeoperations.h"
-#include "nodeabstractproperty.h"
-#include "nodehints.h"
-#include "qmldesignerconstants.h"
-#include "qmldesignerplugin.h"
-#include "qmleditormenu.h"
-#include "qmlvisualnode.h"
-#include "viewmanager.h"
-#include <utils3d.h>
#include <auxiliarydataproperties.h>
#include <designeractionmanager.h>
+#include <designdocument.h>
+#include <designericons.h>
#include <designermcumanager.h>
+#include <externaldependenciesinterface.h>
+#include <generatedcomponentutils.h>
#include <import.h>
-#include <model/modelutils.h>
+#include <materialutils.h>
+#include <metainfo.h>
+#include <modelnodeoperations.h>
+#include <nodeabstractproperty.h>
+#include <nodehints.h>
#include <nodeinstanceview.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+#include <qmleditormenu.h>
+#include <qmlvisualnode.h>
#include <seekerslider.h>
+#include <toolbox.h>
+#include <viewmanager.h>
+#include <utils3d.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/icore.h>
-#include <toolbox.h>
+
+#include <model/modelutils.h>
+
#include <utils/asset.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -359,6 +363,14 @@ void Edit3DWidget::createContextMenu()
resetAction->setToolTip(tr("Reset all shading options for all viewports."));
m_contextMenu->addSeparator();
+
+ m_addToContentLibAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::CreateIcon), // TODO: placeholder icon
+ tr("Add to Content Library"), [&] {
+ view()->emitCustomNotification("add_3d_to_content_lib", {m_contextMenuTarget});
+ });
+
+ m_contextMenu->addSeparator();
}
bool Edit3DWidget::isPasteAvailable() const
@@ -402,7 +414,7 @@ void Edit3DWidget::showOnboardingLabel()
" in the"
" <b>Assets</b>"
" view.");
- text = labelText.arg(Utils::creatorTheme()->color(Utils::Theme::TextColorLink).name());
+ text = labelText.arg(Utils::creatorColor(Utils::Theme::TextColorLink).name());
} else {
text = tr("3D view is not supported in Qt5 projects.");
}
@@ -608,14 +620,18 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos)
void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d)
{
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
m_contextMenuTarget = modelNode;
m_contextMenuPos3d = pos3d;
const bool isModel = modelNode.metaInfo().isQtQuick3DModel();
+ const bool isNode = modelNode.metaInfo().isQtQuick3DNode();
const bool allowAlign = view()->edit3DAction(View3DActionType::AlignCamerasToView)->action()->isEnabled();
const bool isSingleComponent = view()->hasSingleSelectedModelNode() && modelNode.isComponent();
const bool anyNodeSelected = view()->hasSelectedModelNodes();
const bool selectionExcludingRoot = anyNodeSelected && !view()->rootModelNode().isSelected();
+ const bool isInBundle = modelNode.type().startsWith(compUtils.componentBundlesTypePrefix().toLatin1());
if (m_createSubMenu)
m_createSubMenu->setEnabled(!isSceneLocked());
@@ -633,6 +649,7 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
m_toggleGroupAction->setEnabled(true);
m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
+ m_addToContentLibAction->setEnabled(isNode && !isInBundle);
if (m_view) {
int idx = m_view->activeSplit();
@@ -685,7 +702,7 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
} else if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData())
|| dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_MATERIAL)
|| dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)
- || dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_EFFECT)
+ || dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_ITEM)
|| dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_TEXTURE)) {
if (Utils3D::active3DSceneNode(m_view).isValid())
dragEnterEvent->acceptProposedAction();
@@ -694,7 +711,7 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
if (!data.isEmpty()) {
QDataStream stream(data);
stream >> m_draggedEntry;
- if (NodeHints::fromItemLibraryEntry(m_draggedEntry).canBeDroppedInView3D())
+ if (NodeHints::fromItemLibraryEntry(m_draggedEntry, view()->model()).canBeDroppedInView3D())
dragEnterEvent->acceptProposedAction();
}
}
@@ -730,8 +747,8 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
return;
}
- // handle dropping bundle effects
- if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_EFFECT)) {
+ // handle dropping bundle items
+ if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_ITEM)) {
m_view->dropBundleEffect(pos);
m_view->model()->endDrag();
return;
@@ -766,9 +783,14 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
QString fileName = QFileInfo(assetPath).baseName();
fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter
auto model = m_view->model();
- auto metaInfo = model->metaInfo(model->module("Quick3DAssets"), fileName.toUtf8());
+ Utils::PathString import3dTypePrefix = QmlDesignerPlugin::instance()
+ ->documentManager()
+ .generatedComponentUtils()
+ .import3dTypePrefix();
+ auto moduleId = model->module(import3dTypePrefix, Storage::ModuleKind::QmlLibrary);
+ auto metaInfo = model->metaInfo(moduleId, fileName.toUtf8());
if (auto entries = metaInfo.itemLibrariesEntries(); entries.size()) {
- auto entry = ItemLibraryEntry{entries.front(), *model->projectStorage()};
+ auto entry = ItemLibraryEntry{entries.front()};
QmlVisualNode::createQml3DNode(view(), entry, m_canvas->activeScene(), {}, false);
}
}
@@ -780,7 +802,9 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
for (const QString &assetPath : added3DAssets) {
QString fileName = QFileInfo(assetPath).baseName();
fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter
- QString type = QString("Quick3DAssets.%1.%1").arg(fileName);
+ QString type = QString("%1.%2.%2").arg(QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().import3dTypePrefix(),
+ fileName);
QList<ItemLibraryEntry> entriesForType = itemLibInfo->entriesForType(type.toUtf8());
if (!entriesForType.isEmpty()) { // should always be true, but just in case
QmlVisualNode::createQml3DNode(view(),
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
index 211b044d41..97c0469668 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
@@ -100,6 +100,7 @@ private:
QPointer<QAction> m_selectParentAction;
QPointer<QAction> m_toggleGroupAction;
QPointer<QAction> m_wireFrameAction;
+ QPointer<QAction> m_addToContentLibAction;
QHash<int, QPointer<QAction>> m_matOverrideActions;
QPointer<QMenu> m_createSubMenu;
ModelNode m_contextMenuTarget;
diff --git a/src/plugins/qmldesigner/components/edit3d/snapconfiguration.cpp b/src/plugins/qmldesigner/components/edit3d/snapconfiguration.cpp
index 26c5fe0eb2..8890ea8964 100644
--- a/src/plugins/qmldesigner/components/edit3d/snapconfiguration.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/snapconfiguration.cpp
@@ -87,9 +87,11 @@ void SnapConfiguration::resetDefaults()
void SnapConfiguration::hideCursor()
{
- if (QGuiApplication::overrideCursor())
+ if (m_cursorHidden)
return;
+ m_cursorHidden = true;
+
QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
if (QWindow *w = QGuiApplication::focusWindow())
@@ -98,9 +100,11 @@ void SnapConfiguration::hideCursor()
void SnapConfiguration::restoreCursor()
{
- if (!QGuiApplication::overrideCursor())
+ if (!m_cursorHidden)
return;
+ m_cursorHidden = false;
+
QGuiApplication::restoreOverrideCursor();
if (QWindow *w = QGuiApplication::focusWindow())
@@ -109,7 +113,7 @@ void SnapConfiguration::restoreCursor()
void SnapConfiguration::holdCursorInPlace()
{
- if (!QGuiApplication::overrideCursor())
+ if (!m_cursorHidden)
return;
if (QWindow *w = QGuiApplication::focusWindow())
diff --git a/src/plugins/qmldesigner/components/edit3d/snapconfiguration.h b/src/plugins/qmldesigner/components/edit3d/snapconfiguration.h
index 729e6ce7d1..ae401f60f9 100644
--- a/src/plugins/qmldesigner/components/edit3d/snapconfiguration.h
+++ b/src/plugins/qmldesigner/components/edit3d/snapconfiguration.h
@@ -103,6 +103,7 @@ private:
double m_scaleInterval = 0.;
bool m_changes = false;
QPoint m_lastPos;
+ bool m_cursorHidden = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
index 0b7d199b50..a6494811b6 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -206,9 +206,16 @@ static ItemLibraryEntry itemLibraryEntryFromMimeData(const QMimeData *mimeData)
return itemLibraryEntry;
}
-static bool canBeDropped(const QMimeData *mimeData)
+static bool canBeDropped(const QMimeData *mimeData, Model *model)
{
- return NodeHints::fromItemLibraryEntry(itemLibraryEntryFromMimeData(mimeData)).canBeDroppedInFormEditor();
+#ifdef QDS_USE_PROJECTSTORAGE
+ auto itemLibraryEntry = itemLibraryEntryFromMimeData(mimeData);
+ NodeMetaInfo metaInfo{itemLibraryEntry.typeId(), model->projectStorage()};
+ return metaInfo.canBeDroppedInFormEditor() == FlagIs::True;
+#else
+ return NodeHints::fromItemLibraryEntry(itemLibraryEntryFromMimeData(mimeData), model)
+ .canBeDroppedInFormEditor();
+#endif
}
static bool hasItemLibraryInfo(const QMimeData *mimeData)
@@ -218,7 +225,7 @@ static bool hasItemLibraryInfo(const QMimeData *mimeData)
void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
- if (canBeDropped(event->mimeData())) {
+ if (canBeDropped(event->mimeData(), view()->model())) {
event->accept();
end(generateUseSnapping(event->modifiers()));
@@ -290,7 +297,7 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneD
void DragTool::dragEnterEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
{
- if (canBeDropped(event->mimeData())) {
+ if (canBeDropped(event->mimeData(), view()->model())) {
m_blockMove = false;
if (hasItemLibraryInfo(event->mimeData())) {
@@ -306,7 +313,7 @@ void DragTool::dragEnterEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraph
void DragTool::dragLeaveEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
{
- if (canBeDropped(event->mimeData())) {
+ if (canBeDropped(event->mimeData(), view()->model())) {
event->accept();
m_moveManipulator.end();
@@ -363,10 +370,8 @@ void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSc
->data(Constants::MIME_TYPE_ASSETS)).split(',');
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPaths[0]).first;
- if (!m_blockMove
- && !m_isAborted
- && canBeDropped(event->mimeData())
- && assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
+ if (!m_blockMove && !m_isAborted && canBeDropped(event->mimeData(), view()->model())
+ && assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
event->accept();
if (!m_dragNodes.isEmpty()) {
if (targetContainerItem) {
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h
index 1cd2c9f487..c1d5626d28 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.h
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h
@@ -7,7 +7,6 @@
#include "selectionindicator.h"
#include <QObject>
-#include <QScopedPointer>
#include <QPointer>
namespace QmlDesigner {
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
index 35a48a6b6d..dd239dd966 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp
@@ -302,9 +302,9 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const
const QString &author, const QString &text,
const QString &date, QGraphicsItem *parent)
{
- static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::DStextColor);
- static QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColorDarker);
- static QColor frameColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColor);
+ static QColor textColor = Utils::creatorColor(Utils::Theme::DStextColor);
+ static QColor backgroundColor = Utils::creatorColor(Utils::Theme::QmlDesigner_BackgroundColorDarker);
+ static QColor frameColor = Utils::creatorColor(Utils::Theme::QmlDesigner_BackgroundColor);
QFont font;
font.setBold(true);
@@ -405,9 +405,9 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const
QGraphicsItem *FormEditorAnnotationIcon::createTitleBubble(const QRectF &rect, const QString &text, QGraphicsItem *parent)
{
- static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::DStextColor);
- static QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColorDarker);
- static QColor frameColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColor);
+ static QColor textColor = Utils::creatorColor(Utils::Theme::DStextColor);
+ static QColor backgroundColor = Utils::creatorColor(Utils::Theme::QmlDesigner_BackgroundColorDarker);
+ static QColor frameColor = Utils::creatorColor(Utils::Theme::QmlDesigner_BackgroundColor);
QFont font;
font.setBold(true);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
index 9549ce9dd4..d835274a97 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
@@ -3,7 +3,6 @@
#include "formeditorgraphicsview.h"
#include "backgroundaction.h"
-#include "formeditoritem.h"
#include "formeditorwidget.h"
#include "navigation2d.h"
@@ -76,11 +75,11 @@ bool FormEditorGraphicsView::eventFilter(QObject *watched, QEvent *event)
auto mouseEvent = static_cast<QMouseEvent *>(event);
if (!m_panningStartPosition.isNull()) {
horizontalScrollBar()->setValue(horizontalScrollBar()->value() -
- (mouseEvent->x() - m_panningStartPosition.x()));
+ (mouseEvent->position().x() - m_panningStartPosition.x()));
verticalScrollBar()->setValue(verticalScrollBar()->value() -
- (mouseEvent->y() - m_panningStartPosition.y()));
+ (mouseEvent->position().y() - m_panningStartPosition.y()));
}
- m_panningStartPosition = mouseEvent->pos();
+ m_panningStartPosition = mouseEvent->position();
event->accept();
return true;
}
@@ -215,7 +214,7 @@ void FormEditorGraphicsView::drawBackground(QPainter *painter, const QRectF &rec
painter->fillRect(rectangle.intersected(rootItemRect()), backgroundBrush());
}
- QPen pen(Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor));
+ QPen pen(Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorSelectionColor));
pen.setStyle(Qt::DotLine);
pen.setWidth(1);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h
index 60e02582cd..e1e61a8f1e 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h
@@ -46,7 +46,7 @@ private:
void stopPanning(QEvent *event);
Panning m_isPanning = Panning::NotStarted;
- QPoint m_panningStartPosition;
+ QPointF m_panningStartPosition;
QRectF m_rootItemRect;
QImage m_backgroundImage;
};
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
index 12da85e2c4..b3df6b8fe7 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
@@ -48,23 +48,19 @@ void drawIcon(QPainter *painter,
int iconSize,
const QColor &penColor)
{
- static QFontDatabase a;
-
const QString fontName = "qtds_propertyIconFont.ttf";
- Q_ASSERT(a.hasFamily(fontName));
+ QTC_ASSERT(QFontDatabase::hasFamily(fontName), return);
- if (a.hasFamily(fontName)) {
- QFont font(fontName);
- font.setPixelSize(fontSize);
+ QFont font(fontName);
+ font.setPixelSize(fontSize);
- painter->save();
- painter->setPen(penColor);
- painter->setFont(font);
- painter->drawText(QRectF(x, y, iconSize, iconSize), iconSymbol);
+ painter->save();
+ painter->setPen(penColor);
+ painter->setFont(font);
+ painter->drawText(QRectF(x, y, iconSize, iconSize), iconSymbol);
- painter->restore();
- }
+ painter->restore();
}
FormEditorScene *FormEditorItem::scene() const {
@@ -309,7 +305,7 @@ void FormEditorItem::paintBoundingRect(QPainter *painter) const
pen.setJoinStyle(Qt::MiterJoin);
const QColor frameColor(0xaa, 0xaa, 0xaa);
- static const QColor selectionColor = Utils::creatorTheme()->color(
+ static const QColor selectionColor = Utils::creatorColor(
Utils::Theme::QmlDesigner_FormEditorSelectionColor);
if (scene()->showBoundingRects()) {
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditortoolbutton.cpp b/src/plugins/qmldesigner/components/formeditor/formeditortoolbutton.cpp
index 555d0d90e3..f3aa96ada4 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditortoolbutton.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditortoolbutton.cpp
@@ -42,7 +42,7 @@ void FormEditorToolButton::paint(QPainter *painter, const QStyleOptionGraphicsIt
QRectF adjustedRect(size().width() - toolButtonSize, size().height() - toolButtonSize, toolButtonSize, toolButtonSize);
painter->setPen(Qt::NoPen);
- static QColor selectionColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
+ static QColor selectionColor = Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
if (m_state == Hovered)
painter->setBrush(selectionColor.lighter(110));
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
index 0f5b5f4438..45d26f831e 100644
--- a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
@@ -78,7 +78,7 @@ void SelectionIndicator::setItems(const QList<FormEditorItem*> &itemList)
{
clear();
- static QColor selectionColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
+ static QColor selectionColor = Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
for (FormEditorItem *item : itemList) {
if (!item->qmlItemNode().isValid())
@@ -119,7 +119,7 @@ void SelectionIndicator::setItems(const QList<FormEditorItem*> &itemList)
m_annotationItem = nullptr;
}
- static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorForegroundColor);
+ static QColor textColor = Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorForegroundColor);
textItem->setDefaultTextColor(textColor);
QPolygonF labelPolygon = boundingRectInLayerItemSpaceForItem(selectedItem, m_layerItem.data());
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp
index c0bebbb82b..aa2dfd3b28 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp
@@ -64,13 +64,14 @@ namespace QmlDesigner {
DesignDocument acts as a facade to a model representing a qml document,
and the different views/widgets accessing it.
*/
-DesignDocument::DesignDocument(ProjectStorageDependencies projectStorageDependencies,
+DesignDocument::DesignDocument([[maybe_unused]] const QUrl &filePath,
+ ProjectStorageDependencies projectStorageDependencies,
ExternalDependenciesInterface &externalDependencies)
#ifdef QDS_USE_PROJECTSTORAGE
: m_documentModel(Model::create(projectStorageDependencies,
"Item",
{Import::createLibraryImport("QtQuick")},
- {},
+ filePath,
std::make_unique<ModelResourceManagement>()))
#else
: m_documentModel(
@@ -149,7 +150,10 @@ bool DesignDocument::loadInFileComponent(const ModelNode &componentNode)
if (!componentNode.isRootNode()) {
//change to subcomponent model
- changeToInFileComponentModel(createComponentTextModifier(m_documentTextModifier.data(), rewriterView(), componentText, componentNode));
+ changeToInFileComponentModel(createComponentTextModifier(m_documentTextModifier.get(),
+ rewriterView(),
+ componentText,
+ componentNode));
}
return true;
@@ -280,11 +284,10 @@ void DesignDocument::moveNodesToPosition(const QList<ModelNode> &nodes, const st
parentProperty.reparentHere(pastedNode);
QmlVisualNode visualNode(pastedNode);
- if (!firstVisualNode.has_value() && visualNode.isValid()){
+ if (!firstVisualNode && visualNode) {
firstVisualNode = visualNode;
- translationVect = (position.has_value() && firstVisualNode.has_value())
- ? position.value() - firstVisualNode->position()
- : QVector3D();
+ translationVect = (position && firstVisualNode) ? *position - firstVisualNode->position()
+ : QVector3D();
}
visualNode.translate(translationVect);
}
@@ -376,9 +379,12 @@ void DesignDocument::loadDocument(QPlainTextEdit *edit)
m_documentTextModifier.reset(new BaseTextEditModifier(qobject_cast<TextEditor::TextEditorWidget *>(plainTextEdit())));
- connect(m_documentTextModifier.data(), &TextModifier::textChanged, this, &DesignDocument::updateQrcFiles);
+ connect(m_documentTextModifier.get(),
+ &TextModifier::textChanged,
+ this,
+ &DesignDocument::updateQrcFiles);
- m_rewriterView->setTextModifier(m_documentTextModifier.data());
+ m_rewriterView->setTextModifier(m_documentTextModifier.get());
m_inFileComponentTextModifier.reset();
@@ -398,7 +404,7 @@ void DesignDocument::changeToDocumentModel()
if (edit)
edit->document()->clearUndoRedoStacks();
- m_rewriterView->setTextModifier(m_documentTextModifier.data());
+ m_rewriterView->setTextModifier(m_documentTextModifier.get());
m_inFileComponentModel.reset();
m_inFileComponentTextModifier.reset();
@@ -431,7 +437,7 @@ bool DesignDocument::hasProject() const
void DesignDocument::setModified()
{
- if (!m_documentTextModifier.isNull())
+ if (m_documentTextModifier)
m_documentTextModifier->textDocument()->setModified(true);
}
@@ -447,7 +453,7 @@ void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textMod
m_inFileComponentModel = createInFileComponentModel();
- m_rewriterView->setTextModifier(m_inFileComponentTextModifier.data());
+ m_rewriterView->setTextModifier(m_inFileComponentTextModifier.get());
viewManager().attachRewriterView();
viewManager().attachViewsExceptRewriterAndComponetView();
@@ -674,7 +680,7 @@ void DesignDocument::selectAll()
RewriterView *DesignDocument::rewriterView() const
{
- return m_rewriterView.data();
+ return m_rewriterView.get();
}
void DesignDocument::setEditor(Core::IEditor *editor)
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.h b/src/plugins/qmldesigner/components/integration/designdocument.h
index 0d75141205..1f67ff4b30 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.h
+++ b/src/plugins/qmldesigner/components/integration/designdocument.h
@@ -16,9 +16,10 @@
#include <QObject>
#include <QString>
-
#include <QStackedWidget>
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
QT_END_NAMESPACE
@@ -41,7 +42,8 @@ class QMLDESIGNERCOMPONENTS_EXPORT DesignDocument : public QObject
Q_OBJECT
public:
- DesignDocument(ProjectStorageDependencies projectStorageDependencies,
+ DesignDocument(const QUrl &filePath,
+ ProjectStorageDependencies projectStorageDependencies,
ExternalDependenciesInterface &externalDependencies);
~DesignDocument() override;
@@ -142,12 +144,12 @@ private: // variables
ModelPointer m_documentModel;
ModelPointer m_inFileComponentModel;
QPointer<Core::IEditor> m_textEditor;
- QScopedPointer<BaseTextEditModifier> m_documentTextModifier;
- QScopedPointer<ComponentTextModifier> m_inFileComponentTextModifier;
+ std::unique_ptr<BaseTextEditModifier> m_documentTextModifier;
+ std::unique_ptr<ComponentTextModifier> m_inFileComponentTextModifier;
#ifndef QDS_USE_PROJECTSTORAGE
- QScopedPointer<SubComponentManager> m_subComponentManager;
+ std::unique_ptr<SubComponentManager> m_subComponentManager;
#endif
- QScopedPointer<RewriterView> m_rewriterView;
+ std::unique_ptr<RewriterView> m_rewriterView;
bool m_documentLoaded;
ProjectExplorer::Target *m_currentTarget;
ProjectStorageDependencies m_projectStorageDependencies;
diff --git a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
index 6ef95bf4c4..d97b9ff06f 100644
--- a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
@@ -23,6 +23,8 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <memory>
+
namespace QmlDesigner {
DesignDocumentView::DesignDocumentView(ExternalDependenciesInterface &externalDependencies)
@@ -116,14 +118,14 @@ QString DesignDocumentView::toText() const
textEdit.setPlainText(imports + QStringLiteral("Item {\n}\n"));
NotIndentingTextEditModifier modifier(&textEdit);
- QScopedPointer<RewriterView> rewriterView(
- new RewriterView(externalDependencies(), RewriterView::Amend));
+ std::unique_ptr<RewriterView> rewriterView = std::make_unique<RewriterView>(externalDependencies(),
+ RewriterView::Amend);
rewriterView->setCheckSemanticErrors(false);
rewriterView->setPossibleImportsEnabled(false);
rewriterView->setTextModifier(&modifier);
- outputModel->setRewriterView(rewriterView.data());
+ outputModel->setRewriterView(rewriterView.get());
- ModelMerger merger(rewriterView.data());
+ ModelMerger merger(rewriterView.get());
merger.replaceModel(rootModelNode());
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp
new file mode 100644
index 0000000000..608bf42eb3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.cpp
@@ -0,0 +1,82 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "import3dcanvas.h"
+
+#include <QImage>
+#include <QLinearGradient>
+#include <QMouseEvent>
+#include <QPainter>
+
+namespace QmlDesigner {
+
+static QImage createGradientImage(int width, int height) {
+ QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
+
+ QLinearGradient gradient(0, 0, 0, height);
+ gradient.setColorAt(0, QColor(0x999999));
+ gradient.setColorAt(1, QColor(0x222222));
+
+ QPainter painter(&image);
+ painter.fillRect(0, 0, width, height, gradient);
+
+ return image;
+}
+
+Import3dCanvas::Import3dCanvas(QWidget *parent)
+ : QWidget(parent)
+{
+}
+
+void Import3dCanvas::updateRenderImage(const QImage &img)
+{
+ m_image = img;
+ update();
+}
+
+void Import3dCanvas::paintEvent([[maybe_unused]] QPaintEvent *e)
+{
+ QWidget::paintEvent(e);
+
+ QPainter painter(this);
+
+ if (m_image.isNull()) {
+ QImage image = createGradientImage(width(), height());
+ painter.drawImage(rect(), image, QRect(0, 0, image.width(), image.height()));
+ } else {
+ painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height()));
+ }
+}
+
+void Import3dCanvas::resizeEvent(QResizeEvent *)
+{
+ emit requestImageUpdate();
+}
+
+void Import3dCanvas::mousePressEvent(QMouseEvent *e)
+{
+ if (e->buttons() == Qt::LeftButton)
+ m_dragPos = e->position();
+ else
+ m_dragPos = {};
+}
+
+void Import3dCanvas::mouseReleaseEvent(QMouseEvent *)
+{
+ m_dragPos = {};
+}
+
+void Import3dCanvas::mouseMoveEvent(QMouseEvent *e)
+{
+ if (m_dragPos.isNull())
+ return;
+
+ const QPointF curPos = e->position();
+ const QPointF delta = curPos - m_dragPos;
+
+ m_dragPos = curPos;
+
+ emit requestRotation(delta);
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h
new file mode 100644
index 0000000000..72fb19acff
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dcanvas.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <QEvent>
+#include <QImage>
+#include <QPointF>
+#include <QWidget>
+
+namespace QmlDesigner {
+
+class Import3dCanvas : public QWidget
+{
+ Q_OBJECT
+
+public:
+ Import3dCanvas(QWidget *parent);
+
+ void updateRenderImage(const QImage &img);
+
+signals:
+ void requestImageUpdate();
+ void requestRotation(const QPointF &delta);
+
+protected:
+ void paintEvent(QPaintEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+ void mousePressEvent(QMouseEvent *e) override;
+ void mouseReleaseEvent(QMouseEvent *e) override;
+ void mouseMoveEvent(QMouseEvent *e) override;
+
+private:
+ QImage m_image;
+ QPointF m_dragPos;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp
new file mode 100644
index 0000000000..4c455e3c6d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "import3dconnectionmanager.h"
+
+#include <imagecontainer.h>
+#include <puppettocreatorcommand.h>
+
+#include <QImage>
+
+namespace QmlDesigner {
+
+Import3dConnectionManager::Import3dConnectionManager()
+{
+ connections().clear(); // Remove default interactive puppets
+ connections().emplace_back("Import 3D", "import3dmode");
+}
+
+void Import3dConnectionManager::setPreviewImageCallback(ImageCallback callback)
+{
+ m_previewImageCallback = std::move(callback);
+}
+
+void Import3dConnectionManager::dispatchCommand(const QVariant &command,
+ ConnectionManagerInterface::Connection &connection)
+{
+ static const int commandType = QMetaType::type("PuppetToCreatorCommand");
+
+ if (command.typeId() == commandType) {
+ auto cmd = command.value<PuppetToCreatorCommand>();
+ switch (cmd.type()) {
+ case PuppetToCreatorCommand::Import3DPreviewImage: {
+ ImageContainer container = qvariant_cast<ImageContainer>(cmd.data());
+ QImage image = container.image();
+ if (!image.isNull())
+ m_previewImageCallback(image);
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ InteractiveConnectionManager::dispatchCommand(command, connection);
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h
new file mode 100644
index 0000000000..458d612ad2
--- /dev/null
+++ b/src/plugins/qmldesigner/components/itemlibrary/import3dconnectionmanager.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "interactiveconnectionmanager.h"
+
+QT_FORWARD_DECLARE_CLASS(QImage)
+
+namespace QmlDesigner {
+
+class Import3dConnectionManager : public InteractiveConnectionManager
+{
+public:
+ using ImageCallback = std::function<void(const QImage &)>;
+
+ Import3dConnectionManager();
+
+ void setPreviewImageCallback(ImageCallback callback);
+
+protected:
+ void dispatchCommand(const QVariant &command, Connection &connection) override;
+
+private:
+ ImageCallback m_previewImageCallback;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index 29fff4b359..271410233b 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -4,11 +4,16 @@
#include "itemlibraryassetimportdialog.h"
#include "ui_itemlibraryassetimportdialog.h"
+#include "import3dcanvas.h"
+#include "import3dconnectionmanager.h"
+
#include <model.h>
#include <model/modelutils.h>
+#include <nodeinstanceview.h>
#include <nodemetainfo.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
+#include <rewriterview.h>
#include <variantproperty.h>
#include <theme.h>
@@ -73,9 +78,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
const QStringList &importFiles, const QString &defaulTargetDirectory,
const QVariantMap &supportedExts, const QVariantMap &supportedOpts,
const QJsonObject &defaultOpts, const QSet<QString> &preselectedFilesForOverwrite,
- QWidget *parent)
+ AbstractView *view, QWidget *parent)
: QDialog(parent)
, ui(new Ui::ItemLibraryAssetImportDialog)
+ , m_view(view)
, m_importer(this)
, m_preselectedFilesForOverwrite(preselectedFilesForOverwrite)
{
@@ -106,17 +112,15 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
if (m_quick3DFiles.size() != importFiles.size())
addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets.");
- ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import"));
- connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked,
- this, &ItemLibraryAssetImportDialog::onImport);
+ connect(ui->importButton, &QPushButton::clicked, this, &ItemLibraryAssetImportDialog::onImport);
- ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+ ui->importButton->setDefault(true);
ui->advancedSettingsButton->setStyleSheet(
"QPushButton#advancedSettingsButton {background-color: transparent}");
ui->advancedSettingsButton->setStyleSheet(
QString("QPushButton { border: none; color :%1 }").arg(
- Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_HighlightColor).name()));
+ Utils::creatorColor(Utils::Theme::QmlDesigner_HighlightColor).name()));
QStringList importPaths;
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -130,43 +134,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
if (targetDir.isEmpty())
targetDir = defaulTargetDirectory;
- // Import is always done under known folder. The order of preference for folder is:
- // 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
- // 2) An existing QUICK_3D_ASSETS_FOLDER under any project import path
- // 3) New QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path
- // 4) New QUICK_3D_ASSETS_FOLDER under any project import path
- // 5) New QUICK_3D_ASSETS_FOLDER under new DEFAULT_ASSET_IMPORT_FOLDER under project
- const QString defaultAssetFolder = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER);
- const QString quick3DFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
- QString candidatePath = targetDir + defaultAssetFolder + quick3DFolder;
- int candidatePriority = 5;
-
- for (const auto &importPath : std::as_const(importPaths)) {
- if (importPath.startsWith(targetDir)) {
- const bool isDefaultFolder = importPath.endsWith(defaultAssetFolder);
- const QString assetFolder = importPath + quick3DFolder;
- const bool exists = QFileInfo::exists(assetFolder);
- if (exists) {
- if (isDefaultFolder) {
- // Priority one location, stop looking
- candidatePath = assetFolder;
- break;
- } else if (candidatePriority > 2) {
- candidatePriority = 2;
- candidatePath = assetFolder;
- }
- } else {
- if (candidatePriority > 3 && isDefaultFolder) {
- candidatePriority = 3;
- candidatePath = assetFolder;
- } else if (candidatePriority > 4) {
- candidatePriority = 4;
- candidatePath = assetFolder;
- }
- }
- }
- }
- m_quick3DImportPath = candidatePath;
+ m_quick3DImportPath = QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().import3dBasePath().toString();
if (!m_quick3DFiles.isEmpty()) {
QVector<QJsonObject> groups;
@@ -244,10 +213,14 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
ui->tabWidget->setCurrentIndex(0);
}
- connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked,
+ connect(ui->closeButton, &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::onClose);
connect(ui->tabWidget, &QTabWidget::currentChanged,
this, &ItemLibraryAssetImportDialog::updateUi);
+ connect(canvas(), &Import3dCanvas::requestImageUpdate,
+ this, &ItemLibraryAssetImportDialog::onRequestImageUpdate);
+ connect(canvas(), &Import3dCanvas::requestRotation,
+ this, &ItemLibraryAssetImportDialog::onRequestRotation);
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
this, &ItemLibraryAssetImportDialog::addError);
@@ -261,23 +234,35 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
this, &ItemLibraryAssetImportDialog::onImportFinished);
connect(&m_importer, &ItemLibraryAssetImporter::progressChanged,
this, &ItemLibraryAssetImportDialog::setImportProgress);
-
- addInfo(tr("Select import options and press \"Import\" to import the following files:"));
- for (const auto &file : std::as_const(m_quick3DFiles))
- addInfo(file);
+ connect(&m_importer, &ItemLibraryAssetImporter::importReadyForPreview,
+ this, &ItemLibraryAssetImportDialog::onImportReadyForPreview);
connect(ui->advancedSettingsButton, &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::toggleAdvanced);
QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::updateUi);
+
+ if (m_quick3DFiles.size() != 1) {
+ addInfo(tr("Select import options and press \"Import\" to import the following files:"));
+ } else {
+ addInfo(tr("Importing:"));
+ QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
+ }
+
+ for (const auto &file : std::as_const(m_quick3DFiles))
+ addInfo(file);
+
+ updateImportButtonState();
}
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
{
+ cleanupPreviewPuppet();
delete ui;
}
-void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
+void ItemLibraryAssetImportDialog::updateImport(AbstractView *view,
+ const ModelNode &updateNode,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts)
{
@@ -294,11 +279,14 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
QFileInfo compFileInfo{compFileName};
// Find to top asset folder
- const QString assetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER).mid(1);
+ const QString oldAssetFolder = QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER);
+ QString assetFolder = QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER);
const QStringList parts = compFileName.split('/');
int i = parts.size() - 1;
int previousSize = 0;
for (; i >= 0; --i) {
+ if (parts[i] == oldAssetFolder)
+ assetFolder = oldAssetFolder;
if (parts[i] == assetFolder)
break;
previousSize = parts[i].size();
@@ -363,7 +351,8 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode,
{sourceInfo.absoluteFilePath()},
node.model()->fileUrl().toLocalFile(),
supportedExts, supportedOpts, options,
- preselectedFiles, Core::ICore::dialogParent());
+ preselectedFiles, view,
+ Core::ICore::dialogParent());
importDlg->show();
} else {
@@ -512,6 +501,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QJsonValue value(optCheck->isChecked());
optObj.insert("value", value);
m_importOptions[optionsIndex].insert(optKey, optObj);
+ updateImportButtonState();
});
} else {
// Simple options also exist in advanced, so don't connect simple controls directly
@@ -519,13 +509,17 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
auto *advCheck = qobject_cast<QCheckBox *>(
m_labelToControlWidgetMaps[optionsIndex].value(optKey));
if (advCheck) {
- QObject::connect(optCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() {
- if (advCheck->isChecked() != optCheck->isChecked())
+ QObject::connect(optCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
+ if (advCheck->isChecked() != optCheck->isChecked()) {
advCheck->setChecked(optCheck->isChecked());
+ updateImportButtonState();
+ }
});
- QObject::connect(advCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() {
- if (advCheck->isChecked() != optCheck->isChecked())
+ QObject::connect(advCheck, &QCheckBox::toggled, this, [this, optCheck, advCheck]() {
+ if (advCheck->isChecked() != optCheck->isChecked()) {
optCheck->setChecked(advCheck->isChecked());
+ updateImportButtonState();
+ }
});
}
}
@@ -561,6 +555,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QJsonValue value(optSpin->value());
optObj.insert("value", value);
m_importOptions[optionsIndex].insert(optKey, optObj);
+ updateImportButtonState();
});
} else {
auto *advSpin = qobject_cast<QDoubleSpinBox *>(
@@ -568,14 +563,18 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
if (advSpin) {
// Connect corresponding advanced control
QObject::connect(optSpin, &QDoubleSpinBox::valueChanged,
- this, [optSpin, advSpin] {
- if (advSpin->value() != optSpin->value())
+ this, [this, optSpin, advSpin] {
+ if (advSpin->value() != optSpin->value()) {
advSpin->setValue(optSpin->value());
+ updateImportButtonState();
+ }
});
QObject::connect(advSpin, &QDoubleSpinBox::valueChanged,
- this, [optSpin, advSpin] {
- if (advSpin->value() != optSpin->value())
+ this, [this, optSpin, advSpin] {
+ if (advSpin->value() != optSpin->value()) {
optSpin->setValue(advSpin->value());
+ updateImportButtonState();
+ }
});
}
}
@@ -733,8 +732,10 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
// and move the remaining member to ungrouped options
// Note: <= 2 instead of < 2 because each group has group label member
if (i != 0 && groupWidgets.size() <= 2) {
- widgets[0].prepend(groupWidgets[1]);
- groupWidgets[0].first->hide(); // hide group label
+ if (groupWidgets.size() == 2)
+ widgets[0].prepend(groupWidgets[1]);
+ if (groupWidgets.size() >= 1)
+ groupWidgets[0].first->hide(); // hide group label
groupWidgets.clear();
}
}
@@ -858,6 +859,145 @@ bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
return hiddenOptions.contains(id);
}
+void ItemLibraryAssetImportDialog::startPreview()
+{
+ cleanupPreviewPuppet();
+
+ // Preview is done via custom QML file added into the temporary folder of the preview
+ QString previewQml =
+R"(
+import QtQuick
+import QtQuick3D
+
+Rectangle {
+ id: root
+ width: %1
+ height: %2
+
+ property alias sceneNode: sceneNode
+ property alias view3d: view3d
+ property string extents
+ property string sceneModelName: "%3"
+
+ gradient: Gradient {
+ GradientStop { position: 1.0; color: "#222222" }
+ GradientStop { position: 0.0; color: "#999999" }
+ }
+
+ View3D {
+ id: view3d
+ anchors.fill: parent
+ camera: viewCamera
+
+ environment: SceneEnvironment {
+ antialiasingMode: SceneEnvironment.MSAA
+ antialiasingQuality: SceneEnvironment.VeryHigh
+ }
+
+ PerspectiveCamera {
+ id: viewCamera
+ x: 600
+ y: 600
+ z: 600
+ eulerRotation.x: -45
+ eulerRotation.y: -45
+ clipFar: 100000
+ clipNear: 10
+ }
+
+ DirectionalLight {
+ rotation: viewCamera.rotation
+ }
+
+ Node {
+ id: sceneNode
+ }
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ color: "white"
+ text: root.extents
+ font.pixelSize: 14
+ }
+}
+)";
+
+ QSize size = canvas()->size();
+ previewQml = previewQml.arg(size.width()).arg(size.height()).arg(m_previewCompName);
+
+ m_previewFile.writeFileContents(previewQml.toUtf8());
+
+ if (!m_previewFile.exists()) {
+ addWarning("Failed to write preview file.");
+ return;
+ }
+
+ m_connectionManager = new Import3dConnectionManager;
+ m_rewriterView = new RewriterView{m_view->externalDependencies(), RewriterView::Amend};
+ m_nodeInstanceView = new NodeInstanceView{*m_connectionManager, m_view->externalDependencies()};
+
+#ifdef QDS_USE_PROJECTSTORAGE
+ m_model = m_view->model()->createModel("Item");
+#else
+ m_model = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
+ m_model->setFileUrl(m_previewFile.toUrl());
+#endif
+
+ auto textDocument = std::make_unique<QTextDocument>(previewQml);
+ auto modifier = std::make_unique<NotIndentingTextEditModifier>(textDocument.get(),
+ QTextCursor{textDocument.get()});
+ m_rewriterView->setTextModifier(modifier.get());
+ m_model->setRewriterView(m_rewriterView);
+
+ if (!m_rewriterView->errors().isEmpty()) {
+ addWarning("Preview scene creation failed.");
+ cleanupPreviewPuppet();
+ return;
+ }
+
+ m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
+
+ auto previewImageCallback = [this](const QImage &image) {
+ canvas()->updateRenderImage(image);
+ };
+
+ auto crashCallback = [&] {
+ addWarning("Preview process crashed.");
+ cleanupPreviewPuppet();
+ };
+
+ m_connectionManager->setPreviewImageCallback(std::move(previewImageCallback));
+ m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
+
+ m_model->setNodeInstanceView(m_nodeInstanceView);
+}
+
+void ItemLibraryAssetImportDialog::cleanupPreviewPuppet()
+{
+ if (m_model) {
+ m_model->setNodeInstanceView({});
+ m_model->setRewriterView({});
+ m_model.reset();
+ }
+
+ if (m_nodeInstanceView)
+ m_nodeInstanceView->setCrashCallback({});
+
+ if (m_connectionManager)
+ m_connectionManager->setPreviewImageCallback({});
+
+ delete m_rewriterView;
+ delete m_nodeInstanceView;
+ delete m_connectionManager;
+}
+
+Import3dCanvas *ItemLibraryAssetImportDialog::canvas()
+{
+ return ui->import3dcanvas;
+}
+
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
{
m_dialogHeight = event->size().height();
@@ -866,8 +1006,13 @@ void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
{
- ui->buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
- ui->buttonBox->button(QDialogButtonBox::Close)->setText(importing ? tr("Cancel") : tr("Close"));
+ ui->closeButton->setEnabled(true);
+ ui->closeButton->setText(importing ? tr("Cancel") : tr("Close"));
+}
+
+void ItemLibraryAssetImportDialog::updateImportButtonState()
+{
+ ui->importButton->setText(m_previewOptions == m_importOptions ? tr("Accept") : tr("Import"));
}
void ItemLibraryAssetImportDialog::addError(const QString &error, const QString &srcPath)
@@ -889,14 +1034,25 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
void ItemLibraryAssetImportDialog::onImport()
{
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ ui->importButton->setEnabled(false);
+
+ if (!m_previewCompName.isEmpty() && m_previewOptions == m_importOptions) {
+ cleanupPreviewPuppet();
+ m_importer.finalizeQuick3DImport();
+ return;
+ }
+
setCloseButtonState(true);
ui->progressBar->setValue(0);
if (!m_quick3DFiles.isEmpty()) {
- m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
- m_importOptions, m_extToImportOptionsMap,
- m_preselectedFilesForOverwrite);
+ if (!m_previewCompName.isEmpty()) {
+ m_importer.reImportQuick3D(m_previewCompName, m_importOptions);
+ } else {
+ m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
+ m_importOptions, m_extToImportOptionsMap,
+ m_preselectedFilesForOverwrite);
+ }
}
}
@@ -910,10 +1066,37 @@ void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &t
ui->progressBar->setValue(value);
}
+void ItemLibraryAssetImportDialog::onImportReadyForPreview(const QString &path, const QString &compName)
+{
+ addInfo(tr("Import is ready for preview."));
+ if (m_previewCompName.isEmpty())
+ addInfo(tr("Click \"Accept\" to finish the import or adjust options and click \"Import\" to import again."));
+
+ m_previewFile = Utils::FilePath::fromString(path).pathAppended(m_importer.previewFileName());
+ m_previewCompName = compName;
+ m_previewOptions = m_importOptions;
+ QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::startPreview);
+
+ ui->importButton->setEnabled(true);
+ updateImportButtonState();
+}
+
+void ItemLibraryAssetImportDialog::onRequestImageUpdate()
+{
+ if (m_nodeInstanceView)
+ m_nodeInstanceView->view3DAction(View3DActionType::Import3dUpdatePreviewImage, canvas()->size());
+}
+
+void ItemLibraryAssetImportDialog::onRequestRotation(const QPointF &delta)
+{
+ if (m_nodeInstanceView)
+ m_nodeInstanceView->view3DAction(View3DActionType::Import3dRotatePreviewModel, delta);
+}
+
void ItemLibraryAssetImportDialog::onImportNearlyFinished()
{
// Canceling import is no longer doable
- ui->buttonBox->button(QDialogButtonBox::Close)->setEnabled(false);
+ ui->closeButton->setEnabled(false);
}
void ItemLibraryAssetImportDialog::onImportFinished()
@@ -923,19 +1106,28 @@ void ItemLibraryAssetImportDialog::onImportFinished()
QString interruptStr = tr("Import interrupted.");
addError(interruptStr);
setImportProgress(0, interruptStr);
+ if (m_explicitClose)
+ QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose);
} else {
QString doneStr = tr("Import done.");
addInfo(doneStr);
setImportProgress(100, doneStr);
if (m_closeOnFinish) {
// Add small delay to allow user to visually confirm import finishing
- QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::onClose);
+ QTimer::singleShot(1000, this, &ItemLibraryAssetImportDialog::doClose);
}
}
}
void ItemLibraryAssetImportDialog::onClose()
{
+ ui->importButton->setEnabled(false);
+ m_explicitClose = true;
+ doClose();
+}
+
+void ItemLibraryAssetImportDialog::doClose()
+{
if (m_importer.isImporting()) {
addInfo(tr("Canceling import."));
m_importer.cancelImport();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
index c5da478232..e7c4933056 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
@@ -3,14 +3,19 @@
#pragma once
#include "itemlibraryassetimporter.h"
-#include "modelnode.h"
+
+#include <modelnode.h>
+
+#include <utils/filepath.h>
#include <QDialog>
#include <QJsonObject>
+#include <QPointer>
#include <QSet>
QT_BEGIN_NAMESPACE
class QGridLayout;
+class QPushButton;
QT_END_NAMESPACE
namespace Utils {
@@ -19,6 +24,10 @@ class OutputFormatter;
namespace QmlDesigner {
class ItemLibraryAssetImporter;
+class Import3dCanvas;
+class Import3dConnectionManager;
+class NodeInstanceView;
+class RewriterView;
namespace Ui {
class ItemLibraryAssetImportDialog;
@@ -35,10 +44,12 @@ public:
const QVariantMap &supportedOpts,
const QJsonObject &defaultOpts,
const QSet<QString> &preselectedFilesForOverwrite,
+ AbstractView *view,
QWidget *parent = nullptr);
~ItemLibraryAssetImportDialog();
- static void updateImport(const ModelNode &updateNode,
+ static void updateImport(AbstractView *view,
+ const ModelNode &updateNode,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts);
@@ -52,12 +63,17 @@ private slots:
private:
void setCloseButtonState(bool importing);
+ void updateImportButtonState();
void onImport();
void setImportProgress(int value, const QString &text);
+ void onImportReadyForPreview(const QString &path, const QString &compName);
+ void onRequestImageUpdate();
+ void onRequestRotation(const QPointF &delta);
void onImportNearlyFinished();
void onImportFinished();
void onClose();
+ void doClose();
void toggleAdvanced();
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
@@ -69,8 +85,19 @@ private:
bool isSimpleOption(const QString &id);
bool isHiddenOption(const QString &id);
+ void startPreview();
+ void cleanupPreviewPuppet();
+ Import3dCanvas *canvas();
+
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr;
+ QPointer<Import3dConnectionManager> m_connectionManager;
+ QPointer<NodeInstanceView> m_nodeInstanceView;
+ QPointer<RewriterView> m_rewriterView;
+ QPointer<AbstractView> m_view;
+ ModelPointer m_model;
+ Utils::FilePath m_previewFile;
+ QString m_previewCompName;
struct OptionsData
{
@@ -83,6 +110,7 @@ private:
QString m_quick3DImportPath;
ItemLibraryAssetImporter m_importer;
QVector<QJsonObject> m_importOptions;
+ QVector<QJsonObject> m_previewOptions;
QHash<QString, int> m_extToImportOptionsMap;
QSet<QString> m_preselectedFilesForOverwrite;
bool m_closeOnFinish = true;
@@ -91,5 +119,6 @@ private:
OptionsData m_advancedData;
bool m_advancedMode = false;
int m_dialogHeight = 350;
+ bool m_explicitClose = false;
};
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
index 081bc36a3d..e0b9d925fc 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
@@ -6,15 +6,15 @@
<rect>
<x>0</x>
<y>0</y>
- <width>630</width>
+ <width>1100</width>
<height>350</height>
</rect>
</property>
<property name="windowTitle">
<string>Asset Import</string>
</property>
- <layout class="QFormLayout" name="formLayout">
- <item row="0" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
@@ -24,6 +24,12 @@
<verstretch>2</verstretch>
</sizepolicy>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>550</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="currentIndex">
<number>0</number>
</property>
@@ -98,6 +104,12 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
<property name="text">
<string/>
</property>
@@ -111,16 +123,64 @@
</widget>
</item>
<item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
- </property>
- </widget>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="importButton">
+ <property name="text">
+ <string>Import</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</item>
+ <item>
+ <widget class="Import3dCanvas" name="import3dcanvas" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>300</height>
+ </size>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>Import3dCanvas</class>
+ <extends>QWidget</extends>
+ <header>import3dcanvas.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
index 48958ceec9..010d00a970 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "itemlibraryassetimporter.h"
+
#include "assetimportupdatedialog.h"
#include "qmldesignerplugin.h"
#include "qmldesignerconstants.h"
@@ -20,6 +21,7 @@
#include <utils/algorithm.h>
#include <utils/async.h>
+#include <utils/filepath.h>
#include <utils/qtcassert.h>
#include <QApplication>
@@ -57,8 +59,6 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite)
{
- if (m_isImporting)
- cancelImport();
reset();
m_isImporting = true;
@@ -91,6 +91,53 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
}
}
+void ItemLibraryAssetImporter::reImportQuick3D(const QString &assetName,
+ const QVector<QJsonObject> &options)
+{
+ if (!assetName.isEmpty() && !m_parseData.contains(assetName)) {
+ addError(tr("Attempted to reimport non-existing asset: %1").arg(assetName));
+ return;
+ }
+
+ ParseData &pd = m_parseData[assetName];
+ // Change outDir just in case reimport generates different files
+ QDir oldDir = pd.outDir;
+ QString assetFolder = generateAssetFolderName(pd.assetName);
+ pd.outDir.cdUp();
+ pd.outDir.mkpath(assetFolder);
+
+ if (!pd.outDir.cd(assetFolder)) {
+ addError(tr("Could not access temporary asset directory: \"%1\".")
+ .arg(pd.outDir.filePath(assetFolder)));
+ return;
+ }
+
+ if (oldDir.absolutePath().contains(tempDirNameBase()))
+ oldDir.removeRecursively();
+
+ m_isImporting = false;
+ m_cancelled = false;
+
+ m_puppetProcess.reset();
+ m_requiredImports.clear();
+ m_currentImportId = 0;
+ m_puppetQueue.clear();
+
+ for (ParseData &pd : m_parseData)
+ pd.importId = -1;
+
+ pd.options = options[pd.optionsIndex];
+ pd.importId = 1;
+
+ m_importFiles.remove(assetName);
+
+ m_importIdToAssetNameMap.clear();
+ m_importIdToAssetNameMap[pd.importId] = assetName;
+
+ m_puppetQueue.append(pd.importId);
+ startNextImportProcess();
+}
+
bool ItemLibraryAssetImporter::isImporting() const
{
return m_isImporting;
@@ -103,19 +150,19 @@ void ItemLibraryAssetImporter::cancelImport()
notifyFinished();
}
-void ItemLibraryAssetImporter::addError(const QString &errMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addError(const QString &errMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Error: "<< errMsg << srcPath;
emit errorReported(errMsg, srcPath);
}
-void ItemLibraryAssetImporter::addWarning(const QString &warningMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addWarning(const QString &warningMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Warning: " << warningMsg << srcPath;
emit warningReported(warningMsg, srcPath);
}
-void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &srcPath) const
+void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &srcPath)
{
qCDebug(importerLog) << "Info: " << infoMsg << srcPath;
emit infoReported(infoMsg, srcPath);
@@ -126,8 +173,8 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
{
m_puppetProcess.reset();
- if (m_parseData.contains(m_currentImportId)) {
- const ParseData &pd = m_parseData[m_currentImportId];
+ if (m_importIdToAssetNameMap.contains(m_currentImportId)) {
+ const ParseData &pd = m_parseData[m_importIdToAssetNameMap[m_currentImportId]];
QString errStr;
if (exitStatus == QProcess::ExitStatus::CrashExit) {
errStr = tr("Import process crashed.");
@@ -150,11 +197,12 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
addError(tr("Asset import process failed: \"%1\".")
.arg(pd.sourceInfo.absoluteFilePath()));
addError(errStr);
- m_parseData.remove(m_currentImportId);
+ m_parseData.remove(m_importIdToAssetNameMap[m_currentImportId]);
+ m_importIdToAssetNameMap.remove(m_currentImportId);
}
}
- int finishedCount = m_parseData.size() - m_puppetQueue.size();
+ int finishedCount = m_importIdToAssetNameMap.size() - m_puppetQueue.size();
if (!m_puppetQueue.isEmpty())
startNextImportProcess();
@@ -162,7 +210,7 @@ void ItemLibraryAssetImporter::importProcessFinished([[maybe_unused]] int exitCo
notifyProgress(100);
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport);
} else {
- notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size()))));
+ notifyProgress(int(100. * (double(finishedCount) / double(m_importIdToAssetNameMap.size()))));
}
}
@@ -178,7 +226,7 @@ void ItemLibraryAssetImporter::reset()
m_cancelled = false;
delete m_tempDir;
- m_tempDir = new QTemporaryDir;
+ m_tempDir = new QTemporaryDir(QDir::tempPath() + tempDirNameBase());
m_importFiles.clear();
m_overwrittenImports.clear();
m_puppetProcess.reset();
@@ -186,6 +234,7 @@ void ItemLibraryAssetImporter::reset()
m_requiredImports.clear();
m_currentImportId = 0;
m_puppetQueue.clear();
+ m_importIdToAssetNameMap.clear();
}
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
@@ -207,9 +256,11 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
int index = extToImportOptionsMap.value(QFileInfo(file).suffix());
ParseData pd;
pd.options = options[index];
+ pd.optionsIndex = index;
if (preParseQuick3DAsset(file, pd, preselectedFilesForOverwrite)) {
pd.importId = ++m_importIdCounter;
- m_parseData.insert(pd.importId, pd);
+ m_importIdToAssetNameMap[pd.importId] = pd.assetName;
+ m_parseData.insert(pd.assetName, pd);
}
notifyProgress(qRound(++count * quota), progressTitle);
}
@@ -238,7 +289,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
pd.targetDirPath = pd.targetDir.filePath(pd.assetName);
- if (pd.outDir.exists(pd.assetName)) {
+ if (m_parseData.contains(pd.assetName)) {
addWarning(tr("Skipped import of duplicate asset: \"%1\".").arg(pd.assetName));
return false;
}
@@ -287,11 +338,12 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
}
}
- pd.outDir.mkpath(pd.assetName);
+ QString assetFolder = generateAssetFolderName(pd.assetName);
+ pd.outDir.mkpath(assetFolder);
- if (!pd.outDir.cd(pd.assetName)) {
+ if (!pd.outDir.cd(assetFolder)) {
addError(tr("Could not access temporary asset directory: \"%1\".")
- .arg(pd.outDir.filePath(pd.assetName)));
+ .arg(pd.outDir.filePath(assetFolder)));
return false;
}
return true;
@@ -329,12 +381,15 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
if (qmldirFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QString qmlInfo;
qmlInfo.append("module ");
- qmlInfo.append(m_importPath.split('/').last());
+ qmlInfo.append(QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().import3dTypePrefix());
qmlInfo.append(".");
qmlInfo.append(pd.assetName);
qmlInfo.append('\n');
m_requiredImports.append(
- QStringLiteral("%1.%2").arg(pd.targetDir.dirName(), pd.assetName));
+ QStringLiteral("%1.%2").arg(QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().import3dTypePrefix(),
+ pd.assetName));
while (qmlIt.hasNext()) {
qmlIt.next();
QFileInfo fi = QFileInfo(qmlIt.filePath());
@@ -421,7 +476,7 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
// Copy the original asset into a subdirectory
assetFiles.insert(sourcePath, sourceSceneTargetFilePath(pd));
- m_importFiles.insert(assetFiles);
+ m_importFiles.insert(pd.assetName, assetFiles);
}
void ItemLibraryAssetImporter::copyImportedFiles()
@@ -496,6 +551,12 @@ void ItemLibraryAssetImporter::keepUiAlive() const
QApplication::processEvents();
}
+QString ItemLibraryAssetImporter::generateAssetFolderName(const QString &assetName) const
+{
+ static int counter = 0;
+ return assetName + "_QDS_" + QString::number(counter++);
+}
+
ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
{
const QString title = tr("Overwrite Existing Asset?");
@@ -530,7 +591,8 @@ void ItemLibraryAssetImporter::startNextImportProcess()
if (model && view) {
bool done = false;
while (!m_puppetQueue.isEmpty() && !done) {
- const ParseData pd = m_parseData.value(m_puppetQueue.takeLast());
+ const ParseData pd = m_parseData.value(
+ m_importIdToAssetNameMap.value(m_puppetQueue.takeLast()));
QStringList puppetArgs;
QJsonDocument optDoc(pd.options);
@@ -553,7 +615,8 @@ void ItemLibraryAssetImporter::startNextImportProcess()
} else {
addError(tr("Failed to start import 3D asset process."),
pd.sourceInfo.absoluteFilePath());
- m_parseData.remove(pd.importId);
+ const QString assetName = m_importIdToAssetNameMap.take(pd.importId);
+ m_parseData.remove(assetName);
m_puppetProcess.reset();
}
}
@@ -569,8 +632,16 @@ void ItemLibraryAssetImporter::postImport()
postParseQuick3DAsset(pd);
}
- if (!isCancelled())
- finalizeQuick3DImport();
+ if (!isCancelled()) {
+ // TODO: Currently we only support import preview for single imports
+ if (m_parseData.size() != 1) {
+ finalizeQuick3DImport();
+ } else {
+ const ParseData &pd = m_parseData[m_parseData.keys().first()];
+ const QString importedComponentName = pd.assetName;
+ emit importReadyForPreview(pd.outDir.absolutePath(), importedComponentName);
+ }
+ }
}
void ItemLibraryAssetImporter::finalizeQuick3DImport()
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
index 8ad7b5a2de..abe9690951 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
@@ -2,8 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
-#include "import.h"
-
#include <qprocessuniqueptr.h>
#include <QSet>
@@ -35,20 +33,28 @@ public:
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite);
+ void reImportQuick3D(const QString &assetName, const QVector<QJsonObject> &options);
+
bool isImporting() const;
void cancelImport();
bool isCancelled() const;
- void addError(const QString &errMsg, const QString &srcPath = {}) const;
- void addWarning(const QString &warningMsg, const QString &srcPath = {}) const;
- void addInfo(const QString &infoMsg, const QString &srcPath = {}) const;
+ void addError(const QString &errMsg, const QString &srcPath = {});
+ void addWarning(const QString &warningMsg, const QString &srcPath = {});
+ void addInfo(const QString &infoMsg, const QString &srcPath = {});
+
+ QString previewFileName() const { return "QDSImport3dPreviewScene.qml"; }
+ QString tempDirNameBase() const { return "/qds3dimport"; }
+
+ void finalizeQuick3DImport();
signals:
- void errorReported(const QString &, const QString &) const;
- void warningReported(const QString &, const QString &) const;
- void infoReported(const QString &, const QString &) const;
- void progressChanged(int value, const QString &text) const;
- void importNearlyFinished() const;
+ void errorReported(const QString &, const QString &);
+ void warningReported(const QString &, const QString &);
+ void infoReported(const QString &, const QString &);
+ void progressChanged(int value, const QString &text);
+ void importReadyForPreview(const QString &path, const QString &compName);
+ void importNearlyFinished();
void importFinished();
private slots:
@@ -63,7 +69,8 @@ private:
QFileInfo sourceInfo;
QString assetName;
QString originalAssetName;
- int importId;
+ int importId = -1;
+ int optionsIndex = -1;
};
void notifyFinished();
@@ -79,6 +86,7 @@ private:
void notifyProgress(int value, const QString &text);
void notifyProgress(int value);
void keepUiAlive() const;
+ QString generateAssetFolderName(const QString &assetName) const;
enum class OverwriteResult {
Skip,
@@ -89,10 +97,9 @@ private:
OverwriteResult confirmAssetOverwrite(const QString &assetName);
void startNextImportProcess();
void postImport();
- void finalizeQuick3DImport();
QString sourceSceneTargetFilePath(const ParseData &pd);
- QSet<QHash<QString, QString>> m_importFiles;
+ QHash<QString, QHash<QString, QString>> m_importFiles; // Key: asset name
QHash<QString, QStringList> m_overwrittenImports;
bool m_isImporting = false;
bool m_cancelled = false;
@@ -101,7 +108,8 @@ private:
QProcessUniquePointer m_puppetProcess;
int m_importIdCounter = 0;
int m_currentImportId = 0;
- QHash<int, ParseData> m_parseData;
+ QHash<int, QString> m_importIdToAssetNameMap;
+ QHash<QString, ParseData> m_parseData; // Key: asset name
QString m_progressTitle;
QStringList m_requiredImports;
QList<int> m_puppetQueue;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
index dbeacc7595..8ef9512e26 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
@@ -296,15 +296,16 @@ void ItemLibraryModel::setSearchText(const QString &searchText)
Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry)
{
+#ifndef QDS_USE_PROJECTSTORAGE
if (entry.majorVersion() == -1 && entry.minorVersion() == -1)
return Import::createFileImport(entry.requiredImport());
-
+#endif
return Import::createLibraryImport(entry.requiredImport(), QString::number(entry.majorVersion()) + QLatin1Char('.') +
QString::number(entry.minorVersion()));
}
-void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo, Model *model)
+void ItemLibraryModel::update(Model *model)
{
if (!model)
return;
@@ -312,46 +313,54 @@ void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo,
beginResetModel();
clearSections();
+ const QString projectName = DocumentManager::currentProjectName();
+
+ auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
+
QStringList excludedImports {
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1) + ".MaterialBundle",
- QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1) + ".EffectBundle"
+ projectName,
+ compUtils.materialsBundleType(),
+ compUtils.effectsBundleType(),
+ compUtils.userMaterialsBundleType(),
+ compUtils.user3DBundleType(),
+ compUtils.userEffectsBundleType()
};
// create import sections
- const QString projectName = DocumentManager::currentProjectName();
const Imports usedImports = model->usedImports();
QHash<QString, ItemLibraryImport *> importHash;
for (const Import &import : model->imports()) {
- if (import.url() != projectName) {
- if (excludedImports.contains(import.url()) || import.url().startsWith("Effects."))
- continue;
- bool addNew = true;
- bool isQuick3DAsset = import.url().startsWith("Quick3DAssets.");
- QString importUrl = import.url();
- if (isQuick3DAsset)
- importUrl = ItemLibraryImport::quick3DAssetsTitle();
- else if (import.isFileImport())
- importUrl = import.toString(true, true).remove("\"");
-
- ItemLibraryImport *oldImport = importHash.value(importUrl);
- if (oldImport && oldImport->sectionType() == ItemLibraryImport::SectionType::Quick3DAssets
- && isQuick3DAsset) {
- addNew = false; // add only 1 Quick3DAssets import section
- } else if (oldImport && oldImport->importEntry().url() == import.url()) {
- // Retain the higher version if multiples exist
- if (oldImport->importEntry().toVersion() >= import.toVersion() || import.hasVersion())
- addNew = false;
- else
- delete oldImport;
- }
+ if (excludedImports.contains(import.url())
+ || import.url().startsWith(compUtils.composedEffectsTypePrefix())) {
+ continue;
+ }
- if (addNew) {
- auto sectionType = isQuick3DAsset ? ItemLibraryImport::SectionType::Quick3DAssets
- : ItemLibraryImport::SectionType::Default;
- ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this, sectionType);
- itemLibImport->setImportUsed(usedImports.contains(import));
- importHash.insert(importUrl, itemLibImport);
- }
+ bool addNew = true;
+ bool isQuick3DAsset = import.url().startsWith(compUtils.import3dTypePrefix());
+ QString importUrl = import.url();
+ if (isQuick3DAsset)
+ importUrl = ItemLibraryImport::quick3DAssetsTitle();
+ else if (import.isFileImport())
+ importUrl = import.toString(true, true).remove("\"");
+
+ ItemLibraryImport *oldImport = importHash.value(importUrl);
+ if (oldImport && oldImport->sectionType() == ItemLibraryImport::SectionType::Quick3DAssets
+ && isQuick3DAsset) {
+ addNew = false; // add only 1 Quick3DAssets import section
+ } else if (oldImport && oldImport->importEntry().url() == import.url()) {
+ // Retain the higher version if multiples exist
+ if (oldImport->importEntry().toVersion() >= import.toVersion() || import.hasVersion())
+ addNew = false;
+ else
+ delete oldImport;
+ }
+
+ if (addNew) {
+ auto sectionType = isQuick3DAsset ? ItemLibraryImport::SectionType::Quick3DAssets
+ : ItemLibraryImport::SectionType::Default;
+ ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this, sectionType);
+ itemLibImport->setImportUsed(usedImports.contains(import));
+ importHash.insert(importUrl, itemLibImport);
}
}
@@ -367,7 +376,7 @@ void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo,
NodeMetaInfo metaInfo;
if constexpr (useProjectStorage())
- metaInfo = entry.metaInfo();
+ metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()};
else
metaInfo = model->metaInfo(entry.typeName());
@@ -379,7 +388,8 @@ void ItemLibraryModel::update([[maybe_unused]] ItemLibraryInfo *itemLibraryInfo,
|| metaInfo.majorVersion() < 0);
#endif
bool isItem = valid && metaInfo.isQtQuickItem();
- bool forceVisibility = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary();
+ bool forceVisibility = valid
+ && NodeHints::fromItemLibraryEntry(entry, model).visibleInLibrary();
if (m_flowMode) {
isItem = metaInfo.isFlowViewItem();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
index 212ddf8e04..b04ea492d2 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
@@ -37,7 +37,7 @@ public:
QString searchText() const;
ItemLibraryImport *importByUrl(const QString &importName) const;
- void update(ItemLibraryInfo *itemLibraryInfo, Model *model);
+ void update(Model *model);
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 feff523b9c..e4f4ffcd9c 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -164,7 +164,7 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap)
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
m_importableExtensions3DMap,
m_importOptions3DMap, {}, {},
- Core::ICore::dialogParent());
+ this, Core::ICore::dialogParent());
int result = importDlg->exec();
return result == QDialog::Accepted ? AddFilesResult::succeeded() : AddFilesResult::cancelled();
@@ -198,7 +198,7 @@ void ItemLibraryView::customNotification(const AbstractView *view, const QString
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
if (identifier == "UpdateImported3DAsset" && nodeList.size() > 0) {
- ItemLibraryAssetImportDialog::updateImport(nodeList[0],
+ ItemLibraryAssetImportDialog::updateImport(this, nodeList[0],
m_importableExtensions3DMap,
m_importOptions3DMap);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index b710a8226f..ffefc43178 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -118,9 +118,9 @@ void ItemLibraryWidget::resizeEvent(QResizeEvent *event)
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
: m_itemIconSize(24, 24)
- , m_itemLibraryModel(new ItemLibraryModel(this))
- , m_addModuleModel(new ItemLibraryAddImportModel(this))
- , m_itemsWidget(new StudioQuickWidget(this))
+ , m_itemLibraryModel(std::make_unique<ItemLibraryModel>())
+ , m_addModuleModel(std::make_unique<ItemLibraryAddImportModel>())
+ , m_itemsWidget(Utils::makeUniqueObjectPtr<StudioQuickWidget>())
, m_imageCache{imageCache}
{
m_compressionTimer.setInterval(1000);
@@ -146,7 +146,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
- layout->addWidget(m_itemsWidget.data());
+ layout->addWidget(m_itemsWidget.get());
updateSearch();
@@ -167,8 +167,8 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
auto map = m_itemsWidget->registerPropertyMap("ItemLibraryBackend");
- map->setProperties({{"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.data())},
- {"addModuleModel", QVariant::fromValue(m_addModuleModel.data())},
+ map->setProperties({{"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.get())},
+ {"addModuleModel", QVariant::fromValue(m_addModuleModel.get())},
{"itemLibraryIconWidth", m_itemIconSize.width()},
{"itemLibraryIconHeight", m_itemIconSize.height()},
{"rootView", QVariant::fromValue(this)},
@@ -333,9 +333,7 @@ void ItemLibraryWidget::updateModel()
m_compressionTimer.stop();
}
-#ifndef QDS_USE_PROJECTSTORAGE
- m_itemLibraryModel->update(m_itemLibraryInfo.data(), m_model.data());
-#endif
+ m_itemLibraryModel->update(m_model.data());
if (m_itemLibraryModel->rowCount() == 0 && !m_updateRetry) {
m_updateRetry = true; // Only retry once to avoid endless loops
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
index b56532b218..2940db7a73 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
@@ -10,9 +10,10 @@
#include <studioquickwidget.h>
-#include <utils/fancylineedit.h>
-#include <utils/dropsupport.h>
#include <previewtooltip/previewtooltipbackend.h>
+#include <utils/dropsupport.h>
+#include <utils/fancylineedit.h>
+#include <utils/uniqueobjectptr.h>
#include <QFileIconProvider>
#include <QFrame>
@@ -104,10 +105,10 @@ private:
#ifndef QDS_USE_PROJECTSTORAGE
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
#endif
- QPointer<ItemLibraryModel> m_itemLibraryModel;
- QPointer<ItemLibraryAddImportModel> m_addModuleModel;
+ std::unique_ptr<ItemLibraryModel> m_itemLibraryModel;
+ std::unique_ptr<ItemLibraryAddImportModel> m_addModuleModel;
- QScopedPointer<StudioQuickWidget> m_itemsWidget;
+ Utils::UniqueObjectPtr<StudioQuickWidget> m_itemsWidget;
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut;
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
index b6009edc77..f97b6f74ac 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
@@ -29,10 +29,10 @@ public:
QVariant maybeConvertToNumber(const QVariant &value)
{
- if (value.typeId() == QVariant::Bool)
+ if (value.typeId() == QMetaType::Bool)
return value;
- if (value.typeId() == QVariant::String) {
+ if (value.typeId() == QMetaType::QString) {
const QString text = value.toString();
if (text == "true")
return QVariant(true);
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
index d36e78512b..b74f310741 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
@@ -366,6 +366,9 @@ void MaterialBrowserModel::selectMaterial(int idx, bool force)
if (idx != m_selectedIndex || force) {
m_selectedIndex = idx;
emit selectedIndexChanged(idx);
+
+ m_selectedMaterialIsComponent = selectedMaterial().isComponent();
+ emit selectedMaterialIsComponentChanged();
}
}
@@ -434,22 +437,20 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject();
if (propsSpecObj.contains(section)) { // should always be true
const QJsonArray propNames = propsSpecObj.value(section).toArray();
- // auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
- for (const auto &propName : propNames)
+ for (const QJsonValueConstRef &propName : propNames)
copiedProps.append(propName.toString().toLatin1());
if (section == "Base") { // add QtQuick3D.Material base props as well
QJsonObject propsMatObj = m_propertyGroupsObj.value("Material").toObject();
const QJsonArray propNames = propsMatObj.value("Base").toArray();
- // auto == QJsonValueConstRef after 04dc959d49e5e3 / Qt 6.4, QJsonValueRef before
- for (const auto &propName : propNames)
+ for (const QJsonValueConstRef &propName : propNames)
copiedProps.append(propName.toString().toLatin1());
}
}
}
m_copiedMaterialProps.clear();
- for (const auto &propName : copiedProps) {
+ for (const PropertyName &propName : copiedProps) {
PropertyCopyData data;
data.name = propName;
data.isValid = m_allPropsCopied || validProps.contains(propName);
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
index 337dce0550..3b6b64ec86 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
@@ -3,7 +3,7 @@
#pragma once
-#include "modelnode.h"
+#include <modelnode.h>
#include <QAbstractListModel>
#include <QJsonObject>
@@ -20,6 +20,7 @@ class MaterialBrowserModel : public QAbstractListModel
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged)
+ Q_PROPERTY(bool selectedMaterialIsComponent MEMBER m_selectedMaterialIsComponent NOTIFY selectedMaterialIsComponentChanged)
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasModelSelection READ hasModelSelection WRITE setHasModelSelection NOTIFY hasModelSelectionChanged)
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary WRITE setHasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
@@ -110,6 +111,7 @@ signals:
const QList<QmlDesigner::MaterialBrowserModel::PropertyCopyData> &props,
bool all);
void isQt6ProjectChanged();
+ void selectedMaterialIsComponentChanged();
private:
bool isValidIndex(int idx) const;
@@ -132,6 +134,7 @@ private:
bool m_hasMaterialLibrary = false;
bool m_allPropsCopied = true;
bool m_isQt6Project = false;
+ bool m_selectedMaterialIsComponent = false;
QString m_copiedMaterialType;
QPointer<MaterialBrowserView> m_view;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
index ec95f3e5d3..918956a04c 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
@@ -63,7 +63,7 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
return tr("Texture has no source image.");
ModelNode texNode = m_textureList.at(index.row());
- QString info = ImageUtils::imageInfo(source);
+ QString info = ImageUtils::imageInfoString(source);
if (info.isEmpty())
return tr("Texture has no data.");
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index 8bd5761728..7d90dffffc 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -446,8 +446,13 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups()
if (!m_hasQuick3DImport || m_propertyGroupsLoaded || !model())
return;
+#ifdef QDS_USE_PROJECTSTORAGE
+ // TODO
+ QString matPropsPath;
+#else
QString matPropsPath = model()->metaInfo("QtQuick3D.Material").importDirectoryPath()
+ "/designer/propertyGroups.json";
+#endif
m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath);
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
index 47a1e8d293..8723611be0 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
@@ -56,6 +56,13 @@ public:
m_pixmaps.insert(node.internalId(), pixmap);
}
+ QPixmap getPixmap(const ModelNode &node)
+ {
+ QTC_ASSERT(node, return {});
+
+ return m_pixmaps.value(node.internalId());
+ }
+
void clearPixmapCache()
{
m_pixmaps.clear();
@@ -143,7 +150,7 @@ MaterialBrowserWidget::MaterialBrowserWidget(AsynchronousImageCache &imageCache,
: m_materialBrowserView(view)
, m_materialBrowserModel(new MaterialBrowserModel(view, this))
, m_materialBrowserTexturesModel(new MaterialBrowserTexturesModel(view, this))
- , m_quickWidget(new StudioQuickWidget(this))
+ , m_quickWidget(Utils::makeUniqueObjectPtr<StudioQuickWidget>(this))
, m_previewImageProvider(new PreviewImageProvider())
{
QImage defaultImage;
@@ -172,7 +179,7 @@ MaterialBrowserWidget::MaterialBrowserWidget(AsynchronousImageCache &imageCache,
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
- layout->addWidget(m_quickWidget.data());
+ layout->addWidget(m_quickWidget.get());
updateSearch();
@@ -357,6 +364,13 @@ void MaterialBrowserWidget::focusMaterialSection(bool focusMatSec)
}
}
+void MaterialBrowserWidget::addMaterialToContentLibrary()
+{
+ ModelNode mat = m_materialBrowserModel->selectedMaterial();
+ m_materialBrowserView->emitCustomNotification("add_material_to_content_lib", {mat},
+ {m_previewImageProvider->getPixmap(mat)});
+}
+
QString MaterialBrowserWidget::qmlSourcesPath()
{
#ifdef SHARE_QML_PATH
@@ -397,7 +411,7 @@ void MaterialBrowserWidget::setIsDragging(bool val)
StudioQuickWidget *MaterialBrowserWidget::quickWidget() const
{
- return m_quickWidget.data();
+ return m_quickWidget.get();
}
void MaterialBrowserWidget::clearPreviewCache()
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
index bfe7ace34d..6506283f85 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
@@ -7,6 +7,8 @@
#include <coreplugin/icontext.h>
+#include <utils/uniqueobjectptr.h>
+
#include <QFrame>
QT_BEGIN_NAMESPACE
@@ -60,6 +62,7 @@ public:
Q_INVOKABLE void acceptAssetsDropOnMaterial(int matIndex, const QList<QUrl> &urls);
Q_INVOKABLE void acceptTextureDropOnMaterial(int matIndex, const QString &texId);
Q_INVOKABLE void focusMaterialSection(bool focusMatSec);
+ Q_INVOKABLE void addMaterialToContentLibrary();
StudioQuickWidget *quickWidget() const;
@@ -83,7 +86,7 @@ private:
QPointer<MaterialBrowserView> m_materialBrowserView;
QPointer<MaterialBrowserModel> m_materialBrowserModel;
QPointer<MaterialBrowserTexturesModel> m_materialBrowserTexturesModel;
- QScopedPointer<StudioQuickWidget> m_quickWidget;
+ Utils::UniqueObjectPtr<StudioQuickWidget> m_quickWidget;
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
PreviewImageProvider *m_previewImageProvider = nullptr;
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
index 664006fb7a..f583498db7 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorcontextobject.cpp
@@ -46,9 +46,9 @@ QString MaterialEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
QColor theColor;
- if (color.canConvert(QVariant::Color)) {
+ if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>();
- } else if (color.canConvert(QVariant::Vector3D)) {
+ } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
}
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
index ecc460ae51..0e508f8f36 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
@@ -80,8 +80,8 @@ public:
MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialEditor)
: m_quickWidget(Utils::makeUniqueObjectPtr<QQuickWidget>())
- , m_materialEditorTransaction(new MaterialEditorTransaction(materialEditor))
- , m_contextObject(new MaterialEditorContextObject(m_quickWidget.get()))
+ , m_materialEditorTransaction(std::make_unique<MaterialEditorTransaction>(materialEditor))
+ , m_contextObject(std::make_unique<MaterialEditorContextObject>(m_quickWidget.get()))
, m_materialEditorImageProvider(new MaterialEditorImageProvider())
{
m_quickWidget->setObjectName(Constants::OBJECT_NAME_MATERIAL_EDITOR);
@@ -90,7 +90,7 @@ MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialE
m_quickWidget->engine()->addImageProvider("materialEditor", m_materialEditorImageProvider);
m_contextObject->setBackendValues(&m_backendValuesPropertyMap);
m_contextObject->setModel(materialEditor->model());
- context()->setContextObject(m_contextObject.data());
+ context()->setContextObject(m_contextObject.get());
QObject::connect(&m_backendValuesPropertyMap, &DesignerPropertyMap::valueChanged,
materialEditor, &MaterialEditorView::changeValue);
@@ -193,7 +193,7 @@ QQmlContext *MaterialEditorQmlBackend::context() const
MaterialEditorContextObject *MaterialEditorQmlBackend::contextObject() const
{
- return m_contextObject.data();
+ return m_contextObject.get();
}
QQuickWidget *MaterialEditorQmlBackend::widget() const
@@ -224,7 +224,7 @@ DesignerPropertyMap &MaterialEditorQmlBackend::backendValuesPropertyMap()
MaterialEditorTransaction *MaterialEditorQmlBackend::materialEditorTransaction() const
{
- return m_materialEditorTransaction.data();
+ return m_materialEditorTransaction.get();
}
PropertyEditorValue *MaterialEditorQmlBackend::propertyValueForName(const QString &propertyName)
@@ -267,12 +267,9 @@ void MaterialEditorQmlBackend::setup(const QmlObjectNode &selectedMaterialNode,
// anchors
m_backendAnchorBinding.setup(selectedMaterialNode.modelNode());
- context()->setContextProperties(
- QVector<QQmlContext::PropertyPair>{
- {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
- {{"transaction"}, QVariant::fromValue(m_materialEditorTransaction.data())}
- }
- );
+ context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
+ {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
+ {{"transaction"}, QVariant::fromValue(m_materialEditorTransaction.get())}});
contextObject()->setSpecificsUrl(qmlSpecificsFile);
contextObject()->setStateName(stateName);
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.h
index 6f9d6014e9..9fd5fc2399 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.h
@@ -11,6 +11,8 @@
#include <nodemetainfo.h>
+#include <memory>
+
class PropertyEditorValue;
QT_BEGIN_NAMESPACE
@@ -60,12 +62,15 @@ private:
MaterialEditorView *materialEditor);
PropertyName auxNamePostFix(const PropertyName &propertyName);
+ // to avoid a crash while destructing DesignerPropertyMap in the QQmlData
+ // this needs be destructed after m_quickWidget->engine() is destructed
+ DesignerPropertyMap m_backendValuesPropertyMap;
+
Utils::UniqueObjectPtr<QQuickWidget> m_quickWidget = nullptr;
QmlAnchorBindingProxy m_backendAnchorBinding;
QmlModelNodeProxy m_backendModelNode;
- DesignerPropertyMap m_backendValuesPropertyMap;
- QScopedPointer<MaterialEditorTransaction> m_materialEditorTransaction;
- QScopedPointer<MaterialEditorContextObject> m_contextObject;
+ std::unique_ptr<MaterialEditorTransaction> m_materialEditorTransaction;
+ std::unique_ptr<MaterialEditorContextObject> m_contextObject;
QPointer<MaterialEditorImageProvider> m_materialEditorImageProvider;
};
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index e083310cdb..21114267cb 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -24,7 +24,6 @@
#include "qmldesignerplugin.h"
#include "qmltimeline.h"
#include "variantproperty.h"
-#include <itemlibraryentry.h>
#include <utils3d.h>
#include <coreplugin/icore.h>
@@ -63,10 +62,6 @@ MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDe
}
});
- m_typeUpdateTimer.setSingleShot(true);
- m_typeUpdateTimer.setInterval(500);
- connect(&m_typeUpdateTimer, &QTimer::timeout, this, &MaterialEditorView::updatePossibleTypes);
-
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType();
@@ -333,8 +328,10 @@ void MaterialEditorView::resetView()
setupQmlBackend();
- if (m_qmlBackEnd)
+ if (m_qmlBackEnd) {
m_qmlBackEnd->emitSelectionChanged();
+ updatePossibleTypes();
+ }
QTimer::singleShot(0, this, &MaterialEditorView::requestPreviewRender);
@@ -605,7 +602,6 @@ void MaterialEditorView::setupQmlBackend()
else
m_dynamicPropertiesModel->reset();
- delayedTypeUpdate();
initPreviewData();
m_stackedWidget->setCurrentWidget(m_qmlBackEnd->widget());
@@ -690,21 +686,6 @@ void MaterialEditorView::initPreviewData()
}
}
-void MaterialEditorView::delayedTypeUpdate()
-{
- m_typeUpdateTimer.start();
-}
-
-[[maybe_unused]] static Import entryToImport(const ItemLibraryEntry &entry)
-{
- if (entry.majorVersion() == -1 && entry.minorVersion() == -1)
- return Import::createFileImport(entry.requiredImport());
-
- return Import::createLibraryImport(entry.requiredImport(),
- QString::number(entry.majorVersion()) + QLatin1Char('.') +
- QString::number(entry.minorVersion()));
-}
-
void MaterialEditorView::updatePossibleTypes()
{
QTC_ASSERT(model(), return);
@@ -712,49 +693,21 @@ void MaterialEditorView::updatePossibleTypes()
if (!m_qmlBackEnd)
return;
-#ifdef QDS_USE_PROJECTSTORAGE
- auto heirs = model()->qtQuick3DMaterialMetaInfo().heirs();
- heirs.push_back(model()->qtQuick3DMaterialMetaInfo());
- auto entries = Utils::transform<ItemLibraryEntries>(heirs, [&](const auto &heir) {
- return toItemLibraryEntries(heir.itemLibrariesEntries(), *model()->projectStorage());
- });
+ static const QStringList basicTypes {
+ "CustomMaterial",
+ "DefaultMaterial",
+ "PrincipledMaterial",
+ "SpecularGlossyMaterial"
+ };
- // I am unsure about the code intention here
-#else // Ensure basic types are always first
- QStringList nonQuick3dTypes;
- QStringList allTypes;
-
- const QList<ItemLibraryEntry> itemLibEntries = m_itemLibraryInfo->entries();
- for (const ItemLibraryEntry &entry : itemLibEntries) {
- NodeMetaInfo metaInfo = model()->metaInfo(entry.typeName());
- bool valid = metaInfo.isValid()
- && (metaInfo.majorVersion() >= entry.majorVersion()
- || metaInfo.majorVersion() < 0);
- if (valid && metaInfo.isQtQuick3DMaterial()) {
- bool addImport = entry.requiredImport().isEmpty();
- if (!addImport) {
- Import import = entryToImport(entry);
- addImport = model()->hasImport(import, true, true);
- }
- if (addImport) {
- const QList<QByteArray> typeSplit = entry.typeName().split('.');
- const QString typeName = QString::fromLatin1(typeSplit.last());
- if (typeSplit.size() == 2 && typeSplit.first() == "QtQuick3D") {
- if (!allTypes.contains(typeName))
- allTypes.append(typeName);
- } else if (!nonQuick3dTypes.contains(typeName)) {
- nonQuick3dTypes.append(typeName);
- }
- }
- }
- }
+ const QString matType = m_selectedMaterial.simplifiedTypeName();
- allTypes.sort();
- nonQuick3dTypes.sort();
- allTypes.append(nonQuick3dTypes);
+ if (basicTypes.contains(matType)) {
+ m_qmlBackEnd->contextObject()->setPossibleTypes(basicTypes);
+ return;
+ }
- m_qmlBackEnd->contextObject()->setPossibleTypes(allTypes);
-#endif
+ m_qmlBackEnd->contextObject()->setPossibleTypes({matType});
}
void MaterialEditorView::modelAttached(Model *model)
@@ -774,20 +727,6 @@ void MaterialEditorView::modelAttached(Model *model)
m_ensureMatLibTimer.start(500);
}
-#ifndef QDS_USE_PROJECTSTORAGE
- if (m_itemLibraryInfo.data() != model->metaInfo().itemLibraryInfo()) {
- if (m_itemLibraryInfo) {
- disconnect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
- this, &MaterialEditorView::delayedTypeUpdate);
- }
- m_itemLibraryInfo = model->metaInfo().itemLibraryInfo();
- if (m_itemLibraryInfo) {
- connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::entriesChanged,
- this, &MaterialEditorView::delayedTypeUpdate);
- }
- }
-#endif
-
if (!m_setupCompleted) {
reloadQml();
m_setupCompleted = true;
@@ -801,7 +740,8 @@ void MaterialEditorView::modelAboutToBeDetached(Model *model)
{
AbstractView::modelAboutToBeDetached(model);
m_dynamicPropertiesModel->reset();
- m_qmlBackEnd->materialEditorTransaction()->end();
+ if (auto transaction = m_qmlBackEnd->materialEditorTransaction())
+ transaction->end();
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(false);
m_selectedMaterial = {};
}
@@ -938,7 +878,8 @@ void MaterialEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNo
m_selectedModels.append(node);
}
- m_qmlBackEnd->contextObject()->setHasModelSelection(!m_selectedModels.isEmpty());
+ if (m_qmlBackEnd)
+ m_qmlBackEnd->contextObject()->setHasModelSelection(!m_selectedModels.isEmpty());
}
void MaterialEditorView::currentStateChanged(const ModelNode &node)
@@ -1020,7 +961,7 @@ void MaterialEditorView::renameMaterial(ModelNode &material, const QString &newN
return;
executeInTransaction(__FUNCTION__, [&] {
- material.setIdWithRefactoring(model()->generateIdFromName(newName, "material"));
+ material.setIdWithRefactoring(model()->generateNewId(newName, "material"));
VariantProperty objNameProp = material.variantProperty("objectName");
objNameProp.setValue(newName);
@@ -1057,7 +998,7 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
VariantProperty objNameProp = duplicateMatNode.variantProperty("objectName");
objNameProp.setValue(newName);
- duplicateMatNode.setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
+ duplicateMatNode.setIdWithoutRefactoring(model()->generateNewId(newName, "material"));
// sync properties. Only the base state is duplicated.
const QList<AbstractProperty> props = material.properties();
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index c201742bd5..11bea46063 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -109,12 +109,10 @@ private:
bool noValidSelection() const;
void initPreviewData();
- void delayedTypeUpdate();
void updatePossibleTypes();
ModelNode m_selectedMaterial;
QTimer m_ensureMatLibTimer;
- QTimer m_typeUpdateTimer;
QShortcut *m_updateShortcut = nullptr;
int m_timerId = 0;
QStackedWidget *m_stackedWidget = nullptr;
diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
index 58b4c42749..fee3218af0 100644
--- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
+++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
@@ -5,6 +5,8 @@
#include "nodemetainfo.h"
#include "ui_choosefrompropertylistdialog.h"
+#include <qmldesignerplugin.h>
+
namespace QmlDesigner {
// This will filter and return possible properties that the given type can be bound to
@@ -100,7 +102,9 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
#ifdef QDS_USE_PROJECTSTORAGE
// TODO add the types here or use the module
#else
- } else if (insertInfo.typeName().startsWith("ComponentBundles.MaterialBundle")) {
+ } else if (insertInfo.typeName().startsWith(
+ QmlDesignerPlugin::instance()->documentManager()
+ .generatedComponentUtils().materialsBundleType().toUtf8())) {
if (parentInfo.isQtQuick3DModel())
propertyList.append("materials");
#endif
diff --git a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp
index 5b36bee7f9..09cf5945e8 100644
--- a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp
+++ b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp
@@ -79,15 +79,12 @@ void IconCheckboxItemDelegate::paint(QPainter *painter,
if (rowIsPropertyRole(modelIndex.model(), modelIndex) || getModelNode(modelIndex).isRootNode())
return; // Do not paint icons for property rows or root node
- QWindow *window = dynamic_cast<QWidget*>(painter->device())->window()->windowHandle();
- QTC_ASSERT(window, return);
-
const QSize iconSize(16, 16);
QPoint iconPosition(styleOption.rect.left() + (styleOption.rect.width() - iconSize.width()) / 2,
styleOption.rect.top() + 2 + delegateMargin);
const QIcon::State state = isChecked(modelIndex) ? QIcon::State::On : QIcon::State::Off;
- const QPixmap iconPixmap = m_icon.pixmap(window, iconSize, mode, state);
+ const QPixmap iconPixmap = m_icon.pixmap(iconSize, painter->device()->devicePixelRatio(), mode, state);
// Shift the lock icon (last column) slightly to the left due to vertical scrollbar width
if (modelIndex.column() == NavigatorTreeModel::ColumnType::Lock)
diff --git a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
index aacaf6dc0d..223e04fd96 100644
--- a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
+++ b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
@@ -9,9 +9,8 @@
#include "navigatortreeview.h"
#include "navigatorwidget.h"
#include "choosefrompropertylistdialog.h"
-#include "qproxystyle.h"
-
#include <model/modelutils.h>
+#include <dialogutils.h>
#include <modelnodecontextmenu.h>
#include <theme.h>
#include <qmldesignerconstants.h>
@@ -169,8 +168,7 @@ static void setId(const QModelIndex &index, const QString &newId)
return;
if (!ModelNode::isValidId(newId)) {
- Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"),
- NavigatorTreeView::tr("%1 is an invalid id.").arg(newId));
+ DialogUtils::showWarningForInvalidId(newId);
} else if (modelNode.view()->hasId(newId)) {
Core::AsynchronousMessageBox::warning(NavigatorTreeView::tr("Invalid Id"),
NavigatorTreeView::tr("%1 already exists.").arg(newId));
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
index 24d4377ef2..e7fe0ebb77 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
@@ -97,10 +97,10 @@ void LineEdit::paintEvent(QPaintEvent *event)
QPalette p(palette());
p.setColor(QPalette::Active,
QPalette::PlaceholderText,
- Utils::creatorTheme()->color(Utils::Theme::DSplaceholderTextColor));
+ Utils::creatorColor(Utils::Theme::DSplaceholderTextColor));
p.setColor(QPalette::Inactive,
QPalette::PlaceholderText,
- Utils::creatorTheme()->color(Utils::Theme::DSplaceholderTextColor));
+ Utils::creatorColor(Utils::Theme::DSplaceholderTextColor));
setPalette(p);
}
QLineEdit::paintEvent(event);
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index d305753ead..c5fa30fc7d 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -455,7 +455,7 @@ QStringList NavigatorTreeModel::mimeTypes() const
Constants::MIME_TYPE_MATERIAL,
Constants::MIME_TYPE_BUNDLE_TEXTURE,
Constants::MIME_TYPE_BUNDLE_MATERIAL,
- Constants::MIME_TYPE_BUNDLE_EFFECT,
+ Constants::MIME_TYPE_BUNDLE_ITEM,
Constants::MIME_TYPE_ASSETS});
return types;
@@ -570,9 +570,9 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
if (targetNode.isValid())
m_view->emitCustomNotification("drop_bundle_material", {targetNode}); // To ContentLibraryView
- } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_EFFECT)) {
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_ITEM)) {
if (targetNode.isValid())
- m_view->emitCustomNotification("drop_bundle_effect", {targetNode}); // To ContentLibraryView
+ m_view->emitCustomNotification("drop_bundle_item", {targetNode}); // To ContentLibraryView
} else if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
const QStringList assetsPaths = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',');
NodeAbstractProperty targetProperty;
@@ -705,7 +705,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
const ItemLibraryEntry itemLibraryEntry =
createItemLibraryEntryFromMimeData(mimeData->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO));
- const NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry);
+ const NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry, m_view->model());
const QString targetPropertyName = hints.forceNonDefaultProperty();
diff --git a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp
index f99b964f2d..e5e42697e2 100644
--- a/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp
+++ b/src/plugins/qmldesigner/components/navigator/previewtooltip.cpp
@@ -21,7 +21,8 @@ PreviewToolTip::PreviewToolTip(QWidget *parent)
m_ui->idLabel->setElideMode(Qt::ElideLeft);
m_ui->typeLabel->setElideMode(Qt::ElideLeft);
m_ui->infoLabel->setElideMode(Qt::ElideLeft);
- setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name()));
+ setStyleSheet(QString("QWidget { background-color: %1 }")
+ .arg(Utils::creatorColor(Utils::Theme::BackgroundColorNormal).name()));
m_ui->imageLabel->setStyleSheet("background-color: rgba(0, 0, 0, 0)");
static QPixmap checkers;
diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp
index 248a9ec429..4034254420 100644
--- a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp
+++ b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp
@@ -20,7 +20,8 @@ PreviewImageTooltip::PreviewImageTooltip(QWidget *parent)
m_ui->nameLabel->setElideMode(Qt::ElideLeft);
m_ui->pathLabel->setElideMode(Qt::ElideLeft);
m_ui->infoLabel->setElideMode(Qt::ElideLeft);
- setStyleSheet(QString("QWidget { background-color: %1 }").arg(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal).name()));
+ setStyleSheet(QString("QWidget { background-color: %1 }")
+ .arg(Utils::creatorColor(Utils::Theme::BackgroundColorNormal).name()));
}
PreviewImageTooltip::~PreviewImageTooltip() = default;
diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
index 16328ae532..b6d5e2ae47 100644
--- a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
+++ b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
@@ -42,7 +42,18 @@ void PreviewTooltipBackend::showTooltip()
}
});
},
- [](auto) {},
+ [&](ImageCache::AbortReason abortReason) {
+ if (abortReason == ImageCache::AbortReason::Abort) {
+ qWarning() << QLatin1String("PreviewTooltipBackend::showTooltip(): preview generation "
+ "failed for path %1, reason: Abort").arg(m_path);
+ } else if (abortReason == ImageCache::AbortReason::Failed) {
+ qWarning() << QLatin1String("PreviewTooltipBackend::showTooltip(): preview generation "
+ "failed for path %1, reason: Failed").arg(m_path);
+ } else if (abortReason == ImageCache::AbortReason::NoEntry) {
+ qWarning() << QLatin1String("PreviewTooltipBackend::showTooltip(): preview generation "
+ "failed for path %1, reason: NoEntry").arg(m_path);
+ }
+ },
Utils::PathString{m_extraId},
m_auxiliaryData);
diff --git a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
index 45f89ae339..4898366619 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
@@ -143,7 +143,7 @@ QString DynamicPropertiesProxyModel::newPropertyName() const
{
DynamicPropertiesModel *propsModel = dynamicPropertiesModel();
- return QString::fromUtf8(uniquePropertyName("property", propsModel->singleSelectedNode()));
+ return QString::fromUtf8(uniquePropertyName("newName", propsModel->singleSelectedNode()));
}
void DynamicPropertiesProxyModel::createProperty(const QString &name, const QString &type)
@@ -167,6 +167,10 @@ void DynamicPropertiesProxyModel::createProperty(const QString &name, const QStr
QVariant value = defaultValueForType(typeName);
VariantProperty variantProp = modelNode.variantProperty(name.toUtf8());
variantProp.setDynamicTypeNameAndValue(typeName, value);
+ } else if (type == "signal") {
+ SignalDeclarationProperty signalDeclarationProperty
+ = modelNode.signalDeclarationProperty(name.toUtf8());
+ signalDeclarationProperty.setSignature("()");
} else {
QString expression = defaultExpressionForType(typeName);
@@ -270,6 +274,8 @@ PropertyEditorValue *DynamicPropertyRow::createProxyBackendValue()
auto *newValue = new PropertyEditorValue(this);
m_proxyBackendValues.append(newValue);
+ QQmlEngine::setObjectOwnership(newValue, QJSEngine::CppOwnership);
+
return newValue;
}
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
index 591ce5a57f..1a49ce0c39 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
@@ -87,9 +87,9 @@ QString PropertyEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
QColor theColor;
- if (color.canConvert(QVariant::Color)) {
+ if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>();
- } else if (color.canConvert(QVariant::Vector3D)) {
+ } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
}
@@ -586,8 +586,7 @@ int PropertyEditorContextObject::devicePixelRatio()
QStringList PropertyEditorContextObject::styleNamesForFamily(const QString &family)
{
- const QFontDatabase dataBase;
- return dataBase.styles(family);
+ return QFontDatabase::styles(family);
}
QStringList PropertyEditorContextObject::allStatesForId(const QString &id)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
index 7f1ab00bb9..c397d445b1 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
@@ -82,17 +82,18 @@ namespace QmlDesigner {
PropertyEditorQmlBackend::PropertyEditorQmlBackend(PropertyEditorView *propertyEditor,
AsynchronousImageCache &imageCache)
- : m_view(new Quick2PropertyEditorView(imageCache))
- , m_propertyEditorTransaction(new PropertyEditorTransaction(propertyEditor))
- , m_dummyPropertyEditorValue(new PropertyEditorValue())
- , m_contextObject(new PropertyEditorContextObject(m_view))
+ : m_view(Utils::makeUniqueObjectPtr<Quick2PropertyEditorView>(imageCache))
+ , m_propertyEditorTransaction(std::make_unique<PropertyEditorTransaction>(propertyEditor))
+ , m_dummyPropertyEditorValue(std::make_unique<PropertyEditorValue>())
+ , m_contextObject(std::make_unique<PropertyEditorContextObject>(m_view.get()))
{
m_view->engine()->setOutputWarningsToStandardError(QmlDesignerPlugin::instance()
->settings().value(DesignerSettingsKey::SHOW_PROPERTYEDITOR_WARNINGS).toBool());
m_view->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_dummyPropertyEditorValue->setValue(QLatin1String("#000000"));
- context()->setContextProperty(QLatin1String("dummyBackendValue"), m_dummyPropertyEditorValue.data());
+ context()->setContextProperty(QLatin1String("dummyBackendValue"),
+ m_dummyPropertyEditorValue.get());
m_contextObject->setBackendValues(&m_backendValuesPropertyMap);
m_contextObject->setModel(propertyEditor->model());
m_contextObject->insertInQmlContext(context());
@@ -284,6 +285,27 @@ void PropertyEditorQmlBackend::setupAuxiliaryProperties(const QmlObjectNode &qml
}
}
+void PropertyEditorQmlBackend::handleInstancePropertyChangedInModelNodeProxy(
+ const ModelNode &modelNode, const PropertyName &propertyName)
+{
+ m_backendModelNode.handleInstancePropertyChanged(modelNode, propertyName);
+}
+
+void PropertyEditorQmlBackend::handleVariantPropertyChangedInModelNodeProxy(const VariantProperty &property)
+{
+ m_backendModelNode.handleVariantPropertyChanged(property);
+}
+
+void PropertyEditorQmlBackend::handleBindingPropertyChangedInModelNodeProxy(const BindingProperty &property)
+{
+ m_backendModelNode.handleBindingPropertyChanged(property);
+}
+
+void PropertyEditorQmlBackend::handlePropertiesRemovedInModelNodeProxy(const AbstractProperty &property)
+{
+ m_backendModelNode.handlePropertiesRemoved(property);
+}
+
void PropertyEditorQmlBackend::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
const PropertyName &name,
const QVariant &value,
@@ -381,12 +403,12 @@ QQmlContext *PropertyEditorQmlBackend::context()
PropertyEditorContextObject *PropertyEditorQmlBackend::contextObject()
{
- return m_contextObject.data();
+ return m_contextObject.get();
}
QQuickWidget *PropertyEditorQmlBackend::widget()
{
- return m_view;
+ return m_view.get();
}
void PropertyEditorQmlBackend::setSource(const QUrl &url)
@@ -411,7 +433,7 @@ DesignerPropertyMap &PropertyEditorQmlBackend::backendValuesPropertyMap() {
}
PropertyEditorTransaction *PropertyEditorQmlBackend::propertyEditorTransaction() {
- return m_propertyEditorTransaction.data();
+ return m_propertyEditorTransaction.get();
}
PropertyEditorValue *PropertyEditorQmlBackend::propertyValueForName(const QString &propertyName)
@@ -474,12 +496,9 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
// anchors
m_backendAnchorBinding.setup(qmlObjectNode.modelNode());
- context()->setContextProperties(
- QVector<QQmlContext::PropertyPair>{
- {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
- {{"transaction"}, QVariant::fromValue(m_propertyEditorTransaction.data())}
- }
- );
+ context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
+ {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
+ {{"transaction"}, QVariant::fromValue(m_propertyEditorTransaction.get())}});
contextObject()->setHasMultiSelection(
!qmlObjectNode.view()->singleSelectedModelNode().isValid());
@@ -571,13 +590,10 @@ void PropertyEditorQmlBackend::initialSetup(const TypeName &typeName, const QUrl
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(QLatin1String("id"), QVariant::fromValue(valueObject));
- context()->setContextProperties(
- QVector<QQmlContext::PropertyPair>{
- {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
- {{"modelNodeBackend"}, QVariant::fromValue(&m_backendModelNode)},
- {{"transaction"}, QVariant::fromValue(m_propertyEditorTransaction.data())}
- }
- );
+ context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
+ {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
+ {{"modelNodeBackend"}, QVariant::fromValue(&m_backendModelNode)},
+ {{"transaction"}, QVariant::fromValue(m_propertyEditorTransaction.get())}});
contextObject()->setSpecificsUrl(qmlSpecificsFile);
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
index b677258488..1c9b808ac3 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
@@ -3,17 +3,21 @@
#pragma once
-#include "qmlanchorbindingproxy.h"
#include "designerpropertymap.h"
-#include "propertyeditorvalue.h"
#include "propertyeditorcontextobject.h"
+#include "propertyeditorvalue.h"
+#include "qmlanchorbindingproxy.h"
#include "qmlmodelnodeproxy.h"
#include "quick2propertyeditorview.h"
+#include <utils/uniqueobjectptr.h>
+
#include <nodemetainfo.h>
#include <QQmlPropertyMap>
+#include <memory>
+
class PropertyEditorValue;
namespace QmlDesigner {
@@ -71,7 +75,15 @@ public:
PropertyEditorView *propertyEditor);
void setupInsightAttachedProperties(const QmlObjectNode &qmlObjectNode,
PropertyEditorView *propertyEditor);
- void setupAuxiliaryProperties(const QmlObjectNode &qmlObjectNode, PropertyEditorView *propertyEditor);
+ void setupAuxiliaryProperties(const QmlObjectNode &qmlObjectNode,
+ PropertyEditorView *propertyEditor);
+
+ void handleInstancePropertyChangedInModelNodeProxy(const ModelNode &modelNode,
+ const PropertyName &propertyName);
+
+ void handleVariantPropertyChangedInModelNodeProxy(const VariantProperty &property);
+ void handleBindingPropertyChangedInModelNodeProxy(const BindingProperty &property);
+ void handlePropertiesRemovedInModelNodeProxy(const AbstractProperty &property);
static NodeMetaInfo findCommonAncestor(const ModelNode &node);
@@ -92,13 +104,16 @@ private:
static TypeName fixTypeNameForPanes(const TypeName &typeName);
private:
- Quick2PropertyEditorView *m_view;
+ // to avoid a crash while destructing DesignerPropertyMap in the QQmlData
+ // this needs be destructed after m_quickWidget->engine() is destructed
+ DesignerPropertyMap m_backendValuesPropertyMap;
+
+ Utils::UniqueObjectPtr<Quick2PropertyEditorView> m_view = nullptr;
QmlAnchorBindingProxy m_backendAnchorBinding;
QmlModelNodeProxy m_backendModelNode;
- DesignerPropertyMap m_backendValuesPropertyMap;
- QScopedPointer<PropertyEditorTransaction> m_propertyEditorTransaction;
- QScopedPointer<PropertyEditorValue> m_dummyPropertyEditorValue;
- QScopedPointer<PropertyEditorContextObject> m_contextObject;
+ std::unique_ptr<PropertyEditorTransaction> m_propertyEditorTransaction;
+ std::unique_ptr<PropertyEditorValue> m_dummyPropertyEditorValue;
+ std::unique_ptr<PropertyEditorContextObject> m_contextObject;
};
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
index 663ebafb65..27319c15f5 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
@@ -10,16 +10,18 @@
#include "designmodewidget.h"
#include "nodemetainfo.h"
#include "nodeproperty.h"
+#include "propertyeditorview.h"
+#include "qmldesignerplugin.h"
#include "qmlitemnode.h"
#include "qmlobjectnode.h"
-#include "qmldesignerplugin.h"
+#include "rewritertransaction.h"
+#include "rewritingexception.h"
#include <enumeration.h>
#include <utils/qtcassert.h>
#include <QRegularExpression>
-#include <QScopedPointer>
#include <QUrl>
namespace QmlDesigner {
@@ -57,10 +59,10 @@ static bool cleverColorCompare(const QVariant &value1, const QVariant &value2)
return c1.name() == c2.name() && c1.alpha() == c2.alpha();
}
- if (value1.typeId() == QVariant::String && value2.typeId() == QVariant::Color)
+ if (value1.typeId() == QMetaType::QString && value2.typeId() == QVariant::Color)
return cleverColorCompare(QVariant(QColor(value1.toString())), value2);
- if (value1.typeId() == QVariant::Color && value2.typeId() == QVariant::String)
+ if (value1.typeId() == QVariant::Color && value2.typeId() == QMetaType::QString)
return cleverColorCompare(value1, QVariant(QColor(value2.toString())));
return false;
@@ -153,7 +155,8 @@ void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
if (m_expression != expression) {
setExpression(expression);
m_value.clear();
- emit expressionChanged(nameAsQString()); // Note that we set the name in this case
+ emit expressionChanged(nameAsQString());
+ emit expressionChangedQml();// Note that we set the name in this case
}
}
@@ -180,7 +183,7 @@ bool PropertyEditorValue::isInSubState() const
bool PropertyEditorValue::isBound() const
{
const QmlObjectNode objectNode(modelNode());
- return objectNode.isValid() && objectNode.hasBindingProperty(name());
+ return m_forceBound || (objectNode.isValid() && objectNode.hasBindingProperty(name()));
}
bool PropertyEditorValue::isInModel() const
@@ -334,6 +337,7 @@ void PropertyEditorValue::resetValue()
m_expression = QString();
emit valueChanged(nameAsQString(), QVariant());
emit expressionChanged({});
+ emit expressionChangedQml();
}
}
@@ -425,6 +429,34 @@ QStringList PropertyEditorValue::getExpressionAsList() const
return generateStringList(expression());
}
+QVector<double> PropertyEditorValue::getExpressionAsVector() const
+{
+ const QRegularExpression rx(
+ QRegularExpression::anchoredPattern("Qt.vector(2|3|4)d\\((.*?)\\)"));
+ const QRegularExpressionMatch match = rx.match(expression());
+ if (!match.hasMatch())
+ return {};
+
+ const QStringList floats = match.captured(2).split(',', Qt::SkipEmptyParts);
+
+ bool ok;
+
+ const int num = match.captured(1).toInt();
+
+ if (num != floats.count())
+ return {};
+
+ QVector<double> ret;
+ for (const QString &number : floats) {
+ ret.append(number.toDouble(&ok));
+
+ if (!ok)
+ return {};
+ }
+
+ return ret;
+}
+
bool PropertyEditorValue::idListAdd(const QString &value)
{
const QmlObjectNode objectNode(modelNode());
@@ -507,6 +539,32 @@ void PropertyEditorValue::openMaterialEditor(int idx)
m_modelNode.view()->emitCustomNotification("select_material", {}, {idx});
}
+void PropertyEditorValue::setForceBound(bool b)
+{
+ if (m_forceBound == b)
+ return;
+ m_forceBound = b;
+
+ emit isBoundChanged();
+}
+
+void PropertyEditorValue::insertKeyframe()
+{
+ if (!m_modelNode.isValid())
+ return;
+
+ /*If we add more code here we have to forward the property editor view */
+ AbstractView *view = m_modelNode.view();
+
+ QmlTimeline timeline = view->currentTimeline();
+
+ QTC_ASSERT(timeline.isValid(), return );
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ view->executeInTransaction("PropertyEditorContextObject::insertKeyframe",
+ [&] { timeline.insertKeyframe(m_modelNode, name()); });
+}
+
QStringList PropertyEditorValue::generateStringList(const QString &string) const
{
QString copy = string;
@@ -687,4 +745,260 @@ void PropertyEditorNodeWrapper::update()
emit typeChanged();
}
+QQmlPropertyMap *PropertyEditorSubSelectionWrapper::properties()
+{
+ return &m_valuesPropertyMap;
+}
+
+static QObject *variantToQObject(const QVariant &value)
+{
+ if (value.typeId() == QMetaType::QObjectStar || value.typeId() > QMetaType::User)
+ return *(QObject **)value.constData();
+
+ return nullptr;
+}
+
+void PropertyEditorSubSelectionWrapper::createPropertyEditorValue(const QmlObjectNode &qmlObjectNode,
+ const PropertyName &name,
+ const QVariant &value)
+{
+ PropertyName propertyName(name);
+ propertyName.replace('.', '_');
+ auto valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_valuesPropertyMap.value(QString::fromUtf8(propertyName))));
+ if (!valueObject) {
+ valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
+ QObject::connect(valueObject, &PropertyEditorValue::valueChanged, this, &PropertyEditorSubSelectionWrapper::changeValue);
+ QObject::connect(valueObject, &PropertyEditorValue::expressionChanged, this, &PropertyEditorSubSelectionWrapper::changeExpression);
+ QObject::connect(valueObject, &PropertyEditorValue::exportPropertyAsAliasRequested, this, &PropertyEditorSubSelectionWrapper::exportPropertyAsAlias);
+ QObject::connect(valueObject, &PropertyEditorValue::removeAliasExportRequested, this, &PropertyEditorSubSelectionWrapper::removeAliasExport);
+ m_valuesPropertyMap.insert(QString::fromUtf8(propertyName), QVariant::fromValue(valueObject));
+ }
+ valueObject->setName(name);
+ valueObject->setModelNode(qmlObjectNode);
+
+ if (qmlObjectNode.propertyAffectedByCurrentState(name) && !(qmlObjectNode.modelNode().property(name).isBindingProperty()))
+ valueObject->setValue(qmlObjectNode.modelValue(name));
+
+ else
+ valueObject->setValue(value);
+
+ if (propertyName != "id" &&
+ qmlObjectNode.currentState().isBaseState() &&
+ qmlObjectNode.modelNode().property(propertyName).isBindingProperty()) {
+ valueObject->setExpression(qmlObjectNode.modelNode().bindingProperty(propertyName).expression());
+ } else {
+ if (qmlObjectNode.hasBindingProperty(name))
+ valueObject->setExpression(qmlObjectNode.expression(name));
+ else
+ valueObject->setExpression(qmlObjectNode.instanceValue(name).toString());
+ }
+}
+
+void PropertyEditorSubSelectionWrapper::exportPropertyAsAlias(const QString &name)
+{
+ if (name.isNull())
+ return;
+
+ if (locked())
+ return;
+
+ QTC_ASSERT(m_modelNode.isValid(), return);
+
+ view()->executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){
+ PropertyEditorView::generateAliasForProperty(m_modelNode, name);
+ });
+}
+
+void PropertyEditorSubSelectionWrapper::removeAliasExport(const QString &name)
+{
+ if (name.isNull())
+ return;
+
+ if (locked())
+ return;
+
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ view()->executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name]() {
+ PropertyEditorView::removeAliasForProperty(m_modelNode, name);
+ });
+}
+
+bool PropertyEditorSubSelectionWrapper::locked() const
+{
+ return m_locked;
+}
+
+PropertyEditorSubSelectionWrapper::PropertyEditorSubSelectionWrapper(const ModelNode &modelNode)
+ : m_modelNode(modelNode)
+{
+ QmlObjectNode qmlObjectNode(modelNode);
+
+ QTC_ASSERT(qmlObjectNode.isValid(), return );
+
+ for (const auto &property : qmlObjectNode.modelNode().metaInfo().properties()) {
+ auto propertyName = property.name();
+ createPropertyEditorValue(qmlObjectNode,
+ propertyName,
+ qmlObjectNode.instanceValue(propertyName));
+ }
+}
+
+ModelNode PropertyEditorSubSelectionWrapper::modelNode() const
+{
+ return m_modelNode;
+}
+
+void PropertyEditorSubSelectionWrapper::deleteModelNode()
+{
+ QmlObjectNode objectNode(m_modelNode);
+
+ view()->executeInTransaction("PropertyEditorView::changeExpression", [&] {
+ if (objectNode.isValid())
+ objectNode.destroy();
+ });
+}
+
+void PropertyEditorSubSelectionWrapper::changeValue(const QString &name)
+{
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ if (name.isNull())
+ return;
+
+ if (locked())
+ return;
+
+ const QScopeGuard cleanup([&] { m_locked = false; });
+ m_locked = true;
+
+ const NodeMetaInfo metaInfo = m_modelNode.metaInfo();
+ QVariant castedValue;
+ PropertyEditorValue *value = qobject_cast<PropertyEditorValue *>(
+ variantToQObject(m_valuesPropertyMap.value(name)));
+
+ if (auto property = metaInfo.property(name.toUtf8())) {
+ castedValue = property.castedValue(value->value());
+
+ if (castedValue.typeId() == QVariant::Color) {
+ QColor color = castedValue.value<QColor>();
+ QColor newColor = QColor(color.name());
+ newColor.setAlpha(color.alpha());
+ castedValue = QVariant(newColor);
+ }
+
+ if (!value->value().isValid()) { // reset
+ removePropertyFromModel(name.toUtf8());
+ } else {
+ if (castedValue.isValid())
+ commitVariantValueToModel(name.toUtf8(), castedValue);
+ }
+ }
+}
+
+void PropertyEditorSubSelectionWrapper::setValueFromModel(const PropertyName &name,
+ const QVariant &value)
+{
+ m_locked = true;
+
+ QmlObjectNode qmlObjectNode(m_modelNode);
+
+ PropertyName propertyName = name;
+ propertyName.replace('.', '_');
+ auto propertyValue = qobject_cast<PropertyEditorValue *>(
+ variantToQObject(m_valuesPropertyMap.value(QString::fromUtf8(propertyName))));
+ if (propertyValue)
+ propertyValue->setValue(value);
+ m_locked = false;
+}
+
+void PropertyEditorSubSelectionWrapper::resetValue(const PropertyName &name)
+{
+ auto propertyValue = qobject_cast<PropertyEditorValue *>(
+ variantToQObject(m_valuesPropertyMap.value(QString::fromUtf8(name))));
+ if (propertyValue)
+ propertyValue->resetValue();
+}
+
+bool PropertyEditorSubSelectionWrapper::isRelevantModelNode(const ModelNode &modelNode) const
+{
+ QmlObjectNode objectNode(m_modelNode);
+ return modelNode == m_modelNode || objectNode.propertyChangeForCurrentState() == modelNode;
+}
+
+void PropertyEditorSubSelectionWrapper::changeExpression(const QString &propertyName)
+{
+ PropertyName name = propertyName.toUtf8();
+
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ if (name.isNull())
+ return;
+
+ if (locked())
+ return;
+
+ const QScopeGuard cleanup([&] { m_locked = false; });
+ m_locked = true;
+
+ view()->executeInTransaction("PropertyEditorView::changeExpression", [this, name, propertyName] {
+ QmlObjectNode qmlObjectNode{m_modelNode};
+ PropertyEditorValue *value = qobject_cast<PropertyEditorValue *>(
+ variantToQObject(m_valuesPropertyMap.value(propertyName)));
+
+ if (!value) {
+ qWarning() << "PropertyEditor::changeExpression no value for " << propertyName;
+ return;
+ }
+
+ if (value->expression().isEmpty()) {
+ value->resetValue();
+ return;
+ }
+ PropertyEditorView::setExpressionOnObjectNode(qmlObjectNode, name, value->expression());
+ }); /* end of transaction */
+}
+
+void PropertyEditorSubSelectionWrapper::removePropertyFromModel(const PropertyName &propertyName)
+{
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ m_locked = true;
+ try {
+ RewriterTransaction transaction = view()->beginRewriterTransaction(
+ "PropertyEditorView::removePropertyFromModel");
+
+ QmlObjectNode(m_modelNode).removeProperty(propertyName);
+
+ transaction.commit();
+ } catch (const RewritingException &e) {
+ e.showException();
+ }
+ m_locked = false;
+}
+
+void PropertyEditorSubSelectionWrapper::commitVariantValueToModel(const PropertyName &propertyName,
+ const QVariant &value)
+{
+ QTC_ASSERT(m_modelNode.isValid(), return );
+
+ try {
+ RewriterTransaction transaction = view()->beginRewriterTransaction(
+ "PropertyEditorView::commitVariantValueToMode");
+
+ QmlObjectNode(m_modelNode).setVariantProperty(propertyName, value);
+
+ transaction.commit();
+ } catch (const RewritingException &e) {
+ e.showException();
+ }
+}
+
+AbstractView *PropertyEditorSubSelectionWrapper::view() const
+{
+ QTC_CHECK(m_modelNode.isValid());
+
+ return m_modelNode.view();
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
index 59236c4fe2..c4b09f6b5a 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
@@ -14,6 +14,43 @@ namespace QmlDesigner {
class PropertyEditorValue;
+class PropertyEditorSubSelectionWrapper : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQmlPropertyMap *properties READ properties NOTIFY propertiesChanged)
+
+signals:
+ void propertiesChanged();
+
+public:
+ QQmlPropertyMap *properties();
+ PropertyEditorSubSelectionWrapper(const ModelNode &modelNode);
+ ModelNode modelNode() const;
+
+ Q_INVOKABLE void deleteModelNode();
+
+ void setValueFromModel(const PropertyName &name, const QVariant &value);
+ void resetValue(const PropertyName &name);
+
+ bool isRelevantModelNode(const ModelNode &modelNode) const;
+
+private:
+ void changeValue(const QString &name);
+ void changeExpression(const QString &propertyName);
+ void createPropertyEditorValue(const QmlObjectNode &qmlObjectNode, const PropertyName &name, const QVariant &value);
+ void exportPropertyAsAlias(const QString &name);
+ void removeAliasExport(const QString &name);
+ bool locked() const;
+
+ ModelNode m_modelNode;
+ QQmlPropertyMap m_valuesPropertyMap;
+ bool m_locked = false;
+ void removePropertyFromModel(const PropertyName &propertyName);
+ void commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value);
+ AbstractView *view() const;
+};
+
class PropertyEditorNodeWrapper : public QObject
{
Q_OBJECT
@@ -126,12 +163,17 @@ public:
bool isIdList() const;
Q_INVOKABLE QStringList getExpressionAsList() const;
+ Q_INVOKABLE QVector<double> getExpressionAsVector() const;
Q_INVOKABLE bool idListAdd(const QString &value);
Q_INVOKABLE bool idListRemove(int idx);
Q_INVOKABLE bool idListReplace(int idx, const QString &value);
Q_INVOKABLE void commitDrop(const QString &dropData);
Q_INVOKABLE void openMaterialEditor(int idx);
+ Q_INVOKABLE void setForceBound(bool b);
+
+ Q_INVOKABLE void insertKeyframe();
+
public slots:
void resetValue();
void setEnumeration(const QString &scope, const QString &name);
@@ -143,6 +185,8 @@ signals:
void expressionChanged(const QString &name); // HACK - We use the same notifer for the backend and frontend.
// If name is empty the signal is used for QML.
+ void expressionChangedQml();
+
void exportPropertyAsAliasRequested(const QString &name);
void removeAliasExportRequested(const QString &name);
@@ -168,6 +212,7 @@ private:
bool m_hasActiveDrag = false;
bool m_isValid = false; // if the property value belongs to a non-existing complexProperty it is invalid
PropertyEditorNodeWrapper *m_complexNode;
+ bool m_forceBound = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
index 1ff098f4ea..e0d5759617 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
@@ -38,7 +38,6 @@
#include <QFileSystemWatcher>
#include <QQuickItem>
#include <QScopeGuard>
-#include <QScopedPointer>
#include <QShortcut>
#include <QTimer>
@@ -256,66 +255,19 @@ void PropertyEditorView::changeExpression(const QString &propertyName)
underscoreName.replace('.', '_');
QmlObjectNode qmlObjectNode{m_selectedNode};
- PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(QString::fromLatin1(underscoreName));
+ PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(
+ QString::fromUtf8(underscoreName));
if (!value) {
qWarning() << "PropertyEditor::changeExpression no value for " << underscoreName;
return;
}
- if (auto property = qmlObjectNode.modelNode().metaInfo().property(name)) {
- const auto &propertType = property.propertyType();
- if (propertType.isColor()) {
- if (QColor(value->expression().remove('"')).isValid()) {
- qmlObjectNode.setVariantProperty(name, QColor(value->expression().remove('"')));
- return;
- }
- } else if (propertType.isBool()) {
- if (isTrueFalseLiteral(value->expression())) {
- if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
- qmlObjectNode.setVariantProperty(name, true);
- else
- qmlObjectNode.setVariantProperty(name, false);
- return;
- }
- } else if (propertType.isInteger()) {
- bool ok;
- int intValue = value->expression().toInt(&ok);
- if (ok) {
- qmlObjectNode.setVariantProperty(name, intValue);
- return;
- }
- } else if (propertType.isFloat()) {
- bool ok;
- qreal realValue = value->expression().toDouble(&ok);
- if (ok) {
- qmlObjectNode.setVariantProperty(name, realValue);
- return;
- }
- } else if (propertType.isVariant()) {
- bool ok;
- qreal realValue = value->expression().toDouble(&ok);
- if (ok) {
- qmlObjectNode.setVariantProperty(name, realValue);
- return;
- } else if (isTrueFalseLiteral(value->expression())) {
- if (value->expression().compare("true", Qt::CaseInsensitive) == 0)
- qmlObjectNode.setVariantProperty(name, true);
- else
- qmlObjectNode.setVariantProperty(name, false);
- return;
- }
- }
- }
-
if (value->expression().isEmpty()) {
value->resetValue();
return;
}
-
- if (qmlObjectNode.expression(name) != value->expression()
- || !qmlObjectNode.propertyAffectedByCurrentState(name))
- qmlObjectNode.setBindingProperty(name, value->expression());
+ setExpressionOnObjectNode(qmlObjectNode, name, value->expression());
}); /* end of transaction */
}
@@ -330,21 +282,8 @@ void PropertyEditorView::exportPropertyAsAlias(const QString &name)
if (noValidSelection())
return;
- executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){
- const QString id = m_selectedNode.validId();
- QString upperCasePropertyName = name;
- upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper());
- QString aliasName = id + upperCasePropertyName;
- aliasName.replace(".", ""); //remove all dots
-
- PropertyName propertyName = aliasName.toUtf8();
- if (rootModelNode().hasProperty(propertyName)) {
- Core::AsynchronousMessageBox::warning(tr("Cannot Export Property as Alias"),
- tr("Property %1 does already exist for root component.").arg(aliasName));
- return;
- }
- rootModelNode().bindingProperty(propertyName).setDynamicTypeNameAndExpression("alias", id + "." + name);
- });
+ executeInTransaction("PropertyEditorView::exportPropertyAsAlias",
+ [this, name]() { generateAliasForProperty(m_selectedNode, name); });
}
void PropertyEditorView::removeAliasExport(const QString &name)
@@ -358,15 +297,8 @@ void PropertyEditorView::removeAliasExport(const QString &name)
if (noValidSelection())
return;
- executeInTransaction("PropertyEditorView::exportPropertyAsAlias", [this, name](){
- const QString id = m_selectedNode.validId();
-
- for (const BindingProperty &property : rootModelNode().bindingProperties())
- if (property.expression() == (id + "." + name)) {
- rootModelNode().removeProperty(property.name());
- break;
- }
- });
+ executeInTransaction("PropertyEditorView::exportPropertyAsAlias",
+ [this, name]() { removeAliasForProperty(m_selectedNode, name); });
}
bool PropertyEditorView::locked() const
@@ -384,11 +316,113 @@ void PropertyEditorView::refreshMetaInfos(const TypeIds &deletedTypeIds)
m_propertyComponentGenerator.refreshMetaInfos(deletedTypeIds);
}
+void PropertyEditorView::setExpressionOnObjectNode(const QmlObjectNode &constObjectNode,
+ const PropertyName &name,
+ const QString &newExpression)
+{
+ auto qmlObjectNode = constObjectNode;
+ auto expression = newExpression;
+ if (auto property = qmlObjectNode.modelNode().metaInfo().property(name)) {
+ const auto &propertType = property.propertyType();
+ if (propertType.isColor()) {
+ if (QColor(expression.remove('"')).isValid()) {
+ qmlObjectNode.setVariantProperty(name, QColor(expression.remove('"')));
+ return;
+ }
+ } else if (propertType.isBool()) {
+ if (isTrueFalseLiteral(expression)) {
+ if (expression.compare("true", Qt::CaseInsensitive) == 0)
+ qmlObjectNode.setVariantProperty(name, true);
+ else
+ qmlObjectNode.setVariantProperty(name, false);
+ return;
+ }
+ } else if (propertType.isInteger()) {
+ bool ok;
+ int intValue = expression.toInt(&ok);
+ if (ok) {
+ qmlObjectNode.setVariantProperty(name, intValue);
+ return;
+ }
+ } else if (propertType.isFloat()) {
+ bool ok;
+ qreal realValue = expression.toDouble(&ok);
+ if (ok) {
+ qmlObjectNode.setVariantProperty(name, realValue);
+ return;
+ }
+ } else if (propertType.isVariant()) {
+ bool ok;
+ qreal realValue = expression.toDouble(&ok);
+ if (ok) {
+ qmlObjectNode.setVariantProperty(name, realValue);
+ return;
+ } else if (isTrueFalseLiteral(expression)) {
+ if (expression.compare("true", Qt::CaseInsensitive) == 0)
+ qmlObjectNode.setVariantProperty(name, true);
+ else
+ qmlObjectNode.setVariantProperty(name, false);
+ return;
+ }
+ }
+ }
+
+ if (qmlObjectNode.expression(name) != expression
+ || !qmlObjectNode.propertyAffectedByCurrentState(name))
+ qmlObjectNode.setBindingProperty(name, expression);
+}
+
+void PropertyEditorView::generateAliasForProperty(const ModelNode &modelNode, const QString &name)
+{
+ QTC_ASSERT(modelNode.isValid(), return );
+
+ auto view = modelNode.view();
+
+ auto rootNode = view->rootModelNode();
+
+ auto nonConstModelNode = modelNode;
+ const QString id = nonConstModelNode.validId();
+
+ QString upperCasePropertyName = name;
+ upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper());
+ QString aliasName = id + upperCasePropertyName;
+ aliasName.replace(".", ""); //remove all dots
+
+ PropertyName propertyName = aliasName.toUtf8();
+ if (rootNode.hasProperty(propertyName)) {
+ Core::AsynchronousMessageBox::warning(
+ tr("Cannot Export Property as Alias"),
+ tr("Property %1 does already exist for root component.").arg(aliasName));
+ return;
+ }
+ rootNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression("alias", id + "." + name);
+}
+
+void PropertyEditorView::removeAliasForProperty(const ModelNode &modelNode, const QString &propertyName)
+{
+ QTC_ASSERT(modelNode.isValid(), return );
+
+ auto view = modelNode.view();
+
+ auto rootNode = view->rootModelNode();
+
+ auto nonConstModelNode = modelNode;
+
+ const QString id = nonConstModelNode.validId();
+
+ for (const BindingProperty &property : rootNode.bindingProperties()) {
+ if (property.expression() == (id + "." + propertyName)) {
+ rootNode.removeProperty(property.name());
+ break;
+ }
+ }
+}
+
void PropertyEditorView::updateSize()
{
if (!m_qmlBackEndForCurrentType)
return;
- auto frame = m_qmlBackEndForCurrentType->widget()->findChild<QWidget*>("propertyEditorFrame");
+ auto frame = m_qmlBackEndForCurrentType->widget()->findChild<QWidget *>("propertyEditorFrame");
if (frame)
frame->resize(m_stackedWidget->size());
}
@@ -747,7 +781,11 @@ void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
if (noValidSelection())
return;
+ QTC_ASSERT(m_qmlBackEndForCurrentType, return );
+
for (const AbstractProperty &property : propertyList) {
+ m_qmlBackEndForCurrentType->handlePropertiesRemovedInModelNodeProxy(property);
+
ModelNode node(property.parentModelNode());
if (node.isRootNode() && !m_selectedNode.isRootNode())
@@ -805,7 +843,11 @@ void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>&
if (noValidSelection())
return;
+ QTC_ASSERT(m_qmlBackEndForCurrentType, return );
+
for (const VariantProperty &property : propertyList) {
+ m_qmlBackEndForCurrentType->handleVariantPropertyChangedInModelNodeProxy(property);
+
ModelNode node(property.parentModelNode());
if (propertyIsAttachedLayoutProperty(property.name()))
@@ -830,7 +872,11 @@ void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty> &
if (locked() || noValidSelection())
return;
+ QTC_ASSERT(m_qmlBackEndForCurrentType, return );
+
for (const BindingProperty &property : propertyList) {
+ m_qmlBackEndForCurrentType->handleBindingPropertyChangedInModelNodeProxy(property);
+
ModelNode node(property.parentModelNode());
if (property.isAliasExport())
@@ -952,6 +998,9 @@ void PropertyEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
{
if (!m_selectedNode.isValid())
return;
+
+ QTC_ASSERT(m_qmlBackEndForCurrentType, return );
+
m_locked = true;
using ModelNodePropertyPair = QPair<ModelNode, PropertyName>;
@@ -960,7 +1009,11 @@ void PropertyEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
const QmlObjectNode qmlObjectNode(modelNode);
const PropertyName propertyName = propertyPair.second;
- if (qmlObjectNode.isValid() && m_qmlBackEndForCurrentType && modelNode == m_selectedNode && qmlObjectNode.currentState().isValid()) {
+ m_qmlBackEndForCurrentType->handleInstancePropertyChangedInModelNodeProxy(modelNode,
+ propertyName);
+
+ if (qmlObjectNode.isValid() && m_qmlBackEndForCurrentType && modelNode == m_selectedNode
+ && qmlObjectNode.currentState().isValid()) {
const AbstractProperty property = modelNode.property(propertyName);
if (modelNode == m_selectedNode || qmlObjectNode.propertyChangeForCurrentState() == qmlObjectNode) {
if ( !modelNode.hasProperty(propertyName) || modelNode.property(property.name()).isBindingProperty() )
@@ -969,7 +1022,6 @@ void PropertyEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pr
setValue(modelNode, property.name(), qmlObjectNode.modelValue(property.name()));
}
}
-
}
m_locked = false;
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
index cc9b522839..ef2b71f558 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
@@ -84,6 +84,16 @@ public:
void refreshMetaInfos(const TypeIds &deletedTypeIds) override;
+ static void setExpressionOnObjectNode(const QmlObjectNode &objectNode,
+ const PropertyName &name,
+ const QString &expression);
+
+ static void generateAliasForProperty(const ModelNode &modelNode,
+ const QString &propertyName);
+
+ static void removeAliasForProperty(const ModelNode &modelNode,
+ const QString &propertyName);
+
protected:
void timerEvent(QTimerEvent *event) override;
void setupPane(const TypeName &typeName);
diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp
index 96ec5f92e7..1cff0e55e6 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp
@@ -4,6 +4,15 @@
#include "abstractview.h"
#include "qmlmodelnodeproxy.h"
+#include <nodemetainfo.h>
+
+#include <nodeabstractproperty.h>
+#include <nodelistproperty.h>
+#include <variantproperty.h>
+
+#include <utils/qtcassert.h>
+#include <utils/algorithm.h>
+
#include <QtQml>
namespace QmlDesigner {
@@ -17,6 +26,8 @@ void QmlModelNodeProxy::setup(const QmlObjectNode &objectNode)
{
m_qmlObjectNode = objectNode;
+ m_subselection.clear();
+
emit modelNodeChanged();
}
@@ -75,4 +86,229 @@ QString QmlModelNodeProxy::simplifiedTypeName() const
return m_qmlObjectNode.simplifiedTypeName();
}
+static QList<int> toInternalIdList(const QList<ModelNode> &nodes)
+{
+ return Utils::transform(nodes, [](const ModelNode &node) { return node.internalId(); });
+}
+
+QList<int> QmlModelNodeProxy::allChildren(int internalId) const
+{
+ ModelNode modelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(modelNode.isValid(), return {});
+
+ if (internalId >= 0)
+ modelNode = modelNode.view()->modelNodeForInternalId(internalId);
+
+ return allChildren(modelNode);
+}
+
+QList<int> QmlModelNodeProxy::allChildrenOfType(const QString &typeName, int internalId) const
+{
+ ModelNode modelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(modelNode.isValid(), return {});
+
+ if (internalId >= 0)
+ modelNode = modelNode.view()->modelNodeForInternalId(internalId);
+
+ return allChildrenOfType(modelNode, typeName);
+}
+
+QString QmlModelNodeProxy::simplifiedTypeName(int internalId) const
+{
+ ModelNode modelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(modelNode.isValid(), return {});
+
+ return modelNode.view()->modelNodeForInternalId(internalId).simplifiedTypeName();
+}
+
+PropertyEditorSubSelectionWrapper *QmlModelNodeProxy::findWrapper(int internalId) const
+{
+ for (const auto &item : qAsConst(m_subselection)) {
+ if (item->modelNode().internalId() == internalId)
+ return item.data();
+ }
+
+ return nullptr;
+}
+
+PropertyEditorSubSelectionWrapper *QmlModelNodeProxy::registerSubSelectionWrapper(int internalId)
+{
+ auto result = findWrapper(internalId);
+
+ if (result)
+ return result;
+
+ QTC_ASSERT(m_qmlObjectNode.isValid(), return nullptr);
+
+ ModelNode node = m_qmlObjectNode.view()->modelNodeForInternalId(internalId);
+
+ QTC_ASSERT(node.isValid(), return nullptr);
+
+ QSharedPointer<PropertyEditorSubSelectionWrapper> wrapper(
+ new PropertyEditorSubSelectionWrapper(node));
+ m_subselection.append(wrapper);
+
+ QJSEngine::setObjectOwnership(wrapper.data(), QJSEngine::CppOwnership);
+
+ return wrapper.data();
+}
+
+void QmlModelNodeProxy::createModelNode(int internalIdParent,
+ const QString &property,
+ const QString &typeName,
+ const QString &requiredImport)
+{
+ auto parentModelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(parentModelNode.isValid(), return );
+
+ AbstractView *view = parentModelNode.view();
+
+ if (internalIdParent >= 0)
+ parentModelNode = view->modelNodeForInternalId(internalIdParent);
+
+ QTC_ASSERT(parentModelNode.isValid(), return );
+
+ Import import;
+ Q_ASSERT(import.isEmpty());
+
+ if (!requiredImport.isEmpty() && !view->model()->hasImport(requiredImport))
+ import = Import::createLibraryImport(requiredImport);
+
+ view->executeInTransaction("QmlModelNodeProxy::createModelNode", [&] {
+ if (!import.isEmpty())
+ view->model()->changeImports({import}, {});
+
+#ifdef QDS_USE_PROJECTSTORAGE
+ ModelNode newNode = view->createModelNode(typeName.toUtf8());
+#else
+ NodeMetaInfo metaInfo = parentModelNode.model()->metaInfo(typeName.toUtf8());
+ ModelNode newNode = view->createModelNode(metaInfo.typeName(),
+ metaInfo.majorVersion(),
+ metaInfo.minorVersion());
+#endif
+ parentModelNode.nodeAbstractProperty(property.toUtf8()).reparentHere(newNode);
+ });
+}
+
+void QmlModelNodeProxy::moveNode(int internalIdParent,
+ const QString &propertyName,
+ int fromIndex,
+ int toIndex)
+{
+ ModelNode modelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(modelNode.isValid(), return );
+
+ if (internalIdParent >= 0)
+ modelNode = m_qmlObjectNode.view()->modelNodeForInternalId(internalIdParent);
+
+ QTC_ASSERT(modelNode.isValid(), return );
+ AbstractView *view = m_qmlObjectNode.view();
+ view->executeInTransaction("QmlModelNodeProxy::moveNode", [&] {
+ modelNode.nodeListProperty(propertyName.toUtf8()).slide(fromIndex, toIndex);
+ });
+}
+
+bool QmlModelNodeProxy::isInstanceOf(const QString &typeName, int internalId) const
+{
+ ModelNode modelNode = m_qmlObjectNode.modelNode();
+
+ QTC_ASSERT(modelNode.isValid(), return {});
+
+ if (internalId >= 0)
+ modelNode = modelNode.view()->modelNodeForInternalId(internalId);
+
+ NodeMetaInfo metaInfo = modelNode.model()->metaInfo(typeName.toUtf8());
+
+ return modelNode.metaInfo().isBasedOn(metaInfo);
+}
+
+void QmlModelNodeProxy::changeType(int internalId, const QString &typeName)
+{
+ QTC_ASSERT(m_qmlObjectNode.isValid(), return );
+
+ ModelNode node = m_qmlObjectNode.view()->modelNodeForInternalId(internalId);
+
+ QTC_ASSERT(node.isValid(), return );
+
+ QTC_ASSERT(!node.isRootNode(), return );
+#ifdef QDS_USE_PROJECTSTORAGE
+ node.changeType(typeName.toUtf8(), -1, -1);
+#else
+ NodeMetaInfo metaInfo = node.model()->metaInfo(typeName.toUtf8());
+ node.changeType(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion());
+#endif
+}
+
+void QmlModelNodeProxy::handleInstancePropertyChanged(const ModelNode &modelNode,
+ const PropertyName &propertyName)
+{
+ const QmlObjectNode qmlObjectNode(modelNode);
+
+ for (const auto &item : qAsConst(m_subselection)) {
+ if (item && item->isRelevantModelNode(modelNode)) {
+ if (!modelNode.hasProperty(propertyName)
+ || modelNode.property(propertyName).isBindingProperty()) {
+ item->setValueFromModel(propertyName, qmlObjectNode.instanceValue(propertyName));
+ } else {
+ item->setValueFromModel(propertyName, qmlObjectNode.modelValue(propertyName));
+ }
+ }
+ }
+}
+
+void QmlModelNodeProxy::handleBindingPropertyChanged(const BindingProperty &property)
+{
+ for (const auto &item : qAsConst(m_subselection)) {
+ if (item && item->isRelevantModelNode(property.parentModelNode())) {
+ QmlObjectNode objectNode(item->modelNode());
+ if (objectNode.modelNode().property(property.name()).isBindingProperty())
+ item->setValueFromModel(property.name(), objectNode.instanceValue(property.name()));
+ else
+ item->setValueFromModel(property.name(), objectNode.modelValue(property.name()));
+ }
+ }
+}
+
+void QmlModelNodeProxy::handleVariantPropertyChanged(const VariantProperty &property)
+{
+ for (const auto &item : qAsConst(m_subselection)) {
+ if (item && item->isRelevantModelNode(property.parentModelNode())) {
+ QmlObjectNode objectNode(item->modelNode());
+ if (objectNode.modelNode().property(property.name()).isBindingProperty())
+ item->setValueFromModel(property.name(), objectNode.instanceValue(property.name()));
+ else
+ item->setValueFromModel(property.name(), objectNode.modelValue(property.name()));
+ }
+ }
+}
+
+void QmlModelNodeProxy::handlePropertiesRemoved(const AbstractProperty &property)
+{
+ for (const auto &item : qAsConst(m_subselection)) {
+ if (item && item->isRelevantModelNode(property.parentModelNode())) {
+ QmlObjectNode objectNode(item->modelNode());
+ item->resetValue(property.name());
+ item->setValueFromModel(property.name(), objectNode.instanceValue(property.name()));
+ }
+ }
+}
+
+QList<int> QmlModelNodeProxy::allChildren(const ModelNode &modelNode) const
+{
+ return toInternalIdList(modelNode.directSubModelNodes());
+}
+
+QList<int> QmlModelNodeProxy::allChildrenOfType(const ModelNode &modelNode, const QString &typeName) const
+{
+ QTC_ASSERT(modelNode.isValid(), return {});
+
+ NodeMetaInfo metaInfo = modelNode.model()->metaInfo(typeName.toUtf8());
+
+ return toInternalIdList(modelNode.directSubModelNodesOfType(metaInfo));
}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h
index 4740b01fbd..d8a49d7e10 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.h
@@ -3,6 +3,8 @@
#pragma once
+#include "propertyeditorvalue.h"
+
#include <qmlitemnode.h>
#include <QObject>
@@ -16,6 +18,7 @@ class QMLDESIGNERCORE_EXPORT QmlModelNodeProxy : public QObject
Q_PROPERTY(QmlDesigner::ModelNode modelNode READ modelNode NOTIFY modelNodeChanged)
Q_PROPERTY(bool multiSelection READ multiSelection NOTIFY modelNodeChanged)
+
public:
explicit QmlModelNodeProxy(QObject *parent = nullptr);
@@ -36,13 +39,45 @@ public:
QString simplifiedTypeName() const;
+ Q_INVOKABLE QList<int> allChildren(int internalId = -1) const;
+ Q_INVOKABLE QList<int> allChildrenOfType(const QString &typeName, int internalId = -1) const;
+
+ Q_INVOKABLE QString simplifiedTypeName(int internalId) const;
+
+ Q_INVOKABLE PropertyEditorSubSelectionWrapper *registerSubSelectionWrapper(int internalId);
+
+ Q_INVOKABLE void createModelNode(int internalIdParent,
+ const QString &property,
+ const QString &typeName,
+ const QString &requiredImport = {});
+
+ Q_INVOKABLE void moveNode(int internalIdParent,
+ const QString &propertyName,
+ int fromIndex,
+ int toIndex);
+
+ Q_INVOKABLE bool isInstanceOf(const QString &typeName, int internalId = -1) const;
+
+ Q_INVOKABLE void changeType(int internalId, const QString &typeName);
+
+ void handleInstancePropertyChanged(const ModelNode &modelNode, const PropertyName &propertyName);
+
+ void handleBindingPropertyChanged(const BindingProperty &property);
+ void handleVariantPropertyChanged(const VariantProperty &property);
+ void handlePropertiesRemoved(const AbstractProperty &property);
+
signals:
void modelNodeChanged();
void selectionToBeChanged();
void selectionChanged();
private:
+ QList<int> allChildren(const ModelNode &modelNode) const;
+ QList<int> allChildrenOfType(const ModelNode &modelNode, const QString &typeName) const;
+ PropertyEditorSubSelectionWrapper *findWrapper(int internalId) const;
+
QmlObjectNode m_qmlObjectNode;
+ QList<QSharedPointer<PropertyEditorSubSelectionWrapper>> m_subselection;
};
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp
index a8981ff2f0..3f6f6769fb 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp
@@ -15,7 +15,8 @@ TextEditorStatusBar::TextEditorStatusBar(QWidget *parent) : QToolBar(parent), m_
addWidget(m_label);
/* We have to set another .css, since the central widget has already a style sheet */
- m_label->setStyleSheet(QString("QLabel { color :%1 }").arg(Utils::creatorTheme()->color(Utils::Theme::TextColorError).name()));
+ m_label->setStyleSheet(QString("QLabel { color :%1 }")
+ .arg(Utils::creatorColor(Utils::Theme::TextColorError).name()));
}
void TextEditorStatusBar::clearText()
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
index d400251648..2e52b3358b 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
@@ -96,7 +96,8 @@ void TextEditorView::modelAboutToBeDetached(Model *model)
{
AbstractView::modelAboutToBeDetached(model);
- m_widget->setTextEditor(nullptr);
+ if (m_widget)
+ m_widget->setTextEditor(nullptr);
// in case the user closed it explicit we do not want to do anything with the editor
if (Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN) {
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
index 97ef6c4b68..127780f918 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
@@ -265,7 +265,7 @@ void TextEditorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
void TextEditorWidget::dragMoveEvent(QDragMoveEvent *dragMoveEvent)
{
- QTextCursor cursor = m_textEditor->editorWidget()->cursorForPosition(dragMoveEvent->pos());
+ QTextCursor cursor = m_textEditor->editorWidget()->cursorForPosition(dragMoveEvent->position().toPoint());
const int cursorPosition = cursor.position();
RewriterView *rewriterView = m_textEditorView->model()->rewriterView();
@@ -279,7 +279,7 @@ void TextEditorWidget::dragMoveEvent(QDragMoveEvent *dragMoveEvent)
void TextEditorWidget::dropEvent(QDropEvent *dropEvent)
{
- QTextCursor cursor = m_textEditor->editorWidget()->cursorForPosition(dropEvent->pos());
+ QTextCursor cursor = m_textEditor->editorWidget()->cursorForPosition(dropEvent->position().toPoint());
const int cursorPosition = cursor.position();
RewriterView *rewriterView = m_textEditorView->model()->rewriterView();
diff --git a/src/plugins/qmldesigner/components/texttool/textedititemwidget.cpp b/src/plugins/qmldesigner/components/texttool/textedititemwidget.cpp
index b9c5868bd8..dc57cf30c8 100644
--- a/src/plugins/qmldesigner/components/texttool/textedititemwidget.cpp
+++ b/src/plugins/qmldesigner/components/texttool/textedititemwidget.cpp
@@ -38,26 +38,26 @@ void TextEditItemWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem
QLineEdit* TextEditItemWidget::lineEdit() const
{
- if (m_lineEdit.isNull()) {
- m_lineEdit.reset(new QLineEdit);
+ if (!m_lineEdit) {
+ m_lineEdit = std::make_unique<QLineEdit>();
m_lineEdit->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
QPalette palette = m_lineEdit->palette();
- static QColor selectionColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
+ static QColor selectionColor = Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
palette.setColor(QPalette::Highlight, selectionColor);
palette.setColor(QPalette::HighlightedText, Qt::white);
palette.setColor(QPalette::Base, Qt::white);
palette.setColor(QPalette::Text, Qt::black);
m_lineEdit->setPalette(palette);
}
- return m_lineEdit.data();
+ return m_lineEdit.get();
}
QTextEdit* TextEditItemWidget::textEdit() const
{
- if (m_textEdit.isNull()) {
- m_textEdit.reset(new QTextEdit);
+ if (!m_textEdit) {
+ m_textEdit = std::make_unique<QTextEdit>();
QPalette palette = m_textEdit->palette();
- static QColor selectionColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
+ static QColor selectionColor = Utils::creatorColor(Utils::Theme::QmlDesigner_FormEditorSelectionColor);
palette.setColor(QPalette::Highlight, selectionColor);
palette.setColor(QPalette::HighlightedText, Qt::white);
palette.setColor(QPalette::Base, Qt::white);
@@ -65,7 +65,7 @@ QTextEdit* TextEditItemWidget::textEdit() const
m_textEdit->setPalette(palette);
}
- return m_textEdit.data();
+ return m_textEdit.get();
}
void TextEditItemWidget::activateTextEdit(const QSize &maximumSize)
@@ -83,19 +83,19 @@ void TextEditItemWidget::activateLineEdit()
QString TextEditItemWidget::text() const
{
- if (widget() == m_lineEdit.data())
+ if (widget() == m_lineEdit.get())
return m_lineEdit->text();
- else if (widget() == m_textEdit.data())
+ else if (widget() == m_textEdit.get())
return m_textEdit->toPlainText();
return QString();
}
void TextEditItemWidget::updateText(const QString &text)
{
- if (widget() == m_lineEdit.data()) {
+ if (widget() == m_lineEdit.get()) {
m_lineEdit->setText(text);
m_lineEdit->selectAll();
- } else if (widget() == m_textEdit.data()) {
+ } else if (widget() == m_textEdit.get()) {
m_textEdit->setText(text);
m_textEdit->selectAll();
}
diff --git a/src/plugins/qmldesigner/components/texttool/textedititemwidget.h b/src/plugins/qmldesigner/components/texttool/textedititemwidget.h
index 8aa6c409f9..f975f1a3da 100644
--- a/src/plugins/qmldesigner/components/texttool/textedititemwidget.h
+++ b/src/plugins/qmldesigner/components/texttool/textedititemwidget.h
@@ -3,7 +3,8 @@
#pragma once
#include <QGraphicsProxyWidget>
-#include <QScopedPointer>
+
+#include <memory>
QT_BEGIN_NAMESPACE
class QTextEdit;
@@ -32,7 +33,7 @@ protected:
QString text() const;
private:
- mutable QScopedPointer<QLineEdit> m_lineEdit;
- mutable QScopedPointer<QTextEdit> m_textEdit;
+ mutable std::unique_ptr<QLineEdit> m_lineEdit;
+ mutable std::unique_ptr<QTextEdit> m_textEdit;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
index 73e784846b..30f276a48d 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
@@ -47,9 +47,9 @@ QString TextureEditorContextObject::convertColorToString(const QVariant &color)
{
QString colorString;
QColor theColor;
- if (color.canConvert(QVariant::Color)) {
+ if (color.canConvert(QMetaType(QMetaType::QColor))) {
theColor = color.value<QColor>();
- } else if (color.canConvert(QVariant::Vector3D)) {
+ } else if (color.canConvert(QMetaType(QMetaType::QVector3D))) {
auto vec = color.value<QVector3D>();
theColor = QColor::fromRgbF(vec.x(), vec.y(), vec.z());
}
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
index 80cf5693d2..415d943723 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
@@ -42,21 +42,22 @@ static QObject *variantToQObject(const QVariant &value)
namespace QmlDesigner {
-TextureEditorQmlBackend::TextureEditorQmlBackend(TextureEditorView *textureEditor, AsynchronousImageCache &imageCache)
- : m_view(new QQuickWidget)
- , m_textureEditorTransaction(new TextureEditorTransaction(textureEditor))
- , m_contextObject(new TextureEditorContextObject(m_view->rootContext()))
+TextureEditorQmlBackend::TextureEditorQmlBackend(TextureEditorView *textureEditor,
+ AsynchronousImageCache &imageCache)
+ : m_quickWidget(Utils::makeUniqueObjectPtr<QQuickWidget>())
+ , m_textureEditorTransaction(std::make_unique<TextureEditorTransaction>(textureEditor))
+ , m_contextObject(std::make_unique<TextureEditorContextObject>(m_quickWidget->rootContext()))
{
QImage defaultImage;
defaultImage.load(Utils::StyleHelper::dpiSpecificImageFile(":/textureeditor/images/texture_default.png"));
m_textureEditorImageProvider = new AssetImageProvider(imageCache, defaultImage);
- m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
- m_view->setObjectName(Constants::OBJECT_NAME_TEXTURE_EDITOR);
- m_view->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
- m_view->engine()->addImageProvider("qmldesigner_thumbnails", m_textureEditorImageProvider);
+ m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ m_quickWidget->setObjectName(Constants::OBJECT_NAME_TEXTURE_EDITOR);
+ m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+ m_quickWidget->engine()->addImageProvider("qmldesigner_thumbnails", m_textureEditorImageProvider);
m_contextObject->setBackendValues(&m_backendValuesPropertyMap);
m_contextObject->setModel(textureEditor->model());
- context()->setContextObject(m_contextObject.data());
+ context()->setContextObject(m_contextObject.get());
QObject::connect(&m_backendValuesPropertyMap, &DesignerPropertyMap::valueChanged,
textureEditor, &TextureEditorView::changeValue);
@@ -154,22 +155,22 @@ void TextureEditorQmlBackend::setValue(const QmlObjectNode &, const PropertyName
QQmlContext *TextureEditorQmlBackend::context() const
{
- return m_view->rootContext();
+ return m_quickWidget->rootContext();
}
TextureEditorContextObject *TextureEditorQmlBackend::contextObject() const
{
- return m_contextObject.data();
+ return m_contextObject.get();
}
QQuickWidget *TextureEditorQmlBackend::widget() const
{
- return m_view;
+ return m_quickWidget.get();
}
void TextureEditorQmlBackend::setSource(const QUrl &url)
{
- m_view->setSource(url);
+ m_quickWidget->setSource(url);
}
QmlAnchorBindingProxy &TextureEditorQmlBackend::backendAnchorBinding()
@@ -184,7 +185,7 @@ DesignerPropertyMap &TextureEditorQmlBackend::backendValuesPropertyMap()
TextureEditorTransaction *TextureEditorQmlBackend::textureEditorTransaction() const
{
- return m_textureEditorTransaction.data();
+ return m_textureEditorTransaction.get();
}
PropertyEditorValue *TextureEditorQmlBackend::propertyValueForName(const QString &propertyName)
@@ -227,12 +228,9 @@ void TextureEditorQmlBackend::setup(const QmlObjectNode &selectedTextureNode, co
// anchors
m_backendAnchorBinding.setup(selectedTextureNode.modelNode());
- context()->setContextProperties(
- QVector<QQmlContext::PropertyPair>{
- {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
- {{"transaction"}, QVariant::fromValue(m_textureEditorTransaction.data())}
- }
- );
+ context()->setContextProperties(QVector<QQmlContext::PropertyPair>{
+ {{"anchorBackend"}, QVariant::fromValue(&m_backendAnchorBinding)},
+ {{"transaction"}, QVariant::fromValue(m_textureEditorTransaction.get())}});
contextObject()->setSpecificsUrl(qmlSpecificsFile);
contextObject()->setStateName(stateName);
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
index b6d3fddf22..f69c46a569 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
@@ -7,8 +7,12 @@
#include "qmlanchorbindingproxy.h"
#include "qmlmodelnodeproxy.h"
+#include <utils/uniqueobjectptr.h>
+
#include <nodemetainfo.h>
+#include <memory>
+
class PropertyEditorValue;
QT_BEGIN_NAMESPACE
@@ -58,12 +62,15 @@ private:
TextureEditorView *textureEditor);
PropertyName auxNamePostFix(const PropertyName &propertyName);
- QQuickWidget *m_view = nullptr;
+ // to avoid a crash while destructing DesignerPropertyMap in the QQmlData
+ // this needs be destructed after m_quickWidget->engine() is destructed
+ DesignerPropertyMap m_backendValuesPropertyMap;
+
+ Utils::UniqueObjectPtr<QQuickWidget> m_quickWidget;
QmlAnchorBindingProxy m_backendAnchorBinding;
QmlModelNodeProxy m_backendModelNode;
- DesignerPropertyMap m_backendValuesPropertyMap;
- QScopedPointer<TextureEditorTransaction> m_textureEditorTransaction;
- QScopedPointer<TextureEditorContextObject> m_contextObject;
+ std::unique_ptr<TextureEditorTransaction> m_textureEditorTransaction;
+ std::unique_ptr<TextureEditorContextObject> m_contextObject;
AssetImageProvider *m_textureEditorImageProvider = nullptr;
};
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
index 5de3730c97..a637431c4d 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
@@ -43,7 +43,6 @@
#include <QFileInfo>
#include <QQuickWidget>
#include <QQuickItem>
-#include <QScopedPointer>
#include <QStackedWidget>
#include <QShortcut>
#include <QTimer>
@@ -698,7 +697,8 @@ void TextureEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNod
m_selectedModel = selectedNodeList.at(0);
bool hasValidSelection = QmlObjectNode(m_selectedModel).hasBindingProperty("materials");
- m_qmlBackEnd->contextObject()->setHasSingleModelSelection(hasValidSelection);
+ if (m_qmlBackEnd)
+ m_qmlBackEnd->contextObject()->setHasSingleModelSelection(hasValidSelection);
}
void TextureEditorView::currentStateChanged(const ModelNode &node)
diff --git a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp
index 2d8998404a..f289583cc3 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/setframevaluedialog.cpp
@@ -40,7 +40,7 @@ SetFrameValueDialog::SetFrameValueDialog(qreal frame, const QVariant &value,
valueLabel->setAlignment(Qt::AlignRight);
valueLabel->setFixedWidth(labelWidth);
- m_frameControl->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
+ m_frameControl->setRange(std::numeric_limits<int>::lowest(), std::numeric_limits<int>::max());
m_frameControl->setValue(static_cast<int>(frame));
m_frameControl->setAlignment(Qt::AlignRight);
@@ -86,7 +86,6 @@ QWidget* SetFrameValueDialog::createValueControl(const QVariant& value)
switch (value.metaType().id())
{
-
case QMetaType::QColor: {
auto* widget = new ColorControl(value.value<QColor>());
m_valueGetter = [widget]() { return widget->value(); };
@@ -102,7 +101,7 @@ QWidget* SetFrameValueDialog::createValueControl(const QVariant& value)
case QMetaType::Int: {
auto* widget = new QSpinBox;
- widget->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
+ widget->setRange(std::numeric_limits<int>::lowest(), std::numeric_limits<int>::max());
widget->setAlignment(Qt::AlignRight);
widget->setValue(value.toInt());
m_valueGetter = [widget]() { return widget->value(); };
@@ -120,7 +119,7 @@ QWidget* SetFrameValueDialog::createValueControl(const QVariant& value)
case QMetaType::Float: {
auto* widget = new QDoubleSpinBox;
- widget->setRange(std::numeric_limits<float>::min(), std::numeric_limits<float>::max());
+ widget->setRange(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
widget->setAlignment(Qt::AlignRight);
widget->setValue(value.toFloat());
m_valueGetter = [widget]() { return static_cast<float>(widget->value()); };
@@ -132,7 +131,7 @@ QWidget* SetFrameValueDialog::createValueControl(const QVariant& value)
default: {
auto* widget = new QDoubleSpinBox;
- widget->setRange(std::numeric_limits<double>::min(), std::numeric_limits<double>::max());
+ widget->setRange(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max());
widget->setAlignment(Qt::AlignRight);
widget->setValue(value.toDouble());
m_valueGetter = [widget]() { return widget->value(); };
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineanimationform.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineanimationform.cpp
index 83551378ee..56e22dab1b 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineanimationform.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineanimationform.cpp
@@ -13,6 +13,7 @@
#include <variantproperty.h>
#include <qmlitemnode.h>
#include <qmlobjectnode.h>
+#include <dialogutils.h>
#include <coreplugin/messagebox.h>
@@ -96,10 +97,10 @@ TimelineAnimationForm::TimelineAnimationForm(QWidget *parent)
using namespace Layouting;
Grid {
Span(4, mainL), br,
- empty(), br,
+ empty, br,
idL, Span(2, m_idLineEdit), Span(2, Row{ runningL, m_running }), br,
- empty(), startFrameL, m_startFrame, endFrameL, m_endFrame, durationL, m_duration, br,
- empty(), continuousL, m_continuous, loopsL, m_loops, pingPongL, m_pingPong, str, br,
+ empty, startFrameL, m_startFrame, endFrameL, m_endFrame, durationL, m_duration, br,
+ empty, continuousL, m_continuous, loopsL, m_loops, pingPongL, m_pingPong, str, br,
tr("Transition to state:"), transitionToStateL, m_transitionToState, br,
}.attachTo(this);
@@ -141,8 +142,7 @@ TimelineAnimationForm::TimelineAnimationForm(QWidget *parent)
bool error = false;
if (!ModelNode::isValidId(newId)) {
- Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
- tr("%1 is an invalid id.").arg(newId));
+ DialogUtils::showWarningForInvalidId(newId);
error = true;
} else if (animation().view()->hasId(newId)) {
Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp
index b3d408dc0d..2d1e70cd77 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineform.cpp
@@ -10,6 +10,7 @@
#include <nodemetainfo.h>
#include <rewritertransaction.h>
#include <variantproperty.h>
+#include <dialogutils.h>
#include <coreplugin/messagebox.h>
@@ -77,8 +78,8 @@ TimelineForm::TimelineForm(QWidget *parent)
Grid {
Span(2, mainL), br,
idL, m_idLineEdit, br,
- empty(), Row { startFrameL, m_startFrame, st(), endFrameL, m_endFrame }, str, br,
- empty(), Row { m_expressionBinding, m_animation, st() }, br,
+ empty, Row { startFrameL, m_startFrame, st, endFrameL, m_endFrame }, str, br,
+ empty, Row { m_expressionBinding, m_animation, st }, br,
expressionBindingL, m_expressionBindingLineEdit, br,
}.attachTo(this);
@@ -125,8 +126,7 @@ TimelineForm::TimelineForm(QWidget *parent)
bool error = false;
if (!ModelNode::isValidId(newId)) {
- Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
- tr("%1 is an invalid id.").arg(newId));
+ DialogUtils::showWarningForInvalidId(newId);
error = true;
} else if (m_timeline.view()->hasId(newId)) {
Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
index 698ef0f03b..04cc8ebebc 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
@@ -35,7 +35,6 @@
#include <QLineEdit>
#include <QMenu>
#include <QPainter>
-#include <QScopedPointer>
#include <algorithm>
@@ -108,14 +107,14 @@ static void editValue(const ModelNode &frameNode, const std::pair<qreal, qreal>
int userType = value.typeId();
QVariant newValue = dialog->value();
- if (newValue.canConvert(userType)) {
+ if (newValue.canConvert(QMetaType(userType))) {
QVariant newValueConverted = newValue;
- bool converted = newValueConverted.convert(userType);
+ bool converted = newValueConverted.convert(QMetaType(userType));
if (!converted) {
// convert() fails for int to double, so we try this combination
newValueConverted = newValue;
- converted = newValueConverted.convert(QMetaType::Double);
+ converted = newValueConverted.convert(QMetaType(QMetaType::Double));
}
if (converted)
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinesettingsmodel.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinesettingsmodel.cpp
index 39c1f01ce6..9b85599ead 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinesettingsmodel.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinesettingsmodel.cpp
@@ -68,7 +68,7 @@ TimelineEditorDelegate::TimelineEditorDelegate(QWidget *parent)
if (factory == nullptr) {
factory = new QItemEditorFactory;
QItemEditorCreatorBase *creator = new QItemEditorCreator<QComboBox>("currentText");
- factory->registerEditor(QVariant::String, creator);
+ factory->registerEditor(QMetaType::QString, creator);
}
setItemEditorFactory(factory);
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
index 7905df68e9..8288e69316 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
@@ -644,11 +644,12 @@ void TimelineView::registerActions()
TimelineWidget *TimelineView::createWidget()
{
- if (!m_timelineWidget)
+ if (!m_timelineWidget) {
m_timelineWidget = new TimelineWidget(this);
- auto *timelineContext = new TimelineContext(m_timelineWidget);
- Core::ICore::addContextObject(timelineContext);
+ auto *timelineContext = new TimelineContext(m_timelineWidget);
+ Core::ICore::addContextObject(timelineContext);
+ }
return m_timelineWidget;
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
index 591926d3f5..592cf0dff9 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
@@ -221,10 +221,10 @@ TimelineWidget::TimelineWidget(TimelineView *view)
{
QPalette timelinePalette;
- timelinePalette.setColor(QPalette::Text, Utils::creatorTheme()->color(
+ timelinePalette.setColor(QPalette::Text, Utils::creatorColor(
Utils::Theme::DStextColor));
timelinePalette.setColor(QPalette::WindowText, timelinePalette.color(QPalette::Text));
- timelinePalette.setColor(QPalette::Window, Utils::creatorTheme()->color(
+ timelinePalette.setColor(QPalette::Window, Utils::creatorColor(
Utils::Theme::QmlDesigner_BackgroundColorDarkAlternate));
onboardingTopLabel->setPalette(timelinePalette);
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
index e9df928c96..cb84183f92 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
@@ -21,6 +21,9 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/modemanager.h>
+
+#include <texteditor/textdocument.h>
+
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h>
@@ -302,6 +305,20 @@ ToolBarBackend::ToolBarBackend(QObject *parent)
this,
&ToolBarBackend::documentIndexChanged);
+ connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, this, [this]() {
+ static QMetaObject::Connection *lastConnection = nullptr;
+ delete lastConnection;
+
+ if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(
+ Core::EditorManager::currentDocument())) {
+ connect(textDocument->document(),
+ &QTextDocument::modificationChanged,
+ this,
+ &ToolBarBackend::isDocumentDirtyChanged);
+ emit isDocumentDirtyChanged();
+ }
+ });
+
connect(Core::EditorManager::instance(),
&Core::EditorManager::currentEditorChanged,
this,
@@ -740,6 +757,12 @@ bool ToolBarBackend::isSharingEnabled()
return QmlDesigner::checkEnterpriseLicense();
}
+bool ToolBarBackend::isDocumentDirty() const
+{
+ return Core::EditorManager::currentDocument()
+ && Core::EditorManager::currentDocument()->isModified();
+}
+
void ToolBarBackend::launchGlobalAnnotations()
{
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION);
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
index 5d0b0e712a..02bdae1717 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
@@ -97,6 +97,7 @@ class ToolBarBackend : public QObject
Q_PROPERTY(bool isMCUs READ isMCUs NOTIFY isMCUsChanged)
Q_PROPERTY(bool projectOpened READ projectOpened NOTIFY projectOpenedChanged)
Q_PROPERTY(bool isSharingEnabled READ isSharingEnabled NOTIFY isSharingEnabledChanged)
+ Q_PROPERTY(bool isDocumentDirty READ isDocumentDirty NOTIFY isDocumentDirtyChanged)
public:
ToolBarBackend(QObject *parent = nullptr);
@@ -147,6 +148,8 @@ public:
bool isSharingEnabled();
+ bool isDocumentDirty() const;
+
static void launchGlobalAnnotations();
signals:
@@ -167,6 +170,7 @@ signals:
void isMCUsChanged();
void projectOpenedChanged();
void isSharingEnabledChanged();
+ void isDocumentDirtyChanged();
private:
void setupWorkspaces();
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
index 104127bd49..9f9e888823 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
@@ -318,11 +318,12 @@ ModelNode TransitionEditorView::addNewTransition()
TransitionEditorWidget *TransitionEditorView::createWidget()
{
- if (!m_transitionEditorWidget)
+ if (!m_transitionEditorWidget) {
m_transitionEditorWidget = new TransitionEditorWidget(this);
- auto *transitionContext = new TransitionContext(m_transitionEditorWidget);
- Core::ICore::addContextObject(transitionContext);
+ auto *transitionContext = new TransitionContext(m_transitionEditorWidget);
+ Core::ICore::addContextObject(transitionContext);
+ }
return m_transitionEditorWidget;
}
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp
index 1770ba63fc..dcbb0b23b3 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp
@@ -13,6 +13,7 @@
#include <rewritertransaction.h>
#include <variantproperty.h>
#include <qmlitemnode.h>
+#include <dialogutils.h>
#include <coreplugin/messagebox.h>
@@ -45,8 +46,7 @@ TransitionForm::TransitionForm(QWidget *parent)
bool error = false;
if (!ModelNode::isValidId(newId)) {
- Core::AsynchronousMessageBox::warning(tr("Invalid ID"),
- tr("%1 is an invalid ID.").arg(newId));
+ DialogUtils::showWarningForInvalidId(newId);
error = true;
} else if (m_transition.view()->hasId(newId)) {
Core::AsynchronousMessageBox::warning(tr("Invalid ID"),
diff --git a/src/plugins/qmldesigner/componentsplugin/components.metainfo b/src/plugins/qmldesigner/componentsplugin/components.metainfo
index 8a1e365266..2e070aa322 100644
--- a/src/plugins/qmldesigner/componentsplugin/components.metainfo
+++ b/src/plugins/qmldesigner/componentsplugin/components.metainfo
@@ -12,6 +12,7 @@ MetaInfo {
Property { name: "width"; type: "int"; value: 100; }
Property { name: "height"; type: "int"; value: 100; }
+ toolTip: qsTr("Organizes items in a row.")
}
}
@@ -28,6 +29,7 @@ MetaInfo {
Property { name: "width"; type: "int"; value: 100; }
Property { name: "height"; type: "int"; value: 100; }
+ toolTip: qsTr("Organizes items in a column.")
}
}
@@ -44,6 +46,7 @@ MetaInfo {
Property { name: "width"; type: "int"; value: 100; }
Property { name: "height"; type: "int"; value: 100; }
+ toolTip: qsTr("Organizes items in a grid.")
}
}
@@ -57,7 +60,7 @@ MetaInfo {
}
ItemLibraryEntry {
- name: "StackLayout"
+ name: "Stack Layout"
category: "Qt Quick - Layouts"
libraryIcon: ":/componentsplugin/images/stack-layouts-icon.png"
version: "1.0"
@@ -65,6 +68,7 @@ MetaInfo {
Property { name: "width"; type: "int"; value: 100; }
Property { name: "height"; type: "int"; value: 100; }
+ toolTip: qsTr("Organizes items in a grid. Only the top item is visible.")
}
}
}
diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp
new file mode 100644
index 0000000000..da40c4d387
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.cpp
@@ -0,0 +1,291 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "generatedcomponentutils.h"
+#include <qmldesignerconstants.h>
+
+namespace QmlDesigner {
+
+bool couldBeProjectModule(const Utils::FilePath &path, const QString &projectName)
+{
+ if (!path.exists())
+ return false;
+
+ Utils::FilePath qmlDirPath = path.pathAppended("qmldir");
+ if (qmlDirPath.exists()) {
+ Utils::expected_str<QByteArray> qmldirContents = qmlDirPath.fileContents();
+ if (!qmldirContents.has_value())
+ return false;
+
+ const QString expectedLine = QLatin1String("module %1").arg(projectName);
+ QByteArray fileContents = *qmldirContents;
+ QTextStream stream(fileContents);
+ while (!stream.atEnd()) {
+ QString lineData = stream.readLine().trimmed();
+ if (lineData.startsWith(u"module "))
+ return lineData == expectedLine;
+ }
+ }
+ if (path.endsWith(projectName))
+ return true;
+
+ return false;
+}
+
+GeneratedComponentUtils::GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies)
+ : m_externalDependencies(externalDependencies)
+{
+}
+
+Utils::FilePath GeneratedComponentUtils::generatedComponentsPath() const
+{
+ Utils::FilePath projectPath = Utils::FilePath::fromString(m_externalDependencies.currentProjectDirPath());
+ if (projectPath.isEmpty())
+ return {};
+
+ Utils::FilePath assetImportsPath = projectPath.resolvePath(QLatin1String(Constants::OLD_ASSET_IMPORT_FOLDER));
+ if (assetImportsPath.exists())
+ return assetImportsPath;
+
+ Utils::FilePath componentsPath = projectPath.resolvePath(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER));
+ if (!componentsPath.exists())
+ componentsPath.createDir();
+
+ return componentsPath;
+}
+
+Utils::FilePath GeneratedComponentUtils::composedEffectsBasePath() const
+{
+ Utils::FilePath basePath = generatedComponentsPath();
+ if (basePath.isEmpty())
+ return {};
+
+ QString effectsImportPath;
+ if (basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER))
+ effectsImportPath = Constants::OLD_EFFECTS_FOLDER;
+ else
+ effectsImportPath = Constants::COMPOSED_EFFECTS_TYPE;
+
+ return basePath.resolvePath(effectsImportPath);
+}
+
+Utils::FilePath GeneratedComponentUtils::composedEffectPath(const QString &effectPath) const
+{
+ Utils::FilePath effectsBasePath = composedEffectsBasePath();
+
+ QString effectName = Utils::FilePath::fromString(effectPath).baseName();
+
+ return effectsBasePath.resolvePath(effectName + "/" + effectName + ".qml");
+}
+
+Utils::FilePath GeneratedComponentUtils::componentBundlesBasePath() const
+{
+ Utils::FilePath basePath = generatedComponentsPath();
+
+ if (basePath.isEmpty())
+ return {};
+
+ if (basePath.endsWith(Constants::GENERATED_COMPONENTS_FOLDER))
+ return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_TYPE));
+
+ return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_TYPE));
+}
+
+Utils::FilePath GeneratedComponentUtils::import3dBasePath() const
+{
+ Utils::FilePath basePath = generatedComponentsPath();
+
+ if (basePath.isEmpty())
+ return {};
+
+ Utils::FilePath import3dPath;
+ if (basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER))
+ return basePath.resolvePath(QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER));
+
+ return basePath.resolvePath(QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER));
+}
+
+Utils::FilePath GeneratedComponentUtils::materialBundlePath() const
+{
+ Utils::FilePath basePath = componentBundlesBasePath();
+
+ if (basePath.isEmpty())
+ return {};
+
+ if (basePath.endsWith(Constants::OLD_COMPONENT_BUNDLES_TYPE))
+ return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE));
+
+ return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE));
+}
+
+Utils::FilePath GeneratedComponentUtils::effectBundlePath() const
+{
+ Utils::FilePath basePath = componentBundlesBasePath();
+
+ if (basePath.isEmpty())
+ return {};
+
+ if (basePath.endsWith(Constants::OLD_COMPONENT_BUNDLES_TYPE))
+ return basePath.resolvePath(QLatin1String(Constants::OLD_COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE));
+
+ return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE));
+}
+
+Utils::FilePath GeneratedComponentUtils::projectModulePath(bool generateIfNotExists) const
+{
+ using Utils::FilePath;
+ FilePath projectPath = FilePath::fromString(m_externalDependencies.currentProjectDirPath());
+
+ if (projectPath.isEmpty())
+ return {};
+
+ const QString projectName = m_externalDependencies.projectName();
+
+ FilePath newImportDirectory = projectPath.pathAppended(projectName);
+ if (couldBeProjectModule(newImportDirectory, projectName))
+ return newImportDirectory;
+
+ FilePath oldImportDirectory = projectPath.resolvePath(QLatin1String("imports/") + projectName);
+ if (couldBeProjectModule(oldImportDirectory, projectName))
+ return oldImportDirectory;
+
+ for (const QString &path : m_externalDependencies.projectModulePaths()) {
+ FilePath dir = FilePath::fromString(path);
+ if (couldBeProjectModule(dir, projectName))
+ return dir;
+ }
+
+ if (generateIfNotExists)
+ newImportDirectory.createDir();
+
+ return newImportDirectory;
+}
+
+bool GeneratedComponentUtils::isImport3dPath(const QString &path) const
+{
+ return path.contains('/' + QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER))
+ || path.contains(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER) + '/'
+ + QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER));
+}
+
+bool GeneratedComponentUtils::isComposedEffectPath(const QString &path) const
+{
+ return path.contains(Constants::OLD_EFFECTS_IMPORT_FOLDER)
+ || path.contains(QLatin1String(Constants::GENERATED_COMPONENTS_FOLDER) + '/'
+ + QLatin1String(Constants::COMPOSED_EFFECTS_TYPE));
+}
+
+bool GeneratedComponentUtils::isBundlePath(const QString &path) const
+{
+ return path.contains(componentBundlesTypePrefix().replace('.', '/'));
+}
+
+bool GeneratedComponentUtils::isGeneratedPath(const QString &path) const
+{
+ return path.startsWith(generatedComponentsPath().toFSPathString());
+}
+
+
+QString GeneratedComponentUtils::generatedComponentTypePrefix() const
+{
+ Utils::FilePath basePath = generatedComponentsPath();
+ if (basePath.isEmpty() || basePath.endsWith(Constants::OLD_ASSET_IMPORT_FOLDER))
+ return {};
+
+ return Constants::GENERATED_COMPONENTS_FOLDER;
+}
+
+QString GeneratedComponentUtils::import3dTypePrefix() const
+{
+ QString basePrefix = generatedComponentTypePrefix();
+
+ if (basePrefix == Constants::GENERATED_COMPONENTS_FOLDER)
+ return basePrefix + '.' + QLatin1String(Constants::QUICK_3D_COMPONENTS_FOLDER);
+
+ return Constants::OLD_QUICK_3D_ASSETS_FOLDER;
+}
+
+QString GeneratedComponentUtils::import3dTypePath() const
+{
+ QString prefix = import3dTypePrefix();
+ prefix.replace('.', '/');
+ return prefix;
+}
+
+QString GeneratedComponentUtils::componentBundlesTypePrefix() const
+{
+ QString basePrefix = generatedComponentTypePrefix();
+
+ if (basePrefix.endsWith(Constants::GENERATED_COMPONENTS_FOLDER))
+ return basePrefix + '.' + QLatin1String(Constants::COMPONENT_BUNDLES_TYPE);
+
+ return Constants::OLD_COMPONENT_BUNDLES_TYPE;
+}
+
+QString GeneratedComponentUtils::composedEffectsTypePrefix() const
+{
+ QString basePrefix = generatedComponentTypePrefix();
+
+ if (basePrefix == Constants::GENERATED_COMPONENTS_FOLDER)
+ return basePrefix + '.' + QLatin1String(Constants::COMPOSED_EFFECTS_TYPE);
+
+ return Constants::OLD_EFFECTS_FOLDER;
+}
+
+QString GeneratedComponentUtils::materialsBundleId() const
+{
+ bool isNewImportDir = generatedComponentTypePrefix().endsWith(Constants::GENERATED_COMPONENTS_FOLDER);
+
+ return QLatin1String(isNewImportDir ? Constants::COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE
+ : Constants::OLD_COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE);
+}
+
+QString GeneratedComponentUtils::effectsBundleId() const
+{
+ bool isNewImportDir = generatedComponentTypePrefix().endsWith(Constants::GENERATED_COMPONENTS_FOLDER);
+
+ return QLatin1String(isNewImportDir ? Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE
+ : Constants::OLD_COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE);
+}
+
+QString GeneratedComponentUtils::userMaterialsBundleId() const
+{
+ return QLatin1String(Constants::COMPONENT_BUNDLES_USER_MATERIAL_BUNDLE_TYPE);
+}
+
+QString GeneratedComponentUtils::userEffectsBundleId() const
+{
+ return QLatin1String(Constants::COMPONENT_BUNDLES_USER_EFFECT_BUNDLE_TYPE);
+}
+
+QString GeneratedComponentUtils::user3DBundleId() const
+{
+ return QLatin1String(Constants::COMPONENT_BUNDLES_USER_3D_BUNDLE_TYPE);
+}
+
+QString GeneratedComponentUtils::materialsBundleType() const
+{
+ return componentBundlesTypePrefix() + '.' + materialsBundleId();
+}
+
+QString GeneratedComponentUtils::effectsBundleType() const
+{
+ return componentBundlesTypePrefix() + '.' + effectsBundleId();
+}
+
+QString GeneratedComponentUtils::userMaterialsBundleType() const
+{
+ return componentBundlesTypePrefix() + '.' + userMaterialsBundleId();
+}
+
+QString GeneratedComponentUtils::userEffectsBundleType() const
+{
+ return componentBundlesTypePrefix() + '.' + userEffectsBundleId();
+}
+
+QString GeneratedComponentUtils::user3DBundleType() const
+{
+ return componentBundlesTypePrefix() + '.' + user3DBundleId();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/generatedcomponentutils.h b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h
new file mode 100644
index 0000000000..ceddb405a3
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/generatedcomponentutils.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <externaldependenciesinterface.h>
+#include <qmldesignercorelib_exports.h>
+
+#include <utils/filepath.h>
+
+#include <QString>
+
+namespace QmlDesigner {
+
+class QMLDESIGNERCORE_EXPORT GeneratedComponentUtils {
+public:
+ GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies);
+
+ Utils::FilePath generatedComponentsPath() const;
+ Utils::FilePath composedEffectsBasePath() const;
+ Utils::FilePath composedEffectPath(const QString &effectPath) const;
+ Utils::FilePath componentBundlesBasePath() const;
+ Utils::FilePath import3dBasePath() const;
+ Utils::FilePath materialBundlePath() const;
+ Utils::FilePath effectBundlePath() const;
+ Utils::FilePath projectModulePath(bool generateIfNotExists = false) const;
+
+ bool isImport3dPath(const QString &path) const;
+ bool isComposedEffectPath(const QString &path) const;
+ bool isBundlePath(const QString &path) const;
+ bool isGeneratedPath(const QString &path) const;
+
+ QString generatedComponentTypePrefix() const;
+ QString import3dTypePrefix() const;
+ QString import3dTypePath() const;
+ QString componentBundlesTypePrefix() const;
+ QString composedEffectsTypePrefix() const;
+
+ QString materialsBundleId() const;
+ QString effectsBundleId() const;
+ QString userMaterialsBundleId() const;
+ QString userEffectsBundleId() const;
+ QString user3DBundleId() const;
+
+ QString materialsBundleType() const;
+ QString effectsBundleType() const;
+ QString userMaterialsBundleType() const;
+ QString userEffectsBundleType() const;
+ QString user3DBundleType() const;
+
+private:
+ ExternalDependenciesInterface &m_externalDependencies;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
index 955e676d3b..97148e664f 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
@@ -76,8 +76,10 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
AbortCallback abortCallback,
ImageCache::TraceToken traceToken)
{
+#ifdef QDS_USE_PROJECTSTORAGE
if (!m_projectStorage || !m_pathCache)
return;
+#endif
using namespace NanotraceHR::Literals;
auto [collectorTraceToken, flowtoken] = traceToken.beginDurationWithFlow(
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
index c2a912cc3a..fec68c2894 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
@@ -64,8 +64,10 @@ private:
QSize captureImageMaximumSize;
ExternalDependenciesInterface &m_externalDependencies;
ImageCacheCollectorNullImageHandling nullImageHandling{};
+#ifdef QDS_USE_PROJECTSTORAGE
ProjectStorageType *m_projectStorage = nullptr;
PathCacheType *m_pathCache = nullptr;
+#endif
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h b/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h
index fac7e7d9bf..dc5ed3de23 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/taskqueue.h
@@ -31,7 +31,7 @@ public:
{
std::unique_lock lock{m_mutex};
- ensureThreadIsRunning(std::move(traceToken));
+ ensureThreadIsRunning(lock, std::move(traceToken));
m_tasks.emplace_back(std::forward<Arguments>(arguments)...);
}
@@ -54,6 +54,15 @@ public:
clearTasks(oldTasks);
}
+ void putThreadToSleep()
+ {
+ {
+ std::unique_lock lock{m_mutex};
+ m_sleeping = true;
+ }
+ m_condition.notify_all();
+ }
+
private:
void destroy()
{
@@ -66,19 +75,20 @@ private:
{
using namespace std::literals::chrono_literals;
std::unique_lock lock{m_mutex};
- if (m_finishing)
+
+ if (m_finishing || m_sleeping)
return {std::move(lock), true};
+
if (m_tasks.empty()) {
auto timedOutWithoutEntriesOrFinishing = !m_condition.wait_for(lock, 10min, [&] {
- return m_tasks.size() || m_finishing;
+ return m_tasks.size() || m_finishing || m_sleeping;
});
- if (timedOutWithoutEntriesOrFinishing || m_finishing) {
+ if (timedOutWithoutEntriesOrFinishing)
m_sleeping = true;
- return {std::move(lock), true};
- }
}
- return {std::move(lock), false};
+
+ return {std::move(lock), m_finishing || m_sleeping};
}
[[nodiscard]] std::optional<Task> getTask(std::unique_lock<std::mutex> lock)
@@ -94,29 +104,38 @@ private:
return {std::move(task)};
}
- template<typename TraceToken>
- void ensureThreadIsRunning(TraceToken traceToken)
+ template<typename Lock, typename TraceToken>
+ void ensureThreadIsRunning(Lock &lock, TraceToken traceToken)
{
using namespace NanotraceHR::Literals;
if (m_finishing || !m_sleeping)
return;
+ if (m_sleeping) {
+ lock.unlock();
+ joinThread();
+ lock.lock();
+
+ m_sleeping = false;
+ }
+
if (m_backgroundThread.joinable())
return;
- m_sleeping = false;
-
auto [threadCreateToken, flowToken] = traceToken.beginDurationWithFlow(
"thread is created in the task queue"_t);
m_backgroundThread = std::thread{[this](auto traceToken) {
auto duration = traceToken.beginDuration(
"thread is ready"_t);
+
while (true) {
auto [lock, abort] = waitForTasks();
duration.end();
+
if (abort)
return;
+
auto getTaskToken = duration.beginDuration(
"get task from queue"_t);
if (auto task = getTask(std::move(lock)); task) {
diff --git a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
index 71ddeb7dc1..9055f51b6a 100644
--- a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
+++ b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
@@ -28,6 +28,7 @@ public:
virtual QString qmlPuppetFallbackDirectory() const = 0;
virtual QString defaultPuppetToplevelBuildDirectory() const = 0;
virtual QUrl projectUrl() const = 0;
+ virtual QString projectName() const = 0;
virtual QString currentProjectDirPath() const = 0;
virtual QUrl currentResourcePath() const = 0;
virtual void parseItemLibraryDescriptions() = 0;
diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h b/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h
index f88f9e35c6..2d0f2ef31e 100644
--- a/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h
+++ b/src/plugins/qmldesigner/designercore/include/itemlibraryentry.h
@@ -42,13 +42,16 @@ class QMLDESIGNERCORE_EXPORT ItemLibraryEntry
public:
ItemLibraryEntry();
- explicit ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry,
- const ProjectStorageType &projectStorage);
- ~ItemLibraryEntry() = default;
+ ItemLibraryEntry(const ItemLibraryEntry &) = default;
+ ItemLibraryEntry &operator=(const ItemLibraryEntry &) = default;
+ ItemLibraryEntry(ItemLibraryEntry &&) = default;
+ ItemLibraryEntry &operator=(ItemLibraryEntry &&) = default;
+ explicit ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry);
+ ~ItemLibraryEntry();
QString name() const;
TypeName typeName() const;
- const NodeMetaInfo &metaInfo() const;
+ TypeId typeId() const;
QIcon typeIcon() const;
QString libraryEntryIconPath() const;
int majorVersion() const;
@@ -86,7 +89,7 @@ private:
using ItemLibraryEntries = QList<ItemLibraryEntry>;
QMLDESIGNERCORE_EXPORT QList<ItemLibraryEntry> toItemLibraryEntries(
- const Storage::Info::ItemLibraryEntries &entries, const ProjectStorageType &projectStorage);
+ const Storage::Info::ItemLibraryEntries &entries);
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h
index b907e6c5d8..39b5cdaa81 100644
--- a/src/plugins/qmldesigner/designercore/include/model.h
+++ b/src/plugins/qmldesigner/designercore/include/model.h
@@ -137,7 +137,7 @@ public:
ModelPointer createModel(const TypeName &typeName,
std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {});
- QUrl fileUrl() const;
+ const QUrl &fileUrl() const;
SourceId fileUrlSourceId() const;
void setFileUrl(const QUrl &url);
@@ -147,7 +147,7 @@ public:
void setMetaInfo(const MetaInfo &metaInfo);
#endif
- Module module(Utils::SmallStringView moduleName);
+ Module module(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind);
NodeMetaInfo metaInfo(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const;
NodeMetaInfo metaInfo(Module module,
Utils::SmallStringView typeName,
@@ -166,6 +166,7 @@ public:
NodeMetaInfo qtQmlConnectionsMetaInfo() const;
NodeMetaInfo qtQmlModelsListModelMetaInfo() const;
NodeMetaInfo qtQmlModelsListElementMetaInfo() const;
+ NodeMetaInfo qtQmlXmlListModelXmlListModelRoleMetaInfo() const;
NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const;
NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const;
@@ -218,14 +219,17 @@ public:
// Imports:
const Imports &imports() const;
- const Imports &possibleImports() const;
- const Imports &usedImports() const;
+ Imports possibleImports() const;
+ Imports usedImports() const;
void changeImports(Imports importsToBeAdded, Imports importsToBeRemoved);
+#ifndef QDS_USE_PROJECTSTORAGE
void setPossibleImports(Imports possibleImports);
+#endif
+#ifndef QDS_USE_PROJECTSTORAGE
void setUsedImports(Imports usedImports);
+#endif
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);
QStringList importPaths() const;
Import highestPossibleImport(const QString &importPath);
@@ -251,10 +255,7 @@ public:
bool hasId(const QString &id) const;
bool hasImport(const QString &importUrl) const;
- QString generateNewId(const QString &prefixName,
- const QString &fallbackPrefix = "element",
- std::optional<std::function<bool(const QString &)>> isDuplicate = {}) const;
- QString generateIdFromName(const QString &name, const QString &fallbackId = "element") const;
+ QString generateNewId(const QString &prefixName, const QString &fallbackPrefix = "element") const;
void startDrag(QMimeData *mimeData, const QPixmap &icon);
void endDrag();
diff --git a/src/plugins/qmldesigner/designercore/include/modelfwd.h b/src/plugins/qmldesigner/designercore/include/modelfwd.h
index 0a062289fd..91c533fe7b 100644
--- a/src/plugins/qmldesigner/designercore/include/modelfwd.h
+++ b/src/plugins/qmldesigner/designercore/include/modelfwd.h
@@ -77,7 +77,7 @@ constexpr bool useProjectStorage()
using ProjectStorageType = ProjectStorageInterface;
using PathCacheType = SourcePathCacheInterface;
#else
-using ProjectStorageType = ProjectStorage<Sqlite::Database>;
+using ProjectStorageType = ProjectStorage;
using PathCacheType = SourcePathCache<ProjectStorageType, NonLockingMutex>;
#endif
diff --git a/src/plugins/qmldesigner/designercore/include/nodehints.h b/src/plugins/qmldesigner/designercore/include/nodehints.h
index 9e67c2d99b..99470db65f 100644
--- a/src/plugins/qmldesigner/designercore/include/nodehints.h
+++ b/src/plugins/qmldesigner/designercore/include/nodehints.h
@@ -3,9 +3,11 @@
#pragma once
+#include "modelnode.h"
+#include "nodemetainfo.h"
+
#include <QList>
#include <QString>
-#include "modelnode.h"
#include "qmldesignercorelib_global.h"
#include "invalidmetainfoexception.h"
@@ -54,18 +56,19 @@ public:
QHash<QString, QString> hints() const;
static NodeHints fromModelNode(const ModelNode &modelNode);
- static NodeHints fromItemLibraryEntry(const ItemLibraryEntry &entry);
+ static NodeHints fromItemLibraryEntry(const ItemLibraryEntry &entry, Model *model);
private:
explicit NodeHints(const ModelNode &modelNode);
explicit NodeHints(const NodeMetaInfo &metaInfo);
- explicit NodeHints(const ItemLibraryEntry &entry);
+ explicit NodeHints(const ItemLibraryEntry &entry, Model *model);
const ModelNode &modelNode() const;
bool isValid() const;
Model *model() const;
bool evaluateBooleanExpression(const QString &hintName, bool defaultValue, const ModelNode potentialParent = ModelNode()) const;
ModelNode m_modelNode;
+ NodeMetaInfo m_metaInfo;
QHash<QString, QString> m_hints;
};
diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
index 53c755ddc8..fd3f2f9be8 100644
--- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
@@ -27,9 +27,15 @@ QT_END_NAMESPACE
# define DEPRECATED_VERSION_NUMBER \
[[deprecated( \
"In most cases you don't need them anymore because the import is setting them!")]]
+# define DEPRECATED_COMPONENT_FILE_NAME [[deprecated("Use sourceId() instead.")]]
+# define DEPRECATED_IMPORT_DIRECTORY_PATH [[deprecated("Use allExportedTypeNames().")]]
+# define DEPRECATED_REQUIRED_IMPORT_STRING [[deprecated("Use allExportedTypeNames().")]]
#else
# define DEPRECATED_TYPENAME
# define DEPRECATED_VERSION_NUMBER
+# define DEPRECATED_COMPONENT_FILE_NAME
+# define DEPRECATED_IMPORT_DIRECTORY_PATH
+# define DEPRECATED_REQUIRED_IMPORT_STRING
#endif
namespace QmlDesigner {
@@ -116,7 +122,7 @@ public:
Storage::Info::ItemLibraryEntries itemLibrariesEntries() const;
SourceId sourceId() const;
- QString componentFileName() const;
+ DEPRECATED_COMPONENT_FILE_NAME QString componentFileName() const;
bool isBasedOn(const NodeMetaInfo &metaInfo) const;
bool isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const;
@@ -167,6 +173,7 @@ public:
bool isQtMultimediaSoundEffect() const;
bool isQtObject() const;
bool isQtQmlConnections() const;
+ bool isQtQmlModelsListElement() const;
bool isQtQuick3DBakedLightmap() const;
bool isQtQuick3DBuffer() const;
bool isQtQuick3DCamera() const;
@@ -176,9 +183,9 @@ public:
bool isQtQuick3DInstanceList() const;
bool isQtQuick3DInstanceListEntry() const;
bool isQtQuick3DLight() const;
- bool isQtQuickListElement() const;
bool isQtQuickListModel() const;
bool isQtQuickListView() const;
+ bool isQtQuickGridView() const;
bool isQtQuick3DMaterial() const;
bool isQtQuick3DModel() const;
bool isQtQuick3DNode() const;
@@ -235,8 +242,8 @@ public:
bool usesCustomParser() const;
bool isEnumeration() const;
- QString importDirectoryPath() const;
- QString requiredImportString() const;
+ DEPRECATED_IMPORT_DIRECTORY_PATH QString importDirectoryPath() const;
+ DEPRECATED_REQUIRED_IMPORT_STRING QString requiredImportString() const;
friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second)
{
@@ -265,12 +272,14 @@ public:
private:
const Storage::Info::Type &typeData() const;
+ PropertyDeclarationId defaultPropertyDeclarationId() const;
bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const;
private:
TypeId m_typeId;
NotNullPointer<const ProjectStorageType> m_projectStorage = {};
mutable std::optional<Storage::Info::Type> m_typeData;
+ mutable std::optional<PropertyDeclarationId> m_defaultPropertyId;
std::shared_ptr<NodeMetaInfoPrivate> m_privateData;
};
diff --git a/src/plugins/qmldesigner/designercore/include/projectstorageids.h b/src/plugins/qmldesigner/designercore/include/projectstorageids.h
index bc66e0d2b2..7c2e8c4b25 100644
--- a/src/plugins/qmldesigner/designercore/include/projectstorageids.h
+++ b/src/plugins/qmldesigner/designercore/include/projectstorageids.h
@@ -7,6 +7,8 @@
#include <utils/span.h>
+#include <QVarLengthArray>
+
namespace QmlDesigner {
enum class BasicIdType {
@@ -29,6 +31,8 @@ enum class BasicIdType {
using TypeId = Sqlite::BasicId<BasicIdType::Type>;
using TypeIds = std::vector<TypeId>;
+template<std::size_t size>
+using SmallTypeIds = QVarLengthArray<TypeId, size>;
using PropertyDeclarationId = Sqlite::BasicId<BasicIdType::PropertyDeclaration>;
using PropertyDeclarationIds = std::vector<PropertyDeclarationId>;
@@ -44,9 +48,13 @@ using EnumerationDeclarationIds = std::vector<EnumerationDeclarationId>;
using SourceContextId = Sqlite::BasicId<BasicIdType::SourceContext, int>;
using SourceContextIds = std::vector<SourceContextId>;
+template<std::size_t size>
+using SmallSourceContextIds = QVarLengthArray<SourceContextId, size>;
using SourceId = Sqlite::BasicId<BasicIdType::Source, int>;
using SourceIds = std::vector<SourceId>;
+template<std::size_t size>
+using SmallSourceIds = QVarLengthArray<SourceId, size>;
using ModuleId = Sqlite::BasicId<BasicIdType::Module, int>;
using ModuleIds = std::vector<ModuleId>;
diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
index dde5515a5a..e11f201cdb 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h
@@ -174,6 +174,7 @@ public:
ModelNode targetTransition() const;
void assignTargetFlowItem(const QmlFlowTargetNode &flowItem);
QmlFlowItemNode flowItemParent() const;
+private:
void destroyTarget();
};
diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h
index 23841accda..92c79c7863 100644
--- a/src/plugins/qmldesigner/designercore/include/rewriterview.h
+++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h
@@ -8,11 +8,11 @@
#include "documentmessage.h"
#include "rewritertransaction.h"
-#include <QScopedPointer>
#include <QTimer>
#include <QUrl>
#include <functional>
+#include <memory>
namespace QmlJS {
class Document;
@@ -123,7 +123,10 @@ public:
bool renameId(const QString& oldId, const QString& newId);
const QmlJS::Document *document() const;
+
+#ifndef QDS_USE_PROJECTSTORAGE
const QmlJS::ScopeChain *scopeChain() const;
+#endif
QString convertTypeToImportAlias(const QString &type) const;
@@ -135,8 +138,6 @@ public:
void setCheckLinkErrors(bool b) { m_checkLinkErrors = b; }
- QString pathForImport(const Import &import);
-
QStringList importDirectories() const;
QSet<QPair<QString, QString> > qrcMapping() const;
@@ -202,9 +203,9 @@ private: //variables
bool m_checkLinkErrors = true;
DifferenceHandling m_differenceHandling;
- QScopedPointer<Internal::ModelNodePositionStorage> m_positionStorage;
- QScopedPointer<Internal::ModelToTextMerger> m_modelToTextMerger;
- QScopedPointer<Internal::TextToModelMerger> m_textToModelMerger;
+ std::unique_ptr<Internal::ModelNodePositionStorage> m_positionStorage;
+ std::unique_ptr<Internal::ModelToTextMerger> m_modelToTextMerger;
+ std::unique_ptr<Internal::TextToModelMerger> m_textToModelMerger;
QList<DocumentMessage> m_errors;
QList<DocumentMessage> m_warnings;
RewriterTransaction m_removeDefaultPropertyTransaction;
diff --git a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
index 7fa2348854..a42164d1bd 100644
--- a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
+++ b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
@@ -7,6 +7,7 @@
# include "qmldesignercorelib_global.h"
+# include <generatedcomponentutils.h>
# include <import.h>
# include <QObject>
@@ -62,6 +63,7 @@ private: // variables
QDir m_filePathDir;
QPointer<Model> m_model;
ExternalDependenciesInterface &m_externalDependencies;
+ GeneratedComponentUtils m_componentUtils;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 33a100f7b2..484f18e42b 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -64,6 +64,8 @@
#include <qmlitemnode.h>
#include <rewriterview.h>
+#include <projectstorage/projectstorage.h>
+
#include <utils/hdrimage.h>
#include <coreplugin/messagemanager.h>
@@ -89,7 +91,6 @@
#include <QMultiHash>
#include <QPainter>
#include <QPicture>
-#include <QScopedPointer>
#include <QTimerEvent>
#include <QUrl>
@@ -205,22 +206,17 @@ NodeInstanceView::~NodeInstanceView()
static bool isSkippedRootNode(const ModelNode &node)
{
- static const PropertyNameList skipList({"Qt.ListModel", "QtQuick.ListModel", "Qt.ListModel", "QtQuick.ListModel"});
-
- if (skipList.contains(node.type()))
- return true;
-
- return false;
+ return node.metaInfo().isQtQuickListModel();
}
static bool isSkippedNode(const ModelNode &node)
{
- static const PropertyNameList skipList({"QtQuick.XmlRole", "Qt.XmlRole", "QtQuick.ListElement", "Qt.ListElement"});
+ auto model = node.model();
- if (skipList.contains(node.type()))
- return true;
+ auto listElement = model->qtQmlModelsListElementMetaInfo();
+ auto xmlRole = model->qtQmlXmlListModelXmlListModelRoleMetaInfo();
- return false;
+ return node.metaInfo().isBasedOn(listElement, xmlRole);
}
static bool parentTakesOverRendering(const ModelNode &modelNode)
@@ -644,7 +640,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
TypeName(),
key.type};
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
- };
+ }
break;
case AuxiliaryDataType::NodeInstanceAuxiliary:
@@ -656,7 +652,7 @@ void NodeInstanceView::auxiliaryDataChanged(const ModelNode &node,
TypeName(),
key.type};
m_nodeInstanceServer->changeAuxiliaryValues({{container}});
- };
+ }
break;
case AuxiliaryDataType::NodeInstancePropertyOverwrite:
@@ -991,6 +987,8 @@ QRectF NodeInstanceView::sceneRect() const
return {};
}
+namespace {
+
QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
{
QList<ModelNode> filteredNodeList;
@@ -1003,14 +1001,12 @@ QList<ModelNode> filterNodesForSkipItems(const QList<ModelNode> &nodeList)
return filteredNodeList;
}
-namespace {
bool shouldSendAuxiliary(const AuxiliaryDataKey &key)
{
return key.type == AuxiliaryDataType::NodeInstancePropertyOverwrite
|| key.type == AuxiliaryDataType::NodeInstanceAuxiliary || key == invisibleProperty
|| key == lockedProperty;
}
-} // namespace
bool parentIsBehavior(ModelNode node)
{
@@ -1024,6 +1020,43 @@ bool parentIsBehavior(ModelNode node)
return false;
}
+TypeName createQualifiedTypeName(const ModelNode &node)
+{
+ if (!node)
+ return {};
+
+#ifdef QDS_USE_PROJECTSTORAGE
+ auto model = node.model();
+ auto exportedTypes = node.metaInfo().exportedTypeNamesForSourceId(model->fileUrlSourceId());
+ if (exportedTypes.size()) {
+ const auto &exportedType = exportedTypes.front();
+ using Storage::ModuleKind;
+ auto module = model->projectStorage()->module(exportedType.moduleId);
+ Utils::PathString typeName;
+ switch (module.kind) {
+ case ModuleKind::QmlLibrary:
+ typeName += module.name;
+ typeName += '/';
+ break;
+ case ModuleKind::PathLibrary:
+ break;
+ case ModuleKind::CppLibrary:
+ break;
+ }
+
+ typeName += exportedType.name;
+
+ return typeName.toQByteArray();
+ }
+
+ return {};
+#else
+ return node.type();
+#endif
+}
+
+} // namespace
+
CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
{
QList<ModelNode> nodeList = allModelNodes();
@@ -1079,8 +1112,9 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
nodeFlags |= InstanceContainer::ParentTakesOverRendering;
const auto modelNode = instance.modelNode();
+
InstanceContainer container(instance.instanceId(),
- modelNode.type(),
+ createQualifiedTypeName(modelNode),
modelNode.majorVersion(),
modelNode.minorVersion(),
ModelUtils::componentFilePath(modelNode),
@@ -1182,6 +1216,13 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
if (stateNode.isValid() && stateNode.metaInfo().isQtQuickState())
stateInstanceId = stateNode.internalId();
+ QHash<QString, QVariantMap> sceneStates = m_edit3DToolStates[model()->fileUrl()];
+ QHash<QString, QVariantMap> projectStates = m_edit3DToolStates[
+ QUrl::fromLocalFile(m_externalDependencies.currentProjectDirPath())];
+ const QString ptsId = "@PTS";
+ if (projectStates.contains(ptsId))
+ sceneStates.insert(ptsId, projectStates[ptsId]);
+
return CreateSceneCommand(instanceContainerList,
reparentContainerList,
idContainerList,
@@ -1192,7 +1233,7 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
mockupTypesVector,
model()->fileUrl(),
m_externalDependencies.currentResourcePath(),
- m_edit3DToolStates[model()->fileUrl()],
+ sceneStates,
lastUsedLanguage,
m_captureImageMinimumSize,
m_captureImageMaximumSize,
@@ -1243,7 +1284,7 @@ CreateInstancesCommand NodeInstanceView::createCreateInstancesCommand(const QLis
const auto modelNode = instance.modelNode();
InstanceContainer container(instance.instanceId(),
- modelNode.type(),
+ createQualifiedTypeName(modelNode),
modelNode.majorVersion(),
modelNode.minorVersion(),
ModelUtils::componentFilePath(modelNode),
@@ -1710,7 +1751,12 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
auto data = qvariant_cast<QVariantList>(command.data());
if (data.size() == 3) {
QString qmlId = data[0].toString();
- m_edit3DToolStates[model()->fileUrl()][qmlId].insert(data[1].toString(), data[2]);
+ QUrl mainKey;
+ if (qmlId == "@PTS") // Project tool state
+ mainKey = QUrl::fromLocalFile(m_externalDependencies.currentProjectDirPath());
+ else
+ mainKey = model()->fileUrl();
+ m_edit3DToolStates[mainKey][qmlId].insert(data[1].toString(), data[2]);
}
}
} else if (command.type() == PuppetToCreatorCommand::Render3DView) {
@@ -1824,7 +1870,7 @@ QVariant NodeInstanceView::modelNodePreviewImageDataToVariant(const ModelNodePre
placeHolder = {150, 150};
// Placeholder has transparency, but we don't want to show the checkerboard, so
// paint in the correct background color
- placeHolder.fill(Utils::creatorTheme()->color(Utils::Theme::BackgroundColorNormal));
+ placeHolder.fill(Utils::creatorColor(Utils::Theme::BackgroundColorNormal));
QPainter painter(&placeHolder);
painter.drawPixmap(0, 0, 150, 150, placeHolderSrc);
}
@@ -1850,7 +1896,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo
ModelNodePreviewImageData imageData;
imageData.id = modelNode.id();
- imageData.type = QString::fromLatin1(modelNode.type());
+ imageData.type = QString::fromUtf8(createQualifiedTypeName(modelNode));
const double ratio = m_externalDependencies.formEditorDevicePixelRatio();
if (imageSource.isEmpty() && modelNode.metaInfo().isQtQuick3DTexture()) {
@@ -1923,7 +1969,7 @@ QVariant NodeInstanceView::previewImageDataForImageNode(const ModelNode &modelNo
imageData.pixmap = originalPixmap.scaled(dim, dim, Qt::KeepAspectRatio);
imageData.pixmap.setDevicePixelRatio(ratio);
imageData.time = modified;
- imageData.info = ImageUtils::imageInfo(imageSource);
+ imageData.info = ImageUtils::imageInfoString(imageSource);
m_imageDataMap.insert(imageData.id, imageData);
}
}
@@ -1958,7 +2004,7 @@ QVariant NodeInstanceView::previewImageDataForGenericNode(const ModelNode &model
if (m_imageDataMap.contains(id)) {
imageData = m_imageDataMap[id];
} else {
- imageData.type = QString::fromLatin1(modelNode.type());
+ imageData.type = QString::fromLatin1(createQualifiedTypeName(modelNode));
imageData.id = id;
m_imageDataMap.insert(id, imageData);
}
diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp
index 806da7e7c4..2aec766002 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryentry.cpp
@@ -22,7 +22,7 @@ class ItemLibraryEntryData
public:
QString name;
TypeName typeName;
- NodeMetaInfo metaInfo;
+ TypeId typeId;
QString category;
int majorVersion{-1};
int minorVersion{-1};
@@ -64,12 +64,12 @@ ItemLibraryEntry::ItemLibraryEntry()
: m_data(std::make_shared<Internal::ItemLibraryEntryData>())
{}
-ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry,
- const ProjectStorageType &projectStorage)
+ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry)
: ItemLibraryEntry{}
{
m_data->name = entry.name.toQString();
- m_data->metaInfo = {entry.typeId, &projectStorage};
+ m_data->typeId = entry.typeId;
+ m_data->typeName = entry.typeName.toQByteArray();
m_data->category = entry.category.toQString();
if (entry.iconPath.size())
m_data->libraryEntryIconPath = entry.iconPath.toQString();
@@ -87,6 +87,8 @@ ItemLibraryEntry::ItemLibraryEntry(const Storage::Info::ItemLibraryEntry &entry,
m_data->extraFilePaths.emplace_back(extraFilePath.toQString());
}
+ItemLibraryEntry::~ItemLibraryEntry() = default;
+
QString ItemLibraryEntry::name() const
{
return m_data->name;
@@ -97,9 +99,9 @@ TypeName ItemLibraryEntry::typeName() const
return m_data->typeName;
}
-const NodeMetaInfo &ItemLibraryEntry::metaInfo() const
+TypeId ItemLibraryEntry::typeId() const
{
- return m_data->metaInfo;
+ return m_data->typeId;
}
QString ItemLibraryEntry::qmlSource() const
@@ -245,6 +247,7 @@ QDataStream &operator<<(QDataStream &stream, const ItemLibraryEntry &itemLibrary
stream << itemLibraryEntry.m_data->qmlSource;
stream << itemLibraryEntry.m_data->customComponentSource;
stream << itemLibraryEntry.m_data->extraFilePaths;
+ stream << itemLibraryEntry.m_data->typeId.internalId();
return stream;
}
@@ -270,6 +273,9 @@ QDataStream &operator>>(QDataStream &stream, ItemLibraryEntry &itemLibraryEntry)
stream >> itemLibraryEntry.m_data->qmlSource;
stream >> itemLibraryEntry.m_data->customComponentSource;
stream >> itemLibraryEntry.m_data->extraFilePaths;
+ TypeId::DatabaseType internalTypeId;
+ stream >> internalTypeId;
+ itemLibraryEntry.m_data->typeId = TypeId::create(internalTypeId);
return stream;
}
@@ -295,11 +301,10 @@ QDebug operator<<(QDebug debug, const ItemLibraryEntry &itemLibraryEntry)
return debug.space();
}
-QList<ItemLibraryEntry> toItemLibraryEntries(const Storage::Info::ItemLibraryEntries &entries,
- const ProjectStorageType &projectStorage)
+QList<ItemLibraryEntry> toItemLibraryEntries(const Storage::Info::ItemLibraryEntries &entries)
{
return Utils::transform<QList<ItemLibraryEntry>>(entries, [&](const auto &entry) {
- return ItemLibraryEntry{entry, projectStorage};
+ return ItemLibraryEntry{entry};
});
}
diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp
index af61ef6573..0addc6884d 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/metainforeader.cpp
@@ -272,7 +272,7 @@ inline QString deEscape(const QString &value)
inline QVariant deEscapeVariant(const QVariant &value)
{
- if (value.typeId() == QVariant::String)
+ if (value.typeId() == QMetaType::QString)
return deEscape(value.toString());
return value;
}
diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp
index 32e68a3cdc..1f9a3e42bd 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/nodehints.cpp
@@ -106,14 +106,15 @@ QmlDesigner::NodeHints::NodeHints(const ModelNode &node)
}
NodeHints::NodeHints(const NodeMetaInfo &metaInfo)
+ : m_metaInfo{metaInfo}
{
for (const auto &[name, expression] : metaInfo.typeHints())
m_hints.insert(name.toQString(), expression.toQString());
}
-NodeHints::NodeHints(const ItemLibraryEntry &entry)
+NodeHints::NodeHints(const ItemLibraryEntry &entry, [[maybe_unused]] Model *model)
#ifdef QDS_USE_PROJECTSTORAGE
- : NodeHints{entry.metaInfo()}
+ : NodeHints{NodeMetaInfo{entry.typeId(), model->projectStorage()}}
#endif
{
if constexpr (!useProjectStorage())
@@ -135,7 +136,7 @@ bool NodeHints::canBeContainerFor(const ModelNode &potenialChild) const
if (!isValid())
return true;
- auto flagIs = m_modelNode.metaInfo().canBeContainer();
+ auto flagIs = m_metaInfo.canBeContainer();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -151,7 +152,7 @@ bool NodeHints::forceClip() const
if (isSwipeView(modelNode()))
return true;
- auto flagIs = m_modelNode.metaInfo().forceClip();
+ auto flagIs = m_metaInfo.forceClip();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -167,7 +168,7 @@ bool NodeHints::doesLayoutChildren() const
if (isSwipeView(modelNode()))
return true;
- auto flagIs = m_modelNode.metaInfo().doesLayoutChildren();
+ auto flagIs = m_metaInfo.doesLayoutChildren();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -177,7 +178,7 @@ bool NodeHints::doesLayoutChildren() const
bool NodeHints::canBeDroppedInFormEditor() const
{
- auto flagIs = m_modelNode.metaInfo().canBeDroppedInFormEditor();
+ auto flagIs = m_metaInfo.canBeDroppedInFormEditor();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -187,7 +188,7 @@ bool NodeHints::canBeDroppedInFormEditor() const
bool NodeHints::canBeDroppedInNavigator() const
{
- auto flagIs = m_modelNode.metaInfo().canBeDroppedInNavigator();
+ auto flagIs = m_metaInfo.canBeDroppedInNavigator();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -197,7 +198,7 @@ bool NodeHints::canBeDroppedInNavigator() const
bool NodeHints::canBeDroppedInView3D() const
{
- auto flagIs = m_modelNode.metaInfo().canBeDroppedInView3D();
+ auto flagIs = m_metaInfo.canBeDroppedInView3D();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -210,7 +211,7 @@ bool NodeHints::isMovable() const
if (!isValid())
return true;
- auto flagIs = m_modelNode.metaInfo().isMovable();
+ auto flagIs = m_metaInfo.isMovable();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -223,7 +224,7 @@ bool NodeHints::isResizable() const
if (!isValid())
return true;
- auto flagIs = m_modelNode.metaInfo().isResizable();
+ auto flagIs = m_metaInfo.isResizable();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -236,7 +237,7 @@ bool NodeHints::hasFormEditorItem() const
if (!isValid())
return true;
- auto flagIs = m_modelNode.metaInfo().hasFormEditorItem();
+ auto flagIs = m_metaInfo.hasFormEditorItem();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -252,7 +253,7 @@ bool NodeHints::isStackedContainer() const
if (isSwipeView(modelNode()))
return true;
- auto flagIs = m_modelNode.metaInfo().isStackedContainer();
+ auto flagIs = m_metaInfo.isStackedContainer();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -299,7 +300,7 @@ bool NodeHints::takesOverRenderingOfChildren() const
if (!isValid())
return false;
- auto flagIs = m_modelNode.metaInfo().takesOverRenderingOfChildren();
+ auto flagIs = m_metaInfo.takesOverRenderingOfChildren();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -312,7 +313,7 @@ bool NodeHints::visibleInNavigator() const
if (!isValid())
return false;
- auto flagIs = m_modelNode.metaInfo().visibleInNavigator();
+ auto flagIs = m_metaInfo.visibleInNavigator();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -322,7 +323,7 @@ bool NodeHints::visibleInNavigator() const
bool NodeHints::visibleInLibrary() const
{
- auto flagIs = m_modelNode.metaInfo().visibleInLibrary();
+ auto flagIs = m_metaInfo.visibleInLibrary();
if (flagIs != FlagIs::Set)
return convert(flagIs);
@@ -391,9 +392,9 @@ NodeHints NodeHints::fromModelNode(const ModelNode &modelNode)
return NodeHints(modelNode);
}
-NodeHints NodeHints::fromItemLibraryEntry(const ItemLibraryEntry &entry)
+NodeHints NodeHints::fromItemLibraryEntry(const ItemLibraryEntry &entry, Model *model)
{
- return NodeHints(entry);
+ return NodeHints(entry, model);
}
const ModelNode &NodeHints::modelNode() const
diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
index 85f904666c..c656634272 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
@@ -53,6 +53,10 @@ NodeMetaInfo object will result in an InvalidMetaInfoException being thrown.
namespace {
+using Storage::ModuleKind;
+
+auto category = MetaInfoTracing::category;
+
struct TypeDescription
{
QString className;
@@ -919,8 +923,11 @@ const ObjectValue *NodeMetaInfoPrivate::getObjectValue() const
ContextPtr NodeMetaInfoPrivate::context() const
{
+#ifndef QDS_USE_PROJECTSTORAGE
if (m_model && m_model->rewriterView() && m_model->rewriterView()->scopeChain())
return m_model->rewriterView()->scopeChain()->context();
+#endif
+
return ContextPtr(nullptr);
}
@@ -1490,15 +1497,20 @@ MetaInfoType NodeMetaInfo::type() const
{
if constexpr (useProjectStorage()) {
if (isValid()) {
- switch (typeData().traits.kind) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type"_t, category(), keyValue("type id", m_typeId)};
+ auto kind = typeData().traits.kind;
+ tracer.end(keyValue("type kind", kind));
+
+ switch (kind) {
case Storage::TypeTraitsKind::Reference:
return MetaInfoType::Reference;
case Storage::TypeTraitsKind::Value:
return MetaInfoType::Value;
case Storage::TypeTraitsKind::Sequence:
return MetaInfoType::Sequence;
- default:
- break;
+ case Storage::TypeTraitsKind::None:
+ return MetaInfoType::None;
}
}
}
@@ -1508,16 +1520,38 @@ MetaInfoType NodeMetaInfo::type() const
bool NodeMetaInfo::isFileComponent() const
{
- if constexpr (useProjectStorage())
- return isValid() && typeData().traits.isFileComponent;
- else
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is file component"_t, category(), keyValue("type id", m_typeId)};
+
+ auto isFileComponent = typeData().traits.isFileComponent;
+
+ tracer.end(keyValue("is file component", isFileComponent));
+
+ return isFileComponent;
+
+ } else {
return isValid() && m_privateData->isFileComponent();
+ }
}
bool NodeMetaInfo::isProjectComponent() const
{
if constexpr (useProjectStorage()) {
- return isValid() && typeData().traits.isProjectComponent;
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is project component"_t, category(), keyValue("type id", m_typeId)};
+
+ auto isProjectComponent = typeData().traits.isProjectComponent;
+
+ tracer.end(keyValue("is project component", isProjectComponent));
+
+ return isProjectComponent;
}
return false;
@@ -1526,7 +1560,17 @@ bool NodeMetaInfo::isProjectComponent() const
bool NodeMetaInfo::isInProjectModule() const
{
if constexpr (useProjectStorage()) {
- return isValid() && typeData().traits.isInProjectModule;
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is project module"_t, category(), keyValue("type id", m_typeId)};
+
+ auto isInProjectModule = typeData().traits.isInProjectModule;
+
+ tracer.end(keyValue("is project module", isInProjectModule));
+
+ return isInProjectModule;
}
return false;
@@ -1535,10 +1579,17 @@ bool NodeMetaInfo::isInProjectModule() const
FlagIs NodeMetaInfo::canBeContainer() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.canBeContainer;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"can be container"_t, category(), keyValue("type id", m_typeId)};
+
+ auto canBeContainer = typeData().traits.canBeContainer;
- return FlagIs::False;
+ tracer.end(keyValue("can be container", canBeContainer));
+
+ return canBeContainer;
}
return FlagIs::Set;
@@ -1547,10 +1598,17 @@ FlagIs NodeMetaInfo::canBeContainer() const
FlagIs NodeMetaInfo::forceClip() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.forceClip;
+ if (!isValid())
+ return FlagIs::False;
- return FlagIs::False;
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"force clip"_t, category(), keyValue("type id", m_typeId)};
+
+ auto forceClip = typeData().traits.forceClip;
+
+ tracer.end(keyValue("force clip", forceClip));
+
+ return forceClip;
}
return FlagIs::Set;
@@ -1559,10 +1617,17 @@ FlagIs NodeMetaInfo::forceClip() const
FlagIs NodeMetaInfo::doesLayoutChildren() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.doesLayoutChildren;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"does layout children"_t, category(), keyValue("type id", m_typeId)};
- return FlagIs::False;
+ auto doesLayoutChildren = typeData().traits.doesLayoutChildren;
+
+ tracer.end(keyValue("does layout children", doesLayoutChildren));
+
+ return doesLayoutChildren;
}
return FlagIs::Set;
@@ -1571,10 +1636,19 @@ FlagIs NodeMetaInfo::doesLayoutChildren() const
FlagIs NodeMetaInfo::canBeDroppedInFormEditor() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.canBeDroppedInFormEditor;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"can be dropped in form editor"_t,
+ category(),
+ keyValue("type id", m_typeId)};
- return FlagIs::False;
+ auto canBeDroppedInFormEditor = typeData().traits.canBeDroppedInFormEditor;
+
+ tracer.end(keyValue("can be dropped in form editor", canBeDroppedInFormEditor));
+
+ return canBeDroppedInFormEditor;
}
return FlagIs::Set;
@@ -1583,10 +1657,19 @@ FlagIs NodeMetaInfo::canBeDroppedInFormEditor() const
FlagIs NodeMetaInfo::canBeDroppedInNavigator() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.canBeDroppedInNavigator;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"can be dropped in navigator"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
+ auto canBeDroppedInNavigator = typeData().traits.canBeDroppedInNavigator;
- return FlagIs::False;
+ tracer.end(keyValue("can be dropped in navigator", canBeDroppedInNavigator));
+
+ return canBeDroppedInNavigator;
}
return FlagIs::Set;
@@ -1595,10 +1678,19 @@ FlagIs NodeMetaInfo::canBeDroppedInNavigator() const
FlagIs NodeMetaInfo::canBeDroppedInView3D() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.canBeDroppedInView3D;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"can be dropped in view3d"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
+ auto canBeDroppedInView3D = typeData().traits.canBeDroppedInView3D;
+
+ tracer.end(keyValue("can be dropped in view3d", canBeDroppedInView3D));
- return FlagIs::False;
+ return canBeDroppedInView3D;
}
return FlagIs::Set;
@@ -1607,10 +1699,17 @@ FlagIs NodeMetaInfo::canBeDroppedInView3D() const
FlagIs NodeMetaInfo::isMovable() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.isMovable;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is movable"_t, category(), keyValue("type id", m_typeId)};
- return FlagIs::False;
+ auto isMovable = typeData().traits.isMovable;
+
+ tracer.end(keyValue("is movable", isMovable));
+
+ return isMovable;
}
return FlagIs::Set;
@@ -1619,10 +1718,17 @@ FlagIs NodeMetaInfo::isMovable() const
FlagIs NodeMetaInfo::isResizable() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.isResizable;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is resizable"_t, category(), keyValue("type id", m_typeId)};
+
+ auto isResizable = typeData().traits.isResizable;
- return FlagIs::False;
+ tracer.end(keyValue("is resizable", isResizable));
+
+ return isResizable;
}
return FlagIs::Set;
@@ -1631,10 +1737,17 @@ FlagIs NodeMetaInfo::isResizable() const
FlagIs NodeMetaInfo::hasFormEditorItem() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.hasFormEditorItem;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"has form editor item"_t, category(), keyValue("type id", m_typeId)};
+
+ auto hasFormEditorItem = typeData().traits.hasFormEditorItem;
- return FlagIs::False;
+ tracer.end(keyValue("has form editor item", hasFormEditorItem));
+
+ return hasFormEditorItem;
}
return FlagIs::Set;
@@ -1643,10 +1756,17 @@ FlagIs NodeMetaInfo::hasFormEditorItem() const
FlagIs NodeMetaInfo::isStackedContainer() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.isStackedContainer;
+ if (!isValid())
+ return FlagIs::False;
- return FlagIs::False;
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is stacked container"_t, category(), keyValue("type id", m_typeId)};
+
+ auto isStackedContainer = typeData().traits.isStackedContainer;
+
+ tracer.end(keyValue("is stacked container", isStackedContainer));
+
+ return isStackedContainer;
}
return FlagIs::Set;
@@ -1655,10 +1775,19 @@ FlagIs NodeMetaInfo::isStackedContainer() const
FlagIs NodeMetaInfo::takesOverRenderingOfChildren() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.takesOverRenderingOfChildren;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"takes over rendering of children"_t,
+ category(),
+ keyValue("type id", m_typeId)};
- return FlagIs::False;
+ auto takesOverRenderingOfChildren = typeData().traits.takesOverRenderingOfChildren;
+
+ tracer.end(keyValue("takes over rendering of children", takesOverRenderingOfChildren));
+
+ return takesOverRenderingOfChildren;
}
return FlagIs::Set;
@@ -1667,10 +1796,17 @@ FlagIs NodeMetaInfo::takesOverRenderingOfChildren() const
FlagIs NodeMetaInfo::visibleInNavigator() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.visibleInNavigator;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"visible in navigator"_t, category(), keyValue("type id", m_typeId)};
+
+ auto visibleInNavigator = typeData().traits.visibleInNavigator;
- return FlagIs::False;
+ tracer.end(keyValue("visible in navigator", visibleInNavigator));
+
+ return visibleInNavigator;
}
return FlagIs::Set;
@@ -1679,10 +1815,17 @@ FlagIs NodeMetaInfo::visibleInNavigator() const
FlagIs NodeMetaInfo::visibleInLibrary() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return typeData().traits.visibleInLibrary;
+ if (!isValid())
+ return FlagIs::False;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"visible in library"_t, category(), keyValue("type id", m_typeId)};
+
+ auto visibleInLibrary = typeData().traits.visibleInLibrary;
- return FlagIs::False;
+ tracer.end(keyValue("visible in library", visibleInLibrary));
+
+ return visibleInLibrary;
}
return FlagIs::Set;
@@ -1694,6 +1837,12 @@ namespace {
TypeId typeId,
Utils::SmallStringView propertyName)
{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get combound property id"_t,
+ category(),
+ keyValue("type id", typeId),
+ keyValue("property name", propertyName)};
+
auto begin = propertyName.begin();
const auto end = propertyName.end();
@@ -1709,11 +1858,17 @@ namespace {
if (propertyId && found != end) {
begin = std::next(found);
- return projectStorage.propertyDeclarationId(propertyTypeId, {begin, end});
+ auto id = projectStorage.propertyDeclarationId(propertyTypeId, {begin, end});
+
+ tracer.end(keyValue("property id", id));
+
+ return id;
}
}
}
+ tracer.end(keyValue("property id", propertyId));
+
return propertyId;
}
@@ -1721,10 +1876,24 @@ namespace {
bool NodeMetaInfo::hasProperty(Utils::SmallStringView propertyName) const
{
- if constexpr (useProjectStorage())
- return isValid() && bool(propertyId(*m_projectStorage, m_typeId, propertyName));
- else
+ if constexpr (useProjectStorage()) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"has property"_t,
+ category(),
+ keyValue("type id", m_typeId),
+ keyValue("property name", propertyName)};
+
+ if (!isValid())
+ return false;
+
+ auto hasPropertyId = bool(propertyId(*m_projectStorage, m_typeId, propertyName));
+
+ tracer.end(keyValue("has property", hasPropertyId));
+
+ return hasPropertyId;
+ } else {
return isValid() && m_privateData->properties().contains(QByteArrayView(propertyName));
+ }
}
PropertyMetaInfos NodeMetaInfo::properties() const
@@ -1733,12 +1902,14 @@ PropertyMetaInfos NodeMetaInfo::properties() const
return {};
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<PropertyMetaInfos>(
- m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) {
- return PropertyMetaInfo{id, m_projectStorage};
- });
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get properties"_t, category(), keyValue("type id", m_typeId)};
+
+ return Utils::transform<PropertyMetaInfos>(
+ m_projectStorage->propertyDeclarationIds(m_typeId), [&](auto id) {
+ return PropertyMetaInfo{id, m_projectStorage};
+ });
+
} else {
const auto &properties = m_privateData->properties();
@@ -1750,19 +1921,22 @@ PropertyMetaInfos NodeMetaInfo::properties() const
return propertyMetaInfos;
}
-
- return {};
}
PropertyMetaInfos NodeMetaInfo::localProperties() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<PropertyMetaInfos>(
- m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) {
- return PropertyMetaInfo{id, m_projectStorage};
- });
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get local properties"_t, category(), keyValue("type id", m_typeId)};
+
+ return Utils::transform<PropertyMetaInfos>(
+ m_projectStorage->localPropertyDeclarationIds(m_typeId), [&](auto id) {
+ return PropertyMetaInfo{id, m_projectStorage};
+ });
+
} else {
const auto &properties = m_privateData->localProperties();
@@ -1774,71 +1948,82 @@ PropertyMetaInfos NodeMetaInfo::localProperties() const
return propertyMetaInfos;
}
-
- return {};
}
PropertyMetaInfo NodeMetaInfo::property(const PropertyName &propertyName) const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid())
- return {propertyId(*m_projectStorage, m_typeId, propertyName), m_projectStorage};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property"_t,
+ category(),
+ keyValue("type id", m_typeId),
+ keyValue("property name", propertyName)};
+
+ return {propertyId(*m_projectStorage, m_typeId, propertyName), m_projectStorage};
} else {
if (hasProperty(propertyName)) {
return PropertyMetaInfo{m_privateData, propertyName};
}
+ return {};
}
-
- return {};
}
PropertyNameList NodeMetaInfo::signalNames() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<PropertyNameList>(m_projectStorage->signalDeclarationNames(
- m_typeId),
- [&](const auto &name) {
- return name.toQByteArray();
- });
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get signal names"_t, category(), keyValue("type id", m_typeId)};
+
+ return Utils::transform<PropertyNameList>(m_projectStorage->signalDeclarationNames(m_typeId),
+ [&](const auto &name) {
+ return name.toQByteArray();
+ });
+
} else {
- if (isValid())
- return m_privateData->signalNames();
+ return m_privateData->signalNames();
}
-
- return {};
}
PropertyNameList NodeMetaInfo::slotNames() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<PropertyNameList>(m_projectStorage->functionDeclarationNames(
- m_typeId),
- [&](const auto &name) {
- return name.toQByteArray();
- });
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get slot names"_t, category(), keyValue("type id", m_typeId)};
+ return Utils::transform<PropertyNameList>(m_projectStorage->functionDeclarationNames(m_typeId),
+ [&](const auto &name) {
+ return name.toQByteArray();
+ });
} else {
- if (isValid())
- return m_privateData->slotNames();
+ return m_privateData->slotNames();
}
-
- return {};
}
PropertyName NodeMetaInfo::defaultPropertyName() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- if (auto name = m_projectStorage->propertyName(typeData().defaultPropertyId)) {
- return name->toQByteArray();
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get default property name"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+ if (auto name = m_projectStorage->propertyName(defaultPropertyDeclarationId())) {
+ tracer.end(keyValue("default property name", name));
+ return name->toQByteArray();
}
+
} else {
- if (isValid())
- return m_privateData->defaultPropertyName();
+ return m_privateData->defaultPropertyName();
}
return {};
@@ -1846,88 +2031,128 @@ PropertyName NodeMetaInfo::defaultPropertyName() const
PropertyMetaInfo NodeMetaInfo::defaultProperty() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return PropertyMetaInfo(typeData().defaultPropertyId, m_projectStorage);
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get default property"_t, category(), keyValue("type id", m_typeId)};
+
+ auto id = defaultPropertyDeclarationId();
+
+ tracer.end(keyValue("default property id", id));
+
+ return PropertyMetaInfo(id, m_projectStorage);
} else {
return property(defaultPropertyName());
}
-
- return {};
}
bool NodeMetaInfo::hasDefaultProperty() const
{
- if constexpr (useProjectStorage())
- return isValid() && bool(typeData().defaultPropertyId);
- else
+ if (!isValid())
+ return false;
+
+ if constexpr (useProjectStorage()) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"has default property"_t, category(), keyValue("type id", m_typeId)};
+ auto hasDefaultProperty = bool(defaultPropertyDeclarationId());
+ tracer.end(keyValue("has default property", hasDefaultProperty));
+
+ return hasDefaultProperty;
+ } else {
return !defaultPropertyName().isEmpty();
+ }
}
std::vector<NodeMetaInfo> NodeMetaInfo::selfAndPrototypes() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<NodeMetaInfos>(
- m_projectStorage->prototypeAndSelfIds(m_typeId), [&](TypeId typeId) {
- return NodeMetaInfo{typeId, m_projectStorage};
- });
- }
- } else {
- if (isValid()) {
- NodeMetaInfos hierarchy = {*this};
- Model *model = m_privateData->model();
- for (const TypeDescription &type : m_privateData->prototypes()) {
- auto &last = hierarchy.emplace_back(model,
- type.className.toUtf8(),
- type.majorVersion,
- type.minorVersion);
- if (!last.isValid())
- hierarchy.pop_back();
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get self and prototypes"_t,
+ category(),
+ keyValue("type id", m_typeId)};
- return hierarchy;
+ return Utils::transform<NodeMetaInfos>(m_projectStorage->prototypeAndSelfIds(m_typeId),
+ [&](TypeId typeId) {
+ return NodeMetaInfo{typeId, m_projectStorage};
+ });
+ } else {
+ NodeMetaInfos hierarchy = {*this};
+ Model *model = m_privateData->model();
+ for (const TypeDescription &type : m_privateData->prototypes()) {
+ auto &last = hierarchy.emplace_back(model,
+ type.className.toUtf8(),
+ type.majorVersion,
+ type.minorVersion);
+ if (!last.isValid())
+ hierarchy.pop_back();
}
- }
- return {};
+ return hierarchy;
+ }
}
NodeMetaInfos NodeMetaInfo::prototypes() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return Utils::transform<NodeMetaInfos>(
- m_projectStorage->prototypeIds(m_typeId), [&](TypeId typeId) {
- return NodeMetaInfo{typeId, m_projectStorage};
- });
- }
- } else {
- if (isValid()) {
- NodeMetaInfos hierarchy;
- Model *model = m_privateData->model();
- for (const TypeDescription &type : m_privateData->prototypes()) {
- auto &last = hierarchy.emplace_back(model,
- type.className.toUtf8(),
- type.majorVersion,
- type.minorVersion);
- if (!last.isValid())
- hierarchy.pop_back();
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)};
+ return Utils::transform<NodeMetaInfos>(m_projectStorage->prototypeIds(m_typeId),
+ [&](TypeId typeId) {
+ return NodeMetaInfo{typeId, m_projectStorage};
+ });
- return hierarchy;
+ } else {
+ NodeMetaInfos hierarchy;
+ Model *model = m_privateData->model();
+ for (const TypeDescription &type : m_privateData->prototypes()) {
+ auto &last = hierarchy.emplace_back(model,
+ type.className.toUtf8(),
+ type.majorVersion,
+ type.minorVersion);
+ if (!last.isValid())
+ hierarchy.pop_back();
}
+
+ return hierarchy;
}
+}
- return {};
+namespace {
+template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary>
+bool isBasedOnCommonType(NotNullPointer<const ProjectStorageType> projectStorage, TypeId typeId)
+{
+ if (!typeId)
+ return false;
+
+ auto base = projectStorage->commonTypeId<moduleName, typeName, moduleKind>();
+
+ return projectStorage->isBasedOn(typeId, base);
}
+} // namespace
bool NodeMetaInfo::defaultPropertyIsComponent() const
{
- if (hasDefaultProperty())
- return defaultProperty().propertyType().isQmlComponent();
+ if (!isValid())
+ return false;
- return false;
+ if (useProjectStorage()) {
+ auto id = defaultPropertyDeclarationId();
+ auto propertyDeclaration = m_projectStorage->propertyDeclaration(id);
+
+ using namespace Storage::Info;
+ return isBasedOnCommonType<QML, Component>(m_projectStorage, propertyDeclaration->typeId);
+ } else {
+ if (hasDefaultProperty())
+ return defaultProperty().propertyType().isQmlComponent();
+ return false;
+ }
}
TypeName NodeMetaInfo::displayName() const
@@ -1973,10 +2198,16 @@ int NodeMetaInfo::minorVersion() const
Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return m_projectStorage->exportedTypeNames(m_typeId);
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get all exported type names"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
+ return m_projectStorage->exportedTypeNames(m_typeId);
}
return {};
@@ -1984,10 +2215,17 @@ Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const
Storage::Info::ExportedTypeNames NodeMetaInfo::exportedTypeNamesForSourceId(SourceId sourceId) const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return m_projectStorage->exportedTypeNames(m_typeId, sourceId);
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get exported type names for source id"_t,
+ category(),
+ keyValue("type id", m_typeId),
+ keyValue("source id", sourceId)};
+
+ return m_projectStorage->exportedTypeNames(m_typeId, sourceId);
}
return {};
@@ -1995,9 +2233,18 @@ Storage::Info::ExportedTypeNames NodeMetaInfo::exportedTypeNamesForSourceId(Sour
Storage::Info::TypeHints NodeMetaInfo::typeHints() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid())
- return m_projectStorage->typeHints(m_typeId);
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type hints"_t, category(), keyValue("type id", m_typeId)};
+
+ auto hints = m_projectStorage->typeHints(m_typeId);
+
+ tracer.end(keyValue("type hints", hints));
+
+ return hints;
}
return {};
@@ -2005,9 +2252,18 @@ Storage::Info::TypeHints NodeMetaInfo::typeHints() const
Utils::PathString NodeMetaInfo::iconPath() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid())
- return m_projectStorage->typeIconPath(m_typeId);
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get icon path"_t, category(), keyValue("type id", m_typeId)};
+
+ auto iconPath = m_projectStorage->typeIconPath(m_typeId);
+
+ tracer.end(keyValue("icon path", iconPath));
+
+ return iconPath;
}
return {};
@@ -2015,9 +2271,20 @@ Utils::PathString NodeMetaInfo::iconPath() const
Storage::Info::ItemLibraryEntries NodeMetaInfo::itemLibrariesEntries() const
{
+ if (!isValid())
+ return {};
+
if constexpr (useProjectStorage()) {
- if (isValid())
- return m_projectStorage->itemLibraryEntries(m_typeId);
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get item library entries"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
+ auto entries = m_projectStorage->itemLibraryEntries(m_typeId);
+
+ tracer.end(keyValue("item library entries", entries));
+
+ return entries;
}
return {};
@@ -2025,10 +2292,18 @@ Storage::Info::ItemLibraryEntries NodeMetaInfo::itemLibrariesEntries() const
SourceId NodeMetaInfo::sourceId() const
{
+ if (!isValid())
+ return SourceId{};
+
if constexpr (useProjectStorage()) {
- if (isValid()) {
- return typeData().sourceId;
- }
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get source id"_t, category(), keyValue("type id", m_typeId)};
+
+ auto id = typeData().sourceId;
+
+ tracer.end(keyValue("source id", id));
+
+ return id;
}
return SourceId{};
@@ -2061,18 +2336,31 @@ QString NodeMetaInfo::requiredImportString() const
if (!isValid())
return {};
- Import imp = m_privateData->requiredImport();
- if (!imp.isEmpty())
- return imp.toImportString();
+ if constexpr (!useProjectStorage()) {
+ Import imp = m_privateData->requiredImport();
+ if (!imp.isEmpty())
+ return imp.toImportString();
+ }
return {};
}
SourceId NodeMetaInfo::propertyEditorPathId() const
{
+ if (!isValid())
+ return SourceId{};
+
if (useProjectStorage()) {
- if (isValid())
- return m_projectStorage->propertyEditorPathId(m_typeId);
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property editor path id"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
+ auto id = m_projectStorage->propertyEditorPathId(m_typeId);
+
+ tracer.end(keyValue("property editor path id", id));
+
+ return id;
}
return SourceId{};
@@ -2086,6 +2374,14 @@ const Storage::Info::Type &NodeMetaInfo::typeData() const
return *m_typeData;
}
+PropertyDeclarationId NodeMetaInfo::defaultPropertyDeclarationId() const
+{
+ if (!m_defaultPropertyId)
+ m_defaultPropertyId.emplace(m_projectStorage->defaultPropertyDeclarationId(m_typeId));
+
+ return *m_defaultPropertyId;
+}
+
bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const
{
if (!isValid()) {
@@ -2122,9 +2418,13 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
bool NodeMetaInfo::isSuitableForMouseAreaFill() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is suitable for mouse area fill"_t,
+ category(),
+ keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto itemId = m_projectStorage->commonTypeId<QtQuick, Item>();
@@ -2132,11 +2432,16 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const
auto controlsControlId = m_projectStorage->commonTypeId<QtQuick_Controls, Control>();
auto templatesControlId = m_projectStorage->commonTypeId<QtQuick_Templates, Control>();
- return m_projectStorage->isBasedOn(m_typeId,
- itemId,
- mouseAreaId,
- controlsControlId,
- templatesControlId);
+ auto isSuitableForMouseAreaFill = m_projectStorage->isBasedOn(m_typeId,
+ itemId,
+ mouseAreaId,
+ controlsControlId,
+ templatesControlId);
+
+ tracer.end(keyValue("is suitable for mouse area fill", isSuitableForMouseAreaFill));
+
+ return isSuitableForMouseAreaFill;
+
} else {
return isSubclassOf("QtQuick.Item") && !isSubclassOf("QtQuick.MouseArea")
&& !isSubclassOf("QtQuick.Controls.Control")
@@ -2147,6 +2452,15 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const
bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t,
+ category(),
+ keyValue("type id", m_typeId),
+ keyValue("meta info type id", metaInfo.m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId);
} else {
if (!isValid())
@@ -2160,6 +2474,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const
bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId);
} else {
if (!isValid())
@@ -2178,6 +2498,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
const NodeMetaInfo &metaInfo3) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId,
metaInfo1.m_typeId,
metaInfo2.m_typeId,
@@ -2202,6 +2528,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
const NodeMetaInfo &metaInfo4) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId,
metaInfo1.m_typeId,
metaInfo2.m_typeId,
@@ -2229,6 +2561,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
const NodeMetaInfo &metaInfo5) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId,
metaInfo1.m_typeId,
metaInfo2.m_typeId,
@@ -2261,6 +2599,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
const NodeMetaInfo &metaInfo6) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId,
metaInfo1.m_typeId,
metaInfo2.m_typeId,
@@ -2298,6 +2642,12 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
const NodeMetaInfo &metaInfo7) const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)};
+
return m_projectStorage->isBasedOn(m_typeId,
metaInfo1.m_typeId,
metaInfo2.m_typeId,
@@ -2330,26 +2680,14 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
}
}
-namespace {
-template<const char *moduleName, const char *typeName>
-bool isBasedOnCommonType(NotNullPointer<const ProjectStorageType> projectStorage, TypeId typeId)
-{
- if (!typeId) {
- return false;
- }
-
- auto base = projectStorage->commonTypeId<moduleName, typeName>();
-
- return projectStorage->isBasedOn(typeId, base);
-}
-} // namespace
-
bool NodeMetaInfo::isGraphicalItem() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is graphical item"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto itemId = m_projectStorage->commonTypeId<QtQuick, Item>();
@@ -2369,6 +2707,12 @@ bool NodeMetaInfo::isGraphicalItem() const
bool NodeMetaInfo::isQtObject() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is Qt object"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QML, QtObject>(m_projectStorage, m_typeId);
} else {
@@ -2379,6 +2723,14 @@ bool NodeMetaInfo::isQtObject() const
bool NodeMetaInfo::isQtQmlConnections() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is Qt Qml connections"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQml, Connections>(m_projectStorage, m_typeId);
} else {
@@ -2389,9 +2741,11 @@ bool NodeMetaInfo::isQtQmlConnections() const
bool NodeMetaInfo::isLayoutable() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is layoutable"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto positionerId = m_projectStorage->commonTypeId<QtQuick, Positioner>();
@@ -2410,6 +2764,14 @@ bool NodeMetaInfo::isLayoutable() const
bool NodeMetaInfo::isQtQuickLayoutsLayout() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Layouts.Layout"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Layouts, Layout>(m_projectStorage, m_typeId);
} else {
@@ -2420,9 +2782,11 @@ bool NodeMetaInfo::isQtQuickLayoutsLayout() const
bool NodeMetaInfo::isView() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is view"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto listViewId = m_projectStorage->commonTypeId<QtQuick, ListView>();
@@ -2439,17 +2803,20 @@ bool NodeMetaInfo::isView() const
bool NodeMetaInfo::usesCustomParser() const
{
if constexpr (useProjectStorage()) {
- return isValid() && typeData().traits.usesCustomParser;
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)};
+
+ return typeData().traits.usesCustomParser;
} else {
if (!isValid())
return false;
- auto type = typeName();
- return type == "QtQuick.VisualItemModel" || type == "Qt.VisualItemModel"
- || type == "QtQuick.VisualDataModel" || type == "Qt.VisualDataModel"
- || type == "QtQuick.ListModel" || type == "Qt.ListModel"
- || type == "QtQml.Models.ListModel" || type == "QtQuick.XmlListModel"
- || type == "Qt.XmlListModel" || type == "QtQml.XmlListModel.XmlListModel";
+ auto type = simplifiedTypeName();
+ return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel"
+ || type == "XmlListModel";
}
}
@@ -2468,8 +2835,14 @@ bool isTypeId(TypeId typeId, TypeIds... otherTypeIds)
bool NodeMetaInfo::isVector2D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is vector2d"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
- return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector2d>());
+ return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector2d>());
} else {
if (!m_privateData)
return false;
@@ -2483,8 +2856,14 @@ bool NodeMetaInfo::isVector2D() const
bool NodeMetaInfo::isVector3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is vector3d"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
- return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector3d>());
+ return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector3d>());
} else {
if (!m_privateData)
return false;
@@ -2498,8 +2877,14 @@ bool NodeMetaInfo::isVector3D() const
bool NodeMetaInfo::isVector4D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is vector4d"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
- return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector4d>());
+ return isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, vector4d>());
} else {
if (!m_privateData)
return false;
@@ -2513,6 +2898,14 @@ bool NodeMetaInfo::isVector4D() const
bool NodeMetaInfo::isQtQuickPropertyChanges() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.PropertyChanges"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Storage::Info::PropertyChanges>(m_projectStorage,
m_typeId);
@@ -2524,6 +2917,14 @@ bool NodeMetaInfo::isQtQuickPropertyChanges() const
bool NodeMetaInfo::isQtSafeRendererSafeRendererPicture() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is Qt.SafeRenderer.SafeRendererPicture"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<Qt_SafeRenderer, SafeRendererPicture>(m_projectStorage, m_typeId);
} else {
@@ -2534,6 +2935,14 @@ bool NodeMetaInfo::isQtSafeRendererSafeRendererPicture() const
bool NodeMetaInfo::isQtSafeRendererSafePicture() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is Qt.SafeRenderer.SafePicture"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<Qt_SafeRenderer, SafePicture>(m_projectStorage, m_typeId);
} else {
@@ -2544,6 +2953,14 @@ bool NodeMetaInfo::isQtSafeRendererSafePicture() const
bool NodeMetaInfo::isQtQuickTimelineKeyframe() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Timeline.Keyframe"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Timeline, Keyframe>(m_projectStorage, m_typeId);
@@ -2555,6 +2972,14 @@ bool NodeMetaInfo::isQtQuickTimelineKeyframe() const
bool NodeMetaInfo::isQtQuickTimelineTimelineAnimation() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Timeline.TimelineAnimation"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Timeline, TimelineAnimation>(m_projectStorage, m_typeId);
} else {
@@ -2565,6 +2990,14 @@ bool NodeMetaInfo::isQtQuickTimelineTimelineAnimation() const
bool NodeMetaInfo::isQtQuickTimelineTimeline() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Timeline.Timeline"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Timeline, Timeline>(m_projectStorage, m_typeId);
} else {
@@ -2575,6 +3008,14 @@ bool NodeMetaInfo::isQtQuickTimelineTimeline() const
bool NodeMetaInfo::isQtQuickTimelineKeyframeGroup() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Timeline.KeyframeGroup"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Timeline, KeyframeGroup>(m_projectStorage, m_typeId);
} else {
@@ -2585,9 +3026,11 @@ bool NodeMetaInfo::isQtQuickTimelineKeyframeGroup() const
bool NodeMetaInfo::isListOrGridView() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is list or grid view"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto listViewId = m_projectStorage->commonTypeId<QtQuick, ListView>();
@@ -2601,9 +3044,11 @@ bool NodeMetaInfo::isListOrGridView() const
bool NodeMetaInfo::isNumber() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is number"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto intId = m_projectStorage->builtinTypeId<int>();
@@ -2624,6 +3069,14 @@ bool NodeMetaInfo::isNumber() const
bool NodeMetaInfo::isQtQuickExtrasPicture() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Extras.Picture"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Extras, Picture>(m_projectStorage, m_typeId);
} else {
@@ -2634,6 +3087,12 @@ bool NodeMetaInfo::isQtQuickExtrasPicture() const
bool NodeMetaInfo::isQtQuickImage() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Image"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Image>(m_projectStorage, m_typeId);
@@ -2645,6 +3104,14 @@ bool NodeMetaInfo::isQtQuickImage() const
bool NodeMetaInfo::isQtQuickBorderImage() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.BorderImage"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, BorderImage>(m_projectStorage, m_typeId);
@@ -2656,7 +3123,13 @@ bool NodeMetaInfo::isQtQuickBorderImage() const
bool NodeMetaInfo::isAlias() const
{
if constexpr (useProjectStorage()) {
- return false; // there is no type alias
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is alias"_t, category(), keyValue("type id", m_typeId)};
+
+ return false; // all types are already resolved
} else {
return isValid() && m_privateData->qualfiedTypeName() == "alias";
}
@@ -2665,6 +3138,14 @@ bool NodeMetaInfo::isAlias() const
bool NodeMetaInfo::isQtQuickPositioner() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Positioner"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Positioner>(m_projectStorage, m_typeId);
@@ -2676,6 +3157,14 @@ bool NodeMetaInfo::isQtQuickPositioner() const
bool NodeMetaInfo::isQtQuickPropertyAnimation() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.PropertyAnimation"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, PropertyAnimation>(m_projectStorage, m_typeId);
} else {
@@ -2686,6 +3175,12 @@ bool NodeMetaInfo::isQtQuickPropertyAnimation() const
bool NodeMetaInfo::isQtQuickRepeater() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Repeater"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Repeater>(m_projectStorage, m_typeId);
} else {
@@ -2696,6 +3191,14 @@ bool NodeMetaInfo::isQtQuickRepeater() const
bool NodeMetaInfo::isQtQuickControlsTabBar() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Controls.TabBar"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Controls, TabBar>(m_projectStorage, m_typeId);
} else {
@@ -2706,6 +3209,14 @@ bool NodeMetaInfo::isQtQuickControlsTabBar() const
bool NodeMetaInfo::isQtQuickControlsSwipeView() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Controls.SwipeView"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Controls, SwipeView>(m_projectStorage, m_typeId);
} else {
@@ -2716,6 +3227,12 @@ bool NodeMetaInfo::isQtQuickControlsSwipeView() const
bool NodeMetaInfo::isQtQuick3DCamera() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Camera"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Camera>(m_projectStorage, m_typeId);
} else {
@@ -2726,6 +3243,14 @@ bool NodeMetaInfo::isQtQuick3DCamera() const
bool NodeMetaInfo::isQtQuick3DBakedLightmap() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.BakedLightmap"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, BakedLightmap>(m_projectStorage, m_typeId);
} else {
@@ -2736,6 +3261,12 @@ bool NodeMetaInfo::isQtQuick3DBakedLightmap() const
bool NodeMetaInfo::isQtQuick3DBuffer() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Buffer"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Buffer>(m_projectStorage, m_typeId);
} else {
@@ -2746,6 +3277,14 @@ bool NodeMetaInfo::isQtQuick3DBuffer() const
bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.InstanceListEntry"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, InstanceListEntry>(m_projectStorage, m_typeId);
} else {
@@ -2756,6 +3295,12 @@ bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const
bool NodeMetaInfo::isQtQuick3DLight() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Light"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Light>(m_projectStorage, m_typeId);
} else {
@@ -2763,9 +3308,17 @@ bool NodeMetaInfo::isQtQuick3DLight() const
}
}
-bool NodeMetaInfo::isQtQuickListElement() const
+bool NodeMetaInfo::isQtQmlModelsListElement() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQml.Models.ListElement"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQml_Models, ListElement>(m_projectStorage, m_typeId);
} else {
@@ -2776,6 +3329,12 @@ bool NodeMetaInfo::isQtQuickListElement() const
bool NodeMetaInfo::isQtQuickListModel() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.ListModel"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQml_Models, ListModel>(m_projectStorage, m_typeId);
} else {
@@ -2786,6 +3345,12 @@ bool NodeMetaInfo::isQtQuickListModel() const
bool NodeMetaInfo::isQtQuickListView() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.ListView"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, ListView>(m_projectStorage, m_typeId);
} else {
@@ -2793,9 +3358,33 @@ bool NodeMetaInfo::isQtQuickListView() const
}
}
+bool QmlDesigner::NodeMetaInfo::isQtQuickGridView() const
+{
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.GridView"_t, category(), keyValue("type id", m_typeId)};
+
+ using namespace Storage::Info;
+ return isBasedOnCommonType<QtQuick, GridView>(m_projectStorage, m_typeId);
+ } else {
+ return isValid() && (isSubclassOf("QtQuick.GridView"));
+ }
+}
+
bool NodeMetaInfo::isQtQuick3DInstanceList() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.InstanceList"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, InstanceList>(m_projectStorage, m_typeId);
} else {
@@ -2806,6 +3395,14 @@ bool NodeMetaInfo::isQtQuick3DInstanceList() const
bool NodeMetaInfo::isQtQuick3DParticles3DParticle3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Particle3D"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D_Particles3D, Particle3D>(m_projectStorage, m_typeId);
} else {
@@ -2816,6 +3413,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DParticle3D() const
bool NodeMetaInfo::isQtQuick3DParticles3DParticleEmitter3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.ParticleEmitter3D"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D_Particles3D, ParticleEmitter3D>(m_projectStorage,
m_typeId);
@@ -2827,6 +3432,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DParticleEmitter3D() const
bool NodeMetaInfo::isQtQuick3DParticles3DAttractor3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Attractor3D"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D_Particles3D, Attractor3D>(m_projectStorage, m_typeId);
} else {
@@ -2837,8 +3450,16 @@ bool NodeMetaInfo::isQtQuick3DParticles3DAttractor3D() const
bool NodeMetaInfo::isQtQuick3DParticlesAbstractShape() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.AbstractShape"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
- return isBasedOnCommonType<QtQuick3D_Particles3D_cppnative, QQuick3DParticleAbstractShape>(
+ return isBasedOnCommonType<QtQuick3D_Particles3D, QQuick3DParticleAbstractShape, ModuleKind::CppLibrary>(
m_projectStorage, m_typeId);
} else {
return isValid() && isSubclassOf("QQuick3DParticleAbstractShape");
@@ -2848,6 +3469,12 @@ bool NodeMetaInfo::isQtQuick3DParticlesAbstractShape() const
bool NodeMetaInfo::isQtQuickItem() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Item"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Item>(m_projectStorage, m_typeId);
} else {
@@ -2858,6 +3485,12 @@ bool NodeMetaInfo::isQtQuickItem() const
bool NodeMetaInfo::isQtQuickPath() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Path"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Path>(m_projectStorage, m_typeId);
} else {
@@ -2868,6 +3501,14 @@ bool NodeMetaInfo::isQtQuickPath() const
bool NodeMetaInfo::isQtQuickPauseAnimation() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.PauseAnimation"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, PauseAnimation>(m_projectStorage, m_typeId);
} else {
@@ -2878,6 +3519,14 @@ bool NodeMetaInfo::isQtQuickPauseAnimation() const
bool NodeMetaInfo::isQtQuickTransition() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Transition"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Transition>(m_projectStorage, m_typeId);
} else {
@@ -2888,6 +3537,14 @@ bool NodeMetaInfo::isQtQuickTransition() const
bool NodeMetaInfo::isQtQuickWindowWindow() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Window.Window"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Window, Window>(m_projectStorage, m_typeId);
} else {
@@ -2898,6 +3555,12 @@ bool NodeMetaInfo::isQtQuickWindowWindow() const
bool NodeMetaInfo::isQtQuickLoader() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Loader"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Loader>(m_projectStorage, m_typeId);
} else {
@@ -2908,6 +3571,12 @@ bool NodeMetaInfo::isQtQuickLoader() const
bool NodeMetaInfo::isQtQuickState() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.State"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, State>(m_projectStorage, m_typeId);
} else {
@@ -2918,9 +3587,17 @@ bool NodeMetaInfo::isQtQuickState() const
bool NodeMetaInfo::isQtQuickStateOperation() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.StateOperation"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
- return isBasedOnCommonType<QtQuick_cppnative, QQuickStateOperation>(m_projectStorage,
- m_typeId);
+ return isBasedOnCommonType<QtQuick, QQuickStateOperation, ModuleKind::CppLibrary>(m_projectStorage,
+ m_typeId);
} else {
return isValid() && isSubclassOf("<cpp>.QQuickStateOperation");
}
@@ -2929,6 +3606,12 @@ bool NodeMetaInfo::isQtQuickStateOperation() const
bool NodeMetaInfo::isQtQuickText() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Text"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick, Text>(m_projectStorage, m_typeId);
} else {
@@ -2939,6 +3622,14 @@ bool NodeMetaInfo::isQtQuickText() const
bool NodeMetaInfo::isQtMultimediaSoundEffect() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtMultimedia.SoundEffect"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtMultimedia, SoundEffect>(m_projectStorage, m_typeId);
} else {
@@ -2949,9 +3640,11 @@ bool NodeMetaInfo::isQtMultimediaSoundEffect() const
bool NodeMetaInfo::isFlowViewItem() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.ViewItem"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto flowItemId = m_projectStorage->commonTypeId<FlowView, FlowItem>();
@@ -2968,6 +3661,12 @@ bool NodeMetaInfo::isFlowViewItem() const
bool NodeMetaInfo::isFlowViewFlowItem() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.FlowItem"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<FlowView, FlowItem>(m_projectStorage, m_typeId);
} else {
@@ -2978,6 +3677,12 @@ bool NodeMetaInfo::isFlowViewFlowItem() const
bool NodeMetaInfo::isFlowViewFlowView() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.FlowView"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<FlowView, FlowView>(m_projectStorage, m_typeId);
} else {
@@ -2998,6 +3703,14 @@ bool NodeMetaInfo::isFlowViewFlowActionArea() const
bool NodeMetaInfo::isFlowViewFlowTransition() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.FlowTransition"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<FlowView, FlowTransition>(m_projectStorage, m_typeId);
} else {
@@ -3008,6 +3721,14 @@ bool NodeMetaInfo::isFlowViewFlowTransition() const
bool NodeMetaInfo::isFlowViewFlowDecision() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.FlowDecision"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<FlowView, FlowDecision>(m_projectStorage, m_typeId);
} else {
@@ -3018,6 +3739,14 @@ bool NodeMetaInfo::isFlowViewFlowDecision() const
bool NodeMetaInfo::isFlowViewFlowWildcard() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is FlowView.FlowWildcard"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<FlowView, FlowWildcard>(m_projectStorage, m_typeId);
} else {
@@ -3028,6 +3757,14 @@ bool NodeMetaInfo::isFlowViewFlowWildcard() const
bool NodeMetaInfo::isQtQuickStudioComponentsGroupItem() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Studio.Components.GroupItem"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Studio_Components, GroupItem>(m_projectStorage, m_typeId);
} else {
@@ -3038,6 +3775,14 @@ bool NodeMetaInfo::isQtQuickStudioComponentsGroupItem() const
bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick.Studio.Utils.JsonListModel"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick_Studio_Components, JsonListModel>(m_projectStorage,
m_typeId);
@@ -3049,6 +3794,12 @@ bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const
bool NodeMetaInfo::isQmlComponent() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QML, Component>(m_projectStorage, m_typeId);
} else {
@@ -3064,6 +3815,12 @@ bool NodeMetaInfo::isQmlComponent() const
bool NodeMetaInfo::isFont() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId<QtQuick, font>());
} else {
@@ -3074,6 +3831,12 @@ bool NodeMetaInfo::isFont() const
bool NodeMetaInfo::isColor() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QColor>());
} else {
@@ -3089,6 +3852,12 @@ bool NodeMetaInfo::isColor() const
bool NodeMetaInfo::isBool() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<bool>());
} else {
@@ -3104,6 +3873,12 @@ bool NodeMetaInfo::isBool() const
bool NodeMetaInfo::isInteger() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<int>());
} else {
@@ -3119,9 +3894,11 @@ bool NodeMetaInfo::isInteger() const
bool NodeMetaInfo::isFloat() const
{
if constexpr (useProjectStorage()) {
- if (!isValid()) {
+ if (!isValid())
return false;
- }
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)};
using namespace Storage::Info;
auto floatId = m_projectStorage->builtinTypeId<float>();
@@ -3141,6 +3918,12 @@ bool NodeMetaInfo::isFloat() const
bool NodeMetaInfo::isVariant() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QVariant>());
} else {
@@ -3156,6 +3939,12 @@ bool NodeMetaInfo::isVariant() const
bool NodeMetaInfo::isString() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QString>());
} else {
@@ -3171,6 +3960,12 @@ bool NodeMetaInfo::isString() const
bool NodeMetaInfo::isUrl() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId<QUrl>());
} else {
@@ -3186,6 +3981,12 @@ bool NodeMetaInfo::isUrl() const
bool NodeMetaInfo::isQtQuick3DTexture() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Texture"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Texture>(m_projectStorage, m_typeId);
} else {
@@ -3197,6 +3998,12 @@ bool NodeMetaInfo::isQtQuick3DTexture() const
bool NodeMetaInfo::isQtQuick3DShader() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Shader"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Shader>(m_projectStorage, m_typeId);
} else {
@@ -3207,6 +4014,12 @@ bool NodeMetaInfo::isQtQuick3DShader() const
bool NodeMetaInfo::isQtQuick3DPass() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Pass"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Pass>(m_projectStorage, m_typeId);
} else {
@@ -3217,6 +4030,12 @@ bool NodeMetaInfo::isQtQuick3DPass() const
bool NodeMetaInfo::isQtQuick3DCommand() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Command"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Command>(m_projectStorage, m_typeId);
} else {
@@ -3227,6 +4046,14 @@ bool NodeMetaInfo::isQtQuick3DCommand() const
bool NodeMetaInfo::isQtQuick3DDefaultMaterial() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.DefaultMaterial"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, DefaultMaterial>(m_projectStorage, m_typeId);
} else {
@@ -3247,6 +4074,12 @@ bool NodeMetaInfo::isQtQuick3DMaterial() const
bool NodeMetaInfo::isQtQuick3DModel() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Model"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Storage::Info::Model>(m_projectStorage, m_typeId);
} else {
@@ -3257,6 +4090,12 @@ bool NodeMetaInfo::isQtQuick3DModel() const
bool NodeMetaInfo::isQtQuick3DNode() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Node"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Node>(m_projectStorage, m_typeId);
} else {
@@ -3267,6 +4106,14 @@ bool NodeMetaInfo::isQtQuick3DNode() const
bool NodeMetaInfo::isQtQuick3DParticles3DAffector3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.Affector3D"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D_Particles3D, Affector3D>(m_projectStorage, m_typeId);
} else {
@@ -3277,6 +4124,12 @@ bool NodeMetaInfo::isQtQuick3DParticles3DAffector3D() const
bool NodeMetaInfo::isQtQuick3DView3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.View3D"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, View3D>(m_projectStorage, m_typeId);
} else {
@@ -3287,6 +4140,14 @@ bool NodeMetaInfo::isQtQuick3DView3D() const
bool NodeMetaInfo::isQtQuick3DPrincipledMaterial() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.PrincipledMaterial"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, PrincipledMaterial>(m_projectStorage, m_typeId);
} else {
@@ -3297,6 +4158,14 @@ bool NodeMetaInfo::isQtQuick3DPrincipledMaterial() const
bool NodeMetaInfo::isQtQuick3DSpecularGlossyMaterial() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.SpecularGlossyMaterial"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, SpecularGlossyMaterial>(m_projectStorage, m_typeId);
} else {
@@ -3307,6 +4176,14 @@ bool NodeMetaInfo::isQtQuick3DSpecularGlossyMaterial() const
bool NodeMetaInfo::isQtQuick3DParticles3DSpriteParticle3D() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Particles3D.SpriteParticle3D"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D_Particles3D, SpriteParticle3D>(m_projectStorage,
m_typeId);
@@ -3318,6 +4195,14 @@ bool NodeMetaInfo::isQtQuick3DParticles3DSpriteParticle3D() const
bool NodeMetaInfo::isQtQuick3DTextureInput() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.TextureInput"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, TextureInput>(m_projectStorage, m_typeId);
} else {
@@ -3328,6 +4213,14 @@ bool NodeMetaInfo::isQtQuick3DTextureInput() const
bool NodeMetaInfo::isQtQuick3DCubeMapTexture() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.CubeMapTexture"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, CubeMapTexture>(m_projectStorage, m_typeId);
} else {
@@ -3340,6 +4233,14 @@ bool NodeMetaInfo::isQtQuick3DCubeMapTexture() const
bool NodeMetaInfo::isQtQuick3DSceneEnvironment() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.SceneEnvironment"_t,
+ category(),
+ keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, SceneEnvironment>(m_projectStorage, m_typeId);
} else {
@@ -3350,6 +4251,12 @@ bool NodeMetaInfo::isQtQuick3DSceneEnvironment() const
bool NodeMetaInfo::isQtQuick3DEffect() const
{
if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is QtQuick3D.Effect"_t, category(), keyValue("type id", m_typeId)};
+
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Effect>(m_projectStorage, m_typeId);
} else {
@@ -3359,8 +4266,15 @@ bool NodeMetaInfo::isQtQuick3DEffect() const
bool NodeMetaInfo::isEnumeration() const
{
- if constexpr (useProjectStorage())
- return isValid() && typeData().traits.isEnum;
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return false;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is enumeration"_t, category(), keyValue("type id", m_typeId)};
+
+ return typeData().traits.isEnum;
+ }
return false;
}
@@ -3385,8 +4299,15 @@ PropertyMetaInfo::~PropertyMetaInfo() = default;
NodeMetaInfo PropertyMetaInfo::propertyType() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return {propertyData().propertyTypeId, m_projectStorage};
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property type"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return {propertyData().propertyTypeId, m_projectStorage};
} else {
if (isValid())
return NodeMetaInfo{nodeMetaInfoPrivateData()->model(),
@@ -3401,8 +4322,15 @@ NodeMetaInfo PropertyMetaInfo::propertyType() const
NodeMetaInfo PropertyMetaInfo::type() const
{
if constexpr (useProjectStorage()) {
- if (isValid())
- return NodeMetaInfo(propertyData().typeId, m_projectStorage);
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property owner type "_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return NodeMetaInfo(propertyData().typeId, m_projectStorage);
}
return {};
@@ -3410,59 +4338,121 @@ NodeMetaInfo PropertyMetaInfo::type() const
PropertyName PropertyMetaInfo::name() const
{
- if (isValid()) {
- if constexpr (useProjectStorage())
- return PropertyName(Utils::SmallStringView(propertyData().name));
- else
- return propertyName();
- }
+ if (!isValid())
+ return {};
- return {};
+ if constexpr (useProjectStorage()) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property name"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return PropertyName(Utils::SmallStringView(propertyData().name));
+ } else {
+ return propertyName();
+ }
}
bool PropertyMetaInfo::isWritable() const
{
- if constexpr (useProjectStorage())
- return isValid() && !(propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly);
- else
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is property writable"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return !(propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly);
+ } else {
return isValid() && nodeMetaInfoPrivateData()->isPropertyWritable(propertyName());
+ }
}
bool PropertyMetaInfo::isReadOnly() const
{
- return !isWritable();
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is property read only"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly;
+ } else {
+ return !isWritable();
+ }
}
bool PropertyMetaInfo::isListProperty() const
{
- if constexpr (useProjectStorage())
- return isValid() && propertyData().traits & Storage::PropertyDeclarationTraits::IsList;
- else
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is list property"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
+ return propertyData().traits & Storage::PropertyDeclarationTraits::IsList;
+ } else {
return isValid() && nodeMetaInfoPrivateData()->isPropertyList(propertyName());
+ }
}
bool PropertyMetaInfo::isEnumType() const
{
- if constexpr (useProjectStorage())
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is enum type"_t,
+ category(),
+ keyValue("property has enumeration type", m_id)};
+
return propertyType().isEnumeration();
- else
+ } else {
return isValid() && nodeMetaInfoPrivateData()->isPropertyEnum(propertyName());
+ }
}
bool PropertyMetaInfo::isPrivate() const
{
- if constexpr (useProjectStorage())
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is private property"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
return isValid() && propertyData().name.startsWith("__");
- else
+ } else {
return isValid() && propertyName().startsWith("__");
+ }
}
bool PropertyMetaInfo::isPointer() const
{
- if constexpr (useProjectStorage())
+ if constexpr (useProjectStorage()) {
+ if (!isValid())
+ return {};
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is pointer property"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
return isValid() && (propertyData().traits & Storage::PropertyDeclarationTraits::IsPointer);
- else
+ } else {
return isValid() && nodeMetaInfoPrivateData()->isPropertyPointer(propertyName());
+ }
}
namespace {
@@ -3479,6 +4469,11 @@ QVariant PropertyMetaInfo::castedValue(const QVariant &value) const
return {};
if constexpr (!useProjectStorage()) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"cast value"_t,
+ category(),
+ keyValue("property declaration id", m_id)};
+
const QVariant variant = value;
QVariant copyVariant = variant;
const TypeName &typeName = propertyTypeName();
@@ -3496,7 +4491,7 @@ QVariant PropertyMetaInfo::castedValue(const QVariant &value) const
return variant;
} else if (typeId == QVariant::UserType && typeName == "var") {
return variant;
- } else if (variant.typeId() == QVariant::List) {
+ } else if (variant.typeId() == QMetaType::QVariantList) {
// TODO: check the contents of the list
return variant;
} else if (typeName == "var" || typeName == "variant") {
diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
index 403731d1c4..29a093f199 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
@@ -44,6 +44,7 @@ SubComponentManager::SubComponentManager(Model *model,
ExternalDependenciesInterface &externalDependencies)
: m_model(model)
, m_externalDependencies{externalDependencies}
+ , m_componentUtils{externalDependencies}
{
connect(&m_watcher, &QFileSystemWatcher::directoryChanged,
this, [this](const QString &path) { parseDirectory(path); });
@@ -192,7 +193,7 @@ void SubComponentManager::parseDirectory(const QString &canonicalDirPath, bool a
if (!model() || !model()->rewriterView())
return;
- if (canonicalDirPath.endsWith(QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER))) {
+ if (m_componentUtils.isImport3dPath(canonicalDirPath)) {
parseQuick3DAssetsDir(canonicalDirPath);
return;
}
@@ -344,11 +345,8 @@ void SubComponentManager::unregisterQmlFile(const QFileInfo &fileInfo, const QSt
void SubComponentManager::registerQmlFile(const QFileInfo &fileInfo, const QString &qualifier,
bool addToLibrary)
{
- if (!addToLibrary || !model()
- || fileInfo.path().contains(QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER))
- || fileInfo.path().contains(QLatin1String(Constants::DEFAULT_EFFECTS_IMPORT_FOLDER))) {
+ if (!addToLibrary || !model() || m_componentUtils.isGeneratedPath(fileInfo.path()))
return;
- }
QString componentName = fileInfo.baseName();
const QString baseComponentName = componentName;
@@ -395,7 +393,7 @@ void SubComponentManager::parseQuick3DAssetsDir(const QString &quick3DAssetsPath
QDir quick3DAssetsDir(quick3DAssetsPath);
QStringList assets = quick3DAssetsDir.entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
for (QString &asset : assets)
- asset.prepend(QString(Constants::QUICK_3D_ASSETS_FOLDER).mid(1) + '.');
+ asset.prepend(m_componentUtils.import3dTypePrefix() + '.');
// Create item library entries for Quick3D assets that are imported by document
for (auto &import : std::as_const(m_imports)) {
@@ -460,7 +458,8 @@ QStringList SubComponentManager::quick3DAssetPaths() const
const auto impPaths = importPaths();
QStringList retPaths;
for (const auto &impPath : impPaths) {
- const QString assetPath = impPath + QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
+ QString path3d = m_componentUtils.import3dTypePath();
+ const QString assetPath = impPath + '/' + path3d;
if (QFileInfo::exists(assetPath))
retPaths << assetPath;
}
@@ -520,7 +519,7 @@ void SubComponentManager::update(const QUrl &filePath, const Imports &imports)
// Remove old watched asset paths
const QStringList watchPaths = m_watcher.directories();
- const QString &quick3DAssetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER);
+ const QString &quick3DAssetFolder = m_componentUtils.import3dTypePath();
for (const auto &watchPath : watchPaths) {
if (watchPath.endsWith(quick3DAssetFolder))
m_watcher.removePath(watchPath);
@@ -580,7 +579,7 @@ void SubComponentManager::addAndParseImport(const Import &import)
} else {
QString url = import.url();
- if (url.startsWith(QString(Constants::QUICK_3D_ASSETS_FOLDER).mid(1))) {
+ if (url.startsWith(m_componentUtils.import3dTypePrefix())) {
parseQuick3DAssetsItem(import.url());
return;
}
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index 061ab8ae2b..125c7195a8 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -567,8 +567,10 @@ void AbstractView::disableWidget()
void AbstractView::enableWidget()
{
- if (hasWidget() && widgetInfo().widgetFlags == DesignerWidgetFlags::DisableOnError)
- widgetInfo().widget->setEnabled(true);
+ if (hasWidget()) {
+ if (auto info = widgetInfo(); info.widgetFlags == DesignerWidgetFlags::DisableOnError)
+ info.widget->setEnabled(true);
+ }
}
QString AbstractView::contextHelpId() const
diff --git a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
index 141548047e..23c17dc61a 100644
--- a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
@@ -37,10 +37,11 @@ BindingProperty::BindingProperty(const PropertyName &propertyName, const Interna
void BindingProperty::setExpression(const QString &expression)
{
- Internal::WriteLocker locker(model());
if (!isValid())
return;
+ Internal::WriteLocker locker(model());
+
if (isDynamic())
qWarning() << "Calling BindingProperty::setExpression on dynamic property.";
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index a4cd31b2a8..d4eea26378 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -9,7 +9,6 @@
#include "../projectstorage/sourcepath.h"
#include "../projectstorage/sourcepathcache.h"
#include "abstractview.h"
-#include "auxiliarydataproperties.h"
#include "internalbindingproperty.h"
#include "internalnodeabstractproperty.h"
#include "internalnodelistproperty.h"
@@ -33,6 +32,8 @@
#include "signalhandlerproperty.h"
#include "variantproperty.h"
+#include <uniquename.h>
+
#include <projectstorage/projectstorage.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -46,8 +47,6 @@
#include <QRegularExpression>
#include <qcompilerdetection.h>
-#include <string>
-
/*!
\defgroup CoreModel
*/
@@ -170,10 +169,10 @@ Storage::Imports createStorageImports(const Imports &imports,
SourceId fileId)
{
return Utils::transform<Storage::Imports>(imports, [&](const Import &import) {
- return Storage::Import{projectStorage.moduleId(Utils::SmallString{import.url()}),
- import.majorVersion(),
- import.minorVersion(),
- fileId};
+ using Storage::ModuleKind;
+ auto moduleKind = import.isLibraryImport() ? ModuleKind::QmlLibrary : ModuleKind::PathLibrary;
+ auto moduleId = projectStorage.moduleId(Utils::SmallString{import.url()}, moduleKind);
+ return Storage::Import{moduleId, import.majorVersion(), import.minorVersion(), fileId};
});
}
@@ -244,7 +243,7 @@ void ModelPrivate::notifyUsedImportsChanged(const Imports &usedImports)
}
}
-QUrl ModelPrivate::fileUrl() const
+const QUrl &ModelPrivate::fileUrl() const
{
return m_fileUrl;
}
@@ -390,7 +389,11 @@ ImportedTypeNameId ModelPrivate::importedTypeNameId(Utils::SmallStringView typeN
return import.alias() == aliasName;
});
if (found != m_imports.end()) {
- ModuleId moduleId = projectStorage->moduleId(Utils::PathString{found->url()});
+ using Storage::ModuleKind;
+ auto moduleKind = found->isLibraryImport() ? ModuleKind::QmlLibrary
+ : ModuleKind::PathLibrary;
+ ModuleId moduleId = projectStorage->moduleId(Utils::PathString{found->url()},
+ moduleKind);
ImportId importId = projectStorage->importId(
Storage::Import{moduleId, found->majorVersion(), found->minorVersion(), m_sourceId});
return projectStorage->importedTypeNameId(importId, shortTypeName);
@@ -1758,14 +1761,22 @@ Storage::Info::ExportedTypeName Model::exportedTypeNameForMetaInfo(const NodeMet
return {};
}
-const Imports &Model::possibleImports() const
+Imports Model::possibleImports() const
{
+#ifdef QDS_USE_PROJECTSTORAGE
+ return {};
+#else
return d->m_possibleImportList;
+#endif
}
-const Imports &Model::usedImports() const
+Imports Model::usedImports() const
{
+#ifdef QDS_USE_PROJECTSTORAGE
+ return {};
+#else
return d->m_usedImportList;
+#endif
}
void Model::changeImports(Imports importsToBeAdded, Imports importsToBeRemoved)
@@ -1773,6 +1784,7 @@ void Model::changeImports(Imports importsToBeAdded, Imports importsToBeRemoved)
d->changeImports(std::move(importsToBeAdded), std::move(importsToBeRemoved));
}
+#ifndef QDS_USE_PROJECTSTORAGE
void Model::setPossibleImports(Imports possibleImports)
{
auto tracer = d->traceToken.begin("possible imports"_t);
@@ -1784,7 +1796,9 @@ void Model::setPossibleImports(Imports possibleImports)
d->notifyPossibleImportsChanged(d->m_possibleImportList);
}
}
+#endif
+#ifndef QDS_USE_PROJECTSTORAGE
void Model::setUsedImports(Imports usedImports)
{
auto tracer = d->traceToken.begin("used imports"_t);
@@ -1796,6 +1810,7 @@ void Model::setUsedImports(Imports usedImports)
d->notifyUsedImportsChanged(d->m_usedImportList);
}
}
+#endif
static bool compareVersions(const Import &import1, const Import &import2, bool allowHigherVersion)
{
@@ -1848,89 +1863,18 @@ bool Model::hasImport(const QString &importUrl) const
});
}
-static QString firstCharToLower(const QString &string)
-{
- QString resultString = string;
-
- if (!resultString.isEmpty())
- resultString[0] = resultString.at(0).toLower();
-
- return resultString;
-}
-
-QString Model::generateNewId(const QString &prefixName,
- const QString &fallbackPrefix,
- std::optional<std::function<bool(const QString &)>> isDuplicate) const
+QString Model::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const
{
- // First try just the prefixName without number as postfix, then continue with 2 and further
- // as postfix until id does not already exist.
- // Properties of the root node are not allowed for ids, because they are available in the
- // complete context without qualification.
-
- int counter = 0;
-
- QString newBaseId = QStringView(u"%1").arg(firstCharToLower(prefixName));
- newBaseId.remove(QRegularExpression(QStringLiteral("[^a-zA-Z0-9_]")));
-
- if (!newBaseId.isEmpty()) {
- QChar firstChar = newBaseId.at(0);
- if (firstChar.isDigit())
- newBaseId.prepend('_');
- } else {
- newBaseId = fallbackPrefix;
- }
-
- QString newId = newBaseId;
+ QString newId = prefixName;
- if (!isDuplicate.has_value())
- isDuplicate = std::bind(&Model::hasId, this, std::placeholders::_1);
+ if (newId.isEmpty())
+ newId = fallbackPrefix;
- while (!ModelNode::isValidId(newId) || isDuplicate.value()(newId)
- || d->rootNode()->property(newId.toUtf8())) {
- ++counter;
- newId = QStringView(u"%1%2").arg(firstCharToLower(newBaseId)).arg(counter);
- }
-
- return newId;
-}
-
-// Generate a unique camelCase id from a name
-// note: this methods does the same as generateNewId(). The 2 methods should be merged into one
-QString Model::generateIdFromName(const QString &name, const QString &fallbackId) const
-{
- QString newId;
- if (name.isEmpty()) {
- newId = fallbackId;
- } else {
- // convert to camel case
- QStringList nameWords = name.split(" ");
- nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1);
- for (int i = 1; i < nameWords.size(); ++i)
- nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1);
- newId = nameWords.join("");
-
- // if id starts with a number prepend an underscore
- if (newId.at(0).isDigit())
- newId.prepend('_');
- }
-
- // If the new id is not valid (e.g. qml keyword match), try fixing it by prepending underscore
- if (!ModelNode::isValidId(newId))
- newId.prepend("_");
-
- QRegularExpression rgx("\\d+$"); // matches a number at the end of a string
- while (hasId(newId)) { // id exists
- QRegularExpressionMatch match = rgx.match(newId);
- if (match.hasMatch()) { // ends with a number, increment it
- QString numStr = match.captured();
- int num = numStr.toInt() + 1;
- newId = newId.mid(0, match.capturedStart()) + QString::number(num);
- } else {
- newId.append('1');
- }
- }
-
- return newId;
+ return UniqueName::generateId(prefixName, [&] (const QString &id) {
+ // Properties of the root node are not allowed for ids, because they are available in the
+ // complete context without qualification.
+ return hasId(id) || d->rootNode()->property(id.toUtf8());
+ });
}
void Model::startDrag(QMimeData *mimeData, const QPixmap &icon)
@@ -2021,14 +1965,6 @@ bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowH
return false;
}
-QString Model::pathForImport(const Import &import)
-{
- if (!rewriterView())
- return QString();
-
- return rewriterView()->pathForImport(import);
-}
-
QStringList Model::importPaths() const
{
if (rewriterView())
@@ -2110,7 +2046,7 @@ void Model::clearMetaInfoCache()
\brief Returns the URL against which relative URLs within the model should be resolved.
\return The base URL.
*/
-QUrl Model::fileUrl() const
+const QUrl &Model::fileUrl() const
{
return d->fileUrl();
}
@@ -2205,6 +2141,16 @@ NodeMetaInfo Model::qtQmlModelsListElementMetaInfo() const
}
}
+NodeMetaInfo Model::qtQmlXmlListModelXmlListModelRoleMetaInfo() const
+{
+ if constexpr (useProjectStorage()) {
+ using namespace Storage::Info;
+ return createNodeMetaInfo<QtQml_XmlListModel, XmlListModelRole>();
+ } else {
+ return metaInfo("QtQml.XmlListModel.XmlListModelRole");
+ }
+}
+
NodeMetaInfo Model::qmlQtObjectMetaInfo() const
{
if constexpr (useProjectStorage()) {
@@ -2541,8 +2487,7 @@ QList<ItemLibraryEntry> Model::itemLibraryEntries() const
{
#ifdef QDS_USE_PROJECTSTORAGE
using namespace Storage::Info;
- return toItemLibraryEntries(d->projectStorage->itemLibraryEntries(d->m_sourceId),
- *d->projectStorage);
+ return toItemLibraryEntries(d->projectStorage->itemLibraryEntries(d->m_sourceId));
#else
return d->metaInfo().itemLibraryInfo()->entries();
#endif
@@ -2608,11 +2553,10 @@ MetaInfo Model::metaInfo()
}
#endif
-Module Model::module(Utils::SmallStringView moduleName)
+Module Model::module(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind)
{
- if constexpr (useProjectStorage()) {
- return Module(d->projectStorage->moduleId(moduleName), d->projectStorage);
- }
+ if constexpr (useProjectStorage())
+ return Module(d->projectStorage->moduleId(moduleName, moduleKind), d->projectStorage);
return {};
}
diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h
index a3e972f329..cb082fd1d7 100644
--- a/src/plugins/qmldesigner/designercore/model/model_p.h
+++ b/src/plugins/qmldesigner/designercore/model/model_p.h
@@ -122,7 +122,7 @@ public:
ModelPrivate(const ModelPrivate &) = delete;
ModelPrivate &operator=(const ModelPrivate &) = delete;
- QUrl fileUrl() const;
+ const QUrl &fileUrl() const;
void setFileUrl(const QUrl &url);
InternalNodePointer createNode(const TypeName &typeName,
diff --git a/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp b/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp
index a61f1001f9..27ac2e67ab 100644
--- a/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelresourcemanagement.cpp
@@ -515,8 +515,7 @@ struct BindingFilter
struct TargetFilter
{
TargetFilter(NodeDependencies &dependencies, Model *model)
- : flowViewFlowActionAreaMetaInfo{model->flowViewFlowActionAreaMetaInfo()}
- , flowViewFlowTransitionMetaInfo{model->flowViewFlowTransitionMetaInfo()}
+ : flowViewFlowTransitionMetaInfo{model->flowViewFlowTransitionMetaInfo()}
, qtQuickPropertyChangesMetaInfo{model->qtQuickPropertyChangesMetaInfo()}
, qtQuickTimelineKeyframeGroupMetaInfo{model->qtQuickTimelineKeyframeGroupMetaInfo()}
, qtQuickPropertyAnimationMetaInfo{model->qtQuickPropertyAnimationMetaInfo()}
diff --git a/src/plugins/qmldesigner/designercore/model/modelutils.cpp b/src/plugins/qmldesigner/designercore/model/modelutils.cpp
index cb3f482289..6c3e1ea50f 100644
--- a/src/plugins/qmldesigner/designercore/model/modelutils.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelutils.cpp
@@ -9,6 +9,8 @@
#include <projectstorage/projectstorage.h>
#include <projectstorage/sourcepathcache.h>
+#include <coreplugin/messagebox.h>
+
#include <utils/expected.h>
#include <utils/ranges.h>
@@ -107,19 +109,19 @@ PropertyMetaInfo metainfo(const ModelNode &node, const PropertyName &propertyNam
return node.metaInfo().property(propertyName);
}
-QString componentFilePath(const PathCacheType &pathCache, const NodeMetaInfo &metaInfo)
+QString componentFilePath([[maybe_unused]] const PathCacheType &pathCache, const NodeMetaInfo &metaInfo)
{
- if constexpr (useProjectStorage()) {
- auto typeSourceId = metaInfo.sourceId();
+#ifdef QDS_USE_PROJECTSTORAGE
+ auto typeSourceId = metaInfo.sourceId();
- if (typeSourceId && metaInfo.isFileComponent()) {
- return pathCache.sourcePath(typeSourceId).toQString();
- }
- } else {
- return metaInfo.componentFileName();
+ if (typeSourceId && metaInfo.isFileComponent()) {
+ return pathCache.sourcePath(typeSourceId).toQString();
}
return {};
+#else
+ return metaInfo.componentFileName();
+#endif
}
QString componentFilePath(const ModelNode &node)
diff --git a/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp b/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp
index cd7cebbb73..8eaa7947de 100644
--- a/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp
+++ b/src/plugins/qmldesigner/designercore/model/propertycontainer.cpp
@@ -41,7 +41,7 @@ PropertyName PropertyContainer::name() const
QVariant PropertyContainer::value() const
{
- if (m_value.typeId() == QVariant::String)
+ if (m_value.typeId() == QMetaType::QString)
m_value = PropertyParser::read(m_type, m_value.toString());
return m_value;
}
diff --git a/src/plugins/qmldesigner/designercore/model/propertyparser.cpp b/src/plugins/qmldesigner/designercore/model/propertyparser.cpp
index 788530c291..264c944fea 100644
--- a/src/plugins/qmldesigner/designercore/model/propertyparser.cpp
+++ b/src/plugins/qmldesigner/designercore/model/propertyparser.cpp
@@ -201,7 +201,7 @@ QVariant read(const QString &typeStr, const QString &str, const MetaInfo &)
QVariant read(const QString &typeStr, const QString &str)
{
- int type = QMetaType::type(typeStr.toUtf8().constData());
+ int type = QMetaType::fromName(typeStr.toUtf8().constData()).id();
if (type == 0) {
if (typeStr != "binding"_L1 && typeStr != "enum"_L1) {
qWarning() << "Type " << typeStr
@@ -270,15 +270,14 @@ QVariant read(int variantType, const QString &str)
value = QVariant::fromValue<Enumeration>(enumerationFromString(str, &conversionOk));
} else {
value = QVariant(str);
- value.convert(static_cast<QVariant::Type>(variantType));
+ value.convert(QMetaType(variantType));
}
break;
}
}
if (!conversionOk) {
- qWarning() << "Could not convert" << str
- << "to" << QMetaType::typeName(variantType);
+ qWarning() << "Could not convert" << str << "to" << QMetaType(variantType).name();
value = QVariant(str);
}
diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
index 826856428b..6e3b739096 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
@@ -9,8 +9,9 @@
#include "bindingproperty.h"
#include "qmlanchors.h"
-#include <model.h>
#include <abstractview.h>
+#include <generatedcomponentutils.h>
+#include <model.h>
#include <coreplugin/icore.h>
@@ -196,7 +197,9 @@ QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
auto createEffectNode = [=, &newQmlItemNode, &parentProperty]() {
const QString effectName = QFileInfo(effectPath).baseName();
- Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
+ Import import = Import::createLibraryImport(GeneratedComponentUtils(view->externalDependencies())
+ .composedEffectsTypePrefix()
+ + '.' + effectName, "1.0");
try {
if (!view->model()->hasImport(import, true, true))
view->model()->changeImports({import}, {});
@@ -748,7 +751,6 @@ void QmlFlowActionAreaNode::assignTargetFlowItem(const QmlFlowTargetNode &flowIt
ModelNode transition = flowView.addTransition(flowParent.modelNode(),
flowItem.modelNode());
-
modelNode().bindingProperty("target").setExpression(transition.validId());
}
diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
index c84f234257..726d3d52af 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
@@ -24,6 +24,8 @@
#include <QDir>
#include <QRandomGenerator>
+#include <memory>
+
namespace QmlDesigner {
static char imagePlaceHolder[] = "qrc:/qtquickplugin/images/template_image.png";
@@ -182,8 +184,8 @@ void QmlVisualNode::scatter(const ModelNode &targetNode, const std::optional<int
if (!scatter)
return;
- if (offset.has_value()) { // offset
- double offsetValue = offset.value();
+ if (offset) { // offset
+ double offsetValue = *offset;
this->translate(QVector3D(offsetValue, offsetValue, offsetValue));
} else { // scatter in range
const double scatterRange = 20.;
@@ -250,8 +252,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
NodeAbstractProperty parentProperty = parentQmlItemNode.defaultNodeAbstractProperty();
-
- NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry);
+ NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry, view->model());
const PropertyName forceNonDefaultProperty = hints.forceNonDefaultProperty().toUtf8();
QmlObjectNode newNode = QmlItemNode::createQmlObjectNode(view,
@@ -289,17 +290,17 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view,
textEdit.setPlainText(source);
NotIndentingTextEditModifier modifier(&textEdit);
- QScopedPointer<RewriterView> rewriterView(
- new RewriterView(view->externalDependencies(), RewriterView::Amend));
+ std::unique_ptr<RewriterView> rewriterView = std::make_unique<RewriterView>(
+ view->externalDependencies(), RewriterView::Amend);
rewriterView->setCheckSemanticErrors(false);
rewriterView->setTextModifier(&modifier);
rewriterView->setAllowComponentRoot(true);
rewriterView->setPossibleImportsEnabled(false);
- inputModel->setRewriterView(rewriterView.data());
+ inputModel->setRewriterView(rewriterView.get());
if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) {
ModelNode rootModelNode = rewriterView->rootModelNode();
- inputModel->detachView(rewriterView.data());
+ inputModel->detachView(rewriterView.get());
QmlVisualNode(rootModelNode).setPosition(position);
ModelMerger merger(view);
return merger.insertModel(rootModelNode);
@@ -329,7 +330,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
{
QmlObjectNode newQmlObjectNode;
- NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry);
+ NodeHints hints = NodeHints::fromItemLibraryEntry(itemLibraryEntry, view->model());
auto createNodeFunc = [=, &newQmlObjectNode, &parentProperty]() {
#ifndef QDS_USE_PROJECTSTORAGE
@@ -361,13 +362,17 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
propertyPairList.append(position.propertyPairList());
ModelNode::NodeSourceType nodeSourceType = ModelNode::NodeWithoutSource;
- if (itemLibraryEntry.typeName() == "QtQml.Component")
- nodeSourceType = ModelNode::NodeWithComponentSource;
#ifdef QDS_USE_PROJECTSTORAGE
+ NodeMetaInfo metaInfo{itemLibraryEntry.typeId(), view->model()->projectStorage()};
+ if (metaInfo.isQmlComponent())
+ nodeSourceType = ModelNode::NodeWithComponentSource;
newQmlObjectNode = QmlObjectNode(view->createModelNode(
itemLibraryEntry.typeName(), propertyPairList, {}, {}, nodeSourceType));
#else
+ if (itemLibraryEntry.typeName() == "QtQml.Component")
+ nodeSourceType = ModelNode::NodeWithComponentSource;
+
newQmlObjectNode = QmlObjectNode(view->createModelNode(itemLibraryEntry.typeName(),
majorVersion,
minorVersion,
diff --git a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
index c4d96bb250..edee6840ef 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriteactioncompressor.cpp
@@ -58,7 +58,6 @@ void RewriteActionCompressor::compressImports(QList<RewriteAction *> &actions) c
actionsToRemove.append(action);
actionsToRemove.append(addImportAction);
addedImports.remove(import);
- delete addImportAction;
} else {
removedImports.insert(import, action);
}
@@ -67,13 +66,11 @@ void RewriteActionCompressor::compressImports(QList<RewriteAction *> &actions) c
if (RewriteAction *duplicateAction = addedImports.value(import, 0)) {
actionsToRemove.append(duplicateAction);
addedImports.remove(import);
- delete duplicateAction;
addedImports.insert(import, action);
} else if (RewriteAction *removeAction = removedImports.value(import, 0)) {
actionsToRemove.append(action);
actionsToRemove.append(removeAction);
removedImports.remove(import);
- delete removeAction;
} else {
addedImports.insert(import, action);
}
diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
index 4ae2261e60..3c481573d2 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
@@ -16,12 +16,14 @@
#include <filemanager/objectlengthcalculator.h>
#include <modelnode.h>
#include <modelnodepositionstorage.h>
+#include <nodemetainfo.h>
#include <nodeproperty.h>
+#include <projectstorage/projectstorage.h>
+#include <qmlobjectnode.h>
+#include <qmltimelinekeyframegroup.h>
#include <rewritingexception.h>
#include <signalhandlerproperty.h>
#include <variantproperty.h>
-#include <qmlobjectnode.h>
-#include <qmltimelinekeyframegroup.h>
#include <qmljs/parser/qmljsengine_p.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -56,9 +58,9 @@ RewriterView::RewriterView(ExternalDependenciesInterface &externalDependencies,
DifferenceHandling differenceHandling)
: AbstractView{externalDependencies}
, m_differenceHandling(differenceHandling)
- , m_positionStorage(new ModelNodePositionStorage)
- , m_modelToTextMerger(new Internal::ModelToTextMerger(this))
- , m_textToModelMerger(new Internal::TextToModelMerger(this))
+ , m_positionStorage(std::make_unique<ModelNodePositionStorage>())
+ , m_modelToTextMerger(std::make_unique<Internal::ModelToTextMerger>(this))
+ , m_textToModelMerger(std::make_unique<Internal::TextToModelMerger>(this))
{
m_amendTimer.setSingleShot(true);
@@ -78,12 +80,12 @@ RewriterView::~RewriterView() = default;
Internal::ModelToTextMerger *RewriterView::modelToTextMerger() const
{
- return m_modelToTextMerger.data();
+ return m_modelToTextMerger.get();
}
Internal::TextToModelMerger *RewriterView::textToModelMerger() const
{
- return m_textToModelMerger.data();
+ return m_textToModelMerger.get();
}
void RewriterView::modelAttached(Model *model)
@@ -92,7 +94,7 @@ void RewriterView::modelAttached(Model *model)
AbstractView::modelAttached(model);
- ModelAmender differenceHandler(m_textToModelMerger.data());
+ ModelAmender differenceHandler(m_textToModelMerger.get());
const QString qmlSource = m_textModifier->text();
if (m_textToModelMerger->load(qmlSource, differenceHandler))
m_lastCorrectQmlSource = qmlSource;
@@ -104,6 +106,7 @@ void RewriterView::modelAttached(Model *model)
m_modelAttachPending = true;
QTimer::singleShot(1000, this, [this, model](){
modelAttached(model);
+ restoreAuxiliaryData();
});
}
}
@@ -492,7 +495,7 @@ void RewriterView::amendQmlText()
const QString newQmlText = m_textModifier->text();
- ModelAmender differenceHandler(m_textToModelMerger.data());
+ ModelAmender differenceHandler(m_textToModelMerger.get());
if (m_textToModelMerger->load(newQmlText, differenceHandler))
m_lastCorrectQmlSource = newQmlText;
emitCustomNotification(EndRewriterAmend);
@@ -593,7 +596,7 @@ QString RewriterView::auxiliaryDataAsQML() const
hasAuxData = true;
QString strValue = value.toString();
- auto metaType = static_cast<QMetaType::Type>(value.type());
+ const int metaType = value.typeId();
if (metaType == QMetaType::QString
|| metaType == QMetaType::QColor) {
@@ -698,7 +701,7 @@ void RewriterView::forceAmend()
Internal::ModelNodePositionStorage *RewriterView::positionStorage() const
{
- return m_positionStorage.data();
+ return m_positionStorage.get();
}
QList<DocumentMessage> RewriterView::warnings() const
@@ -755,7 +758,7 @@ void RewriterView::resetToLastCorrectQml()
{
m_textModifier->textDocument()->undo();
m_textModifier->textDocument()->clearUndoRedoStacks(QTextDocument::RedoStack);
- ModelAmender differenceHandler(m_textToModelMerger.data());
+ ModelAmender differenceHandler(m_textToModelMerger.get());
Internal::WriteLocker::unlock(model());
m_textToModelMerger->load(m_textModifier->text(), differenceHandler);
Internal::WriteLocker::lock(model());
@@ -933,10 +936,12 @@ bool RewriterView::renameId(const QString& oldId, const QString& newId)
return false;
}
+#ifndef QDS_USE_PROJECTSTORAGE
const QmlJS::ScopeChain *RewriterView::scopeChain() const
{
return textToModelMerger()->scopeChain();
}
+#endif
const QmlJS::Document *RewriterView::document() const
{
@@ -989,38 +994,74 @@ QString RewriterView::convertTypeToImportAlias(const QString &type) const
return result;
}
-QString RewriterView::pathForImport(const Import &import)
+QStringList RewriterView::importDirectories() const
{
- if (scopeChain() && scopeChain()->context() && document()) {
- const QString importStr = import.isFileImport() ? import.file() : import.url();
- const QmlJS::Imports *imports = scopeChain()->context()->imports(document());
+ const QList<Utils::FilePath> list(m_textToModelMerger->vContext().paths.begin(),
+ m_textToModelMerger->vContext().paths.end());
- QmlJS::ImportInfo importInfo;
+ return Utils::transform(list, [](const Utils::FilePath &p) { return p.toString(); });
+}
- for (const QmlJS::Import &qmljsImport : imports->all()) {
- if (qmljsImport.info.name() == importStr)
- importInfo = qmljsImport.info;
- }
- const QString importPath = importInfo.path();
- return importPath;
+QSet<QPair<QString, QString> > RewriterView::qrcMapping() const
+{
+ return m_textToModelMerger->qrcMapping();
+}
+
+namespace {
+#ifdef QDS_USE_PROJECTSTORAGE
+
+ModuleIds generateModuleIds(const ModelNodes &nodes)
+{
+ ModuleIds moduleIds;
+ moduleIds.reserve(Utils::usize(nodes));
+ for (const auto &node : nodes) {
+ auto exportedNames = node.metaInfo().allExportedTypeNames();
+ if (exportedNames.size())
+ moduleIds.push_back(exportedNames.front().moduleId);
}
- return QString();
+ std::sort(moduleIds.begin(), moduleIds.end());
+ moduleIds.erase(std::unique(moduleIds.begin(), moduleIds.end()), moduleIds.end());
+
+ return moduleIds;
}
-QStringList RewriterView::importDirectories() const
+QStringList generateImports(ModuleIds moduleIds, const ProjectStorageType &projectStorage)
{
- const QList<Utils::FilePath> list(m_textToModelMerger->vContext().paths.begin(),
- m_textToModelMerger->vContext().paths.end());
+ QStringList imports;
+ imports.reserve(std::ssize(moduleIds));
- return Utils::transform(list, [](const Utils::FilePath &p) { return p.toString(); });
+ for (auto moduleId : moduleIds) {
+ using Storage::ModuleKind;
+ auto module = projectStorage.module(moduleId);
+ switch (module.kind) {
+ case ModuleKind::QmlLibrary:
+ imports.push_back("import " + module.name.toQString());
+ break;
+ case ModuleKind::PathLibrary:
+ imports.push_back("import \"" + module.name.toQString() + "\"");
+ break;
+ case ModuleKind::CppLibrary:
+ break;
+ }
+ }
+
+ return imports;
}
-QSet<QPair<QString, QString> > RewriterView::qrcMapping() const
+QStringList generateImports(const ModelNodes &nodes)
{
- return m_textToModelMerger->qrcMapping();
+ if (nodes.empty())
+ return {};
+
+ auto moduleIds = generateModuleIds(nodes);
+
+ return generateImports(moduleIds, *nodes.front().model()->projectStorage());
}
+#endif
+} // namespace
+
void RewriterView::moveToComponent(const ModelNode &modelNode)
{
if (!modelNode.isValid())
@@ -1029,20 +1070,26 @@ void RewriterView::moveToComponent(const ModelNode &modelNode)
int offset = nodeOffset(modelNode);
const QList<ModelNode> nodes = modelNode.allSubModelNodesAndThisNode();
- QSet<QString> directPaths;
+#ifdef QDS_USE_PROJECTSTORAGE
+ auto directPaths = generateImports(nodes);
+#else
+ QSet<QString> directPathsSet;
// Always add QtQuick import
QString quickImport = model()->qtQuickItemMetaInfo().requiredImportString();
if (!quickImport.isEmpty())
- directPaths.insert(quickImport);
+ directPathsSet.insert(quickImport);
for (const ModelNode &partialNode : nodes) {
QString importStr = partialNode.metaInfo().requiredImportString();
if (importStr.size())
- directPaths << importStr;
+ directPathsSet << importStr;
}
- QString importData = Utils::sorted(directPaths.values()).join(QChar::LineFeed);
+ auto directPaths = directPathsSet.values();
+#endif
+
+ QString importData = Utils::sorted(directPaths).join(QChar::LineFeed);
if (importData.size())
importData.append(QString(2, QChar::LineFeed));
@@ -1108,7 +1155,7 @@ void RewriterView::qmlTextChanged()
switch (m_differenceHandling) {
case Validate: {
- ModelValidator differenceHandler(m_textToModelMerger.data());
+ ModelValidator differenceHandler(m_textToModelMerger.get());
if (m_textToModelMerger->load(newQmlText, differenceHandler))
m_lastCorrectQmlSource = newQmlText;
break;
diff --git a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
index 16877b61db..4f744d54e6 100644
--- a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
@@ -23,6 +23,8 @@
#include <QQueue>
#include <QRegularExpression>
+#include <memory>
+
namespace {
QPoint pointForModelNode(const QmlDesigner::ModelNode &node)
@@ -641,10 +643,10 @@ void StylesheetMerger::styleMerge(const QString &qmlTemplateString,
textEditTemplate.setPlainText(imports + qmlTemplateString);
NotIndentingTextEditModifier textModifierTemplate(&textEditTemplate);
- QScopedPointer<RewriterView> templateRewriterView(
- new RewriterView(externalDependencies, RewriterView::Amend));
+ std::unique_ptr<RewriterView> templateRewriterView = std::make_unique<RewriterView>(
+ externalDependencies, RewriterView::Amend);
templateRewriterView->setTextModifier(&textModifierTemplate);
- templateModel->attachView(templateRewriterView.data());
+ templateModel->attachView(templateRewriterView.get());
templateRewriterView->setCheckSemanticErrors(false);
templateRewriterView->setPossibleImportsEnabled(false);
@@ -665,12 +667,12 @@ void StylesheetMerger::styleMerge(const QString &qmlTemplateString,
textEditStyle.setPlainText(parentRewriterView->textModifierContent());
NotIndentingTextEditModifier textModifierStyle(&textEditStyle);
- QScopedPointer<RewriterView> styleRewriterView(
- new RewriterView(externalDependencies, RewriterView::Amend));
+ std::unique_ptr<RewriterView> styleRewriterView = std::make_unique<RewriterView>(
+ externalDependencies, RewriterView::Amend);
styleRewriterView->setTextModifier(&textModifierStyle);
- styleModel->attachView(styleRewriterView.data());
+ styleModel->attachView(styleRewriterView.get());
- StylesheetMerger merger(templateRewriterView.data(), styleRewriterView.data());
+ StylesheetMerger merger(templateRewriterView.get(), styleRewriterView.get());
try {
merger.merge();
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index f7be6cf5e4..ded7fbc5ef 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -57,7 +57,7 @@ using namespace QmlJS;
using namespace Qt::StringLiterals;
static Q_LOGGING_CATEGORY(rewriterBenchmark, "qtc.rewriter.load", QtWarningMsg)
-static Q_LOGGING_CATEGORY(texttomodelMergerDebug, "qtc.texttomodelmerger.debug", QtDebugMsg)
+static Q_LOGGING_CATEGORY(texttomodelMergerLog, "qtc.texttomodelmerger", QtWarningMsg)
namespace {
@@ -67,17 +67,6 @@ bool isSupportedAttachedProperties(const QString &propertyName)
|| propertyName.startsWith(QLatin1String("InsightCategory."));
}
-bool isSupportedVersion(QmlDesigner::Version version)
-{
- if (version.major == 2)
- return version.minor <= 15;
-
- if (version.major == 6)
- return version.minor <= 6;
-
- return false;
-}
-
bool isGlobalQtEnums(QStringView value)
{
static constexpr auto list = Utils::to_array<std::u16string_view>(
@@ -95,6 +84,9 @@ bool isGlobalQtEnums(QStringView value)
u"TopToBottom", u"UpArrowCursor", u"Vertical", u"WaitCursor",
u"WhatsThisCursor", u"WheelFocus"});
+ if (value.toString().startsWith("Key_"))
+ return true;
+
return std::binary_search(std::begin(list),
std::end(list),
QmlDesigner::ModelUtils::toStdStringView(value));
@@ -102,32 +94,28 @@ bool isGlobalQtEnums(QStringView value)
bool isKnownEnumScopes(QStringView value)
{
- static constexpr auto list = Utils::to_array<std::u16string_view>({u"TextInput",
- u"TextEdit",
- u"Material",
- u"Universal",
- u"Font",
- u"Shape",
- u"ShapePath",
- u"AbstractButton",
- u"Text",
- u"ShaderEffectSource",
- u"Grid",
- u"ItemLayer",
- u"ImageLayer",
- u"SpriteLayer",
- u"Light"});
+ static constexpr auto list = Utils::to_array<std::u16string_view>(
+ {u"TextInput",
+ u"TextEdit",
+ u"Material",
+ u"Universal",
+ u"Font",
+ u"Shape",
+ u"ShapePath",
+ u"AbstractButton",
+ u"Text",
+ u"ShaderEffectSource",
+ u"Grid",
+ u"ItemLayer",
+ u"ImageLayer",
+ u"SpriteLayer",
+ u"Light",
+ u"ExtendedSceneEnvironment.GlowBlendMode"});
return std::find(std::begin(list), std::end(list), QmlDesigner::ModelUtils::toStdStringView(value))
!= std::end(list);
}
-bool supportedQtQuickVersion(const QmlDesigner::Import &import)
-{
- auto version = import.toVersion();
- return version.isEmpty() || isSupportedVersion(version);
-}
-
QString stripQuotes(const QString &str)
{
if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
@@ -431,14 +419,19 @@ namespace Internal {
class ReadingContext
{
public:
- ReadingContext(const Snapshot &snapshot, const Document::Ptr &doc,
- const ViewerContext &vContext, Model *model)
+ ReadingContext([[maybe_unused]] const Snapshot &snapshot,
+ [[maybe_unused]] const Document::Ptr &doc,
+ [[maybe_unused]] const ViewerContext &vContext,
+ Model *model)
: m_doc(doc)
+#ifndef QDS_USE_PROJECTSTORAGE
, m_context(
- Link(snapshot, vContext, ModelManagerInterface::instance()->builtins(doc))
- (doc, &m_diagnosticLinkMessages))
+ Link(snapshot,
+ vContext,
+ ModelManagerInterface::instance()->builtins(doc))(doc, &m_diagnosticLinkMessages))
, m_scopeChain(doc, m_context)
, m_scopeBuilder(&m_scopeChain)
+#endif
, m_model(model)
{
}
@@ -446,12 +439,19 @@ public:
~ReadingContext() = default;
Document::Ptr doc() const
- { return m_doc; }
+ {
+ return m_doc;
+ }
+#ifndef QDS_USE_PROJECTSTORAGE
void enterScope(AST::Node *node)
{ m_scopeBuilder.push(node); }
- void leaveScope() { m_scopeBuilder.pop(); }
+ void leaveScope()
+ {
+ m_scopeBuilder.pop();
+ }
+#endif
std::tuple<NodeMetaInfo, TypeName> lookup(AST::UiQualifiedId *astTypeNode)
{
@@ -481,113 +481,6 @@ public:
return node.metaInfo().hasProperty(propertyName.toUtf8());
}
- /// When something is changed here, also change Check::checkScopeObjectMember in
- /// qmljscheck.cpp
- /// ### Maybe put this into the context as a helper function.
- ///
- bool lookupProperty(const QString &prefix,
- const AST::UiQualifiedId *id,
- const Value **property = nullptr,
- const ObjectValue **parentObject = nullptr,
- QString *name = nullptr)
- {
- QList<const ObjectValue *> scopeObjects = m_scopeChain.qmlScopeObjects();
- if (scopeObjects.isEmpty())
- return false;
-
- if (!id)
- return false; // ### error?
-
- if (id->name.isEmpty()) // possible after error recovery
- return false;
-
- QString propertyName;
- if (prefix.isEmpty())
- propertyName = id->name.toString();
- else
- propertyName = prefix;
-
- if (name)
- *name = propertyName;
-
- if (propertyName == u"id" && !id->next)
- return false; // ### should probably be a special value
-
- // attached properties
- bool isAttachedProperty = false;
- if (! propertyName.isEmpty() && propertyName[0].isUpper()) {
- isAttachedProperty = true;
- if (const ObjectValue *qmlTypes = m_scopeChain.qmlTypes())
- scopeObjects += qmlTypes;
- }
-
- if (scopeObjects.isEmpty())
- return false;
-
- // global lookup for first part of id
- const ObjectValue *objectValue = nullptr;
- const Value *value = nullptr;
- for (int i = scopeObjects.size() - 1; i >= 0; --i) {
- objectValue = scopeObjects[i];
- value = objectValue->lookupMember(propertyName, m_context);
- if (value)
- break;
- }
- if (parentObject)
- *parentObject = objectValue;
- if (!value) {
- qCInfo(texttomodelMergerDebug) << Q_FUNC_INFO << "Skipping invalid property name" << propertyName;
- return false;
- }
-
- // can't look up members for attached properties
- if (isAttachedProperty)
- return false;
-
- // resolve references
- if (const Reference *ref = value->asReference())
- value = m_context->lookupReference(ref);
-
- // member lookup
- const AST::UiQualifiedId *idPart = id;
- if (prefix.isEmpty())
- idPart = idPart->next;
- for (; idPart; idPart = idPart->next) {
- objectValue = value_cast<ObjectValue>(value);
- if (! objectValue) {
-// if (idPart->name)
-// qDebug() << idPart->name->asString() << "has no property named"
-// << propertyName;
- return false;
- }
- if (parentObject)
- *parentObject = objectValue;
-
- if (idPart->name.isEmpty()) {
- // somebody typed "id." and error recovery still gave us a valid tree,
- // so just bail out here.
- return false;
- }
-
- propertyName = idPart->name.toString();
- if (name)
- *name = propertyName;
-
- value = objectValue->lookupMember(propertyName, m_context);
- if (! value) {
-// if (idPart->name)
-// qDebug() << "In" << idPart->name->asString() << ":"
-// << objectValue->className() << "has no property named"
-// << propertyName;
- return false;
- }
- }
-
- if (property)
- *property = value;
- return true;
- }
-
bool isArrayProperty(const AbstractProperty &property)
{
return ModelUtils::metainfo(property).isListProperty();
@@ -610,9 +503,9 @@ public:
if (!propertyMetaInfo.isValid()) {
const bool isAttached = !propertyName.isEmpty() && propertyName[0].isUpper();
// Only list elements might have unknown properties.
- if (!node.metaInfo().isQtQuickListElement() && !isAttached) {
- qCInfo(texttomodelMergerDebug)
- << Q_FUNC_INFO << "Unknown property"
+ if (!node.metaInfo().isQtQmlModelsListElement() && !isAttached) {
+ qCInfo(texttomodelMergerLog)
+ << Q_FUNC_INFO << "\nUnknown property"
<< propertyPrefix + QLatin1Char('.') + toString(propertyId) << "on line"
<< propertyId->identifierToken.startLine << "column"
<< propertyId->identifierToken.startColumn;
@@ -668,6 +561,11 @@ public:
//Check for known enum scopes used globally
if (isKnownEnumScopes(astValueList.constFirst()))
return QVariant::fromValue(Enumeration(astValue));
+ } else if (astValueList.size() == 3) {
+ QString enumName = astValueList.constFirst() + '.' + astValueList.at(1);
+ if (isKnownEnumScopes(enumName))
+ return QVariant::fromValue(
+ Enumeration(enumName.toUtf8(), astValueList.constLast().toUtf8()));
}
auto eStmt = AST::cast<AST::ExpressionStatement *>(rhs);
@@ -685,9 +583,12 @@ public:
return QVariant();
}
-
+#ifndef QDS_USE_PROJECTSTORAGE
const ScopeChain &scopeChain() const
- { return m_scopeChain; }
+ {
+ return m_scopeChain;
+ }
+#endif
QList<DiagnosticMessage> diagnosticLinkMessages() const
{ return m_diagnosticLinkMessages; }
@@ -695,9 +596,11 @@ public:
private:
Document::Ptr m_doc;
QList<DiagnosticMessage> m_diagnosticLinkMessages;
+#ifndef QDS_USE_PROJECTSTORAGE
ContextPtr m_context;
ScopeChain m_scopeChain;
ScopeBuilder m_scopeBuilder;
+#endif
Model *m_model;
};
@@ -841,6 +744,7 @@ constexpr auto skipModules = std::make_tuple(EndsWith(u".impl"),
Equals(u"QtQuick.Controls.NativeStyle"),
Equals(u"QtQuick.Controls.Universal"),
Equals(u"QtQuick.Controls.Windows"),
+ Equals(u"QtQuick3D.MaterialEditor"),
StartsWith(u"QtQuick.LocalStorage"),
StartsWith(u"QtQuick.NativeStyle"),
StartsWith(u"QtQuick.Pdf"),
@@ -866,6 +770,7 @@ constexpr auto skipModules = std::make_tuple(EndsWith(u".impl"),
StartsWith(u"QtWebSockets"),
StartsWith(u"QtWebView"));
+#ifndef QDS_USE_PROJECTSTORAGE
bool skipModule(QStringView moduleName)
{
return std::apply([=](const auto &...skipModule) { return (skipModule(moduleName) || ...); },
@@ -931,9 +836,11 @@ QmlDesigner::Imports createQt5Modules()
QmlDesigner::Import::createLibraryImport("QtQuick.Studio.MultiText", "1.0"),
QmlDesigner::Import::createLibraryImport("Qt.SafeRenderer", "2.0")};
}
+#endif
} // namespace
+#ifndef QDS_USE_PROJECTSTORAGE
void TextToModelMerger::setupPossibleImports()
{
if (!m_rewriterView->possibleImportsEnabled())
@@ -942,10 +849,10 @@ void TextToModelMerger::setupPossibleImports()
static QUrl lastProjectUrl;
auto &externalDependencies = m_rewriterView->externalDependencies();
auto projectUrl = externalDependencies.projectUrl();
+
auto allUsedImports = m_scopeChain->context()->imports(m_document.data())->all();
if (m_possibleModules.isEmpty() || projectUrl != lastProjectUrl) {
-
auto &externalDependencies = m_rewriterView->externalDependencies();
if (externalDependencies.isQt6Project()) {
ModuleScanner moduleScanner{[&](QStringView moduleName) {
@@ -975,7 +882,9 @@ void TextToModelMerger::setupPossibleImports()
if (m_rewriterView->isAttached())
m_rewriterView->model()->setPossibleImports(modules);
}
+#endif
+#ifndef QDS_USE_PROJECTSTORAGE
void TextToModelMerger::setupUsedImports()
{
const QmlJS::Imports *imports = m_scopeChain->context()->imports(m_document.data());
@@ -1010,6 +919,7 @@ void TextToModelMerger::setupUsedImports()
if (m_rewriterView->isAttached())
m_rewriterView->model()->setUsedImports(usedImports);
}
+#endif
Document::MutablePtr TextToModelMerger::createParsedDocument(const QUrl &url, const QString &data, QList<DocumentMessage> *errors)
{
@@ -1100,15 +1010,16 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
m_vContext = ModelManagerInterface::instance()->projectVContext(Dialect::Qml, m_document);
ReadingContext ctxt(snapshot, m_document, m_vContext, m_rewriterView->model());
- m_scopeChain = QSharedPointer<const ScopeChain>(
- new ScopeChain(ctxt.scopeChain()));
+
+#ifndef QDS_USE_PROJECTSTORAGE
+ m_scopeChain = QSharedPointer<const ScopeChain>(new ScopeChain(ctxt.scopeChain()));
if (view()->checkLinkErrors()) {
qCInfo(rewriterBenchmark) << "linked:" << time.elapsed();
collectLinkErrors(&errors, ctxt);
}
-
setupPossibleImports();
+#endif
qCInfo(rewriterBenchmark) << "possible imports:" << time.elapsed();
@@ -1142,7 +1053,9 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
qCInfo(rewriterBenchmark) << "synced nodes:" << time.elapsed();
+#ifndef QDS_USE_PROJECTSTORAGE
setupUsedImports();
+#endif
setActive(false);
@@ -1239,8 +1152,9 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
else if (!modelNode.nodeSource().isEmpty() || modelNode.nodeSourceType() != ModelNode::NodeWithoutSource)
clearImplicitComponentDelayed(modelNode, differenceHandler.isAmender());
-
+#ifndef QDS_USE_PROJECTSTORAGE
context->enterScope(astNode);
+#endif
QSet<PropertyName> modelPropertyNames = Utils::toSet(modelNode.propertyNames());
if (!modelNode.id().isEmpty())
@@ -1254,7 +1168,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
if (auto array = AST::cast<AST::UiArrayBinding *>(member)) {
const QString astPropertyName = toString(array->qualifiedId);
- if (isPropertyChangesType(typeName) || isConnectionsType(typeName) || context->lookupProperty(QString(), array->qualifiedId)) {
+ if (isPropertyChangesType(typeName) || isConnectionsType(typeName)
+ || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) {
AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8());
QList<AST::UiObjectMember *> arrayMembers;
for (AST::UiArrayMemberList *iter = array->members; iter; iter = iter->next)
@@ -1286,13 +1201,8 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
// Store Behaviours in the default property
defaultPropertyItems.append(member);
} else {
- const Value *propertyType = nullptr;
- const ObjectValue *containingObject = nullptr;
- if (context->lookupProperty({},
- binding->qualifiedId,
- &propertyType,
- &containingObject)
- || isPropertyChangesType(typeName) || isConnectionsType(typeName)) {
+ if (isPropertyChangesType(typeName) || isConnectionsType(typeName)
+ || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) {
AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8());
if (context->isArrayProperty(modelProperty))
syncArrayProperty(modelProperty, {member}, context, differenceHandler);
@@ -1396,7 +1306,9 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
differenceHandler.propertyAbsentFromQml(modelProperty);
}
+#ifndef QDS_USE_PROJECTSTORAGE
context->leaveScope();
+#endif
}
static QVariant parsePropertyExpression(AST::ExpressionNode *expressionNode)
@@ -1476,9 +1388,8 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN
}
if (isLiteralValue(script)) {
- if (isPropertyChangesType(modelNode.type())
- || isConnectionsType(modelNode.type())
- || isListElementType(modelNode.type())) {
+ if (isPropertyChangesType(modelNode.type()) || isConnectionsType(modelNode.type())
+ || isListElementType(modelNode.type())) {
AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8());
QVariant variantValue = parsePropertyScriptBinding(script);
if (!variantValue.isValid())
@@ -1512,15 +1423,14 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN
syncVariantProperty(modelProperty, enumValue, TypeName(), differenceHandler); // TODO: parse type
return astPropertyName.toUtf8();
} else { // Not an enum, so:
- if (isPropertyChangesType(modelNode.type())
- || isConnectionsType(modelNode.type())
- || context->lookupProperty(prefix, script->qualifiedId)
- || isSupportedAttachedProperties(astPropertyName)) {
+ if (isPropertyChangesType(modelNode.type()) || isConnectionsType(modelNode.type())
+ || isSupportedAttachedProperties(astPropertyName)
+ || modelNode.metaInfo().hasProperty(astPropertyName.toUtf8())) {
AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8());
syncExpressionProperty(modelProperty, astValue, TypeName(), differenceHandler); // TODO: parse type
return astPropertyName.toUtf8();
} else {
- qWarning() << Q_FUNC_INFO << "Skipping invalid expression property" << astPropertyName
+ qCInfo(texttomodelMergerLog) << Q_FUNC_INFO << "\nSkipping invalid expression property" << astPropertyName
<< "for node type" << modelNode.type();
return PropertyName();
}
@@ -1655,7 +1565,7 @@ void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty,
const TypeName &astType,
DifferenceHandler &differenceHandler)
{
- if (astValue.canConvert(QMetaType::QString))
+ if (astValue.canConvert(QMetaType(QMetaType::QString)))
populateQrcMapping(astValue.toString());
if (modelProperty.isVariantProperty()) {
@@ -2232,42 +2142,31 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
bool hasQtQuick = false;
for (const QmlDesigner::Import &import : m_rewriterView->model()->imports()) {
if (import.isLibraryImport() && import.url() == u"QtQuick") {
- if (supportedQtQuickVersion(import)) {
- hasQtQuick = true;
-
- auto &externalDependencies = m_rewriterView->externalDependencies();
- if (externalDependencies.hasStartupTarget()) {
- const bool qt6import = !import.hasVersion() || import.majorVersion() == 6;
-
- if (!externalDependencies.isQt6Import() && (m_hasVersionlessImport || qt6import)) {
- const QmlJS::DiagnosticMessage diagnosticMessage(
- QmlJS::Severity::Error,
- SourceLocation(0, 0, 0, 0),
- QCoreApplication::translate(
- "QmlDesigner::TextToModelMerger",
- "Qt Quick 6 is not supported with a Qt 5 kit."));
- errors->prepend(
- DocumentMessage(diagnosticMessage,
- QUrl::fromLocalFile(m_document->fileName().path())));
- }
- } else {
+ hasQtQuick = true;
+
+ auto &externalDependencies = m_rewriterView->externalDependencies();
+ if (externalDependencies.hasStartupTarget()) {
+ const bool qt6import = !import.hasVersion() || import.majorVersion() == 6;
+
+ if (!externalDependencies.isQt6Import() && (m_hasVersionlessImport || qt6import)) {
const QmlJS::DiagnosticMessage diagnosticMessage(
QmlJS::Severity::Error,
SourceLocation(0, 0, 0, 0),
- QCoreApplication::translate("QmlDesigner::TextToModelMerger",
- "The Design Mode requires a valid Qt kit."));
+ QCoreApplication::translate(
+ "QmlDesigner::TextToModelMerger",
+ "Qt Quick 6 is not supported with a Qt 5 kit."));
errors->prepend(
DocumentMessage(diagnosticMessage,
QUrl::fromLocalFile(m_document->fileName().path())));
}
} else {
- const QmlJS::DiagnosticMessage
- diagnosticMessage(QmlJS::Severity::Error,
- SourceLocation(0, 0, 0, 0),
- QCoreApplication::translate("QmlDesigner::TextToModelMerger",
- "Unsupported Qt Quick version."));
- errors->append(DocumentMessage(diagnosticMessage,
- QUrl::fromLocalFile(m_document->fileName().path())));
+ const QmlJS::DiagnosticMessage diagnosticMessage(
+ QmlJS::Severity::Error,
+ SourceLocation(0, 0, 0, 0),
+ QCoreApplication::translate("QmlDesigner::TextToModelMerger",
+ "The Design Mode requires a valid Qt kit."));
+ errors->prepend(DocumentMessage(diagnosticMessage,
+ QUrl::fromLocalFile(m_document->fileName().path())));
}
}
}
@@ -2276,8 +2175,10 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
errors->append(DocumentMessage(QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import for Qt Quick found.")));
}
-void TextToModelMerger::collectSemanticErrorsAndWarnings(QList<DocumentMessage> *errors, QList<DocumentMessage> *warnings)
+void TextToModelMerger::collectSemanticErrorsAndWarnings(
+ [[maybe_unused]] QList<DocumentMessage> *errors, [[maybe_unused]] QList<DocumentMessage> *warnings)
{
+#ifndef QDS_USE_PROJECTSTORAGE
Check check(m_document, m_scopeChain->context());
check.disableMessage(StaticAnalysis::ErrPrototypeCycle);
check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototype);
@@ -2306,6 +2207,7 @@ void TextToModelMerger::collectSemanticErrorsAndWarnings(QList<DocumentMessage>
if (message.severity == Severity::Warning)
warnings->append(DocumentMessage(message.toDiagnosticMessage(), fileNameUrl));
}
+#endif
}
void TextToModelMerger::populateQrcMapping(const QString &filePath)
@@ -2410,6 +2312,9 @@ QSet<QPair<QString, QString> > TextToModelMerger::qrcMapping() const
QList<QmlTypeData> TextToModelMerger::getQMLSingletons() const
{
+#ifdef QDS_USE_PROJECTSTORAGE
+ return {};
+#else
QList<QmlTypeData> list;
if (!m_scopeChain || !m_scopeChain->document())
return list;
@@ -2440,6 +2345,7 @@ QList<QmlTypeData> TextToModelMerger::getQMLSingletons() const
}
}
return list;
+#endif
}
void TextToModelMerger::clearPossibleImportKeys()
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
index f511906040..e22f747718 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
@@ -37,15 +37,19 @@ public:
bool isActive() const;
void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler);
+#ifndef QDS_USE_PROJECTSTORAGE
void setupPossibleImports();
+#endif
void setupUsedImports();
bool load(const QString &data, DifferenceHandler &differenceHandler);
RewriterView *view() const
{ return m_rewriterView; }
+#ifndef QDS_USE_PROJECTSTORAGE
const QmlJS::ScopeChain *scopeChain() const
{ return m_scopeChain.data(); }
+#endif
const QmlJS::Document *document() const
{ return m_document.data(); }
@@ -141,7 +145,9 @@ private:
private:
RewriterView *m_rewriterView;
bool m_isActive;
+#ifndef QDS_USE_PROJECTSTORAGE
QSharedPointer<const QmlJS::ScopeChain> m_scopeChain;
+#endif
QmlJS::Document::Ptr m_document;
QTimer m_setupTimer;
QSet<ModelNode> m_setupComponentList;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
index 03c25dfac7..76305b1fbe 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
@@ -84,16 +84,15 @@ inline constexpr char PrincipledMaterial[] = "PrincipledMaterial";
inline constexpr char PropertyAnimation[] = "PropertyAnimation";
inline constexpr char PropertyChanges[] = "PropertyChanges";
inline constexpr char QML[] = "QML";
-inline constexpr char QML_cppnative[] = "QML-cppnative";
inline constexpr char QQuick3DParticleAbstractShape[] = "QQuick3DParticleAbstractShape";
inline constexpr char QQuickStateOperation[] = "QQuickStateOperation";
inline constexpr char QtMultimedia[] = "QtMultimedia";
inline constexpr char QtObject[] = "QtObject";
inline constexpr char QtQml[] = "QtQml";
inline constexpr char QtQml_Models[] = "QtQml.Models";
+inline constexpr char QtQml_XmlListModel[] = "QtQml.XmlListModel";
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_Controls[] = "QtQuick.Controls";
inline constexpr char QtQuick_Dialogs[] = "QtQuick.Dialogs";
@@ -103,7 +102,6 @@ inline constexpr char QtQuick_Studio_Components[] = "QtQuick.Studio.Components";
inline constexpr char QtQuick_Templates[] = "QtQuick.Templates";
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 Rectangle[] = "Rectangle";
inline constexpr char Repeater[] = "Repeater";
@@ -131,6 +129,7 @@ inline constexpr char Transition[] = "Transition";
inline constexpr char UIntType[] = "uint";
inline constexpr char View3D[] = "View3D";
inline constexpr char Window[] = "Window";
+inline constexpr char XmlListModelRole[] = "XmlListModelRole";
inline constexpr char color[] = "color";
inline constexpr char date[] = "date";
inline constexpr char font[] = "font";
@@ -147,7 +146,7 @@ struct BaseCacheType
QmlDesigner::TypeId typeId;
};
-template<const char *moduleName_, const char *typeName_>
+template<const char *moduleName_, ModuleKind moduleKind, const char *typeName_>
struct CacheType : public BaseCacheType
{
};
@@ -155,105 +154,107 @@ struct CacheType : public BaseCacheType
template<typename ProjectStorage>
class CommonTypeCache
{
- using CommonTypes = std::tuple<CacheType<FlowView, FlowActionArea>,
- CacheType<FlowView, FlowDecision>,
- CacheType<FlowView, FlowItem>,
- CacheType<FlowView, FlowTransition>,
- CacheType<FlowView, FlowView>,
- CacheType<FlowView, FlowWildcard>,
- CacheType<QML, BoolType>,
- CacheType<QML, Component>,
- CacheType<QML, DoubleType>,
- CacheType<QML, IntType>,
- CacheType<QML, QtObject>,
- CacheType<QML, date>,
- CacheType<QML, string>,
- CacheType<QML, url>,
- CacheType<QML, var>,
- CacheType<QML_cppnative, FloatType>,
- CacheType<QML_cppnative, UIntType>,
- CacheType<QtQml, Connections>,
- CacheType<QtMultimedia, SoundEffect>,
- CacheType<QtQml_Models, ListElement>,
- CacheType<QtQml_Models, ListModel>,
- CacheType<QtQuick, BorderImage>,
- CacheType<QtQuick, GridView>,
- CacheType<QtQuick, Image>,
- CacheType<QtQuick, Item>,
- CacheType<QtQuick, ListView>,
- CacheType<QtQuick, Loader>,
- CacheType<QtQuick, MouseArea>,
- CacheType<QtQuick, Path>,
- CacheType<QtQuick, PathView>,
- CacheType<QtQuick, PauseAnimation>,
- CacheType<QtQuick, Positioner>,
- CacheType<QtQuick, PropertyAnimation>,
- CacheType<QtQuick, PropertyChanges>,
- CacheType<QtQuick, Rectangle>,
- CacheType<QtQuick, Repeater>,
- CacheType<QtQuick, State>,
- CacheType<QtQuick, StateGroup>,
- CacheType<QtQuick, Text>,
- CacheType<QtQuick, TextEdit>,
- CacheType<QtQuick, Transition>,
- CacheType<QtQuick, color>,
- CacheType<QtQuick, font>,
- CacheType<QtQuick, vector2d>,
- CacheType<QtQuick, vector3d>,
- CacheType<QtQuick, vector4d>,
- CacheType<QtQuick3D, BakedLightmap>,
- CacheType<QtQuick3D, Buffer>,
- CacheType<QtQuick3D, Camera>,
- CacheType<QtQuick3D, Command>,
- CacheType<QtQuick3D, CubeMapTexture>,
- CacheType<QtQuick3D, DefaultMaterial>,
- CacheType<QtQuick3D, DirectionalLight>,
- CacheType<QtQuick3D, Effect>,
- CacheType<QtQuick3D, InstanceList>,
- CacheType<QtQuick3D, InstanceListEntry>,
- CacheType<QtQuick3D, Light>,
- CacheType<QtQuick3D, Material>,
- CacheType<QtQuick3D, Model>,
- CacheType<QtQuick3D, Node>,
- CacheType<QtQuick3D, OrthographicCamera>,
- CacheType<QtQuick3D, Pass>,
- CacheType<QtQuick3D, PerspectiveCamera>,
- CacheType<QtQuick3D, PointLight>,
- CacheType<QtQuick3D, PrincipledMaterial>,
- CacheType<QtQuick3D, SceneEnvironment>,
- CacheType<QtQuick3D, Shader>,
- CacheType<QtQuick3D, SpecularGlossyMaterial>,
- CacheType<QtQuick3D, SpotLight>,
- CacheType<QtQuick3D, Texture>,
- CacheType<QtQuick3D, TextureInput>,
- CacheType<QtQuick3D, View3D>,
- CacheType<QtQuick3D_Particles3D, Affector3D>,
- CacheType<QtQuick3D_Particles3D, Attractor3D>,
- CacheType<QtQuick3D_Particles3D, Model>,
- CacheType<QtQuick3D_Particles3D, Particle3D>,
- CacheType<QtQuick3D_Particles3D, ParticleEmitter3D>,
- CacheType<QtQuick3D_Particles3D, SpriteParticle3D>,
- CacheType<QtQuick3D_Particles3D_cppnative, QQuick3DParticleAbstractShape>,
- CacheType<QtQuick_Controls, Control>,
- CacheType<QtQuick_Controls, Popup>,
- CacheType<QtQuick_Controls, SplitView>,
- CacheType<QtQuick_Controls, SwipeView>,
- CacheType<QtQuick_Controls, TabBar>,
- CacheType<QtQuick_Controls, TextArea>,
- CacheType<QtQuick_Dialogs, Dialog>,
- CacheType<QtQuick_Extras, Picture>,
- CacheType<QtQuick_Layouts, Layout>,
- CacheType<QtQuick_Studio_Components, GroupItem>,
- CacheType<QtQuick_Studio_Components, JsonListModel>,
- CacheType<QtQuick_Templates, Control>,
- CacheType<QtQuick_Timeline, Keyframe>,
- CacheType<QtQuick_Timeline, KeyframeGroup>,
- CacheType<QtQuick_Timeline, Timeline>,
- CacheType<QtQuick_Timeline, TimelineAnimation>,
- CacheType<QtQuick_cppnative, QQuickStateOperation>,
- CacheType<Qt_SafeRenderer, SafePicture>,
- CacheType<Qt_SafeRenderer, SafeRendererPicture>,
- CacheType<QtQuick_Window, Window>>;
+ using CommonTypes = std::tuple<
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowActionArea>,
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowDecision>,
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowItem>,
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowTransition>,
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowView>,
+ CacheType<FlowView, ModuleKind::QmlLibrary, FlowWildcard>,
+ CacheType<QML, ModuleKind::QmlLibrary, BoolType>,
+ CacheType<QML, ModuleKind::QmlLibrary, Component>,
+ CacheType<QML, ModuleKind::QmlLibrary, DoubleType>,
+ CacheType<QML, ModuleKind::QmlLibrary, IntType>,
+ CacheType<QML, ModuleKind::QmlLibrary, QtObject>,
+ CacheType<QML, ModuleKind::QmlLibrary, date>,
+ CacheType<QML, ModuleKind::QmlLibrary, string>,
+ CacheType<QML, ModuleKind::QmlLibrary, url>,
+ CacheType<QML, ModuleKind::QmlLibrary, var>,
+ CacheType<QML, ModuleKind::CppLibrary, FloatType>,
+ CacheType<QML, ModuleKind::CppLibrary, UIntType>,
+ CacheType<QtQml, ModuleKind::QmlLibrary, Connections>,
+ CacheType<QtMultimedia, ModuleKind::QmlLibrary, SoundEffect>,
+ CacheType<QtQml_Models, ModuleKind::QmlLibrary, ListElement>,
+ CacheType<QtQml_Models, ModuleKind::QmlLibrary, ListModel>,
+ CacheType<QtQml_XmlListModel, ModuleKind::QmlLibrary, XmlListModelRole>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, BorderImage>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, GridView>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Image>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Item>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, ListView>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Loader>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, MouseArea>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Path>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, PathView>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, PauseAnimation>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Positioner>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, PropertyAnimation>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, PropertyChanges>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Rectangle>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Repeater>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, State>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, StateGroup>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Text>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, TextEdit>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, Transition>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, color>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, font>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, vector2d>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, vector3d>,
+ CacheType<QtQuick, ModuleKind::QmlLibrary, vector4d>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, BakedLightmap>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Buffer>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Camera>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Command>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, CubeMapTexture>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, DefaultMaterial>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, DirectionalLight>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Effect>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, InstanceList>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, InstanceListEntry>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Light>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Material>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Model>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Node>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, OrthographicCamera>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Pass>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, PerspectiveCamera>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, PointLight>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, PrincipledMaterial>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, SceneEnvironment>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Shader>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, SpecularGlossyMaterial>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, SpotLight>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, Texture>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, TextureInput>,
+ CacheType<QtQuick3D, ModuleKind::QmlLibrary, View3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Affector3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Attractor3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Model>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, Particle3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, ParticleEmitter3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::QmlLibrary, SpriteParticle3D>,
+ CacheType<QtQuick3D_Particles3D, ModuleKind::CppLibrary, QQuick3DParticleAbstractShape>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, Control>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, Popup>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, SplitView>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, SwipeView>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, TabBar>,
+ CacheType<QtQuick_Controls, ModuleKind::QmlLibrary, TextArea>,
+ CacheType<QtQuick_Dialogs, ModuleKind::QmlLibrary, Dialog>,
+ CacheType<QtQuick_Extras, ModuleKind::QmlLibrary, Picture>,
+ CacheType<QtQuick_Layouts, ModuleKind::QmlLibrary, Layout>,
+ CacheType<QtQuick_Studio_Components, ModuleKind::QmlLibrary, GroupItem>,
+ CacheType<QtQuick_Studio_Components, ModuleKind::QmlLibrary, JsonListModel>,
+ CacheType<QtQuick_Templates, ModuleKind::QmlLibrary, Control>,
+ CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, Keyframe>,
+ CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, KeyframeGroup>,
+ CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, Timeline>,
+ CacheType<QtQuick_Timeline, ModuleKind::QmlLibrary, TimelineAnimation>,
+ CacheType<QtQuick, ModuleKind::CppLibrary, QQuickStateOperation>,
+ CacheType<Qt_SafeRenderer, ModuleKind::QmlLibrary, SafePicture>,
+ CacheType<Qt_SafeRenderer, ModuleKind::QmlLibrary, SafeRendererPicture>,
+ CacheType<QtQuick_Window, ModuleKind::QmlLibrary, Window>>;
public:
CommonTypeCache(const ProjectStorage &projectStorage)
@@ -280,14 +281,14 @@ public:
std::fill(std::begin(m_typesWithoutProperties), std ::end(m_typesWithoutProperties), TypeId{});
}
- template<const char *moduleName, const char *typeName>
+ template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary>
TypeId typeId() const
{
- auto &type = std::get<CacheType<moduleName, typeName>>(m_types);
+ auto &type = std::get<CacheType<moduleName, moduleKind, typeName>>(m_types);
if (type.typeId)
return type.typeId;
- return refreshTypedId(type, moduleName, typeName);
+ return refreshTypedId(type, moduleName, moduleKind, typeName);
}
template<const char *typeName>
@@ -304,11 +305,11 @@ public:
else if constexpr (std::is_same_v<Type, int>)
return typeId<QML, IntType>();
else if constexpr (std::is_same_v<Type, uint>)
- return typeId<QML_cppnative, UIntType>();
+ return typeId<QML, UIntType, ModuleKind::CppLibrary>();
else if constexpr (std::is_same_v<Type, bool>)
return typeId<QML, BoolType>();
else if constexpr (std::is_same_v<Type, float>)
- return typeId<QML_cppnative, FloatType>();
+ return typeId<QML, FloatType, ModuleKind::CppLibrary>();
else if constexpr (std::is_same_v<Type, QString>)
return typeId<QML, string>();
else if constexpr (std::is_same_v<Type, QDateTime>)
@@ -338,10 +339,11 @@ public:
private:
TypeId refreshTypedId(BaseCacheType &type,
::Utils::SmallStringView moduleName,
+ ModuleKind moduleKind,
::Utils::SmallStringView typeName) const
{
if (!type.moduleId)
- type.moduleId = m_projectStorage.moduleId(moduleName);
+ type.moduleId = m_projectStorage.moduleId(moduleName, moduleKind);
type.typeId = m_projectStorage.typeId(type.moduleId, typeName, Storage::Version{});
@@ -350,10 +352,11 @@ private:
TypeId refreshTypedIdWithoutTransaction(BaseCacheType &type,
::Utils::SmallStringView moduleName,
- ::Utils::SmallStringView typeName) const
+ ::Utils::SmallStringView typeName,
+ ModuleKind moduleKind) const
{
if (!type.moduleId)
- type.moduleId = m_projectStorage.fetchModuleIdUnguarded(moduleName);
+ type.moduleId = m_projectStorage.fetchModuleIdUnguarded(moduleName, moduleKind);
type.typeId = m_projectStorage.fetchTypeIdByModuleIdAndExportedName(type.moduleId, typeName);
@@ -368,26 +371,27 @@ private:
std::copy(std::begin(typeIds), std::end(typeIds), std::begin(m_typesWithoutProperties));
}
- template<const char *moduleName, const char *typeName>
+ template<const char *moduleName, const char *typeName, ModuleKind moduleKind = ModuleKind::QmlLibrary>
TypeId typeIdWithoutTransaction() const
{
- auto &type = std::get<CacheType<moduleName, typeName>>(m_types);
+ auto &type = std::get<CacheType<moduleName, moduleKind, typeName>>(m_types);
if (type.typeId)
return type.typeId;
- return refreshTypedIdWithoutTransaction(type, moduleName, typeName);
+ return refreshTypedIdWithoutTransaction(type, moduleName, typeName, moduleKind);
}
void updateTypeIdsWithoutProperties()
{
- setupTypeIdsWithoutProperties({typeIdWithoutTransaction<QML, BoolType>(),
- typeIdWithoutTransaction<QML, IntType>(),
- typeIdWithoutTransaction<QML_cppnative, UIntType>(),
- typeIdWithoutTransaction<QML, DoubleType>(),
- typeIdWithoutTransaction<QML_cppnative, FloatType>(),
- typeIdWithoutTransaction<QML, date>(),
- typeIdWithoutTransaction<QML, string>(),
- typeIdWithoutTransaction<QML, url>()});
+ setupTypeIdsWithoutProperties(
+ {typeIdWithoutTransaction<QML, BoolType>(),
+ typeIdWithoutTransaction<QML, IntType>(),
+ typeIdWithoutTransaction<QML, UIntType, ModuleKind::CppLibrary>(),
+ typeIdWithoutTransaction<QML, DoubleType>(),
+ typeIdWithoutTransaction<QML, FloatType, ModuleKind::CppLibrary>(),
+ typeIdWithoutTransaction<QML, date>(),
+ typeIdWithoutTransaction<QML, string>(),
+ typeIdWithoutTransaction<QML, url>()});
}
private:
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h b/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h
index f3e275b8f3..48b3ba2700 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/filestatus.h
@@ -50,6 +50,18 @@ public:
explicit operator bool() const { return isValid(); }
+ template<typename String>
+ friend void convertToString(String &string, const FileStatus &fileStatus)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("source id", fileStatus.sourceId),
+ keyValue("size", fileStatus.size),
+ keyValue("last modified", fileStatus.lastModified));
+
+ convertToString(string, dict);
+ }
+
public:
SourceId sourceId;
long long size = -1;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp
index 1376b2c3d9..d11190fdc7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.cpp
@@ -11,6 +11,7 @@
#include <QDateTime>
#include <QDir>
+#include <QDirIterator>
#include <QFileInfo>
namespace QmlDesigner {
@@ -69,6 +70,18 @@ QString FileSystem::contentAsQString(const QString &filePath) const
return {};
}
+QStringList FileSystem::subdirectories(const QString &directoryPath) const
+{
+ QStringList directoryPaths;
+ directoryPaths.reserve(100);
+ QDirIterator directoryIterator{directoryPath, QDir::Dirs | QDir::NoDotAndDotDot};
+
+ while (directoryIterator.hasNext())
+ directoryPaths.push_back(directoryIterator.next());
+
+ return directoryPaths;
+}
+
void FileSystem::remove(const SourceIds &sourceIds)
{
for (SourceId sourceId : sourceIds)
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h
index 078fd1ee98..1c881741c6 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/filesystem.h
@@ -6,6 +6,7 @@
#include "filestatuscache.h"
#include "filesysteminterface.h"
#include "nonlockingmutex.h"
+#include "projectstoragefwd.h"
namespace Sqlite {
class Database;
@@ -16,12 +17,9 @@ namespace QmlDesigner {
template<typename ProjectStorage, typename Mutex>
class SourcePathCache;
-template<typename Database>
-class ProjectStorage;
-
class FileSystem : public FileSystemInterface
{
- using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
+ using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>;
public:
FileSystem(PathCache &sourcePathCache)
@@ -33,6 +31,7 @@ public:
long long lastModified(SourceId sourceId) const override;
FileStatus fileStatus(SourceId sourceId) const override;
QString contentAsQString(const QString &filePath) const override;
+ QStringList subdirectories(const QString &directoryPath) const override;
void remove(const SourceIds &sourceIds) override;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h b/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h
index 6a7c964fa6..ff7608c9a3 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/filesysteminterface.h
@@ -20,6 +20,7 @@ public:
virtual FileStatus fileStatus(SourceId sourceId) const = 0;
virtual void remove(const SourceIds &sourceIds) = 0;
virtual QString contentAsQString(const QString &filePath) const = 0;
+ virtual QStringList subdirectories(const QString &directoryPath) const = 0;
protected:
~FileSystemInterface() = default;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp
index 3e493e8772..2283b64945 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp
@@ -3,20 +3,4896 @@
#include "projectstorage.h"
-#include <tracing/qmldesignertracing.h>
-
#include <sqlitedatabase.h>
namespace QmlDesigner {
-NanotraceHR::StringViewCategory<projectStorageTracingStatus()> &projectStorageCategory()
+enum class SpecialIdState { Unresolved = -1 };
+
+constexpr TypeId unresolvedTypeId = TypeId::createSpecialState(SpecialIdState::Unresolved);
+
+class UnresolvedTypeId : public TypeId
+{
+public:
+ constexpr UnresolvedTypeId()
+ : TypeId{TypeId::createSpecialState(SpecialIdState::Unresolved)}
+ {}
+
+ static constexpr UnresolvedTypeId create(DatabaseType idNumber)
+ {
+ UnresolvedTypeId id;
+ id.id = idNumber;
+ return id;
+ }
+};
+
+struct ProjectStorage::Statements
{
- thread_local NanotraceHR::StringViewCategory<projectStorageTracingStatus()>
- projectStorageCategory_{"project storage"_t, Tracing::eventQueue(), projectStorageCategory};
+ Statements(Sqlite::Database &database)
+ : database{database}
+ {}
+
+ Sqlite::Database &database;
+ Sqlite::ReadWriteStatement<1, 2> insertTypeStatement{
+ "INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database};
+ Sqlite::WriteStatement<5> updatePrototypeAndExtensionStatement{
+ "UPDATE types "
+ "SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 "
+ "WHERE typeId=?1 AND ( "
+ " prototypeId IS NOT ?2 "
+ " OR extensionId IS NOT ?3 "
+ " OR prototypeId IS NOT ?4 "
+ " OR extensionNameId IS NOT ?5)",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIdByExportedNameStatement{
+ "SELECT typeId FROM exportedTypeNames WHERE name=?1", database};
+ mutable Sqlite::ReadStatement<1, 2> selectTypeIdByModuleIdAndExportedNameStatement{
+ "SELECT typeId FROM exportedTypeNames "
+ "WHERE moduleId=?1 AND name=?2 "
+ "ORDER BY majorVersion DESC, minorVersion DESC "
+ "LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 3> selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement{
+ "SELECT typeId FROM exportedTypeNames "
+ "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3"
+ "ORDER BY minorVersion DESC "
+ "LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 4> selectTypeIdByModuleIdAndExportedNameAndVersionStatement{
+ "SELECT typeId FROM exportedTypeNames "
+ "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3 AND minorVersion<=?4"
+ "ORDER BY minorVersion DESC "
+ "LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectPropertyDeclarationResultByPropertyDeclarationIdStatement{
+ "SELECT propertyTypeId, propertyDeclarationId, propertyTraits "
+ "FROM propertyDeclarations "
+ "WHERE propertyDeclarationId=?1 "
+ "LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{
+ "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{
+ "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database};
+ mutable Sqlite::ReadStatement<2> selectAllSourceContextsStatement{
+ "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database};
+ Sqlite::WriteStatement<1> insertIntoSourceContextsStatement{
+ "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database};
+ mutable Sqlite::ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{
+ "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database};
+ mutable Sqlite::ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{
+ "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{
+ "SELECT sourceContextId FROM sources WHERE sourceId = ?", database};
+ Sqlite::WriteStatement<2> insertIntoSourcesStatement{
+ "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database};
+ mutable Sqlite::ReadStatement<3> selectAllSourcesStatement{
+ "SELECT sourceName, sourceContextId, sourceId FROM sources", database};
+ mutable Sqlite::ReadStatement<8, 1> selectTypeByTypeIdStatement{
+ "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, "
+ "pd.name "
+ "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON "
+ "defaultPropertyId=propertyDeclarationId "
+ "WHERE t.typeId=?",
+ database};
+ mutable Sqlite::ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{
+ "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM "
+ "exportedTypeNames WHERE typeId=?",
+ database};
+ mutable Sqlite::ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{
+ "SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) "
+ "FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND "
+ "sourceId=?2",
+ database};
+ mutable Sqlite::ReadStatement<8> selectTypesStatement{
+ "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, "
+ "pd.name "
+ "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON "
+ "defaultPropertyId=propertyDeclarationId",
+ database};
+ Sqlite::WriteStatement<2> updateTypeTraitStatement{
+ "UPDATE types SET traits = ?2 WHERE typeId=?1", database};
+ Sqlite::WriteStatement<2> updateTypeAnnotationTraitStatement{
+ "WITH RECURSIVE "
+ " typeSelection(typeId) AS ("
+ " VALUES(?1) "
+ " UNION ALL "
+ " SELECT t.typeId "
+ " FROM types AS t JOIN typeSelection AS ts "
+ " WHERE prototypeId=ts.typeId "
+ " AND t.typeId NOT IN (SELECT typeId FROM typeAnnotations)) "
+ "UPDATE types AS t "
+ "SET annotationTraits = ?2 "
+ "FROM typeSelection ts "
+ "WHERE t.typeId=ts.typeId",
+ database};
+ Sqlite::ReadStatement<1, 2> selectNotUpdatedTypesInSourcesStatement{
+ "SELECT DISTINCT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN "
+ "carray(?2))",
+ database};
+ Sqlite::WriteStatement<1> deleteTypeNamesByTypeIdStatement{
+ "DELETE FROM exportedTypeNames WHERE typeId=?", database};
+ Sqlite::WriteStatement<1> deleteEnumerationDeclarationByTypeIdStatement{
+ "DELETE FROM enumerationDeclarations WHERE typeId=?", database};
+ Sqlite::WriteStatement<1> deletePropertyDeclarationByTypeIdStatement{
+ "DELETE FROM propertyDeclarations WHERE typeId=?", database};
+ Sqlite::WriteStatement<1> deleteFunctionDeclarationByTypeIdStatement{
+ "DELETE FROM functionDeclarations WHERE typeId=?", database};
+ Sqlite::WriteStatement<1> deleteSignalDeclarationByTypeIdStatement{
+ "DELETE FROM signalDeclarations WHERE typeId=?", database};
+ Sqlite::WriteStatement<1> deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database};
+ mutable Sqlite::ReadStatement<4, 1> selectPropertyDeclarationsByTypeIdStatement{
+ "SELECT name, propertyTypeId, propertyTraits, (SELECT name FROM "
+ "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM "
+ "propertyDeclarations AS pd WHERE typeId=?",
+ database};
+ Sqlite::ReadStatement<6, 1> selectPropertyDeclarationsForTypeIdStatement{
+ "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, "
+ "propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations "
+ "WHERE typeId=? ORDER BY name",
+ database};
+ Sqlite::ReadWriteStatement<1, 5> insertPropertyDeclarationStatement{
+ "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, "
+ "propertyImportedTypeNameId, aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5, NULL) "
+ "RETURNING propertyDeclarationId",
+ database};
+ Sqlite::WriteStatement<4> updatePropertyDeclarationStatement{
+ "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, "
+ "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=NULL WHERE "
+ "propertyDeclarationId=?1",
+ database};
+ Sqlite::WriteStatement<3> updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{
+ "WITH RECURSIVE "
+ " properties(aliasPropertyDeclarationId) AS ( "
+ " SELECT propertyDeclarationId FROM propertyDeclarations WHERE "
+ " aliasPropertyDeclarationId=?1 "
+ " UNION ALL "
+ " SELECT pd.propertyDeclarationId FROM "
+ " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) "
+ "UPDATE propertyDeclarations AS pd "
+ "SET propertyTypeId=?2, propertyTraits=?3 "
+ "FROM properties AS p "
+ "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId",
+ database};
+ Sqlite::WriteStatement<1> updatePropertyAliasDeclarationRecursivelyStatement{
+ "WITH RECURSIVE "
+ " propertyValues(propertyTypeId, propertyTraits) AS ("
+ " SELECT propertyTypeId, propertyTraits FROM propertyDeclarations "
+ " WHERE propertyDeclarationId=?1), "
+ " properties(aliasPropertyDeclarationId) AS ( "
+ " SELECT propertyDeclarationId FROM propertyDeclarations WHERE "
+ " aliasPropertyDeclarationId=?1 "
+ " UNION ALL "
+ " SELECT pd.propertyDeclarationId FROM "
+ " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) "
+ "UPDATE propertyDeclarations AS pd "
+ "SET propertyTypeId=pv.propertyTypeId, propertyTraits=pv.propertyTraits "
+ "FROM properties AS p, propertyValues AS pv "
+ "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId",
+ database};
+ Sqlite::WriteStatement<1> deletePropertyDeclarationStatement{
+ "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
+ Sqlite::ReadStatement<3, 1> selectPropertyDeclarationsWithAliasForTypeIdStatement{
+ "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations "
+ "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name",
+ database};
+ Sqlite::WriteStatement<5> updatePropertyDeclarationWithAliasAndTypeStatement{
+ "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, "
+ "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=?5 WHERE "
+ "propertyDeclarationId=?1",
+ database};
+ Sqlite::ReadWriteStatement<1, 2> insertAliasPropertyDeclarationStatement{
+ "INSERT INTO propertyDeclarations(typeId, name) VALUES(?1, ?2) RETURNING "
+ "propertyDeclarationId",
+ database};
+ mutable Sqlite::ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{
+ "SELECT name, returnTypeName, signature, functionDeclarationId FROM "
+ "functionDeclarations WHERE typeId=? ORDER BY name, signature",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{
+ "SELECT name, returnTypeName, functionDeclarationId FROM "
+ "functionDeclarations WHERE typeId=? ORDER BY name",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectFunctionParameterDeclarationsStatement{
+ "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
+ "json_extract(json_each.value, '$.tr') FROM functionDeclarations, "
+ "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?",
+ database};
+ Sqlite::WriteStatement<4> insertFunctionDeclarationStatement{
+ "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, "
+ "?3, ?4)",
+ database};
+ Sqlite::WriteStatement<3> updateFunctionDeclarationStatement{
+ "UPDATE functionDeclarations "
+ "SET returnTypeName=?2, signature=?3 "
+ "WHERE functionDeclarationId=?1",
+ database};
+ Sqlite::WriteStatement<1> deleteFunctionDeclarationStatement{
+ "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database};
+ mutable Sqlite::ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{
+ "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER "
+ "BY name, signature",
+ database};
+ mutable Sqlite::ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{
+ "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectSignalParameterDeclarationsStatement{
+ "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
+ "json_extract(json_each.value, '$.tr') FROM signalDeclarations, "
+ "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?",
+ database};
+ Sqlite::WriteStatement<3> insertSignalDeclarationStatement{
+ "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database};
+ Sqlite::WriteStatement<2> updateSignalDeclarationStatement{
+ "UPDATE signalDeclarations SET signature=?2 WHERE signalDeclarationId=?1", database};
+ Sqlite::WriteStatement<1> deleteSignalDeclarationStatement{
+ "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database};
+ mutable Sqlite::ReadStatement<3, 1> selectEnumerationDeclarationsForTypeIdStatement{
+ "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM "
+ "enumerationDeclarations WHERE typeId=? ORDER BY name",
+ database};
+ mutable Sqlite::ReadStatement<2, 1> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{
+ "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER "
+ "BY name",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectEnumeratorDeclarationStatement{
+ "SELECT json_each.key, json_each.value, json_each.type!='null' FROM "
+ "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE "
+ "enumerationDeclarationId=?",
+ database};
+ Sqlite::WriteStatement<3> insertEnumerationDeclarationStatement{
+ "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, "
+ "?3)",
+ database};
+ Sqlite::WriteStatement<2> updateEnumerationDeclarationStatement{
+ "UPDATE enumerationDeclarations SET enumeratorDeclarations=?2 WHERE "
+ "enumerationDeclarationId=?1",
+ database};
+ Sqlite::WriteStatement<1> deleteEnumerationDeclarationStatement{
+ "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database};
+ mutable Sqlite::ReadStatement<1, 2> selectModuleIdByNameStatement{
+ "SELECT moduleId FROM modules WHERE kind=?1 AND name=?2 LIMIT 1", database};
+ mutable Sqlite::ReadWriteStatement<1, 2> insertModuleNameStatement{
+ "INSERT INTO modules(kind, name) VALUES(?1, ?2) RETURNING moduleId", database};
+ mutable Sqlite::ReadStatement<2, 1> selectModuleStatement{
+ "SELECT name, kind FROM modules WHERE moduleId =?1", database};
+ mutable Sqlite::ReadStatement<3> selectAllModulesStatement{
+ "SELECT name, kind, moduleId FROM modules", database};
+ mutable Sqlite::ReadStatement<1, 2> selectTypeIdBySourceIdAndNameStatement{
+ "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database};
+ mutable Sqlite::ReadStatement<1, 3> selectTypeIdByModuleIdsAndExportedNameStatement{
+ "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND "
+ "name=?3",
+ database};
+ mutable Sqlite::ReadStatement<4> selectAllDocumentImportForSourceIdStatement{
+ "SELECT moduleId, majorVersion, minorVersion, sourceId "
+ "FROM documentImports ",
+ database};
+ mutable Sqlite::ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{
+ "SELECT importId, sourceId, moduleId, majorVersion, minorVersion "
+ "FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, "
+ "moduleId, majorVersion, minorVersion",
+ database};
+ Sqlite::ReadWriteStatement<1, 5> insertDocumentImportWithoutVersionStatement{
+ "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, "
+ "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING importId",
+ database};
+ Sqlite::ReadWriteStatement<1, 6> insertDocumentImportWithMajorVersionStatement{
+ "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
+ "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6) RETURNING importId",
+ database};
+ Sqlite::ReadWriteStatement<1, 7> insertDocumentImportWithVersionStatement{
+ "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
+ "minorVersion, parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) RETURNING "
+ "importId",
+ database};
+ Sqlite::WriteStatement<1> deleteDocumentImportStatement{
+ "DELETE FROM documentImports WHERE importId=?1", database};
+ Sqlite::WriteStatement<2> deleteDocumentImportsWithParentImportIdStatement{
+ "DELETE FROM documentImports WHERE sourceId=?1 AND parentImportId=?2", database};
+ Sqlite::WriteStatement<1> deleteDocumentImportsWithSourceIdsStatement{
+ "DELETE FROM documentImports WHERE sourceId IN carray(?1)", database};
+ mutable Sqlite::ReadStatement<1, 2> selectPropertyDeclarationIdByTypeIdAndNameStatement{
+ "SELECT propertyDeclarationId "
+ "FROM propertyDeclarations "
+ "WHERE typeId=?1 AND name=?2 "
+ "LIMIT 1",
+ database};
+ Sqlite::WriteStatement<2> updateAliasIdPropertyDeclarationStatement{
+ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2 WHERE "
+ "aliasPropertyDeclarationId=?1",
+ database};
+ Sqlite::WriteStatement<2> updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{
+ "UPDATE propertyDeclarations SET propertyTypeId=new.propertyTypeId, "
+ "propertyTraits=new.propertyTraits, aliasPropertyDeclarationId=?1 FROM (SELECT "
+ "propertyTypeId, propertyTraits FROM propertyDeclarations WHERE propertyDeclarationId=?1) "
+ "AS new WHERE aliasPropertyDeclarationId=?2",
+ database};
+ Sqlite::WriteStatement<1> updateAliasPropertyDeclarationToNullStatement{
+ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL, propertyTypeId=NULL, "
+ "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
+ "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
+ database};
+ Sqlite::ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
+ "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
+ " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId "
+ "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target "
+ " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
+ " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId "
+ "WHERE alias.propertyTypeId=?1 "
+ "UNION ALL "
+ "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
+ " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId "
+ "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target "
+ " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
+ " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId "
+ "WHERE target.typeId=?1 "
+ "UNION ALL "
+ "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
+ " alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId "
+ "FROM propertyDeclarations AS alias JOIN propertyDeclarations AS target "
+ " ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
+ " alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId "
+ "WHERE alias.propertyImportedTypeNameId IN "
+ " (SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
+ " WHERE typeId=?1)",
+ database};
+ Sqlite::ReadStatement<3, 1> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{
+ "WITH RECURSIVE "
+ " properties(propertyDeclarationId, propertyImportedTypeNameId, typeId, "
+ " aliasPropertyDeclarationId) AS ("
+ " SELECT propertyDeclarationId, propertyImportedTypeNameId, typeId, "
+ " aliasPropertyDeclarationId FROM propertyDeclarations WHERE "
+ " aliasPropertyDeclarationId=?1"
+ " UNION ALL "
+ " SELECT pd.propertyDeclarationId, pd.propertyImportedTypeNameId, pd.typeId, "
+ " pd.aliasPropertyDeclarationId FROM propertyDeclarations AS pd JOIN properties AS "
+ " p ON pd.aliasPropertyDeclarationId=p.propertyDeclarationId)"
+ "SELECT propertyDeclarationId, propertyImportedTypeNameId, aliasPropertyDeclarationId "
+ " FROM properties",
+ database};
+ Sqlite::ReadWriteStatement<3, 1> updatesPropertyDeclarationPropertyTypeToNullStatement{
+ "UPDATE propertyDeclarations SET propertyTypeId=NULL WHERE propertyTypeId=?1 AND "
+ "aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, "
+ "propertyImportedTypeNameId",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectPropertyNameStatement{
+ "SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
+ Sqlite::WriteStatement<2> updatePropertyDeclarationTypeStatement{
+ "UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database};
+ Sqlite::ReadWriteStatement<2, 2> updatePrototypeIdToTypeIdStatement{
+ "UPDATE types "
+ "SET prototypeId=?2 "
+ "WHERE prototypeId=?1 "
+ "RETURNING typeId, prototypeNameId",
+ database};
+ Sqlite::ReadWriteStatement<2, 2> updateExtensionIdToTypeIdStatement{
+ "UPDATE types "
+ "SET extensionId=?2 "
+ "WHERE extensionId=?1 "
+ "RETURNING typeId, extensionNameId",
+ database};
+ Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement{
+ "SELECT typeId, prototypeNameId "
+ "FROM types "
+ "WHERE prototypeNameId IN ( "
+ " SELECT importedTypeNameId "
+ " FROM "
+ " importedTypeNames WHERE name=?1) "
+ " AND prototypeId=?2",
+ database};
+ Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement{
+ "SELECT typeId , prototypeNameId "
+ "FROM types "
+ "WHERE prototypeId=?1 AND sourceId=?2",
+ database};
+ Sqlite::ReadStatement<2, 2> selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement{
+ "SELECT typeId, extensionNameId "
+ "FROM types "
+ "WHERE extensionId=?1 AND sourceId=?2",
+ database};
+ Sqlite::ReadWriteStatement<3, 3> updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement{
+ "UPDATE types "
+ "SET prototypeId=?2, extensionId=?3 "
+ "WHERE sourceId=?1 "
+ "RETURNING typeId, prototypeNameId, extensionNameId",
+ database};
+ Sqlite::ReadStatement<2, 2> selectTypeIdForExtensionIdAndTypeNameStatement{
+ "SELECT typeId , prototypeNameId "
+ "FROM types "
+ "WHERE extensionNameId IN ( "
+ " SELECT importedTypeNameId "
+ " FROM importedTypeNames "
+ " WHERE name=?1) "
+ " AND extensionId=?2",
+ database};
+ Sqlite::WriteStatement<2> updateTypePrototypeStatement{
+ "UPDATE types SET prototypeId=?2 WHERE typeId=?1", database};
+ Sqlite::WriteStatement<2> updateTypeExtensionStatement{
+ "UPDATE types SET extensionId=?2 WHERE typeId=?1", database};
+ mutable Sqlite::ReadStatement<1, 1> selectPrototypeAndExtensionIdsStatement{
+ "WITH RECURSIVE "
+ " prototypes(typeId) AS ( "
+ " SELECT prototypeId FROM types WHERE typeId=?1 "
+ " UNION ALL "
+ " SELECT extensionId FROM types WHERE typeId=?1 "
+ " UNION ALL "
+ " SELECT prototypeId FROM types JOIN prototypes USING(typeId) "
+ " UNION ALL "
+ " SELECT extensionId FROM types JOIN prototypes USING(typeId)) "
+ "SELECT typeId FROM prototypes WHERE typeId IS NOT NULL",
+ database};
+ Sqlite::WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{
+ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, "
+ "propertyImportedTypeNameId=?3 WHERE propertyDeclarationId=?1 AND "
+ "(aliasPropertyDeclarationId IS NOT ?2 OR propertyImportedTypeNameId IS NOT ?3)",
+ database};
+ Sqlite::WriteStatement<1> updatetPropertiesDeclarationValuesOfAliasStatement{
+ "WITH RECURSIVE "
+ " properties(propertyDeclarationId, propertyTypeId, propertyTraits) AS ( "
+ " SELECT aliasPropertyDeclarationId, propertyTypeId, propertyTraits FROM "
+ " propertyDeclarations WHERE propertyDeclarationId=?1 "
+ " UNION ALL "
+ " SELECT pd.aliasPropertyDeclarationId, pd.propertyTypeId, pd.propertyTraits FROM "
+ " propertyDeclarations AS pd JOIN properties USING(propertyDeclarationId)) "
+ "UPDATE propertyDeclarations AS pd SET propertyTypeId=p.propertyTypeId, "
+ " propertyTraits=p.propertyTraits "
+ "FROM properties AS p "
+ "WHERE pd.propertyDeclarationId=?1 AND p.propertyDeclarationId IS NULL AND "
+ " (pd.propertyTypeId IS NOT p.propertyTypeId OR pd.propertyTraits IS NOT "
+ " p.propertyTraits)",
+ database};
+ Sqlite::WriteStatement<1> updatePropertyDeclarationAliasIdToNullStatement{
+ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL WHERE "
+ "propertyDeclarationId=?1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectPropertyDeclarationIdsForAliasChainStatement{
+ "WITH RECURSIVE "
+ " properties(propertyDeclarationId) AS ( "
+ " SELECT aliasPropertyDeclarationId FROM propertyDeclarations WHERE "
+ " propertyDeclarationId=?1 "
+ " UNION ALL "
+ " SELECT aliasPropertyDeclarationId FROM propertyDeclarations JOIN properties "
+ " USING(propertyDeclarationId)) "
+ "SELECT propertyDeclarationId FROM properties",
+ database};
+ mutable Sqlite::ReadStatement<3> selectAllFileStatusesStatement{
+ "SELECT sourceId, size, lastModified FROM fileStatuses ORDER BY sourceId", database};
+ mutable Sqlite::ReadStatement<3, 1> selectFileStatusesForSourceIdsStatement{
+ "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId IN carray(?1) ORDER "
+ "BY sourceId",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectFileStatusesForSourceIdStatement{
+ "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId=?1 ORDER BY sourceId",
+ database};
+ Sqlite::WriteStatement<3> insertFileStatusStatement{
+ "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES(?1, ?2, ?3)", database};
+ Sqlite::WriteStatement<1> deleteFileStatusStatement{
+ "DELETE FROM fileStatuses WHERE sourceId=?1", database};
+ Sqlite::WriteStatement<3> updateFileStatusStatement{
+ "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database};
+ Sqlite::ReadStatement<1, 1> selectTypeIdBySourceIdStatement{
+ "SELECT typeId FROM types WHERE sourceId=?", database};
+ mutable Sqlite::ReadStatement<1, 3> selectImportedTypeNameIdStatement{
+ "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 "
+ "AND name=?3 LIMIT 1",
+ database};
+ mutable Sqlite::ReadWriteStatement<1, 3> insertImportedTypeNameIdStatement{
+ "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) "
+ "RETURNING importedTypeNameId",
+ database};
+ mutable Sqlite::ReadStatement<1, 2> selectImportIdBySourceIdAndModuleIdStatement{
+ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion "
+ "IS NULL AND minorVersion IS NULL LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 3> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{
+ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND "
+ "majorVersion=?3 AND minorVersion IS NULL LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 4> selectImportIdBySourceIdAndModuleIdAndVersionStatement{
+ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND "
+ "majorVersion=?3 AND minorVersion=?4 LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectKindFromImportedTypeNamesStatement{
+ "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database};
+ mutable Sqlite::ReadStatement<1, 1> selectNameFromImportedTypeNamesStatement{
+ "SELECT name FROM importedTypeNames WHERE importedTypeNameId=?1", database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{
+ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON "
+ "importOrSourceId=di.importId JOIN documentImports AS di2 ON di.sourceId=di2.sourceId AND "
+ "di.moduleId=di2.sourceModuleId "
+ "JOIN exportedTypeNames AS etn ON di2.moduleId=etn.moduleId WHERE "
+ "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND "
+ "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS "
+ "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, "
+ "etn.minorVersion DESC NULLS FIRST LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIdForImportedTypeNameNamesStatement{
+ "WITH "
+ " importTypeNames(moduleId, name, kind, majorVersion, minorVersion) AS ( "
+ " SELECT moduleId, name, di.kind, majorVersion, minorVersion "
+ " FROM importedTypeNames AS itn JOIN documentImports AS di ON "
+ " importOrSourceId=sourceId "
+ " WHERE "
+ " importedTypeNameId=?1 AND itn.kind=1) "
+ "SELECT typeId FROM importTypeNames AS itn "
+ " JOIN exportedTypeNames AS etn USING(moduleId, name) "
+ "WHERE (itn.majorVersion IS NULL OR (itn.majorVersion=etn.majorVersion "
+ " AND (itn.minorVersion IS NULL OR itn.minorVersion>=etn.minorVersion))) "
+ "ORDER BY itn.kind, etn.majorVersion DESC NULLS FIRST, etn.minorVersion DESC NULLS FIRST "
+ "LIMIT 1",
+ database};
+ Sqlite::WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database};
+ Sqlite::WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database};
+ mutable Sqlite::ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{
+ "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, "
+ "exportedTypeNameId FROM exportedTypeNames WHERE typeId in carray(?1) ORDER BY moduleId, "
+ "name, majorVersion, minorVersion",
+ database};
+ Sqlite::WriteStatement<5> insertExportedTypeNamesWithVersionStatement{
+ "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) "
+ "VALUES(?1, ?2, ?3, ?4, ?5)",
+ database};
+ Sqlite::WriteStatement<4> insertExportedTypeNamesWithMajorVersionStatement{
+ "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) "
+ "VALUES(?1, ?2, ?3, ?4)",
+ database};
+ Sqlite::WriteStatement<3> insertExportedTypeNamesWithoutVersionStatement{
+ "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database};
+ Sqlite::WriteStatement<1> deleteExportedTypeNameStatement{
+ "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database};
+ Sqlite::WriteStatement<2> updateExportedTypeNameTypeIdStatement{
+ "UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database};
+ mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfosForSourceIdsStatement{
+ "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE "
+ "directorySourceId IN carray(?1) ORDER BY directorySourceId, sourceId",
+ database};
+ Sqlite::WriteStatement<4> insertDirectoryInfoStatement{
+ "INSERT INTO directoryInfos(directorySourceId, sourceId, "
+ "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)",
+ database};
+ Sqlite::WriteStatement<2> deleteDirectoryInfoStatement{
+ "DELETE FROM directoryInfos WHERE directorySourceId=?1 AND sourceId=?2", database};
+ Sqlite::WriteStatement<4> updateDirectoryInfoStatement{
+ "UPDATE directoryInfos SET moduleId=?3, fileType=?4 WHERE directorySourceId=?1 AND sourceId=?2",
+ database};
+ mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfosForSourceIdStatement{
+ "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE "
+ "directorySourceId=?1",
+ database};
+ mutable Sqlite::ReadStatement<4, 2> selectDirectoryInfosForSourceIdAndFileTypeStatement{
+ "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE "
+ "directorySourceId=?1 AND fileType=?2",
+ database};
+ mutable Sqlite::ReadStatement<1, 2> selectDirectoryInfosSourceIdsForSourceIdAndFileTypeStatement{
+ "SELECT sourceId FROM directoryInfos WHERE directorySourceId=?1 AND fileType=?2", database};
+ mutable Sqlite::ReadStatement<4, 1> selectDirectoryInfoForSourceIdStatement{
+ "SELECT directorySourceId, sourceId, moduleId, fileType FROM directoryInfos WHERE "
+ "sourceId=?1 LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{
+ "SELECT typeId FROM types WHERE sourceId IN carray(?1)", database};
+ mutable Sqlite::ReadStatement<6, 1> selectModuleExportedImportsForSourceIdStatement{
+ "SELECT moduleExportedImportId, moduleId, exportedModuleId, ifnull(majorVersion, -1), "
+ "ifnull(minorVersion, -1), isAutoVersion FROM moduleExportedImports WHERE moduleId IN "
+ "carray(?1) ORDER BY moduleId, exportedModuleId",
+ database};
+ Sqlite::WriteStatement<3> insertModuleExportedImportWithoutVersionStatement{
+ "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion) "
+ "VALUES (?1, ?2, ?3)",
+ database};
+ Sqlite::WriteStatement<4> insertModuleExportedImportWithMajorVersionStatement{
+ "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
+ "majorVersion) VALUES (?1, ?2, ?3, ?4)",
+ database};
+ Sqlite::WriteStatement<5> insertModuleExportedImportWithVersionStatement{
+ "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
+ "majorVersion, minorVersion) VALUES (?1, ?2, ?3, ?4, ?5)",
+ database};
+ Sqlite::WriteStatement<1> deleteModuleExportedImportStatement{
+ "DELETE FROM moduleExportedImports WHERE moduleExportedImportId=?1", database};
+ mutable Sqlite::ReadStatement<3, 3> selectModuleExportedImportsForModuleIdStatement{
+ "WITH RECURSIVE "
+ " imports(moduleId, majorVersion, minorVersion, moduleExportedImportId) AS ( "
+ " SELECT exportedModuleId, "
+ " iif(isAutoVersion=1, ?2, majorVersion), "
+ " iif(isAutoVersion=1, ?3, minorVersion), "
+ " moduleExportedImportId "
+ " FROM moduleExportedImports WHERE moduleId=?1 "
+ " UNION ALL "
+ " SELECT exportedModuleId, "
+ " iif(mei.isAutoVersion=1, i.majorVersion, mei.majorVersion), "
+ " iif(mei.isAutoVersion=1, i.minorVersion, mei.minorVersion), "
+ " mei.moduleExportedImportId "
+ " FROM moduleExportedImports AS mei JOIN imports AS i USING(moduleId)) "
+ "SELECT DISTINCT moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) "
+ "FROM imports",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectLocalPropertyDeclarationIdsForTypeStatement{
+ "SELECT propertyDeclarationId "
+ "FROM propertyDeclarations "
+ "WHERE typeId=? "
+ "ORDER BY propertyDeclarationId",
+ database};
+ mutable Sqlite::ReadStatement<1, 2> selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement{
+ "SELECT propertyDeclarationId "
+ "FROM propertyDeclarations "
+ "WHERE typeId=?1 AND name=?2 LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<4, 1> selectPropertyDeclarationForPropertyDeclarationIdStatement{
+ "SELECT typeId, name, propertyTraits, propertyTypeId "
+ "FROM propertyDeclarations "
+ "WHERE propertyDeclarationId=?1 LIMIT 1",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectSignalDeclarationNamesForTypeStatement{
+ "WITH RECURSIVE "
+ " all_prototype_and_extension(typeId, prototypeId) AS ("
+ " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
+ " UNION ALL "
+ " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
+ " typeChain(typeId) AS ("
+ " VALUES(?1)"
+ " UNION ALL "
+ " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain "
+ " USING(typeId)) "
+ "SELECT name FROM typeChain JOIN signalDeclarations "
+ " USING(typeId) ORDER BY name",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectFuncionDeclarationNamesForTypeStatement{
+ "WITH RECURSIVE "
+ " all_prototype_and_extension(typeId, prototypeId) AS ("
+ " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
+ " UNION ALL "
+ " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
+ " typeChain(typeId) AS ("
+ " VALUES(?1)"
+ " UNION ALL "
+ " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain "
+ " USING(typeId))"
+ "SELECT name FROM typeChain JOIN functionDeclarations "
+ " USING(typeId) ORDER BY name",
+ database};
+ mutable Sqlite::ReadStatement<2> selectTypesWithDefaultPropertyStatement{
+ "SELECT typeId, defaultPropertyId FROM types ORDER BY typeId", database};
+ Sqlite::WriteStatement<2> updateDefaultPropertyIdStatement{
+ "UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database};
+ Sqlite::WriteStatement<1> updateDefaultPropertyIdToNullStatement{
+ "UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database};
+ mutable Sqlite::ReadStatement<3, 1> selectInfoTypeByTypeIdStatement{
+ "SELECT sourceId, traits, annotationTraits FROM types WHERE typeId=?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectSourceIdByTypeIdStatement{
+ "SELECT sourceId FROM types WHERE typeId=?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectPrototypeAnnotationTraitsByTypeIdStatement{
+ "SELECT annotationTraits "
+ "FROM types "
+ "WHERE typeId=(SELECT prototypeId FROM types WHERE typeId=?)",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectDefaultPropertyDeclarationIdStatement{
+ "SELECT defaultPropertyId FROM types WHERE typeId=?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{
+ "WITH RECURSIVE "
+ " all_prototype_and_extension(typeId, prototypeId) AS ("
+ " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
+ " UNION ALL "
+ " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
+ " prototypes(typeId, level) AS ("
+ " SELECT prototypeId, 0 FROM all_prototype_and_extension WHERE typeId=?"
+ " UNION ALL "
+ " SELECT prototypeId, p.level+1 FROM all_prototype_and_extension JOIN "
+ " prototypes AS p USING(typeId)) "
+ "SELECT typeId FROM prototypes ORDER BY level",
+ database};
+ Sqlite::WriteStatement<2> upsertPropertyEditorPathIdStatement{
+ "INSERT INTO propertyEditorPaths(typeId, pathSourceId) VALUES(?1, ?2) ON CONFLICT DO "
+ "UPDATE SET pathSourceId=excluded.pathSourceId WHERE pathSourceId IS NOT "
+ "excluded.pathSourceId",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectPropertyEditorPathIdStatement{
+ "SELECT pathSourceId FROM propertyEditorPaths WHERE typeId=?", database};
+ mutable Sqlite::ReadStatement<3, 1> selectPropertyEditorPathsForForSourceIdsStatement{
+ "SELECT typeId, pathSourceId, directoryId "
+ "FROM propertyEditorPaths "
+ "WHERE directoryId IN carray(?1) "
+ "ORDER BY typeId",
+ database};
+ Sqlite::WriteStatement<3> insertPropertyEditorPathStatement{
+ "INSERT INTO propertyEditorPaths(typeId, pathSourceId, directoryId) VALUES (?1, ?2, ?3)",
+ database};
+ Sqlite::WriteStatement<3> updatePropertyEditorPathsStatement{
+ "UPDATE propertyEditorPaths "
+ "SET pathSourceId=?2, directoryId=?3 "
+ "WHERE typeId=?1",
+ database};
+ Sqlite::WriteStatement<1> deletePropertyEditorPathStatement{
+ "DELETE FROM propertyEditorPaths WHERE typeId=?1", database};
+ mutable Sqlite::ReadStatement<5, 1> selectTypeAnnotationsForSourceIdsStatement{
+ "SELECT typeId, typeName, iconPath, itemLibrary, hints FROM typeAnnotations WHERE "
+ "sourceId IN carray(?1) ORDER BY typeId",
+ database};
+ Sqlite::WriteStatement<7> insertTypeAnnotationStatement{
+ "INSERT INTO "
+ " typeAnnotations(typeId, sourceId, directorySourceId, typeName, iconPath, itemLibrary, "
+ " hints) "
+ "VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)",
+ database};
+ Sqlite::WriteStatement<5> updateTypeAnnotationStatement{
+ "UPDATE typeAnnotations "
+ "SET typeName=?2, iconPath=?3, itemLibrary=?4, hints=?5 "
+ "WHERE typeId=?1",
+ database};
+ Sqlite::WriteStatement<1> deleteTypeAnnotationStatement{
+ "DELETE FROM typeAnnotations WHERE typeId=?1", database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIconPathStatement{
+ "SELECT iconPath FROM typeAnnotations WHERE typeId=?1", database};
+ mutable Sqlite::ReadStatement<2, 1> selectTypeHintsStatement{
+ "SELECT hints.key, hints.value "
+ "FROM typeAnnotations, json_each(typeAnnotations.hints) AS hints "
+ "WHERE typeId=?1 AND hints IS NOT NULL",
+ database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeAnnotationSourceIdsStatement{
+ "SELECT sourceId FROM typeAnnotations WHERE directorySourceId=?1 ORDER BY sourceId", database};
+ mutable Sqlite::ReadStatement<1, 0> selectTypeAnnotationDirectorySourceIdsStatement{
+ "SELECT DISTINCT directorySourceId FROM typeAnnotations ORDER BY directorySourceId", database};
+ mutable Sqlite::ReadStatement<10> selectItemLibraryEntriesStatement{
+ "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', "
+ " i.value->>'$.category', i.value->>'$.import', i.value->>'$.toolTip', "
+ " i.value->>'$.properties', i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
+ "FROM typeAnnotations AS ta , json_each(ta.itemLibrary) AS i "
+ "WHERE ta.itemLibrary IS NOT NULL",
+ database};
+ mutable Sqlite::ReadStatement<10, 1> selectItemLibraryEntriesByTypeIdStatement{
+ "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', "
+ " i.value->>'$.category', i.value->>'$.import', i.value->>'$.toolTip', "
+ " i.value->>'$.properties', i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
+ "FROM typeAnnotations AS ta, json_each(ta.itemLibrary) AS i "
+ "WHERE typeId=?1 AND ta.itemLibrary IS NOT NULL",
+ database};
+ mutable Sqlite::ReadStatement<10, 1> selectItemLibraryEntriesBySourceIdStatement{
+ "SELECT typeId, typeName, i.value->>'$.name', i.value->>'$.iconPath', "
+ "i.value->>'$.category', "
+ " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', "
+ " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
+ "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i "
+ "WHERE typeId IN (SELECT DISTINCT typeId "
+ " FROM documentImports AS di JOIN exportedTypeNames "
+ " USING(moduleId) "
+ " WHERE di.sourceId=?)",
+ database};
+ mutable Sqlite::ReadStatement<3, 1> selectItemLibraryPropertiesStatement{
+ "SELECT p.value->>0, p.value->>1, p.value->>2 FROM json_each(?1) AS p", database};
+ mutable Sqlite::ReadStatement<1, 1> selectItemLibraryExtraFilePathsStatement{
+ "SELECT p.value FROM json_each(?1) AS p", database};
+ mutable Sqlite::ReadStatement<1, 1> selectTypeIdsByModuleIdStatement{
+ "SELECT DISTINCT typeId FROM exportedTypeNames WHERE moduleId=?", database};
+ mutable Sqlite::ReadStatement<1, 1> selectHeirTypeIdsStatement{
+ "WITH RECURSIVE "
+ " typeSelection(typeId) AS ("
+ " SELECT typeId FROM types WHERE prototypeId=?1 OR extensionId=?1"
+ " UNION ALL "
+ " SELECT t.typeId "
+ " FROM types AS t JOIN typeSelection AS ts "
+ " WHERE prototypeId=ts.typeId OR extensionId=ts.typeId)"
+ "SELECT typeId FROM typeSelection",
+ database};
+};
+
+class ProjectStorage::Initializer
+{
+public:
+ Initializer(Database &database, bool isInitialized)
+ {
+ if (!isInitialized) {
+ auto moduleIdColumn = createModulesTable(database);
+ createSourceContextsTable(database);
+ createSourcesTable(database);
+ createTypesAndePropertyDeclarationsTables(database, moduleIdColumn);
+ createExportedTypeNamesTable(database, moduleIdColumn);
+ createImportedTypeNamesTable(database);
+ createEnumerationsTable(database);
+ createFunctionsTable(database);
+ createSignalsTable(database);
+ createModuleExportedImportsTable(database, moduleIdColumn);
+ createDocumentImportsTable(database, moduleIdColumn);
+ createFileStatusesTable(database);
+ createDirectoryInfosTable(database);
+ createPropertyEditorPathsTable(database);
+ createTypeAnnotionsTable(database);
+ }
+ database.setIsInitialized(true);
+ }
+
+ void createSourceContextsTable(Database &database)
+ {
+ Sqlite::Table table;
+ table.setUseIfNotExists(true);
+ table.setName("sourceContexts");
+ table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
+ const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath");
+
+ table.addUniqueIndex({sourceContextPathColumn});
+
+ table.initialize(database);
+ }
+
+ void createSourcesTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("sources");
+ table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
+ const auto &sourceContextIdColumn = table.addColumn(
+ "sourceContextId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::NotNull{},
+ Sqlite::ForeignKey{"sourceContexts",
+ "sourceContextId",
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Cascade}});
+ const auto &sourceNameColumn = table.addColumn("sourceName", Sqlite::StrictColumnType::Text);
+ table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn});
+
+ table.initialize(database);
+ }
+
+ void createTypesAndePropertyDeclarationsTables(
+ Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn)
+ {
+ Sqlite::StrictTable typesTable;
+ typesTable.setUseIfNotExists(true);
+ typesTable.setName("types");
+ typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
+ auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
+ auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text);
+ typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer);
+ auto &prototypeIdColumn = typesTable.addColumn("prototypeId",
+ Sqlite::StrictColumnType::Integer);
+ auto &prototypeNameIdColumn = typesTable.addColumn("prototypeNameId",
+ Sqlite::StrictColumnType::Integer);
+ auto &extensionIdColumn = typesTable.addColumn("extensionId",
+ Sqlite::StrictColumnType::Integer);
+ auto &extensionNameIdColumn = typesTable.addColumn("extensionNameId",
+ Sqlite::StrictColumnType::Integer);
+ auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId",
+ Sqlite::StrictColumnType::Integer);
+ typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer);
+ typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn});
+ typesTable.addIndex({defaultPropertyIdColumn});
+ typesTable.addIndex({prototypeIdColumn, sourceIdColumn});
+ typesTable.addIndex({extensionIdColumn, sourceIdColumn});
+ typesTable.addIndex({prototypeNameIdColumn});
+ typesTable.addIndex({extensionNameIdColumn});
+
+ typesTable.initialize(database);
+
+ {
+ Sqlite::StrictTable propertyDeclarationTable;
+ propertyDeclarationTable.setUseIfNotExists(true);
+ propertyDeclarationTable.setName("propertyDeclarations");
+ propertyDeclarationTable.addColumn("propertyDeclarationId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId");
+ auto &nameColumn = propertyDeclarationTable.addColumn("name");
+ auto &propertyTypeIdColumn = propertyDeclarationTable.addForeignKeyColumn(
+ "propertyTypeId",
+ typesTable,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Restrict);
+ propertyDeclarationTable.addColumn("propertyTraits", Sqlite::StrictColumnType::Integer);
+ propertyDeclarationTable.addColumn("propertyImportedTypeNameId",
+ Sqlite::StrictColumnType::Integer);
+ auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn(
+ "aliasPropertyDeclarationId",
+ propertyDeclarationTable,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Restrict);
+ auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
+ "aliasPropertyDeclarationTailId",
+ propertyDeclarationTable,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Restrict);
+
+ propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
+ propertyDeclarationTable.addIndex({propertyTypeIdColumn});
+ propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
+ "aliasPropertyDeclarationId IS NOT NULL");
+ propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
+ "aliasPropertyDeclarationTailId IS NOT NULL");
+
+ propertyDeclarationTable.initialize(database);
+ }
+ }
+
+ void createExportedTypeNamesTable(Database &database,
+ const Sqlite::StrictColumn &foreignModuleIdColumn)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("exportedTypeNames");
+ table.addColumn("exportedTypeNameId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
+ foreignModuleIdColumn,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::NoAction);
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+ auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
+ auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer);
+ auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer);
+
+ table.addUniqueIndex({moduleIdColumn, nameColumn},
+ "majorVersion IS NULL AND minorVersion IS NULL");
+ table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn},
+ "majorVersion IS NOT NULL AND minorVersion IS NULL");
+ table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn},
+ "majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
+
+ table.addIndex({typeIdColumn});
+ table.addIndex({moduleIdColumn, nameColumn});
+
+ table.initialize(database);
+ }
+
+ void createImportedTypeNamesTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("importedTypeNames");
+ table.addColumn("importedTypeNameId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &importOrSourceIdColumn = table.addColumn("importOrSourceId");
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+ auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer);
+
+ table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn});
+ table.addIndex({nameColumn});
+
+ table.initialize(database);
+ }
+
+ void createEnumerationsTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("enumerationDeclarations");
+ table.addColumn("enumerationDeclarationId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+ table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text);
+
+ table.addUniqueIndex({typeIdColumn, nameColumn});
+
+ table.initialize(database);
+ }
+
+ void createFunctionsTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("functionDeclarations");
+ table.addColumn("functionDeclarationId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+ auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text);
+ table.addColumn("returnTypeName");
+
+ table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
+
+ table.initialize(database);
+ }
+
+ void createSignalsTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("signalDeclarations");
+ table.addColumn("signalDeclarationId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+ auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text);
+
+ table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
+
+ table.initialize(database);
+ }
+
+ Sqlite::StrictColumn createModulesTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("modules");
+ auto &modelIdColumn = table.addColumn("moduleId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer);
+ auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
+
+ table.addUniqueIndex({kindColumn, nameColumn});
- return projectStorageCategory_;
+ table.initialize(database);
+
+ return std::move(modelIdColumn);
+ }
+
+ void createModuleExportedImportsTable(Database &database,
+ const Sqlite::StrictColumn &foreignModuleIdColumn)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("moduleExportedImports");
+ table.addColumn("moduleExportedImportId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
+ foreignModuleIdColumn,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Cascade,
+ Sqlite::Enforment::Immediate);
+ auto &sourceIdColumn = table.addColumn("exportedModuleId", Sqlite::StrictColumnType::Integer);
+ table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer);
+ table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer);
+ table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer);
+
+ table.addUniqueIndex({sourceIdColumn, moduleIdColumn});
+
+ table.initialize(database);
+ }
+
+ void createDocumentImportsTable(Database &database,
+ const Sqlite::StrictColumn &foreignModuleIdColumn)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("documentImports");
+ table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
+ auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
+ auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
+ foreignModuleIdColumn,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Cascade,
+ Sqlite::Enforment::Immediate);
+ auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId",
+ foreignModuleIdColumn,
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Cascade,
+ Sqlite::Enforment::Immediate);
+ auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer);
+ auto &majorVersionColumn = table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer);
+ auto &minorVersionColumn = table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer);
+ auto &parentImportIdColumn = table.addColumn("parentImportId",
+ Sqlite::StrictColumnType::Integer);
+
+ table.addUniqueIndex(
+ {sourceIdColumn, moduleIdColumn, kindColumn, sourceModuleIdColumn, parentImportIdColumn},
+ "majorVersion IS NULL AND minorVersion IS NULL");
+ table.addUniqueIndex({sourceIdColumn,
+ moduleIdColumn,
+ kindColumn,
+ sourceModuleIdColumn,
+ majorVersionColumn,
+ parentImportIdColumn},
+ "majorVersion IS NOT NULL AND minorVersion IS NULL");
+ table.addUniqueIndex({sourceIdColumn,
+ moduleIdColumn,
+ kindColumn,
+ sourceModuleIdColumn,
+ majorVersionColumn,
+ minorVersionColumn,
+ parentImportIdColumn},
+ "majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
+
+ table.addIndex({sourceIdColumn, kindColumn});
+
+ table.initialize(database);
+ }
+
+ void createFileStatusesTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setName("fileStatuses");
+ table.addColumn("sourceId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{},
+ Sqlite::ForeignKey{"sources",
+ "sourceId",
+ Sqlite::ForeignKeyAction::NoAction,
+ Sqlite::ForeignKeyAction::Cascade}});
+ table.addColumn("size", Sqlite::StrictColumnType::Integer);
+ table.addColumn("lastModified", Sqlite::StrictColumnType::Integer);
+
+ table.initialize(database);
+ }
+
+ void createDirectoryInfosTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setUseWithoutRowId(true);
+ table.setName("directoryInfos");
+ auto &directorySourceIdColumn = table.addColumn("directorySourceId",
+ Sqlite::StrictColumnType::Integer);
+ auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
+ table.addColumn("moduleId", Sqlite::StrictColumnType::Integer);
+ auto &fileTypeColumn = table.addColumn("fileType", Sqlite::StrictColumnType::Integer);
+
+ table.addPrimaryKeyContraint({directorySourceIdColumn, sourceIdColumn});
+ table.addUniqueIndex({sourceIdColumn});
+ table.addIndex({directorySourceIdColumn, fileTypeColumn});
+
+ table.initialize(database);
+ }
+
+ void createPropertyEditorPathsTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setUseWithoutRowId(true);
+ table.setName("propertyEditorPaths");
+ table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
+ table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer);
+ auto &directoryIdColumn = table.addColumn("directoryId", Sqlite::StrictColumnType::Integer);
+
+ table.addIndex({directoryIdColumn});
+
+ table.initialize(database);
+ }
+
+ void createTypeAnnotionsTable(Database &database)
+ {
+ Sqlite::StrictTable table;
+ table.setUseIfNotExists(true);
+ table.setUseWithoutRowId(true);
+ table.setName("typeAnnotations");
+ auto &typeIdColumn = table.addColumn("typeId",
+ Sqlite::StrictColumnType::Integer,
+ {Sqlite::PrimaryKey{}});
+ auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
+ auto &directorySourceIdColumn = table.addColumn("directorySourceId",
+ Sqlite::StrictColumnType::Integer);
+ table.addColumn("typeName", Sqlite::StrictColumnType::Text);
+ table.addColumn("iconPath", Sqlite::StrictColumnType::Text);
+ table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text);
+ table.addColumn("hints", Sqlite::StrictColumnType::Text);
+
+ table.addUniqueIndex({sourceIdColumn, typeIdColumn});
+ table.addIndex({directorySourceIdColumn});
+
+ table.initialize(database);
+ }
+};
+
+ProjectStorage::ProjectStorage(Database &database,
+ ProjectStorageErrorNotifierInterface &errorNotifier,
+ bool isInitialized)
+ : database{database}
+ , errorNotifier{&errorNotifier}
+ , exclusiveTransaction{database}
+ , initializer{std::make_unique<ProjectStorage::Initializer>(database, isInitialized)}
+ , moduleCache{ModuleStorageAdapter{*this}}
+ , s{std::make_unique<ProjectStorage::Statements>(database)}
+{
+ NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()};
+
+ exclusiveTransaction.commit();
+
+ database.walCheckpointFull();
+
+ moduleCache.populate();
}
-} // namespace QmlDesigner
+ProjectStorage::~ProjectStorage() = default;
+
+void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackage package)
+{
+ NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()};
+
+ TypeIds deletedTypeIds;
+ Sqlite::withImmediateTransaction(database, [&] {
+ AliasPropertyDeclarations insertedAliasPropertyDeclarations;
+ AliasPropertyDeclarations updatedAliasPropertyDeclarations;
+
+ AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
+ PropertyDeclarations relinkablePropertyDeclarations;
+ Prototypes relinkablePrototypes;
+ Prototypes relinkableExtensions;
+
+ 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,
+ relinkablePrototypes,
+ relinkableExtensions);
+ synchronizeTypes(package.types,
+ updatedTypeIds,
+ insertedAliasPropertyDeclarations,
+ updatedAliasPropertyDeclarations,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ package.updatedSourceIds);
+ synchronizeTypeAnnotations(package.typeAnnotations, package.updatedTypeAnnotationSourceIds);
+ synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths,
+ package.updatedPropertyEditorQmlPathSourceIds);
+
+ deleteNotUpdatedTypes(updatedTypeIds,
+ package.updatedSourceIds,
+ typeIdsToBeDeleted,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ deletedTypeIds);
+
+ relink(relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ deletedTypeIds);
+
+ linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
+
+ synchronizeDirectoryInfos(package.directoryInfos, package.updatedDirectoryInfoSourceIds);
+
+ commonTypeCache_.resetTypeIds();
+ });
+
+ callRefreshMetaInfoCallback(deletedTypeIds);
+}
+
+void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"synchronize document imports"_t,
+ projectStorageCategory(),
+ keyValue("imports", imports),
+ keyValue("source id", sourceId)};
+
+ Sqlite::withImmediateTransaction(database, [&] {
+ AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
+ PropertyDeclarations relinkablePropertyDeclarations;
+ Prototypes relinkablePrototypes;
+ Prototypes relinkableExtensions;
+ TypeIds deletedTypeIds;
+
+ synchronizeDocumentImports(imports,
+ {sourceId},
+ Storage::Synchronization::ImportKind::Import,
+ Relink::Yes,
+ relinkablePrototypes,
+ relinkableExtensions);
+
+ relink(relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ deletedTypeIds);
+ });
+}
+
+void ProjectStorage::addObserver(ProjectStorageObserver *observer)
+{
+ NanotraceHR::Tracer tracer{"add observer"_t, projectStorageCategory()};
+ observers.push_back(observer);
+}
+
+void ProjectStorage::removeObserver(ProjectStorageObserver *observer)
+{
+ NanotraceHR::Tracer tracer{"remove observer"_t, projectStorageCategory()};
+ observers.removeOne(observer);
+}
+
+ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName, Storage::ModuleKind kind) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get module id"_t,
+ projectStorageCategory(),
+ keyValue("module name", moduleName)};
+
+ auto moduleId = moduleCache.id({moduleName, kind});
+
+ tracer.end(keyValue("module id", moduleId));
+
+ return moduleId;
+}
+
+Storage::Module ProjectStorage::module(ModuleId moduleId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get module name"_t,
+ projectStorageCategory(),
+ keyValue("module id", moduleId)};
+
+ if (!moduleId)
+ throw ModuleDoesNotExists{};
+
+ auto module = moduleCache.value(moduleId);
+
+ tracer.end(keyValue("module name", module.name));
+ tracer.end(keyValue("module kind", module.kind));
+
+ return {module.name, module.kind};
+}
+
+TypeId ProjectStorage::typeId(ModuleId moduleId,
+ Utils::SmallStringView exportedTypeName,
+ Storage::Version version) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type id by exported name"_t,
+ projectStorageCategory(),
+ keyValue("module id", moduleId),
+ keyValue("exported type name", exportedTypeName),
+ keyValue("version", version)};
+
+ TypeId typeId;
+
+ if (version.minor) {
+ typeId = s->selectTypeIdByModuleIdAndExportedNameAndVersionStatement.valueWithTransaction<TypeId>(
+ moduleId, exportedTypeName, version.major.value, version.minor.value);
+
+ } else if (version.major) {
+ typeId = s->selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement
+ .valueWithTransaction<TypeId>(moduleId, exportedTypeName, version.major.value);
+
+ } else {
+ typeId = s->selectTypeIdByModuleIdAndExportedNameStatement
+ .valueWithTransaction<TypeId>(moduleId, exportedTypeName);
+ }
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+TypeId ProjectStorage::typeId(ImportedTypeNameId typeNameId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type id by imported type name"_t,
+ projectStorageCategory(),
+ keyValue("imported type name id", typeNameId)};
+
+ auto typeId = Sqlite::withDeferredTransaction(database, [&] { return fetchTypeId(typeNameId); });
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+QVarLengthArray<TypeId, 256> ProjectStorage::typeIds(ModuleId moduleId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type ids by module id"_t,
+ projectStorageCategory(),
+ keyValue("module id", moduleId)};
+
+ auto typeIds = s->selectTypeIdsByModuleIdStatement
+ .valuesWithTransaction<QVarLengthArray<TypeId, 256>>(moduleId);
+
+ tracer.end(keyValue("type ids", typeIds));
+
+ return typeIds;
+}
+
+Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get exported type names by type id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto exportedTypenames = s->selectExportedTypesByTypeIdStatement
+ .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId);
+
+ tracer.end(keyValue("exported type names", exportedTypenames));
+
+ return exportedTypenames;
+}
+
+Storage::Info::ExportedTypeNames ProjectStorage::exportedTypeNames(TypeId typeId, SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get exported type names by source id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("source id", sourceId)};
+
+ auto exportedTypenames = s->selectExportedTypesByTypeIdAndSourceIdStatement
+ .valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId,
+ sourceId);
+
+ tracer.end(keyValue("exported type names", exportedTypenames));
+
+ return exportedTypenames;
+}
+
+ImportId ProjectStorage::importId(const Storage::Import &import) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get import id by import"_t,
+ projectStorageCategory(),
+ keyValue("import", import)};
+
+ auto importId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchImportId(import.sourceId, import);
+ });
+
+ tracer.end(keyValue("import id", importId));
+
+ return importId;
+}
+
+ImportedTypeNameId ProjectStorage::importedTypeNameId(ImportId importId,
+ Utils::SmallStringView typeName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get imported type name id by import id"_t,
+ projectStorageCategory(),
+ keyValue("import id", importId),
+ keyValue("imported type name", typeName)};
+
+ auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported,
+ importId,
+ typeName);
+ });
+
+ tracer.end(keyValue("imported type name id", importedTypeNameId));
+
+ return importedTypeNameId;
+}
+
+ImportedTypeNameId ProjectStorage::importedTypeNameId(SourceId sourceId,
+ Utils::SmallStringView typeName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get imported type name id by source id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId),
+ keyValue("imported type name", typeName)};
+
+ auto importedTypeNameId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported,
+ sourceId,
+ typeName);
+ });
+
+ tracer.end(keyValue("imported type name id", importedTypeNameId));
+
+ return importedTypeNameId;
+}
+
+QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::propertyDeclarationIds(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property declaration ids"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto propertyDeclarationIds = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchPropertyDeclarationIds(typeId);
+ });
+
+ std::sort(propertyDeclarationIds.begin(), propertyDeclarationIds.end());
+
+ tracer.end(keyValue("property declaration ids", propertyDeclarationIds));
+
+ return propertyDeclarationIds;
+}
+
+QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::localPropertyDeclarationIds(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get local property declaration ids"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto propertyDeclarationIds = s->selectLocalPropertyDeclarationIdsForTypeStatement
+ .valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>(
+ typeId);
+
+ tracer.end(keyValue("property declaration ids", propertyDeclarationIds));
+
+ return propertyDeclarationIds;
+}
+
+PropertyDeclarationId ProjectStorage::propertyDeclarationId(TypeId typeId,
+ Utils::SmallStringView propertyName) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property declaration id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("property name", propertyName)};
+
+ auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchPropertyDeclarationId(typeId, propertyName);
+ });
+
+ tracer.end(keyValue("property declaration id", propertyDeclarationId));
+
+ return propertyDeclarationId;
+}
+
+PropertyDeclarationId ProjectStorage::localPropertyDeclarationId(TypeId typeId,
+ Utils::SmallStringView propertyName) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get local property declaration id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("property name", propertyName)};
+
+ auto propertyDeclarationId = s->selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement
+ .valueWithTransaction<PropertyDeclarationId>(typeId,
+ propertyName);
+
+ tracer.end(keyValue("property declaration id", propertyDeclarationId));
+
+ return propertyDeclarationId;
+}
+
+PropertyDeclarationId ProjectStorage::defaultPropertyDeclarationId(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get default property declaration id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchDefaultPropertyDeclarationId(typeId);
+ });
+
+ tracer.end(keyValue("property declaration id", propertyDeclarationId));
+
+ return propertyDeclarationId;
+}
+
+std::optional<Storage::Info::PropertyDeclaration> ProjectStorage::propertyDeclaration(
+ PropertyDeclarationId propertyDeclarationId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property declaration"_t,
+ projectStorageCategory(),
+ keyValue("property declaration id", propertyDeclarationId)};
+
+ auto propertyDeclaration = s->selectPropertyDeclarationForPropertyDeclarationIdStatement
+ .optionalValueWithTransaction<Storage::Info::PropertyDeclaration>(
+ propertyDeclarationId);
+
+ tracer.end(keyValue("property declaration", propertyDeclaration));
+
+ return propertyDeclaration;
+}
+
+std::optional<Storage::Info::Type> ProjectStorage::type(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory(), keyValue("type id", typeId)};
+
+ auto type = s->selectInfoTypeByTypeIdStatement.optionalValueWithTransaction<Storage::Info::Type>(
+ typeId);
+
+ tracer.end(keyValue("type", type));
+
+ return type;
+}
+
+Utils::PathString ProjectStorage::typeIconPath(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type icon path"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto typeIconPath = s->selectTypeIconPathStatement.valueWithTransaction<Utils::PathString>(typeId);
+
+ tracer.end(keyValue("type icon path", typeIconPath));
+
+ return typeIconPath;
+}
+
+Storage::Info::TypeHints ProjectStorage::typeHints(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type hints"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto typeHints = s->selectTypeHintsStatement.valuesWithTransaction<Storage::Info::TypeHints, 4>(
+ typeId);
+
+ tracer.end(keyValue("type hints", typeHints));
+
+ return typeHints;
+}
+
+SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(SourceId directoryId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type annotaion source ids"_t,
+ projectStorageCategory(),
+ keyValue("source id", directoryId)};
+
+ auto sourceIds = s->selectTypeAnnotationSourceIdsStatement.valuesWithTransaction<SmallSourceIds<4>>(
+ directoryId);
+
+ tracer.end(keyValue("source ids", sourceIds));
+
+ return sourceIds;
+}
+
+SmallSourceIds<64> ProjectStorage::typeAnnotationDirectorySourceIds() const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type annotaion source ids"_t, projectStorageCategory()};
+
+ auto sourceIds = s->selectTypeAnnotationDirectorySourceIdsStatement
+ .valuesWithTransaction<SmallSourceIds<64>>();
+
+ tracer.end(keyValue("source ids", sourceIds));
+
+ return sourceIds;
+}
+
+Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get item library entries by type id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ using Storage::Info::ItemLibraryProperties;
+ Storage::Info::ItemLibraryEntries entries;
+
+ auto callback = [&](TypeId typeId_,
+ Utils::SmallStringView typeName,
+ Utils::SmallStringView name,
+ Utils::SmallStringView iconPath,
+ Utils::SmallStringView category,
+ Utils::SmallStringView import,
+ Utils::SmallStringView toolTip,
+ Utils::SmallStringView properties,
+ Utils::SmallStringView extraFilePaths,
+ Utils::SmallStringView templatePath) {
+ auto &last = entries.emplace_back(
+ typeId_, typeName, name, iconPath, category, import, toolTip, templatePath);
+ if (properties.size())
+ s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
+ if (extraFilePaths.size())
+ s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
+ };
+
+ s->selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId);
+
+ tracer.end(keyValue("item library entries", entries));
+
+ return entries;
+}
+
+Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(ImportId importId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get item library entries by import id"_t,
+ projectStorageCategory(),
+ keyValue("import id", importId)};
+
+ using Storage::Info::ItemLibraryProperties;
+ Storage::Info::ItemLibraryEntries entries;
+
+ auto callback = [&](TypeId typeId_,
+ Utils::SmallStringView typeName,
+ Utils::SmallStringView name,
+ Utils::SmallStringView iconPath,
+ Utils::SmallStringView category,
+ Utils::SmallStringView import,
+ Utils::SmallStringView toolTip,
+ Utils::SmallStringView properties,
+ Utils::SmallStringView extraFilePaths,
+ Utils::SmallStringView templatePath) {
+ auto &last = entries.emplace_back(
+ typeId_, typeName, name, iconPath, category, import, toolTip, templatePath);
+ if (properties.size())
+ s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
+ if (extraFilePaths.size())
+ s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
+ };
+
+ s->selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, importId);
+
+ tracer.end(keyValue("item library entries", entries));
+
+ return entries;
+}
+
+Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get item library entries by source id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId)};
+
+ using Storage::Info::ItemLibraryProperties;
+ Storage::Info::ItemLibraryEntries entries;
+
+ auto callback = [&](TypeId typeId,
+ Utils::SmallStringView typeName,
+ Utils::SmallStringView name,
+ Utils::SmallStringView iconPath,
+ Utils::SmallStringView category,
+ Utils::SmallStringView import,
+ Utils::SmallStringView toolTip,
+ Utils::SmallStringView properties,
+ Utils::SmallStringView extraFilePaths,
+ Utils::SmallStringView templatePath) {
+ auto &last = entries.emplace_back(
+ typeId, typeName, name, iconPath, category, import, toolTip, templatePath);
+ if (properties.size())
+ s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
+ if (extraFilePaths.size())
+ s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
+ };
+
+ s->selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId);
+
+ tracer.end(keyValue("item library entries", entries));
+
+ return entries;
+}
+
+Storage::Info::ItemLibraryEntries ProjectStorage::allItemLibraryEntries() const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()};
+
+ using Storage::Info::ItemLibraryProperties;
+ Storage::Info::ItemLibraryEntries entries;
+
+ auto callback = [&](TypeId typeId,
+ Utils::SmallStringView typeName,
+ Utils::SmallStringView name,
+ Utils::SmallStringView iconPath,
+ Utils::SmallStringView category,
+ Utils::SmallStringView import,
+ Utils::SmallStringView toolTip,
+ Utils::SmallStringView properties,
+ Utils::SmallStringView extraFilePaths,
+ Utils::SmallStringView templatePath) {
+ auto &last = entries.emplace_back(
+ typeId, typeName, name, iconPath, category, import, toolTip, templatePath);
+ if (properties.size())
+ s->selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
+ if (extraFilePaths.size())
+ s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
+ };
+
+ s->selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback);
+
+ tracer.end(keyValue("item library entries", entries));
+
+ return entries;
+}
+
+std::vector<Utils::SmallString> ProjectStorage::signalDeclarationNames(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get signal names"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto signalDeclarationNames = s->selectSignalDeclarationNamesForTypeStatement
+ .valuesWithTransaction<Utils::SmallString, 32>(typeId);
+
+ tracer.end(keyValue("signal names", signalDeclarationNames));
+
+ return signalDeclarationNames;
+}
+
+std::vector<Utils::SmallString> ProjectStorage::functionDeclarationNames(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get function names"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto functionDeclarationNames = s->selectFuncionDeclarationNamesForTypeStatement
+ .valuesWithTransaction<Utils::SmallString, 32>(typeId);
+
+ tracer.end(keyValue("function names", functionDeclarationNames));
+
+ return functionDeclarationNames;
+}
+
+std::optional<Utils::SmallString> ProjectStorage::propertyName(
+ PropertyDeclarationId propertyDeclarationId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get property name"_t,
+ projectStorageCategory(),
+ keyValue("property declaration id", propertyDeclarationId)};
+
+ auto propertyName = s->selectPropertyNameStatement.optionalValueWithTransaction<Utils::SmallString>(
+ propertyDeclarationId);
+
+ tracer.end(keyValue("property name", propertyName));
+
+ return propertyName;
+}
+
+SmallTypeIds<16> ProjectStorage::prototypeIds(TypeId type) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get prototypes"_t, projectStorageCategory(), keyValue("type id", type)};
+
+ auto prototypeIds = s->selectPrototypeAndExtensionIdsStatement
+ .valuesWithTransaction<SmallTypeIds<16>>(type);
+
+ tracer.end(keyValue("type ids", prototypeIds));
+
+ return prototypeIds;
+}
+
+SmallTypeIds<16> ProjectStorage::prototypeAndSelfIds(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()};
+
+ SmallTypeIds<16> prototypeAndSelfIds;
+ prototypeAndSelfIds.push_back(typeId);
+
+ s->selectPrototypeAndExtensionIdsStatement.readToWithTransaction(prototypeAndSelfIds, typeId);
+
+ tracer.end(keyValue("type ids", prototypeAndSelfIds));
+
+ return prototypeAndSelfIds;
+}
+
+SmallTypeIds<64> ProjectStorage::heirIds(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()};
+
+ auto heirIds = s->selectHeirTypeIdsStatement.valuesWithTransaction<SmallTypeIds<64>>(typeId);
+
+ tracer.end(keyValue("type ids", heirIds));
+
+ return heirIds;
+}
+
+bool ProjectStorage::isBasedOn(TypeId) const
+{
+ return false;
+}
+
+bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1) const
+{
+ return isBasedOn_(typeId, id1);
+}
+
+bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const
+{
+ return isBasedOn_(typeId, id1, id2);
+}
+
+bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const
+{
+ return isBasedOn_(typeId, id1, id2, id3);
+}
+
+bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const
+{
+ return isBasedOn_(typeId, id1, id2, id3, id4);
+}
+
+bool ProjectStorage::isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const
+{
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5);
+}
+
+bool ProjectStorage::isBasedOn(
+ TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const
+{
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6);
+}
+
+bool ProjectStorage::isBasedOn(
+ TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6, TypeId id7) const
+{
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7);
+}
+
+TypeId ProjectStorage::fetchTypeIdByExportedName(Utils::SmallStringView name) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t,
+ projectStorageCategory(),
+ keyValue("exported type name", name)};
+
+ auto typeId = s->selectTypeIdByExportedNameStatement.valueWithTransaction<TypeId>(name);
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+TypeId ProjectStorage::fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds,
+ Utils::SmallStringView name) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type id by module ids and exported name"_t,
+ projectStorageCategory(),
+ keyValue("module ids", NanotraceHR::array(moduleIds)),
+ keyValue("exported type name", name)};
+ auto typeId = s->selectTypeIdByModuleIdsAndExportedNameStatement.valueWithTransaction<TypeId>(
+ static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name);
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+TypeId ProjectStorage::fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type id by name"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId),
+ keyValue("internal type name", name)};
+
+ auto typeId = s->selectTypeIdBySourceIdAndNameStatement.valueWithTransaction<TypeId>(sourceId,
+ name);
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+Storage::Synchronization::Type ProjectStorage::fetchTypeByTypeId(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type by type id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto type = Sqlite::withDeferredTransaction(database, [&] {
+ auto type = s->selectTypeByTypeIdStatement.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);
+
+ return type;
+ });
+
+ tracer.end(keyValue("type", type));
+
+ return type;
+}
+
+Storage::Synchronization::Types ProjectStorage::fetchTypes()
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch types"_t, projectStorageCategory()};
+
+ auto types = Sqlite::withDeferredTransaction(database, [&] {
+ auto types = s->selectTypesStatement.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);
+ }
+
+ return types;
+ });
+
+ tracer.end(keyValue("type", types));
+
+ return types;
+}
+
+SourceContextId ProjectStorage::fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()};
+
+ auto sourceContextId = readSourceContextId(sourceContextPath);
+
+ return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath);
+}
+
+SourceContextId ProjectStorage::fetchSourceContextId(Utils::SmallStringView sourceContextPath)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source context id"_t,
+ projectStorageCategory(),
+ keyValue("source context path", sourceContextPath)};
+
+ SourceContextId sourceContextId;
+ try {
+ sourceContextId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchSourceContextIdUnguarded(sourceContextPath);
+ });
+ } catch (const Sqlite::ConstraintPreventsModification &) {
+ sourceContextId = fetchSourceContextId(sourceContextPath);
+ }
+
+ tracer.end(keyValue("source context id", sourceContextId));
+
+ return sourceContextId;
+}
+
+Utils::PathString ProjectStorage::fetchSourceContextPath(SourceContextId sourceContextId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source context path"_t,
+ projectStorageCategory(),
+ keyValue("source context id", sourceContextId)};
+
+ auto path = Sqlite::withDeferredTransaction(database, [&] {
+ auto optionalSourceContextPath = s->selectSourceContextPathFromSourceContextsBySourceContextIdStatement
+ .optionalValue<Utils::PathString>(sourceContextId);
+
+ if (!optionalSourceContextPath)
+ throw SourceContextIdDoesNotExists();
+
+ return std::move(*optionalSourceContextPath);
+ });
+
+ tracer.end(keyValue("source context path", path));
+
+ return path;
+}
+
+Cache::SourceContexts ProjectStorage::fetchAllSourceContexts() const
+{
+ NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()};
+
+ return s->selectAllSourceContextsStatement.valuesWithTransaction<Cache::SourceContext, 128>();
+}
+
+SourceId ProjectStorage::fetchSourceId(SourceContextId sourceContextId,
+ Utils::SmallStringView sourceName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source id"_t,
+ projectStorageCategory(),
+ keyValue("source context id", sourceContextId),
+ keyValue("source name", sourceName)};
+
+ auto sourceId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchSourceIdUnguarded(sourceContextId, sourceName);
+ });
+
+ tracer.end(keyValue("source id", sourceId));
+
+ return sourceId;
+}
+
+Cache::SourceNameAndSourceContextId ProjectStorage::fetchSourceNameAndSourceContextId(SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source name and source context id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId)};
+
+ auto value = s->selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
+ .valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId);
+
+ if (!value.sourceContextId)
+ throw SourceIdDoesNotExists();
+
+ tracer.end(keyValue("source name", value.sourceName),
+ keyValue("source context id", value.sourceContextId));
+
+ return value;
+}
+
+void ProjectStorage::clearSources()
+{
+ Sqlite::withImmediateTransaction(database, [&] {
+ s->deleteAllSourceContextsStatement.execute();
+ s->deleteAllSourcesStatement.execute();
+ });
+}
+
+SourceContextId ProjectStorage::fetchSourceContextId(SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source context id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId)};
+
+ auto sourceContextId = s->selectSourceContextIdFromSourcesBySourceIdStatement
+ .valueWithTransaction<SourceContextId>(sourceId);
+
+ if (!sourceContextId)
+ throw SourceIdDoesNotExists();
+
+ tracer.end(keyValue("source context id", sourceContextId));
+
+ return sourceContextId;
+}
+
+Cache::Sources ProjectStorage::fetchAllSources() const
+{
+ NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()};
+
+ return s->selectAllSourcesStatement.valuesWithTransaction<Cache::Source, 1024>();
+}
+
+SourceId ProjectStorage::fetchSourceIdUnguarded(SourceContextId sourceContextId,
+ Utils::SmallStringView sourceName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch source id unguarded"_t,
+ projectStorageCategory(),
+ keyValue("source context id", sourceContextId),
+ keyValue("source name", sourceName)};
+
+ auto sourceId = readSourceId(sourceContextId, sourceName);
+
+ if (!sourceId)
+ sourceId = writeSourceId(sourceContextId, sourceName);
+
+ tracer.end(keyValue("source id", sourceId));
+
+ return sourceId;
+}
+
+FileStatuses ProjectStorage::fetchAllFileStatuses() const
+{
+ NanotraceHR::Tracer tracer{"fetch all file statuses"_t, projectStorageCategory()};
+
+ return s->selectAllFileStatusesStatement.valuesWithTransaction<FileStatus>();
+}
+
+FileStatus ProjectStorage::fetchFileStatus(SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch file status"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId)};
+
+ auto fileStatus = s->selectFileStatusesForSourceIdStatement.valueWithTransaction<FileStatus>(
+ sourceId);
+
+ tracer.end(keyValue("file status", fileStatus));
+
+ return fileStatus;
+}
+
+std::optional<Storage::Synchronization::DirectoryInfo> ProjectStorage::fetchDirectoryInfo(SourceId sourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch directory info"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId)};
+
+ auto directoryInfo = s->selectDirectoryInfoForSourceIdStatement
+ .optionalValueWithTransaction<Storage::Synchronization::DirectoryInfo>(
+ sourceId);
+
+ tracer.end(keyValue("directory info", directoryInfo));
+
+ return directoryInfo;
+}
+
+Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(SourceId directorySourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch directory infos by source id"_t,
+ projectStorageCategory(),
+ keyValue("source id", directorySourceId)};
+
+ auto directoryInfos = s->selectDirectoryInfosForSourceIdStatement
+ .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 1024>(
+ directorySourceId);
+
+ tracer.end(keyValue("directory infos", directoryInfos));
+
+ return directoryInfos;
+}
+
+Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(
+ SourceId directorySourceId, Storage::Synchronization::FileType fileType) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch directory infos by source id and file type"_t,
+ projectStorageCategory(),
+ keyValue("source id", directorySourceId),
+ keyValue("file type", fileType)};
+
+ auto directoryInfos = s->selectDirectoryInfosForSourceIdAndFileTypeStatement
+ .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 16>(
+ directorySourceId, fileType);
+
+ tracer.end(keyValue("directory infos", directoryInfos));
+
+ return directoryInfos;
+}
+
+Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(
+ const SourceIds &directorySourceIds) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch directory infos by source ids"_t,
+ projectStorageCategory(),
+ keyValue("source ids", directorySourceIds)};
+
+ auto directoryInfos = s->selectDirectoryInfosForSourceIdsStatement
+ .valuesWithTransaction<Storage::Synchronization::DirectoryInfo, 64>(
+ toIntegers(directorySourceIds));
+
+ tracer.end(keyValue("directory infos", directoryInfos));
+
+ return directoryInfos;
+}
+
+SmallSourceIds<32> ProjectStorage::fetchSubdirectorySourceIds(SourceId directorySourceId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch subdirectory source ids"_t,
+ projectStorageCategory(),
+ keyValue("source id", directorySourceId)};
+
+ auto sourceIds = s->selectDirectoryInfosSourceIdsForSourceIdAndFileTypeStatement
+ .valuesWithTransaction<SmallSourceIds<32>>(
+ directorySourceId, Storage::Synchronization::FileType::Directory);
+
+ tracer.end(keyValue("source ids", sourceIds));
+
+ return sourceIds;
+}
+
+void ProjectStorage::setPropertyEditorPathId(TypeId typeId, SourceId pathId)
+{
+ Sqlite::ImmediateSessionTransaction transaction{database};
+
+ s->upsertPropertyEditorPathIdStatement.write(typeId, pathId);
+
+ transaction.commit();
+}
+
+SourceId ProjectStorage::propertyEditorPathId(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"property editor path id"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto sourceId = s->selectPropertyEditorPathIdStatement.valueWithTransaction<SourceId>(typeId);
+
+ tracer.end(keyValue("source id", sourceId));
+
+ return sourceId;
+}
+
+Storage::Imports ProjectStorage::fetchDocumentImports() const
+{
+ NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()};
+
+ return s->selectAllDocumentImportForSourceIdStatement.valuesWithTransaction<Storage::Imports>();
+}
+
+void ProjectStorage::resetForTestsOnly()
+{
+ database.clearAllTablesForTestsOnly();
+ commonTypeCache_.clearForTestsOnly();
+ moduleCache.clearForTestOnly();
+}
+
+ModuleId ProjectStorage::fetchModuleId(Utils::SmallStringView moduleName,
+ Storage::ModuleKind moduleKind)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch module id"_t,
+ projectStorageCategory(),
+ keyValue("module name", moduleName),
+ keyValue("module kind", moduleKind)};
+
+ auto moduleId = Sqlite::withDeferredTransaction(database, [&] {
+ return fetchModuleIdUnguarded(moduleName, moduleKind);
+ });
+
+ tracer.end(keyValue("module id", moduleId));
+
+ return moduleId;
+}
+
+Storage::Module ProjectStorage::fetchModule(ModuleId id)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch module name"_t,
+ projectStorageCategory(),
+ keyValue("module id", id)};
+
+ auto module = Sqlite::withDeferredTransaction(database, [&] { return fetchModuleUnguarded(id); });
+
+ tracer.end(keyValue("module name", module.name));
+ tracer.end(keyValue("module name", module.kind));
+
+ return module;
+}
+
+ProjectStorage::ModuleCacheEntries ProjectStorage::fetchAllModules() const
+{
+ NanotraceHR::Tracer tracer{"fetch all modules"_t, projectStorageCategory()};
+
+ return s->selectAllModulesStatement.valuesWithTransaction<ModuleCacheEntry, 128>();
+}
+
+void ProjectStorage::callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"call refresh meta info callback"_t,
+ projectStorageCategory(),
+ keyValue("type ids", deletedTypeIds)};
+
+ if (deletedTypeIds.size()) {
+ for (ProjectStorageObserver *observer : observers)
+ observer->removedTypeIds(deletedTypeIds);
+ }
+}
+
+SourceIds ProjectStorage::filterSourceIdsWithoutType(const SourceIds &updatedSourceIds,
+ SourceIds &sourceIdsOfTypes)
+{
+ std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end());
+
+ SourceIds sourceIdsWithoutTypeSourceIds;
+ sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size());
+ std::set_difference(updatedSourceIds.begin(),
+ updatedSourceIds.end(),
+ sourceIdsOfTypes.begin(),
+ sourceIdsOfTypes.end(),
+ std::back_inserter(sourceIdsWithoutTypeSourceIds));
+
+ return sourceIdsWithoutTypeSourceIds;
+}
+
+TypeIds ProjectStorage::fetchTypeIds(const SourceIds &sourceIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type ids"_t,
+ projectStorageCategory(),
+ keyValue("source ids", sourceIds)};
+
+ return s->selectTypeIdsForSourceIdsStatement.values<TypeId, 128>(toIntegers(sourceIds));
+}
+
+void ProjectStorage::unique(SourceIds &sourceIds)
+{
+ std::sort(sourceIds.begin(), sourceIds.end());
+ auto newEnd = std::unique(sourceIds.begin(), sourceIds.end());
+ sourceIds.erase(newEnd, sourceIds.end());
+}
+
+void ProjectStorage::synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"synchronize type traits"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("type traits", traits)};
+
+ s->updateTypeAnnotationTraitStatement.write(typeId, traits.annotation);
+}
+
+void ProjectStorage::updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations)
+{
+ NanotraceHR::Tracer tracer{"update type id in type annotations"_t, projectStorageCategory()};
+
+ for (auto &annotation : typeAnnotations) {
+ annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId,
+ annotation.typeName);
+ }
+
+ typeAnnotations.erase(std::remove_if(typeAnnotations.begin(),
+ typeAnnotations.end(),
+ [](const auto &annotation) { return !annotation.typeId; }),
+ typeAnnotations.end());
+}
+
+void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations,
+ const SourceIds &updatedTypeAnnotationSourceIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()};
+
+ using Storage::Synchronization::TypeAnnotation;
+
+ updateTypeIdInTypeAnnotations(typeAnnotations);
+
+ auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; };
+
+ std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) {
+ return first.typeId < second.typeId;
+ });
+
+ auto range = s->selectTypeAnnotationsForSourceIdsStatement.range<TypeAnnotationView>(
+ toIntegers(updatedTypeAnnotationSourceIds));
+
+ auto insert = [&](const TypeAnnotation &annotation) {
+ if (!annotation.sourceId)
+ throw TypeAnnotationHasInvalidSourceId{};
+
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert type annotations"_t,
+ projectStorageCategory(),
+ keyValue("type annotation", annotation)};
+
+ s->insertTypeAnnotationStatement.write(annotation.typeId,
+ annotation.sourceId,
+ annotation.directorySourceId,
+ annotation.typeName,
+ annotation.iconPath,
+ createEmptyAsNull(annotation.itemLibraryJson),
+ createEmptyAsNull(annotation.hintsJson));
+
+ synchronizeTypeTraits(annotation.typeId, annotation.traits);
+ };
+
+ auto update = [&](const TypeAnnotationView &annotationFromDatabase,
+ const TypeAnnotation &annotation) {
+
+ if (annotationFromDatabase.typeName != annotation.typeName
+ || annotationFromDatabase.iconPath != annotation.iconPath
+ || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson
+ || annotationFromDatabase.hintsJson != annotation.hintsJson) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update type annotations"_t,
+ projectStorageCategory(),
+ keyValue("type annotation from database",
+ annotationFromDatabase),
+ keyValue("type annotation", annotation)};
+
+ s->updateTypeAnnotationStatement.write(annotation.typeId,
+ annotation.typeName,
+ annotation.iconPath,
+ createEmptyAsNull(annotation.itemLibraryJson),
+ createEmptyAsNull(annotation.hintsJson));
+
+ synchronizeTypeTraits(annotation.typeId, annotation.traits);
+
+ return Sqlite::UpdateChange::Update;
+ }
+
+ synchronizeTypeTraits(annotation.typeId, annotation.traits);
+
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const TypeAnnotationView &annotationFromDatabase) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove type annotations"_t,
+ projectStorageCategory(),
+ keyValue("type annotation", annotationFromDatabase)};
+
+ auto prototypeAnnotationTraits = s->selectPrototypeAnnotationTraitsByTypeIdStatement
+ .value<long long>(annotationFromDatabase.typeId);
+ s->deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId);
+
+ s->updateTypeAnnotationTraitStatement.write(annotationFromDatabase.typeId,
+ prototypeAnnotationTraits);
+ };
+
+ Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizeTypeTrait(const Storage::Synchronization::Type &type)
+{
+ s->updateTypeTraitStatement.write(type.typeId, type.traits.type);
+}
+
+void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types,
+ TypeIds &updatedTypeIds,
+ AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions,
+ const SourceIds &updatedSourceIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()};
+
+ Storage::Synchronization::ExportedTypes exportedTypes;
+ exportedTypes.reserve(types.size() * 3);
+ SourceIds sourceIdsOfTypes;
+ sourceIdsOfTypes.reserve(updatedSourceIds.size());
+ SourceIds notUpdatedExportedSourceIds;
+ notUpdatedExportedSourceIds.reserve(updatedSourceIds.size());
+ SourceIds exportedSourceIds;
+ exportedSourceIds.reserve(types.size());
+
+ for (auto &type : types) {
+ if (!type.sourceId)
+ throw TypeHasInvalidSourceId{};
+
+ TypeId typeId = declareType(type);
+ synchronizeTypeTrait(type);
+ sourceIdsOfTypes.push_back(type.sourceId);
+ updatedTypeIds.push_back(typeId);
+ if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) {
+ exportedSourceIds.push_back(type.sourceId);
+ extractExportedTypes(typeId, type, exportedTypes);
+ }
+ }
+
+ std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) {
+ return first.typeId < second.typeId;
+ });
+
+ unique(exportedSourceIds);
+
+ SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, sourceIdsOfTypes);
+ exportedSourceIds.insert(exportedSourceIds.end(),
+ sourceIdsWithoutType.begin(),
+ sourceIdsWithoutType.end());
+ TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds);
+ synchronizeExportedTypes(exportedTypeIds,
+ exportedTypes,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions);
+
+ syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions);
+ resetDefaultPropertiesIfChanged(types);
+ resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations);
+ syncDeclarations(types,
+ insertedAliasPropertyDeclarations,
+ updatedAliasPropertyDeclarations,
+ relinkablePropertyDeclarations);
+ syncDefaultProperties(types);
+}
+
+void ProjectStorage::synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos,
+ const SourceIds &updatedDirectoryInfoSourceIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize directory infos"_t, projectStorageCategory()};
+
+ auto compareKey = [](auto &&first, auto &&second) {
+ auto directorySourceIdDifference = first.directorySourceId - second.directorySourceId;
+ if (directorySourceIdDifference != 0)
+ return directorySourceIdDifference;
+
+ return first.sourceId - second.sourceId;
+ };
+
+ std::sort(directoryInfos.begin(), directoryInfos.end(), [&](auto &&first, auto &&second) {
+ return std::tie(first.directorySourceId, first.sourceId)
+ < std::tie(second.directorySourceId, second.sourceId);
+ });
+
+ auto range = s->selectDirectoryInfosForSourceIdsStatement.range<Storage::Synchronization::DirectoryInfo>(
+ toIntegers(updatedDirectoryInfoSourceIds));
+
+ auto insert = [&](const Storage::Synchronization::DirectoryInfo &directoryInfo) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert directory info"_t,
+ projectStorageCategory(),
+ keyValue("directory info", directoryInfo)};
+
+ if (!directoryInfo.directorySourceId)
+ throw DirectoryInfoHasInvalidProjectSourceId{};
+ if (!directoryInfo.sourceId)
+ throw DirectoryInfoHasInvalidSourceId{};
+
+ s->insertDirectoryInfoStatement.write(directoryInfo.directorySourceId,
+ directoryInfo.sourceId,
+ directoryInfo.moduleId,
+ directoryInfo.fileType);
+ };
+
+ auto update = [&](const Storage::Synchronization::DirectoryInfo &directoryInfoFromDatabase,
+ const Storage::Synchronization::DirectoryInfo &directoryInfo) {
+ if (directoryInfoFromDatabase.fileType != directoryInfo.fileType
+ || !compareInvalidAreTrue(directoryInfoFromDatabase.moduleId, directoryInfo.moduleId)) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update directory info"_t,
+ projectStorageCategory(),
+ keyValue("directory info", directoryInfo),
+ keyValue("directory info from database",
+ directoryInfoFromDatabase)};
+
+ s->updateDirectoryInfoStatement.write(directoryInfo.directorySourceId,
+ directoryInfo.sourceId,
+ directoryInfo.moduleId,
+ directoryInfo.fileType);
+ return Sqlite::UpdateChange::Update;
+ }
+
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const Storage::Synchronization::DirectoryInfo &directoryInfo) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove directory info"_t,
+ projectStorageCategory(),
+ keyValue("directory info", directoryInfo)};
+
+ s->deleteDirectoryInfoStatement.write(directoryInfo.directorySourceId, directoryInfo.sourceId);
+ };
+
+ Sqlite::insertUpdateDelete(range, directoryInfos, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizeFileStatuses(FileStatuses &fileStatuses,
+ const SourceIds &updatedSourceIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()};
+
+ auto compareKey = [](auto &&first, auto &&second) { return first.sourceId - second.sourceId; };
+
+ std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) {
+ return first.sourceId < second.sourceId;
+ });
+
+ auto range = s->selectFileStatusesForSourceIdsStatement.range<FileStatus>(
+ toIntegers(updatedSourceIds));
+
+ auto insert = [&](const FileStatus &fileStatus) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert file status"_t,
+ projectStorageCategory(),
+ keyValue("file status", fileStatus)};
+
+ if (!fileStatus.sourceId)
+ throw FileStatusHasInvalidSourceId{};
+ s->insertFileStatusStatement.write(fileStatus.sourceId,
+ fileStatus.size,
+ fileStatus.lastModified);
+ };
+
+ auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) {
+ if (fileStatusFromDatabase.lastModified != fileStatus.lastModified
+ || fileStatusFromDatabase.size != fileStatus.size) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update file status"_t,
+ projectStorageCategory(),
+ keyValue("file status", fileStatus),
+ keyValue("file status from database", fileStatusFromDatabase)};
+
+ s->updateFileStatusStatement.write(fileStatus.sourceId,
+ fileStatus.size,
+ fileStatus.lastModified);
+ return Sqlite::UpdateChange::Update;
+ }
+
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const FileStatus &fileStatus) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove file status"_t,
+ projectStorageCategory(),
+ keyValue("file status", fileStatus)};
+
+ s->deleteFileStatusStatement.write(fileStatus.sourceId);
+ };
+
+ Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizeImports(Storage::Imports &imports,
+ const SourceIds &updatedSourceIds,
+ Storage::Imports &moduleDependencies,
+ const SourceIds &updatedModuleDependencySourceIds,
+ Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
+ const ModuleIds &updatedModuleIds,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()};
+
+ synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds);
+ NanotraceHR::Tracer importTracer{"synchronize qml document imports"_t, projectStorageCategory()};
+ synchronizeDocumentImports(imports,
+ updatedSourceIds,
+ Storage::Synchronization::ImportKind::Import,
+ Relink::No,
+ relinkablePrototypes,
+ relinkableExtensions);
+ importTracer.end();
+ NanotraceHR::Tracer moduleDependenciesTracer{"synchronize module depdencies"_t,
+ projectStorageCategory()};
+ synchronizeDocumentImports(moduleDependencies,
+ updatedModuleDependencySourceIds,
+ Storage::Synchronization::ImportKind::ModuleDependency,
+ Relink::Yes,
+ relinkablePrototypes,
+ relinkableExtensions);
+ moduleDependenciesTracer.end();
+}
+
+void ProjectStorage::synchromizeModuleExportedImports(
+ Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
+ const ModuleIds &updatedModuleIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize module exported imports"_t, projectStorageCategory()};
+ std::sort(moduleExportedImports.begin(),
+ moduleExportedImports.end(),
+ [](auto &&first, auto &&second) {
+ return std::tie(first.moduleId, first.exportedModuleId)
+ < std::tie(second.moduleId, second.exportedModuleId);
+ });
+
+ auto range = s->selectModuleExportedImportsForSourceIdStatement
+ .range<Storage::Synchronization::ModuleExportedImportView>(
+ toIntegers(updatedModuleIds));
+
+ auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view,
+ const Storage::Synchronization::ModuleExportedImport &import) -> long long {
+ auto moduleIdDifference = view.moduleId - import.moduleId;
+ if (moduleIdDifference != 0)
+ return moduleIdDifference;
+
+ return view.exportedModuleId - import.exportedModuleId;
+ };
+
+ auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert module exported import"_t,
+ projectStorageCategory(),
+ keyValue("module exported import", import),
+ keyValue("module id", import.moduleId)};
+ tracer.tick("exported module"_t, keyValue("module id", import.exportedModuleId));
+
+ if (import.version.minor) {
+ s->insertModuleExportedImportWithVersionStatement.write(import.moduleId,
+ import.exportedModuleId,
+ import.isAutoVersion,
+ import.version.major.value,
+ import.version.minor.value);
+ } else if (import.version.major) {
+ s->insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId,
+ import.exportedModuleId,
+ import.isAutoVersion,
+ import.version.major.value);
+ } else {
+ s->insertModuleExportedImportWithoutVersionStatement.write(import.moduleId,
+ import.exportedModuleId,
+ import.isAutoVersion);
+ }
+ };
+
+ auto update = [](const Storage::Synchronization::ModuleExportedImportView &,
+ const Storage::Synchronization::ModuleExportedImport &) {
+ return Sqlite::UpdateChange::No;
+ };
-template class QmlDesigner::ProjectStorage<Sqlite::Database>;
+ auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove module exported import"_t,
+ projectStorageCategory(),
+ keyValue("module exported import view", view),
+ keyValue("module id", view.moduleId)};
+ tracer.tick("exported module"_t, keyValue("module id", view.exportedModuleId));
+
+ s->deleteModuleExportedImportStatement.write(view.moduleExportedImportId);
+ };
+
+ Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove);
+}
+
+ModuleId ProjectStorage::fetchModuleIdUnguarded(Utils::SmallStringView name,
+ Storage::ModuleKind kind) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch module id ungarded"_t,
+ projectStorageCategory(),
+ keyValue("module name", name),
+ keyValue("module kind", kind)};
+
+ auto moduleId = s->selectModuleIdByNameStatement.value<ModuleId>(kind, name);
+
+ if (!moduleId)
+ moduleId = s->insertModuleNameStatement.value<ModuleId>(kind, name);
+
+ tracer.end(keyValue("module id", moduleId));
+
+ return moduleId;
+}
+
+Storage::Module ProjectStorage::fetchModuleUnguarded(ModuleId id) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch module ungarded"_t,
+ projectStorageCategory(),
+ keyValue("module id", id)};
+
+ auto module = s->selectModuleStatement.value<Storage::Module>(id);
+
+ if (!module)
+ throw ModuleDoesNotExists{};
+
+ tracer.end(keyValue("module name", module.name));
+ tracer.end(keyValue("module name", module.kind));
+
+ return module;
+}
+
+void ProjectStorage::handleAliasPropertyDeclarationsWithPropertyType(
+ TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle alias property declarations with property type"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("relinkable alias property declarations",
+ relinkableAliasPropertyDeclarations)};
+
+ auto callback = [&](TypeId typeId_,
+ PropertyDeclarationId propertyDeclarationId,
+ ImportedTypeNameId propertyImportedTypeNameId,
+ PropertyDeclarationId aliasPropertyDeclarationId,
+ PropertyDeclarationId aliasPropertyDeclarationTailId) {
+ auto aliasPropertyName = s->selectPropertyNameStatement.value<Utils::SmallString>(
+ aliasPropertyDeclarationId);
+ Utils::SmallString aliasPropertyNameTail;
+ if (aliasPropertyDeclarationTailId)
+ aliasPropertyNameTail = s->selectPropertyNameStatement.value<Utils::SmallString>(
+ aliasPropertyDeclarationTailId);
+
+ relinkableAliasPropertyDeclarations.emplace_back(TypeId{typeId_},
+ PropertyDeclarationId{propertyDeclarationId},
+ ImportedTypeNameId{propertyImportedTypeNameId},
+ std::move(aliasPropertyName),
+ std::move(aliasPropertyNameTail));
+
+ s->updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
+ };
+
+ s->selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback, typeId);
+}
+
+void ProjectStorage::handlePropertyDeclarationWithPropertyType(
+ TypeId typeId, PropertyDeclarations &relinkablePropertyDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle property declarations with property type"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("relinkable property declarations",
+ relinkablePropertyDeclarations)};
+
+ s->updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations,
+ typeId);
+}
+
+void ProjectStorage::handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle prototypes"_t,
+ projectStorageCategory(),
+ keyValue("type id", prototypeId),
+ keyValue("relinkable prototypes", relinkablePrototypes)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
+ if (prototypeNameId)
+ relinkablePrototypes.emplace_back(typeId, prototypeNameId);
+ };
+
+ s->updatePrototypeIdToTypeIdStatement.readCallback(callback, prototypeId, unresolvedTypeId);
+}
+
+void ProjectStorage::handlePrototypesWithExportedTypeNameAndTypeId(
+ Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkablePrototypes)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle invalid prototypes"_t,
+ projectStorageCategory(),
+ keyValue("type id", exportedTypeName),
+ keyValue("relinkable prototypes", relinkablePrototypes)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
+ relinkablePrototypes.emplace_back(typeId, prototypeNameId);
+ };
+
+ s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement.readCallback(callback,
+ exportedTypeName,
+ typeId);
+}
+
+void ProjectStorage::handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle extension"_t,
+ projectStorageCategory(),
+ keyValue("type id", extensionId),
+ keyValue("relinkable extensions", relinkableExtensions)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
+ if (extensionNameId)
+ relinkableExtensions.emplace_back(typeId, extensionNameId);
+ };
+
+ s->updateExtensionIdToTypeIdStatement.readCallback(callback, extensionId, unresolvedTypeId);
+}
+
+void ProjectStorage::handleExtensionsWithExportedTypeNameAndTypeId(
+ Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle invalid extensions"_t,
+ projectStorageCategory(),
+ keyValue("type id", exportedTypeName),
+ keyValue("relinkable extensions", relinkableExtensions)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
+ relinkableExtensions.emplace_back(typeId, extensionNameId);
+ };
+
+ s->selectTypeIdForExtensionIdAndTypeNameStatement.readCallback(callback, exportedTypeName, typeId);
+}
+
+void ProjectStorage::deleteType(TypeId typeId,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"delete type"_t, projectStorageCategory(), keyValue("type id", typeId)};
+
+ handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations);
+ handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations);
+ handlePrototypes(typeId, relinkablePrototypes);
+ handleExtensions(typeId, relinkableExtensions);
+ s->deleteTypeNamesByTypeIdStatement.write(typeId);
+ s->deleteEnumerationDeclarationByTypeIdStatement.write(typeId);
+ s->deletePropertyDeclarationByTypeIdStatement.write(typeId);
+ s->deleteFunctionDeclarationByTypeIdStatement.write(typeId);
+ s->deleteSignalDeclarationByTypeIdStatement.write(typeId);
+ s->deleteTypeStatement.write(typeId);
+}
+
+void ProjectStorage::relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations,
+ const TypeIds &deletedTypeIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"relink alias properties"_t,
+ projectStorageCategory(),
+ keyValue("alias property declarations", aliasPropertyDeclarations),
+ keyValue("deleted type ids", deletedTypeIds)};
+
+ std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end());
+
+ Utils::set_greedy_difference(
+ aliasPropertyDeclarations.cbegin(),
+ aliasPropertyDeclarations.cend(),
+ deletedTypeIds.begin(),
+ deletedTypeIds.end(),
+ [&](const AliasPropertyDeclaration &alias) {
+ auto typeId = fetchTypeId(alias.aliasImportedTypeNameId);
+
+ if (!typeId)
+ throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)};
+
+ auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded(
+ typeId, alias.aliasPropertyName);
+
+ s->updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId,
+ propertyTypeId,
+ propertyTraits,
+ alias.aliasImportedTypeNameId,
+ aliasId);
+ },
+ TypeCompare<AliasPropertyDeclaration>{});
+}
+
+void ProjectStorage::relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration,
+ const TypeIds &deletedTypeIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"relink property declarations"_t,
+ projectStorageCategory(),
+ keyValue("relinkable property declarations",
+ relinkablePropertyDeclaration),
+ keyValue("deleted type ids", deletedTypeIds)};
+
+ std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end());
+
+ Utils::set_greedy_difference(
+ relinkablePropertyDeclaration.cbegin(),
+ relinkablePropertyDeclaration.cend(),
+ deletedTypeIds.begin(),
+ deletedTypeIds.end(),
+ [&](const PropertyDeclaration &property) {
+ TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId);
+
+ if (!propertyTypeId)
+ throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)};
+
+ s->updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId,
+ propertyTypeId);
+ },
+ TypeCompare<PropertyDeclaration>{});
+}
+
+template<typename Callable>
+void ProjectStorage::relinkPrototypes(Prototypes &relinkablePrototypes,
+ const TypeIds &deletedTypeIds,
+ Callable updateStatement)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"relink prototypes"_t,
+ projectStorageCategory(),
+ keyValue("relinkable prototypes", relinkablePrototypes),
+ keyValue("deleted type ids", deletedTypeIds)};
+
+ std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end());
+ relinkablePrototypes.erase(std::unique(relinkablePrototypes.begin(), relinkablePrototypes.end()),
+ relinkablePrototypes.end());
+
+ Utils::set_greedy_difference(
+ relinkablePrototypes.cbegin(),
+ relinkablePrototypes.cend(),
+ deletedTypeIds.begin(),
+ deletedTypeIds.end(),
+ [&](const Prototype &prototype) {
+ TypeId prototypeId = fetchTypeId(prototype.prototypeNameId);
+
+ if (!prototypeId)
+ errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName(prototype.prototypeNameId),
+ fetchTypeSourceId(prototype.typeId));
+
+ updateStatement(prototype.typeId, prototypeId);
+ checkForPrototypeChainCycle(prototype.typeId);
+ },
+ TypeCompare<Prototype>{});
+}
+
+void ProjectStorage::deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
+ const SourceIds &updatedSourceIds,
+ const TypeIds &typeIdsToBeDeleted,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions,
+ TypeIds &deletedTypeIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"delete not updated types"_t,
+ projectStorageCategory(),
+ keyValue("updated type ids", updatedTypeIds),
+ keyValue("updated source ids", updatedSourceIds),
+ keyValue("type ids to be deleted", typeIdsToBeDeleted)};
+
+ auto callback = [&](TypeId typeId) {
+ deletedTypeIds.push_back(typeId);
+ deleteType(typeId,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions);
+ };
+
+ s->selectNotUpdatedTypesInSourcesStatement.readCallback(callback,
+ toIntegers(updatedSourceIds),
+ toIntegers(updatedTypeIds));
+ for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted)
+ callback(typeIdToBeDeleted);
+}
+
+void ProjectStorage::relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions,
+ TypeIds &deletedTypeIds)
+{
+ NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()};
+
+ std::sort(deletedTypeIds.begin(), deletedTypeIds.end());
+
+ relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) {
+ s->updateTypePrototypeStatement.write(typeId, prototypeId);
+ });
+ relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) {
+ s->updateTypeExtensionStatement.write(typeId, prototypeId);
+ });
+ relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds);
+ relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds);
+}
+
+PropertyDeclarationId ProjectStorage::fetchAliasId(TypeId aliasTypeId,
+ Utils::SmallStringView aliasPropertyName,
+ Utils::SmallStringView aliasPropertyNameTail)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch alias id"_t,
+ projectStorageCategory(),
+ keyValue("alias type id", aliasTypeId),
+ keyValue("alias property name", aliasPropertyName),
+ keyValue("alias property name tail", aliasPropertyNameTail)};
+
+ if (aliasPropertyNameTail.empty())
+ return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName);
+
+ auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName);
+
+ return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId,
+ aliasPropertyNameTail);
+}
+
+void ProjectStorage::linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"link alias property declarations alias ids"_t,
+ projectStorageCategory(),
+ keyValue("alias property declarations", aliasDeclarations)};
+
+ for (const auto &aliasDeclaration : aliasDeclarations) {
+ auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId);
+
+ if (!aliasTypeId) {
+ throw TypeNameDoesNotExists{
+ fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)};
+ }
+
+ auto aliasId = fetchAliasId(aliasTypeId,
+ aliasDeclaration.aliasPropertyName,
+ aliasDeclaration.aliasPropertyNameTail);
+
+ s->updatePropertyDeclarationAliasIdAndTypeNameIdStatement.write(
+ aliasDeclaration.propertyDeclarationId, aliasId, aliasDeclaration.aliasImportedTypeNameId);
+ }
+}
+
+void ProjectStorage::updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update alias property declarations"_t,
+ projectStorageCategory(),
+ keyValue("alias property declarations", aliasDeclarations)};
+
+ for (const auto &aliasDeclaration : aliasDeclarations) {
+ s->updatetPropertiesDeclarationValuesOfAliasStatement.write(
+ aliasDeclaration.propertyDeclarationId);
+ s->updatePropertyAliasDeclarationRecursivelyStatement.write(
+ aliasDeclaration.propertyDeclarationId);
+ }
+}
+
+void ProjectStorage::checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"check alias property declarations cycles"_t,
+ projectStorageCategory(),
+ keyValue("alias property declarations", aliasDeclarations)};
+ for (const auto &aliasDeclaration : aliasDeclarations)
+ checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId);
+}
+
+void ProjectStorage::linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ const AliasPropertyDeclarations &updatedAliasPropertyDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()};
+
+ linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations);
+ linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations);
+
+ checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations);
+ checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations);
+
+ updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations);
+ updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations);
+}
+
+void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
+ Storage::Synchronization::ExportedTypes &exportedTypes,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()};
+
+ std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
+ if (first.moduleId < second.moduleId)
+ return true;
+ else if (first.moduleId > second.moduleId)
+ return false;
+
+ auto nameCompare = Sqlite::compare(first.name, second.name);
+
+ if (nameCompare < 0)
+ return true;
+ else if (nameCompare > 0)
+ return false;
+
+ return first.version < second.version;
+ });
+
+ auto range = s->selectExportedTypesForSourceIdsStatement
+ .range<Storage::Synchronization::ExportedTypeView>(toIntegers(updatedTypeIds));
+
+ auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view,
+ const Storage::Synchronization::ExportedType &type) -> long long {
+ auto moduleIdDifference = view.moduleId - type.moduleId;
+ if (moduleIdDifference != 0)
+ return moduleIdDifference;
+
+ auto nameDifference = Sqlite::compare(view.name, type.name);
+ if (nameDifference != 0)
+ return nameDifference;
+
+ auto versionDifference = view.version.major.value - type.version.major.value;
+ if (versionDifference != 0)
+ return versionDifference;
+
+ return view.version.minor.value - type.version.minor.value;
+ };
+
+ auto insert = [&](const Storage::Synchronization::ExportedType &type) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert exported type"_t,
+ projectStorageCategory(),
+ keyValue("exported type", type),
+ keyValue("type id", type.typeId),
+ keyValue("module id", type.moduleId)};
+ if (!type.moduleId)
+ throw QmlDesigner::ModuleDoesNotExists{};
+
+ try {
+ if (type.version) {
+ s->insertExportedTypeNamesWithVersionStatement.write(type.moduleId,
+ type.name,
+ type.version.major.value,
+ type.version.minor.value,
+ type.typeId);
+
+ } else if (type.version.major) {
+ s->insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId,
+ type.name,
+ type.version.major.value,
+ type.typeId);
+ } else {
+ s->insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId,
+ type.name,
+ type.typeId);
+ }
+ } catch (const Sqlite::ConstraintPreventsModification &) {
+ throw QmlDesigner::ExportedTypeCannotBeInserted{type.name};
+ }
+
+ handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes);
+ handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions);
+ };
+
+ auto update = [&](const Storage::Synchronization::ExportedTypeView &view,
+ const Storage::Synchronization::ExportedType &type) {
+ if (view.typeId != type.typeId) {
+ NanotraceHR::Tracer tracer{"update exported type"_t,
+ projectStorageCategory(),
+ keyValue("exported type", type),
+ keyValue("exported type view", view),
+ keyValue("type id", type.typeId),
+ keyValue("module id", type.typeId)};
+
+ handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations);
+ handleAliasPropertyDeclarationsWithPropertyType(view.typeId,
+ relinkableAliasPropertyDeclarations);
+ handlePrototypes(view.typeId, relinkablePrototypes);
+ handleExtensions(view.typeId, relinkableExtensions);
+ s->updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId);
+ return Sqlite::UpdateChange::Update;
+ }
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) {
+ NanotraceHR::Tracer tracer{"remove exported type"_t,
+ projectStorageCategory(),
+ keyValue("exported type", view),
+ keyValue("type id", view.typeId),
+ keyValue("module id", view.moduleId)};
+
+ handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations);
+ handleAliasPropertyDeclarationsWithPropertyType(view.typeId,
+ relinkableAliasPropertyDeclarations);
+ handlePrototypes(view.typeId, relinkablePrototypes);
+ handleExtensions(view.typeId, relinkableExtensions);
+
+ s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId);
+ };
+
+ Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizePropertyDeclarationsInsertAlias(
+ AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ const Storage::Synchronization::PropertyDeclaration &value,
+ SourceId sourceId,
+ TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert property declaration to alias"_t,
+ projectStorageCategory(),
+ keyValue("property declaration", value)};
+
+ auto callback = [&](PropertyDeclarationId propertyDeclarationId) {
+ insertedAliasPropertyDeclarations.emplace_back(typeId,
+ propertyDeclarationId,
+ fetchImportedTypeNameId(value.typeName,
+ sourceId),
+ value.aliasPropertyName,
+ value.aliasPropertyNameTail);
+ return Sqlite::CallbackControl::Abort;
+ };
+
+ s->insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name);
+}
+
+QVarLengthArray<PropertyDeclarationId, 128> ProjectStorage::fetchPropertyDeclarationIds(
+ TypeId baseTypeId) const
+{
+ QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds;
+
+ s->selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, baseTypeId);
+
+ auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId);
+
+ for (TypeId prototype : range) {
+ s->selectLocalPropertyDeclarationIdsForTypeStatement.readTo(propertyDeclarationIds, prototype);
+ }
+
+ return propertyDeclarationIds;
+}
+
+PropertyDeclarationId ProjectStorage::fetchNextPropertyDeclarationId(
+ TypeId baseTypeId, Utils::SmallStringView propertyName) const
+{
+ auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId);
+
+ for (TypeId prototype : range) {
+ auto propertyDeclarationId = s->selectPropertyDeclarationIdByTypeIdAndNameStatement
+ .value<PropertyDeclarationId>(prototype, propertyName);
+
+ if (propertyDeclarationId)
+ return propertyDeclarationId;
+ }
+
+ return PropertyDeclarationId{};
+}
+
+PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationId(TypeId typeId,
+ Utils::SmallStringView propertyName) const
+{
+ auto propertyDeclarationId = s->selectPropertyDeclarationIdByTypeIdAndNameStatement
+ .value<PropertyDeclarationId>(typeId, propertyName);
+
+ if (propertyDeclarationId)
+ return propertyDeclarationId;
+
+ return fetchNextPropertyDeclarationId(typeId, propertyName);
+}
+
+PropertyDeclarationId ProjectStorage::fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const
+{
+ auto range = s->selectPrototypeAndExtensionIdsStatement.range<TypeId>(baseTypeId);
+
+ for (TypeId prototype : range) {
+ auto propertyDeclarationId = s->selectDefaultPropertyDeclarationIdStatement
+ .value<PropertyDeclarationId>(prototype);
+
+ if (propertyDeclarationId)
+ return propertyDeclarationId;
+ }
+
+ return PropertyDeclarationId{};
+}
+
+PropertyDeclarationId ProjectStorage::fetchDefaultPropertyDeclarationId(TypeId typeId) const
+{
+ auto propertyDeclarationId = s->selectDefaultPropertyDeclarationIdStatement
+ .value<PropertyDeclarationId>(typeId);
+
+ if (propertyDeclarationId)
+ return propertyDeclarationId;
+
+ return fetchNextDefaultPropertyDeclarationId(typeId);
+}
+
+void ProjectStorage::synchronizePropertyDeclarationsInsertProperty(
+ const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert property declaration"_t,
+ projectStorageCategory(),
+ keyValue("property declaration", value)};
+
+ auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId);
+ auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId);
+
+ if (!propertyTypeId)
+ throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId};
+
+ auto propertyDeclarationId = s->insertPropertyDeclarationStatement.value<PropertyDeclarationId>(
+ typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId);
+
+ auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, value.name);
+ if (nextPropertyDeclarationId) {
+ s->updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId,
+ propertyDeclarationId);
+ s->updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
+ .write(propertyDeclarationId, propertyTypeId, value.traits);
+ }
+}
+
+void ProjectStorage::synchronizePropertyDeclarationsUpdateAlias(
+ AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
+ const Storage::Synchronization::PropertyDeclarationView &view,
+ const Storage::Synchronization::PropertyDeclaration &value,
+ SourceId sourceId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update property declaration to alias"_t,
+ projectStorageCategory(),
+ keyValue("property declaration", value),
+ keyValue("property declaration view", view)};
+
+ updatedAliasPropertyDeclarations.emplace_back(view.typeId,
+ view.id,
+ fetchImportedTypeNameId(value.typeName, sourceId),
+ value.aliasPropertyName,
+ value.aliasPropertyNameTail,
+ view.aliasId);
+}
+
+Sqlite::UpdateChange ProjectStorage::synchronizePropertyDeclarationsUpdateProperty(
+ const Storage::Synchronization::PropertyDeclarationView &view,
+ const Storage::Synchronization::PropertyDeclaration &value,
+ SourceId sourceId,
+ PropertyDeclarationIds &propertyDeclarationIds)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update property declaration"_t,
+ projectStorageCategory(),
+ keyValue("property declaration", value),
+ keyValue("property declaration view", view)};
+
+ auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId);
+
+ auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId);
+
+ if (!propertyTypeId)
+ throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId), sourceId};
+
+ if (view.traits == value.traits && propertyTypeId == view.typeId
+ && propertyImportedTypeNameId == view.typeNameId)
+ return Sqlite::UpdateChange::No;
+
+ s->updatePropertyDeclarationStatement.write(view.id,
+ propertyTypeId,
+ value.traits,
+ propertyImportedTypeNameId);
+ s->updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id,
+ propertyTypeId,
+ value.traits);
+ propertyDeclarationIds.push_back(view.id);
+
+ tracer.end(keyValue("updated", "yes"));
+
+ return Sqlite::UpdateChange::Update;
+}
+
+void ProjectStorage::synchronizePropertyDeclarations(
+ TypeId typeId,
+ Storage::Synchronization::PropertyDeclarations &propertyDeclarations,
+ SourceId sourceId,
+ AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
+ PropertyDeclarationIds &propertyDeclarationIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()};
+
+ std::sort(propertyDeclarations.begin(), propertyDeclarations.end(), [](auto &&first, auto &&second) {
+ return Sqlite::compare(first.name, second.name) < 0;
+ });
+
+ auto range = s->selectPropertyDeclarationsForTypeIdStatement
+ .range<Storage::Synchronization::PropertyDeclarationView>(typeId);
+
+ auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view,
+ const Storage::Synchronization::PropertyDeclaration &value) {
+ return Sqlite::compare(view.name, value.name);
+ };
+
+ auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) {
+ if (value.kind == Storage::Synchronization::PropertyKind::Alias) {
+ synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations,
+ value,
+ sourceId,
+ typeId);
+ } else {
+ synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId);
+ }
+ };
+
+ auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view,
+ const Storage::Synchronization::PropertyDeclaration &value) {
+ if (value.kind == Storage::Synchronization::PropertyKind::Alias) {
+ synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations,
+ view,
+ value,
+ sourceId);
+ propertyDeclarationIds.push_back(view.id);
+ } else {
+ return synchronizePropertyDeclarationsUpdateProperty(view,
+ value,
+ sourceId,
+ propertyDeclarationIds);
+ }
+
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove property declaration"_t,
+ projectStorageCategory(),
+ keyValue("property declaratio viewn", view)};
+
+ auto nextPropertyDeclarationId = fetchNextPropertyDeclarationId(typeId, view.name);
+
+ if (nextPropertyDeclarationId) {
+ s->updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement
+ .write(nextPropertyDeclarationId, view.id);
+ }
+
+ s->updateDefaultPropertyIdToNullStatement.write(view.id);
+ s->deletePropertyDeclarationStatement.write(view.id);
+ propertyDeclarationIds.push_back(view.id);
+ };
+
+ Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull(
+ Storage::Synchronization::Type &type, PropertyDeclarationIds &propertyDeclarationIds)
+{
+ NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t,
+ projectStorageCategory()};
+
+ if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
+ return;
+
+ Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations;
+
+ std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) {
+ return Sqlite::compare(first.name, second.name) < 0;
+ });
+
+ auto range = s->selectPropertyDeclarationsWithAliasForTypeIdStatement
+ .range<AliasPropertyDeclarationView>(type.typeId);
+
+ auto compareKey = [](const AliasPropertyDeclarationView &view,
+ const Storage::Synchronization::PropertyDeclaration &value) {
+ return Sqlite::compare(view.name, value.name);
+ };
+
+ auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {};
+
+ auto update = [&](const AliasPropertyDeclarationView &,
+ const Storage::Synchronization::PropertyDeclaration &) {
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const AliasPropertyDeclarationView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"reset removed alias property declaration to null"_t,
+ projectStorageCategory(),
+ keyValue("alias property declaration view", view)};
+
+ s->updatePropertyDeclarationAliasIdToNullStatement.write(view.id);
+ propertyDeclarationIds.push_back(view.id);
+ };
+
+ Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull(
+ Storage::Synchronization::Types &types,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations)
+{
+ NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t, projectStorageCategory()};
+
+ PropertyDeclarationIds propertyDeclarationIds;
+ propertyDeclarationIds.reserve(types.size());
+
+ for (auto &&type : types)
+ resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds);
+
+ removeRelinkableEntries(relinkableAliasPropertyDeclarations,
+ propertyDeclarationIds,
+ PropertyCompare<AliasPropertyDeclaration>{});
+}
+
+void ProjectStorage::handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId,
+ TypeId prototypeId,
+ Prototypes &relinkablePrototypes)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId),
+ keyValue("type id", prototypeId)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
+ if (prototypeNameId)
+ relinkablePrototypes.emplace_back(typeId, prototypeNameId);
+ };
+
+ s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement.readCallback(callback,
+ prototypeId,
+ sourceId);
+}
+
+void ProjectStorage::handlePrototypesAndExtensionsWithSourceId(SourceId sourceId,
+ TypeId prototypeId,
+ TypeId extensionId,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle prototypes with source id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId),
+ keyValue("prototype id", prototypeId),
+ keyValue("extension id", extensionId)};
+
+ auto callback =
+ [&](TypeId typeId, ImportedTypeNameId prototypeNameId, ImportedTypeNameId extensionNameId) {
+ if (prototypeNameId)
+ relinkablePrototypes.emplace_back(typeId, prototypeNameId);
+ if (extensionNameId)
+ relinkableExtensions.emplace_back(typeId, extensionNameId);
+ };
+
+ s->updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement.readCallback(callback,
+ sourceId,
+ prototypeId,
+ extensionId);
+}
+
+void ProjectStorage::handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId,
+ TypeId extensionId,
+ Prototypes &relinkableExtensions)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t,
+ projectStorageCategory(),
+ keyValue("source id", sourceId),
+ keyValue("type id", extensionId)};
+
+ auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
+ if (extensionNameId)
+ relinkableExtensions.emplace_back(typeId, extensionNameId);
+ };
+
+ s->selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement.readCallback(callback,
+ extensionId,
+ sourceId);
+}
+
+ImportId ProjectStorage::insertDocumentImport(const Storage::Import &import,
+ Storage::Synchronization::ImportKind importKind,
+ ModuleId sourceModuleId,
+ ImportId parentImportId,
+ Relink relink,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ if (relink == Relink::Yes) {
+ handlePrototypesWithSourceIdAndPrototypeId(import.sourceId,
+ unresolvedTypeId,
+ relinkablePrototypes);
+ handleExtensionsWithSourceIdAndExtensionId(import.sourceId,
+ unresolvedTypeId,
+ relinkableExtensions);
+ }
+
+ if (import.version.minor) {
+ return s->insertDocumentImportWithVersionStatement.value<ImportId>(import.sourceId,
+ import.moduleId,
+ sourceModuleId,
+ importKind,
+ import.version.major.value,
+ import.version.minor.value,
+ parentImportId);
+ } else if (import.version.major) {
+ return s->insertDocumentImportWithMajorVersionStatement.value<ImportId>(import.sourceId,
+ import.moduleId,
+ sourceModuleId,
+ importKind,
+ import.version.major.value,
+ parentImportId);
+ } else {
+ return s->insertDocumentImportWithoutVersionStatement.value<ImportId>(import.sourceId,
+ import.moduleId,
+ sourceModuleId,
+ importKind,
+ parentImportId);
+ }
+}
+
+void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports,
+ const SourceIds &updatedSourceIds,
+ Storage::Synchronization::ImportKind importKind,
+ Relink relink,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
+ return std::tie(first.sourceId, first.moduleId, first.version)
+ < std::tie(second.sourceId, second.moduleId, second.version);
+ });
+
+ auto range = s->selectDocumentImportForSourceIdStatement
+ .range<Storage::Synchronization::ImportView>(toIntegers(updatedSourceIds),
+ importKind);
+
+ auto compareKey = [](const Storage::Synchronization::ImportView &view,
+ const Storage::Import &import) -> long long {
+ auto sourceIdDifference = view.sourceId - import.sourceId;
+ if (sourceIdDifference != 0)
+ return sourceIdDifference;
+
+ auto moduleIdDifference = view.moduleId - import.moduleId;
+ if (moduleIdDifference != 0)
+ return moduleIdDifference;
+
+ auto versionDifference = view.version.major.value - import.version.major.value;
+ if (versionDifference != 0)
+ return versionDifference;
+
+ return view.version.minor.value - import.version.minor.value;
+ };
+
+ auto insert = [&](const Storage::Import &import) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert import"_t,
+ projectStorageCategory(),
+ keyValue("import", import),
+ keyValue("import kind", importKind),
+ keyValue("source id", import.sourceId),
+ keyValue("module id", import.moduleId)};
+
+ auto importId = insertDocumentImport(import,
+ importKind,
+ import.moduleId,
+ ImportId{},
+ relink,
+ relinkablePrototypes,
+ relinkableExtensions);
+ auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) {
+ Storage::Import additionImport{exportedModuleId,
+ Storage::Version{majorVersion, minorVersion},
+ import.sourceId};
+
+ auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import
+ ? Storage::Synchronization::ImportKind::ModuleExportedImport
+ : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency;
+
+ NanotraceHR::Tracer tracer{"insert indirect import"_t,
+ projectStorageCategory(),
+ keyValue("import", import),
+ keyValue("import kind", exportedImportKind),
+ keyValue("source id", import.sourceId),
+ keyValue("module id", import.moduleId)};
+
+ auto indirectImportId = insertDocumentImport(additionImport,
+ exportedImportKind,
+ import.moduleId,
+ importId,
+ relink,
+ relinkablePrototypes,
+ relinkableExtensions);
+
+ tracer.end(keyValue("import id", indirectImportId));
+ };
+
+ s->selectModuleExportedImportsForModuleIdStatement.readCallback(callback,
+ import.moduleId,
+ import.version.major.value,
+ import.version.minor.value);
+ tracer.end(keyValue("import id", importId));
+ };
+
+ auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) {
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const Storage::Synchronization::ImportView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove import"_t,
+ projectStorageCategory(),
+ keyValue("import", view),
+ keyValue("import id", view.importId),
+ keyValue("source id", view.sourceId),
+ keyValue("module id", view.moduleId)};
+
+ s->deleteDocumentImportStatement.write(view.importId);
+ s->deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId);
+ if (relink == Relink::Yes) {
+ handlePrototypesAndExtensionsWithSourceId(view.sourceId,
+ unresolvedTypeId,
+ unresolvedTypeId,
+ relinkablePrototypes,
+ relinkableExtensions);
+ }
+ };
+
+ Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
+}
+
+Utils::PathString ProjectStorage::createJson(const Storage::Synchronization::ParameterDeclarations &parameters)
+{
+ NanotraceHR::Tracer tracer{"create json from parameter declarations"_t, projectStorageCategory()};
+
+ Utils::PathString json;
+ json.append("[");
+
+ Utils::SmallStringView comma{""};
+
+ for (const auto &parameter : parameters) {
+ json.append(comma);
+ comma = ",";
+ json.append(R"({"n":")");
+ json.append(parameter.name);
+ json.append(R"(","tn":")");
+ json.append(parameter.typeName);
+ if (parameter.traits == Storage::PropertyDeclarationTraits::None) {
+ json.append("\"}");
+ } else {
+ json.append(R"(","tr":)");
+ json.append(Utils::SmallString::number(Utils::to_underlying(parameter.traits)));
+ json.append("}");
+ }
+ }
+
+ json.append("]");
+
+ return json;
+}
+
+TypeId ProjectStorage::fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId,
+ Utils::SmallStringView name) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type id by module id and exported name"_t,
+ projectStorageCategory(),
+ keyValue("module id", moduleId),
+ keyValue("exported name", name)};
+
+ return s->selectTypeIdByModuleIdAndExportedNameStatement.value<TypeId>(moduleId, name);
+}
+
+void ProjectStorage::addTypeIdToPropertyEditorQmlPaths(
+ Storage::Synchronization::PropertyEditorQmlPaths &paths)
+{
+ NanotraceHR::Tracer tracer{"add type id to property editor qml paths"_t, projectStorageCategory()};
+
+ for (auto &path : paths)
+ path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName);
+}
+
+void ProjectStorage::synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths,
+ SourceIds updatedPropertyEditorQmlPathsSourceIds)
+{
+ using Storage::Synchronization::PropertyEditorQmlPath;
+ std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) {
+ return first.typeId < second.typeId;
+ });
+
+ auto range = s->selectPropertyEditorPathsForForSourceIdsStatement.range<PropertyEditorQmlPathView>(
+ toIntegers(updatedPropertyEditorQmlPathsSourceIds));
+
+ auto compareKey = [](const PropertyEditorQmlPathView &view,
+ const PropertyEditorQmlPath &value) -> long long {
+ return view.typeId - value.typeId;
+ };
+
+ auto insert = [&](const PropertyEditorQmlPath &path) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert property editor paths"_t,
+ projectStorageCategory(),
+ keyValue("property editor qml path", path)};
+
+ if (path.typeId)
+ s->insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId);
+ };
+
+ auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update property editor paths"_t,
+ projectStorageCategory(),
+ keyValue("property editor qml path", value),
+ keyValue("property editor qml path view", view)};
+
+ if (value.pathId != view.pathId || value.directoryId != view.directoryId) {
+ s->updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId);
+
+ tracer.end(keyValue("updated", "yes"));
+
+ return Sqlite::UpdateChange::Update;
+ }
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const PropertyEditorQmlPathView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove property editor paths"_t,
+ projectStorageCategory(),
+ keyValue("property editor qml path view", view)};
+
+ s->deletePropertyEditorPathStatement.write(view.typeId);
+ };
+
+ Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizePropertyEditorQmlPaths(
+ Storage::Synchronization::PropertyEditorQmlPaths &paths,
+ SourceIds updatedPropertyEditorQmlPathsSourceIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t, projectStorageCategory()};
+
+ addTypeIdToPropertyEditorQmlPaths(paths);
+ synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds);
+}
+
+void ProjectStorage::synchronizeFunctionDeclarations(
+ TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations)
+{
+ NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()};
+
+ std::sort(functionsDeclarations.begin(),
+ functionsDeclarations.end(),
+ [](auto &&first, auto &&second) {
+ auto compare = Sqlite::compare(first.name, second.name);
+
+ if (compare == 0) {
+ Utils::PathString firstSignature{createJson(first.parameters)};
+ Utils::PathString secondSignature{createJson(second.parameters)};
+
+ return Sqlite::compare(firstSignature, secondSignature) < 0;
+ }
+
+ return compare < 0;
+ });
+
+ auto range = s->selectFunctionDeclarationsForTypeIdStatement
+ .range<Storage::Synchronization::FunctionDeclarationView>(typeId);
+
+ auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view,
+ const Storage::Synchronization::FunctionDeclaration &value) {
+ auto nameKey = Sqlite::compare(view.name, value.name);
+ if (nameKey != 0)
+ return nameKey;
+
+ Utils::PathString valueSignature{createJson(value.parameters)};
+
+ return Sqlite::compare(view.signature, valueSignature);
+ };
+
+ auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert function declaration"_t,
+ projectStorageCategory(),
+ keyValue("function declaration", value)};
+
+ Utils::PathString signature{createJson(value.parameters)};
+
+ s->insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature);
+ };
+
+ auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view,
+ const Storage::Synchronization::FunctionDeclaration &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update function declaration"_t,
+ projectStorageCategory(),
+ keyValue("function declaration", value),
+ keyValue("function declaration view", view)};
+
+ Utils::PathString signature{createJson(value.parameters)};
+
+ if (value.returnTypeName == view.returnTypeName && signature == view.signature)
+ return Sqlite::UpdateChange::No;
+
+ s->updateFunctionDeclarationStatement.write(view.id, value.returnTypeName, signature);
+
+ tracer.end(keyValue("updated", "yes"));
+
+ return Sqlite::UpdateChange::Update;
+ };
+
+ auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove function declaration"_t,
+ projectStorageCategory(),
+ keyValue("function declaration view", view)};
+
+ s->deleteFunctionDeclarationStatement.write(view.id);
+ };
+
+ Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::synchronizeSignalDeclarations(
+ TypeId typeId, Storage::Synchronization::SignalDeclarations &signalDeclarations)
+{
+ NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()};
+
+ std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) {
+ auto compare = Sqlite::compare(first.name, second.name);
+
+ if (compare == 0) {
+ Utils::PathString firstSignature{createJson(first.parameters)};
+ Utils::PathString secondSignature{createJson(second.parameters)};
+
+ return Sqlite::compare(firstSignature, secondSignature) < 0;
+ }
+
+ return compare < 0;
+ });
+
+ auto range = s->selectSignalDeclarationsForTypeIdStatement
+ .range<Storage::Synchronization::SignalDeclarationView>(typeId);
+
+ auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view,
+ const Storage::Synchronization::SignalDeclaration &value) {
+ auto nameKey = Sqlite::compare(view.name, value.name);
+ if (nameKey != 0)
+ return nameKey;
+
+ Utils::PathString valueSignature{createJson(value.parameters)};
+
+ return Sqlite::compare(view.signature, valueSignature);
+ };
+
+ auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert signal declaration"_t,
+ projectStorageCategory(),
+ keyValue("signal declaration", value)};
+
+ Utils::PathString signature{createJson(value.parameters)};
+
+ s->insertSignalDeclarationStatement.write(typeId, value.name, signature);
+ };
+
+ auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view,
+ [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) {
+ return Sqlite::UpdateChange::No;
+ };
+
+ auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove signal declaration"_t,
+ projectStorageCategory(),
+ keyValue("signal declaration view", view)};
+
+ s->deleteSignalDeclarationStatement.write(view.id);
+ };
+
+ Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove);
+}
+
+Utils::PathString ProjectStorage::createJson(
+ const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"create json from enumerator declarations"_t, projectStorageCategory()};
+
+ Utils::PathString json;
+ json.append("{");
+
+ Utils::SmallStringView comma{"\""};
+
+ for (const auto &enumerator : enumeratorDeclarations) {
+ json.append(comma);
+ comma = ",\"";
+ json.append(enumerator.name);
+ if (enumerator.hasValue) {
+ json.append("\":\"");
+ json.append(Utils::SmallString::number(enumerator.value));
+ json.append("\"");
+ } else {
+ json.append("\":null");
+ }
+ }
+
+ json.append("}");
+
+ return json;
+}
+
+void ProjectStorage::synchronizeEnumerationDeclarations(
+ TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations)
+{
+ NanotraceHR::Tracer tracer{"synchronize enumeration declaration"_t, projectStorageCategory()};
+
+ std::sort(enumerationDeclarations.begin(),
+ enumerationDeclarations.end(),
+ [](auto &&first, auto &&second) {
+ return Sqlite::compare(first.name, second.name) < 0;
+ });
+
+ auto range = s->selectEnumerationDeclarationsForTypeIdStatement
+ .range<Storage::Synchronization::EnumerationDeclarationView>(typeId);
+
+ auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view,
+ const Storage::Synchronization::EnumerationDeclaration &value) {
+ return Sqlite::compare(view.name, value.name);
+ };
+
+ auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"insert enumeration declaration"_t,
+ projectStorageCategory(),
+ keyValue("enumeration declaration", value)};
+
+ Utils::PathString signature{createJson(value.enumeratorDeclarations)};
+
+ s->insertEnumerationDeclarationStatement.write(typeId, value.name, signature);
+ };
+
+ auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view,
+ const Storage::Synchronization::EnumerationDeclaration &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"update enumeration declaration"_t,
+ projectStorageCategory(),
+ keyValue("enumeration declaration", value),
+ keyValue("enumeration declaration view", view)};
+
+ Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)};
+
+ if (enumeratorDeclarations == view.enumeratorDeclarations)
+ return Sqlite::UpdateChange::No;
+
+ s->updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations);
+
+ tracer.end(keyValue("updated", "yes"));
+
+ return Sqlite::UpdateChange::Update;
+ };
+
+ auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"remove enumeration declaration"_t,
+ projectStorageCategory(),
+ keyValue("enumeration declaration view", view)};
+
+ s->deleteEnumerationDeclarationStatement.write(view.id);
+ };
+
+ Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::extractExportedTypes(TypeId typeId,
+ const Storage::Synchronization::Type &type,
+ Storage::Synchronization::ExportedTypes &exportedTypes)
+{
+ for (const auto &exportedType : type.exportedTypes)
+ exportedTypes.emplace_back(exportedType.name, exportedType.version, typeId, exportedType.moduleId);
+}
+
+TypeId ProjectStorage::declareType(Storage::Synchronization::Type &type)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"declare type"_t,
+ projectStorageCategory(),
+ keyValue("source id", type.sourceId),
+ keyValue("type name", type.typeName)};
+
+ if (type.typeName.isEmpty()) {
+ type.typeId = s->selectTypeIdBySourceIdStatement.value<TypeId>(type.sourceId);
+
+ tracer.end(keyValue("type id", type.typeId));
+
+ return type.typeId;
+ }
+
+ type.typeId = s->insertTypeStatement.value<TypeId>(type.sourceId, type.typeName);
+
+ if (!type.typeId)
+ type.typeId = s->selectTypeIdBySourceIdAndNameStatement.value<TypeId>(type.sourceId,
+ type.typeName);
+
+ tracer.end(keyValue("type id", type.typeId));
+
+ return type.typeId;
+}
+
+void ProjectStorage::syncDeclarations(Storage::Synchronization::Type &type,
+ AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
+ PropertyDeclarationIds &propertyDeclarationIds)
+{
+ NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()};
+
+ if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
+ return;
+
+ synchronizePropertyDeclarations(type.typeId,
+ type.propertyDeclarations,
+ type.sourceId,
+ insertedAliasPropertyDeclarations,
+ updatedAliasPropertyDeclarations,
+ propertyDeclarationIds);
+ synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations);
+ synchronizeSignalDeclarations(type.typeId, type.signalDeclarations);
+ synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations);
+}
+
+void ProjectStorage::syncDeclarations(Storage::Synchronization::Types &types,
+ AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
+ AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
+ PropertyDeclarations &relinkablePropertyDeclarations)
+{
+ NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()};
+
+ PropertyDeclarationIds propertyDeclarationIds;
+ propertyDeclarationIds.reserve(types.size() * 10);
+
+ for (auto &&type : types)
+ syncDeclarations(type,
+ insertedAliasPropertyDeclarations,
+ updatedAliasPropertyDeclarations,
+ propertyDeclarationIds);
+
+ removeRelinkableEntries(relinkablePropertyDeclarations,
+ propertyDeclarationIds,
+ PropertyCompare<PropertyDeclaration>{});
+}
+
+void ProjectStorage::syncDefaultProperties(Storage::Synchronization::Types &types)
+{
+ NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()};
+
+ auto range = s->selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>();
+
+ auto compareKey = [](const TypeWithDefaultPropertyView &view,
+ const Storage::Synchronization::Type &value) {
+ return view.typeId - value.typeId;
+ };
+
+ auto insert = [&](const Storage::Synchronization::Type &) {
+
+ };
+
+ auto update = [&](const TypeWithDefaultPropertyView &view,
+ const Storage::Synchronization::Type &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"synchronize default properties by update"_t,
+ projectStorageCategory(),
+ keyValue("type id", value.typeId),
+ keyValue("value", value),
+ keyValue("view", view)};
+
+ PropertyDeclarationId valueDefaultPropertyId;
+ if (value.defaultPropertyName.size())
+ valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded(value.typeId,
+ value.defaultPropertyName)
+ .propertyDeclarationId;
+
+ if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId))
+ return Sqlite::UpdateChange::No;
+
+ s->updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId);
+
+ tracer.end(keyValue("updated", "yes"),
+ keyValue("default property id", valueDefaultPropertyId));
+
+ return Sqlite::UpdateChange::Update;
+ };
+
+ auto remove = [&](const TypeWithDefaultPropertyView &) {};
+
+ Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types)
+{
+ NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()};
+
+ auto range = s->selectTypesWithDefaultPropertyStatement.range<TypeWithDefaultPropertyView>();
+
+ auto compareKey = [](const TypeWithDefaultPropertyView &view,
+ const Storage::Synchronization::Type &value) {
+ return view.typeId - value.typeId;
+ };
+
+ auto insert = [&](const Storage::Synchronization::Type &) {
+
+ };
+
+ auto update = [&](const TypeWithDefaultPropertyView &view,
+ const Storage::Synchronization::Type &value) {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"reset changed default properties by update"_t,
+ projectStorageCategory(),
+ keyValue("type id", value.typeId),
+ keyValue("value", value),
+ keyValue("view", view)};
+
+ PropertyDeclarationId valueDefaultPropertyId;
+ if (value.defaultPropertyName.size()) {
+ auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(
+ value.typeId, value.defaultPropertyName);
+ if (optionalValueDefaultPropertyId)
+ valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId;
+ }
+
+ if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId))
+ return Sqlite::UpdateChange::No;
+
+ s->updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{});
+
+ tracer.end(keyValue("updated", "yes"));
+
+ return Sqlite::UpdateChange::Update;
+ };
+
+ auto remove = [&](const TypeWithDefaultPropertyView &) {};
+
+ Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove);
+}
+
+void ProjectStorage::checkForPrototypeChainCycle(TypeId typeId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"check for prototype chain cycle"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto callback = [=](TypeId currentTypeId) {
+ if (typeId == currentTypeId)
+ throw PrototypeChainCycle{};
+ };
+
+ s->selectPrototypeAndExtensionIdsStatement.readCallback(callback, typeId);
+}
+
+void ProjectStorage::checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"check for alias chain cycle"_t,
+ projectStorageCategory(),
+ keyValue("property declaration id", propertyDeclarationId)};
+ auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) {
+ if (propertyDeclarationId == currentPropertyDeclarationId)
+ throw AliasChainCycle{};
+ };
+
+ s->selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback,
+ propertyDeclarationId);
+}
+
+std::pair<TypeId, ImportedTypeNameId> ProjectStorage::fetchImportedTypeNameIdAndTypeId(
+ const Storage::Synchronization::ImportedTypeName &importedTypeName, SourceId sourceId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch imported type name id and type id"_t,
+ projectStorageCategory(),
+ keyValue("imported type name", importedTypeName),
+ keyValue("source id", sourceId)};
+
+ TypeId typeId;
+ ImportedTypeNameId typeNameId;
+ auto typeName = std::visit([](auto &&importedTypeName) { return importedTypeName.name; },
+ importedTypeName);
+ if (!typeName.empty()) {
+ typeNameId = fetchImportedTypeNameId(importedTypeName, sourceId);
+
+ typeId = fetchTypeId(typeNameId);
+
+ tracer.end(keyValue("type id", typeId), keyValue("type name id", typeNameId));
+
+ if (!typeId) {
+ errorNotifier->typeNameCannotBeResolved(typeName, sourceId);
+ return {unresolvedTypeId, typeNameId};
+ }
+ }
+
+ return {typeId, typeNameId};
+}
+
+void ProjectStorage::syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds)
+{
+ if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
+ return;
+
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"synchronize prototype and extension"_t,
+ projectStorageCategory(),
+ keyValue("prototype", type.prototype),
+ keyValue("extension", type.extension),
+ keyValue("type id", type.typeId),
+ keyValue("source id", type.sourceId)};
+
+ auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype,
+ type.sourceId);
+ auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension,
+ type.sourceId);
+
+ s->updatePrototypeAndExtensionStatement.write(type.typeId,
+ prototypeId,
+ prototypeTypeNameId,
+ extensionId,
+ extensionTypeNameId);
+
+ if (prototypeId || extensionId)
+ checkForPrototypeChainCycle(type.typeId);
+
+ typeIds.push_back(type.typeId);
+
+ tracer.end(keyValue("prototype id", prototypeId),
+ keyValue("prototype type name id", prototypeTypeNameId),
+ keyValue("extension id", extensionId),
+ keyValue("extension type name id", extensionTypeNameId));
+}
+
+void ProjectStorage::syncPrototypesAndExtensions(Storage::Synchronization::Types &types,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions)
+{
+ NanotraceHR::Tracer tracer{"synchronize prototypes and extensions"_t, projectStorageCategory()};
+
+ TypeIds typeIds;
+ typeIds.reserve(types.size());
+
+ for (auto &type : types)
+ syncPrototypeAndExtension(type, typeIds);
+
+ removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{});
+ removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{});
+}
+
+ImportId ProjectStorage::fetchImportId(SourceId sourceId, const Storage::Import &import) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch imported type name id"_t,
+ projectStorageCategory(),
+ keyValue("import", import),
+ keyValue("source id", sourceId)};
+
+ ImportId importId;
+ if (import.version) {
+ importId = s->selectImportIdBySourceIdAndModuleIdAndVersionStatement.value<ImportId>(
+ sourceId, import.moduleId, import.version.major.value, import.version.minor.value);
+ } else if (import.version.major) {
+ importId = s->selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement
+ .value<ImportId>(sourceId, import.moduleId, import.version.major.value);
+ } else {
+ importId = s->selectImportIdBySourceIdAndModuleIdStatement.value<ImportId>(sourceId,
+ import.moduleId);
+ }
+
+ tracer.end(keyValue("import id", importId));
+
+ return importId;
+}
+
+ImportedTypeNameId ProjectStorage::fetchImportedTypeNameId(
+ const Storage::Synchronization::ImportedTypeName &name, SourceId sourceId)
+{
+ struct Inspect
+ {
+ auto operator()(const Storage::Synchronization::ImportedType &importedType)
+ {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch imported type name id"_t,
+ projectStorageCategory(),
+ keyValue("imported type name", importedType.name),
+ keyValue("source id", sourceId),
+ keyValue("type name kind", "exported"sv)};
+
+ return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported,
+ sourceId,
+ importedType.name);
+ }
+
+ auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType)
+ {
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch imported type name id"_t,
+ projectStorageCategory(),
+ keyValue("imported type name", importedType.name),
+ keyValue("import", importedType.import),
+ keyValue("type name kind", "qualified exported"sv)};
+
+ ImportId importId = storage.fetchImportId(sourceId, importedType.import);
+
+ auto importedTypeNameId = storage.fetchImportedTypeNameId(
+ Storage::Synchronization::TypeNameKind::QualifiedExported, importId, importedType.name);
+
+ tracer.end(keyValue("import id", importId), keyValue("source id", sourceId));
+
+ return importedTypeNameId;
+ }
+
+ ProjectStorage &storage;
+ SourceId sourceId;
+ };
+
+ return std::visit(Inspect{*this, sourceId}, name);
+}
+
+TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type id with type name kind"_t,
+ projectStorageCategory(),
+ keyValue("type name id", typeNameId)};
+
+ auto kind = s->selectKindFromImportedTypeNamesStatement.value<Storage::Synchronization::TypeNameKind>(
+ typeNameId);
+
+ auto typeId = fetchTypeId(typeNameId, kind);
+
+ tracer.end(keyValue("type id", typeId), keyValue("type name kind", kind));
+
+ return typeId;
+}
+
+Utils::SmallString ProjectStorage::fetchImportedTypeName(ImportedTypeNameId typeNameId) const
+{
+ return s->selectNameFromImportedTypeNamesStatement.value<Utils::SmallString>(typeNameId);
+}
+
+SourceId ProjectStorage::fetchTypeSourceId(TypeId typeId) const
+{
+ return s->selectSourceIdByTypeIdStatement.value<SourceId>(typeId);
+}
+
+TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId,
+ Storage::Synchronization::TypeNameKind kind) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch type id"_t,
+ projectStorageCategory(),
+ keyValue("type name id", typeNameId),
+ keyValue("type name kind", kind)};
+
+ TypeId typeId;
+ if (kind == Storage::Synchronization::TypeNameKind::Exported) {
+ typeId = s->selectTypeIdForImportedTypeNameNamesStatement.value<UnresolvedTypeId>(typeNameId);
+ } else {
+ typeId = s->selectTypeIdForQualifiedImportedTypeNameNamesStatement.value<UnresolvedTypeId>(
+ typeNameId);
+ }
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
+}
+
+std::optional<ProjectStorage::FetchPropertyDeclarationResult>
+ProjectStorage::fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId,
+ Utils::SmallStringView name)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch optional property declaration by type id and name ungarded"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("property name", name)};
+
+ auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name);
+ auto propertyDeclaration = s->selectPropertyDeclarationResultByPropertyDeclarationIdStatement
+ .optionalValue<FetchPropertyDeclarationResult>(
+ propertyDeclarationId);
+
+ tracer.end(keyValue("property declaration", propertyDeclaration));
+
+ return propertyDeclaration;
+}
+
+ProjectStorage::FetchPropertyDeclarationResult ProjectStorage::fetchPropertyDeclarationByTypeIdAndNameUngarded(
+ TypeId typeId, Utils::SmallStringView name)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch property declaration by type id and name ungarded"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("property name", name)};
+
+ auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, name);
+ tracer.end(keyValue("property declaration", propertyDeclaration));
+
+ if (propertyDeclaration)
+ return *propertyDeclaration;
+
+ throw PropertyNameDoesNotExists{};
+}
+
+PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationIdByTypeIdAndNameUngarded(
+ TypeId typeId, Utils::SmallStringView name)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch property declaration id by type id and name ungarded"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("property name", name)};
+
+ auto propertyDeclarationId = fetchPropertyDeclarationId(typeId, name);
+
+ tracer.end(keyValue("property declaration id", propertyDeclarationId));
+
+ if (propertyDeclarationId)
+ return propertyDeclarationId;
+
+ throw PropertyNameDoesNotExists{};
+}
+
+SourceContextId ProjectStorage::readSourceContextId(Utils::SmallStringView sourceContextPath)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"read source context id"_t,
+ projectStorageCategory(),
+ keyValue("source context path", sourceContextPath)};
+
+ auto sourceContextId = s->selectSourceContextIdFromSourceContextsBySourceContextPathStatement
+ .value<SourceContextId>(sourceContextPath);
+
+ tracer.end(keyValue("source context id", sourceContextId));
+
+ return sourceContextId;
+}
+
+SourceContextId ProjectStorage::writeSourceContextId(Utils::SmallStringView sourceContextPath)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"write source context id"_t,
+ projectStorageCategory(),
+ keyValue("source context path", sourceContextPath)};
+
+ s->insertIntoSourceContextsStatement.write(sourceContextPath);
+
+ auto sourceContextId = SourceContextId::create(static_cast<int>(database.lastInsertedRowId()));
+
+ tracer.end(keyValue("source context id", sourceContextId));
+
+ return sourceContextId;
+}
+
+SourceId ProjectStorage::writeSourceId(SourceContextId sourceContextId,
+ Utils::SmallStringView sourceName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"write source id"_t,
+ projectStorageCategory(),
+ keyValue("source context id", sourceContextId),
+ keyValue("source name", sourceName)};
+
+ s->insertIntoSourcesStatement.write(sourceContextId, sourceName);
+
+ auto sourceId = SourceId::create(static_cast<int>(database.lastInsertedRowId()));
+
+ tracer.end(keyValue("source id", sourceId));
+
+ return sourceId;
+}
+
+SourceId ProjectStorage::readSourceId(SourceContextId sourceContextId,
+ Utils::SmallStringView sourceName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"read source id"_t,
+ projectStorageCategory(),
+ keyValue("source context id", sourceContextId),
+ keyValue("source name", sourceName)};
+
+ auto sourceId = s->selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement
+ .value<SourceId>(sourceContextId, sourceName);
+
+ tracer.end(keyValue("source id", sourceId));
+
+ return sourceId;
+}
+
+Storage::Synchronization::ExportedTypes ProjectStorage::fetchExportedTypes(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch exported type"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto exportedTypes = s->selectExportedTypesByTypeIdStatement
+ .values<Storage::Synchronization::ExportedType, 12>(typeId);
+
+ tracer.end(keyValue("exported types", exportedTypes));
+
+ return exportedTypes;
+}
+
+Storage::Synchronization::PropertyDeclarations ProjectStorage::fetchPropertyDeclarations(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch property declarations"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ auto propertyDeclarations = s->selectPropertyDeclarationsByTypeIdStatement
+ .values<Storage::Synchronization::PropertyDeclaration, 24>(typeId);
+
+ tracer.end(keyValue("property declarations", propertyDeclarations));
+
+ return propertyDeclarations;
+}
+
+Storage::Synchronization::FunctionDeclarations ProjectStorage::fetchFunctionDeclarations(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch signal declarations"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ Storage::Synchronization::FunctionDeclarations functionDeclarations;
+
+ auto callback = [&](Utils::SmallStringView name,
+ Utils::SmallStringView returnType,
+ FunctionDeclarationId functionDeclarationId) {
+ auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType);
+ functionDeclaration.parameters = s->selectFunctionParameterDeclarationsStatement
+ .values<Storage::Synchronization::ParameterDeclaration, 8>(
+ functionDeclarationId);
+ };
+
+ s->selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId);
+
+ tracer.end(keyValue("function declarations", functionDeclarations));
+
+ return functionDeclarations;
+}
+
+Storage::Synchronization::SignalDeclarations ProjectStorage::fetchSignalDeclarations(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch signal declarations"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ Storage::Synchronization::SignalDeclarations signalDeclarations;
+
+ auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) {
+ auto &signalDeclaration = signalDeclarations.emplace_back(name);
+ signalDeclaration.parameters = s->selectSignalParameterDeclarationsStatement
+ .values<Storage::Synchronization::ParameterDeclaration, 8>(
+ signalDeclarationId);
+ };
+
+ s->selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId);
+
+ tracer.end(keyValue("signal declarations", signalDeclarations));
+
+ return signalDeclarations;
+}
+
+Storage::Synchronization::EnumerationDeclarations ProjectStorage::fetchEnumerationDeclarations(TypeId typeId)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch enumeration declarations"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId)};
+
+ Storage::Synchronization::EnumerationDeclarations enumerationDeclarations;
+
+ auto callback = [&](Utils::SmallStringView name,
+ EnumerationDeclarationId enumerationDeclarationId) {
+ enumerationDeclarations.emplace_back(
+ name,
+ s->selectEnumeratorDeclarationStatement
+ .values<Storage::Synchronization::EnumeratorDeclaration, 8>(enumerationDeclarationId));
+ };
+
+ s->selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement
+ .readCallback(callback, typeId);
+
+ tracer.end(keyValue("enumeration declarations", enumerationDeclarations));
+
+ return enumerationDeclarations;
+}
+
+template<typename... TypeIds>
+bool ProjectStorage::isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"is based on"_t,
+ projectStorageCategory(),
+ keyValue("type id", typeId),
+ keyValue("base type ids", NanotraceHR::array(baseTypeIds...))};
+
+ static_assert(((std::is_same_v<TypeId, TypeIds>) &&...), "Parameter must be a TypeId!");
+
+ if (((typeId == baseTypeIds) || ...)) {
+ tracer.end(keyValue("is based on", true));
+ return true;
+ }
+
+ auto range = s->selectPrototypeAndExtensionIdsStatement.rangeWithTransaction<TypeId>(typeId);
+
+ auto isBasedOn = std::any_of(range.begin(), range.end(), [&](TypeId currentTypeId) {
+ return ((currentTypeId == baseTypeIds) || ...);
+ });
+
+ tracer.end(keyValue("is based on", isBasedOn));
+
+ return isBasedOn;
+}
+
+template<typename Id>
+ImportedTypeNameId ProjectStorage::fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind kind,
+ Id id,
+ Utils::SmallStringView typeName)
+{
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"fetch imported type name id"_t,
+ projectStorageCategory(),
+ keyValue("imported type name", typeName),
+ keyValue("kind", kind)};
+
+ auto importedTypeNameId = s->selectImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind,
+ id,
+ typeName);
+
+ if (!importedTypeNameId)
+ importedTypeNameId = s->insertImportedTypeNameIdStatement.value<ImportedTypeNameId>(kind,
+ id,
+ typeName);
+
+ tracer.end(keyValue("imported type name id", importedTypeNameId));
+
+ return importedTypeNameId;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
index a770577a65..54d9101596 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
@@ -4,11 +4,15 @@
#pragma once
#include "commontypecache.h"
+#include "projectstorageerrornotifier.h"
#include "projectstorageexceptions.h"
#include "projectstorageinterface.h"
+#include "projectstoragetypes.h"
#include "sourcepathcachetypes.h"
#include "storagecache.h"
+#include <tracing/qmldesignertracing.h>
+
#include <sqlitealgorithms.h>
#include <sqlitedatabase.h>
#include <sqlitetable.h>
@@ -28,516 +32,167 @@ namespace QmlDesigner {
using namespace NanotraceHR::Literals;
-constexpr NanotraceHR::Tracing projectStorageTracingStatus()
-{
-#ifdef ENABLE_PROJECT_STORAGE_TRACING
- return NanotraceHR::Tracing::IsEnabled;
-#else
- return NanotraceHR::Tracing::IsDisabled;
-#endif
-}
-
-[[gnu::pure]] NanotraceHR::StringViewCategory<projectStorageTracingStatus()> &projectStorageCategory();
+using ProjectStorageTracing::projectStorageCategory;
-template<typename Database>
class ProjectStorage final : public ProjectStorageInterface
{
- friend Storage::Info::CommonTypeCache<Database>;
-
-public:
- template<int ResultCount, int BindParameterCount = 0>
- using ReadStatement = typename Database::template ReadStatement<ResultCount, BindParameterCount>;
- template<int ResultCount, int BindParameterCount = 0>
- using ReadWriteStatement = typename Database::template ReadWriteStatement<ResultCount, BindParameterCount>;
- template<int BindParameterCount>
- using WriteStatement = typename Database::template WriteStatement<BindParameterCount>;
-
- ProjectStorage(Database &database, bool isInitialized)
- : database{database}
- , exclusiveTransaction{database}
- , initializer{database, isInitialized}
- {
- NanotraceHR::Tracer tracer{"initialize"_t, projectStorageCategory()};
+ using Database = Sqlite::Database;
+ friend Storage::Info::CommonTypeCache<ProjectStorageType>;
- exclusiveTransaction.commit();
+ enum class Relink { No, Yes };
- database.walCheckpointFull();
-
- moduleCache.populate();
- }
-
- void synchronize(Storage::Synchronization::SynchronizationPackage package) override
- {
- NanotraceHR::Tracer tracer{"synchronize"_t, projectStorageCategory()};
-
- TypeIds deletedTypeIds;
- Sqlite::withImmediateTransaction(database, [&] {
- AliasPropertyDeclarations insertedAliasPropertyDeclarations;
- AliasPropertyDeclarations updatedAliasPropertyDeclarations;
-
- AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
- PropertyDeclarations relinkablePropertyDeclarations;
- Prototypes relinkablePrototypes;
- Prototypes relinkableExtensions;
-
- 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);
- synchronizeTypeAnnotations(package.typeAnnotations,
- package.updatedTypeAnnotationSourceIds);
- synchronizePropertyEditorQmlPaths(package.propertyEditorQmlPaths,
- package.updatedPropertyEditorQmlPathSourceIds);
-
- 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();
- });
-
- callRefreshMetaInfoCallback(deletedTypeIds);
- }
+public:
+ ProjectStorage(Database &database,
+ ProjectStorageErrorNotifierInterface &errorNotifier,
+ bool isInitialized);
+ ~ProjectStorage();
- void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override
- {
- NanotraceHR::Tracer tracer{"synchronize document imports"_t, projectStorageCategory()};
+ void synchronize(Storage::Synchronization::SynchronizationPackage package) override;
- Sqlite::withImmediateTransaction(database, [&] {
- synchronizeDocumentImports(imports,
- {sourceId},
- Storage::Synchronization::ImportKind::Import);
- });
- }
+ void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override;
- void addObserver(ProjectStorageObserver *observer) override { observers.push_back(observer); }
-
- void removeObserver(ProjectStorageObserver *observer) override
+ void setErrorNotifier(ProjectStorageErrorNotifierInterface &errorNotifier)
{
- observers.removeOne(observer);
+ this->errorNotifier = &errorNotifier;
}
- ModuleId moduleId(Utils::SmallStringView moduleName) const override
- {
- NanotraceHR::Tracer tracer{"get module id"_t, projectStorageCategory()};
-
- return moduleCache.id(moduleName);
- }
+ void addObserver(ProjectStorageObserver *observer) override;
- Utils::SmallString moduleName(ModuleId moduleId) const
- {
- NanotraceHR::Tracer tracer{"get module name"_t, projectStorageCategory()};
+ void removeObserver(ProjectStorageObserver *observer) override;
- if (!moduleId)
- throw ModuleDoesNotExists{};
+ ModuleId moduleId(Utils::SmallStringView moduleName, Storage::ModuleKind kind) const override;
- return moduleCache.value(moduleId);
- }
+ Storage::Module module(ModuleId moduleId) const override;
TypeId typeId(ModuleId moduleId,
Utils::SmallStringView exportedTypeName,
- Storage::Version version) const override
- {
- NanotraceHR::Tracer tracer{"get type id by exported name"_t, projectStorageCategory()};
+ Storage::Version version) const override;
- if (version.minor)
- return selectTypeIdByModuleIdAndExportedNameAndVersionStatement
- .template valueWithTransaction<TypeId>(moduleId,
- exportedTypeName,
- version.major.value,
- version.minor.value);
+ TypeId typeId(ImportedTypeNameId typeNameId) const override;
- if (version.major)
- return selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement
- .template valueWithTransaction<TypeId>(moduleId, exportedTypeName, version.major.value);
+ QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override;
- return selectTypeIdByModuleIdAndExportedNameStatement
- .template valueWithTransaction<TypeId>(moduleId, exportedTypeName);
- }
-
- TypeId typeId(ImportedTypeNameId typeNameId) const override
- {
- NanotraceHR::Tracer tracer{"get type id by imported type name"_t, projectStorageCategory()};
-
- return Sqlite::withDeferredTransaction(database, [&] { return fetchTypeId(typeNameId); });
- }
-
- QVarLengthArray<TypeId, 256> typeIds(ModuleId moduleId) const override
- {
- NanotraceHR::Tracer tracer{"get type ids by module id"_t, projectStorageCategory()};
-
- return selectTypeIdsByModuleIdStatement
- .template valuesWithTransaction<QVarLengthArray<TypeId, 256>>(moduleId);
- }
-
- Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get exported type names by type id"_t, projectStorageCategory()};
+ Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId) const override;
- return selectExportedTypesByTypeIdStatement
- .template valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId);
- }
+ Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId, SourceId sourceId) const override;
- Storage::Info::ExportedTypeNames exportedTypeNames(TypeId typeId,
- SourceId sourceId) const override
- {
- NanotraceHR::Tracer tracer{"get exported type names by source id"_t, projectStorageCategory()};
-
- return selectExportedTypesByTypeIdAndSourceIdStatement
- .template valuesWithTransaction<Storage::Info::ExportedTypeName, 4>(typeId, sourceId);
- }
+ ImportId importId(const Storage::Import &import) const override;
- ImportId importId(const Storage::Import &import) const override
- {
- NanotraceHR::Tracer tracer{"get import id by import"_t, projectStorageCategory()};
+ ImportedTypeNameId importedTypeNameId(ImportId importId, Utils::SmallStringView typeName) override;
- return Sqlite::withDeferredTransaction(database, [&] {
- return fetchImportId(import.sourceId, import);
- });
- }
+ ImportedTypeNameId importedTypeNameId(SourceId sourceId, Utils::SmallStringView typeName) override;
- ImportedTypeNameId importedTypeNameId(ImportId importId,
- Utils::SmallStringView typeName) override
- {
- NanotraceHR::Tracer tracer{"get imported type name id by import id"_t,
- projectStorageCategory()};
+ QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override;
- return Sqlite::withDeferredTransaction(database, [&] {
- return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported,
- importId,
- typeName);
- });
- }
-
- ImportedTypeNameId importedTypeNameId(SourceId sourceId,
- Utils::SmallStringView typeName) override
- {
- NanotraceHR::Tracer tracer{"get imported type name id by source id"_t,
- projectStorageCategory()};
-
- return Sqlite::withDeferredTransaction(database, [&] {
- return fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported,
- sourceId,
- typeName);
- });
- }
-
- QVarLengthArray<PropertyDeclarationId, 128> propertyDeclarationIds(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get property declaration ids"_t, projectStorageCategory()};
-
- return selectPropertyDeclarationIdsForTypeStatement
- .template valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>(typeId);
- }
-
- QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get local property declaration ids"_t, projectStorageCategory()};
-
- return selectLocalPropertyDeclarationIdsForTypeStatement
- .template valuesWithTransaction<QVarLengthArray<PropertyDeclarationId, 128>>(typeId);
- }
+ QVarLengthArray<PropertyDeclarationId, 128> localPropertyDeclarationIds(TypeId typeId) const override;
PropertyDeclarationId propertyDeclarationId(TypeId typeId,
- Utils::SmallStringView propertyName) const override
- {
- NanotraceHR::Tracer tracer{"get property declaration id"_t, projectStorageCategory()};
-
- return selectPropertyDeclarationIdForTypeAndPropertyNameStatement
- .template valueWithTransaction<PropertyDeclarationId>(typeId, propertyName);
- }
+ Utils::SmallStringView propertyName) const override;
PropertyDeclarationId localPropertyDeclarationId(TypeId typeId,
- Utils::SmallStringView propertyName) const
- {
- NanotraceHR::Tracer tracer{"get local property declaration id"_t, projectStorageCategory()};
+ Utils::SmallStringView propertyName) const;
- return selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement
- .template valueWithTransaction<PropertyDeclarationId>(typeId, propertyName);
- }
+ PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const override;
std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration(
- PropertyDeclarationId propertyDeclarationId) const override
- {
- NanotraceHR::Tracer tracer{"get property declaration"_t, projectStorageCategory()};
-
- return selectPropertyDeclarationForPropertyDeclarationIdStatement
- .template optionalValueWithTransaction<Storage::Info::PropertyDeclaration>(
- propertyDeclarationId);
- }
-
- std::optional<Storage::Info::Type> type(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get type"_t, projectStorageCategory()};
-
- return selectInfoTypeByTypeIdStatement.template optionalValueWithTransaction<Storage::Info::Type>(
- typeId);
- }
+ PropertyDeclarationId propertyDeclarationId) const override;
- Utils::PathString typeIconPath(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get type icon path"_t, projectStorageCategory()};
-
- return selectTypeIconPathStatement.template valueWithTransaction<Utils::PathString>(typeId);
- }
-
- Storage::Info::TypeHints typeHints(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get type hints"_t, projectStorageCategory()};
+ std::optional<Storage::Info::Type> type(TypeId typeId) const override;
- return selectTypeHintsStatement.template valuesWithTransaction<Storage::Info::TypeHints, 4>(
- typeId);
- }
+ Utils::PathString typeIconPath(TypeId typeId) const override;
- Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get item library entries by type id"_t, projectStorageCategory()};
-
- using Storage::Info::ItemLibraryProperties;
- Storage::Info::ItemLibraryEntries entries;
-
- auto callback = [&](TypeId typeId_,
- Utils::SmallStringView name,
- Utils::SmallStringView iconPath,
- Utils::SmallStringView category,
- Utils::SmallStringView import,
- Utils::SmallStringView toolTip,
- Utils::SmallStringView properties,
- Utils::SmallStringView extraFilePaths,
- Utils::SmallStringView templatePath) {
- auto &last = entries.emplace_back(
- typeId_, name, iconPath, category, import, toolTip, templatePath);
- if (properties.size())
- selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
- if (extraFilePaths.size())
- selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
- };
-
- selectItemLibraryEntriesByTypeIdStatement.readCallbackWithTransaction(callback, typeId);
-
- return entries;
- }
+ Storage::Info::TypeHints typeHints(TypeId typeId) const override;
- Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override
- {
- NanotraceHR::Tracer tracer{"get item library entries by source id"_t,
- projectStorageCategory()};
+ SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const override;
- using Storage::Info::ItemLibraryProperties;
- Storage::Info::ItemLibraryEntries entries;
-
- auto callback = [&](TypeId typeId,
- Utils::SmallStringView name,
- Utils::SmallStringView iconPath,
- Utils::SmallStringView category,
- Utils::SmallStringView import,
- Utils::SmallStringView toolTip,
- Utils::SmallStringView properties,
- Utils::SmallStringView extraFilePaths,
- Utils::SmallStringView templatePath) {
- auto &last = entries.emplace_back(
- typeId, name, iconPath, category, import, toolTip, templatePath);
- if (properties.size())
- selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
- if (extraFilePaths.size())
- selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
- };
-
- selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId);
-
- return entries;
- }
+ SmallSourceIds<64> typeAnnotationDirectorySourceIds() const override;
- Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override
- {
- NanotraceHR::Tracer tracer{"get all item library entries"_t, projectStorageCategory()};
-
- using Storage::Info::ItemLibraryProperties;
- Storage::Info::ItemLibraryEntries entries;
-
- auto callback = [&](TypeId typeId,
- Utils::SmallStringView name,
- Utils::SmallStringView iconPath,
- Utils::SmallStringView category,
- Utils::SmallStringView import,
- Utils::SmallStringView toolTip,
- Utils::SmallStringView properties,
- Utils::SmallStringView extraFilePaths,
- Utils::SmallStringView templatePath) {
- auto &last = entries.emplace_back(
- typeId, name, iconPath, category, import, toolTip, templatePath);
- if (properties.size())
- selectItemLibraryPropertiesStatement.readTo(last.properties, properties);
- if (extraFilePaths.size())
- selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths);
- };
-
- selectItemLibraryEntriesStatement.readCallbackWithTransaction(callback);
-
- return entries;
- }
+ Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override;
- std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get signal names"_t, projectStorageCategory()};
+ Storage::Info::ItemLibraryEntries itemLibraryEntries(ImportId importId) const;
- return selectSignalDeclarationNamesForTypeStatement
- .template valuesWithTransaction<Utils::SmallString, 32>(typeId);
- }
+ Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override;
- std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get function names"_t, projectStorageCategory()};
+ Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override;
- return selectFuncionDeclarationNamesForTypeStatement
- .template valuesWithTransaction<Utils::SmallString, 32>(typeId);
- }
+ std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override;
- std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override
- {
- NanotraceHR::Tracer tracer{"get property name"_t, projectStorageCategory()};
+ std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override;
- return selectPropertyNameStatement.template optionalValueWithTransaction<Utils::SmallString>(
- propertyDeclarationId);
- }
+ std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override;
- const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const override
+ const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const override
{
return commonTypeCache_;
}
- template<const char *moduleName, const char *typeName>
+ template<const char *moduleName, const char *typeName, Storage::ModuleKind moduleKind = Storage::ModuleKind::QmlLibrary>
TypeId commonTypeId() const
{
- NanotraceHR::Tracer tracer{"get type id from common type cache"_t, projectStorageCategory()};
+ using NanotraceHR::keyValue;
+ NanotraceHR::Tracer tracer{"get type id from common type cache"_t,
+ projectStorageCategory(),
+ keyValue("module name", std::string_view{moduleName}),
+ keyValue("type name", std::string_view{typeName})};
+
+ auto typeId = commonTypeCache_.typeId<moduleName, typeName, moduleKind>();
+
+ tracer.end(keyValue("type id", typeId));
- return commonTypeCache_.template typeId<moduleName, typeName>();
+ return typeId;
}
template<typename BuiltinType>
TypeId builtinTypeId() const
{
+ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t,
projectStorageCategory()};
- return commonTypeCache_.template builtinTypeId<BuiltinType>();
+ auto typeId = commonTypeCache_.builtinTypeId<BuiltinType>();
+
+ tracer.end(keyValue("type id", typeId));
+
+ return typeId;
}
template<const char *builtinType>
TypeId builtinTypeId() const
{
+ using NanotraceHR::keyValue;
NanotraceHR::Tracer tracer{"get builtin type id from common type cache"_t,
projectStorageCategory()};
- return commonTypeCache_.template builtinTypeId<builtinType>();
- }
+ auto typeId = commonTypeCache_.builtinTypeId<builtinType>();
- TypeIds prototypeIds(TypeId type) const override
- {
- NanotraceHR::Tracer tracer{"get prototypes"_t, projectStorageCategory()};
+ tracer.end(keyValue("type id", typeId));
- return selectPrototypeIdsForTypeIdInOrderStatement.template valuesWithTransaction<TypeId, 16>(
- type);
+ return typeId;
}
- TypeIds prototypeAndSelfIds(TypeId type) const override
- {
- NanotraceHR::Tracer tracer{"get prototypes and self"_t, projectStorageCategory()};
+ SmallTypeIds<16> prototypeIds(TypeId type) const override;
- return selectPrototypeAndSelfIdsForTypeIdInOrderStatement
- .template valuesWithTransaction<TypeId, 16>(type);
- }
+ SmallTypeIds<16> prototypeAndSelfIds(TypeId typeId) const override;
- TypeIds heirIds(TypeId typeId) const override
- {
- NanotraceHR::Tracer tracer{"get heirs"_t, projectStorageCategory()};
-
- return selectHeirTypeIdsStatement.template valuesWithTransaction<TypeId, 64>(typeId);
- }
+ SmallTypeIds<64> heirIds(TypeId typeId) const override;
template<typename... TypeIds>
- bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const
- {
- NanotraceHR::Tracer tracer{"is based on"_t, projectStorageCategory()};
+ bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const;
- static_assert(((std::is_same_v<TypeId, TypeIds>) &&...), "Parameter must be a TypeId!");
+ bool isBasedOn(TypeId) const;
- if (((typeId == baseTypeIds) || ...))
- return true;
+ bool isBasedOn(TypeId typeId, TypeId id1) const override;
- auto range = selectPrototypeIdsStatement.template rangeWithTransaction<TypeId>(typeId);
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override;
- for ([[maybe_unused]] TypeId currentTypeId : range) {
- if (((currentTypeId == baseTypeIds) || ...))
- return true;
- }
-
- return false;
- }
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override;
- bool isBasedOn(TypeId typeId) const { return isBasedOn_(typeId); }
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override;
- bool isBasedOn(TypeId typeId, TypeId id1) const override { return isBasedOn_(typeId, id1); }
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override;
- 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)
+ const override;
bool isBasedOn(TypeId typeId,
TypeId id1,
@@ -546,316 +201,147 @@ public:
TypeId id4,
TypeId id5,
TypeId id6,
- TypeId id7) const override
- {
- return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7);
- }
+ TypeId id7) const override;
- TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const
- {
- NanotraceHR::Tracer tracer{"is based on"_t, projectStorageCategory()};
+ TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const;
- return selectTypeIdByExportedNameStatement.template valueWithTransaction<TypeId>(name);
- }
+ TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds,
+ Utils::SmallStringView name) const;
- TypeId fetchTypeIdByModuleIdsAndExportedName(ModuleIds moduleIds, Utils::SmallStringView name) const
- {
- return selectTypeIdByModuleIdsAndExportedNameStatement.template valueWithTransaction<TypeId>(
- static_cast<void *>(moduleIds.data()), static_cast<long long>(moduleIds.size()), name);
- }
+ TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name);
- TypeId fetchTypeIdByName(SourceId sourceId, Utils::SmallStringView name)
- {
- return selectTypeIdBySourceIdAndNameStatement.template valueWithTransaction<TypeId>(sourceId,
- name);
- }
+ Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId);
- Storage::Synchronization::Type fetchTypeByTypeId(TypeId 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);
-
- return type;
- });
- }
-
- Storage::Synchronization::Types fetchTypes()
- {
- return Sqlite::withDeferredTransaction(database, [&] {
- 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);
- }
-
- return types;
- });
- }
-
- bool fetchIsProtype(TypeId type, TypeId prototype)
- {
- return bool(selectPrototypeIdStatement.template valueWithTransaction<TypeId>(type, prototype));
- }
-
- auto fetchPrototypes(TypeId type)
- {
- return selectPrototypeIdsInOrderStatement.template rangeWithTransaction<TypeId>(type);
- }
-
- SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath)
- {
- NanotraceHR::Tracer tracer{"fetch source context id unguarded"_t, projectStorageCategory()};
-
- auto sourceContextId = readSourceContextId(sourceContextPath);
-
- return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath);
- }
-
- SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
- {
- NanotraceHR::Tracer tracer{"fetch source context id"_t, projectStorageCategory()};
-
- try {
- return Sqlite::withDeferredTransaction(database, [&] {
- return fetchSourceContextIdUnguarded(sourceContextPath);
- });
- } catch (const Sqlite::ConstraintPreventsModification &) {
- return fetchSourceContextId(sourceContextPath);
- }
- }
+ Storage::Synchronization::Types fetchTypes();
- Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
- {
- NanotraceHR::Tracer tracer{"fetch source context path"_t, projectStorageCategory()};
-
- return Sqlite::withDeferredTransaction(database, [&] {
- auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
- .template optionalValue<Utils::PathString>(
- sourceContextId);
-
- if (!optionalSourceContextPath)
- throw SourceContextIdDoesNotExists();
-
- return std::move(*optionalSourceContextPath);
- });
- }
+ SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath);
- auto fetchAllSourceContexts() const
- {
- NanotraceHR::Tracer tracer{"fetch all source contexts"_t, projectStorageCategory()};
+ SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath);
- return selectAllSourceContextsStatement
- .template valuesWithTransaction<Cache::SourceContext, 128>();
- }
+ Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const;
- SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
- {
- NanotraceHR::Tracer tracer{"fetch source id"_t, projectStorageCategory()};
-
- return Sqlite::withDeferredTransaction(database, [&] {
- return fetchSourceIdUnguarded(sourceContextId, sourceName);
- });
- }
+ Cache::SourceContexts fetchAllSourceContexts() const;
- auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
- {
- NanotraceHR::Tracer tracer{"fetch source name and source context id"_t,
- projectStorageCategory()};
+ SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
- auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
- .template valueWithTransaction<Cache::SourceNameAndSourceContextId>(sourceId);
+ Cache::SourceNameAndSourceContextId fetchSourceNameAndSourceContextId(SourceId sourceId) const;
- if (!value.sourceContextId)
- throw SourceIdDoesNotExists();
+ void clearSources();
- return value;
- }
+ SourceContextId fetchSourceContextId(SourceId sourceId) const;
- void clearSources()
- {
- Sqlite::withImmediateTransaction(database, [&] {
- deleteAllSourceContextsStatement.execute();
- deleteAllSourcesStatement.execute();
- });
- }
+ Cache::Sources fetchAllSources() const;
- SourceContextId fetchSourceContextId(SourceId sourceId) const
- {
- NanotraceHR::Tracer tracer{"fetch source context id"_t, projectStorageCategory()};
+ SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId,
+ Utils::SmallStringView sourceName);
- auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement
- .template valueWithTransaction<SourceContextId>(sourceId);
+ FileStatuses fetchAllFileStatuses() const;
- if (!sourceContextId)
- throw SourceIdDoesNotExists();
+ FileStatus fetchFileStatus(SourceId sourceId) const override;
- return sourceContextId;
- }
+ std::optional<Storage::Synchronization::DirectoryInfo> fetchDirectoryInfo(SourceId sourceId) const override;
- auto fetchAllSources() const
- {
- NanotraceHR::Tracer tracer{"fetch all sources"_t, projectStorageCategory()};
+ Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceId directorySourceId) const override;
+ Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(
+ SourceId directorySourceId, Storage::Synchronization::FileType fileType) const override;
+ Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(const SourceIds &directorySourceIds) const;
+ SmallSourceIds<32> fetchSubdirectorySourceIds(SourceId directorySourceId) const override;
- return selectAllSourcesStatement.template valuesWithTransaction<Cache::Source, 1024>();
- }
+ void setPropertyEditorPathId(TypeId typeId, SourceId pathId);
- SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
- {
- NanotraceHR::Tracer tracer{"fetch source id unguarded"_t, projectStorageCategory()};
+ SourceId propertyEditorPathId(TypeId typeId) const override;
- auto sourceId = readSourceId(sourceContextId, sourceName);
+ Storage::Imports fetchDocumentImports() const;
- if (sourceId)
- return sourceId;
+ void resetForTestsOnly();
- return writeSourceId(sourceContextId, sourceName);
- }
-
- auto fetchAllFileStatuses() const
- {
- NanotraceHR::Tracer tracer{"fetch all file statuses"_t, projectStorageCategory()};
-
- return selectAllFileStatusesStatement.template rangeWithTransaction<FileStatus>();
- }
-
- FileStatus fetchFileStatus(SourceId sourceId) const override
- {
- NanotraceHR::Tracer tracer{"fetch file status"_t, projectStorageCategory()};
-
- return selectFileStatusesForSourceIdStatement.template valueWithTransaction<FileStatus>(
- sourceId);
- }
-
- std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const override
- {
- NanotraceHR::Tracer tracer{"fetch project data"_t, projectStorageCategory()};
-
- return selectProjectDataForSourceIdStatement
- .template optionalValueWithTransaction<Storage::Synchronization::ProjectData>(sourceId);
- }
-
- Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override
- {
- NanotraceHR::Tracer tracer{"fetch project datas by source id"_t, projectStorageCategory()};
-
- return selectProjectDatasForSourceIdStatement
- .template valuesWithTransaction<Storage::Synchronization::ProjectData, 1024>(
- projectSourceId);
- }
-
- Storage::Synchronization::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const
- {
- NanotraceHR::Tracer tracer{"fetch project datas by source ids"_t, projectStorageCategory()};
-
- return selectProjectDatasForSourceIdsStatement
- .template valuesWithTransaction<Storage::Synchronization::ProjectData, 64>(
- toIntegers(projectSourceIds));
- }
-
- void setPropertyEditorPathId(TypeId typeId, SourceId pathId)
+private:
+ struct ModuleView
{
- Sqlite::ImmediateSessionTransaction transaction{database};
+ ModuleView() = default;
- upsertPropertyEditorPathIdStatement.write(typeId, pathId);
+ ModuleView(Utils::SmallStringView name, Storage::ModuleKind kind)
+ : name{name}
+ , kind{kind}
+ {}
- transaction.commit();
- }
+ ModuleView(const Storage::Module &module)
+ : name{module.name}
+ , kind{module.kind}
+ {}
- SourceId propertyEditorPathId(TypeId typeId) const override
- {
- return selectPropertyEditorPathIdStatement.template valueWithTransaction<SourceId>(typeId);
- }
+ Utils::SmallStringView name;
+ Storage::ModuleKind kind;
- Storage::Imports fetchDocumentImports() const
- {
- NanotraceHR::Tracer tracer{"fetch document imports"_t, projectStorageCategory()};
+ friend bool operator<(ModuleView first, ModuleView second)
+ {
+ return std::tie(first.kind, first.name) < std::tie(second.kind, second.name);
+ }
- return selectAllDocumentImportForSourceIdStatement
- .template valuesWithTransaction<Storage::Imports>();
- }
+ friend bool operator==(const Storage::Module &first, ModuleView second)
+ {
+ return first.name == second.name && first.kind == second.kind;
+ }
- void resetForTestsOnly()
- {
- database.clearAllTablesForTestsOnly();
- commonTypeCache_.clearForTestsOnly();
- moduleCache.clearForTestOnly();
- }
+ friend bool operator==(ModuleView first, const Storage::Module &second)
+ {
+ return second == first;
+ }
+ };
-private:
class ModuleStorageAdapter
{
public:
- auto fetchId(const Utils::SmallStringView name) { return storage.fetchModuleId(name); }
+ auto fetchId(ModuleView module) { return storage.fetchModuleId(module.name, module.kind); }
- auto fetchValue(ModuleId id) { return storage.fetchModuleName(id); }
+ auto fetchValue(ModuleId id) { return storage.fetchModule(id); }
auto fetchAll() { return storage.fetchAllModules(); }
ProjectStorage &storage;
};
- class Module : public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId>
+ friend ModuleStorageAdapter;
+
+ static bool moduleNameLess(ModuleView first, ModuleView second) noexcept
+ {
+ return first < second;
+ }
+
+ class ModuleCacheEntry : public StorageCacheEntry<Storage::Module, ModuleView, ModuleId>
{
- using Base = StorageCacheEntry<Utils::PathString, Utils::SmallStringView, ModuleId>;
+ using Base = StorageCacheEntry<Storage::Module, ModuleView, ModuleId>;
public:
using Base::Base;
- friend bool operator==(const Module &first, const Module &second)
+ ModuleCacheEntry(Utils::SmallStringView name, Storage::ModuleKind kind, ModuleId moduleId)
+ : Base{{name, kind}, moduleId}
+ {}
+
+ friend bool operator==(const ModuleCacheEntry &first, const ModuleCacheEntry &second)
{
return &first == &second && first.value == second.value;
}
- };
- friend ModuleStorageAdapter;
+ friend bool operator==(const ModuleCacheEntry &first, ModuleView second)
+ {
+ return first.value.name == second.name && first.value.kind == second.kind;
+ }
+ };
- static bool moduleNameLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept
- {
- return first < second;
- }
+ using ModuleCacheEntries = std::vector<ModuleCacheEntry>;
- using ModuleCache = StorageCache<Utils::PathString,
- Utils::SmallStringView,
- ModuleId,
- ModuleStorageAdapter,
- NonLockingMutex,
- moduleNameLess,
- Module>;
+ using ModuleCache
+ = StorageCache<Storage::Module, ModuleView, ModuleId, ModuleStorageAdapter, NonLockingMutex, moduleNameLess, ModuleCacheEntry>;
- ModuleId fetchModuleId(Utils::SmallStringView moduleName)
- {
- return Sqlite::withDeferredTransaction(database,
- [&] { return fetchModuleIdUnguarded(moduleName); });
- }
+ ModuleId fetchModuleId(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind);
- auto fetchModuleName(ModuleId id)
- {
- return Sqlite::withDeferredTransaction(database, [&] { return fetchModuleNameUnguarded(id); });
- }
+ Storage::Module fetchModule(ModuleId id);
- auto fetchAllModules() const
- {
- return selectAllModulesStatement.template valuesWithTransaction<Module, 128>();
- }
+ ModuleCacheEntries fetchAllModules() const;
- void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds)
- {
- if (deletedTypeIds.size()) {
- for (ProjectStorageObserver *observer : observers)
- observer->removedTypeIds(deletedTypeIds);
- }
- }
+ void callRefreshMetaInfoCallback(const TypeIds &deletedTypeIds);
class AliasPropertyDeclaration
{
@@ -882,6 +368,25 @@ private:
< std::tie(second.typeId, second.propertyDeclarationId);
}
+ template<typename String>
+ friend void convertToString(String &string,
+ const AliasPropertyDeclaration &aliasPropertyDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(
+ keyValue("type id", aliasPropertyDeclaration.typeId),
+ keyValue("property declaration id", aliasPropertyDeclaration.propertyDeclarationId),
+ keyValue("alias imported type name id",
+ aliasPropertyDeclaration.aliasImportedTypeNameId),
+ keyValue("alias property name", aliasPropertyDeclaration.aliasPropertyName),
+ keyValue("alias property name tail", aliasPropertyDeclaration.aliasPropertyNameTail),
+ keyValue("alias property declaration id",
+ aliasPropertyDeclaration.aliasPropertyDeclarationId));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId typeId;
PropertyDeclarationId propertyDeclarationId;
@@ -910,6 +415,20 @@ private:
< std::tie(second.typeId, second.propertyDeclarationId);
}
+ template<typename String>
+ friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", propertyDeclaration.typeId),
+ keyValue("property declaration id",
+ propertyDeclaration.propertyDeclarationId),
+ keyValue("imported type name id",
+ propertyDeclaration.importedTypeNameId));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId typeId;
PropertyDeclarationId propertyDeclarationId;
@@ -931,6 +450,22 @@ private:
return first.typeId < second.typeId;
}
+ friend bool operator==(Prototype first, Prototype second)
+ {
+ return first.typeId == second.typeId;
+ }
+
+ template<typename String>
+ friend void convertToString(String &string, const Prototype &prototype)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", prototype.typeId),
+ keyValue("prototype name id", prototype.prototypeNameId));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId typeId;
ImportedTypeNameId prototypeNameId;
@@ -970,127 +505,67 @@ private:
}
};
- SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, SourceIds &sourceIdsOfTypes)
- {
- std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end());
+ SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds,
+ SourceIds &sourceIdsOfTypes);
- SourceIds sourceIdsWithoutTypeSourceIds;
- sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size());
- std::set_difference(updatedSourceIds.begin(),
- updatedSourceIds.end(),
- sourceIdsOfTypes.begin(),
- sourceIdsOfTypes.end(),
- std::back_inserter(sourceIdsWithoutTypeSourceIds));
+ TypeIds fetchTypeIds(const SourceIds &sourceIds);
- return sourceIdsWithoutTypeSourceIds;
- }
-
- TypeIds fetchTypeIds(const SourceIds &sourceIds)
- {
- return selectTypeIdsForSourceIdsStatement.template values<TypeId, 128>(toIntegers(sourceIds));
- }
-
- void unique(SourceIds &sourceIds)
- {
- std::sort(sourceIds.begin(), sourceIds.end());
- auto newEnd = std::unique(sourceIds.begin(), sourceIds.end());
- sourceIds.erase(newEnd, sourceIds.end());
- }
+ void unique(SourceIds &sourceIds);
- void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits)
- {
- updateTypeAnnotationTraitStatement.write(typeId, traits.annotation);
- }
+ void synchronizeTypeTraits(TypeId typeId, Storage::TypeTraits traits);
class TypeAnnotationView
{
public:
TypeAnnotationView(TypeId typeId,
+ Utils::SmallStringView typeName,
Utils::SmallStringView iconPath,
Utils::SmallStringView itemLibraryJson,
Utils::SmallStringView hintsJson)
: typeId{typeId}
+ , typeName{typeName}
, iconPath{iconPath}
, itemLibraryJson{itemLibraryJson}
, hintsJson{hintsJson}
{}
+ template<typename String>
+ friend void convertToString(String &string, const TypeAnnotationView &typeAnnotationView)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", typeAnnotationView.typeId),
+ keyValue("type name", typeAnnotationView.typeName),
+ keyValue("icon path", typeAnnotationView.iconPath),
+ keyValue("item library json", typeAnnotationView.itemLibraryJson),
+ keyValue("hints json", typeAnnotationView.hintsJson));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId typeId;
+ Utils::SmallStringView typeName;
Utils::SmallStringView iconPath;
Utils::SmallStringView itemLibraryJson;
Utils::PathString hintsJson;
};
- void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations)
- {
- for (auto &annotation : typeAnnotations) {
- annotation.typeId = fetchTypeIdByModuleIdAndExportedName(annotation.moduleId,
- annotation.typeName);
- }
- }
+ void updateTypeIdInTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations);
- void synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations,
- const SourceIds &updatedTypeAnnotationSourceIds)
+ template<typename Value>
+ static Sqlite::ValueView createEmptyAsNull(const Value &value)
{
- NanotraceHR::Tracer tracer{"synchronize type annotations"_t, projectStorageCategory()};
-
- using Storage::Synchronization::TypeAnnotation;
-
- updateTypeIdInTypeAnnotations(typeAnnotations);
-
- auto compareKey = [](auto &&first, auto &&second) { return first.typeId - second.typeId; };
+ if (value.size())
+ return Sqlite::ValueView::create(value);
- std::sort(typeAnnotations.begin(), typeAnnotations.end(), [&](auto &&first, auto &&second) {
- return first.typeId < second.typeId;
- });
-
- auto range = selectTypeAnnotationsForSourceIdsStatement.template range<TypeAnnotationView>(
- toIntegers(updatedTypeAnnotationSourceIds));
-
- auto insert = [&](const TypeAnnotation &annotation) {
- if (!annotation.sourceId)
- throw TypeAnnotationHasInvalidSourceId{};
-
- synchronizeTypeTraits(annotation.typeId, annotation.traits);
-
- insertTypeAnnotationStatement.write(annotation.typeId,
- annotation.sourceId,
- annotation.iconPath,
- annotation.itemLibraryJson,
- annotation.hintsJson);
- };
-
- auto update = [&](const TypeAnnotationView &annotationFromDatabase,
- const TypeAnnotation &annotation) {
- synchronizeTypeTraits(annotation.typeId, annotation.traits);
-
- if (annotationFromDatabase.iconPath != annotation.iconPath
- || annotationFromDatabase.itemLibraryJson != annotation.itemLibraryJson
- || annotationFromDatabase.hintsJson != annotation.hintsJson) {
- updateTypeAnnotationStatement.write(annotation.typeId,
- annotation.iconPath,
- annotation.itemLibraryJson,
- annotation.hintsJson);
- return Sqlite::UpdateChange::Update;
- }
-
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const TypeAnnotationView &annotationFromDatabase) {
- synchronizeTypeTraits(annotationFromDatabase.typeId, Storage::TypeTraits{});
-
- deleteTypeAnnotationStatement.write(annotationFromDatabase.typeId);
- };
-
- Sqlite::insertUpdateDelete(range, typeAnnotations, compareKey, insert, update, remove);
+ return Sqlite::ValueView{};
}
- void synchronizeTypeTrait(const Storage::Synchronization::Type &type)
- {
- updateTypeTraitStatement.write(type.typeId, type.traits.type);
- }
+ void synchronizeTypeAnnotations(Storage::Synchronization::TypeAnnotations &typeAnnotations,
+ const SourceIds &updatedTypeAnnotationSourceIds);
+
+ void synchronizeTypeTrait(const Storage::Synchronization::Type &type);
void synchronizeTypes(Storage::Synchronization::Types &types,
TypeIds &updatedTypeIds,
@@ -1100,403 +575,62 @@ private:
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
Prototypes &relinkableExtensions,
- const SourceIds &updatedSourceIds)
- {
- NanotraceHR::Tracer tracer{"synchronize types"_t, projectStorageCategory()};
-
- Storage::Synchronization::ExportedTypes exportedTypes;
- exportedTypes.reserve(types.size() * 3);
- SourceIds sourceIdsOfTypes;
- sourceIdsOfTypes.reserve(updatedSourceIds.size());
- SourceIds notUpdatedExportedSourceIds;
- notUpdatedExportedSourceIds.reserve(updatedSourceIds.size());
- SourceIds exportedSourceIds;
- exportedSourceIds.reserve(types.size());
-
- for (auto &type : types) {
- if (!type.sourceId)
- throw TypeHasInvalidSourceId{};
-
- TypeId typeId = declareType(type);
- synchronizeTypeTrait(type);
- sourceIdsOfTypes.push_back(type.sourceId);
- updatedTypeIds.push_back(typeId);
- if (type.changeLevel != Storage::Synchronization::ChangeLevel::ExcludeExportedTypes) {
- exportedSourceIds.push_back(type.sourceId);
- extractExportedTypes(typeId, type, exportedTypes);
- }
- }
-
- std::sort(types.begin(), types.end(), [](const auto &first, const auto &second) {
- return first.typeId < second.typeId;
- });
-
- unique(exportedSourceIds);
-
- SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds,
- sourceIdsOfTypes);
- exportedSourceIds.insert(exportedSourceIds.end(),
- sourceIdsWithoutType.begin(),
- sourceIdsWithoutType.end());
- TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds);
- synchronizeExportedTypes(exportedTypeIds,
- exportedTypes,
- relinkableAliasPropertyDeclarations,
- relinkablePropertyDeclarations,
- relinkablePrototypes,
- relinkableExtensions);
-
- syncPrototypesAndExtensions(types, relinkablePrototypes, relinkableExtensions);
- resetDefaultPropertiesIfChanged(types);
- resetRemovedAliasPropertyDeclarationsToNull(types, relinkableAliasPropertyDeclarations);
- syncDeclarations(types,
- insertedAliasPropertyDeclarations,
- updatedAliasPropertyDeclarations,
- relinkablePropertyDeclarations);
- syncDefaultProperties(types);
- }
+ const SourceIds &updatedSourceIds);
- void synchronizeProjectDatas(Storage::Synchronization::ProjectDatas &projectDatas,
- const SourceIds &updatedProjectSourceIds)
- {
- NanotraceHR::Tracer tracer{"synchronize project datas"_t, projectStorageCategory()};
-
- auto compareKey = [](auto &&first, auto &&second) {
- auto projectSourceIdDifference = first.projectSourceId - second.projectSourceId;
- if (projectSourceIdDifference != 0)
- return projectSourceIdDifference;
-
- return first.sourceId - second.sourceId;
- };
-
- std::sort(projectDatas.begin(), projectDatas.end(), [&](auto &&first, auto &&second) {
- return std::tie(first.projectSourceId, first.sourceId)
- < std::tie(second.projectSourceId, second.sourceId);
- });
-
- auto range = selectProjectDatasForSourceIdsStatement
- .template range<Storage::Synchronization::ProjectData>(
- toIntegers(updatedProjectSourceIds));
-
- auto insert = [&](const Storage::Synchronization::ProjectData &projectData) {
- if (!projectData.projectSourceId)
- throw ProjectDataHasInvalidProjectSourceId{};
- if (!projectData.sourceId)
- throw ProjectDataHasInvalidSourceId{};
-
- insertProjectDataStatement.write(projectData.projectSourceId,
- projectData.sourceId,
- projectData.moduleId,
- projectData.fileType);
- };
-
- auto update = [&](const Storage::Synchronization::ProjectData &projectDataFromDatabase,
- const Storage::Synchronization::ProjectData &projectData) {
- if (projectDataFromDatabase.fileType != projectData.fileType
- || !compareInvalidAreTrue(projectDataFromDatabase.moduleId, projectData.moduleId)) {
- updateProjectDataStatement.write(projectData.projectSourceId,
- projectData.sourceId,
- projectData.moduleId,
- projectData.fileType);
- return Sqlite::UpdateChange::Update;
- }
-
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::ProjectData &projectData) {
- deleteProjectDataStatement.write(projectData.projectSourceId, projectData.sourceId);
- };
-
- Sqlite::insertUpdateDelete(range, projectDatas, compareKey, insert, update, remove);
- }
+ void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos,
+ const SourceIds &updatedDirectoryInfoSourceIds);
- void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds)
- {
- NanotraceHR::Tracer tracer{"synchronize file statuses"_t, projectStorageCategory()};
-
- auto compareKey = [](auto &&first, auto &&second) {
- return first.sourceId - second.sourceId;
- };
-
- std::sort(fileStatuses.begin(), fileStatuses.end(), [&](auto &&first, auto &&second) {
- return first.sourceId < second.sourceId;
- });
-
- auto range = selectFileStatusesForSourceIdsStatement.template range<FileStatus>(
- toIntegers(updatedSourceIds));
-
- auto insert = [&](const FileStatus &fileStatus) {
- if (!fileStatus.sourceId)
- throw FileStatusHasInvalidSourceId{};
- insertFileStatusStatement.write(fileStatus.sourceId,
- fileStatus.size,
- fileStatus.lastModified);
- };
-
- auto update = [&](const FileStatus &fileStatusFromDatabase, const FileStatus &fileStatus) {
- if (fileStatusFromDatabase.lastModified != fileStatus.lastModified
- || fileStatusFromDatabase.size != fileStatus.size) {
- updateFileStatusStatement.write(fileStatus.sourceId,
- fileStatus.size,
- fileStatus.lastModified);
- return Sqlite::UpdateChange::Update;
- }
-
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const FileStatus &fileStatus) {
- deleteFileStatusStatement.write(fileStatus.sourceId);
- };
-
- Sqlite::insertUpdateDelete(range, fileStatuses, compareKey, insert, update, remove);
- }
+ void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds);
void synchronizeImports(Storage::Imports &imports,
const SourceIds &updatedSourceIds,
Storage::Imports &moduleDependencies,
const SourceIds &updatedModuleDependencySourceIds,
Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
- const ModuleIds &updatedModuleIds)
- {
- NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()};
-
- synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds);
- synchronizeDocumentImports(imports,
- updatedSourceIds,
- Storage::Synchronization::ImportKind::Import);
- synchronizeDocumentImports(moduleDependencies,
- updatedModuleDependencySourceIds,
- Storage::Synchronization::ImportKind::ModuleDependency);
- }
+ const ModuleIds &updatedModuleIds,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions);
void synchromizeModuleExportedImports(
Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
- const ModuleIds &updatedModuleIds)
- {
- std::sort(moduleExportedImports.begin(),
- moduleExportedImports.end(),
- [](auto &&first, auto &&second) {
- return std::tie(first.moduleId, first.exportedModuleId)
- < std::tie(second.moduleId, second.exportedModuleId);
- });
-
- auto range = selectModuleExportedImportsForSourceIdStatement
- .template range<Storage::Synchronization::ModuleExportedImportView>(
- toIntegers(updatedModuleIds));
-
- auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view,
- const Storage::Synchronization::ModuleExportedImport &import) -> long long {
- auto moduleIdDifference = view.moduleId - import.moduleId;
- if (moduleIdDifference != 0)
- return moduleIdDifference;
-
- return view.exportedModuleId - import.exportedModuleId;
- };
-
- auto insert = [&](const Storage::Synchronization::ModuleExportedImport &import) {
- if (import.version.minor) {
- insertModuleExportedImportWithVersionStatement.write(import.moduleId,
- import.exportedModuleId,
- import.isAutoVersion,
- import.version.major.value,
- import.version.minor.value);
- } else if (import.version.major) {
- insertModuleExportedImportWithMajorVersionStatement.write(import.moduleId,
- import.exportedModuleId,
- import.isAutoVersion,
- import.version.major.value);
- } else {
- insertModuleExportedImportWithoutVersionStatement.write(import.moduleId,
- import.exportedModuleId,
- import.isAutoVersion);
- }
- };
-
- auto update = [](const Storage::Synchronization::ModuleExportedImportView &,
- const Storage::Synchronization::ModuleExportedImport &) {
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::ModuleExportedImportView &view) {
- deleteModuleExportedImportStatement.write(view.moduleExportedImportId);
- };
-
- Sqlite::insertUpdateDelete(range, moduleExportedImports, compareKey, insert, update, remove);
- }
-
- ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const override
- {
- auto moduleId = selectModuleIdByNameStatement.template value<ModuleId>(name);
+ const ModuleIds &updatedModuleIds);
- if (moduleId)
- return moduleId;
+ ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name,
+ Storage::ModuleKind moduleKind) const override;
- return insertModuleNameStatement.template value<ModuleId>(name);
- }
-
- auto fetchModuleNameUnguarded(ModuleId id) const
- {
- auto moduleName = selectModuleNameStatement.template value<Utils::PathString>(id);
-
- if (moduleName.empty())
- throw ModuleDoesNotExists{};
-
- return moduleName;
- }
+ Storage::Module fetchModuleUnguarded(ModuleId id) const;
void handleAliasPropertyDeclarationsWithPropertyType(
- TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations)
- {
- auto callback = [&](TypeId typeId_,
- PropertyDeclarationId propertyDeclarationId,
- ImportedTypeNameId propertyImportedTypeNameId,
- PropertyDeclarationId aliasPropertyDeclarationId,
- PropertyDeclarationId aliasPropertyDeclarationTailId) {
- auto aliasPropertyName = selectPropertyNameStatement.template value<Utils::SmallString>(
- aliasPropertyDeclarationId);
- Utils::SmallString aliasPropertyNameTail;
- if (aliasPropertyDeclarationTailId)
- aliasPropertyNameTail = selectPropertyNameStatement.template value<Utils::SmallString>(
- aliasPropertyDeclarationTailId);
-
- relinkableAliasPropertyDeclarations
- .emplace_back(TypeId{typeId_},
- PropertyDeclarationId{propertyDeclarationId},
- ImportedTypeNameId{propertyImportedTypeNameId},
- std::move(aliasPropertyName),
- std::move(aliasPropertyNameTail));
-
- updateAliasPropertyDeclarationToNullStatement.write(propertyDeclarationId);
- };
-
- selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement.readCallback(callback,
- typeId);
- }
+ TypeId typeId, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations);
void handlePropertyDeclarationWithPropertyType(TypeId typeId,
- PropertyDeclarations &relinkablePropertyDeclarations)
- {
- updatesPropertyDeclarationPropertyTypeToNullStatement.readTo(relinkablePropertyDeclarations,
- typeId);
- }
+ PropertyDeclarations &relinkablePropertyDeclarations);
- void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes)
- {
- auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
- relinkablePrototypes.emplace_back(typeId, prototypeNameId);
- };
-
- updatePrototypeIdToNullStatement.readCallback(callback, prototypeId);
- }
-
- void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions)
- {
- auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
- relinkableExtensions.emplace_back(typeId, extensionNameId);
- };
-
- updateExtensionIdToNullStatement.readCallback(callback, extensionId);
- }
+ void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes);
+ void handlePrototypesWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName,
+ TypeId typeId,
+ Prototypes &relinkablePrototypes);
+ void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions);
+ void handleExtensionsWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName,
+ TypeId typeId,
+ Prototypes &relinkableExtensions);
void deleteType(TypeId typeId,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
- Prototypes &relinkableExtensions)
- {
- handlePropertyDeclarationWithPropertyType(typeId, relinkablePropertyDeclarations);
- handleAliasPropertyDeclarationsWithPropertyType(typeId, relinkableAliasPropertyDeclarations);
- handlePrototypes(typeId, relinkablePrototypes);
- handleExtensions(typeId, relinkableExtensions);
- deleteTypeNamesByTypeIdStatement.write(typeId);
- deleteEnumerationDeclarationByTypeIdStatement.write(typeId);
- deletePropertyDeclarationByTypeIdStatement.write(typeId);
- deleteFunctionDeclarationByTypeIdStatement.write(typeId);
- deleteSignalDeclarationByTypeIdStatement.write(typeId);
- deleteTypeStatement.write(typeId);
- }
+ Prototypes &relinkableExtensions);
void relinkAliasPropertyDeclarations(AliasPropertyDeclarations &aliasPropertyDeclarations,
- const TypeIds &deletedTypeIds)
- {
- NanotraceHR::Tracer tracer{"relink alias properties"_t, projectStorageCategory()};
-
- std::sort(aliasPropertyDeclarations.begin(), aliasPropertyDeclarations.end());
-
- Utils::set_greedy_difference(
- aliasPropertyDeclarations.cbegin(),
- aliasPropertyDeclarations.cend(),
- deletedTypeIds.begin(),
- deletedTypeIds.end(),
- [&](const AliasPropertyDeclaration &alias) {
- auto typeId = fetchTypeId(alias.aliasImportedTypeNameId);
-
- if (!typeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(alias.aliasImportedTypeNameId)};
-
- auto [propertyTypeId, aliasId, propertyTraits] = fetchPropertyDeclarationByTypeIdAndNameUngarded(
- typeId, alias.aliasPropertyName);
-
- updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId,
- propertyTypeId,
- propertyTraits,
- alias.aliasImportedTypeNameId,
- aliasId);
- },
- TypeCompare<AliasPropertyDeclaration>{});
- }
+ const TypeIds &deletedTypeIds);
void relinkPropertyDeclarations(PropertyDeclarations &relinkablePropertyDeclaration,
- const TypeIds &deletedTypeIds)
- {
- NanotraceHR::Tracer tracer{"relink properties"_t, projectStorageCategory()};
-
- std::sort(relinkablePropertyDeclaration.begin(), relinkablePropertyDeclaration.end());
-
- Utils::set_greedy_difference(
- relinkablePropertyDeclaration.cbegin(),
- relinkablePropertyDeclaration.cend(),
- deletedTypeIds.begin(),
- deletedTypeIds.end(),
- [&](const PropertyDeclaration &property) {
- TypeId propertyTypeId = fetchTypeId(property.importedTypeNameId);
-
- if (!propertyTypeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(property.importedTypeNameId)};
-
- updatePropertyDeclarationTypeStatement.write(property.propertyDeclarationId,
- propertyTypeId);
- },
- TypeCompare<PropertyDeclaration>{});
- }
+ const TypeIds &deletedTypeIds);
template<typename Callable>
void relinkPrototypes(Prototypes &relinkablePrototypes,
const TypeIds &deletedTypeIds,
- Callable updateStatement)
- {
- NanotraceHR::Tracer tracer{"relink prototypes"_t, projectStorageCategory()};
-
- std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end());
-
- Utils::set_greedy_difference(
- relinkablePrototypes.cbegin(),
- relinkablePrototypes.cend(),
- deletedTypeIds.begin(),
- deletedTypeIds.end(),
- [&](const Prototype &prototype) {
- TypeId prototypeId = fetchTypeId(prototype.prototypeNameId);
-
- if (!prototypeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(prototype.prototypeNameId)};
-
- updateStatement(prototype.typeId, prototypeId);
- checkForPrototypeChainCycle(prototype.typeId);
- },
- TypeCompare<Prototype>{});
- }
+ Callable updateStatement);
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
const SourceIds &updatedSourceIds,
@@ -1505,295 +639,66 @@ private:
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
Prototypes &relinkableExtensions,
- TypeIds &deletedTypeIds)
- {
- NanotraceHR::Tracer tracer{"delete not updated types"_t, projectStorageCategory()};
-
- auto callback = [&](TypeId typeId) {
- deletedTypeIds.push_back(typeId);
- deleteType(typeId,
- relinkableAliasPropertyDeclarations,
- relinkablePropertyDeclarations,
- relinkablePrototypes,
- relinkableExtensions);
- };
-
- selectNotUpdatedTypesInSourcesStatement.readCallback(callback,
- toIntegers(updatedSourceIds),
- toIntegers(updatedTypeIds));
- for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted)
- callback(typeIdToBeDeleted);
- }
+ TypeIds &deletedTypeIds);
void relink(AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
Prototypes &relinkableExtensions,
- TypeIds &deletedTypeIds)
- {
- NanotraceHR::Tracer tracer{"relink"_t, projectStorageCategory()};
-
- std::sort(deletedTypeIds.begin(), deletedTypeIds.end());
-
- relinkPrototypes(relinkablePrototypes, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) {
- updateTypePrototypeStatement.write(typeId, prototypeId);
- });
- relinkPrototypes(relinkableExtensions, deletedTypeIds, [&](TypeId typeId, TypeId prototypeId) {
- updateTypeExtensionStatement.write(typeId, prototypeId);
- });
- relinkPropertyDeclarations(relinkablePropertyDeclarations, deletedTypeIds);
- relinkAliasPropertyDeclarations(relinkableAliasPropertyDeclarations, deletedTypeIds);
- }
+ TypeIds &deletedTypeIds);
PropertyDeclarationId fetchAliasId(TypeId aliasTypeId,
Utils::SmallStringView aliasPropertyName,
- Utils::SmallStringView aliasPropertyNameTail)
- {
- if (aliasPropertyNameTail.empty())
- return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName);
+ Utils::SmallStringView aliasPropertyNameTail);
- auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId,
- aliasPropertyName);
+ void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations);
- return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId,
- aliasPropertyNameTail);
- }
+ void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations);
- void linkAliasPropertyDeclarationAliasIds(const AliasPropertyDeclarations &aliasDeclarations)
- {
- for (const auto &aliasDeclaration : aliasDeclarations) {
- auto aliasTypeId = fetchTypeId(aliasDeclaration.aliasImportedTypeNameId);
-
- if (!aliasTypeId) {
- throw TypeNameDoesNotExists{
- fetchImportedTypeName(aliasDeclaration.aliasImportedTypeNameId)};
- }
-
- auto aliasId = fetchAliasId(aliasTypeId,
- aliasDeclaration.aliasPropertyName,
- aliasDeclaration.aliasPropertyNameTail);
-
- updatePropertyDeclarationAliasIdAndTypeNameIdStatement
- .write(aliasDeclaration.propertyDeclarationId,
- aliasId,
- aliasDeclaration.aliasImportedTypeNameId);
- }
- }
-
- void updateAliasPropertyDeclarationValues(const AliasPropertyDeclarations &aliasDeclarations)
- {
- for (const auto &aliasDeclaration : aliasDeclarations) {
- updatetPropertiesDeclarationValuesOfAliasStatement.write(
- aliasDeclaration.propertyDeclarationId);
- updatePropertyAliasDeclarationRecursivelyStatement.write(
- aliasDeclaration.propertyDeclarationId);
- }
- }
-
- void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations)
- {
- for (const auto &aliasDeclaration : aliasDeclarations)
- checkForAliasChainCycle(aliasDeclaration.propertyDeclarationId);
- }
+ void checkAliasPropertyDeclarationCycles(const AliasPropertyDeclarations &aliasDeclarations);
void linkAliases(const AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
- const AliasPropertyDeclarations &updatedAliasPropertyDeclarations)
- {
- NanotraceHR::Tracer tracer{"link aliases"_t, projectStorageCategory()};
-
- linkAliasPropertyDeclarationAliasIds(insertedAliasPropertyDeclarations);
- linkAliasPropertyDeclarationAliasIds(updatedAliasPropertyDeclarations);
-
- checkAliasPropertyDeclarationCycles(insertedAliasPropertyDeclarations);
- checkAliasPropertyDeclarationCycles(updatedAliasPropertyDeclarations);
-
- updateAliasPropertyDeclarationValues(insertedAliasPropertyDeclarations);
- updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations);
- }
+ const AliasPropertyDeclarations &updatedAliasPropertyDeclarations);
void synchronizeExportedTypes(const TypeIds &updatedTypeIds,
Storage::Synchronization::ExportedTypes &exportedTypes,
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
PropertyDeclarations &relinkablePropertyDeclarations,
Prototypes &relinkablePrototypes,
- Prototypes &relinkableExtensions)
- {
- NanotraceHR::Tracer tracer{"synchronize exported types"_t, projectStorageCategory()};
-
- std::sort(exportedTypes.begin(), exportedTypes.end(), [](auto &&first, auto &&second) {
- if (first.moduleId < second.moduleId)
- return true;
- else if (first.moduleId > second.moduleId)
- return false;
-
- auto nameCompare = Sqlite::compare(first.name, second.name);
-
- if (nameCompare < 0)
- return true;
- else if (nameCompare > 0)
- return false;
-
- return first.version < second.version;
- });
-
- auto range = selectExportedTypesForSourceIdsStatement
- .template range<Storage::Synchronization::ExportedTypeView>(
- toIntegers(updatedTypeIds));
-
- auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view,
- const Storage::Synchronization::ExportedType &type) -> long long {
- auto moduleIdDifference = view.moduleId - type.moduleId;
- if (moduleIdDifference != 0)
- return moduleIdDifference;
-
- auto nameDifference = Sqlite::compare(view.name, type.name);
- if (nameDifference != 0)
- return nameDifference;
-
- auto versionDifference = view.version.major.value - type.version.major.value;
- if (versionDifference != 0)
- return versionDifference;
-
- return view.version.minor.value - type.version.minor.value;
- };
-
- auto insert = [&](const Storage::Synchronization::ExportedType &type) {
- if (!type.moduleId)
- throw QmlDesigner::ModuleDoesNotExists{};
-
- try {
- if (type.version) {
- insertExportedTypeNamesWithVersionStatement.write(type.moduleId,
- type.name,
- type.version.major.value,
- type.version.minor.value,
- type.typeId);
-
- } else if (type.version.major) {
- insertExportedTypeNamesWithMajorVersionStatement.write(type.moduleId,
- type.name,
- type.version.major.value,
- type.typeId);
- } else {
- insertExportedTypeNamesWithoutVersionStatement.write(type.moduleId,
- type.name,
- type.typeId);
- }
- } catch (const Sqlite::ConstraintPreventsModification &) {
- throw QmlDesigner::ExportedTypeCannotBeInserted{type.name};
- }
- };
-
- auto update = [&](const Storage::Synchronization::ExportedTypeView &view,
- const Storage::Synchronization::ExportedType &type) {
- if (view.typeId != type.typeId) {
- handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations);
- handleAliasPropertyDeclarationsWithPropertyType(view.typeId,
- relinkableAliasPropertyDeclarations);
- handlePrototypes(view.typeId, relinkablePrototypes);
- handleExtensions(view.typeId, relinkableExtensions);
- updateExportedTypeNameTypeIdStatement.write(view.exportedTypeNameId, type.typeId);
- return Sqlite::UpdateChange::Update;
- }
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::ExportedTypeView &view) {
- handlePropertyDeclarationWithPropertyType(view.typeId, relinkablePropertyDeclarations);
- handleAliasPropertyDeclarationsWithPropertyType(view.typeId,
- relinkableAliasPropertyDeclarations);
- handlePrototypes(view.typeId, relinkablePrototypes);
- handleExtensions(view.typeId, relinkableExtensions);
- deleteExportedTypeNameStatement.write(view.exportedTypeNameId);
- };
-
- Sqlite::insertUpdateDelete(range, exportedTypes, compareKey, insert, update, remove);
- }
+ Prototypes &relinkableExtensions);
void synchronizePropertyDeclarationsInsertAlias(
AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
const Storage::Synchronization::PropertyDeclaration &value,
SourceId sourceId,
- TypeId typeId)
- {
- auto callback = [&](PropertyDeclarationId propertyDeclarationId) {
- insertedAliasPropertyDeclarations.emplace_back(typeId,
- propertyDeclarationId,
- fetchImportedTypeNameId(value.typeName,
- sourceId),
- value.aliasPropertyName,
- value.aliasPropertyNameTail);
- return Sqlite::CallbackControl::Abort;
- };
-
- insertAliasPropertyDeclarationStatement.readCallback(callback, typeId, value.name);
- }
+ TypeId typeId);
+
+ QVarLengthArray<PropertyDeclarationId, 128> fetchPropertyDeclarationIds(TypeId baseTypeId) const;
+
+ PropertyDeclarationId fetchNextPropertyDeclarationId(TypeId baseTypeId,
+ Utils::SmallStringView propertyName) const;
+
+ PropertyDeclarationId fetchPropertyDeclarationId(TypeId typeId,
+ Utils::SmallStringView propertyName) const;
+
+ PropertyDeclarationId fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const;
+
+ PropertyDeclarationId fetchDefaultPropertyDeclarationId(TypeId typeId) const;
void synchronizePropertyDeclarationsInsertProperty(
- const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId)
- {
- auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId);
- auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId);
-
- if (!propertyTypeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId)};
-
- auto propertyDeclarationId = insertPropertyDeclarationStatement.template value<PropertyDeclarationId>(
- typeId, value.name, propertyTypeId, value.traits, propertyImportedTypeNameId);
-
- auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement
- .template value<PropertyDeclarationId>(typeId,
- value.name);
- if (nextPropertyDeclarationId) {
- updateAliasIdPropertyDeclarationStatement.write(nextPropertyDeclarationId,
- propertyDeclarationId);
- updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement
- .write(propertyDeclarationId, propertyTypeId, value.traits);
- }
- }
+ const Storage::Synchronization::PropertyDeclaration &value, SourceId sourceId, TypeId typeId);
void synchronizePropertyDeclarationsUpdateAlias(
AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
const Storage::Synchronization::PropertyDeclarationView &view,
const Storage::Synchronization::PropertyDeclaration &value,
- SourceId sourceId)
- {
- auto last = updatedAliasPropertyDeclarations.emplace_back(view.typeId,
- view.id,
- fetchImportedTypeNameId(value.typeName,
- sourceId),
- value.aliasPropertyName,
- value.aliasPropertyNameTail,
- view.aliasId);
- }
+ SourceId sourceId);
- auto synchronizePropertyDeclarationsUpdateProperty(
+ Sqlite::UpdateChange synchronizePropertyDeclarationsUpdateProperty(
const Storage::Synchronization::PropertyDeclarationView &view,
const Storage::Synchronization::PropertyDeclaration &value,
SourceId sourceId,
- PropertyDeclarationIds &propertyDeclarationIds)
- {
- auto propertyImportedTypeNameId = fetchImportedTypeNameId(value.typeName, sourceId);
-
- auto propertyTypeId = fetchTypeId(propertyImportedTypeNameId);
-
- if (!propertyTypeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(propertyImportedTypeNameId)};
-
- if (view.traits == value.traits && propertyTypeId == view.typeId
- && propertyImportedTypeNameId == view.typeNameId)
- return Sqlite::UpdateChange::No;
-
- updatePropertyDeclarationStatement.write(view.id,
- propertyTypeId,
- value.traits,
- propertyImportedTypeNameId);
- updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement.write(view.id,
- propertyTypeId,
- value.traits);
- propertyDeclarationIds.push_back(view.id);
- return Sqlite::UpdateChange::Update;
- }
+ PropertyDeclarationIds &propertyDeclarationIds);
void synchronizePropertyDeclarations(
TypeId typeId,
@@ -1801,270 +706,78 @@ private:
SourceId sourceId,
AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
- PropertyDeclarationIds &propertyDeclarationIds)
- {
- NanotraceHR::Tracer tracer{"synchronize property declaration"_t, projectStorageCategory()};
-
- std::sort(propertyDeclarations.begin(),
- propertyDeclarations.end(),
- [](auto &&first, auto &&second) {
- return Sqlite::compare(first.name, second.name) < 0;
- });
-
- auto range = selectPropertyDeclarationsForTypeIdStatement
- .template range<Storage::Synchronization::PropertyDeclarationView>(typeId);
-
- auto compareKey = [](const Storage::Synchronization::PropertyDeclarationView &view,
- const Storage::Synchronization::PropertyDeclaration &value) {
- return Sqlite::compare(view.name, value.name);
- };
-
- auto insert = [&](const Storage::Synchronization::PropertyDeclaration &value) {
- if (value.kind == Storage::Synchronization::PropertyKind::Alias) {
- synchronizePropertyDeclarationsInsertAlias(insertedAliasPropertyDeclarations,
- value,
- sourceId,
- typeId);
- } else {
- synchronizePropertyDeclarationsInsertProperty(value, sourceId, typeId);
- }
- };
-
- auto update = [&](const Storage::Synchronization::PropertyDeclarationView &view,
- const Storage::Synchronization::PropertyDeclaration &value) {
- if (value.kind == Storage::Synchronization::PropertyKind::Alias) {
- synchronizePropertyDeclarationsUpdateAlias(updatedAliasPropertyDeclarations,
- view,
- value,
- sourceId);
- propertyDeclarationIds.push_back(view.id);
- } else {
- return synchronizePropertyDeclarationsUpdateProperty(view,
- value,
- sourceId,
- propertyDeclarationIds);
- }
-
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::PropertyDeclarationView &view) {
- auto nextPropertyDeclarationId = selectPropertyDeclarationIdPrototypeChainDownStatement
- .template value<PropertyDeclarationId>(typeId,
- view.name);
- if (nextPropertyDeclarationId) {
- updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement
- .write(nextPropertyDeclarationId, view.id);
- }
-
- updateDefaultPropertyIdToNullStatement.write(view.id);
- deletePropertyDeclarationStatement.write(view.id);
- propertyDeclarationIds.push_back(view.id);
- };
-
- Sqlite::insertUpdateDelete(range, propertyDeclarations, compareKey, insert, update, remove);
- }
+ PropertyDeclarationIds &propertyDeclarationIds);
- void resetRemovedAliasPropertyDeclarationsToNull(Storage::Synchronization::Type &type,
- PropertyDeclarationIds &propertyDeclarationIds)
+ class AliasPropertyDeclarationView
{
- if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
- return;
-
- Storage::Synchronization::PropertyDeclarations &aliasDeclarations = type.propertyDeclarations;
+ public:
+ explicit AliasPropertyDeclarationView(Utils::SmallStringView name,
+ PropertyDeclarationId id,
+ PropertyDeclarationId aliasId)
+ : name{name}
+ , id{id}
+ , aliasId{aliasId}
+ {}
- class AliasPropertyDeclarationView
+ template<typename String>
+ friend void convertToString(String &string,
+ const AliasPropertyDeclarationView &aliasPropertyDeclarationView)
{
- public:
- explicit AliasPropertyDeclarationView(Utils::SmallStringView name,
- PropertyDeclarationId id,
- PropertyDeclarationId aliasId)
- : name{name}
- , id{id}
- , aliasId{aliasId}
- {}
-
- public:
- Utils::SmallStringView name;
- PropertyDeclarationId id;
- PropertyDeclarationId aliasId;
- };
-
- std::sort(aliasDeclarations.begin(), aliasDeclarations.end(), [](auto &&first, auto &&second) {
- return Sqlite::compare(first.name, second.name) < 0;
- });
-
- auto range = selectPropertyDeclarationsWithAliasForTypeIdStatement
- .template range<AliasPropertyDeclarationView>(type.typeId);
-
- auto compareKey = [](const AliasPropertyDeclarationView &view,
- const Storage::Synchronization::PropertyDeclaration &value) {
- return Sqlite::compare(view.name, value.name);
- };
-
- auto insert = [&](const Storage::Synchronization::PropertyDeclaration &) {};
-
- auto update = [&](const AliasPropertyDeclarationView &,
- const Storage::Synchronization::PropertyDeclaration &) {
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const AliasPropertyDeclarationView &view) {
- updatePropertyDeclarationAliasIdToNullStatement.write(view.id);
- propertyDeclarationIds.push_back(view.id);
- };
-
- Sqlite::insertUpdateDelete(range, aliasDeclarations, compareKey, insert, update, remove);
- }
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", aliasPropertyDeclarationView.name),
+ keyValue("id", aliasPropertyDeclarationView.id),
+ keyValue("alias id", aliasPropertyDeclarationView.aliasId));
- void resetRemovedAliasPropertyDeclarationsToNull(
- Storage::Synchronization::Types &types,
- AliasPropertyDeclarations &relinkableAliasPropertyDeclarations)
- {
- NanotraceHR::Tracer tracer{"reset removed alias properties to null"_t,
- projectStorageCategory()};
+ convertToString(string, dict);
+ }
- PropertyDeclarationIds propertyDeclarationIds;
- propertyDeclarationIds.reserve(types.size());
+ public:
+ Utils::SmallStringView name;
+ PropertyDeclarationId id;
+ PropertyDeclarationId aliasId;
+ };
- for (auto &&type : types)
- resetRemovedAliasPropertyDeclarationsToNull(type, propertyDeclarationIds);
+ void resetRemovedAliasPropertyDeclarationsToNull(Storage::Synchronization::Type &type,
+ PropertyDeclarationIds &propertyDeclarationIds);
- removeRelinkableEntries(relinkableAliasPropertyDeclarations,
- propertyDeclarationIds,
- PropertyCompare<AliasPropertyDeclaration>{});
- }
+ void resetRemovedAliasPropertyDeclarationsToNull(
+ Storage::Synchronization::Types &types,
+ AliasPropertyDeclarations &relinkableAliasPropertyDeclarations);
+
+ void handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId,
+ TypeId prototypeId,
+ Prototypes &relinkablePrototypes);
+ void handlePrototypesAndExtensionsWithSourceId(SourceId sourceId,
+ TypeId prototypeId,
+ TypeId extensionId,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions);
+ void handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId,
+ TypeId extensionId,
+ Prototypes &relinkableExtensions);
ImportId insertDocumentImport(const Storage::Import &import,
Storage::Synchronization::ImportKind importKind,
ModuleId sourceModuleId,
- ImportId parentImportId)
- {
- if (import.version.minor) {
- return insertDocumentImportWithVersionStatement
- .template value<ImportId>(import.sourceId,
- import.moduleId,
- sourceModuleId,
- importKind,
- import.version.major.value,
- import.version.minor.value,
- parentImportId);
- } else if (import.version.major) {
- return insertDocumentImportWithMajorVersionStatement
- .template value<ImportId>(import.sourceId,
- import.moduleId,
- sourceModuleId,
- importKind,
- import.version.major.value,
- parentImportId);
- } else {
- return insertDocumentImportWithoutVersionStatement.template value<ImportId>(
- import.sourceId, import.moduleId, sourceModuleId, importKind, parentImportId);
- }
- }
+ ImportId parentImportId,
+ Relink forceRelink,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions);
void synchronizeDocumentImports(Storage::Imports &imports,
const SourceIds &updatedSourceIds,
- Storage::Synchronization::ImportKind importKind)
- {
- std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
- return std::tie(first.sourceId, first.moduleId, first.version)
- < std::tie(second.sourceId, second.moduleId, second.version);
- });
-
- auto range = selectDocumentImportForSourceIdStatement
- .template range<Storage::Synchronization::ImportView>(toIntegers(
- updatedSourceIds),
- importKind);
-
- auto compareKey = [](const Storage::Synchronization::ImportView &view,
- const Storage::Import &import) -> long long {
- auto sourceIdDifference = view.sourceId - import.sourceId;
- if (sourceIdDifference != 0)
- return sourceIdDifference;
-
- auto moduleIdDifference = view.moduleId - import.moduleId;
- if (moduleIdDifference != 0)
- return moduleIdDifference;
-
- auto versionDifference = view.version.major.value - import.version.major.value;
- if (versionDifference != 0)
- return versionDifference;
-
- return view.version.minor.value - import.version.minor.value;
- };
-
- auto insert = [&](const Storage::Import &import) {
- auto importId = insertDocumentImport(import, importKind, import.moduleId, ImportId{});
- auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) {
- Storage::Import additionImport{exportedModuleId,
- Storage::Version{majorVersion, minorVersion},
- import.sourceId};
-
- auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import
- ? Storage::Synchronization::ImportKind::ModuleExportedImport
- : Storage::Synchronization::ImportKind::ModuleExportedModuleDependency;
-
- insertDocumentImport(additionImport, exportedImportKind, import.moduleId, importId);
- };
-
- selectModuleExportedImportsForModuleIdStatement.readCallback(callback,
- import.moduleId,
- import.version.major.value,
- import.version.minor.value);
- };
-
- auto update = [](const Storage::Synchronization::ImportView &, const Storage::Import &) {
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::ImportView &view) {
- deleteDocumentImportStatement.write(view.importId);
- deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId);
- };
-
- Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
- }
-
- static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations &parameters)
- {
- Utils::PathString json;
- json.append("[");
-
- Utils::SmallStringView comma{""};
-
- for (const auto &parameter : parameters) {
- json.append(comma);
- comma = ",";
- json.append(R"({"n":")");
- json.append(parameter.name);
- json.append(R"(","tn":")");
- json.append(parameter.typeName);
- if (parameter.traits == Storage::PropertyDeclarationTraits::None) {
- json.append("\"}");
- } else {
- json.append(R"(","tr":)");
- json.append(Utils::SmallString::number(to_underlying(parameter.traits)));
- json.append("}");
- }
- }
+ Storage::Synchronization::ImportKind importKind,
+ Relink forceRelink,
+ Prototypes &relinkablePrototypes,
+ Prototypes &relinkableExtensions);
- json.append("]");
-
- return json;
- }
+ static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations &parameters);
TypeId fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId,
- Utils::SmallStringView name) const override
- {
- return selectTypeIdByModuleIdAndExportedNameStatement.template value<TypeId>(moduleId, name);
- }
+ Utils::SmallStringView name) const override;
- void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths)
- {
- for (auto &path : paths)
- path.typeId = fetchTypeIdByModuleIdAndExportedName(path.moduleId, path.typeName);
- }
+ void addTypeIdToPropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths);
class PropertyEditorQmlPathView
{
@@ -2075,6 +788,19 @@ private:
, directoryId{directoryId}
{}
+ template<typename String>
+ friend void convertToString(String &string,
+ const PropertyEditorQmlPathView &propertyEditorQmlPathView)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", propertyEditorQmlPathView.typeId),
+ keyValue("source id", propertyEditorQmlPathView.pathId),
+ keyValue("directory id", propertyEditorQmlPathView.directoryId));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId typeId;
SourceId pathId;
@@ -2082,279 +808,33 @@ private:
};
void synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths,
- SourceIds updatedPropertyEditorQmlPathsSourceIds)
- {
- using Storage::Synchronization::PropertyEditorQmlPath;
- std::sort(paths.begin(), paths.end(), [](auto &&first, auto &&second) {
- return first.typeId < second.typeId;
- });
-
- auto range = selectPropertyEditorPathsForForSourceIdsStatement
- .template range<PropertyEditorQmlPathView>(
- toIntegers(updatedPropertyEditorQmlPathsSourceIds));
-
- auto compareKey = [](const PropertyEditorQmlPathView &view,
- const PropertyEditorQmlPath &value) -> long long {
- return view.typeId - value.typeId;
- };
-
- auto insert = [&](const PropertyEditorQmlPath &path) {
- if (path.typeId)
- insertPropertyEditorPathStatement.write(path.typeId, path.pathId, path.directoryId);
- };
-
- auto update = [&](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) {
- if (value.pathId != view.pathId || value.directoryId != view.directoryId) {
- updatePropertyEditorPathsStatement.write(value.typeId, value.pathId, value.directoryId);
- return Sqlite::UpdateChange::Update;
- }
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const PropertyEditorQmlPathView &view) {
- deletePropertyEditorPathStatement.write(view.typeId);
- };
-
- Sqlite::insertUpdateDelete(range, paths, compareKey, insert, update, remove);
- }
+ SourceIds updatedPropertyEditorQmlPathsSourceIds);
void synchronizePropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths,
- SourceIds updatedPropertyEditorQmlPathsSourceIds)
- {
- NanotraceHR::Tracer tracer{"synchronize property editor qml paths"_t,
- projectStorageCategory()};
-
- addTypeIdToPropertyEditorQmlPaths(paths);
- synchronizePropertyEditorPaths(paths, updatedPropertyEditorQmlPathsSourceIds);
- }
+ SourceIds updatedPropertyEditorQmlPathsSourceIds);
void synchronizeFunctionDeclarations(
- TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations)
- {
- NanotraceHR::Tracer tracer{"synchronize function declaration"_t, projectStorageCategory()};
-
- std::sort(functionsDeclarations.begin(),
- functionsDeclarations.end(),
- [](auto &&first, auto &&second) {
- auto compare = Sqlite::compare(first.name, second.name);
-
- if (compare == 0) {
- Utils::PathString firstSignature{createJson(first.parameters)};
- Utils::PathString secondSignature{createJson(second.parameters)};
-
- return Sqlite::compare(firstSignature, secondSignature) < 0;
- }
-
- return compare < 0;
- });
-
- auto range = selectFunctionDeclarationsForTypeIdStatement
- .template range<Storage::Synchronization::FunctionDeclarationView>(typeId);
-
- auto compareKey = [](const Storage::Synchronization::FunctionDeclarationView &view,
- const Storage::Synchronization::FunctionDeclaration &value) {
- auto nameKey = Sqlite::compare(view.name, value.name);
- if (nameKey != 0)
- return nameKey;
-
- Utils::PathString valueSignature{createJson(value.parameters)};
-
- return Sqlite::compare(view.signature, valueSignature);
- };
-
- auto insert = [&](const Storage::Synchronization::FunctionDeclaration &value) {
- Utils::PathString signature{createJson(value.parameters)};
-
- insertFunctionDeclarationStatement.write(typeId, value.name, value.returnTypeName, signature);
- };
-
- auto update = [&](const Storage::Synchronization::FunctionDeclarationView &view,
- const Storage::Synchronization::FunctionDeclaration &value) {
- Utils::PathString signature{createJson(value.parameters)};
-
- if (value.returnTypeName == view.returnTypeName)
- return Sqlite::UpdateChange::No;
-
- updateFunctionDeclarationStatement.write(view.id, value.returnTypeName);
-
- return Sqlite::UpdateChange::Update;
- };
-
- auto remove = [&](const Storage::Synchronization::FunctionDeclarationView &view) {
- deleteFunctionDeclarationStatement.write(view.id);
- };
-
- Sqlite::insertUpdateDelete(range, functionsDeclarations, compareKey, insert, update, remove);
- }
+ TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations);
void synchronizeSignalDeclarations(TypeId typeId,
- Storage::Synchronization::SignalDeclarations &signalDeclarations)
- {
- NanotraceHR::Tracer tracer{"synchronize signal declaration"_t, projectStorageCategory()};
-
- std::sort(signalDeclarations.begin(), signalDeclarations.end(), [](auto &&first, auto &&second) {
- auto compare = Sqlite::compare(first.name, second.name);
-
- if (compare == 0) {
- Utils::PathString firstSignature{createJson(first.parameters)};
- Utils::PathString secondSignature{createJson(second.parameters)};
-
- return Sqlite::compare(firstSignature, secondSignature) < 0;
- }
-
- return compare < 0;
- });
-
- auto range = selectSignalDeclarationsForTypeIdStatement
- .template range<Storage::Synchronization::SignalDeclarationView>(typeId);
-
- auto compareKey = [](const Storage::Synchronization::SignalDeclarationView &view,
- const Storage::Synchronization::SignalDeclaration &value) {
- auto nameKey = Sqlite::compare(view.name, value.name);
- if (nameKey != 0)
- return nameKey;
-
- Utils::PathString valueSignature{createJson(value.parameters)};
-
- return Sqlite::compare(view.signature, valueSignature);
- };
-
- auto insert = [&](const Storage::Synchronization::SignalDeclaration &value) {
- Utils::PathString signature{createJson(value.parameters)};
-
- insertSignalDeclarationStatement.write(typeId, value.name, signature);
- };
-
- auto update = [&]([[maybe_unused]] const Storage::Synchronization::SignalDeclarationView &view,
- [[maybe_unused]] const Storage::Synchronization::SignalDeclaration &value) {
- return Sqlite::UpdateChange::No;
- };
-
- auto remove = [&](const Storage::Synchronization::SignalDeclarationView &view) {
- deleteSignalDeclarationStatement.write(view.id);
- };
-
- Sqlite::insertUpdateDelete(range, signalDeclarations, compareKey, insert, update, remove);
- }
+ Storage::Synchronization::SignalDeclarations &signalDeclarations);
static Utils::PathString createJson(
- const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations)
- {
- Utils::PathString json;
- json.append("{");
-
- Utils::SmallStringView comma{"\""};
-
- for (const auto &enumerator : enumeratorDeclarations) {
- json.append(comma);
- comma = ",\"";
- json.append(enumerator.name);
- if (enumerator.hasValue) {
- json.append("\":\"");
- json.append(Utils::SmallString::number(enumerator.value));
- json.append("\"");
- } else {
- json.append("\":null");
- }
- }
-
- json.append("}");
-
- return json;
- }
+ const Storage::Synchronization::EnumeratorDeclarations &enumeratorDeclarations);
void synchronizeEnumerationDeclarations(
- TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations)
- {
- NanotraceHR::Tracer tracer{"synchronize enumeation declaration"_t, projectStorageCategory()};
-
- std::sort(enumerationDeclarations.begin(),
- enumerationDeclarations.end(),
- [](auto &&first, auto &&second) {
- return Sqlite::compare(first.name, second.name) < 0;
- });
-
- auto range = selectEnumerationDeclarationsForTypeIdStatement
- .template range<Storage::Synchronization::EnumerationDeclarationView>(typeId);
-
- auto compareKey = [](const Storage::Synchronization::EnumerationDeclarationView &view,
- const Storage::Synchronization::EnumerationDeclaration &value) {
- return Sqlite::compare(view.name, value.name);
- };
-
- auto insert = [&](const Storage::Synchronization::EnumerationDeclaration &value) {
- Utils::PathString signature{createJson(value.enumeratorDeclarations)};
-
- insertEnumerationDeclarationStatement.write(typeId, value.name, signature);
- };
-
- auto update = [&](const Storage::Synchronization::EnumerationDeclarationView &view,
- const Storage::Synchronization::EnumerationDeclaration &value) {
- Utils::PathString enumeratorDeclarations{createJson(value.enumeratorDeclarations)};
-
- if (enumeratorDeclarations == view.enumeratorDeclarations)
- return Sqlite::UpdateChange::No;
-
- updateEnumerationDeclarationStatement.write(view.id, enumeratorDeclarations);
-
- return Sqlite::UpdateChange::Update;
- };
-
- auto remove = [&](const Storage::Synchronization::EnumerationDeclarationView &view) {
- deleteEnumerationDeclarationStatement.write(view.id);
- };
-
- Sqlite::insertUpdateDelete(range, enumerationDeclarations, compareKey, insert, update, remove);
- }
+ TypeId typeId, Storage::Synchronization::EnumerationDeclarations &enumerationDeclarations);
void extractExportedTypes(TypeId typeId,
const Storage::Synchronization::Type &type,
- Storage::Synchronization::ExportedTypes &exportedTypes)
- {
- for (const auto &exportedType : type.exportedTypes)
- exportedTypes.emplace_back(exportedType.name,
- exportedType.version,
- typeId,
- exportedType.moduleId);
- }
-
- TypeId declareType(Storage::Synchronization::Type &type)
- {
- if (type.typeName.isEmpty()) {
- type.typeId = selectTypeIdBySourceIdStatement.template value<TypeId>(type.sourceId);
-
- return type.typeId;
- }
+ Storage::Synchronization::ExportedTypes &exportedTypes);
- type.typeId = insertTypeStatement.template value<TypeId>(type.sourceId, type.typeName);
-
- if (!type.typeId)
- type.typeId = selectTypeIdBySourceIdAndNameStatement.template value<TypeId>(type.sourceId,
- type.typeName);
-
- return type.typeId;
- }
+ TypeId declareType(Storage::Synchronization::Type &type);
void syncDeclarations(Storage::Synchronization::Type &type,
AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
- PropertyDeclarationIds &propertyDeclarationIds)
- {
- NanotraceHR::Tracer tracer{"synchronize declaration per type"_t, projectStorageCategory()};
-
- if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
- return;
-
- synchronizePropertyDeclarations(type.typeId,
- type.propertyDeclarations,
- type.sourceId,
- insertedAliasPropertyDeclarations,
- updatedAliasPropertyDeclarations,
- propertyDeclarationIds);
- synchronizeFunctionDeclarations(type.typeId, type.functionDeclarations);
- synchronizeSignalDeclarations(type.typeId, type.signalDeclarations);
- synchronizeEnumerationDeclarations(type.typeId, type.enumerationDeclarations);
- }
+ PropertyDeclarationIds &propertyDeclarationIds);
template<typename Relinkable, typename Ids, typename Compare>
void removeRelinkableEntries(std::vector<Relinkable> &relinkables, Ids &ids, Compare compare)
@@ -2381,23 +861,7 @@ private:
void syncDeclarations(Storage::Synchronization::Types &types,
AliasPropertyDeclarations &insertedAliasPropertyDeclarations,
AliasPropertyDeclarations &updatedAliasPropertyDeclarations,
- PropertyDeclarations &relinkablePropertyDeclarations)
- {
- NanotraceHR::Tracer tracer{"synchronize declaration"_t, projectStorageCategory()};
-
- PropertyDeclarationIds propertyDeclarationIds;
- propertyDeclarationIds.reserve(types.size() * 10);
-
- for (auto &&type : types)
- syncDeclarations(type,
- insertedAliasPropertyDeclarations,
- updatedAliasPropertyDeclarations,
- propertyDeclarationIds);
-
- removeRelinkableEntries(relinkablePropertyDeclarations,
- propertyDeclarationIds,
- PropertyCompare<PropertyDeclaration>{});
- }
+ PropertyDeclarations &relinkablePropertyDeclarations);
class TypeWithDefaultPropertyView
{
@@ -2407,240 +871,55 @@ private:
, defaultPropertyId{defaultPropertyId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const TypeWithDefaultPropertyView &view)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", view.typeId),
+ keyValue("property id", view.defaultPropertyId));
+
+ convertToString(string, dict);
+ }
+
TypeId typeId;
PropertyDeclarationId defaultPropertyId;
};
- void syncDefaultProperties(Storage::Synchronization::Types &types)
- {
- NanotraceHR::Tracer tracer{"synchronize default properties"_t, projectStorageCategory()};
-
- auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>();
-
- auto compareKey = [](const TypeWithDefaultPropertyView &view,
- const Storage::Synchronization::Type &value) {
- return view.typeId - value.typeId;
- };
-
- auto insert = [&](const Storage::Synchronization::Type &) {
-
- };
-
- auto update = [&](const TypeWithDefaultPropertyView &view,
- const Storage::Synchronization::Type &value) {
- PropertyDeclarationId valueDefaultPropertyId;
- if (value.defaultPropertyName.size())
- valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded(
- value.typeId, value.defaultPropertyName)
- .propertyDeclarationId;
+ void syncDefaultProperties(Storage::Synchronization::Types &types);
- if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId))
- return Sqlite::UpdateChange::No;
+ void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types);
- updateDefaultPropertyIdStatement.write(value.typeId, valueDefaultPropertyId);
+ void checkForPrototypeChainCycle(TypeId typeId) const;
- return Sqlite::UpdateChange::Update;
- };
-
- auto remove = [&](const TypeWithDefaultPropertyView &) {};
-
- Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove);
- }
-
- void resetDefaultPropertiesIfChanged(Storage::Synchronization::Types &types)
- {
- NanotraceHR::Tracer tracer{"reset changed default properties"_t, projectStorageCategory()};
-
- auto range = selectTypesWithDefaultPropertyStatement.template range<TypeWithDefaultPropertyView>();
-
- auto compareKey = [](const TypeWithDefaultPropertyView &view,
- const Storage::Synchronization::Type &value) {
- return view.typeId - value.typeId;
- };
-
- auto insert = [&](const Storage::Synchronization::Type &) {
-
- };
-
- auto update = [&](const TypeWithDefaultPropertyView &view,
- const Storage::Synchronization::Type &value) {
- PropertyDeclarationId valueDefaultPropertyId;
- if (value.defaultPropertyName.size()) {
- auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(
- value.typeId, value.defaultPropertyName);
- if (optionalValueDefaultPropertyId)
- valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId;
- }
-
- if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId))
- return Sqlite::UpdateChange::No;
-
- updateDefaultPropertyIdStatement.write(value.typeId, Sqlite::NullValue{});
-
- return Sqlite::UpdateChange::Update;
- };
-
- auto remove = [&](const TypeWithDefaultPropertyView &) {};
-
- Sqlite::insertUpdateDelete(range, types, compareKey, insert, update, remove);
- }
-
- void checkForPrototypeChainCycle(TypeId typeId) const
- {
- auto callback = [=](TypeId currentTypeId) {
- if (typeId == currentTypeId)
- throw PrototypeChainCycle{};
- };
-
- selectTypeIdsForPrototypeChainIdStatement.readCallback(callback, typeId);
- }
-
- void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const
- {
- auto callback = [=](PropertyDeclarationId currentPropertyDeclarationId) {
- if (propertyDeclarationId == currentPropertyDeclarationId)
- throw AliasChainCycle{};
- };
-
- selectPropertyDeclarationIdsForAliasChainStatement.readCallback(callback,
- propertyDeclarationId);
- }
+ void checkForAliasChainCycle(PropertyDeclarationId propertyDeclarationId) const;
std::pair<TypeId, ImportedTypeNameId> fetchImportedTypeNameIdAndTypeId(
- const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId)
- {
- TypeId typeId;
- ImportedTypeNameId typeNameId;
- if (!std::visit([](auto &&typeName_) -> bool { return typeName_.name.isEmpty(); }, typeName)) {
- typeNameId = fetchImportedTypeNameId(typeName, sourceId);
-
- typeId = fetchTypeId(typeNameId);
-
- if (!typeId)
- throw TypeNameDoesNotExists{fetchImportedTypeName(typeNameId)};
- }
-
- return {typeId, typeNameId};
- }
+ const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId);
- void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds)
- {
- if (type.changeLevel == Storage::Synchronization::ChangeLevel::Minimal)
- return;
-
- auto [prototypeId, prototypeTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.prototype,
- type.sourceId);
- auto [extensionId, extensionTypeNameId] = fetchImportedTypeNameIdAndTypeId(type.extension,
- type.sourceId);
-
- updatePrototypeAndExtensionStatement.write(type.typeId,
- prototypeId,
- prototypeTypeNameId,
- extensionId,
- extensionTypeNameId);
-
- if (prototypeId || extensionId)
- checkForPrototypeChainCycle(type.typeId);
-
- typeIds.push_back(type.typeId);
- }
+ void syncPrototypeAndExtension(Storage::Synchronization::Type &type, TypeIds &typeIds);
void syncPrototypesAndExtensions(Storage::Synchronization::Types &types,
Prototypes &relinkablePrototypes,
- Prototypes &relinkableExtensions)
- {
- NanotraceHR::Tracer tracer{"synchronize prototypes"_t, projectStorageCategory()};
-
- TypeIds typeIds;
- typeIds.reserve(types.size());
+ Prototypes &relinkableExtensions);
- for (auto &type : types)
- syncPrototypeAndExtension(type, typeIds);
-
- removeRelinkableEntries(relinkablePrototypes, typeIds, TypeCompare<Prototype>{});
- removeRelinkableEntries(relinkableExtensions, typeIds, TypeCompare<Prototype>{});
- }
-
- ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const
- {
- if (import.version) {
- return selectImportIdBySourceIdAndModuleIdAndVersionStatement.template value<ImportId>(
- sourceId, import.moduleId, import.version.major.value, import.version.minor.value);
- }
-
- if (import.version.major) {
- return selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement
- .template value<ImportId>(sourceId, import.moduleId, import.version.major.value);
- }
-
- return selectImportIdBySourceIdAndModuleIdStatement.template value<ImportId>(sourceId,
- import.moduleId);
- }
+ ImportId fetchImportId(SourceId sourceId, const Storage::Import &import) const;
ImportedTypeNameId fetchImportedTypeNameId(const Storage::Synchronization::ImportedTypeName &name,
- SourceId sourceId)
- {
- struct Inspect
- {
- auto operator()(const Storage::Synchronization::ImportedType &importedType)
- {
- return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::Exported,
- sourceId,
- importedType.name);
- }
-
- auto operator()(const Storage::Synchronization::QualifiedImportedType &importedType)
- {
- ImportId importId = storage.fetchImportId(sourceId, importedType.import);
-
- return storage.fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind::QualifiedExported,
- importId,
- importedType.name);
- }
-
- ProjectStorage &storage;
- SourceId sourceId;
- };
-
- return std::visit(Inspect{*this, sourceId}, name);
- }
+ SourceId sourceId);
template<typename Id>
ImportedTypeNameId fetchImportedTypeNameId(Storage::Synchronization::TypeNameKind kind,
Id id,
- Utils::SmallStringView typeName)
- {
- auto importedTypeNameId = selectImportedTypeNameIdStatement
- .template value<ImportedTypeNameId>(kind, id, typeName);
-
- if (importedTypeNameId)
- return importedTypeNameId;
-
- return insertImportedTypeNameIdStatement.template value<ImportedTypeNameId>(kind, id, typeName);
- }
-
- TypeId fetchTypeId(ImportedTypeNameId typeNameId) const
- {
- auto kind = selectKindFromImportedTypeNamesStatement
- .template value<Storage::Synchronization::TypeNameKind>(typeNameId);
-
- return fetchTypeId(typeNameId, kind);
- }
+ Utils::SmallStringView typeName);
- Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const
- {
- return selectNameFromImportedTypeNamesStatement.template value<Utils::SmallString>(typeNameId);
- }
+ TypeId fetchTypeId(ImportedTypeNameId typeNameId) const;
- TypeId fetchTypeId(ImportedTypeNameId typeNameId, Storage::Synchronization::TypeNameKind kind) const
- {
- if (kind == Storage::Synchronization::TypeNameKind::QualifiedExported) {
- return selectTypeIdForQualifiedImportedTypeNameNamesStatement.template value<TypeId>(
- typeNameId);
- }
+ Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const;
+ SourceId fetchTypeSourceId(TypeId typeId) const;
- return selectTypeIdForImportedTypeNameNamesStatement.template value<TypeId>(typeNameId);
- }
+ TypeId fetchTypeId(ImportedTypeNameId typeNameId,
+ Storage::Synchronization::TypeNameKind kind) const;
class FetchPropertyDeclarationResult
{
@@ -2653,1303 +932,65 @@ private:
, propertyTraits{propertyTraits}
{}
+ template<typename String>
+ friend void convertToString(String &string, const FetchPropertyDeclarationResult &result)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("property type id", result.propertyTypeId),
+ keyValue("property declaration id", result.propertyDeclarationId),
+ keyValue("property traits", result.propertyTraits));
+
+ convertToString(string, dict);
+ }
+
public:
TypeId propertyTypeId;
PropertyDeclarationId propertyDeclarationId;
Storage::PropertyDeclarationTraits propertyTraits;
};
- auto fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId,
- Utils::SmallStringView name)
- {
- return selectPropertyDeclarationByTypeIdAndNameStatement
- .template optionalValue<FetchPropertyDeclarationResult>(typeId, name);
- }
+ std::optional<FetchPropertyDeclarationResult> fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(
+ TypeId typeId, Utils::SmallStringView name);
FetchPropertyDeclarationResult fetchPropertyDeclarationByTypeIdAndNameUngarded(
- TypeId typeId, Utils::SmallStringView name)
- {
- auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId,
- name);
-
- if (propertyDeclaration)
- return *propertyDeclaration;
-
- throw PropertyNameDoesNotExists{};
- }
+ TypeId typeId, Utils::SmallStringView name);
PropertyDeclarationId fetchPropertyDeclarationIdByTypeIdAndNameUngarded(TypeId typeId,
- Utils::SmallStringView name)
- {
- auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement
- .template value<PropertyDeclarationId>(typeId, name);
+ Utils::SmallStringView name);
- if (propertyDeclarationId)
- return propertyDeclarationId;
+ SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath);
- throw PropertyNameDoesNotExists{};
- }
+ SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath);
- SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath)
- {
- return selectSourceContextIdFromSourceContextsBySourceContextPathStatement
- .template value<SourceContextId>(sourceContextPath);
- }
+ SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
- SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath)
- {
- insertIntoSourceContextsStatement.write(sourceContextPath);
+ SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName);
- return SourceContextId::create(database.lastInsertedRowId());
- }
+ Storage::Synchronization::ExportedTypes fetchExportedTypes(TypeId typeId);
- SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
- {
- insertIntoSourcesStatement.write(sourceContextId, sourceName);
+ Storage::Synchronization::PropertyDeclarations fetchPropertyDeclarations(TypeId typeId);
- return SourceId::create(database.lastInsertedRowId());
- }
-
- SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
- {
- return selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement
- .template value<SourceId>(sourceContextId, sourceName);
- }
-
- auto fetchExportedTypes(TypeId typeId)
- {
- return selectExportedTypesByTypeIdStatement
- .template values<Storage::Synchronization::ExportedType, 12>(typeId);
- }
-
- auto fetchPropertyDeclarations(TypeId typeId)
- {
- return selectPropertyDeclarationsByTypeIdStatement
- .template values<Storage::Synchronization::PropertyDeclaration, 24>(typeId);
- }
-
- auto fetchFunctionDeclarations(TypeId typeId)
- {
- Storage::Synchronization::FunctionDeclarations functionDeclarations;
-
- auto callback = [&](Utils::SmallStringView name,
- Utils::SmallStringView returnType,
- FunctionDeclarationId functionDeclarationId) {
- auto &functionDeclaration = functionDeclarations.emplace_back(name, returnType);
- functionDeclaration.parameters = selectFunctionParameterDeclarationsStatement
- .template values<Storage::Synchronization::ParameterDeclaration,
- 8>(functionDeclarationId);
- };
-
- selectFunctionDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId);
-
- return functionDeclarations;
- }
-
- auto fetchSignalDeclarations(TypeId typeId)
- {
- Storage::Synchronization::SignalDeclarations signalDeclarations;
-
- auto callback = [&](Utils::SmallStringView name, SignalDeclarationId signalDeclarationId) {
- auto &signalDeclaration = signalDeclarations.emplace_back(name);
- signalDeclaration.parameters = selectSignalParameterDeclarationsStatement
- .template values<Storage::Synchronization::ParameterDeclaration,
- 8>(signalDeclarationId);
- };
-
- selectSignalDeclarationsForTypeIdWithoutSignatureStatement.readCallback(callback, typeId);
-
- return signalDeclarations;
- }
-
- auto fetchEnumerationDeclarations(TypeId typeId)
- {
- Storage::Synchronization::EnumerationDeclarations enumerationDeclarations;
-
- auto callback = [&](Utils::SmallStringView name,
- EnumerationDeclarationId enumerationDeclarationId) {
- enumerationDeclarations.emplace_back(
- name,
- selectEnumeratorDeclarationStatement
- .template values<Storage::Synchronization::EnumeratorDeclaration, 8>(
- enumerationDeclarationId));
- };
-
- selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement
- .readCallback(callback, typeId);
-
- return enumerationDeclarations;
- }
-
- class Initializer
- {
- public:
- Initializer(Database &database, bool isInitialized)
- {
- if (!isInitialized) {
- auto moduleIdColumn = createModulesTable(database);
- createSourceContextsTable(database);
- createSourcesTable(database);
- createTypesAndePropertyDeclarationsTables(database, moduleIdColumn);
- createExportedTypeNamesTable(database, moduleIdColumn);
- createImportedTypeNamesTable(database);
- createEnumerationsTable(database);
- createFunctionsTable(database);
- createSignalsTable(database);
- createModuleExportedImportsTable(database, moduleIdColumn);
- createDocumentImportsTable(database, moduleIdColumn);
- createFileStatusesTable(database);
- createProjectDatasTable(database);
- createPropertyEditorPathsTable(database);
- createTypeAnnotionsTable(database);
- }
- database.setIsInitialized(true);
- }
-
- void createSourceContextsTable(Database &database)
- {
- Sqlite::Table table;
- table.setUseIfNotExists(true);
- table.setName("sourceContexts");
- table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
- const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath");
-
- table.addUniqueIndex({sourceContextPathColumn});
-
- table.initialize(database);
- }
-
- void createSourcesTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("sources");
- table.addColumn("sourceId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
- const auto &sourceContextIdColumn = table.addColumn(
- "sourceContextId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::NotNull{},
- Sqlite::ForeignKey{"sourceContexts",
- "sourceContextId",
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Cascade}});
- const auto &sourceNameColumn = table.addColumn("sourceName",
- Sqlite::StrictColumnType::Text);
- table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn});
-
- table.initialize(database);
- }
-
- void createTypesAndePropertyDeclarationsTables(
- Database &database, [[maybe_unused]] const Sqlite::StrictColumn &foreignModuleIdColumn)
- {
- Sqlite::StrictTable typesTable;
- typesTable.setUseIfNotExists(true);
- typesTable.setName("types");
- typesTable.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
- auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
- auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text);
- typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer);
- auto &prototypeIdColumn = typesTable.addForeignKeyColumn("prototypeId",
- typesTable,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Restrict);
- typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer);
- auto &extensionIdColumn = typesTable.addForeignKeyColumn("extensionId",
- typesTable,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Restrict);
- typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer);
- auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId",
- Sqlite::StrictColumnType::Integer);
- typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer);
- typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn});
- typesTable.addIndex({defaultPropertyIdColumn});
- typesTable.addIndex({prototypeIdColumn});
- typesTable.addIndex({extensionIdColumn});
-
- typesTable.initialize(database);
-
- {
- Sqlite::StrictTable propertyDeclarationTable;
- propertyDeclarationTable.setUseIfNotExists(true);
- propertyDeclarationTable.setName("propertyDeclarations");
- propertyDeclarationTable.addColumn("propertyDeclarationId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &typeIdColumn = propertyDeclarationTable.addColumn("typeId");
- auto &nameColumn = propertyDeclarationTable.addColumn("name");
- propertyDeclarationTable.addForeignKeyColumn("propertyTypeId",
- typesTable,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Restrict);
- propertyDeclarationTable.addColumn("propertyTraits",
- Sqlite::StrictColumnType::Integer);
- propertyDeclarationTable.addColumn("propertyImportedTypeNameId",
- Sqlite::StrictColumnType::Integer);
- auto &aliasPropertyDeclarationIdColumn = propertyDeclarationTable.addForeignKeyColumn(
- "aliasPropertyDeclarationId",
- propertyDeclarationTable,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Restrict);
- auto &aliasPropertyDeclarationTailIdColumn = propertyDeclarationTable.addForeignKeyColumn(
- "aliasPropertyDeclarationTailId",
- propertyDeclarationTable,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Restrict);
-
- propertyDeclarationTable.addUniqueIndex({typeIdColumn, nameColumn});
- propertyDeclarationTable.addIndex({aliasPropertyDeclarationIdColumn},
- "aliasPropertyDeclarationId IS NOT NULL");
- propertyDeclarationTable.addIndex({aliasPropertyDeclarationTailIdColumn},
- "aliasPropertyDeclarationTailId IS NOT NULL");
-
- propertyDeclarationTable.initialize(database);
- }
- }
-
- void createExportedTypeNamesTable(Database &database,
- const Sqlite::StrictColumn &foreignModuleIdColumn)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("exportedTypeNames");
- table.addColumn("exportedTypeNameId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
- foreignModuleIdColumn,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::NoAction);
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
- auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
- auto &majorVersionColumn = table.addColumn("majorVersion",
- Sqlite::StrictColumnType::Integer);
- auto &minorVersionColumn = table.addColumn("minorVersion",
- Sqlite::StrictColumnType::Integer);
-
- table.addUniqueIndex({moduleIdColumn, nameColumn},
- "majorVersion IS NULL AND minorVersion IS NULL");
- table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn},
- "majorVersion IS NOT NULL AND minorVersion IS NULL");
- table.addUniqueIndex({moduleIdColumn, nameColumn, majorVersionColumn, minorVersionColumn},
- "majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
-
- table.addIndex({typeIdColumn});
-
- table.initialize(database);
- }
-
- void createImportedTypeNamesTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("importedTypeNames");
- table.addColumn("importedTypeNameId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &importOrSourceIdColumn = table.addColumn("importOrSourceId");
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
- auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer);
-
- table.addUniqueIndex({kindColumn, importOrSourceIdColumn, nameColumn});
-
- table.initialize(database);
- }
-
- void createEnumerationsTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("enumerationDeclarations");
- table.addColumn("enumerationDeclarationId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
- table.addColumn("enumeratorDeclarations", Sqlite::StrictColumnType::Text);
-
- table.addUniqueIndex({typeIdColumn, nameColumn});
-
- table.initialize(database);
- }
-
- void createFunctionsTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("functionDeclarations");
- table.addColumn("functionDeclarationId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
- auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text);
- table.addColumn("returnTypeName");
-
- table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
-
- table.initialize(database);
- }
-
- void createSignalsTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("signalDeclarations");
- table.addColumn("signalDeclarationId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &typeIdColumn = table.addColumn("typeId", Sqlite::StrictColumnType::Integer);
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
- auto &signatureColumn = table.addColumn("signature", Sqlite::StrictColumnType::Text);
-
- table.addUniqueIndex({typeIdColumn, nameColumn, signatureColumn});
-
- table.initialize(database);
- }
-
- Sqlite::StrictColumn createModulesTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("modules");
- auto &modelIdColumn = table.addColumn("moduleId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &nameColumn = table.addColumn("name", Sqlite::StrictColumnType::Text);
-
- table.addUniqueIndex({nameColumn});
-
- table.initialize(database);
-
- return std::move(modelIdColumn);
- }
-
- void createModuleExportedImportsTable(Database &database,
- const Sqlite::StrictColumn &foreignModuleIdColumn)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("moduleExportedImports");
- table.addColumn("moduleExportedImportId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
- foreignModuleIdColumn,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Cascade,
- Sqlite::Enforment::Immediate);
- auto &sourceIdColumn = table.addColumn("exportedModuleId",
- Sqlite::StrictColumnType::Integer);
- table.addColumn("isAutoVersion", Sqlite::StrictColumnType::Integer);
- table.addColumn("majorVersion", Sqlite::StrictColumnType::Integer);
- table.addColumn("minorVersion", Sqlite::StrictColumnType::Integer);
-
- table.addUniqueIndex({sourceIdColumn, moduleIdColumn});
-
- table.initialize(database);
- }
-
- void createDocumentImportsTable(Database &database,
- const Sqlite::StrictColumn &foreignModuleIdColumn)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("documentImports");
- table.addColumn("importId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
- auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
- auto &moduleIdColumn = table.addForeignKeyColumn("moduleId",
- foreignModuleIdColumn,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Cascade,
- Sqlite::Enforment::Immediate);
- auto &sourceModuleIdColumn = table.addForeignKeyColumn("sourceModuleId",
- foreignModuleIdColumn,
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Cascade,
- Sqlite::Enforment::Immediate);
- auto &kindColumn = table.addColumn("kind", Sqlite::StrictColumnType::Integer);
- auto &majorVersionColumn = table.addColumn("majorVersion",
- Sqlite::StrictColumnType::Integer);
- auto &minorVersionColumn = table.addColumn("minorVersion",
- Sqlite::StrictColumnType::Integer);
- auto &parentImportIdColumn = table.addColumn("parentImportId",
- Sqlite::StrictColumnType::Integer);
-
- table.addUniqueIndex({sourceIdColumn,
- moduleIdColumn,
- kindColumn,
- sourceModuleIdColumn,
- parentImportIdColumn},
- "majorVersion IS NULL AND minorVersion IS NULL");
- table.addUniqueIndex({sourceIdColumn,
- moduleIdColumn,
- kindColumn,
- sourceModuleIdColumn,
- majorVersionColumn,
- parentImportIdColumn},
- "majorVersion IS NOT NULL AND minorVersion IS NULL");
- table.addUniqueIndex({sourceIdColumn,
- moduleIdColumn,
- kindColumn,
- sourceModuleIdColumn,
- majorVersionColumn,
- minorVersionColumn,
- parentImportIdColumn},
- "majorVersion IS NOT NULL AND minorVersion IS NOT NULL");
-
- table.initialize(database);
- }
+ Storage::Synchronization::FunctionDeclarations fetchFunctionDeclarations(TypeId typeId);
- void createFileStatusesTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setName("fileStatuses");
- table.addColumn("sourceId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{},
- Sqlite::ForeignKey{"sources",
- "sourceId",
- Sqlite::ForeignKeyAction::NoAction,
- Sqlite::ForeignKeyAction::Cascade}});
- table.addColumn("size", Sqlite::StrictColumnType::Integer);
- table.addColumn("lastModified", Sqlite::StrictColumnType::Integer);
-
- table.initialize(database);
- }
+ Storage::Synchronization::SignalDeclarations fetchSignalDeclarations(TypeId typeId);
- void createProjectDatasTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setUseWithoutRowId(true);
- table.setName("projectDatas");
- auto &projectSourceIdColumn = table.addColumn("projectSourceId",
- Sqlite::StrictColumnType::Integer);
- auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
- table.addColumn("moduleId", Sqlite::StrictColumnType::Integer);
- table.addColumn("fileType", Sqlite::StrictColumnType::Integer);
-
- table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn});
- table.addUniqueIndex({sourceIdColumn});
-
- table.initialize(database);
- }
+ Storage::Synchronization::EnumerationDeclarations fetchEnumerationDeclarations(TypeId typeId);
- void createPropertyEditorPathsTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setUseWithoutRowId(true);
- table.setName("propertyEditorPaths");
- table.addColumn("typeId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}});
- table.addColumn("pathSourceId", Sqlite::StrictColumnType::Integer);
- auto &directoryIdColumn = table.addColumn("directoryId",
- Sqlite::StrictColumnType::Integer);
-
- table.addIndex({directoryIdColumn});
-
- table.initialize(database);
- }
+ class Initializer;
- void createTypeAnnotionsTable(Database &database)
- {
- Sqlite::StrictTable table;
- table.setUseIfNotExists(true);
- table.setUseWithoutRowId(true);
- table.setName("typeAnnotations");
- auto &typeIdColumn = table.addColumn("typeId",
- Sqlite::StrictColumnType::Integer,
- {Sqlite::PrimaryKey{}});
- auto &sourceIdColumn = table.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
- table.addColumn("iconPath", Sqlite::StrictColumnType::Text);
- table.addColumn("itemLibrary", Sqlite::StrictColumnType::Text);
- table.addColumn("hints", Sqlite::StrictColumnType::Text);
-
- table.addUniqueIndex({sourceIdColumn, typeIdColumn});
-
- table.initialize(database);
- }
- };
+ struct Statements;
public:
Database &database;
+ ProjectStorageErrorNotifierInterface *errorNotifier = nullptr; // cannot be null
Sqlite::ExclusiveNonThrowingDestructorTransaction<Database> exclusiveTransaction;
- Initializer initializer;
+ std::unique_ptr<Initializer> initializer;
mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}};
- Storage::Info::CommonTypeCache<ProjectStorageInterface> commonTypeCache_{*this};
+ Storage::Info::CommonTypeCache<ProjectStorageType> commonTypeCache_{*this};
QVarLengthArray<ProjectStorageObserver *, 24> observers;
- ReadWriteStatement<1, 2> insertTypeStatement{
- "INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database};
- WriteStatement<5> updatePrototypeAndExtensionStatement{
- "UPDATE types SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 "
- "WHERE typeId=?1 AND (prototypeId IS NOT ?2 OR extensionId IS NOT ?3 AND prototypeId "
- "IS NOT ?4 OR extensionNameId IS NOT ?5)",
- database};
- mutable ReadStatement<1, 1> selectTypeIdByExportedNameStatement{
- "SELECT typeId FROM exportedTypeNames WHERE name=?1", database};
- mutable ReadStatement<1, 2> selectTypeIdByModuleIdAndExportedNameStatement{
- "SELECT typeId FROM exportedTypeNames "
- "WHERE moduleId=?1 AND name=?2 "
- "ORDER BY majorVersion DESC, minorVersion DESC "
- "LIMIT 1",
- database};
- mutable ReadStatement<1, 3> selectTypeIdByModuleIdAndExportedNameAndMajorVersionStatement{
- "SELECT typeId FROM exportedTypeNames "
- "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3"
- "ORDER BY minorVersion DESC "
- "LIMIT 1",
- database};
- mutable ReadStatement<1, 4> selectTypeIdByModuleIdAndExportedNameAndVersionStatement{
- "SELECT typeId FROM exportedTypeNames "
- "WHERE moduleId=?1 AND name=?2 AND majorVersion=?3 AND minorVersion<=?4"
- "ORDER BY minorVersion DESC "
- "LIMIT 1",
- database};
- mutable ReadStatement<1, 2> selectPrototypeIdStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId) AS ("
- " VALUES(?1) "
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN typeSelection "
- " USING(typeId))"
- "SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1",
- database};
- mutable ReadStatement<1, 2> selectPropertyDeclarationIdByTypeIdAndNameStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId, level) AS ("
- " VALUES(?1, 0) "
- " UNION ALL "
- " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN "
- " typeSelection USING(typeId)) "
- "SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) "
- " WHERE name=?2 ORDER BY level LIMIT 1",
- database};
- mutable ReadStatement<3, 2> selectPropertyDeclarationByTypeIdAndNameStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId, level) AS ("
- " VALUES(?1, 0) "
- " UNION ALL "
- " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN "
- " typeSelection USING(typeId))"
- "SELECT propertyTypeId, propertyDeclarationId, propertyTraits "
- " FROM propertyDeclarations JOIN typeSelection USING(typeId) "
- " WHERE name=?2 ORDER BY level LIMIT 1",
- database};
- mutable ReadStatement<1, 1> selectPrototypeIdsInOrderStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId, level) AS ("
- " VALUES(?1, 0) "
- " UNION ALL "
- " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN "
- " typeSelection USING(typeId) WHERE prototypeId IS NOT NULL) "
- "SELECT typeId FROM typeSelection ORDER BY level DESC",
- database};
- mutable ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{
- "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database};
- mutable ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{
- "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database};
- mutable ReadStatement<2> selectAllSourceContextsStatement{
- "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database};
- WriteStatement<1> insertIntoSourceContextsStatement{
- "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database};
- mutable ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{
- "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database};
- mutable ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{
- "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database};
- mutable ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{
- "SELECT sourceContextId FROM sources WHERE sourceId = ?", database};
- WriteStatement<2> insertIntoSourcesStatement{
- "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database};
- mutable ReadStatement<3> selectAllSourcesStatement{
- "SELECT sourceName, sourceContextId, sourceId FROM sources", database};
- mutable ReadStatement<8, 1> selectTypeByTypeIdStatement{
- "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, "
- "pd.name "
- "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON "
- "defaultPropertyId=propertyDeclarationId "
- "WHERE t.typeId=?",
- database};
- mutable ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{
- "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM "
- "exportedTypeNames WHERE typeId=?",
- database};
- mutable ReadStatement<4, 2> selectExportedTypesByTypeIdAndSourceIdStatement{
- "SELECT etn.moduleId, name, ifnull(etn.majorVersion, -1), ifnull(etn.minorVersion, -1) "
- "FROM exportedTypeNames AS etn JOIN documentImports USING(moduleId) WHERE typeId=?1 AND "
- "sourceId=?2",
- database};
- mutable ReadStatement<8> selectTypesStatement{
- "SELECT sourceId, t.name, t.typeId, prototypeId, extensionId, traits, annotationTraits, "
- "pd.name "
- "FROM types AS t LEFT JOIN propertyDeclarations AS pd ON "
- "defaultPropertyId=propertyDeclarationId",
- database};
- WriteStatement<2> updateTypeTraitStatement{"UPDATE types SET traits = ?2 WHERE typeId=?1",
- database};
- WriteStatement<2> updateTypeAnnotationTraitStatement{
- "UPDATE types SET annotationTraits = ?2 WHERE typeId=?1", database};
- ReadStatement<1, 2> selectNotUpdatedTypesInSourcesStatement{
- "SELECT DISTINCT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN "
- "carray(?2))",
- database};
- WriteStatement<1> deleteTypeNamesByTypeIdStatement{
- "DELETE FROM exportedTypeNames WHERE typeId=?", database};
- WriteStatement<1> deleteEnumerationDeclarationByTypeIdStatement{
- "DELETE FROM enumerationDeclarations WHERE typeId=?", database};
- WriteStatement<1> deletePropertyDeclarationByTypeIdStatement{
- "DELETE FROM propertyDeclarations WHERE typeId=?", database};
- WriteStatement<1> deleteFunctionDeclarationByTypeIdStatement{
- "DELETE FROM functionDeclarations WHERE typeId=?", database};
- WriteStatement<1> deleteSignalDeclarationByTypeIdStatement{
- "DELETE FROM signalDeclarations WHERE typeId=?", database};
- WriteStatement<1> deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database};
- mutable ReadStatement<4, 1> selectPropertyDeclarationsByTypeIdStatement{
- "SELECT name, propertyTypeId, propertyTraits, (SELECT name FROM "
- "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM "
- "propertyDeclarations AS pd WHERE typeId=?",
- database};
- ReadStatement<6, 1> selectPropertyDeclarationsForTypeIdStatement{
- "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, "
- "propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations "
- "WHERE typeId=? ORDER BY name",
- database};
- ReadWriteStatement<1, 5> insertPropertyDeclarationStatement{
- "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, "
- "propertyImportedTypeNameId, aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5, NULL) "
- "RETURNING propertyDeclarationId",
- database};
- WriteStatement<4> updatePropertyDeclarationStatement{
- "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, "
- "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=NULL WHERE "
- "propertyDeclarationId=?1",
- database};
- WriteStatement<3> updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{
- "WITH RECURSIVE "
- " properties(aliasPropertyDeclarationId) AS ( "
- " SELECT propertyDeclarationId FROM propertyDeclarations WHERE "
- " aliasPropertyDeclarationId=?1 "
- " UNION ALL "
- " SELECT pd.propertyDeclarationId FROM "
- " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) "
- "UPDATE propertyDeclarations AS pd "
- "SET propertyTypeId=?2, propertyTraits=?3 "
- "FROM properties AS p "
- "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId",
- database};
- WriteStatement<1> updatePropertyAliasDeclarationRecursivelyStatement{
- "WITH RECURSIVE "
- " propertyValues(propertyTypeId, propertyTraits) AS ("
- " SELECT propertyTypeId, propertyTraits FROM propertyDeclarations "
- " WHERE propertyDeclarationId=?1), "
- " properties(aliasPropertyDeclarationId) AS ( "
- " SELECT propertyDeclarationId FROM propertyDeclarations WHERE "
- " aliasPropertyDeclarationId=?1 "
- " UNION ALL "
- " SELECT pd.propertyDeclarationId FROM "
- " propertyDeclarations AS pd JOIN properties USING(aliasPropertyDeclarationId)) "
- "UPDATE propertyDeclarations AS pd "
- "SET propertyTypeId=pv.propertyTypeId, propertyTraits=pv.propertyTraits "
- "FROM properties AS p, propertyValues AS pv "
- "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId",
- database};
- WriteStatement<1> deletePropertyDeclarationStatement{
- "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
- ReadStatement<3, 1> selectPropertyDeclarationsWithAliasForTypeIdStatement{
- "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations "
- "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name",
- database};
- WriteStatement<5> updatePropertyDeclarationWithAliasAndTypeStatement{
- "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, "
- "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=?5 WHERE "
- "propertyDeclarationId=?1",
- database};
- ReadWriteStatement<1, 2> insertAliasPropertyDeclarationStatement{
- "INSERT INTO propertyDeclarations(typeId, name) VALUES(?1, ?2) RETURNING "
- "propertyDeclarationId",
- database};
- mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{
- "SELECT name, returnTypeName, signature, functionDeclarationId FROM "
- "functionDeclarations WHERE typeId=? ORDER BY name, signature",
- database};
- mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{
- "SELECT name, returnTypeName, functionDeclarationId FROM "
- "functionDeclarations WHERE typeId=? ORDER BY name",
- database};
- mutable ReadStatement<3, 1> selectFunctionParameterDeclarationsStatement{
- "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
- "json_extract(json_each.value, '$.tr') FROM functionDeclarations, "
- "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?",
- database};
- WriteStatement<4> insertFunctionDeclarationStatement{
- "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, "
- "?3, ?4)",
- database};
- WriteStatement<2> updateFunctionDeclarationStatement{
- "UPDATE functionDeclarations SET returnTypeName=?2 WHERE functionDeclarationId=?1", database};
- WriteStatement<1> deleteFunctionDeclarationStatement{
- "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database};
- mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{
- "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER "
- "BY name, signature",
- database};
- mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{
- "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name",
- database};
- mutable ReadStatement<3, 1> selectSignalParameterDeclarationsStatement{
- "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), "
- "json_extract(json_each.value, '$.tr') FROM signalDeclarations, "
- "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?",
- database};
- WriteStatement<3> insertSignalDeclarationStatement{
- "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database};
- WriteStatement<2> updateSignalDeclarationStatement{
- "UPDATE signalDeclarations SET signature=?2 WHERE signalDeclarationId=?1", database};
- WriteStatement<1> deleteSignalDeclarationStatement{
- "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database};
- mutable ReadStatement<3, 1> selectEnumerationDeclarationsForTypeIdStatement{
- "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM "
- "enumerationDeclarations WHERE typeId=? ORDER BY name",
- database};
- mutable ReadStatement<2, 1> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{
- "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER "
- "BY name",
- database};
- mutable ReadStatement<3, 1> selectEnumeratorDeclarationStatement{
- "SELECT json_each.key, json_each.value, json_each.type!='null' FROM "
- "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE "
- "enumerationDeclarationId=?",
- database};
- WriteStatement<3> insertEnumerationDeclarationStatement{
- "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, "
- "?3)",
- database};
- WriteStatement<2> updateEnumerationDeclarationStatement{
- "UPDATE enumerationDeclarations SET enumeratorDeclarations=?2 WHERE "
- "enumerationDeclarationId=?1",
- database};
- WriteStatement<1> deleteEnumerationDeclarationStatement{
- "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database};
- mutable ReadStatement<1, 1> selectModuleIdByNameStatement{
- "SELECT moduleId FROM modules WHERE name=? LIMIT 1", database};
- mutable ReadWriteStatement<1, 1> insertModuleNameStatement{
- "INSERT INTO modules(name) VALUES(?1) RETURNING moduleId", database};
- mutable ReadStatement<1, 1> selectModuleNameStatement{
- "SELECT name FROM modules WHERE moduleId =?1", database};
- mutable ReadStatement<2> selectAllModulesStatement{"SELECT name, moduleId FROM modules", database};
- mutable ReadStatement<1, 2> selectTypeIdBySourceIdAndNameStatement{
- "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database};
- mutable ReadStatement<1, 3> selectTypeIdByModuleIdsAndExportedNameStatement{
- "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND "
- "name=?3",
- database};
- mutable ReadStatement<4> selectAllDocumentImportForSourceIdStatement{
- "SELECT moduleId, majorVersion, minorVersion, sourceId "
- "FROM documentImports ",
- database};
- mutable ReadStatement<5, 2> selectDocumentImportForSourceIdStatement{
- "SELECT importId, sourceId, moduleId, majorVersion, minorVersion "
- "FROM documentImports WHERE sourceId IN carray(?1) AND kind=?2 ORDER BY sourceId, "
- "moduleId, majorVersion, minorVersion",
- database};
- ReadWriteStatement<1, 5> insertDocumentImportWithoutVersionStatement{
- "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, "
- "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5) RETURNING importId",
- database};
- ReadWriteStatement<1, 6> insertDocumentImportWithMajorVersionStatement{
- "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
- "parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6) RETURNING importId",
- database};
- ReadWriteStatement<1, 7> insertDocumentImportWithVersionStatement{
- "INSERT INTO documentImports(sourceId, moduleId, sourceModuleId, kind, majorVersion, "
- "minorVersion, parentImportId) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) RETURNING "
- "importId",
- database};
- WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1",
- database};
- WriteStatement<2> deleteDocumentImportsWithParentImportIdStatement{
- "DELETE FROM documentImports WHERE sourceId=?1 AND parentImportId=?2", database};
- WriteStatement<1> deleteDocumentImportsWithSourceIdsStatement{
- "DELETE FROM documentImports WHERE sourceId IN carray(?1)", database};
- ReadStatement<1, 2> selectPropertyDeclarationIdPrototypeChainDownStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId, level) AS ("
- " SELECT prototypeId, 0 FROM types WHERE typeId=?1 AND prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT prototypeId, typeSelection.level+1 FROM all_prototype_and_extension JOIN "
- " typeSelection USING(typeId))"
- "SELECT propertyDeclarationId FROM typeSelection JOIN propertyDeclarations "
- " USING(typeId) WHERE name=?2 ORDER BY level LIMIT 1",
- database};
- WriteStatement<2> updateAliasIdPropertyDeclarationStatement{
- "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2 WHERE "
- "aliasPropertyDeclarationId=?1",
- database};
- WriteStatement<2> updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{
- "UPDATE propertyDeclarations SET propertyTypeId=new.propertyTypeId, "
- "propertyTraits=new.propertyTraits, aliasPropertyDeclarationId=?1 FROM (SELECT "
- "propertyTypeId, propertyTraits FROM propertyDeclarations WHERE propertyDeclarationId=?1) "
- "AS new WHERE aliasPropertyDeclarationId=?2",
- database};
- WriteStatement<1> updateAliasPropertyDeclarationToNullStatement{
- "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL, propertyTypeId=NULL, "
- "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT "
- "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)",
- database};
- ReadStatement<5, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{
- "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, "
- "alias.aliasPropertyDeclarationId, alias.aliasPropertyDeclarationTailId FROM "
- "propertyDeclarations AS alias JOIN propertyDeclarations AS target ON "
- "alias.aliasPropertyDeclarationId=target.propertyDeclarationId OR "
- "alias.aliasPropertyDeclarationTailId=target.propertyDeclarationId WHERE "
- "alias.propertyTypeId=?1 OR target.typeId=?1 OR alias.propertyImportedTypeNameId IN "
- "(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) "
- "WHERE typeId=?1)",
- database};
- ReadStatement<3, 1> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{
- "WITH RECURSIVE "
- " properties(propertyDeclarationId, propertyImportedTypeNameId, typeId, "
- " aliasPropertyDeclarationId) AS ("
- " SELECT propertyDeclarationId, propertyImportedTypeNameId, typeId, "
- " aliasPropertyDeclarationId FROM propertyDeclarations WHERE "
- " aliasPropertyDeclarationId=?1"
- " UNION ALL "
- " SELECT pd.propertyDeclarationId, pd.propertyImportedTypeNameId, pd.typeId, "
- " pd.aliasPropertyDeclarationId FROM propertyDeclarations AS pd JOIN properties AS "
- " p ON pd.aliasPropertyDeclarationId=p.propertyDeclarationId)"
- "SELECT propertyDeclarationId, propertyImportedTypeNameId, aliasPropertyDeclarationId "
- " FROM properties",
- database};
- ReadWriteStatement<3, 1> updatesPropertyDeclarationPropertyTypeToNullStatement{
- "UPDATE propertyDeclarations SET propertyTypeId=NULL WHERE propertyTypeId=?1 AND "
- "aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, "
- "propertyImportedTypeNameId",
- database};
- mutable ReadStatement<1, 1> selectPropertyNameStatement{
- "SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
- WriteStatement<2> updatePropertyDeclarationTypeStatement{
- "UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database};
- ReadWriteStatement<2, 1> updatePrototypeIdToNullStatement{
- "UPDATE types SET prototypeId=NULL WHERE prototypeId=?1 RETURNING "
- "typeId, prototypeNameId",
- database};
- ReadWriteStatement<2, 1> updateExtensionIdToNullStatement{
- "UPDATE types SET extensionId=NULL WHERE extensionId=?1 RETURNING "
- "typeId, extensionNameId",
- database};
- WriteStatement<2> updateTypePrototypeStatement{
- "UPDATE types SET prototypeId=?2 WHERE typeId=?1", database};
- WriteStatement<2> updateTypeExtensionStatement{
- "UPDATE types SET extensionId=?2 WHERE typeId=?1", database};
- mutable ReadStatement<1, 1> selectTypeIdsForPrototypeChainIdStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " prototypes(typeId) AS ("
- " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?"
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN "
- " prototypes USING(typeId)) "
- "SELECT typeId FROM prototypes",
- database};
- WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{
- "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, "
- "propertyImportedTypeNameId=?3 WHERE propertyDeclarationId=?1 AND "
- "(aliasPropertyDeclarationId IS NOT ?2 OR propertyImportedTypeNameId IS NOT ?3)",
- database};
- WriteStatement<1> updatetPropertiesDeclarationValuesOfAliasStatement{
- "WITH RECURSIVE "
- " properties(propertyDeclarationId, propertyTypeId, propertyTraits) AS ( "
- " SELECT aliasPropertyDeclarationId, propertyTypeId, propertyTraits FROM "
- " propertyDeclarations WHERE propertyDeclarationId=?1 "
- " UNION ALL "
- " SELECT pd.aliasPropertyDeclarationId, pd.propertyTypeId, pd.propertyTraits FROM "
- " propertyDeclarations AS pd JOIN properties USING(propertyDeclarationId)) "
- "UPDATE propertyDeclarations AS pd SET propertyTypeId=p.propertyTypeId, "
- " propertyTraits=p.propertyTraits "
- "FROM properties AS p "
- "WHERE pd.propertyDeclarationId=?1 AND p.propertyDeclarationId IS NULL AND "
- " (pd.propertyTypeId IS NOT p.propertyTypeId OR pd.propertyTraits IS NOT "
- " p.propertyTraits)",
- database};
- WriteStatement<1> updatePropertyDeclarationAliasIdToNullStatement{
- "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL WHERE "
- "propertyDeclarationId=?1",
- database};
- mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForAliasChainStatement{
- "WITH RECURSIVE "
- " properties(propertyDeclarationId) AS ( "
- " SELECT aliasPropertyDeclarationId FROM propertyDeclarations WHERE "
- " propertyDeclarationId=?1 "
- " UNION ALL "
- " SELECT aliasPropertyDeclarationId FROM propertyDeclarations JOIN properties "
- " USING(propertyDeclarationId)) "
- "SELECT propertyDeclarationId FROM properties",
- database};
- mutable ReadStatement<3> selectAllFileStatusesStatement{
- "SELECT sourceId, size, lastModified FROM fileStatuses ORDER BY sourceId", database};
- mutable ReadStatement<3, 1> selectFileStatusesForSourceIdsStatement{
- "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId IN carray(?1) ORDER "
- "BY sourceId",
- database};
- mutable ReadStatement<3, 1> selectFileStatusesForSourceIdStatement{
- "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId=?1 ORDER BY sourceId",
- database};
- WriteStatement<3> insertFileStatusStatement{
- "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES(?1, ?2, ?3)", database};
- WriteStatement<1> deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1",
- database};
- WriteStatement<3> updateFileStatusStatement{
- "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database};
- ReadStatement<1, 1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?",
- database};
- mutable ReadStatement<1, 3> selectImportedTypeNameIdStatement{
- "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 "
- "AND name=?3 LIMIT 1",
- database};
- mutable ReadWriteStatement<1, 3> insertImportedTypeNameIdStatement{
- "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) "
- "RETURNING importedTypeNameId",
- database};
- mutable ReadStatement<1, 2> selectImportIdBySourceIdAndModuleIdStatement{
- "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion "
- "IS NULL AND minorVersion IS NULL LIMIT 1",
- database};
- mutable ReadStatement<1, 3> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{
- "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND "
- "majorVersion=?3 AND minorVersion IS NULL LIMIT 1",
- database};
- mutable ReadStatement<1, 4> selectImportIdBySourceIdAndModuleIdAndVersionStatement{
- "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND "
- "majorVersion=?3 AND minorVersion=?4 LIMIT 1",
- database};
- mutable ReadStatement<1, 1> selectKindFromImportedTypeNamesStatement{
- "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database};
- mutable ReadStatement<1, 1> selectNameFromImportedTypeNamesStatement{
- "SELECT name FROM importedTypeNames WHERE importedTypeNameId=?1", database};
- mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{
- "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON "
- "importOrSourceId=di.importId JOIN documentImports AS di2 ON di.sourceId=di2.sourceId AND "
- "di.moduleId=di2.sourceModuleId "
- "JOIN exportedTypeNames AS etn ON di2.moduleId=etn.moduleId WHERE "
- "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND "
- "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS "
- "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, "
- "etn.minorVersion DESC NULLS FIRST LIMIT 1",
- database};
- mutable ReadStatement<1, 1> selectTypeIdForImportedTypeNameNamesStatement{
- "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON "
- "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE "
- "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND "
- "(di.majorVersion IS NULL OR (di.majorVersion=etn.majorVersion AND (di.minorVersion IS "
- "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY di.kind, etn.majorVersion DESC "
- "NULLS FIRST, etn.minorVersion DESC NULLS FIRST LIMIT 1",
- database};
- WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database};
- WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database};
- mutable ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{
- "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, "
- "exportedTypeNameId FROM exportedTypeNames WHERE typeId in carray(?1) ORDER BY moduleId, "
- "name, majorVersion, minorVersion",
- database};
- WriteStatement<5> insertExportedTypeNamesWithVersionStatement{
- "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) "
- "VALUES(?1, ?2, ?3, ?4, ?5)",
- database};
- WriteStatement<4> insertExportedTypeNamesWithMajorVersionStatement{
- "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) "
- "VALUES(?1, ?2, ?3, ?4)",
- database};
- WriteStatement<3> insertExportedTypeNamesWithoutVersionStatement{
- "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database};
- WriteStatement<1> deleteExportedTypeNameStatement{
- "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database};
- WriteStatement<2> updateExportedTypeNameTypeIdStatement{
- "UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database};
- mutable ReadStatement<4, 1> selectProjectDatasForSourceIdsStatement{
- "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
- "projectSourceId IN carray(?1) ORDER BY projectSourceId, sourceId",
- database};
- WriteStatement<4> insertProjectDataStatement{
- "INSERT INTO projectDatas(projectSourceId, sourceId, "
- "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)",
- database};
- WriteStatement<2> deleteProjectDataStatement{
- "DELETE FROM projectDatas WHERE projectSourceId=?1 AND sourceId=?2", database};
- WriteStatement<4> updateProjectDataStatement{
- "UPDATE projectDatas SET moduleId=?3, fileType=?4 WHERE projectSourceId=?1 AND sourceId=?2",
- database};
- 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{
- "SELECT moduleExportedImportId, moduleId, exportedModuleId, ifnull(majorVersion, -1), "
- "ifnull(minorVersion, -1), isAutoVersion FROM moduleExportedImports WHERE moduleId IN "
- "carray(?1) ORDER BY moduleId, exportedModuleId",
- database};
- WriteStatement<3> insertModuleExportedImportWithoutVersionStatement{
- "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion) "
- "VALUES (?1, ?2, ?3)",
- database};
- WriteStatement<4> insertModuleExportedImportWithMajorVersionStatement{
- "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
- "majorVersion) VALUES (?1, ?2, ?3, ?4)",
- database};
- WriteStatement<5> insertModuleExportedImportWithVersionStatement{
- "INSERT INTO moduleExportedImports(moduleId, exportedModuleId, isAutoVersion, "
- "majorVersion, minorVersion) VALUES (?1, ?2, ?3, ?4, ?5)",
- database};
- WriteStatement<1> deleteModuleExportedImportStatement{
- "DELETE FROM moduleExportedImports WHERE moduleExportedImportId=?1", database};
- mutable ReadStatement<3, 3> selectModuleExportedImportsForModuleIdStatement{
- "WITH RECURSIVE "
- " imports(moduleId, majorVersion, minorVersion, moduleExportedImportId) AS ( "
- " SELECT exportedModuleId, "
- " iif(isAutoVersion=1, ?2, majorVersion), "
- " iif(isAutoVersion=1, ?3, minorVersion), "
- " moduleExportedImportId "
- " FROM moduleExportedImports WHERE moduleId=?1 "
- " UNION ALL "
- " SELECT exportedModuleId, "
- " iif(mei.isAutoVersion=1, i.majorVersion, mei.majorVersion), "
- " iif(mei.isAutoVersion=1, i.minorVersion, mei.minorVersion), "
- " mei.moduleExportedImportId "
- " FROM moduleExportedImports AS mei JOIN imports AS i USING(moduleId)) "
- "SELECT DISTINCT moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) "
- "FROM imports",
- database};
- mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForTypeStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeChain(typeId) AS ("
- " VALUES(?1)"
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain "
- " USING(typeId))"
- "SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations "
- " USING(typeId) ORDER BY propertyDeclarationId",
- database};
- mutable ReadStatement<1, 1> selectLocalPropertyDeclarationIdsForTypeStatement{
- "SELECT propertyDeclarationId "
- "FROM propertyDeclarations "
- "WHERE typeId=? "
- "ORDER BY propertyDeclarationId",
- database};
- mutable ReadStatement<1, 2> selectPropertyDeclarationIdForTypeAndPropertyNameStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeChain(typeId, level) AS ("
- " VALUES(?1, 0)"
- " UNION ALL "
- " SELECT prototypeId, typeChain.level + 1 FROM all_prototype_and_extension JOIN "
- " typeChain USING(typeId))"
- "SELECT propertyDeclarationId FROM typeChain JOIN propertyDeclarations "
- " USING(typeId) WHERE name=?2 ORDER BY level LIMIT 1",
- database};
- mutable ReadStatement<1, 2> selectLocalPropertyDeclarationIdForTypeAndPropertyNameStatement{
- "SELECT propertyDeclarationId "
- "FROM propertyDeclarations "
- "WHERE typeId=?1 AND name=?2 LIMIT 1",
- database};
- mutable ReadStatement<4, 1> selectPropertyDeclarationForPropertyDeclarationIdStatement{
- "SELECT typeId, name, propertyTraits, propertyTypeId "
- "FROM propertyDeclarations "
- "WHERE propertyDeclarationId=?1 LIMIT 1",
- database};
- mutable ReadStatement<1, 1> selectSignalDeclarationNamesForTypeStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeChain(typeId) AS ("
- " VALUES(?1)"
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain "
- " USING(typeId)) "
- "SELECT name FROM typeChain JOIN signalDeclarations "
- " USING(typeId) ORDER BY name",
- database};
- mutable ReadStatement<1, 1> selectFuncionDeclarationNamesForTypeStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeChain(typeId) AS ("
- " VALUES(?1)"
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN typeChain "
- " USING(typeId))"
- "SELECT name FROM typeChain JOIN functionDeclarations "
- " USING(typeId) ORDER BY name",
- database};
- mutable ReadStatement<2> selectTypesWithDefaultPropertyStatement{
- "SELECT typeId, defaultPropertyId FROM types ORDER BY typeId", database};
- WriteStatement<2> updateDefaultPropertyIdStatement{
- "UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database};
- WriteStatement<1> updateDefaultPropertyIdToNullStatement{
- "UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database};
- mutable ReadStatement<4, 1> selectInfoTypeByTypeIdStatement{
- "SELECT defaultPropertyId, sourceId, traits, annotationTraits FROM types WHERE typeId=?",
- database};
- mutable ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " prototypes(typeId, level) AS ("
- " SELECT prototypeId, 0 FROM all_prototype_and_extension WHERE typeId=?"
- " UNION ALL "
- " SELECT prototypeId, p.level+1 FROM all_prototype_and_extension JOIN "
- " prototypes AS p USING(typeId)) "
- "SELECT typeId FROM prototypes ORDER BY level",
- database};
- mutable ReadStatement<1, 1> selectPrototypeAndSelfIdsForTypeIdInOrderStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeChain(typeId, level) AS ("
- " VALUES(?1, 0)"
- " UNION ALL "
- " SELECT prototypeId, tc.level+1 FROM all_prototype_and_extension JOIN "
- " typeChain AS tc USING(typeId)) "
- "SELECT typeId FROM typeChain ORDER BY level",
- database};
- mutable ReadStatement<1, 1> selectPrototypeIdsStatement{
- "WITH RECURSIVE "
- " all_prototype_and_extension(typeId, prototypeId) AS ("
- " SELECT typeId, prototypeId FROM types WHERE prototypeId IS NOT NULL"
- " UNION ALL "
- " SELECT typeId, extensionId FROM types WHERE extensionId IS NOT NULL),"
- " typeSelection(typeId) AS ("
- " SELECT prototypeId FROM all_prototype_and_extension WHERE typeId=?1 "
- " UNION ALL "
- " SELECT prototypeId FROM all_prototype_and_extension JOIN typeSelection "
- " USING(typeId))"
- "SELECT typeId FROM typeSelection",
- database};
- WriteStatement<2> upsertPropertyEditorPathIdStatement{
- "INSERT INTO propertyEditorPaths(typeId, pathSourceId) VALUES(?1, ?2) ON CONFLICT DO "
- "UPDATE SET pathSourceId=excluded.pathSourceId WHERE pathSourceId IS NOT "
- "excluded.pathSourceId",
- database};
- mutable ReadStatement<1, 1> selectPropertyEditorPathIdStatement{
- "SELECT pathSourceId FROM propertyEditorPaths WHERE typeId=?", database};
- mutable ReadStatement<3, 1> selectPropertyEditorPathsForForSourceIdsStatement{
- "SELECT typeId, pathSourceId, directoryId "
- "FROM propertyEditorPaths "
- "WHERE directoryId IN carray(?1) "
- "ORDER BY typeId",
- database};
- WriteStatement<3> insertPropertyEditorPathStatement{
- "INSERT INTO propertyEditorPaths(typeId, pathSourceId, directoryId) VALUES (?1, ?2, ?3)",
- database};
- WriteStatement<3> updatePropertyEditorPathsStatement{"UPDATE propertyEditorPaths "
- "SET pathSourceId=?2, directoryId=?3 "
- "WHERE typeId=?1",
- database};
- WriteStatement<1> deletePropertyEditorPathStatement{
- "DELETE FROM propertyEditorPaths WHERE typeId=?1", database};
- mutable ReadStatement<4, 1> selectTypeAnnotationsForSourceIdsStatement{
- "SELECT typeId, iconPath, itemLibrary, hints FROM typeAnnotations WHERE "
- "sourceId IN carray(?1) ORDER BY typeId",
- database};
- WriteStatement<5> insertTypeAnnotationStatement{
- "INSERT INTO typeAnnotations(typeId, sourceId, iconPath, itemLibrary, hints) VALUES(?1, "
- "?2, ?3, ?4, ?5)",
- database};
- WriteStatement<4> updateTypeAnnotationStatement{
- "UPDATE typeAnnotations SET iconPath=?2, itemLibrary=?3, hints=?4 WHERE typeId=?1", database};
- WriteStatement<1> deleteTypeAnnotationStatement{"DELETE FROM typeAnnotations WHERE typeId=?1",
- database};
- mutable ReadStatement<1, 1> selectTypeIconPathStatement{
- "SELECT iconPath FROM typeAnnotations WHERE typeId=?1", database};
- mutable ReadStatement<2, 1> selectTypeHintsStatement{
- "SELECT hints.key, hints.value "
- "FROM typeAnnotations, json_each(typeAnnotations.hints) AS hints "
- "WHERE typeId=?1",
- database};
- mutable ReadStatement<9> selectItemLibraryEntriesStatement{
- "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', "
- " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', "
- " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
- "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i",
- database};
- mutable ReadStatement<9, 1> selectItemLibraryEntriesByTypeIdStatement{
- "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', "
- " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', "
- " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
- "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i "
- "WHERE typeId=?1",
- database};
- mutable ReadStatement<9, 1> selectItemLibraryEntriesBySourceIdStatement{
- "SELECT typeId, i.value->>'$.name', i.value->>'$.iconPath', i.value->>'$.category', "
- " i.value->>'$.import', i.value->>'$.toolTip', i.value->>'$.properties', "
- " i.value->>'$.extraFilePaths', i.value->>'$.templatePath' "
- "FROM typeAnnotations, json_each(typeAnnotations.itemLibrary) AS i "
- "WHERE typeId IN (SELECT DISTINCT typeId "
- " FROM documentImports AS di JOIN exportedTypeNames USING(moduleId) "
- " WHERE di.sourceId=?)",
- database};
- mutable ReadStatement<3, 1> selectItemLibraryPropertiesStatement{
- "SELECT p.value->>0, p.value->>1, p.value->>2 FROM json_each(?1) AS p", database};
- mutable ReadStatement<1, 1> selectItemLibraryExtraFilePathsStatement{
- "SELECT p.value FROM json_each(?1) AS p", database};
- mutable ReadStatement<1, 1> selectTypeIdsByModuleIdStatement{
- "SELECT DISTINCT typeId FROM exportedTypeNames WHERE moduleId=?", database};
- mutable ReadStatement<1, 1> selectHeirTypeIdsStatement{
- "WITH RECURSIVE "
- " typeSelection(typeId) AS ("
- " SELECT typeId FROM types WHERE prototypeId=?1 OR extensionId=?1"
- " UNION ALL "
- " SELECT t.typeId "
- " FROM types AS t JOIN typeSelection AS ts "
- " WHERE prototypeId=ts.typeId OR extensionId=ts.typeId)"
- "SELECT typeId FROM typeSelection",
- database};
+ std::unique_ptr<Statements> s;
};
-extern template class ProjectStorage<Sqlite::Database>;
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp
new file mode 100644
index 0000000000..a4705f5eec
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "projectstorageerrornotifier.h"
+
+#include "sourcepathcache.h"
+
+namespace QmlDesigner {
+
+void ProjectStorageErrorNotifier::typeNameCannotBeResolved(Utils::SmallStringView typeName,
+ SourceId sourceId)
+{
+ qDebug() << "Missing type name: " << typeName
+ << " in file: " << m_pathCache.sourcePath(sourceId).toStringView();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h
new file mode 100644
index 0000000000..2695e93019
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "projectstorageerrornotifierinterface.h"
+
+#include <modelfwd.h>
+
+namespace QmlDesigner {
+
+class ProjectStorageErrorNotifier final : public ProjectStorageErrorNotifierInterface
+{
+public:
+ ProjectStorageErrorNotifier(PathCacheType &pathCache)
+ : m_pathCache{pathCache}
+ {}
+
+ void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) override;
+
+private:
+ PathCacheType &m_pathCache;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h
new file mode 100644
index 0000000000..8136c9d599
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "projectstorageids.h"
+
+#include <utils/smallstringview.h>
+
+namespace QmlDesigner {
+
+class ProjectStorageErrorNotifierInterface
+{
+public:
+ ProjectStorageErrorNotifierInterface() = default;
+ ProjectStorageErrorNotifierInterface(ProjectStorageErrorNotifierInterface &&) = default;
+ ProjectStorageErrorNotifierInterface &operator=(ProjectStorageErrorNotifierInterface &&) = default;
+ ProjectStorageErrorNotifierInterface(const ProjectStorageErrorNotifierInterface &) = delete;
+ ProjectStorageErrorNotifierInterface &operator=(const ProjectStorageErrorNotifierInterface &) = delete;
+
+ virtual void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) = 0;
+
+protected:
+ ~ProjectStorageErrorNotifierInterface() = default;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
index efe9bc58f5..a86b78a785 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
@@ -3,87 +3,186 @@
#include "projectstorageexceptions.h"
+#include <tracing/qmldesignertracing.h>
+
namespace QmlDesigner {
+using namespace NanotraceHR::Literals;
+using NanotraceHR::keyValue;
+
+namespace {
+auto &category()
+{
+ return ProjectStorageTracing::projectStorageCategory();
+}
+} // namespace
+
+NoSourcePathForInvalidSourceId::NoSourcePathForInvalidSourceId()
+{
+ category().threadEvent("NoSourcePathForInvalidSourceId"_t);
+}
+
const char *NoSourcePathForInvalidSourceId::what() const noexcept
{
return "You cannot get a file path for an invalid file path id!";
}
+NoSourceContextPathForInvalidSourceContextId::NoSourceContextPathForInvalidSourceContextId()
+{
+ category().threadEvent("NoSourceContextPathForInvalidSourceContextId"_t);
+}
+
const char *NoSourceContextPathForInvalidSourceContextId::what() const noexcept
{
return "You cannot get a directory path for an invalid directory path id!";
}
+SourceContextIdDoesNotExists::SourceContextIdDoesNotExists()
+{
+ category().threadEvent("SourceContextIdDoesNotExists"_t);
+}
+
const char *SourceContextIdDoesNotExists::what() const noexcept
{
return "The source context id does not exist in the database!";
}
+SourceIdDoesNotExists::SourceIdDoesNotExists()
+{
+ category().threadEvent("SourceIdDoesNotExists"_t);
+}
+
const char *SourceIdDoesNotExists::what() const noexcept
{
return "The source id does not exist in the database!";
}
+TypeHasInvalidSourceId::TypeHasInvalidSourceId()
+{
+ category().threadEvent("TypeHasInvalidSourceId"_t);
+}
+
const char *TypeHasInvalidSourceId::what() const noexcept
{
return "The source id is invalid!";
}
+ModuleDoesNotExists::ModuleDoesNotExists()
+{
+ category().threadEvent("ModuleDoesNotExists"_t);
+}
+
const char *ModuleDoesNotExists::what() const noexcept
{
return "The module does not exist!";
}
+ModuleAlreadyExists::ModuleAlreadyExists()
+{
+ category().threadEvent("ModuleAlreadyExists"_t);
+}
+
const char *ModuleAlreadyExists::what() const noexcept
{
return "The module does already exist!";
}
-TypeNameDoesNotExists::TypeNameDoesNotExists(std::string_view errorMessage)
- : ProjectStorageErrorWithMessage{"TypeNameDoesNotExists"sv, errorMessage}
-{}
+TypeNameDoesNotExists::TypeNameDoesNotExists(std::string_view typeName, SourceId sourceId)
+ : ProjectStorageErrorWithMessage{
+ "TypeNameDoesNotExists"sv,
+ Utils::SmallString::join(
+ {"type: ", typeName, ", source id: ", Utils::SmallString::number(sourceId.internalId())})}
+{
+ category().threadEvent("TypeNameDoesNotExists"_t,
+ keyValue("type name", typeName),
+ keyValue("source id", sourceId));
+}
+
+PropertyNameDoesNotExists::PropertyNameDoesNotExists()
+{
+ category().threadEvent("PropertyNameDoesNotExists"_t);
+}
const char *PropertyNameDoesNotExists::what() const noexcept
{
return "The property name does not exist!";
}
+PrototypeChainCycle::PrototypeChainCycle()
+{
+ category().threadEvent("PrototypeChainCycle"_t);
+}
+
const char *PrototypeChainCycle::what() const noexcept
{
return "There is a prototype chain cycle!";
}
+AliasChainCycle::AliasChainCycle()
+{
+ category().threadEvent("AliasChainCycle"_t);
+}
+
const char *AliasChainCycle::what() const noexcept
{
return "There is a prototype chain cycle!";
}
+CannotParseQmlTypesFile::CannotParseQmlTypesFile()
+{
+ category().threadEvent("CannotParseQmlTypesFile"_t);
+}
+
const char *CannotParseQmlTypesFile::what() const noexcept
{
return "Cannot parse qml types file!";
}
+CannotParseQmlDocumentFile::CannotParseQmlDocumentFile()
+{
+ category().threadEvent("CannotParseQmlDocumentFile"_t);
+}
+
const char *CannotParseQmlDocumentFile::what() const noexcept
{
return "Cannot parse qml types file!";
}
-const char *ProjectDataHasInvalidProjectSourceId::what() const noexcept
+DirectoryInfoHasInvalidProjectSourceId::DirectoryInfoHasInvalidProjectSourceId()
+{
+ category().threadEvent("DirectoryInfoHasInvalidProjectSourceId"_t);
+}
+
+const char *DirectoryInfoHasInvalidProjectSourceId::what() const noexcept
{
return "The project source id is invalid!";
}
-const char *ProjectDataHasInvalidSourceId::what() const noexcept
+DirectoryInfoHasInvalidSourceId::DirectoryInfoHasInvalidSourceId()
+{
+ category().threadEvent("DirectoryInfoHasInvalidSourceId"_t);
+}
+
+const char *DirectoryInfoHasInvalidSourceId::what() const noexcept
{
return "The source id is invalid!";
}
-const char *ProjectDataHasInvalidModuleId::what() const noexcept
+DirectoryInfoHasInvalidModuleId::DirectoryInfoHasInvalidModuleId()
+{
+ category().threadEvent("DirectoryInfoHasInvalidModuleId"_t);
+}
+
+const char *DirectoryInfoHasInvalidModuleId::what() const noexcept
{
return "The module id is invalid!";
}
+FileStatusHasInvalidSourceId::FileStatusHasInvalidSourceId()
+{
+ category().threadEvent("FileStatusHasInvalidSourceId"_t);
+}
+
const char *FileStatusHasInvalidSourceId::what() const noexcept
{
return "The source id in file status is invalid!";
@@ -110,7 +209,14 @@ const char *ProjectStorageErrorWithMessage::what() const noexcept
ExportedTypeCannotBeInserted::ExportedTypeCannotBeInserted(std::string_view errorMessage)
: ProjectStorageErrorWithMessage{"ExportedTypeCannotBeInserted"sv, errorMessage}
-{}
+{
+ category().threadEvent("ExportedTypeCannotBeInserted"_t, keyValue("error message", errorMessage));
+}
+
+TypeAnnotationHasInvalidSourceId::TypeAnnotationHasInvalidSourceId()
+{
+ category().threadEvent("TypeAnnotationHasInvalidSourceId"_t);
+}
const char *TypeAnnotationHasInvalidSourceId::what() const noexcept
{
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
index 412dd4a9ff..f4f78f714b 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
@@ -5,6 +5,8 @@
#include "../include/qmldesignercorelib_global.h"
+#include "projectstorageids.h"
+
#include <exception>
namespace QmlDesigner {
@@ -13,15 +15,19 @@ using namespace std::literals::string_view_literals;
class QMLDESIGNERCORE_EXPORT ProjectStorageError : public std::exception
{
+protected:
+ ProjectStorageError() = default;
+
public:
const char *what() const noexcept override;
};
class ProjectStorageErrorWithMessage : public ProjectStorageError
{
-public:
+protected:
ProjectStorageErrorWithMessage(std::string_view error, std::string_view errorMessage);
+public:
const char *what() const noexcept override;
public:
@@ -31,42 +37,49 @@ public:
class QMLDESIGNERCORE_EXPORT NoSourcePathForInvalidSourceId : public ProjectStorageError
{
public:
+ NoSourcePathForInvalidSourceId();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : public ProjectStorageError
{
public:
+ NoSourceContextPathForInvalidSourceContextId();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : public ProjectStorageError
{
public:
+ SourceContextIdDoesNotExists();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : public ProjectStorageError
{
public:
+ SourceIdDoesNotExists();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT TypeHasInvalidSourceId : public ProjectStorageError
{
public:
+ TypeHasInvalidSourceId();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT ModuleDoesNotExists : public ProjectStorageError
{
public:
+ ModuleDoesNotExists();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT ModuleAlreadyExists : public ProjectStorageError
{
public:
+ ModuleAlreadyExists();
const char *what() const noexcept override;
};
@@ -79,66 +92,76 @@ public:
class QMLDESIGNERCORE_EXPORT TypeNameDoesNotExists : public ProjectStorageErrorWithMessage
{
public:
- TypeNameDoesNotExists(std::string_view errorMessage);
+ TypeNameDoesNotExists(std::string_view typeName, SourceId sourceId = SourceId{});
};
class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : public ProjectStorageError
{
public:
+ PropertyNameDoesNotExists();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : public ProjectStorageError
{
public:
+ PrototypeChainCycle();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT AliasChainCycle : public ProjectStorageError
{
public:
+ AliasChainCycle();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT CannotParseQmlTypesFile : public ProjectStorageError
{
public:
+ CannotParseQmlTypesFile();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT CannotParseQmlDocumentFile : public ProjectStorageError
{
public:
+ CannotParseQmlDocumentFile();
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidProjectSourceId : public ProjectStorageError
+class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidProjectSourceId : public ProjectStorageError
{
public:
+ DirectoryInfoHasInvalidProjectSourceId();
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidSourceId : public ProjectStorageError
+class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidSourceId : public ProjectStorageError
{
public:
+ DirectoryInfoHasInvalidSourceId();
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidModuleId : public ProjectStorageError
+class QMLDESIGNERCORE_EXPORT DirectoryInfoHasInvalidModuleId : public ProjectStorageError
{
public:
+ DirectoryInfoHasInvalidModuleId();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT FileStatusHasInvalidSourceId : public ProjectStorageError
{
public:
+ FileStatusHasInvalidSourceId();
const char *what() const noexcept override;
};
class QMLDESIGNERCORE_EXPORT TypeAnnotationHasInvalidSourceId : public ProjectStorageError
{
public:
+ TypeAnnotationHasInvalidSourceId();
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 b33c609509..cbb7d4265a 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h
@@ -11,7 +11,6 @@ namespace QmlDesigner {
class ProjectStorageInterface;
class SourcePathCacheInterface;
-template<typename Database>
class ProjectStorage;
template<typename Type>
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
index 427c0ff8d6..1d630344ae 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
@@ -7,6 +7,9 @@
#include <sqlite/sqlitevalue.h>
#include <utils/smallstring.h>
+#include <utils/utility.h>
+
+#include <QVarLengthArray>
#include <array>
#include <tuple>
@@ -15,19 +18,57 @@
namespace QmlDesigner {
-template<typename Enumeration>
-constexpr std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept
-{
- static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration");
- return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
-}
+template<std::size_t size>
+using SmallPathStrings = QVarLengthArray<Utils::PathString, size>;
enum class FlagIs : unsigned int { False, Set, True };
+template<typename String>
+void convertToString(String &string, const FlagIs &flagIs)
+{
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+
+ if (flagIs == FlagIs::False)
+ convertToString(string, false);
+ else if (flagIs == FlagIs::True)
+ convertToString(string, true);
+ else
+ convertToString(string, "is set");
+}
+
} // namespace QmlDesigner
namespace QmlDesigner::Storage {
+enum class ModuleKind { QmlLibrary, CppLibrary, PathLibrary };
+
+struct Module
+{
+ Module() = default;
+
+ Module(Utils::SmallStringView name, Storage::ModuleKind kind)
+ : name{name}
+ , kind{kind}
+ {}
+
+ template<typename ModuleType>
+ Module(const ModuleType &module)
+ : name{module.name}
+ , kind{module.kind}
+ {}
+
+ Utils::PathString name;
+ Storage::ModuleKind kind = Storage::ModuleKind::QmlLibrary;
+
+ friend bool operator==(const Module &first, const Module &second)
+ {
+ return first.name == second.name && first.kind == second.kind;
+ }
+
+ explicit operator bool() const { return name.size(); }
+};
+
enum class PropertyDeclarationTraits : int {
None = 0,
IsReadOnly = 1 << 0,
@@ -46,6 +87,18 @@ constexpr bool operator&(PropertyDeclarationTraits first, PropertyDeclarationTra
return static_cast<int>(first) & static_cast<int>(second);
}
+template<typename String>
+void convertToString(String &string, const PropertyDeclarationTraits &traits)
+{
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("is read only", traits & PropertyDeclarationTraits::IsReadOnly),
+ keyValue("is pointer", traits & PropertyDeclarationTraits::IsPointer),
+ keyValue("is list", traits & PropertyDeclarationTraits::IsList));
+
+ convertToString(string, dict);
+}
+
enum class TypeTraitsKind : unsigned int {
None,
Reference,
@@ -53,6 +106,25 @@ enum class TypeTraitsKind : unsigned int {
Sequence,
};
+template<typename String>
+void convertToString(String &string, const TypeTraitsKind &kind)
+{
+ switch (kind) {
+ case TypeTraitsKind::None:
+ convertToString(string, "None");
+ break;
+ case TypeTraitsKind::Reference:
+ convertToString(string, "Reference");
+ break;
+ case TypeTraitsKind::Value:
+ convertToString(string, "Value");
+ break;
+ case TypeTraitsKind::Sequence:
+ convertToString(string, "Sequence");
+ break;
+ }
+}
+
struct TypeTraits
{
constexpr TypeTraits()
@@ -100,6 +172,35 @@ struct TypeTraits
return first.type == second.type && first.annotation == second.annotation;
}
+ template<typename String>
+ friend void convertToString(String &string, const TypeTraits &typeTraits)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(
+ keyValue("kind", typeTraits.kind),
+ keyValue("is enum", typeTraits.isEnum),
+ keyValue("is file component", typeTraits.isFileComponent),
+ keyValue("is project component", typeTraits.isProjectComponent),
+ keyValue("is in project module", typeTraits.isInProjectModule),
+ keyValue("uses custom parser", typeTraits.usesCustomParser),
+ keyValue("can be container", typeTraits.canBeContainer),
+ keyValue("force clip", typeTraits.forceClip),
+ keyValue("does layout children", typeTraits.doesLayoutChildren),
+ keyValue("can be dropped in form editor", typeTraits.canBeDroppedInFormEditor),
+ keyValue("can be dropped in navigator", typeTraits.canBeDroppedInNavigator),
+ keyValue("can be dropped in view 3D", typeTraits.canBeDroppedInView3D),
+ keyValue("is movable", typeTraits.isMovable),
+ keyValue("is resizable", typeTraits.isResizable),
+ keyValue("has form editor item", typeTraits.hasFormEditorItem),
+ keyValue("is stacked container", typeTraits.isStackedContainer),
+ keyValue("takes over rendering of children", typeTraits.takesOverRenderingOfChildren),
+ keyValue("visible in navigator", typeTraits.visibleInNavigator),
+ keyValue("visible in library", typeTraits.visibleInLibrary));
+
+ convertToString(string, dict);
+ }
+
union {
struct
{
@@ -202,10 +303,22 @@ public:
explicit operator bool() const { return major && minor; }
+ template<typename String>
+ friend void convertToString(String &string, const Version &version)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("major version", version.major.value),
+ keyValue("minor version", version.minor.value));
+
+ convertToString(string, dict);
+ }
+
public:
VersionNumber major;
VersionNumber minor;
};
+
} // namespace QmlDesigner::Storage
namespace QmlDesigner::Storage::Info {
@@ -217,6 +330,17 @@ struct TypeHint
, expression{expression}
{}
+ template<typename String>
+ friend void convertToString(String &string, const TypeHint &typeHint)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", typeHint.name),
+ keyValue("expression", typeHint.expression));
+
+ convertToString(string, dict);
+ }
+
Utils::SmallString name;
Utils::PathString expression;
};
@@ -231,6 +355,18 @@ struct ItemLibraryProperty
, value{value}
{}
+ template<typename String>
+ friend void convertToString(String &string, const ItemLibraryProperty &property)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", property.name),
+ keyValue("type", property.type),
+ keyValue("value", property.value));
+
+ convertToString(string, dict);
+ }
+
Utils::SmallString name;
Utils::SmallString type;
Sqlite::Value value;
@@ -243,6 +379,7 @@ using ToolTipString = Utils::BasicSmallString<94>;
struct ItemLibraryEntry
{
ItemLibraryEntry(TypeId typeId,
+ Utils::SmallStringView typeName,
Utils::SmallStringView name,
Utils::SmallStringView iconPath,
Utils::SmallStringView category,
@@ -250,6 +387,7 @@ struct ItemLibraryEntry
Utils::SmallStringView toolTip,
Utils::SmallStringView templatePath)
: typeId{typeId}
+ , typeName{typeName}
, name{name}
, iconPath{iconPath}
, category{category}
@@ -259,6 +397,7 @@ struct ItemLibraryEntry
{}
ItemLibraryEntry(TypeId typeId,
+ Utils::SmallStringView typeName,
Utils::SmallStringView name,
Utils::SmallStringView iconPath,
Utils::SmallStringView category,
@@ -266,6 +405,7 @@ struct ItemLibraryEntry
Utils::SmallStringView toolTip,
ItemLibraryProperties properties)
: typeId{typeId}
+ , typeName{typeName}
, name{name}
, iconPath{iconPath}
, category{category}
@@ -274,7 +414,27 @@ struct ItemLibraryEntry
, properties{std::move(properties)}
{}
+ template<typename String>
+ friend void convertToString(String &string, const ItemLibraryEntry &entry)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", entry.typeId),
+ keyValue("type name", entry.typeName),
+ keyValue("name", entry.name),
+ keyValue("icon path", entry.iconPath),
+ keyValue("category", entry.category),
+ keyValue("import", entry.import),
+ keyValue("tool tip", entry.toolTip),
+ keyValue("template path", entry.templatePath),
+ keyValue("properties", entry.properties),
+ keyValue("extra file paths", entry.extraFilePaths));
+
+ convertToString(string, dict);
+ }
+
TypeId typeId;
+ Utils::SmallString typeName;
Utils::SmallString name;
Utils::PathString iconPath;
Utils::SmallString category;
@@ -321,6 +481,18 @@ public:
< std::tie(second.moduleId, second.name, second.version);
}
+ template<typename String>
+ friend void convertToString(String &string, const ExportedTypeName &exportedTypeName)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", exportedTypeName.name),
+ keyValue("version", exportedTypeName.version),
+ keyValue("module id", exportedTypeName.moduleId));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
Storage::Version version;
@@ -342,6 +514,19 @@ public:
, propertyTypeId{propertyTypeId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type id", propertyDeclaration.typeId),
+ keyValue("name", propertyDeclaration.name),
+ keyValue("traits", propertyDeclaration.traits),
+ keyValue("property type id", propertyDeclaration.propertyTypeId));
+
+ convertToString(string, dict);
+ }
+
TypeId typeId;
::Utils::SmallString name;
PropertyDeclarationTraits traits;
@@ -351,22 +536,26 @@ public:
class Type
{
public:
- Type(PropertyDeclarationId defaultPropertyId,
- SourceId sourceId,
- long long typeTraits,
- long long typeAnnotationTraits)
- : defaultPropertyId{defaultPropertyId}
- , sourceId{sourceId}
+ Type(SourceId sourceId, long long typeTraits, long long typeAnnotationTraits)
+ : sourceId{sourceId}
, traits{typeTraits, typeAnnotationTraits}
{}
- Type(PropertyDeclarationId defaultPropertyId, SourceId sourceId, TypeTraits traits)
- : defaultPropertyId{defaultPropertyId}
- , sourceId{sourceId}
+ Type(SourceId sourceId, TypeTraits traits)
+ : sourceId{sourceId}
, traits{traits}
{}
- PropertyDeclarationId defaultPropertyId;
+ template<typename String>
+ friend void convertToString(String &string, const Type &type)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("source id", type.sourceId), keyValue("traits", type.traits));
+
+ convertToString(string, dict);
+ }
+
SourceId sourceId;
TypeTraits traits;
};
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
index 266c6ee7ca..4d840d2a5c 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
@@ -31,7 +31,8 @@ public:
virtual void addObserver(ProjectStorageObserver *observer) = 0;
virtual void removeObserver(ProjectStorageObserver *observer) = 0;
- virtual ModuleId moduleId(::Utils::SmallStringView name) const = 0;
+ virtual ModuleId moduleId(::Utils::SmallStringView name, Storage::ModuleKind kind) const = 0;
+ virtual QmlDesigner::Storage::Module module(ModuleId moduleId) const = 0;
virtual std::optional<Storage::Info::PropertyDeclaration>
propertyDeclaration(PropertyDeclarationId propertyDeclarationId) const = 0;
virtual TypeId typeId(ModuleId moduleId,
@@ -54,7 +55,10 @@ public:
virtual PropertyDeclarationId propertyDeclarationId(TypeId typeId,
::Utils::SmallStringView propertyName) const
= 0;
+ virtual PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const = 0;
virtual std::optional<Storage::Info::Type> type(TypeId typeId) const = 0;
+ virtual SmallSourceIds<4> typeAnnotationSourceIds(SourceId directoryId) const = 0;
+ virtual SmallSourceIds<64> typeAnnotationDirectorySourceIds() const = 0;
virtual Utils::PathString typeIconPath(TypeId typeId) const = 0;
virtual Storage::Info::TypeHints typeHints(TypeId typeId) const = 0;
virtual Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const = 0;
@@ -64,9 +68,9 @@ public:
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 TypeIds heirIds(TypeId typeId) const = 0;
+ virtual SmallTypeIds<16> prototypeAndSelfIds(TypeId type) const = 0;
+ virtual SmallTypeIds<16> prototypeIds(TypeId type) const = 0;
+ virtual SmallTypeIds<64> heirIds(TypeId typeId) 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;
@@ -76,16 +80,20 @@ public:
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 Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceId sourceId) const = 0;
+ virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(
+ SourceId directorySourceId, Storage::Synchronization::FileType) const
+ = 0;
+ virtual std::optional<Storage::Synchronization::DirectoryInfo> fetchDirectoryInfo(SourceId sourceId) const = 0;
+ virtual SmallSourceIds<32> fetchSubdirectorySourceIds(SourceId directorySourceId) const = 0;
virtual SourceId propertyEditorPathId(TypeId typeId) const = 0;
- virtual const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const = 0;
+ virtual const Storage::Info::CommonTypeCache<ProjectStorageType> &commonTypeCache() const = 0;
- template<const char *moduleName, const char *typeName>
+ template<const char *moduleName, const char *typeName, Storage::ModuleKind moduleKind = Storage::ModuleKind::QmlLibrary>
TypeId commonTypeId() const
{
- return commonTypeCache().template typeId<moduleName, typeName>();
+ return commonTypeCache().template typeId<moduleName, typeName, moduleKind>();
}
template<typename BuiltinType>
@@ -104,7 +112,7 @@ protected:
ProjectStorageInterface() = default;
~ProjectStorageInterface() = default;
- virtual ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name) const = 0;
+ virtual ModuleId fetchModuleIdUnguarded(Utils::SmallStringView name, Storage::ModuleKind moduleKind) const = 0;
virtual TypeId fetchTypeIdByModuleIdAndExportedName(ModuleId moduleId, Utils::SmallStringView name) const = 0;
};
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
index a9185d91e8..04f11096bd 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
@@ -12,6 +12,28 @@ namespace QmlDesigner {
enum class SourceType : int { Qml, QmlUi, QmlTypes, QmlDir, Directory };
+template<typename String>
+void convertToString(String &string, SourceType sourceType)
+{
+ switch (sourceType) {
+ case SourceType::Qml:
+ convertToString(string, "Qml");
+ break;
+ case SourceType::QmlUi:
+ convertToString(string, "QmlUi");
+ break;
+ case SourceType::QmlTypes:
+ convertToString(string, "QmlTypes");
+ break;
+ case SourceType::QmlDir:
+ convertToString(string, "QmlDir");
+ break;
+ case SourceType::Directory:
+ convertToString(string, "Directory");
+ break;
+ }
+}
+
class ProjectChunkId
{
public:
@@ -46,6 +68,17 @@ public:
friend bool operator<(ProjectChunkId first, ProjectPartId second) { return first.id < second; }
friend bool operator<(ProjectPartId first, ProjectChunkId second) { return first < second.id; }
+
+ template<typename String>
+ friend void convertToString(String &string, const ProjectChunkId &id)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("project part id", id.id),
+ keyValue("source type", id.sourceType));
+
+ convertToString(string, dict);
+ }
};
using ProjectChunkIds = std::vector<ProjectChunkId>;
@@ -67,6 +100,16 @@ public:
return first.id == second.id && first.sourceIds == second.sourceIds;
}
+ template<typename String>
+ friend void convertToString(String &string, const IdPaths &idPaths)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("id", idPaths.id), keyValue("source ids", idPaths.sourceIds));
+
+ convertToString(string, dict);
+ }
+
public:
ProjectChunkId id;
SourceIds sourceIds;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
index 18c3931249..1592628af5 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
@@ -7,8 +7,10 @@
#include "projectstorageids.h"
#include "projectstorageinfotypes.h"
+#include <nanotrace/nanotracehr.h>
#include <sqlite/sqlitevalue.h>
#include <utils/smallstring.h>
+#include <utils/utility.h>
#include <tuple>
#include <variant>
@@ -45,6 +47,17 @@ public:
< std::tie(second.sourceId, second.moduleId, second.version);
}
+ template<typename String>
+ friend void convertToString(String &string, const Import &import)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("module id", import.moduleId),
+ keyValue("source id", import.sourceId),
+ keyValue("version", import.version));
+ convertToString(string, dict);
+ }
+
public:
Storage::Version version;
ModuleId moduleId;
@@ -57,11 +70,53 @@ namespace Synchronization {
enum class TypeNameKind { Exported = 1, QualifiedExported = 2 };
-enum class FileType : char { QmlTypes, QmlDocument };
+template<typename String>
+void convertToString(String &string, const TypeNameKind &kind)
+{
+ switch (kind) {
+ case TypeNameKind::Exported:
+ convertToString(string, "Exported");
+ break;
+ case TypeNameKind::QualifiedExported:
+ convertToString(string, "QualifiedExported");
+ break;
+ }
+}
+
+enum class FileType : char { QmlTypes, QmlDocument, Directory };
+
+template<typename String>
+void convertToString(String &string, const FileType &type)
+{
+ switch (type) {
+ case FileType::QmlTypes:
+ convertToString(string, "QmlTypes");
+ break;
+ case FileType::QmlDocument:
+ convertToString(string, "QmlDocument");
+ break;
+ case FileType::Directory:
+ convertToString(string, "Directory");
+ break;
+ }
+}
enum class IsQualified : int { No, Yes };
-inline int operator-(IsQualified first, IsQualified second)
+template<typename String>
+void convertToString(String &string, const IsQualified &isQualified)
+{
+ switch (isQualified) {
+ case IsQualified::No:
+ convertToString(string, "No");
+ break;
+ case IsQualified::Yes:
+ convertToString(string, "Yes");
+ break;
+ }
+}
+
+inline int operator-(IsQualified first, const IsQualified &second)
{
return static_cast<int>(first) - static_cast<int>(second);
}
@@ -78,6 +133,25 @@ enum class ImportKind : char {
ModuleExportedModuleDependency
};
+template<typename String>
+void convertToString(String &string, const ImportKind &kind)
+{
+ switch (kind) {
+ case ImportKind::Import:
+ convertToString(string, "Import");
+ break;
+ case ImportKind::ModuleDependency:
+ convertToString(string, "ModuleDependency");
+ break;
+ case ImportKind::ModuleExportedImport:
+ convertToString(string, "ModuleExportedImport");
+ break;
+ case ImportKind::ModuleExportedModuleDependency:
+ convertToString(string, "ModuleExportedModuleDependency");
+ break;
+ }
+}
+
class ImportView
{
public:
@@ -97,6 +171,19 @@ public:
&& first.version == second.version;
}
+ template<typename String>
+ friend void convertToString(String &string, const ImportView &import)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("import id", import.importId),
+ keyValue("source id", import.sourceId),
+ keyValue("module id", import.moduleId),
+ keyValue("version", import.version));
+
+ convertToString(string, dict);
+ }
+
public:
ImportId importId;
SourceId sourceId;
@@ -106,9 +193,22 @@ public:
enum class IsAutoVersion : char { No, Yes };
+template<typename String>
+void convertToString(String &string, const IsAutoVersion &isAutoVersion)
+{
+ switch (isAutoVersion) {
+ case IsAutoVersion::No:
+ convertToString(string, "No");
+ break;
+ case IsAutoVersion::Yes:
+ convertToString(string, "Yes");
+ break;
+ }
+}
+
constexpr bool operator<(IsAutoVersion first, IsAutoVersion second)
{
- return to_underlying(first) < to_underlying(second);
+ return Utils::to_underlying(first) < Utils::to_underlying(second);
}
class ModuleExportedImport
@@ -137,6 +237,19 @@ public:
< std::tie(second.moduleId, second.exportedModuleId, second.isAutoVersion, second.version);
}
+ template<typename String>
+ friend void convertToString(String &string, const ModuleExportedImport &import)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("module id", import.moduleId),
+ keyValue("exported module id", import.exportedModuleId),
+ keyValue("version", import.version),
+ keyValue("is auto version", import.isAutoVersion));
+
+ convertToString(string, dict);
+ }
+
public:
Storage::Version version;
ModuleId moduleId;
@@ -171,6 +284,20 @@ public:
&& first.version == second.version && first.isAutoVersion == second.isAutoVersion;
}
+ template<typename String>
+ friend void convertToString(String &string, const ModuleExportedImportView &import)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("module exported import id", import.moduleExportedImportId),
+ keyValue("module id", import.moduleId),
+ keyValue("exported module id", import.exportedModuleId),
+ keyValue("version", import.version),
+ keyValue("is auto version", import.isAutoVersion));
+
+ convertToString(string, dict);
+ }
+
public:
ModuleExportedImportId moduleExportedImportId;
Storage::Version version;
@@ -192,6 +319,16 @@ public:
return first.name == second.name;
}
+ template<typename String>
+ friend void convertToString(String &string, const ImportedType &importedType)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", importedType.name));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString name;
};
@@ -210,6 +347,17 @@ public:
return first.name == second.name && first.import == second.import;
}
+ template<typename String>
+ friend void convertToString(String &string, const QualifiedImportedType &importedType)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", importedType.name),
+ keyValue("import", importedType.import));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString name;
Import import;
@@ -264,6 +412,19 @@ public:
< std::tie(second.moduleId, second.name, second.version);
}
+ template<typename String>
+ friend void convertToString(String &string, const ExportedType &exportedType)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", exportedType.name),
+ keyValue("module id", exportedType.moduleId),
+ keyValue("type id", exportedType.typeId),
+ keyValue("version", exportedType.version));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
Storage::Version version;
@@ -295,6 +456,20 @@ public:
, exportedTypeNameId{exportedTypeNameId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const ExportedTypeView &exportedType)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", exportedType.name),
+ keyValue("module id", exportedType.moduleId),
+ keyValue("type id", exportedType.typeId),
+ keyValue("version", exportedType.version),
+ keyValue("version", exportedType.exportedTypeNameId));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallStringView name;
Storage::Version version;
@@ -305,6 +480,43 @@ public:
using ImportedTypeName = std::variant<ImportedType, QualifiedImportedType>;
+template<typename String>
+void convertToString(String &string, const ImportedTypeName &typeName)
+{
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+
+ struct Dispatcher
+ {
+ static const QmlDesigner::Storage::Import &nullImport()
+ {
+ static QmlDesigner::Storage::Import import;
+
+ return import;
+ }
+
+ void operator()(const QmlDesigner::Storage::Synchronization::ImportedType &importedType) const
+ {
+ auto dict = dictonary(keyValue("name", importedType.name));
+
+ convertToString(string, dict);
+ }
+
+ void operator()(
+ const QmlDesigner::Storage::Synchronization::QualifiedImportedType &qualifiedImportedType) const
+ {
+ auto dict = dictonary(keyValue("name", qualifiedImportedType.name),
+ keyValue("import", qualifiedImportedType.import));
+
+ convertToString(string, dict);
+ }
+
+ String &string;
+ };
+
+ std::visit(Dispatcher{string}, typeName);
+}
+
class EnumeratorDeclaration
{
public:
@@ -325,6 +537,18 @@ public:
&& first.hasValue == second.hasValue;
}
+ template<typename String>
+ friend void convertToString(String &string, const EnumeratorDeclaration &enumeratorDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", enumeratorDeclaration.name),
+ keyValue("value", enumeratorDeclaration.value),
+ keyValue("has value", enumeratorDeclaration.hasValue));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
long long value = 0;
@@ -349,6 +573,18 @@ public:
&& first.enumeratorDeclarations == second.enumeratorDeclarations;
}
+ template<typename String>
+ friend void convertToString(String &string, const EnumerationDeclaration &enumerationDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", enumerationDeclaration.name),
+ keyValue("enumerator declarations",
+ enumerationDeclaration.enumeratorDeclarations));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString name;
EnumeratorDeclarations enumeratorDeclarations;
@@ -368,6 +604,20 @@ public:
, id{id}
{}
+ template<typename String>
+ friend void convertToString(String &string,
+ const EnumerationDeclarationView &enumerationDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", enumerationDeclaration.name),
+ keyValue("enumerator declarations",
+ enumerationDeclaration.enumeratorDeclarations),
+ keyValue("id", enumerationDeclaration.id));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallStringView name;
::Utils::SmallStringView enumeratorDeclarations;
@@ -392,6 +642,18 @@ public:
&& first.traits == second.traits;
}
+ template<typename String>
+ friend void convertToString(String &string, const ParameterDeclaration &parameterDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", parameterDeclaration.name),
+ keyValue("type name", parameterDeclaration.typeName),
+ keyValue("traits", parameterDeclaration.traits));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
TypeNameString typeName;
@@ -418,6 +680,17 @@ public:
return first.name == second.name && first.parameters == second.parameters;
}
+ template<typename String>
+ friend void convertToString(String &string, const SignalDeclaration &signalDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", signalDeclaration.name),
+ keyValue("parameters", signalDeclaration.parameters));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
ParameterDeclarations parameters;
@@ -437,6 +710,18 @@ public:
, id{id}
{}
+ template<typename String>
+ friend void convertToString(String &string, const SignalDeclarationView &signalDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", signalDeclaration.name),
+ keyValue("signature", signalDeclaration.signature),
+ keyValue("id", signalDeclaration.id));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallStringView name;
::Utils::SmallStringView signature;
@@ -467,6 +752,18 @@ public:
&& first.parameters == second.parameters;
}
+ template<typename String>
+ friend void convertToString(String &string, const FunctionDeclaration &functionDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", functionDeclaration.name),
+ keyValue("return type name", functionDeclaration.returnTypeName),
+ keyValue("parameters", functionDeclaration.parameters));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
TypeNameString returnTypeName;
@@ -489,6 +786,19 @@ public:
, id{id}
{}
+ template<typename String>
+ friend void convertToString(String &string, const FunctionDeclarationView &functionDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", functionDeclaration.name),
+ keyValue("return type name", functionDeclaration.returnTypeName),
+ keyValue("signature", functionDeclaration.signature),
+ keyValue("id", functionDeclaration.id));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallStringView name;
::Utils::SmallStringView returnTypeName;
@@ -498,6 +808,19 @@ public:
enum class PropertyKind { Property, Alias };
+template<typename String>
+void convertToString(String &string, const PropertyKind &kind)
+{
+ switch (kind) {
+ case PropertyKind::Property:
+ convertToString(string, "Property");
+ break;
+ case PropertyKind::Alias:
+ convertToString(string, "Alias");
+ break;
+ }
+}
+
class PropertyDeclaration
{
public:
@@ -567,6 +890,24 @@ public:
&& first.traits == second.traits && first.kind == second.kind;
}
+ template<typename String>
+ friend void convertToString(String &string, const PropertyDeclaration &propertyDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", propertyDeclaration.name),
+ keyValue("type name", propertyDeclaration.typeName),
+ keyValue("alias property name", propertyDeclaration.aliasPropertyName),
+ keyValue("alias property name tail",
+ propertyDeclaration.aliasPropertyNameTail),
+ keyValue("traits", propertyDeclaration.traits),
+ keyValue("type id", propertyDeclaration.typeId),
+ keyValue("property type id", propertyDeclaration.propertyTypeId),
+ keyValue("kind", propertyDeclaration.kind));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallString name;
ImportedTypeName typeName;
@@ -597,6 +938,21 @@ public:
, aliasId{aliasId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const PropertyDeclarationView &propertyDeclaration)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("name", propertyDeclaration.name),
+ keyValue("traits", propertyDeclaration.traits),
+ keyValue("type id", propertyDeclaration.typeId),
+ keyValue("type name id", propertyDeclaration.typeNameId),
+ keyValue("id", propertyDeclaration.id),
+ keyValue("alias id", propertyDeclaration.aliasId));
+
+ convertToString(string, dict);
+ }
+
public:
::Utils::SmallStringView name;
PropertyDeclarationTraits traits = {};
@@ -608,6 +964,22 @@ public:
enum class ChangeLevel : char { Full, Minimal, ExcludeExportedTypes };
+template<typename String>
+void convertToString(String &string, const ChangeLevel &changeLevel)
+{
+ switch (changeLevel) {
+ case ChangeLevel::Full:
+ convertToString(string, "Full");
+ break;
+ case ChangeLevel::Minimal:
+ convertToString(string, "Minimal");
+ break;
+ case ChangeLevel::ExcludeExportedTypes:
+ convertToString(string, "ExcludeExportedTypes");
+ break;
+ }
+}
+
class Type
{
public:
@@ -717,6 +1089,27 @@ public:
&& first.sourceId == second.sourceId;
}
+ template<typename String>
+ friend void convertToString(String &string, const Type &type)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type name", type.typeName),
+ keyValue("prototype", type.prototype),
+ keyValue("extension", type.extension),
+ keyValue("exported types", type.exportedTypes),
+ keyValue("property declarations", type.propertyDeclarations),
+ keyValue("function declarations", type.functionDeclarations),
+ keyValue("signal declarations", type.signalDeclarations),
+ keyValue("enumeration declarations", type.enumerationDeclarations),
+ keyValue("traits", type.traits),
+ keyValue("source id", type.sourceId),
+ keyValue("change level", type.changeLevel),
+ keyValue("default property name", type.defaultPropertyName));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString typeName;
::Utils::SmallString defaultPropertyName;
@@ -747,6 +1140,20 @@ public:
, moduleId{moduleId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const PropertyEditorQmlPath &propertyEditorQmlPath)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type name", propertyEditorQmlPath.typeName),
+ keyValue("type id", propertyEditorQmlPath.typeId),
+ keyValue("path id", propertyEditorQmlPath.pathId),
+ keyValue("directory id", propertyEditorQmlPath.directoryId),
+ keyValue("module id", propertyEditorQmlPath.moduleId));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString typeName;
TypeId typeId;
@@ -757,39 +1164,55 @@ public:
using PropertyEditorQmlPaths = std::vector<class PropertyEditorQmlPath>;
-class ProjectData
+class DirectoryInfo
{
public:
- ProjectData(SourceId projectSourceId, SourceId sourceId, ModuleId moduleId, FileType fileType)
- : projectSourceId{projectSourceId}
+ DirectoryInfo(SourceId directorySourceId, SourceId sourceId, ModuleId moduleId, FileType fileType)
+ : directorySourceId{directorySourceId}
, sourceId{sourceId}
, moduleId{moduleId}
, fileType{fileType}
{}
- friend bool operator==(const ProjectData &first, const ProjectData &second)
+ friend bool operator==(const DirectoryInfo &first, const DirectoryInfo &second)
{
- return first.projectSourceId == second.projectSourceId && first.sourceId == second.sourceId
+ return first.directorySourceId == second.directorySourceId && first.sourceId == second.sourceId
&& first.moduleId.internalId() == second.moduleId.internalId()
&& first.fileType == second.fileType;
}
+ template<typename String>
+ friend void convertToString(String &string, const DirectoryInfo &directoryInfo)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("project source id", directoryInfo.directorySourceId),
+ keyValue("source id", directoryInfo.sourceId),
+ keyValue("module id", directoryInfo.moduleId),
+ keyValue("file type", directoryInfo.fileType));
+
+ convertToString(string, dict);
+ }
+
public:
- SourceId projectSourceId;
+ SourceId directorySourceId;
SourceId sourceId;
ModuleId moduleId;
FileType fileType;
};
-using ProjectDatas = std::vector<ProjectData>;
+using DirectoryInfos = std::vector<DirectoryInfo>;
class TypeAnnotation
{
public:
- TypeAnnotation(SourceId sourceId)
+ TypeAnnotation(SourceId sourceId, SourceId directorySourceId)
: sourceId{sourceId}
+ , directorySourceId{directorySourceId}
{}
+
TypeAnnotation(SourceId sourceId,
+ SourceId directorySourceId,
Utils::SmallStringView typeName,
ModuleId moduleId,
Utils::SmallStringView iconPath,
@@ -803,8 +1226,26 @@ public:
, sourceId{sourceId}
, moduleId{moduleId}
, traits{traits}
+ , directorySourceId{directorySourceId}
{}
+ template<typename String>
+ friend void convertToString(String &string, const TypeAnnotation &typeAnnotation)
+ {
+ using NanotraceHR::dictonary;
+ using NanotraceHR::keyValue;
+ auto dict = dictonary(keyValue("type name", typeAnnotation.typeName),
+ keyValue("icon path", typeAnnotation.iconPath),
+ keyValue("item library json", typeAnnotation.itemLibraryJson),
+ keyValue("hints json", typeAnnotation.hintsJson),
+ keyValue("type id", typeAnnotation.typeId),
+ keyValue("source id", typeAnnotation.sourceId),
+ keyValue("module id", typeAnnotation.moduleId),
+ keyValue("traits", typeAnnotation.traits));
+
+ convertToString(string, dict);
+ }
+
public:
TypeNameString typeName;
Utils::PathString iconPath;
@@ -814,6 +1255,7 @@ public:
SourceId sourceId;
ModuleId moduleId;
TypeTraits traits;
+ SourceId directorySourceId;
};
using TypeAnnotations = std::vector<TypeAnnotation>;
@@ -853,9 +1295,9 @@ public:
, fileStatuses(std::move(fileStatuses))
{}
- SynchronizationPackage(SourceIds updatedProjectSourceIds, ProjectDatas projectDatas)
- : projectDatas(std::move(projectDatas))
- , updatedProjectSourceIds(std::move(updatedProjectSourceIds))
+ SynchronizationPackage(SourceIds updatedDirectoryInfoSourceIds, DirectoryInfos directoryInfos)
+ : directoryInfos(std::move(directoryInfos))
+ , updatedDirectoryInfoSourceIds(std::move(updatedDirectoryInfoSourceIds))
{}
public:
@@ -864,8 +1306,8 @@ public:
SourceIds updatedSourceIds;
SourceIds updatedFileStatusSourceIds;
FileStatuses fileStatuses;
- ProjectDatas projectDatas;
- SourceIds updatedProjectSourceIds;
+ DirectoryInfos directoryInfos;
+ SourceIds updatedDirectoryInfoSourceIds;
Imports moduleDependencies;
SourceIds updatedModuleDependencySourceIds;
ModuleExportedImports moduleExportedImports;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
index 62fcf310f6..a0e7bba3c5 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
@@ -11,8 +11,11 @@
#include "qmltypesparserinterface.h"
#include "sourcepath.h"
#include "sourcepathcache.h"
+#include "typeannotationreader.h"
#include <sqlitedatabase.h>
+#include <tracing/qmldesignertracing.h>
+#include <utils/set_algorithm.h>
#include <QDirIterator>
#include <QRegularExpression>
@@ -21,6 +24,26 @@
#include <functional>
namespace QmlDesigner {
+constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory;
+using NanotraceHR::keyValue;
+using Tracer = ProjectStorageTracing::Category::TracerType;
+
+template<typename String>
+void convertToString(String &string, const ProjectStorageUpdater::FileState &state)
+{
+ switch (state) {
+ case ProjectStorageUpdater::FileState::Changed:
+ convertToString(string, "Changed");
+ break;
+ case ProjectStorageUpdater::FileState::NotChanged:
+ convertToString(string, "NotChanged");
+ break;
+ case ProjectStorageUpdater::FileState::NotExists:
+ convertToString(string, "NotExists");
+ break;
+ }
+}
+
namespace {
QStringList filterMultipleEntries(QStringList qmlTypes)
@@ -79,6 +102,8 @@ ProjectStorageUpdater::Components createComponents(
}
for (const QmlDirParser::Component &qmlDirParserComponent : qmlDirParserComponents) {
+ if (qmlDirParserComponent.fileName.contains('/'))
+ continue;
components.push_back(ProjectStorageUpdater::Component{qmlDirParserComponent.fileName,
qmlDirParserComponent.typeName,
moduleId,
@@ -110,10 +135,15 @@ SourceIds filterNotUpdatedSourceIds(SourceIds updatedSourceIds, SourceIds notUpd
return filteredUpdatedSourceIds;
}
-void addSourceIds(SourceIds &sourceIds, const Storage::Synchronization::ProjectDatas &projectDatas)
+void addSourceIds(SourceIds &sourceIds,
+ const Storage::Synchronization::DirectoryInfos &directoryInfos,
+ TracerLiteral message,
+ Tracer &tracer)
{
- for (const auto &projectData : projectDatas)
- sourceIds.push_back(projectData.sourceId);
+ for (const auto &directoryInfo : directoryInfos) {
+ tracer.tick(message, keyValue("source id", directoryInfo.sourceId));
+ sourceIds.push_back(directoryInfo.sourceId);
+ }
}
Storage::Version convertVersion(LanguageUtils::ComponentVersion version)
@@ -131,34 +161,84 @@ Storage::Synchronization::IsAutoVersion convertToIsAutoVersion(QmlDirParser::Imp
void addDependencies(Storage::Imports &dependencies,
SourceId sourceId,
const QList<QmlDirParser::Import> &qmldirDependencies,
- ProjectStorageInterface &projectStorage)
+ ProjectStorageInterface &projectStorage,
+ TracerLiteral message,
+ Tracer &tracer)
{
for (const QmlDirParser::Import &qmldirDependency : qmldirDependencies) {
- ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module}
- + "-cppnative");
- dependencies.emplace_back(moduleId, Storage::Version{}, sourceId);
+ ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module},
+ Storage::ModuleKind::CppLibrary);
+ auto &import = dependencies.emplace_back(moduleId, Storage::Version{}, sourceId);
+ tracer.tick(message, keyValue("import", import));
}
}
+void addModuleExportedImport(Storage::Synchronization::ModuleExportedImports &imports,
+ ModuleId moduleId,
+ ModuleId exportedModuleId,
+ Storage::Version version,
+ Storage::Synchronization::IsAutoVersion isAutoVersion,
+ std::string_view moduleName,
+ Storage::ModuleKind moduleKind,
+ std::string_view exportedModuleName)
+{
+ NanotraceHR::Tracer tracer{"add module exported imports"_t,
+ category(),
+ keyValue("module id", moduleId),
+ keyValue("exported module id", exportedModuleId),
+ keyValue("version", version),
+ keyValue("is auto version", isAutoVersion),
+ keyValue("module name", moduleName),
+ keyValue("module kind", moduleKind),
+ keyValue("exported module name", exportedModuleName)};
+
+ imports.emplace_back(moduleId, exportedModuleId, version, isAutoVersion);
+}
+
+bool isOptionalImport(QmlDirParser::Import::Flags flags)
+{
+ return flags & QmlDirParser::Import::Optional && !(flags & QmlDirParser::Import::OptionalDefault);
+}
+
void addModuleExportedImports(Storage::Synchronization::ModuleExportedImports &imports,
ModuleId moduleId,
ModuleId cppModuleId,
+ std::string_view moduleName,
const QList<QmlDirParser::Import> &qmldirImports,
ProjectStorageInterface &projectStorage)
{
+ NanotraceHR::Tracer tracer{"add module exported imports"_t,
+ category(),
+ keyValue("cpp module id", cppModuleId),
+ keyValue("module id", moduleId)};
+
for (const QmlDirParser::Import &qmldirImport : qmldirImports) {
- ModuleId exportedModuleId = projectStorage.moduleId(Utils::PathString{qmldirImport.module});
- imports.emplace_back(moduleId,
- exportedModuleId,
- convertVersion(qmldirImport.version),
- convertToIsAutoVersion(qmldirImport.flags));
+ if (isOptionalImport(qmldirImport.flags))
+ continue;
- ModuleId exportedCppModuleId = projectStorage.moduleId(
- Utils::PathString{qmldirImport.module} + "-cppnative");
- imports.emplace_back(cppModuleId,
- exportedCppModuleId,
- Storage::Version{},
- Storage::Synchronization::IsAutoVersion::No);
+ Utils::PathString exportedModuleName{qmldirImport.module};
+ using Storage::ModuleKind;
+ ModuleId exportedModuleId = projectStorage.moduleId(exportedModuleName,
+ ModuleKind::QmlLibrary);
+ addModuleExportedImport(imports,
+ moduleId,
+ exportedModuleId,
+ convertVersion(qmldirImport.version),
+ convertToIsAutoVersion(qmldirImport.flags),
+ moduleName,
+ ModuleKind::QmlLibrary,
+ exportedModuleName);
+
+ ModuleId exportedCppModuleId = projectStorage.moduleId(exportedModuleName,
+ ModuleKind::CppLibrary);
+ addModuleExportedImport(imports,
+ cppModuleId,
+ exportedCppModuleId,
+ Storage::Version{},
+ Storage::Synchronization::IsAutoVersion::No,
+ moduleName,
+ ModuleKind::CppLibrary,
+ exportedModuleName);
}
}
@@ -182,8 +262,14 @@ std::vector<IdPaths> createIdPaths(ProjectStorageUpdater::WatchedSourceIdsIds wa
void ProjectStorageUpdater::update(QStringList directories,
QStringList qmlTypesPaths,
- const QString &propertyEditorResourcesPath)
+ const QString &propertyEditorResourcesPath,
+ const QStringList &typeAnnotationPaths)
{
+ NanotraceHR::Tracer tracer{"update"_t,
+ category(),
+ keyValue("directories", directories),
+ keyValue("qml types paths", qmlTypesPaths)};
+
Storage::Synchronization::SynchronizationPackage package;
WatchedSourceIdsIds watchedSourceIds{Utils::span{directories}.size()};
NotUpdatedSourceIds notUpdatedSourceIds{Utils::span{directories}.size()};
@@ -191,6 +277,7 @@ void ProjectStorageUpdater::update(QStringList directories,
updateDirectories(directories, package, notUpdatedSourceIds, watchedSourceIds);
updateQmlTypes(qmlTypesPaths, package, notUpdatedSourceIds, watchedSourceIds);
updatePropertyEditorPaths(propertyEditorResourcesPath, package, notUpdatedSourceIds);
+ updateTypeAnnotations(typeAnnotationPaths, package, notUpdatedSourceIds);
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
std::move(notUpdatedSourceIds.sourceIds));
@@ -198,7 +285,13 @@ void ProjectStorageUpdater::update(QStringList directories,
std::move(package.updatedFileStatusSourceIds),
std::move(notUpdatedSourceIds.fileStatusSourceIds));
- m_projectStorage.synchronize(std::move(package));
+ try {
+ m_projectStorage.synchronize(std::move(package));
+ } catch (const TypeNameDoesNotExists &exception) {
+ qDebug() << "missing type: " << exception.what();
+ } catch (...) {
+ qWarning() << "Project storage could not been updated!";
+ }
m_pathWatcher.updateIdPaths(createIdPaths(watchedSourceIds, m_projectPartId));
}
@@ -211,25 +304,30 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
if (qmlTypesPaths.empty())
return;
- ModuleId moduleId = m_projectStorage.moduleId("QML-cppnative");
+ NanotraceHR::Tracer tracer{"update qmltypes file"_t, category()};
+
+ ModuleId moduleId = m_projectStorage.moduleId("QML", Storage::ModuleKind::CppLibrary);
for (const QString &qmlTypesPath : qmlTypesPaths) {
SourceId sourceId = m_pathCache.sourceId(SourcePath{qmlTypesPath});
watchedSourceIdsIds.qmltypesSourceIds.push_back(sourceId);
+ tracer.tick("append watched qml types source id"_t,
+ keyValue("source id", sourceId),
+ keyValue("qml types path", qmlTypesPath));
- Storage::Synchronization::ProjectData projectData{sourceId,
- sourceId,
- moduleId,
- Storage::Synchronization::FileType::QmlTypes};
+ Storage::Synchronization::DirectoryInfo directoryInfo{
+ sourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes};
- FileState state = parseTypeInfo(projectData,
+ FileState state = parseTypeInfo(directoryInfo,
Utils::PathString{qmlTypesPath},
package,
notUpdatedSourceIds);
if (state == FileState::Changed) {
- package.projectDatas.push_back(std::move(projectData));
- package.updatedProjectSourceIds.push_back(sourceId);
+ tracer.tick("append project data"_t, keyValue("project data", directoryInfo));
+ package.directoryInfos.push_back(std::move(directoryInfo));
+ tracer.tick("append updated project source ids"_t, keyValue("source id", sourceId));
+ package.updatedDirectoryInfoSourceIds.push_back(sourceId);
}
}
}
@@ -246,24 +344,199 @@ ProjectStorageUpdater::FileState combineState(FileStates... fileStates)
return ProjectStorageUpdater::FileState::NotExists;
}
+
} // namespace
+void ProjectStorageUpdater::updateDirectoryChanged(std::string_view directoryPath,
+ FileState qmldirState,
+ SourcePath qmldirSourcePath,
+ SourceId qmldirSourceId,
+ SourceId directorySourceId,
+ SourceContextId directoryId,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds,
+ Tracer &tracer)
+{
+ QmlDirParser parser;
+ if (qmldirState != FileState::NotExists)
+ parser.parse(m_fileSystem.contentAsQString(QString{qmldirSourcePath}));
+
+ if (qmldirState != FileState::NotChanged) {
+ tracer.tick("append updated source id"_t, keyValue("module id", qmldirSourceId));
+ package.updatedSourceIds.push_back(qmldirSourceId);
+ }
+
+ using Storage::ModuleKind;
+ Utils::PathString moduleName{parser.typeNamespace()};
+ ModuleId moduleId = m_projectStorage.moduleId(moduleName, ModuleKind::QmlLibrary);
+ ModuleId cppModuleId = m_projectStorage.moduleId(moduleName, ModuleKind::CppLibrary);
+ ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath, ModuleKind::PathLibrary);
+
+ auto imports = filterMultipleEntries(parser.imports());
+
+ addModuleExportedImports(package.moduleExportedImports,
+ moduleId,
+ cppModuleId,
+ moduleName,
+ imports,
+ m_projectStorage);
+ tracer.tick("append updated module id"_t, keyValue("module id", moduleId));
+ package.updatedModuleIds.push_back(moduleId);
+
+ const auto qmlDirectoryInfos = m_projectStorage.fetchDirectoryInfos(directorySourceId);
+ addSourceIds(package.updatedSourceIds, qmlDirectoryInfos, "append updated source id"_t, tracer);
+ addSourceIds(package.updatedFileStatusSourceIds,
+ qmlDirectoryInfos,
+ "append updated file status source id"_t,
+ tracer);
+
+ auto qmlTypes = filterMultipleEntries(parser.typeInfos());
+
+ if (!qmlTypes.isEmpty()) {
+ parseTypeInfos(qmlTypes,
+ filterMultipleEntries(parser.dependencies()),
+ imports,
+ directorySourceId,
+ directoryPath,
+ cppModuleId,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
+ }
+ parseQmlComponents(
+ createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath),
+ directorySourceId,
+ directoryId,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds,
+ qmldirState);
+ tracer.tick("append updated project source id"_t, keyValue("module id", moduleId));
+ package.updatedDirectoryInfoSourceIds.push_back(directorySourceId);
+}
+
void ProjectStorageUpdater::updateDirectories(const QStringList &directories,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds,
WatchedSourceIdsIds &watchedSourceIdsIds)
{
+ NanotraceHR::Tracer tracer{"update directories"_t, category()};
+
for (const QString &directory : directories)
- updateDirectory({directory}, package, notUpdatedSourceIds, watchedSourceIdsIds);
+ updateDirectory({directory}, {}, package, notUpdatedSourceIds, watchedSourceIdsIds);
+}
+
+void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &directoryPath,
+ SourceId directorySourceId,
+ FileState directoryState,
+ const SourceContextIds &subdirectoriesToIgnore,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds)
+{
+ struct Directory
+ {
+ Directory(Utils::SmallStringView path, SourceContextId sourceContextId, SourceId sourceId)
+ : path{path}
+ , sourceContextId{sourceContextId}
+ , sourceId{sourceId}
+ {}
+
+ bool operator<(const Directory &other) const
+ {
+ return sourceContextId < other.sourceContextId;
+ }
+
+ bool operator==(const Directory &other) const
+ {
+ return sourceContextId == other.sourceContextId;
+ }
+
+ Utils::PathString path;
+ SourceContextId sourceContextId;
+ SourceId sourceId;
+ };
+
+ struct Compare
+ {
+ bool operator()(const Directory &first, const Directory &second) const
+ {
+ return first.sourceContextId < second.sourceContextId;
+ }
+
+ bool operator()(const Directory &first, SourceContextId second) const
+ {
+ return first.sourceContextId < second;
+ }
+
+ bool operator()(SourceContextId first, const Directory &second) const
+ {
+ return first < second.sourceContextId;
+ }
+ };
+
+ using Directories = QVarLengthArray<Directory, 32>;
+
+ auto subdirectorySourceIds = m_projectStorage.fetchSubdirectorySourceIds(directorySourceId);
+ auto subdirectories = Utils::transform<Directories>(
+ subdirectorySourceIds, [&](SourceId sourceId) -> Directory {
+ auto sourceContextId = m_pathCache.sourceContextId(sourceId);
+ auto subdirectoryPath = m_pathCache.sourceContextPath(sourceContextId);
+ return {subdirectoryPath, sourceContextId, sourceId};
+ });
+
+ auto exisitingSubdirectoryPaths = m_fileSystem.subdirectories(directoryPath.toQString());
+ Directories existingSubdirecories;
+ for (const QString &subdirectory : exisitingSubdirectoryPaths) {
+ if (subdirectory.endsWith("/designer") || subdirectory.endsWith("/QtQuick/Scene2D")
+ || subdirectory.endsWith("/QtQuick/Scene3D"))
+ continue;
+ Utils::PathString subdirectoryPath = subdirectory;
+ auto [sourceContextId, sourceId] = m_pathCache.sourceContextAndSourceId(
+ SourcePath{subdirectoryPath + "/."});
+ subdirectories.emplace_back(subdirectoryPath, sourceContextId, sourceId);
+ existingSubdirecories.emplace_back(subdirectoryPath, sourceContextId, sourceId);
+ }
+
+ std::sort(subdirectories.begin(), subdirectories.end());
+ subdirectories.erase(std::unique(subdirectories.begin(), subdirectories.end()),
+ subdirectories.end());
+
+ std::set_difference(subdirectories.begin(),
+ subdirectories.end(),
+ subdirectoriesToIgnore.begin(),
+ subdirectoriesToIgnore.end(),
+ Utils::make_iterator([&](const Directory &subdirectory) {
+ updateDirectory(subdirectory.path,
+ subdirectoriesToIgnore,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
+ }),
+ Compare{});
+
+ if (directoryState == FileState::Changed) {
+ for (const auto &[subdirectoryPath, sourceContextId, subdirectorySourceId] :
+ existingSubdirecories) {
+ package.directoryInfos.emplace_back(directorySourceId,
+ subdirectorySourceId,
+ ModuleId{},
+ Storage::Synchronization::FileType::Directory);
+ }
+ }
}
void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath,
+ const SourceContextIds &subdirectoriesToIgnore,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds,
WatchedSourceIdsIds &watchedSourceIdsIds)
{
+ NanotraceHR::Tracer tracer{"update directory"_t, category(), keyValue("directory", directoryPath)};
+
SourcePath qmldirSourcePath{directoryPath + "/qmldir"};
- auto [directoryId, qmlDirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath);
+ auto [directoryId, qmldirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath);
SourcePath directorySourcePath{directoryPath + "/."};
auto directorySourceId = m_pathCache.sourceId(directorySourcePath);
@@ -271,82 +544,69 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa
if (directoryState != FileState::NotExists)
watchedSourceIdsIds.directorySourceIds.push_back(directorySourceId);
- auto qmldirState = fileState(qmlDirSourceId, package, notUpdatedSourceIds);
+ auto qmldirState = fileState(qmldirSourceId, package, notUpdatedSourceIds);
if (qmldirState != FileState::NotExists)
- watchedSourceIdsIds.qmldirSourceIds.push_back(qmlDirSourceId);
+ watchedSourceIdsIds.qmldirSourceIds.push_back(qmldirSourceId);
switch (combineState(directoryState, qmldirState)) {
case FileState::Changed: {
- QmlDirParser parser;
- if (qmldirState != FileState::NotExists)
- parser.parse(m_fileSystem.contentAsQString(QString{qmldirSourcePath}));
-
- if (qmldirState != FileState::NotChanged)
- package.updatedSourceIds.push_back(qmlDirSourceId);
-
- Utils::PathString moduleName{parser.typeNamespace()};
- ModuleId moduleId = m_projectStorage.moduleId(moduleName);
- ModuleId cppModuleId = m_projectStorage.moduleId(moduleName + "-cppnative");
- ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath);
-
- auto imports = filterMultipleEntries(parser.imports());
-
- addModuleExportedImports(package.moduleExportedImports,
- moduleId,
- cppModuleId,
- imports,
- m_projectStorage);
- package.updatedModuleIds.push_back(moduleId);
-
- const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(directorySourceId);
- addSourceIds(package.updatedSourceIds, qmlProjectDatas);
- addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
-
- auto qmlTypes = filterMultipleEntries(parser.typeInfos());
-
- if (!qmlTypes.isEmpty()) {
- parseTypeInfos(qmlTypes,
- filterMultipleEntries(parser.dependencies()),
- imports,
- directorySourceId,
- directoryPath,
- cppModuleId,
- package,
- notUpdatedSourceIds,
- watchedSourceIdsIds);
- }
- parseQmlComponents(
- createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath),
- directorySourceId,
- directoryId,
- package,
- notUpdatedSourceIds,
- watchedSourceIdsIds,
- qmldirState);
- package.updatedProjectSourceIds.push_back(directorySourceId);
+ tracer.tick("update directory changed"_t);
+ updateDirectoryChanged(directoryPath,
+ qmldirState,
+ qmldirSourcePath,
+ qmldirSourceId,
+ directorySourceId,
+ directoryId,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds,
+ tracer);
break;
}
case FileState::NotChanged: {
- parseProjectDatas(m_projectStorage.fetchProjectDatas(directorySourceId),
- package,
- notUpdatedSourceIds,
- watchedSourceIdsIds);
+ tracer.tick("update directory not changed"_t);
+
+ parseDirectoryInfos(m_projectStorage.fetchDirectoryInfos(directorySourceId),
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
break;
}
case FileState::NotExists: {
+ tracer.tick("update directory don't exits"_t);
+
package.updatedFileStatusSourceIds.push_back(directorySourceId);
- package.updatedFileStatusSourceIds.push_back(qmlDirSourceId);
- package.updatedProjectSourceIds.push_back(directorySourceId);
- package.updatedSourceIds.push_back(qmlDirSourceId);
- auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(directorySourceId);
- for (const Storage::Synchronization::ProjectData &projectData : qmlProjectDatas) {
- package.updatedSourceIds.push_back(projectData.sourceId);
- package.updatedFileStatusSourceIds.push_back(projectData.sourceId);
+ package.updatedFileStatusSourceIds.push_back(qmldirSourceId);
+ package.updatedDirectoryInfoSourceIds.push_back(directorySourceId);
+ package.updatedSourceIds.push_back(qmldirSourceId);
+ auto qmlDirectoryInfos = m_projectStorage.fetchDirectoryInfos(directorySourceId);
+ for (const Storage::Synchronization::DirectoryInfo &directoryInfo : qmlDirectoryInfos) {
+ tracer.tick("append updated source id"_t, keyValue("source id", directoryInfo.sourceId));
+ package.updatedSourceIds.push_back(directoryInfo.sourceId);
+ tracer.tick("append updated file status source id"_t,
+ keyValue("source id", directoryInfo.sourceId));
+ package.updatedFileStatusSourceIds.push_back(directoryInfo.sourceId);
}
break;
}
}
+
+ updateSubdirectories(directoryPath,
+ directorySourceId,
+ directoryState,
+ subdirectoriesToIgnore,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
+
+ tracer.end(keyValue("qmldir source path", qmldirSourcePath),
+ keyValue("directory source path", directorySourcePath),
+ keyValue("directory id", directoryId),
+ keyValue("qmldir source id", qmldirSourceId),
+ keyValue("directory source source id", directorySourceId),
+ keyValue("qmldir state", qmldirState),
+ keyValue("directory state", directoryState));
}
void ProjectStorageUpdater::updatePropertyEditorPaths(
@@ -354,6 +614,10 @@ void ProjectStorageUpdater::updatePropertyEditorPaths(
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds)
{
+ NanotraceHR::Tracer tracer{"update property editor paths"_t,
+ category(),
+ keyValue("property editor resources path", propertyEditorResourcesPath)};
+
if (propertyEditorResourcesPath.isEmpty())
return;
@@ -368,49 +632,196 @@ void ProjectStorageUpdater::updatePropertyEditorPaths(
auto state = fileState(directorySourceId, package, notUpdatedSourceIds);
- if (state == FileState::Changed)
- updatePropertyEditorPath(pathInfo.filePath(), package, directorySourceId);
+ if (state == FileState::Changed) {
+ updatePropertyEditorPath(pathInfo.filePath(),
+ package,
+ directorySourceId,
+ propertyEditorResourcesPath.size() + 1);
+ }
}
}
+namespace {
+
+template<typename SourceIds1, typename SourceIds2>
+SmallSourceIds<16> mergedSourceIds(const SourceIds1 &sourceIds1, const SourceIds2 &sourceIds2)
+{
+ SmallSourceIds<16> mergedSourceIds;
+
+ std::set_union(sourceIds1.begin(),
+ sourceIds1.end(),
+ sourceIds2.begin(),
+ sourceIds2.end(),
+ std::back_inserter(mergedSourceIds));
+
+ return mergedSourceIds;
+}
+} // namespace
+
+void ProjectStorageUpdater::updateTypeAnnotations(const QStringList &directoryPaths,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds)
+{
+ NanotraceHR::Tracer tracer("update type annotations"_t, category());
+
+ std::map<SourceId, SmallSourceIds<16>> updatedSourceIdsDictonary;
+
+ for (SourceId directoryId : m_projectStorage.typeAnnotationDirectorySourceIds())
+ updatedSourceIdsDictonary[directoryId] = {};
+
+ for (const auto &directoryPath : directoryPaths)
+ updateTypeAnnotations(directoryPath, package, notUpdatedSourceIds, updatedSourceIdsDictonary);
+
+ updateTypeAnnotationDirectories(package, notUpdatedSourceIds, updatedSourceIdsDictonary);
+}
+
void ProjectStorageUpdater::updateTypeAnnotations(
- const QString & /*propertyEditorResourcesPath*/,
- Storage::Synchronization::SynchronizationPackage & /*package*/,
- NotUpdatedSourceIds & /*notUpdatedSourceIds*/)
+ const QString &rootDirectoryPath,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary)
+{
+ NanotraceHR::Tracer tracer("update type annotation directory"_t,
+ category(),
+ keyValue("path", rootDirectoryPath));
+
+ if (rootDirectoryPath.isEmpty())
+ return;
+
+ QDirIterator directoryIterator{rootDirectoryPath,
+ {"*.metainfo"},
+ QDir::NoDotAndDotDot | QDir::Files,
+ QDirIterator::Subdirectories};
+
+ while (directoryIterator.hasNext()) {
+ auto fileInfo = directoryIterator.nextFileInfo();
+ auto filePath = fileInfo.filePath();
+ SourceId sourceId = m_pathCache.sourceId(SourcePath{filePath});
+
+ auto directoryPath = fileInfo.canonicalPath();
+
+ SourceId directorySourceId = m_pathCache.sourceId(SourcePath{directoryPath + "/."});
+
+ auto state = fileState(sourceId, package, notUpdatedSourceIds);
+ if (state == FileState::Changed)
+ updateTypeAnnotation(directoryPath, fileInfo.filePath(), sourceId, directorySourceId, package);
+
+ if (state != FileState::NotChanged)
+ updatedSourceIdsDictonary[directorySourceId].push_back(sourceId);
+ }
+}
+
+void ProjectStorageUpdater::updateTypeAnnotationDirectories(
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary)
+{
+ for (auto &[directorySourceId, updatedSourceIds] : updatedSourceIdsDictonary) {
+ auto directoryState = fileState(directorySourceId, package, notUpdatedSourceIds);
+
+ if (directoryState != FileState::NotChanged) {
+ auto existingTypeAnnotationSourceIds = m_projectStorage.typeAnnotationSourceIds(
+ directorySourceId);
+
+ std::sort(updatedSourceIds.begin(), updatedSourceIds.end());
+
+ auto changedSourceIds = mergedSourceIds(existingTypeAnnotationSourceIds, updatedSourceIds);
+ package.updatedTypeAnnotationSourceIds.insert(package.updatedTypeAnnotationSourceIds.end(),
+ changedSourceIds.begin(),
+ changedSourceIds.end());
+ } else {
+ package.updatedTypeAnnotationSourceIds.insert(package.updatedTypeAnnotationSourceIds.end(),
+ updatedSourceIds.begin(),
+ updatedSourceIds.end());
+ }
+ }
+}
+
+namespace {
+QString contentFromFile(const QString &path)
{
- // const auto typeAnnotations = dir.entryInfoList({"*.metainfo"}, QDir::Files);
+ QFile file{path};
+ if (file.open(QIODevice::ReadOnly))
+ return QString::fromUtf8(file.readAll());
+
+ return {};
+}
+} // namespace
+
+void ProjectStorageUpdater::updateTypeAnnotation(const QString &directoryPath,
+ const QString &filePath,
+ SourceId sourceId,
+ SourceId directorySourceId,
+ Storage::Synchronization::SynchronizationPackage &package)
+{
+ NanotraceHR::Tracer tracer{"update type annotation path"_t,
+ category(),
+ keyValue("path", filePath),
+ keyValue("directory path", directoryPath)};
+
+ Storage::TypeAnnotationReader reader{m_projectStorage};
+
+ auto annotations = reader.parseTypeAnnotation(contentFromFile(filePath),
+ directoryPath,
+ sourceId,
+ directorySourceId);
+ auto &typeAnnotations = package.typeAnnotations;
+ package.typeAnnotations.insert(typeAnnotations.end(),
+ std::make_move_iterator(annotations.begin()),
+ std::make_move_iterator(annotations.end()));
}
void ProjectStorageUpdater::updatePropertyEditorPath(
const QString &directoryPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceId directorySourceId)
+ SourceId directorySourceId,
+ long long pathOffset)
{
+ NanotraceHR::Tracer tracer{"update property editor path"_t,
+ category(),
+ keyValue("directory path", directoryPath),
+ keyValue("directory source id", directorySourceId)};
+
+ tracer.tick("append updated property editor qml path source id"_t,
+ keyValue("source id", directorySourceId));
package.updatedPropertyEditorQmlPathSourceIds.push_back(directorySourceId);
auto dir = QDir{directoryPath};
const auto fileInfos = dir.entryInfoList({"*Pane.qml", "*Specifics.qml"}, QDir::Files);
for (const auto &fileInfo : fileInfos)
- updatePropertyEditorFilePath(fileInfo.filePath(), package, directorySourceId);
+ updatePropertyEditorFilePath(fileInfo.filePath(), package, directorySourceId, pathOffset);
}
void ProjectStorageUpdater::updatePropertyEditorFilePath(
const QString &path,
Storage::Synchronization::SynchronizationPackage &package,
- SourceId directorySourceId)
+ SourceId directorySourceId,
+ long long pathOffset)
{
- QRegularExpression regex{R"xo(.+\/(\w+)\/(\w+)(Specifics|Pane).qml)xo"};
- auto match = regex.match(path);
+ NanotraceHR::Tracer tracer{"update property editor file path"_t,
+ category(),
+ keyValue("directory path", path),
+ keyValue("directory source id", directorySourceId)};
+
+ QRegularExpression regex{R"xo((.+)\/(\w+)(Specifics|Pane).qml)xo"};
+ auto match = regex.match(QStringView{path}.mid(pathOffset));
QString oldModuleName;
ModuleId moduleId;
if (match.hasMatch()) {
- auto moduleName = match.capturedView(1);
+ auto moduleName = match.capturedView(1).toString();
+ moduleName.replace('/', '.');
if (oldModuleName != moduleName) {
- oldModuleName = moduleName.toString();
- moduleId = m_projectStorage.moduleId(Utils::SmallString{moduleName});
+ oldModuleName = moduleName;
+ moduleId = m_projectStorage.moduleId(Utils::SmallString{moduleName},
+ Storage::ModuleKind::QmlLibrary);
}
Storage::TypeNameString typeName{match.capturedView(2)};
SourceId pathId = m_pathCache.sourceId(SourcePath{path});
- package.propertyEditorQmlPaths.emplace_back(moduleId, typeName, pathId, directorySourceId);
+ const auto &paths = package.propertyEditorQmlPaths.emplace_back(moduleId,
+ typeName,
+ pathId,
+ directorySourceId);
+ tracer.tick("append property editor qml paths"_t,
+ keyValue("property editor qml paths", paths));
}
}
@@ -447,6 +858,10 @@ bool contains(const Container &container, Id id)
void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &changedIdPaths)
{
+ NanotraceHR::Tracer tracer{"paths with ids changed"_t,
+ category(),
+ keyValue("id paths", changedIdPaths)};
+
m_changedIdPaths.insert(m_changedIdPaths.end(), changedIdPaths.begin(), changedIdPaths.end());
Storage::Synchronization::SynchronizationPackage package;
@@ -486,7 +901,11 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan
for (auto sourceContextId : directorySourceContextIds) {
Utils::PathString directory = m_pathCache.sourceContextPath(sourceContextId);
- updateDirectory(directory, package, notUpdatedSourceIds, watchedSourceIds);
+ updateDirectory(directory,
+ directorySourceContextIds,
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIds);
}
for (SourceId sourceId : filterUniqueSourceIds(qmlDocumentSourceIds)) {
@@ -498,9 +917,9 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &chan
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);
+ auto directoryInfo = m_projectStorage.fetchDirectoryInfo(sourceId);
+ if (directoryInfo)
+ parseTypeInfo(*directoryInfo, qmltypesPath, package, notUpdatedSourceIds);
}
}
} catch (const QmlDesigner::CannotParseQmlTypesFile &) {
@@ -539,72 +958,99 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
NotUpdatedSourceIds &notUpdatedSourceIds,
WatchedSourceIdsIds &watchedSourceIds)
{
+ NanotraceHR::Tracer tracer{"parse type infos"_t,
+ category(),
+ keyValue("directory source id", directorySourceId),
+ keyValue("directory path", directoryPath),
+ keyValue("module id", moduleId)};
+
for (const QString &typeInfo : typeInfos) {
+ NanotraceHR::Tracer tracer{"parse type info"_t, category(), keyValue("type info", typeInfo)};
+
Utils::PathString qmltypesPath = Utils::PathString::join(
{directoryPath, "/", Utils::SmallString{typeInfo}});
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath});
+ tracer.tick("append qmltypes source id"_t, keyValue("source id", sourceId));
watchedSourceIds.qmltypesSourceIds.push_back(sourceId);
addDependencies(package.moduleDependencies,
sourceId,
joinImports(qmldirDependencies, qmldirImports),
- m_projectStorage);
+ m_projectStorage,
+ "append module dependency"_t,
+ tracer);
+
+ tracer.tick("append module dependenct source source id"_t, keyValue("source id", sourceId));
package.updatedModuleDependencySourceIds.push_back(sourceId);
- auto projectData = package.projectDatas.emplace_back(
+ const auto &directoryInfo = package.directoryInfos.emplace_back(
directorySourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes);
+ tracer.tick("append project data"_t, keyValue("source id", sourceId));
- parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds);
+ parseTypeInfo(directoryInfo, qmltypesPath, package, notUpdatedSourceIds);
}
}
-void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
- Storage::Synchronization::SynchronizationPackage &package,
- NotUpdatedSourceIds &notUpdatedSourceIds,
- WatchedSourceIdsIds &watchedSourceIds)
+void ProjectStorageUpdater::parseDirectoryInfos(
+ const Storage::Synchronization::DirectoryInfos &directoryInfos,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIds)
{
- for (const Storage::Synchronization::ProjectData &projectData : projectDatas) {
- switch (projectData.fileType) {
+ NanotraceHR::Tracer tracer{"parse project datas"_t, category()};
+
+ for (const Storage::Synchronization::DirectoryInfo &directoryInfo : directoryInfos) {
+ switch (directoryInfo.fileType) {
case Storage::Synchronization::FileType::QmlTypes: {
- watchedSourceIds.qmltypesSourceIds.push_back(projectData.sourceId);
+ watchedSourceIds.qmltypesSourceIds.push_back(directoryInfo.sourceId);
- auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
- parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds);
+ auto qmltypesPath = m_pathCache.sourcePath(directoryInfo.sourceId);
+ parseTypeInfo(directoryInfo, qmltypesPath, package, notUpdatedSourceIds);
break;
}
case Storage::Synchronization::FileType::QmlDocument: {
- watchedSourceIds.qmlSourceIds.push_back(projectData.sourceId);
+ watchedSourceIds.qmlSourceIds.push_back(directoryInfo.sourceId);
- parseQmlComponent(projectData.sourceId, package, notUpdatedSourceIds);
+ parseQmlComponent(directoryInfo.sourceId, package, notUpdatedSourceIds);
+ break;
}
+ case Storage::Synchronization::FileType::Directory:
+ break;
}
}
}
-auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
+auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::DirectoryInfo &directoryInfo,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds) -> FileState
{
- auto state = fileState(projectData.sourceId, package, notUpdatedSourceIds);
+ NanotraceHR::Tracer tracer{"parse type info"_t,
+ category(),
+ keyValue("qmltypes path", qmltypesPath)};
+
+ auto state = fileState(directoryInfo.sourceId, package, notUpdatedSourceIds);
switch (state) {
case FileState::Changed: {
- package.updatedSourceIds.push_back(projectData.sourceId);
+ tracer.tick("append updated source ids"_t, keyValue("source id", directoryInfo.sourceId));
+ package.updatedSourceIds.push_back(directoryInfo.sourceId);
const auto content = m_fileSystem.contentAsQString(QString{qmltypesPath});
- m_qmlTypesParser.parse(content, package.imports, package.types, projectData);
+ m_qmlTypesParser.parse(content, package.imports, package.types, directoryInfo);
break;
}
case FileState::NotChanged: {
- notUpdatedSourceIds.sourceIds.push_back(projectData.sourceId);
+ tracer.tick("append not updated source ids"_t, keyValue("source id", directoryInfo.sourceId));
+ notUpdatedSourceIds.sourceIds.push_back(directoryInfo.sourceId);
break;
}
case FileState::NotExists:
throw CannotParseQmlTypesFile{};
- break;
}
+ tracer.end(keyValue("state", state));
+
return state;
}
@@ -617,6 +1063,14 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
WatchedSourceIdsIds &watchedSourceIds,
FileState qmldirState)
{
+ NanotraceHR::Tracer tracer{"parse qml component"_t,
+ category(),
+ keyValue("relative file path", relativeFilePath),
+ keyValue("directory path", directoryPath),
+ keyValue("exported types", exportedTypes),
+ keyValue("directory source id", directorySourceId),
+ keyValue("qmldir state", qmldirState)};
+
if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end())
return;
@@ -626,16 +1080,18 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
Storage::Synchronization::Type type;
auto state = fileState(sourceId, package, notUpdatedSourceIds);
+ tracer.tick("append watched qml source id"_t, keyValue("source id", sourceId));
watchedSourceIds.qmlSourceIds.push_back(sourceId);
switch (state) {
case FileState::NotChanged:
if (qmldirState == FileState::NotExists) {
+ tracer.tick("append not updated source id"_t, keyValue("source id", sourceId));
notUpdatedSourceIds.sourceIds.emplace_back(sourceId);
- package.projectDatas.emplace_back(directorySourceId,
- sourceId,
- ModuleId{},
- Storage::Synchronization::FileType::QmlDocument);
+
+ const auto &directoryInfo = package.directoryInfos.emplace_back(
+ directorySourceId, sourceId, ModuleId{}, Storage::Synchronization::FileType::QmlDocument);
+ tracer.tick("append project data"_t, keyValue("project data", directoryInfo));
return;
}
@@ -649,11 +1105,11 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
break;
}
- package.projectDatas.emplace_back(directorySourceId,
- sourceId,
- ModuleId{},
- Storage::Synchronization::FileType::QmlDocument);
+ const auto &directoryInfo = package.directoryInfos.emplace_back(
+ directorySourceId, sourceId, ModuleId{}, Storage::Synchronization::FileType::QmlDocument);
+ tracer.tick("append project data"_t, keyValue("project data", directoryInfo));
+ tracer.tick("append updated source id"_t, keyValue("source id", sourceId));
package.updatedSourceIds.push_back(sourceId);
type.typeName = SourcePath{qmlFilePath}.name();
@@ -661,6 +1117,8 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
type.sourceId = sourceId;
type.exportedTypes = std::move(exportedTypes);
+ tracer.end(keyValue("type", type));
+
package.types.push_back(std::move(type));
}
@@ -668,10 +1126,13 @@ void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds)
{
+ NanotraceHR::Tracer tracer{"parse qml component"_t, category(), keyValue("source id", sourceId)};
+
auto state = fileState(sourceId, package, notUpdatedSourceIds);
if (state == FileState::NotChanged)
return;
+ tracer.tick("append updated source id"_t, keyValue("source id", sourceId));
package.updatedSourceIds.push_back(sourceId);
if (state == FileState::NotExists)
@@ -687,6 +1148,8 @@ void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId,
type.sourceId = sourceId;
type.changeLevel = Storage::Synchronization::ChangeLevel::ExcludeExportedTypes;
+ tracer.end(keyValue("type", type));
+
package.types.push_back(std::move(type));
}
@@ -733,6 +1196,12 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
WatchedSourceIdsIds &watchedSourceIdsIds,
FileState qmldirState)
{
+ NanotraceHR::Tracer tracer{"parse qml components"_t,
+ category(),
+ keyValue("directory source id", directorySourceId),
+ keyValue("directory id", directoryId),
+ keyValue("qmldir state", qmldirState)};
+
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return first.fileName < second.fileName;
});
@@ -760,22 +1229,37 @@ ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds) const
{
+ NanotraceHR::Tracer tracer{"update property editor paths"_t,
+ category(),
+ keyValue("source id", sourceId)};
+
auto currentFileStatus = m_fileStatusCache.find(sourceId);
if (!currentFileStatus.isValid()) {
+ tracer.tick("append updated file status source id"_t, keyValue("source id", sourceId));
package.updatedFileStatusSourceIds.push_back(sourceId);
+
+ tracer.end(keyValue("state", FileState::NotExists));
return FileState::NotExists;
}
auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId);
if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) {
+ tracer.tick("append file status"_t, keyValue("file status", sourceId));
package.fileStatuses.push_back(currentFileStatus);
+
+ tracer.tick("append updated file status source id"_t, keyValue("source id", sourceId));
package.updatedFileStatusSourceIds.push_back(sourceId);
+
+ tracer.end(keyValue("state", FileState::Changed));
return FileState::Changed;
}
+ tracer.tick("append not updated file status source id"_t, keyValue("source id", sourceId));
notUpdatedSourceIds.fileStatusSourceIds.push_back(sourceId);
+
+ tracer.end(keyValue("state", FileState::NotChanged));
return FileState::NotChanged;
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
index 187a2219d0..baecbd6b11 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
@@ -11,10 +11,15 @@
#include "projectstoragetypes.h"
#include "sourcepath.h"
+#include <modelfwd.h>
+
+#include <tracing/qmldesignertracing.h>
+
#include <qmljs/parser/qmldirparser_p.h>
#include <QStringList>
+#include <map>
#include <vector>
namespace Sqlite {
@@ -27,7 +32,6 @@ class ProjectStorageInterface;
template<typename ProjectStorage, typename Mutex>
class SourcePathCache;
class FileStatusCache;
-template<typename Database>
class ProjectStorage;
class QmlDocumentParserInterface;
class QmlTypesParserInterface;
@@ -35,10 +39,10 @@ class QmlTypesParserInterface;
class ProjectStorageUpdater final : public ProjectStoragePathWatcherNotifierInterface
{
public:
- using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
+ using PathCache = SourcePathCache<ProjectStorage, NonLockingMutex>;
ProjectStorageUpdater(FileSystemInterface &fileSystem,
- ProjectStorageInterface &projectStorage,
+ ProjectStorageType &projectStorage,
FileStatusCache &fileStatusCache,
PathCache &pathCache,
QmlDocumentParserInterface &qmlDocumentParser,
@@ -57,7 +61,8 @@ public:
void update(QStringList directories,
QStringList qmlTypesPaths,
- const QString &propertyEditorResourcesPath);
+ const QString &propertyEditorResourcesPath,
+ const QStringList &typeAnnotationPaths);
void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) override;
void pathsChanged(const SourceIds &filePathIds) override;
@@ -138,22 +143,54 @@ private:
WatchedSourceIdsIds &watchedSourceIdsIds);
void updateDirectory(const Utils::PathString &directory,
+ const SourceContextIds &subdirecoriesToIgnore,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds,
WatchedSourceIdsIds &watchedSourceIdsIds);
+ void updateSubdirectories(const Utils::PathString &directory,
+ SourceId directorySourceId,
+ FileState directoryFileState,
+ const SourceContextIds &subdirecoriesToIgnore,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
+ void updateDirectoryChanged(std::string_view directoryPath,
+ FileState qmldirState,
+ SourcePath qmldirSourcePath,
+ SourceId qmldirSourceId,
+ SourceId directorySourceId,
+ SourceContextId directoryId,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds,
+ ProjectStorageTracing::Category::TracerType &tracer);
void updatePropertyEditorPaths(const QString &propertyEditorResourcesPath,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds);
- void updateTypeAnnotations(const QString &propertyEditorResourcesPath,
+ void updateTypeAnnotations(const QString &directoryPath,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary);
+ void updateTypeAnnotationDirectories(Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ std::map<SourceId, SmallSourceIds<16>> &updatedSourceIdsDictonary);
+ void updateTypeAnnotations(const QStringList &directoryPath,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds);
+ void updateTypeAnnotation(const QString &directoryPath,
+ const QString &filePath,
+ SourceId sourceId,
+ SourceId directorySourceId,
+ Storage::Synchronization::SynchronizationPackage &package);
void updatePropertyEditorPath(const QString &path,
Storage::Synchronization::SynchronizationPackage &package,
- SourceId directorySourceId);
+ SourceId directorySourceId,
+ long long pathOffset);
void updatePropertyEditorFilePath(const QString &filePath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceId directorySourceId);
+ SourceId directorySourceId,
+ long long pathOffset);
void parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports,
@@ -163,11 +200,11 @@ private:
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds,
WatchedSourceIdsIds &watchedSourceIdsIds);
- void parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
- Storage::Synchronization::SynchronizationPackage &package,
- NotUpdatedSourceIds &notUpdatedSourceIds,
- WatchedSourceIdsIds &watchedSourceIdsIds);
- FileState parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
+ void parseDirectoryInfos(const Storage::Synchronization::DirectoryInfos &directoryInfos,
+ Storage::Synchronization::SynchronizationPackage &package,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
+ FileState parseTypeInfo(const Storage::Synchronization::DirectoryInfo &directoryInfo,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
NotUpdatedSourceIds &notUpdatedSourceIds);
@@ -197,7 +234,7 @@ private:
private:
std::vector<IdPaths> m_changedIdPaths;
FileSystemInterface &m_fileSystem;
- ProjectStorageInterface &m_projectStorage;
+ ProjectStorageType &m_projectStorage;
FileStatusCache &m_fileStatusCache;
PathCache &m_pathCache;
QmlDocumentParserInterface &m_qmlDocumentParser;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
index f9eb8080f7..4338da62ce 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
@@ -10,6 +10,8 @@
#include <sqlitedatabase.h>
+#include <tracing/qmldesignertracing.h>
+
#ifdef QDS_BUILD_QMLPARSER
#include <private/qqmldomtop_p.h>
#endif
@@ -21,6 +23,10 @@ namespace QmlDesigner {
#ifdef QDS_BUILD_QMLPARSER
+constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory;
+using NanotraceHR::keyValue;
+using Tracer = ProjectStorageTracing::Category::TracerType;
+
namespace QmlDom = QQmlJS::Dom;
namespace Synchronization = Storage::Synchronization;
@@ -60,23 +66,32 @@ Storage::Import createImport(const QmlDom::Import &qmlImport,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
+ using Storage::ModuleKind;
using QmlUriKind = QQmlJS::Dom::QmlUri::Kind;
auto &&uri = qmlImport.uri;
- if (uri.kind() == QmlUriKind::RelativePath) {
+ switch (uri.kind()) {
+ case QmlUriKind::AbsolutePath:
+ case QmlUriKind::DirectoryUrl: {
+ auto moduleId = storage.moduleId(Utils::PathString{uri.toString()}, ModuleKind::PathLibrary);
+ return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
+ }
+ case QmlUriKind::RelativePath: {
auto path = createNormalizedPath(directoryPath, uri.localPath());
- auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath()));
+ auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath()),
+ ModuleKind::PathLibrary);
return Storage::Import(moduleId, Storage::Version{}, sourceId);
}
-
- if (uri.kind() == QmlUriKind::ModuleUri) {
- auto moduleId = storage.moduleId(Utils::PathString{uri.moduleUri()});
+ case QmlUriKind::ModuleUri: {
+ auto moduleId = storage.moduleId(Utils::PathString{uri.moduleUri()}, ModuleKind::QmlLibrary);
return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
}
+ case QmlUriKind::Invalid:
+ return Storage::Import{};
+ }
- auto moduleId = storage.moduleId(Utils::PathString{uri.toString()});
- return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
+ return Storage::Import{};
}
QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports,
@@ -84,6 +99,11 @@ QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
+ NanotraceHR::Tracer tracer{"create qualified imports"_t,
+ category(),
+ keyValue("sourceId", sourceId),
+ keyValue("directoryPath", directoryPath)};
+
QualifiedImports qualifiedImports;
for (const QmlDom::Import &qmlImport : qmlImports) {
@@ -92,6 +112,8 @@ QualifiedImports createQualifiedImports(const QList<QmlDom::Import> &qmlImports,
createImport(qmlImport, sourceId, directoryPath, storage));
}
+ tracer.end(keyValue("qualified imports", qualifiedImports));
+
return qualifiedImports;
}
@@ -109,11 +131,13 @@ void addImports(Storage::Imports &imports,
}
}
- auto localDirectoryModuleId = storage.moduleId(directoryPath);
+ using Storage::ModuleKind;
+
+ auto localDirectoryModuleId = storage.moduleId(directoryPath, ModuleKind::PathLibrary);
imports.emplace_back(localDirectoryModuleId, Storage::Version{}, sourceId);
++importCount;
- auto qmlModuleId = storage.moduleId("QML");
+ auto qmlModuleId = storage.moduleId("QML", ModuleKind::QmlLibrary);
imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId);
++importCount;
@@ -280,6 +304,11 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon
SourceId sourceId,
Utils::SmallStringView directoryPath)
{
+ NanotraceHR::Tracer tracer{"qml document parser parse"_t,
+ category(),
+ keyValue("sourceId", sourceId),
+ keyValue("directoryPath", directoryPath)};
+
Storage::Synchronization::Type type;
using Option = QmlDom::DomEnvironment::Option;
@@ -335,7 +364,7 @@ Storage::Synchronization::Type QmlDocumentParser::parse(const QString &sourceCon
m_storage);
type.prototype = createImportedTypeName(qmlObject.name(), qualifiedImports);
-
+ type.defaultPropertyName = qmlObject.localDefaultPropertyName();
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
addPropertyDeclarations(type, qmlObject, qualifiedImports, file);
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
index b8ab4ec4b1..1b494a2f69 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
@@ -15,7 +15,7 @@ class SourcePathCache;
class QmlDocumentParser final : public QmlDocumentParserInterface
{
public:
- using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
+ using ProjectStorage = QmlDesigner::ProjectStorage;
using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
#ifdef QDS_BUILD_QMLPARSER
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
index 3768535299..b3ec4f0024 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
@@ -5,8 +5,12 @@
#include "projectstorage.h"
+#include <tracing/qmldesignertracing.h>
+
#include <sqlitedatabase.h>
+#include <utils/span.h>
+
#ifdef QDS_BUILD_QMLPARSER
#include <private/qqmldomtop_p.h>
#include <private/qqmljstypedescriptionreader_p.h>
@@ -21,6 +25,10 @@ namespace QmlDesigner {
#ifdef QDS_BUILD_QMLPARSER
+constexpr auto category = ProjectStorageTracing::projectStorageUpdaterCategory;
+using NanotraceHR::keyValue;
+using Tracer = ProjectStorageTracing::Category::TracerType;
+using Storage::ModuleKind;
namespace QmlDom = QQmlJS::Dom;
namespace {
@@ -31,6 +39,8 @@ using Storage::TypeNameString;
ComponentWithoutNamespaces createComponentNameWithoutNamespaces(const QList<QQmlJSExportedScope> &objects)
{
+ NanotraceHR::Tracer tracer{"parse qmltypes file"_t, category()};
+
ComponentWithoutNamespaces componentWithoutNamespaces;
for (const auto &object : objects) {
@@ -46,23 +56,24 @@ ComponentWithoutNamespaces createComponentNameWithoutNamespaces(const QList<QQml
name);
}
+ tracer.end(keyValue("components without namespace", componentWithoutNamespaces));
+
return componentWithoutNamespaces;
}
-void appendImports(Storage::Imports &imports,
- const QString &dependency,
- SourceId sourceId,
- QmlTypesParser::ProjectStorage &storage)
+const Storage::Import &appendImports(Storage::Imports &imports,
+ const QString &dependency,
+ SourceId sourceId,
+ QmlTypesParser::ProjectStorage &storage)
{
auto spaceFound = std::find_if(dependency.begin(), dependency.end(), [](QChar c) {
return c.isSpace();
});
Utils::PathString moduleName{QStringView(dependency.begin(), spaceFound)};
- moduleName.append("-cppnative");
- ModuleId cppModuleId = storage.moduleId(moduleName);
+ ModuleId cppModuleId = storage.moduleId(moduleName, ModuleKind::CppLibrary);
- imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
+ return imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
}
void addImports(Storage::Imports &imports,
@@ -71,13 +82,26 @@ void addImports(Storage::Imports &imports,
QmlTypesParser::ProjectStorage &storage,
ModuleId cppModuleId)
{
- for (const QString &dependency : dependencies)
- appendImports(imports, dependency, sourceId, storage);
+ NanotraceHR::Tracer tracer{
+ "add imports"_t,
+ category(),
+ keyValue("source id", sourceId),
+ keyValue("module id", cppModuleId),
+ };
+
+ for (const QString &dependency : dependencies) {
+ const auto &import = appendImports(imports, dependency, sourceId, storage);
+ tracer.tick("append import"_t, keyValue("import", import), keyValue("dependency", dependency));
+ }
- imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
+ const auto &import = imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
+ tracer.tick("append import"_t, keyValue("import", import));
- if (ModuleId qmlCppModuleId = storage.moduleId("QML-cppnative"); cppModuleId != qmlCppModuleId)
- imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId);
+ if (ModuleId qmlCppModuleId = storage.moduleId("QML", ModuleKind::CppLibrary);
+ cppModuleId != qmlCppModuleId) {
+ const auto &import = imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId);
+ tracer.tick("append import"_t, keyValue("import", import));
+ }
}
Storage::TypeTraits createAccessTypeTraits(QQmlJSScope::AccessSemantics accessSematics)
@@ -121,7 +145,8 @@ Storage::Synchronization::ExportedTypes createExports(const QList<QQmlJSScope::E
for (const QQmlJSScope::Export &qmlExport : qmlExports) {
TypeNameString exportedTypeName{qmlExport.type()};
- exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()}),
+ exportedTypes.emplace_back(storage.moduleId(Utils::SmallString{qmlExport.package()},
+ ModuleKind::QmlLibrary),
std::move(exportedTypeName),
createVersion(qmlExport.version()));
}
@@ -412,6 +437,11 @@ void addType(Storage::Synchronization::Types &types,
QmlTypesParser::ProjectStorage &storage,
const ComponentWithoutNamespaces &componentNameWithoutNamespace)
{
+ NanotraceHR::Tracer tracer{"add type"_t,
+ category(),
+ keyValue("source id", sourceId),
+ keyValue("module id", cppModuleId)};
+
const auto &component = *exportScope.scope;
auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(
@@ -421,7 +451,7 @@ void addType(Storage::Synchronization::Types &types,
auto exports = exportScope.exports;
auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations);
- types.emplace_back(
+ const auto &type = types.emplace_back(
Utils::SmallStringView{typeName},
Storage::Synchronization::ImportedType{TypeNameString{component.baseTypeName()}},
Storage::Synchronization::ImportedType{TypeNameString{component.extensionTypeName()}},
@@ -431,24 +461,61 @@ void addType(Storage::Synchronization::Types &types,
createProperties(component.ownProperties(), enumerationTypes, componentNameWithoutNamespace),
std::move(functionsDeclarations),
std::move(signalDeclarations),
- createEnumeration(enumerations));
+ createEnumeration(enumerations),
+ Storage::Synchronization::ChangeLevel::Full,
+ Utils::SmallString{component.ownDefaultPropertyName()});
+ tracer.end(keyValue("type", type));
+}
+
+using namespace Qt::StringLiterals;
+
+constexpr auto skipLists = std::make_tuple(
+ std::pair{std::pair{"QtQuick.Templates"_sv, ModuleKind::CppLibrary}, std::array{"QQuickItem"_L1}});
+
+Utils::span<const QLatin1StringView> getSkipList(const Storage::Module &module)
+{
+ static constexpr Utils::span<const QLatin1StringView> emptySkipList;
+ auto currentSkipList = emptySkipList;
+
+ std::apply(
+ [&](const auto &entry) {
+ if (entry.first.first == module.name && entry.first.second == module.kind)
+ currentSkipList = entry.second;
+ },
+ skipLists);
+
+ return currentSkipList;
+}
+
+bool skipType(const QQmlJSExportedScope &object, Utils::span<const QLatin1StringView> skipList)
+{
+ return std::any_of(skipList.begin(), skipList.end(), [&](const QLatin1StringView skip) {
+ return object.scope->internalName() == skip;
+ });
}
void addTypes(Storage::Synchronization::Types &types,
- const Storage::Synchronization::ProjectData &projectData,
+ const Storage::Synchronization::DirectoryInfo &directoryInfo,
const QList<QQmlJSExportedScope> &objects,
QmlTypesParser::ProjectStorage &storage,
const ComponentWithoutNamespaces &componentNameWithoutNamespaces)
{
+ NanotraceHR::Tracer tracer{"add types"_t, category()};
types.reserve(Utils::usize(objects) + types.size());
- for (const auto &object : objects)
+ const auto skipList = getSkipList(storage.module(directoryInfo.moduleId));
+
+ for (const auto &object : objects) {
+ if (skipType(object, skipList))
+ continue;
+
addType(types,
- projectData.sourceId,
- projectData.moduleId,
+ directoryInfo.sourceId,
+ directoryInfo.moduleId,
object,
storage,
componentNameWithoutNamespaces);
+ }
}
} // namespace
@@ -456,8 +523,10 @@ void addTypes(Storage::Synchronization::Types &types,
void QmlTypesParser::parse(const QString &sourceContent,
Storage::Imports &imports,
Storage::Synchronization::Types &types,
- const Storage::Synchronization::ProjectData &projectData)
+ const Storage::Synchronization::DirectoryInfo &directoryInfo)
{
+ NanotraceHR::Tracer tracer{"qmltypes parser parse"_t, category()};
+
QQmlJSTypeDescriptionReader reader({}, sourceContent);
QList<QQmlJSExportedScope> components;
QStringList dependencies;
@@ -467,8 +536,8 @@ void QmlTypesParser::parse(const QString &sourceContent,
auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components);
- addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId);
- addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces);
+ addImports(imports, directoryInfo.sourceId, dependencies, m_storage, directoryInfo.moduleId);
+ addTypes(types, directoryInfo, components, m_storage, componentNameWithoutNamespaces);
}
#else
@@ -476,7 +545,7 @@ void QmlTypesParser::parse(const QString &sourceContent,
void QmlTypesParser::parse([[maybe_unused]] const QString &sourceContent,
[[maybe_unused]] Storage::Imports &imports,
[[maybe_unused]] Storage::Synchronization::Types &types,
- [[maybe_unused]] const Storage::Synchronization::ProjectData &projectData)
+ [[maybe_unused]] const Storage::Synchronization::DirectoryInfo &directoryInfo)
{}
#endif
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
index 7c41925f30..c73a429f91 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
@@ -4,6 +4,7 @@
#pragma once
#include "nonlockingmutex.h"
+#include "projectstoragefwd.h"
#include "qmltypesparserinterface.h"
namespace Sqlite {
@@ -12,17 +13,13 @@ class Database;
namespace QmlDesigner {
-template<typename Database>
-class ProjectStorage;
-
template<typename ProjectStorage, typename Mutex>
class SourcePathCache;
class QmlTypesParser final : public QmlTypesParserInterface
{
public:
- using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
-
+ using ProjectStorage = QmlDesigner::ProjectStorage;
#ifdef QDS_BUILD_QMLPARSER
QmlTypesParser(ProjectStorage &storage)
: m_storage{storage}
@@ -34,7 +31,7 @@ public:
void parse(const QString &sourceContent,
Storage::Imports &imports,
Storage::Synchronization::Types &types,
- const Storage::Synchronization::ProjectData &projectData) override;
+ const Storage::Synchronization::DirectoryInfo &directoryInfo) override;
private:
#ifdef QDS_BUILD_QMLPARSER
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h
index cdc7cd54d7..c0880cf5c6 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparserinterface.h
@@ -15,7 +15,7 @@ public:
virtual void parse(const QString &sourceContent,
Storage::Imports &imports,
Storage::Synchronization::Types &types,
- const Storage::Synchronization::ProjectData &projectData)
+ const Storage::Synchronization::DirectoryInfo &directoryInfo)
= 0;
protected:
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h b/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h
index 837e58d48a..fa550a4d52 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/sourcepath.h
@@ -7,6 +7,8 @@
#include <utils/smallstring.h>
+#include <QVarLengthArray>
+
namespace QmlDesigner {
class SourcePath : public Utils::PathString
@@ -117,10 +119,17 @@ public:
std::ptrdiff_t slashIndex() const { return m_slashIndex; }
+ template<typename String>
+ friend void convertToString(String &string, const SourcePath &path)
+ {
+ convertToString(string, path.toStringView());
+ }
+
private:
std::ptrdiff_t m_slashIndex = -1;
};
using SourcePaths = std::vector<SourcePath>;
-
+template<std::size_t size>
+using SmallSourcePaths = QVarLengthArray<SourcePath, size>;
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h
index 5feaf30d00..1ef8ba7f21 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/sourcepathcachetypes.h
@@ -125,4 +125,6 @@ public:
SourceContextId sourceContextId;
};
+using SourceNameAndSourceContextIds = std::vector<SourceNameAndSourceContextId>;
+
} // namespace QmlDesigner::Cache
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h b/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h
index 85c6147d2c..32ecb1c3f7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/storagecache.h
@@ -313,7 +313,7 @@ private:
return entries.end();
}
- auto value = *found;
+ const auto &value = *found;
if (value == view) {
return found;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp
index b829e9db36..71eba94966 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.cpp
@@ -27,11 +27,11 @@ constexpr auto propertyElementName = "Property"_L1;
constexpr auto extraFileElementName = "ExtraFile"_L1;
} // namespace
-Synchronization::TypeAnnotations TypeAnnotationReader::parseTypeAnnotation(const QString &content,
- const QString &directoryPath,
- SourceId sourceId)
+Synchronization::TypeAnnotations TypeAnnotationReader::parseTypeAnnotation(
+ const QString &content, const QString &directoryPath, SourceId sourceId, SourceId directorySourceId)
{
m_sourceId = sourceId;
+ m_directorySourceId = directorySourceId;
m_directoryPath = directoryPath;
m_parserState = ParsingDocument;
if (!SimpleAbstractStreamReader::readFromSource(content)) {
@@ -178,8 +178,15 @@ TypeAnnotationReader::ParserSate TypeAnnotationReader::readDocument(const QStrin
TypeAnnotationReader::ParserSate TypeAnnotationReader::readMetaInfoRootElement(const QString &name)
{
if (name == typeElementName) {
- m_typeAnnotations.emplace_back(m_sourceId);
+ auto &annotation = m_typeAnnotations.emplace_back(m_sourceId, m_directorySourceId);
+ annotation.traits.canBeDroppedInFormEditor = FlagIs::True;
+ annotation.traits.canBeDroppedInNavigator = FlagIs::True;
+ annotation.traits.isMovable = FlagIs::True;
+ annotation.traits.isResizable = FlagIs::True;
+ annotation.traits.hasFormEditorItem = FlagIs::True;
+ annotation.traits.visibleInLibrary = FlagIs::True;
m_itemLibraryEntries = json::array();
+
return ParsingType;
} else {
addErrorInvalidType(name);
@@ -258,7 +265,8 @@ void TypeAnnotationReader::readTypeProperty(QStringView name, const QVariant &va
auto [moduleName, typeName] = decomposeTypePath(fullTypeName);
m_typeAnnotations.back().typeName = typeName;
- m_typeAnnotations.back().moduleId = m_projectStorage.moduleId(moduleName);
+ m_typeAnnotations.back().moduleId = m_projectStorage.moduleId(moduleName,
+ ModuleKind::QmlLibrary);
} else if (name == "icon"_L1) {
m_typeAnnotations.back().iconPath = absoluteFilePathForDocument(value.toString());
@@ -277,7 +285,7 @@ void TypeAnnotationReader::readItemLibraryEntryProperty(QStringView name, const
} else if (name == "category"_L1) {
m_itemLibraryEntries.back()["category"] = value;
} else if (name == "libraryIcon"_L1) {
- m_itemLibraryEntries.back()["iconPath"] = value;
+ m_itemLibraryEntries.back()["iconPath"] = absoluteFilePathForDocument(variant.toString());
} else if (name == "version"_L1) {
// setVersion(value.toString());
} else if (name == "requiredImport"_L1) {
@@ -304,7 +312,7 @@ QString deEscape(const QString &value)
QVariant deEscapeVariant(const QVariant &value)
{
- if (value.typeId() == QVariant::String)
+ if (value.typeId() == QMetaType::QString)
return deEscape(value.toString());
return value;
}
@@ -427,8 +435,8 @@ void TypeAnnotationReader::setVersion(const QString &versionNumber)
int minor = 0;
if (!versionNumber.isEmpty()) {
- int val;
- bool ok;
+ int val = -1;
+ bool ok = false;
if (versionNumber.contains('.'_L1)) {
val = versionNumber.split('.'_L1).constFirst().toInt(&ok);
major = ok ? val : major;
@@ -459,9 +467,9 @@ using json = nlohmann::json;
out = json::array({});
out.push_back(property.name);
out.push_back(property.type);
- if (property.value.type() == QVariant::String)
+ if (property.value.typeId() == QMetaType::QString)
out.push_back(Utils::PathString{property.value.toString()});
- else if (property.value.type() == QVariant::Int || property.value.type() == QVariant::LongLong)
+ else if (property.value.typeId() == QMetaType::Int || property.value.typeId() == QMetaType::LongLong)
out.push_back(property.value.toLongLong());
else
out.push_back(property.value.toDouble());
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h
index 9332d5bed9..a320493ee2 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/typeannotationreader.h
@@ -49,7 +49,8 @@ public:
Synchronization::TypeAnnotations parseTypeAnnotation(const QString &content,
const QString &directoryPath,
- SourceId sourceId);
+ SourceId sourceId,
+ SourceId directorySourceId);
QStringList errors();
@@ -124,6 +125,7 @@ private:
json m_itemLibraryEntries;
Property m_currentProperty;
SourceId m_sourceId;
+ SourceId m_directorySourceId;
};
} // namespace QmlDesigner::Storage
diff --git a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp
index d49c6156a6..cbe7b0ec38 100644
--- a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp
+++ b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.cpp
@@ -3,40 +3,48 @@
#include "qmldesignertracing.h"
+#include <sqlitebasestatement.h>
+
namespace QmlDesigner {
+
+using namespace NanotraceHR::Literals;
+
namespace Tracing {
namespace {
using TraceFile = NanotraceHR::TraceFile<tracingStatus()>;
-TraceFile &traceFile()
+auto &traceFile()
{
- static TraceFile traceFile{"qml_designer.json"};
- return traceFile;
+ if constexpr (std::is_same_v<Sqlite::TraceFile, TraceFile>) {
+ return Sqlite::traceFile();
+ } else {
+ static TraceFile traceFile{"tracing.json"};
+ return traceFile;
+ }
}
} // namespace
EventQueue &eventQueue()
{
- thread_local NanotraceHR::EventQueueData<NanotraceHR::StringViewTraceEvent, 10000, tracingStatus()>
- stringViewEventQueueData(traceFile());
+ thread_local NanotraceHR::EventQueue<NanotraceHR::StringViewTraceEvent, tracingStatus()>
+ stringViewEventQueue(traceFile());
- return stringViewEventQueueData;
+ return stringViewEventQueue;
}
EventQueueWithStringArguments &eventQueueWithStringArguments()
{
- thread_local NanotraceHR::
- EventQueueData<NanotraceHR::StringViewWithStringArgumentsTraceEvent, 1000, tracingStatus()>
- stringViewWithStringArgumentsEventQueueData(traceFile());
+ thread_local NanotraceHR::EventQueue<NanotraceHR::StringViewWithStringArgumentsTraceEvent, tracingStatus()>
+ stringViewWithStringArgumentsEventQueue(traceFile());
- return stringViewWithStringArgumentsEventQueueData;
+ return stringViewWithStringArgumentsEventQueue;
}
StringEventQueue &stringEventQueue()
{
- thread_local NanotraceHR::EventQueueData<NanotraceHR::StringTraceEvent, 1000, tracingStatus()> eventQueue(
+ thread_local NanotraceHR::EventQueue<NanotraceHR::StringTraceEvent, tracingStatus()> eventQueue(
traceFile());
return eventQueue;
@@ -46,7 +54,6 @@ StringEventQueue &stringEventQueue()
namespace ModelTracing {
namespace {
-using namespace NanotraceHR::Literals;
thread_local Category category_{"model"_t, Tracing::stringEventQueue(), category};
@@ -58,4 +65,36 @@ Category &category()
}
} // namespace ModelTracing
+
+namespace ProjectStorageTracing {
+
+Category &projectStorageCategory()
+{
+ thread_local Category category{"project storage"_t,
+ Tracing::eventQueueWithStringArguments(),
+ projectStorageCategory};
+
+ return category;
+}
+
+Category &projectStorageUpdaterCategory()
+{
+ thread_local Category category{"project storage updater"_t,
+ Tracing::eventQueueWithStringArguments(),
+ projectStorageCategory};
+
+ return category;
+}
+
+} // namespace ProjectStorageTracing
+
+namespace MetaInfoTracing {
+Category &category()
+{
+ thread_local Category category_{"meta info"_t, Tracing::eventQueueWithStringArguments(), category};
+
+ return category_;
+}
+} // namespace MetaInfoTracing
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h
index 31058260d6..899ceb6cd2 100644
--- a/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h
+++ b/src/plugins/qmldesigner/designercore/tracing/qmldesignertracing.h
@@ -44,4 +44,38 @@ using AsynchronousToken = Category::AsynchronousTokenType;
[[gnu::pure]] QMLDESIGNERCORE_EXPORT Category &category();
} // namespace ModelTracing
+
+namespace ProjectStorageTracing {
+constexpr NanotraceHR::Tracing projectStorageTracingStatus()
+{
+#ifdef ENABLE_PROJECT_STORAGE_TRACING
+ return NanotraceHR::Tracing::IsEnabled;
+#else
+ return NanotraceHR::Tracing::IsDisabled;
+#endif
+}
+
+using Category = NanotraceHR::StringViewWithStringArgumentsCategory<projectStorageTracingStatus()>;
+
+[[gnu::pure]] Category &projectStorageCategory();
+
+[[gnu::pure]] Category &projectStorageUpdaterCategory();
+
+} // namespace ProjectStorageTracing
+
+namespace MetaInfoTracing {
+constexpr NanotraceHR::Tracing tracingStatus()
+{
+#ifdef ENABLE_METAINFO_TRACING
+ return NanotraceHR::Tracing::IsEnabled;
+#else
+ return NanotraceHR::Tracing::IsDisabled;
+#endif
+}
+
+using Category = NanotraceHR::StringViewWithStringArgumentsCategory<tracingStatus()>;
+
+[[gnu::pure]] Category &category();
+
+} // namespace MetaInfoTracing
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/uniquename.cpp b/src/plugins/qmldesigner/designercore/uniquename.cpp
new file mode 100644
index 0000000000..d7506164db
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/uniquename.cpp
@@ -0,0 +1,165 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "uniquename.h"
+
+#include <utils/span.h>
+
+#include <QFileInfo>
+#include <QRegularExpression>
+
+namespace QmlDesigner::UniqueName {
+
+using namespace Qt::Literals;
+
+constexpr QLatin1StringView keywords[] {
+ "anchors"_L1, "as"_L1, "baseState"_L1,
+ "border"_L1, "bottom"_L1, "break"_L1,
+ "case"_L1, "catch"_L1, "clip"_L1,
+ "color"_L1, "continue"_L1, "data"_L1,
+ "debugger"_L1, "default"_L1, "delete"_L1,
+ "do"_L1, "else"_L1, "enabled"_L1,
+ "finally"_L1, "flow"_L1, "focus"_L1,
+ "font"_L1, "for"_L1, "function"_L1,
+ "height"_L1, "if"_L1, "import"_L1,
+ "in"_L1, "instanceof"_L1, "item"_L1,
+ "layer"_L1, "left"_L1, "margin"_L1,
+ "new"_L1, "opacity"_L1, "padding"_L1,
+ "parent"_L1, "print"_L1, "rect"_L1,
+ "return"_L1, "right"_L1, "scale"_L1,
+ "shaderInfo"_L1, "source"_L1, "sprite"_L1,
+ "spriteSequence"_L1, "state"_L1, "switch"_L1,
+ "text"_L1, "this"_L1, "throw"_L1,
+ "top"_L1, "try"_L1, "typeof"_L1,
+ "var"_L1, "visible"_L1, "void"_L1,
+ "while"_L1, "with"_L1, "x"_L1,
+ "y"_L1
+};
+
+namespace {
+
+QString toCamelCase(const QString &input)
+{
+ QString result = input.at(0).toLower();
+ bool capitalizeNext = false;
+
+ for (const QChar &c : Utils::span{input}.subspan(1)) {
+ bool isValidChar = c.isLetterOrNumber() || c == '_';
+ if (isValidChar)
+ result += capitalizeNext ? c.toUpper() : c;
+
+ capitalizeNext = !isValidChar;
+ }
+
+ return result;
+}
+
+} // namespace
+
+/**
+ * @brief Generates a unique name based on the provided name.
+ *
+ * This method iteratively generates a name by appending suffixes until a unique name is found.
+ * The uniqueness of the generated name is determined by the provided predicate function.
+ *
+ * @param name The original name to be made unique.
+ * @param predicate A function that checks if a name exists. Returns true if the name exists,
+ * false if name is unique.
+ * @return A unique name derived from the provided name.
+ */
+QString generate(const QString &name, std::function<bool(const QString &)> predicate)
+{
+ if (!predicate(name))
+ return name;
+
+ // match prefix and number (including zero padding) parts
+ static QRegularExpression rgx("(\\D*?)(\\d+)$");
+ QRegularExpressionMatch match = rgx.match(name);
+
+ QString prefix;
+ int number = 0;
+ int padding = 0;
+
+ if (match.hasMatch()) {
+ // Split the name into prefix and number
+ prefix = match.captured(1);
+ QString numberStr = match.captured(2);
+ number = numberStr.toInt();
+ padding = numberStr.size();
+ } else {
+ prefix = name;
+ }
+
+ QString nameTemplate = "%1%2";
+ QString newName;
+ do {
+ newName = nameTemplate.arg(prefix).arg(++number, padding, 10, QChar('0'));
+ } while (predicate(newName));
+
+ return newName;
+}
+
+/**
+ * @brief Generates a unique path based on the provided path. If the path belongs to a file, the
+ * filename or if it's a directory, the directory name will be adjusted to ensure uniqueness.
+ *
+ * This method appends a numerical suffix (or increment it if it exists) to the filename or
+ * directory name if necessary to make it unique.
+ *
+ * @param path The original path to be made unique.
+ * @return A unique path derived from the provided path.
+ */
+QString generatePath(const QString &path)
+{
+ // Remove the trailing slash if it exists (otherwise QFileInfo::path() returns empty)
+ QString adjustedPath = path;
+ if (adjustedPath.endsWith('/'))
+ adjustedPath.chop(1);
+
+ QFileInfo fileInfo = QFileInfo(adjustedPath);
+ QString baseName = fileInfo.baseName();
+ QString suffix = fileInfo.completeSuffix();
+ if (!suffix.isEmpty())
+ suffix.prepend('.');
+
+ QString parentDir = fileInfo.path();
+ QString pathTemplate = parentDir + "/%1" + suffix;
+
+ QString uniqueBaseName = UniqueName::generate(baseName, [&] (const QString &currName) {
+ return QFileInfo::exists(pathTemplate.arg(currName));
+ });
+
+ return pathTemplate.arg(uniqueBaseName);
+}
+
+/**
+ * @brief Generates a unique ID based on the provided id
+ *
+ * This works similar to get() with additional restrictions:
+ * - Removes non-Latin1 characters
+ * - Removes spaces
+ * - Ensures the first letter is lowercase
+ * - Converts spaces to camel case
+ * - Prepends an underscore if id starts with a number or is a reserved word
+ *
+ * @param id The original id to be made unique.
+ * @return A unique Id (when predicate() returns false)
+ */
+QString generateId(const QString &id, std::function<bool(const QString &)> predicate)
+{
+ // remove non word (non A-Z, a-z, 0-9) or space characters
+ QString newId = id.trimmed();
+
+ newId = toCamelCase(newId);
+
+ // prepend _ if starts with a digit or invalid id (such as reserved words)
+ if (newId.at(0).isDigit() || std::binary_search(std::begin(keywords), std::end(keywords), newId))
+ newId.prepend('_');
+
+ if (!predicate)
+ return newId;
+
+ return UniqueName::generate(newId, predicate);
+}
+
+} // namespace QmlDesigner::UniqueName
diff --git a/src/plugins/qmldesigner/designercore/uniquename.h b/src/plugins/qmldesigner/designercore/uniquename.h
new file mode 100644
index 0000000000..85927c4514
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/uniquename.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <qmldesignercorelib_exports.h>
+
+#include <QString>
+
+namespace QmlDesigner::UniqueName {
+
+QString generate(const QString &name, std::function<bool(const QString &)> predicate);
+QString generatePath(const QString &path);
+QMLDESIGNERCORE_EXPORT QString generateId(const QString &id,
+ std::function<bool(const QString &)> predicate = {});
+
+} // namespace QmlDesigner::UniqueName
diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp
index 43fb0d9d75..796261935a 100644
--- a/src/plugins/qmldesigner/designmodecontext.cpp
+++ b/src/plugins/qmldesigner/designmodecontext.cpp
@@ -3,7 +3,6 @@
#include "designmodecontext.h"
#include "assetslibrarywidget.h"
-#include "collectionwidget.h"
#include "designmodewidget.h"
#include "edit3dwidget.h"
#include "formeditorwidget.h"
@@ -98,15 +97,4 @@ void TextEditorContext::contextHelp(const HelpCallback &callback) const
qobject_cast<TextEditorWidget *>(m_widget)->contextHelp(callback);
}
-CollectionEditorContext::CollectionEditorContext(QWidget *widget)
- : IContext(widget)
-{
- setWidget(widget);
- setContext(Core::Context(Constants::C_QMLCOLLECTIONEDITOR, Constants::C_QT_QUICK_TOOLS_MENU));
-}
-
-void CollectionEditorContext::contextHelp(const HelpCallback &callback) const
-{
- qobject_cast<CollectionWidget *>(m_widget)->contextHelp(callback);
-}
} // namespace QmlDesigner::Internal
diff --git a/src/plugins/qmldesigner/designmodecontext.h b/src/plugins/qmldesigner/designmodecontext.h
index 12f0113d97..1d146deb7d 100644
--- a/src/plugins/qmldesigner/designmodecontext.h
+++ b/src/plugins/qmldesigner/designmodecontext.h
@@ -73,14 +73,5 @@ public:
TextEditorContext(QWidget *widget);
void contextHelp(const Core::IContext::HelpCallback &callback) const override;
};
-
-class CollectionEditorContext : public Core::IContext
-{
- Q_OBJECT
-
-public:
- CollectionEditorContext(QWidget *widget);
- void contextHelp(const Core::IContext::HelpCallback &callback) const override;
-};
} // namespace Internal
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h
index 464994b7e3..881335da75 100644
--- a/src/plugins/qmldesigner/designmodewidget.h
+++ b/src/plugins/qmldesigner/designmodewidget.h
@@ -11,7 +11,6 @@
#include <QWidget>
#include <QMainWindow>
-#include <QScopedPointer>
#include <advanceddockingsystem/dockmanager.h>
#include <annotationeditor/globalannotationeditor.h>
diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp
index fcaac762ba..92d80680a9 100644
--- a/src/plugins/qmldesigner/documentmanager.cpp
+++ b/src/plugins/qmldesigner/documentmanager.cpp
@@ -130,7 +130,7 @@ static void openComponentSourcePropertyOfLoader(const ModelNode &modelNode)
}
Core::EditorManager::openEditor(FilePath::fromString(
- componentModelNode.metaInfo().componentFileName()),
+ ModelUtils::componentFilePath(componentModelNode)),
Utils::Id(),
Core::EditorManager::DoNotMakeVisible);
}
@@ -230,7 +230,9 @@ void DocumentManager::setCurrentDesignDocument(Core::IEditor *editor)
auto found = m_designDocuments.find(editor);
if (found == m_designDocuments.end()) {
auto &inserted = m_designDocuments[editor] = std::make_unique<DesignDocument>(
- m_projectManager.projectStorageDependencies(), m_externalDependencies);
+ editor->document()->filePath().toString(),
+ m_projectManager.projectStorageDependencies(),
+ m_externalDependencies);
m_currentDesignDocument = inserted.get();
m_currentDesignDocument->setEditor(editor);
} else {
@@ -266,6 +268,11 @@ void DocumentManager::resetPossibleImports()
}
}
+const GeneratedComponentUtils &DocumentManager::generatedComponentUtils() const
+{
+ return m_generatedComponentUtils;
+}
+
bool DocumentManager::goIntoComponent(const ModelNode &modelNode)
{
QImage image = QmlDesignerPlugin::instance()->viewManager().takeFormEditorScreenshot();
@@ -537,6 +544,13 @@ Utils::FilePath DocumentManager::currentResourcePath()
if (contentFilePath.exists())
return contentFilePath;
+ const auto project = ProjectManager::startupProject();
+ const QString baseName = project->rootProjectDirectory().baseName() + "Content";
+
+ contentFilePath = resourcePath.pathAppended(baseName);
+ if (contentFilePath.exists())
+ return contentFilePath;
+
return resourcePath;
}
diff --git a/src/plugins/qmldesigner/documentmanager.h b/src/plugins/qmldesigner/documentmanager.h
index 090630e5fe..6447694339 100644
--- a/src/plugins/qmldesigner/documentmanager.h
+++ b/src/plugins/qmldesigner/documentmanager.h
@@ -5,6 +5,8 @@
#include "qmldesigner_global.h"
+#include <generatedcomponentutils.h>
+
#include <QObject>
#include <QList>
#include <QLoggingCategory>
@@ -31,6 +33,7 @@ public:
ExternalDependenciesInterface &externalDependencies)
: m_projectManager{projectManager}
, m_externalDependencies{externalDependencies}
+ , m_generatedComponentUtils(externalDependencies)
{}
void setCurrentDesignDocument(Core::IEditor *editor);
@@ -41,6 +44,8 @@ public:
void resetPossibleImports();
+ const GeneratedComponentUtils &generatedComponentUtils() const;
+
static bool goIntoComponent(const ModelNode &modelNode);
static void goIntoComponent(const QString &fileName);
@@ -64,6 +69,7 @@ private:
QPointer<DesignDocument> m_currentDesignDocument;
QmlDesignerProjectManager &m_projectManager;
ExternalDependenciesInterface &m_externalDependencies;
+ GeneratedComponentUtils m_generatedComponentUtils;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/documentwarningwidget.cpp b/src/plugins/qmldesigner/documentwarningwidget.cpp
index 9fb2b87635..a1cc12d825 100644
--- a/src/plugins/qmldesigner/documentwarningwidget.cpp
+++ b/src/plugins/qmldesigner/documentwarningwidget.cpp
@@ -39,8 +39,7 @@ DocumentWarningWidget::DocumentWarningWidget(QWidget *parent)
m_messageLabel->setWordWrap(true);
m_messageLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
- m_ignoreWarningsCheckBox->setText(tr("Always ignore these warnings about features "
- "not supported by Qt Quick Designer."));
+ m_ignoreWarningsCheckBox->setText(tr("Turn off warnings about unsupported Qt Design Studio features."));
connect(m_navigateLabel, &QLabel::linkActivated, this, [this](const QString &link) {
if (link == QLatin1String("goToCode")) {
@@ -93,7 +92,7 @@ void DocumentWarningWidget::refreshContent()
m_ignoreWarningsCheckBox->hide();
m_continueButton->setText(tr("OK"));
} else {
- m_headerLabel->setText(tr("This QML file contains features which are not supported by Qt Quick Designer at:"));
+ m_headerLabel->setText(tr("This QML file contains features which are not supported by Qt Design Studio at:"));
{
QSignalBlocker blocker(m_ignoreWarningsCheckBox);
m_ignoreWarningsCheckBox->setChecked(!warningsEnabled());
@@ -150,8 +149,8 @@ bool DocumentWarningWidget::eventFilter(QObject *object, QEvent *event)
void DocumentWarningWidget::showEvent(QShowEvent *event)
{
- const QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::DScontrolBackground);
- const QColor outlineColor = Utils::creatorTheme()->color(Utils::Theme::DScontrolOutline);
+ const QColor backgroundColor = Utils::creatorColor(Utils::Theme::DScontrolBackground);
+ const QColor outlineColor = Utils::creatorColor(Utils::Theme::DScontrolOutline);
QPalette pal = palette();
pal.setColor(QPalette::ToolTipBase, backgroundColor);
pal.setColor(QPalette::ToolTipText, outlineColor);
diff --git a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
index 6e8a2b6024..7819c6b49d 100644
--- a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
+++ b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
@@ -126,7 +126,7 @@ void PuppetEnvironmentBuilder::addRendering() const
{
m_environment.set("QML_BAD_GUI_RENDER_LOOP", "true");
m_environment.set("QML_PUPPET_MODE", "true");
- m_environment.set("QML_DISABLE_DISK_CACHE", "true");
+ //m_environment.set("QML_DISABLE_DISK_CACHE", "true");
m_environment.set("QMLPUPPET_RENDER_EFFECTS", "true");
if (!m_environment.hasKey("QT_SCREEN_SCALE_FACTORS") && !m_environment.hasKey("QT_SCALE_FACTOR"))
m_environment.set("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index db63d894fe..28f3ed6097 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -19,7 +19,6 @@ inline constexpr char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator";
inline constexpr char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor";
inline constexpr char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser";
inline constexpr char C_QMLASSETSLIBRARY[] = "QmlDesigner::AssetsLibrary";
-inline constexpr char C_QMLCOLLECTIONEDITOR[] = "QmlDesigner::CollectionEditor";
// Special context for preview menu, shared b/w designer and text editor
inline constexpr char C_QT_QUICK_TOOLS_MENU[] = "QmlDesigner::ToolsMenu";
@@ -51,6 +50,7 @@ inline constexpr char EDIT3D_EDIT_CAMERA[] = "QmlDesigner.Editor3D.EditCameraTog
inline constexpr char EDIT3D_ORIENTATION[] = "QmlDesigner.Editor3D.OrientationToggle";
inline constexpr char EDIT3D_EDIT_LIGHT[] = "QmlDesigner.Editor3D.EditLightToggle";
inline constexpr char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid";
+inline constexpr char EDIT3D_EDIT_SHOW_LOOKAT[] = "QmlDesigner.Editor3D.ToggleLookAt";
inline constexpr char EDIT3D_EDIT_SELECT_BACKGROUND_COLOR[]
= "QmlDesigner.Editor3D.SelectBackgroundColor";
inline constexpr char EDIT3D_EDIT_SELECT_GRID_COLOR[] = "QmlDesigner.Editor3D.SelectGridColor";
@@ -78,15 +78,28 @@ inline constexpr char EDIT3D_SNAP_CONFIG[] = "QmlDesigner.Editor3D.SnapConfig";
inline constexpr char EDIT3D_CAMERA_SPEED_CONFIG[] = "QmlDesigner.Editor3D.CameraSpeedConfig";
inline constexpr char QML_DESIGNER_SUBFOLDER[] = "/designer/";
-inline constexpr char COMPONENT_BUNDLES_FOLDER[] = "/ComponentBundles";
+inline constexpr char BUNDLE_JSON_FILENAME[] = "bundle.json";
+inline constexpr char COMPONENT_BUNDLES_TYPE[] = "Bundles";
+inline constexpr char COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE[] = "Materials";
+inline constexpr char COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE[] = "Effects";
+inline constexpr char COMPONENT_BUNDLES_USER_MATERIAL_BUNDLE_TYPE[] = "UserMaterials";
+inline constexpr char COMPONENT_BUNDLES_USER_EFFECT_BUNDLE_TYPE[] = "UserEffects";
+inline constexpr char COMPONENT_BUNDLES_USER_3D_BUNDLE_TYPE[] = "User3D";
+inline constexpr char GENERATED_COMPONENTS_FOLDER[] = "Generated";
inline constexpr char COMPONENT_BUNDLES_ASSET_REF_FILE[] = "_asset_ref.json";
-inline constexpr char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
+inline constexpr char OLD_QUICK_3D_ASSETS_FOLDER[] = "Quick3DAssets";
+inline constexpr char QUICK_3D_COMPONENTS_FOLDER[] = "QtQuick3D";
inline constexpr char QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX[] = "_libicon";
inline constexpr char QUICK_3D_ASSET_IMPORT_DATA_NAME[] = "_importdata.json";
inline constexpr char QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY[] = "import_options";
inline constexpr char QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY[] = "source_scene";
-inline constexpr char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports";
-inline constexpr char DEFAULT_EFFECTS_IMPORT_FOLDER[] = "/asset_imports/Effects";
+inline constexpr char OLD_ASSET_IMPORT_FOLDER[] = "asset_imports";
+inline constexpr char OLD_EFFECTS_IMPORT_FOLDER[] = "/asset_imports/Effects";
+inline constexpr char OLD_EFFECTS_FOLDER[] = "Effects";
+inline constexpr char OLD_COMPONENT_BUNDLES_TYPE[] = "ComponentBundles";
+inline constexpr char OLD_COMPONENT_BUNDLES_MATERIAL_BUNDLE_TYPE[] = "MaterialBundle";
+inline constexpr char OLD_COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE[] = "EffectBundle";
+inline constexpr char COMPOSED_EFFECTS_TYPE[] = "Effects";
inline constexpr char MATERIAL_LIB_ID[] = "__materialLibrary__";
inline constexpr char MIME_TYPE_ITEM_LIBRARY_INFO[]
@@ -94,7 +107,7 @@ inline constexpr char MIME_TYPE_ITEM_LIBRARY_INFO[]
inline constexpr char MIME_TYPE_ASSETS[] = "application/vnd.qtdesignstudio.assets";
inline constexpr char MIME_TYPE_MATERIAL[] = "application/vnd.qtdesignstudio.material";
inline constexpr char MIME_TYPE_TEXTURE[] = "application/vnd.qtdesignstudio.texture";
-inline constexpr char MIME_TYPE_BUNDLE_EFFECT[] = "application/vnd.qtdesignstudio.bundleeffect";
+inline constexpr char MIME_TYPE_BUNDLE_ITEM[] = "application/vnd.qtdesignstudio.bundleitem";
inline constexpr char MIME_TYPE_BUNDLE_MATERIAL[] = "application/vnd.qtdesignstudio.bundlematerial";
inline constexpr char MIME_TYPE_BUNDLE_TEXTURE[] = "application/vnd.qtdesignstudio.bundletexture";
inline constexpr char MIME_TYPE_ASSET_IMAGE[] = "application/vnd.qtdesignstudio.asset.image";
@@ -174,7 +187,6 @@ inline constexpr char OBJECT_NAME_EFFECT_COMPOSER[] = "QQuickWidgetEffectCompose
inline constexpr char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
inline constexpr char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor";
inline constexpr char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
-inline constexpr char OBJECT_NAME_COLLECTION_EDITOR[] = "QQuickWidgetQDSCollectionEditor";
inline constexpr char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor";
inline constexpr char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor";
inline constexpr char OBJECT_NAME_TOP_TOOLBAR[] = "QQuickWidgetTopToolbar";
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
index 321d95197f..97b2b46e7d 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
@@ -56,6 +56,11 @@ QUrl ExternalDependencies::projectUrl() const
return {};
}
+QString ExternalDependencies::projectName() const
+{
+ return QmlDesignerPlugin::instance()->documentManager().currentProjectName();
+}
+
QString ExternalDependencies::currentProjectDirPath() const
{
return QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
index b4908c2383..6a49e4b551 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
@@ -21,6 +21,7 @@ public:
QString qmlPuppetFallbackDirectory() const override;
QString defaultPuppetToplevelBuildDirectory() const override;
QUrl projectUrl() const override;
+ QString projectName() const override;
QString currentProjectDirPath() const override;
QUrl currentResourcePath() const override;
void parseItemLibraryDescriptions() override;
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index 601cf96681..9b6fb50425 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -4,7 +4,6 @@
#include "qmldesignerplugin.h"
#include "qmldesignertr.h"
-#include "collectioneditor/collectionview.h"
#include "coreplugin/iwizardfactory.h"
#include "designmodecontext.h"
#include "designmodewidget.h"
@@ -298,7 +297,6 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
//TODO Move registering those types out of the property editor, since they are used also in the states editor
Quick2PropertyEditorView::registerQmlTypes();
- CollectionView::registerDeclarativeType();
StudioQuickWidget::registerDeclarativeType();
QmlDesignerBase::WindowManager::registerDeclarativeType();
@@ -392,7 +390,6 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget)
Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR);
Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER);
Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY);
- Core::Context qmlDesignerCollectionEditorContext(Constants::C_QMLCOLLECTIONEDITOR);
context->context().add(qmlDesignerMainContext);
context->context().add(qmlDesignerFormEditorContext);
@@ -400,7 +397,6 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget)
context->context().add(qmlDesignerNavigatorContext);
context->context().add(qmlDesignerMaterialBrowserContext);
context->context().add(qmlDesignerAssetsLibraryContext);
- context->context().add(qmlDesignerCollectionEditorContext);
context->context().add(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID);
d->shortCutManager.registerActions(qmlDesignerMainContext, qmlDesignerFormEditorContext,
@@ -625,12 +621,14 @@ void QmlDesignerPlugin::enforceDelayedInitialize()
return;
// adding default path to item library plugins
- const QString postfix = Utils::HostOsInfo::isMacHost() ? QString("/QmlDesigner")
- : QString("/qmldesigner");
- const QStringList pluginPaths = Utils::transform(ExtensionSystem::PluginManager::pluginPaths(),
- [postfix](const QString &p) {
- return QString(p + postfix);
- });
+ const QString postfix = Utils::HostOsInfo::isMacHost()
+ ? QString("QmlDesigner")
+ : QString("qmldesigner");
+ const QStringList pluginPaths =
+ Utils::transform(ExtensionSystem::PluginManager::pluginPaths(),
+ [postfix](const Utils::FilePath &p) {
+ return (p / postfix).toFSPathString();
+ });
#ifndef QDS_USE_PROJECTSTORAGE
MetaInfo::initializeGlobal(pluginPaths, d->externalDependencies);
diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
index 7e28849fbb..730a557d12 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
@@ -12,15 +12,16 @@
#include <projectstorage/filesystem.h>
#include <projectstorage/nonlockingmutex.h>
#include <projectstorage/projectstorage.h>
+#include <projectstorage/projectstorageerrornotifier.h>
#include <projectstorage/projectstoragepathwatcher.h>
#include <projectstorage/projectstorageupdater.h>
#include <projectstorage/qmldocumentparser.h>
#include <projectstorage/qmltypesparser.h>
#include <projectstorage/sourcepathcache.h>
-#include <sqlitedatabase.h>
#include <qmlprojectmanager/qmlproject.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitaspect.h>
+#include <sqlitedatabase.h>
#include <asynchronousexplicitimagecache.h>
#include <asynchronousimagecache.h>
@@ -41,6 +42,7 @@
#include <QDirIterator>
#include <QFileSystemWatcher>
+#include <QLibraryInfo>
#include <QQmlEngine>
using namespace std::chrono;
@@ -180,7 +182,8 @@ public:
pathCache.sourceId(SourcePath{project->projectDirectory().toString() + "/."}).internalId())}
{}
Sqlite::Database database;
- ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
+ ProjectStorageErrorNotifier errorNotifier{pathCache};
+ ProjectStorage storage{database, errorNotifier, database.isInitialized()};
PathCacheType pathCache{storage};
FileSystem fileSystem{pathCache};
FileStatusCache fileStatusCache{fileSystem};
@@ -237,30 +240,34 @@ QmlDesignerProjectManager::QmlDesignerProjectManager(ExternalDependenciesInterfa
, m_externalDependencies{externalDependencies}
{
auto editorManager = ::Core::EditorManager::instance();
- QObject::connect(editorManager, &::Core::EditorManager::editorOpened, [&](auto *editor) {
+ QObject::connect(editorManager, &::Core::EditorManager::editorOpened, &dummy, [&](auto *editor) {
editorOpened(editor);
});
- QObject::connect(editorManager, &::Core::EditorManager::currentEditorChanged, [&](auto *editor) {
- currentEditorChanged(editor);
- });
- QObject::connect(editorManager, &::Core::EditorManager::editorsClosed, [&](const auto &editors) {
- editorsClosed(editors);
- });
+ QObject::connect(editorManager,
+ &::Core::EditorManager::currentEditorChanged,
+ &dummy,
+ [&](auto *editor) { currentEditorChanged(editor); });
+ QObject::connect(editorManager,
+ &::Core::EditorManager::editorsClosed,
+ &dummy,
+ [&](const auto &editors) { editorsClosed(editors); });
auto sessionManager = ::ProjectExplorer::ProjectManager::instance();
QObject::connect(sessionManager,
&::ProjectExplorer::ProjectManager::projectAdded,
+ &dummy,
[&](auto *project) { projectAdded(project); });
QObject::connect(sessionManager,
&::ProjectExplorer::ProjectManager::aboutToRemoveProject,
+ &dummy,
[&](auto *project) { aboutToRemoveProject(project); });
QObject::connect(sessionManager,
&::ProjectExplorer::ProjectManager::projectRemoved,
+ &dummy,
[&](auto *project) { projectRemoved(project); });
- QObject::connect(&m_previewImageCacheData->timer,
- &QTimer::timeout,
- this,
- &QmlDesignerProjectManager::generatePreview);
+ QObject::connect(&m_previewImageCacheData->timer, &QTimer::timeout, &dummy, [&]() {
+ generatePreview();
+ });
}
QmlDesignerProjectManager::~QmlDesignerProjectManager() = default;
@@ -281,7 +288,7 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache()
}
namespace {
-[[maybe_unused]] ProjectStorage<Sqlite::Database> *dummyProjectStorage()
+[[maybe_unused]] ProjectStorage *dummyProjectStorage()
{
return nullptr;
}
@@ -336,82 +343,36 @@ Utils::FilePath qmlPath(::ProjectExplorer::Target *target)
return {};
}
-template<typename... Path>
-bool skipDirectoriesWith(const QStringView directoryPath, const Path &...paths)
-{
- return (directoryPath.contains(paths) || ...);
-}
-
-template<typename... Path>
-bool skipDirectoriesEndsWith(const QStringView directoryPath, const Path &...paths)
-{
- return (directoryPath.endsWith(paths) || ...);
-}
-
-bool skipPath(const QString &directoryPath)
-{
- return skipDirectoriesWith(directoryPath,
- u"QtApplicationManager",
- u"QtInterfaceFramework",
- u"QtOpcUa",
- u"Qt3D",
- u"Scene2D",
- u"Scene3D",
- u"QtWayland",
- u"Qt5Compat",
- u"QtCharts",
- u"QtLocation",
- u"QtPositioning",
- u"MaterialEditor",
- u"QtTextToSpeech",
- u"QtWebEngine",
- u"Qt/labs",
- u"QtDataVisualization")
- || skipDirectoriesEndsWith(directoryPath, u"designer");
-}
-
-void collectQmldirPaths(const QString &path, QStringList &qmldirPaths)
-{
- QDirIterator dirIterator{path, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories};
-
- while (dirIterator.hasNext()) {
- auto directoryPath = dirIterator.next();
-
- QString qmldirPath = directoryPath + "/qmldir";
- if (!skipPath(directoryPath) && QFileInfo::exists(qmldirPath))
- qmldirPaths.push_back(directoryPath);
- }
-}
-
[[maybe_unused]] void projectQmldirPaths(::ProjectExplorer::Target *target, QStringList &qmldirPaths)
{
::QmlProjectManager::QmlBuildSystem *buildSystem = getQmlBuildSystem(target);
const Utils::FilePath projectDirectoryPath = buildSystem->canonicalProjectDir();
- const QStringList importPaths = buildSystem->importPaths();
- const QDir projectDirectory(projectDirectoryPath.toString());
- for (const QString &importPath : importPaths)
- collectQmldirPaths(importPath, qmldirPaths);
+ qmldirPaths.push_back(projectDirectoryPath.path());
}
[[maybe_unused]] void qtQmldirPaths(::ProjectExplorer::Target *target, QStringList &qmldirPaths)
{
- if constexpr (useProjectStorage())
- collectQmldirPaths(qmlPath(target).toString(), qmldirPaths);
+ if constexpr (useProjectStorage()) {
+ auto qmlRootPath = qmlPath(target).toString();
+ qmldirPaths.push_back(qmlRootPath + "/QtQml");
+ qmldirPaths.push_back(qmlRootPath + "/QtQuick");
+ qmldirPaths.push_back(qmlRootPath + "/QtQuick3D");
+ qmldirPaths.push_back(qmlRootPath + "/Qt5Compat");
+ }
}
-[[maybe_unused]] void qtQmldirPathsForLiteDesigner(::ProjectExplorer::Target *target,
- QStringList &qmldirPaths)
+[[maybe_unused]] void qtQmldirPathsForLiteDesigner(QStringList &qmldirPaths)
{
if constexpr (useProjectStorage()) {
- auto qmlRootPath = qmlPath(target).toString();
- collectQmldirPaths(qmlRootPath + "/QtQml", qmldirPaths);
- collectQmldirPaths(qmlRootPath + "/QtQuick", qmldirPaths);
+ auto qmlRootPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
+ qmldirPaths.push_back(qmlRootPath + "/QtQml");
+ qmldirPaths.push_back(qmlRootPath + "/QtQuick");
}
}
-QStringList directories(::ProjectExplorer::Target *target)
+[[maybe_unused]] QStringList directories(::ProjectExplorer::Target *target)
{
if (!target)
return {};
@@ -419,12 +380,21 @@ QStringList directories(::ProjectExplorer::Target *target)
QStringList qmldirPaths;
qmldirPaths.reserve(100);
- if constexpr (isUsingQmlDesignerLite()) {
- qtQmldirPathsForLiteDesigner(target, qmldirPaths);
- } else {
- qtQmldirPaths(target, qmldirPaths);
- projectQmldirPaths(target, qmldirPaths);
- }
+ qtQmldirPaths(target, qmldirPaths);
+ projectQmldirPaths(target, qmldirPaths);
+
+ std::sort(qmldirPaths.begin(), qmldirPaths.end());
+ qmldirPaths.erase(std::unique(qmldirPaths.begin(), qmldirPaths.end()), qmldirPaths.end());
+
+ return qmldirPaths;
+}
+
+[[maybe_unused]] QStringList directoriesForLiteDesigner()
+{
+ QStringList qmldirPaths;
+ qmldirPaths.reserve(100);
+
+ qtQmldirPathsForLiteDesigner(qmldirPaths);
std::sort(qmldirPaths.begin(), qmldirPaths.end());
qmldirPaths.erase(std::unique(qmldirPaths.begin(), qmldirPaths.end()), qmldirPaths.end());
@@ -432,7 +402,7 @@ QStringList directories(::ProjectExplorer::Target *target)
return qmldirPaths;
}
-QStringList qmlTypes(::ProjectExplorer::Target *target)
+[[maybe_unused]] QStringList qmlTypes(::ProjectExplorer::Target *target)
{
if (!target)
return {};
@@ -440,10 +410,26 @@ QStringList qmlTypes(::ProjectExplorer::Target *target)
QStringList qmldirPaths;
qmldirPaths.reserve(2);
- const QString installDirectory = qmlPath(target).toString();
+ const QString qmlRootPath = qmlPath(target).toString();
+
+ qmldirPaths.append(qmlRootPath + "/builtins.qmltypes");
+ qmldirPaths.append(qmlRootPath + "/jsroot.qmltypes");
+
+ qmldirPaths.append(
+ Core::ICore::resourcePath("qmldesigner/projectstorage/fake.qmltypes").toString());
+
+ return qmldirPaths;
+}
+
+[[maybe_unused]] QStringList qmlTypesForLiteDesigner()
+{
+ QStringList qmldirPaths;
+ qmldirPaths.reserve(2);
+
+ const auto qmlRootPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
- qmldirPaths.append(installDirectory + "/builtins.qmltypes");
- qmldirPaths.append(installDirectory + "/jsroot.qmltypes");
+ qmldirPaths.append(qmlRootPath + "/builtins.qmltypes");
+ qmldirPaths.append(qmlRootPath + "/jsroot.qmltypes");
qmldirPaths.append(
Core::ICore::resourcePath("qmldesigner/projectstorage/fake.qmltypes").toString());
@@ -461,6 +447,11 @@ QString propertyEditorResourcesPath()
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
}
+QString qtCreatorItemLibraryPath()
+{
+ return Core::ICore::resourcePath("qmldesigner/itemLibrary").toString();
+}
+
} // namespace
void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project)
@@ -533,12 +524,12 @@ QmlDesignerProjectManager::ImageCacheData *QmlDesignerProjectManager::imageCache
m_imageCacheData->nodeInstanceCollector.setTarget(project->activeTarget());
QObject::connect(project,
&ProjectExplorer::Project::activeTargetChanged,
- this,
+ &dummy,
setTargetInImageCache);
}
QObject::connect(ProjectExplorer::ProjectManager::instance(),
&ProjectExplorer::ProjectManager::startupProjectChanged,
- this,
+ &dummy,
[=](ProjectExplorer::Project *project) {
setTargetInImageCache(activeTarget(project));
});
@@ -594,9 +585,17 @@ void QmlDesignerProjectManager::update()
if (!m_projectData || !m_projectData->projectStorageData)
return;
- m_projectData->projectStorageData->updater.update(directories(m_projectData->activeTarget),
- qmlTypes(m_projectData->activeTarget),
- propertyEditorResourcesPath());
+ if constexpr (isUsingQmlDesignerLite()) {
+ m_projectData->projectStorageData->updater.update(directoriesForLiteDesigner(),
+ qmlTypesForLiteDesigner(),
+ propertyEditorResourcesPath(),
+ {qtCreatorItemLibraryPath()});
+ } else {
+ m_projectData->projectStorageData->updater.update(directories(m_projectData->activeTarget),
+ qmlTypes(m_projectData->activeTarget),
+ propertyEditorResourcesPath(),
+ {qtCreatorItemLibraryPath()});
+ }
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h
index bd45bf16c9..1e5cec2e3e 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h
@@ -28,10 +28,8 @@ namespace QmlDesigner {
class ExternalDependenciesInterface;
-class QmlDesignerProjectManager : public QObject
+class QmlDesignerProjectManager
{
- Q_OBJECT
-
class QmlDesignerProjectManagerProjectData;
class PreviewImageCacheData;
class ImageCacheData;
@@ -70,5 +68,6 @@ private:
std::unique_ptr<PreviewImageCacheData> m_previewImageCacheData;
std::unique_ptr<QmlDesignerProjectManagerProjectData> m_projectData;
ExternalDependenciesInterface &m_externalDependencies;
+ QObject dummy;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
index d5036c939c..34cd4338ac 100644
--- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
+++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
@@ -165,7 +165,7 @@ void QmlPreviewWidgetPlugin::setLanguageLocale(const QString &locale)
QObject *QmlPreviewWidgetPlugin::getPreviewPlugin()
{
- const QVector<ExtensionSystem::PluginSpec *> &specs = ExtensionSystem::PluginManager::plugins();
+ const ExtensionSystem::PluginSpecs &specs = ExtensionSystem::PluginManager::plugins();
const auto pluginIt = std::find_if(specs.cbegin(), specs.cend(),
[](const ExtensionSystem::PluginSpec *p) {
return p->name() == "QmlPreview";
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-16px.png b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-16px.png
new file mode 100644
index 0000000000..5171fdd79d
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-16px.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px.png b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px.png
new file mode 100644
index 0000000000..2fba147700
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px@2x.png
new file mode 100644
index 0000000000..170c113bbd
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/frame-animation-24px@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
index 34838797d4..c2a1ff5929 100644
--- a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
+++ b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
@@ -127,5 +127,8 @@
<file>images/extended-view3d-16px.png</file>
<file>images/extended-view3d-24px.png</file>
<file>images/extended-view3d-24px@2x.png</file>
+ <file>images/frame-animation-16px.png</file>
+ <file>images/frame-animation-24px.png</file>
+ <file>images/frame-animation-24px@2x.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
index 3f3cdb7910..63d390dded 100644
--- a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
+++ b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
@@ -374,7 +374,6 @@ MetaInfo {
name: "Keyframe"
category: "none"
version: "1.0"
- requiredImport: "none"
}
}
@@ -386,7 +385,6 @@ MetaInfo {
name: "KeyframeGroup"
category: "none"
version: "1.0"
- requiredImport: "none"
}
}
@@ -551,6 +549,26 @@ MetaInfo {
}
Type {
+ name: "QtQuick.FrameAnimation"
+ icon: ":/qtquickplugin/images/frame-animation-16px.png"
+
+ Hints {
+ visibleInNavigator: true
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeContainer: false
+ }
+
+ ItemLibraryEntry {
+ name: "Frame Animation"
+ category: "d.Qt Quick - Animation"
+ libraryIcon: ":/qtquickplugin/images/frame-animation-24px.png"
+ version: "2.0"
+ toolTip: qsTr("Triggers a handler at every animation frame update.")
+ }
+ }
+
+ Type {
name: "QtQml.Timer"
icon: ":/qtquickplugin/images/timer-16px.png"
diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp
index 344e2700d9..df17f005a2 100644
--- a/src/plugins/qmldesigner/settingspage.cpp
+++ b/src/plugins/qmldesigner/settingspage.cpp
@@ -39,7 +39,8 @@ namespace Internal {
static QStringList puppetModes()
{
- static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode", "bakelightsmode"};
+ static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode",
+ "bakelightsmode", "import3dmode"};
return puppetModeList;
}
@@ -135,7 +136,7 @@ SettingsPageWidget::SettingsPageWidget(ExternalDependencies &externalDependencie
m_useDefaultPuppetRadioButton = new QRadioButton(tr("Use fallback QML emulation layer"));
m_useDefaultPuppetRadioButton->setToolTip(
- tr("If you select this radio button, Qt Quick Designer always uses the "
+ tr("If you select this radio button, Qt Design Studio always uses the "
"QML emulation layer (QML Puppet) located at the following path."));
m_useDefaultPuppetRadioButton->setChecked(true);
@@ -167,7 +168,7 @@ SettingsPageWidget::SettingsPageWidget(ExternalDependencies &externalDependencie
m_designerWarningsCheckBox = new QCheckBox(
tr("Warn about unsupported features in .ui.qml files"));
m_designerWarningsCheckBox->setToolTip(
- tr("Warns about QML features that are not properly supported by the Qt Quick Designer."));
+ tr("Warns about QML features that are not properly supported by the Qt Design Studio."));
m_designerWarningsUiQmlfiles = new QCheckBox(
tr("Warn about using .qml files instead of .ui.qml files"));
diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp
index 961aa1c952..661ff3f271 100644
--- a/src/plugins/qmldesigner/shortcutmanager.cpp
+++ b/src/plugins/qmldesigner/shortcutmanager.cpp
@@ -144,7 +144,8 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer(
QmlProjectManager::Constants::EXPORT_MENU);
- exportMenu->addAction(command, QmlProjectManager::Constants::G_EXPORT_CONVERT);
+ if (exportMenu)
+ exportMenu->addAction(command, QmlProjectManager::Constants::G_EXPORT_CONVERT);
//Close Editor
Core::ActionManager::registerAction(&m_closeCurrentEditorAction, Core::Constants::CLOSE, qmlDesignerMainContext);
@@ -231,12 +232,10 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
connect(Core::ICore::instance(), &Core::ICore::contextChanged, this, [&](const Core::Context &context) {
isMatBrowserActive = context.contains(Constants::C_QMLMATERIALBROWSER);
isAssetsLibraryActive = context.contains(Constants::C_QMLASSETSLIBRARY);
- isCollectionEditorActive = context.contains(Constants::C_QMLCOLLECTIONEDITOR);
if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLEDITOR3D)
&& !context.contains(Constants::C_QMLNAVIGATOR)) {
- m_deleteAction.setEnabled(isMatBrowserActive || isAssetsLibraryActive
- || isCollectionEditorActive);
+ m_deleteAction.setEnabled(isMatBrowserActive || isAssetsLibraryActive);
m_cutAction.setEnabled(false);
m_copyAction.setEnabled(false);
m_pasteAction.setEnabled(false);
@@ -293,8 +292,6 @@ void ShortCutManager::deleteSelected()
actionManager.view()->emitCustomNotification("delete_selected_material");
else if (isAssetsLibraryActive)
actionManager.view()->emitCustomNotification("delete_selected_assets");
- else if (isCollectionEditorActive)
- actionManager.view()->emitCustomNotification("delete_selected_collection");
else if (currentDesignDocument())
currentDesignDocument()->deleteSelected();
}
diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h
index 8714bb5fbc..70b019217c 100644
--- a/src/plugins/qmldesigner/shortcutmanager.h
+++ b/src/plugins/qmldesigner/shortcutmanager.h
@@ -64,7 +64,6 @@ private:
bool isMatBrowserActive = false;
bool isAssetsLibraryActive = false;
- bool isCollectionEditorActive = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/asset.cpp b/src/plugins/qmldesigner/utils/asset.cpp
index 2984a4d890..ec1e4312e4 100644
--- a/src/plugins/qmldesigner/utils/asset.cpp
+++ b/src/plugins/qmldesigner/utils/asset.cpp
@@ -1,15 +1,19 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include <QImageReader>
-
#include "asset.h"
+#include "hdrimage.h"
+
+#include <QImageReader>
+#include <QPixmap>
+
namespace QmlDesigner {
Asset::Asset(const QString &filePath)
: m_filePath(filePath)
{
+ m_fileName = filePath.split('/').last();
const QStringList split = filePath.split('.');
if (split.size() > 1)
m_suffix = "*." + split.last().toLower();
@@ -105,6 +109,19 @@ bool Asset::isSupported(const QString &path)
return supportedSuffixes().contains(path);
}
+QPixmap Asset::pixmap(const QSize &size) const
+{
+ if (!isImage() && !isHdrFile())
+ return {};
+
+ QPixmap icon = isHdrFile() ? HdrImage{m_filePath}.toPixmap() : QPixmap{m_filePath};
+
+ if (size.isValid())
+ icon = icon.scaled(size, Qt::KeepAspectRatio);
+
+ return icon;
+}
+
Asset::Type Asset::type() const
{
return m_type;
@@ -175,6 +192,11 @@ const QString Asset::id() const
return m_filePath;
}
+const QString Asset::fileName() const
+{
+ return m_fileName;
+}
+
bool Asset::isSupported() const
{
return m_type != Asset::Type::Unknown;
diff --git a/src/plugins/qmldesigner/utils/asset.h b/src/plugins/qmldesigner/utils/asset.h
index cb09f3a5ee..a5c5899f34 100644
--- a/src/plugins/qmldesigner/utils/asset.h
+++ b/src/plugins/qmldesigner/utils/asset.h
@@ -3,8 +3,11 @@
#pragma once
+#include <QSize>
#include <QString>
+QT_FORWARD_DECLARE_CLASS(QPixmap)
+
namespace QmlDesigner {
class Asset
@@ -37,7 +40,9 @@ public:
const QString suffix() const;
const QString id() const;
+ const QString fileName() const;
bool hasSuffix() const;
+ QPixmap pixmap(const QSize &size = {}) const;
Type type() const;
bool isImage() const;
@@ -58,6 +63,7 @@ private:
void resolveType();
QString m_filePath;
+ QString m_fileName;
QString m_suffix;
Type m_type = Unknown;
};
diff --git a/src/plugins/qmldesigner/utils/imageutils.cpp b/src/plugins/qmldesigner/utils/imageutils.cpp
index 8fa3131cd3..42df6184b9 100644
--- a/src/plugins/qmldesigner/utils/imageutils.cpp
+++ b/src/plugins/qmldesigner/utils/imageutils.cpp
@@ -11,7 +11,7 @@
namespace QmlDesigner {
-QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes)
+QString ImageUtils::imageInfoString(const QSize &dimensions, qint64 sizeInBytes)
{
return QLatin1String("%1 x %2\n%3")
.arg(QString::number(dimensions.width()),
@@ -20,7 +20,7 @@ QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes)
sizeInBytes, 2, QLocale::DataSizeTraditionalFormat));
}
-QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
+QPair<QSize, qint64> QmlDesigner::ImageUtils::imageInfo(const QString &path)
{
QFileInfo info(path);
if (!info.exists())
@@ -52,7 +52,13 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
if (width <= 0 || height <= 0)
return {};
- return imageInfo(QSize(width, height), info.size());
+ return {QSize(width, height), info.size()};
+}
+
+QString ImageUtils::imageInfoString(const QString &path)
+{
+ QPair<QSize, qint64> info = imageInfo(path);
+ return imageInfoString(info.first, info.second);
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/imageutils.h b/src/plugins/qmldesigner/utils/imageutils.h
index a4036614a3..dae64423bb 100644
--- a/src/plugins/qmldesigner/utils/imageutils.h
+++ b/src/plugins/qmldesigner/utils/imageutils.h
@@ -12,8 +12,9 @@ class ImageUtils
public:
ImageUtils();
- static QString imageInfo(const QSize &dimensions, qint64 sizeInBytes);
- static QString imageInfo(const QString &path);
+ static QPair<QSize, qint64> imageInfo(const QString &path);
+ static QString imageInfoString(const QString &path);
+ static QString imageInfoString(const QSize &dimensions, qint64 sizeInBytes);
};
} // namespace QmlDesigner