summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Jenssen <tim.jenssen@qt.io>2023-03-30 13:34:12 +0200
committerTim Jenssen <tim.jenssen@qt.io>2023-03-30 13:30:42 +0000
commitadb664f52128b3c28323a5d4dccedc204dec8b34 (patch)
tree5bc4573e921a37f7ba46d73eba16c6f08db37da4
parent6f765181c9b9e716f3ae746183cdeac2459ac194 (diff)
parent5b28748554b3f97c4e163606208878d573f2a655 (diff)
downloadqt-creator-adb664f52128b3c28323a5d4dccedc204dec8b34.tar.gz
Merge remote-tracking branch 'origin/qds/dev'
Conflicts: src/libs/utils/filepath.cpp src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp tests/unit/unittest/CMakeLists.txt Change-Id: I017a6075db41a5233487ac855ffe23de2b2bb0ee
-rw-r--r--.gitignore-blame2
-rw-r--r--cmake/QtCreatorAPI.cmake3
-rw-r--r--doc/config/macros.qdocconf1
-rw-r--r--doc/qtcreator/src/user-interface/creator-ui.qdoc8
-rw-r--r--doc/qtdesignstudio/examples/doc/images/material-bundle-example.webpbin0 -> 60022 bytes
-rw-r--r--doc/qtdesignstudio/examples/doc/materialbundle.qdoc33
-rw-r--r--doc/qtdesignstudio/images/3d-view-context-menu.pngbin4571 -> 10442 bytes
-rw-r--r--doc/qtdesignstudio/images/assets-view-effect.pngbin4813 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/content-library-add-texture.pngbin15426 -> 15528 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/3d-background-color.pngbin335 -> 348 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/align-camera-on.pngbin309 -> 282 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/align-view-on.pngbin321 -> 277 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/apply-material.pngbin779 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/apply.pngbin0 -> 330 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/arrowleft.pngbin147 -> 176 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/arrowright.pngbin149 -> 177 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/back_one_frame.pngbin153 -> 227 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/create_component.pngbin0 -> 376 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/curve_editor.pngbin190 -> 286 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/easing-curve-linear-icon.pngbin201 -> 247 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/easing-curve-spline-icon.pngbin391 -> 360 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/easing-curve-step-icon.pngbin147 -> 255 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/edit.pngbin242 -> 263 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/edit_component.pngbin0 -> 345 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/edit_light_off.pngbin0 -> 281 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/edit_light_on.pngbin0 -> 260 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/fit_selected.pngbin0 -> 296 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/forward_one_frame.pngbin147 -> 234 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/global.pngbin0 -> 323 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/global_record_keyframes.pngbin162 -> 263 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/home.pngbin0 -> 299 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/move_off.pngbin0 -> 289 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/navigator-arrowdown.pngbin165 -> 159 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/navigator-arrowup.pngbin160 -> 162 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/orthographic_camera.pngbin0 -> 244 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-animation-on.pngbin316 -> 2101 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-pause.pngbin120 -> 157 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-play.pngbin159 -> 205 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-restart.pngbin302 -> 335 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particles-seek.pngbin311 -> 331 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/perspective_camera.pngbin0 -> 216 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/reset.pngbin0 -> 294 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/rotate_off.pngbin0 -> 272 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/scale_off.pngbin0 -> 303 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/select_group.pngbin0 -> 210 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/select_item.pngbin0 -> 263 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/settings.pngbin0 -> 315 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/start_playback.pngbin143 -> 234 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/to_first_frame.pngbin135 -> 249 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/to_last_frame.pngbin132 -> 272 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/visibilityon.pngbin271 -> 295 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/zoomAll.pngbin302 -> 236 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/zoomIn.pngbin323 -> 300 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/zoomOut.pngbin314 -> 276 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/zoomSelection.pngbin316 -> 287 bytes
-rw-r--r--doc/qtdesignstudio/images/loader3d-navigator.pngbin6100 -> 5906 bytes
-rw-r--r--doc/qtdesignstudio/images/material-copy-properties.pngbin34372 -> 24286 bytes
-rw-r--r--doc/qtdesignstudio/images/navigator-material-texture.pngbin3820 -> 4048 bytes
-rw-r--r--doc/qtdesignstudio/images/navigator-show-all-loader.pngbin9079 -> 8056 bytes
-rw-r--r--doc/qtdesignstudio/images/new-effect-file.pngbin9517 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/qml-shapes-rectangle.pngbin38147 -> 56733 bytes
-rw-r--r--doc/qtdesignstudio/images/qml-shapes.pngbin13756 -> 20563 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-alignment.pngbin13055 -> 13015 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-anchors.pngbin15914 -> 15122 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-bindings.pngbin3567 -> 3514 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-breadcrumbs.pngbin14483 -> 44652 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-button.pngbin8390 -> 3937 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-canvas-color.pngbin5691 -> 4557 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-connections.pngbin3698 -> 3294 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-dynamicprops.pngbin4094 -> 3352 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-editing-components.pngbin75716 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-editing-components.webpbin0 -> 54684 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-element-size.pngbin41513 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-element-size.webpbin0 -> 12894 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-export-item.pngbin3968 -> 4640 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-form-editor-move-cursor.pngbin8669 -> 9983 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-form-editor.pngbin14960 -> 9604 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-mcu-support.pngbin53982 -> 50795 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-navigator-arrows.pngbin4757 -> 5657 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-navigator.pngbin14017 -> 24569 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-preview-size.pngbin33337 -> 45589 bytes
-rw-r--r--doc/qtdesignstudio/images/qmldesigner-tutorial-user-icon.pngbin41618 -> 44536 bytes
-rw-r--r--doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.pngbin66818 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webpbin0 -> 38358 bytes
-rw-r--r--doc/qtdesignstudio/images/qtds-running-emulator.pngbin230313 -> 228819 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-annotations.pngbin24011 -> 23328 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-assets-tab.pngbin16901 -> 16953 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-components-context-menu-hide.pngbin25418 -> 20061 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-components-context-menu.pngbin26033 -> 22024 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-components-tab-add.pngbin18109 -> 24346 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-components-tab.pngbin11249 -> 14277 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-custom-properties.pngbin19316 -> 26597 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-button-types.pngbin16959 -> 16320 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-image-type.pngbin15492 -> 27166 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-indicator-types.pngbin6191 -> 5075 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-qtquickcontrols-types.pngbin14414 -> 15269 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-rotating-items.pngbin8637 -> 10790 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-scaling-items.pngbin6935 -> 8340 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-selector-types.pngbin11676 -> 11311 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-designer-stacked-view.pngbin104177 -> 103745 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-library-context-menu.pngbin16678 -> 16734 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-positioner-column-properties.pngbin14422 -> 15722 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-positioner-flow-properties.pngbin19188 -> 19764 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-positioner-grid-properties.pngbin20174 -> 24243 bytes
-rw-r--r--doc/qtdesignstudio/images/qtquick-text-editor.pngbin23333 -> 21010 bytes
-rw-r--r--doc/qtdesignstudio/images/repeater3d-listmodel-navigator.pngbin5344 -> 5996 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-2d-effects.pngbin14539 -> 11380 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-area-light.pngbin21349 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-area-light.webpbin0 -> 27570 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-directional-light.pngbin19122 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-directional-light.webpbin0 -> 14130 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-axis-helper.pngbin58091 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-axis-helper.webpbin0 -> 30310 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-move.pngbin38487 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-move.webpbin0 -> 30488 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-rotate.pngbin41596 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-rotate.webpbin0 -> 31534 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-scale.pngbin38694 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-scale.webpbin0 -> 30344 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor.pngbin41273 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor.webpbin0 -> 29906 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-effects.pngbin9034 -> 17846 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-instancing-instance-list.pngbin11023 -> 7671 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-models.pngbin18552 -> 24452 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-particles-fire-assets.pngbin13380 -> 15298 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-particles-fire-components.pngbin12228 -> 13357 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-particles-fire-emitter1.pngbin7086 -> 8182 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-particles-sprite-template.pngbin12072 -> 10999 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-point-light.pngbin21503 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-point-light.webpbin0 -> 43008 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-spot-light.pngbin25519 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-spot-light.webpbin0 -> 37918 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-animation.pngbin5662 -> 6392 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-connection-view-properties.pngbin5878 -> 3106 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-custom-material-uniform-properties.pngbin5647 -> 3892 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-design-mode-states-timeline.pngbin12629 -> 28166 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-design-mode.pngbin77171 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-design-mode.webpbin0 -> 76408 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-dial.pngbin38697 -> 53036 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-editing-3d-scenes.pngbin46797 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-flipable.pngbin29253 -> 34716 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.pngbin24767 -> 27938 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-and.pngbin27108 -> 31579 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-bidirectional-binding.pngbin20359 -> 33054 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-input.pngbin26641 -> 29140 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-string-mapper-input.pngbin24487 -> 28290 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-not-check-box.pngbin26981 -> 33194 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-not.pngbin23491 -> 27477 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-range-mapper-inputmin.pngbin31335 -> 44681 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-logic-helper-string-mapper-text.pngbin20759 -> 36413 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-navigator-view3d.pngbin12276 -> 5890 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qml-imports-slconnector.pngbin11185 -> 18083 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qtquick-3d-custom-effect-navigator.pngbin4637 -> 7845 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qtquick-3d-default-material.pngbin11769 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-qtquick-3d-material.pngbin64943 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-shapes.pngbin15345 -> 19638 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.pngbin13930 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.webpbin0 -> 11086 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-no-tracks.pngbin8096 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-no-tracks.webpbin0 -> 6008 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.pngbin9657 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.webpbin0 -> 6906 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-with-tracks.pngbin13697 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline-with-tracks.webpbin0 -> 10612 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline.pngbin14055 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-timeline.webpbin0 -> 10114 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-per-property-recording.pngbin6041 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-per-property-recording.webpbin0 -> 5950 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-states.pngbin9294 -> 0 bytes
-rw-r--r--doc/qtdesignstudio/images/timeline-states.webpbin0 -> 10436 bytes
-rw-r--r--doc/qtdesignstudio/images/toolbar-show-live-preview.pngbin8359 -> 4996 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-change-file.pngbin0 -> 7619 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-column-layout.pngbin0 -> 15463 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-components-2.pngbin0 -> 5217 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-components.pngbin0 -> 5196 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-new-file.pngbin0 -> 17755 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-page-components.pngbin0 -> 14101 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-page-margins.pngbin0 -> 11333 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-size-binding-2.pngbin0 -> 4485 bytes
-rw-r--r--doc/qtdesignstudio/images/web-navigation-size-binding.pngbin0 -> 4659 bytes
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-buttons.qdoc6
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-positioning.qdoc6
-rw-r--r--doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc289
-rw-r--r--doc/qtdesignstudio/src/overviews/qt-design-viewer.qdoc6
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc4
-rw-r--r--doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc3
-rw-r--r--doc/qtdesignstudio/src/qtbridge/qtbridge-figma-template.qdoc87
-rw-r--r--doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc11
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc33
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc8
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc46
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc8
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-designer.qdoc157
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc37
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-navigator.qdoc6
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-properties.qdoc22
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc14
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline.qdoc11
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc8
-rw-r--r--doc/qtdesignstudio/src/views/studio-material-editor.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/studio-texture-editor.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/studio-translations.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/studio-workspaces.qdoc2
-rwxr-xr-xscripts/makedmg.py17
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml)130
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml)168
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml)78
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml)118
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFilesDialog.qml)5
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml)3
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/ErrorDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/ErrorDialog.qml)0
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/NewEffectDialog.qml)31
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml)4
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml (renamed from share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml)12
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml88
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml124
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml4
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml12
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml34
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml105
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml242
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml11
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml8
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/DownloadPane.qml81
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/TextureProgressBar.qml62
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml3
-rw-r--r--share/qtcreator/qmldesigner/designericons.json150
-rw-r--r--share/qtcreator/qmldesigner/feedback/FeedbackPopup.qml143
-rw-r--r--share/qtcreator/qmldesigner/feedback/star_empty.pngbin0 -> 468 bytes
-rw-r--r--share/qtcreator/qmldesigner/feedback/star_empty@2x.pngbin0 -> 833 bytes
-rw-r--r--share/qtcreator/qmldesigner/feedback/star_filled.pngbin0 -> 424 bytes
-rw-r--r--share/qtcreator/qmldesigner/feedback/star_filled@2x.pngbin0 -> 650 bytes
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml5
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml9
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml191
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml599
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml10
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml36
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureBrowserContextMenu.qml5
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml20
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml3
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml58
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml56
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml14
-rw-r--r--share/qtcreator/qmldesigner/newstateseditor/Main.qml24
-rw-r--r--share/qtcreator/qmldesigner/newstateseditor/MenuButton.qml30
-rw-r--r--share/qtcreator/qmldesigner/newstateseditor/StateScrollBar.qml2
-rw-r--r--share/qtcreator/qmldesigner/newstateseditor/StateThumbnail.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml3
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimationTargetSection.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml38
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ColumnSpecifics.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ConnectionsSpecifics.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml12
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckSection.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml10
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ContainerSection.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSection.qml8
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml3
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml15
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml10
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSection.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSection.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml10
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml20
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml13
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml7
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/FlowSpecifics.qml15
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml35
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridViewSpecifics.qml35
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LayerSection.qml24
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ListViewSpecifics.qml35
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LoaderSpecifics.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml26
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/PathViewSpecifics.qml29
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml12
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RepeaterSpecifics.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RowSpecifics.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml52
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSection.qml64
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSpecifics.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSection.qml83
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSpecifics.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSection.qml66
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSpecifics.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioListenerSpecifics.qml16
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSection.qml277
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSpecifics.qml18
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/NodeSection.qml350
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSection.qml234
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSpecifics.qml18
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml41
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorLogic.qml29
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml33
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml5
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DynamicPropertiesSection.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml81
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml26
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableGeometrySection.qml27
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml19
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml13
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml32
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml16
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImageSection.qml25
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml18
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml50
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OriginControl.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PaddingSection.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml25
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml12
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml125
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml55
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Button.qml25
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonGroup.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonRow.qml45
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckBox.qml125
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml148
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml207
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml159
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ContextMenu.qml74
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Dialog.qml59
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButton.qml98
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButtonBox.qml45
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml342
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Indicator.qml50
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/InfinityLoopIndicator.qml38
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ItemDelegate.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator2D.qml36
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3D.qml61
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3DComponent.qml34
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml21
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml41
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItemWithIcon.qml34
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuSeparator.qml12
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ProgressBar.qml32
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RadioButton.qml93
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml38
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml267
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxIndicator.qml135
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml166
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollBar.qml12
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollView.qml22
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml274
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SecondColumnLayout.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml49
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml16
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLayout.qml14
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Slider.qml187
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SliderPopup.qml52
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBox.qml249
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxIndicator.qml120
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxInput.qml175
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Switch.qml135
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabBar.qml18
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabButton.qml27
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextArea.qml83
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml182
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml45
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml266
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TranslationIndicator.qml111
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml30
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml4
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml190
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/DefaultStyle.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml496
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/PrimaryButtonStyle.qml30
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/SearchControlStyle.qml44
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatesControlStyle.qml33
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarButtonStyle.qml34
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarControlStyle.qml33
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml16
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/TopToolbarButtonStyle.qml34
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml280
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarButtonStyle.qml35
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarControlStyle.qml15
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttfbin29604 -> 57196 bytes
-rwxr-xr-xshare/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir12
-rw-r--r--share/qtcreator/qmldesigner/statusbar/Main.qml85
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject22
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/CMakeLists.txt121
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl22
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/DirectoryFontLoader.qml.tpl34
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/constants_module.qmlproject.tpl13
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl3
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl2
-rw-r--r--share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml4
-rw-r--r--share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml58
-rw-r--r--share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorTopSection.qml5
-rw-r--r--share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml93
-rw-r--r--share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml177
-rw-r--r--share/qtcreator/qmldesigner/toolbar/Main.qml403
-rw-r--r--share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml24
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk1
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk2
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk2
-rw-r--r--share/qtcreator/themes/dark.creatortheme109
-rw-r--r--share/qtcreator/themes/default.creatortheme60
-rw-r--r--share/qtcreator/themes/design-light.creatortheme63
-rw-r--r--share/qtcreator/themes/design.creatortheme191
-rw-r--r--share/qtcreator/themes/flat-dark.creatortheme106
-rw-r--r--share/qtcreator/themes/flat-light.creatortheme59
-rw-r--r--share/qtcreator/themes/flat.creatortheme106
-rw-r--r--src/app/main.cpp18
-rw-r--r--src/libs/3rdparty/sqlite/carray.c51
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.c8960
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.h330
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3ext.h12
-rw-r--r--src/libs/advanceddockingsystem/dockareatitlebar.cpp4
-rw-r--r--src/libs/advanceddockingsystem/dockfocuscontroller.cpp19
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.cpp9
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.h2
-rw-r--r--src/libs/qmljs/qmljscheck.cpp28
-rw-r--r--src/libs/qmljs/qmljslink.cpp2
-rw-r--r--src/libs/qmljs/qmljsscopebuilder.cpp1
-rw-r--r--src/libs/qmljs/qmljsscopechain.cpp10
-rw-r--r--src/libs/qmljs/qmljsscopechain.h4
-rw-r--r--src/libs/sqlite/CMakeLists.txt2
-rw-r--r--src/libs/sqlite/constraints.h2
-rw-r--r--src/libs/sqlite/sqlitebasestatement.cpp326
-rw-r--r--src/libs/sqlite/sqlitebasestatement.h36
-rw-r--r--src/libs/sqlite/sqlitedatabase.cpp2
-rw-r--r--src/libs/sqlite/sqlitedatabase.h13
-rw-r--r--src/libs/sqlite/sqlitedatabasebackend.cpp180
-rw-r--r--src/libs/sqlite/sqlitedatabasebackend.h24
-rw-r--r--src/libs/sqlite/sqliteexception.cpp823
-rw-r--r--src/libs/sqlite/sqliteexception.h700
-rw-r--r--src/libs/sqlite/sqlitefunctionregistry.cpp50
-rw-r--r--src/libs/sqlite/sqlitefunctionregistry.h12
-rw-r--r--src/libs/sqlite/sqliteindex.h4
-rw-r--r--src/libs/sqlite/sqliteprogresshandler.h31
-rw-r--r--src/libs/sqlite/sqlitereadstatement.h3
-rw-r--r--src/libs/sqlite/sqlitesessionchangeset.cpp14
-rw-r--r--src/libs/sqlite/sqlitesessions.cpp11
-rw-r--r--src/libs/sqlite/sqlitesessions.h12
-rw-r--r--src/libs/sqlite/sqlitetable.h2
-rw-r--r--src/libs/sqlite/sqlitevalue.h4
-rw-r--r--src/libs/sqlite/sqlitewritestatement.h3
-rw-r--r--src/libs/sqlite/sqlstatementbuilder.cpp19
-rw-r--r--src/libs/sqlite/sqlstatementbuilder.h3
-rw-r--r--src/libs/sqlite/sqlstatementbuilderexception.h11
-rw-r--r--src/libs/sqlite/tableconstraints.h2
-rw-r--r--src/libs/utils/CMakeLists.txt2
-rw-r--r--src/libs/utils/filepath.cpp4
-rw-r--r--src/libs/utils/filesystemwatcher.cpp61
-rw-r--r--src/libs/utils/icon.cpp4
-rw-r--r--src/libs/utils/icon.h2
-rw-r--r--src/libs/utils/persistentsettings.cpp6
-rw-r--r--src/libs/utils/persistentsettings.h2
-rw-r--r--src/libs/utils/ranges.h95
-rw-r--r--src/libs/utils/smallstringlayout.h4
-rw-r--r--src/libs/utils/styleanimator.cpp (renamed from src/plugins/coreplugin/styleanimator.cpp)6
-rw-r--r--src/libs/utils/styleanimator.h (renamed from src/plugins/coreplugin/styleanimator.h)17
-rw-r--r--src/libs/utils/stylehelper.cpp110
-rw-r--r--src/libs/utils/stylehelper.h4
-rw-r--r--src/libs/utils/theme/theme.cpp3
-rw-r--r--src/libs/utils/theme/theme.h23
-rw-r--r--src/libs/utils/utils.qbs2
-rw-r--r--src/plugins/CMakeLists.txt4
-rw-r--r--src/plugins/coreplugin/CMakeLists.txt1
-rw-r--r--src/plugins/coreplugin/coreconstants.h2
-rw-r--r--src/plugins/coreplugin/coreplugin.qbs2
-rw-r--r--src/plugins/coreplugin/dialogs/settingsdialog.cpp22
-rw-r--r--src/plugins/coreplugin/icore.cpp2
-rw-r--r--src/plugins/coreplugin/mainwindow.cpp9
-rw-r--r--src/plugins/coreplugin/manhattanstyle.cpp813
-rw-r--r--src/plugins/coreplugin/manhattanstyle.h22
-rw-r--r--src/plugins/projectexplorer/projectwindow.cpp10
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt109
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc3
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp17
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h1
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp49
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h11
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp38
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h7
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp230
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h60
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx.pngbin0 -> 1505 bytes
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx@2x.pngbin0 -> 2594 bytes
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx_128.pngbin0 -> 3257 bytes
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractaction.cpp37
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractaction.h22
-rw-r--r--src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp7
-rw-r--r--src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp79
-rw-r--r--src/plugins/qmldesigner/components/componentcore/changestyleaction.h8
-rw-r--r--src/plugins/qmldesigner/components/componentcore/componentcore_constants.h7
-rw-r--r--src/plugins/qmldesigner/components/componentcore/crumblebar.cpp40
-rw-r--r--src/plugins/qmldesigner/components/componentcore/crumblebar.h36
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp383
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanager.h6
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designericons.cpp40
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designericons.h38
-rw-r--r--src/plugins/qmldesigner/components/componentcore/groupitemaction.cpp155
-rw-r--r--src/plugins/qmldesigner/components/componentcore/groupitemaction.h23
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp3
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h16
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp45
-rw-r--r--src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp152
-rw-r--r--src/plugins/qmldesigner/components/componentcore/qmleditormenu.h65
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.cpp27
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h144
-rw-r--r--src/plugins/qmldesigner/components/componentcore/viewmanager.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/zoomaction.cpp29
-rw-r--r--src/plugins/qmldesigner/components/componentcore/zoomaction.h3
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp7
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/backendmodel.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp6
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp5
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/delegates.cpp4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/delegates.h4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp262
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h23
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.h4
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp34
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h16
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp191
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h16
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp99
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h33
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp10
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h4
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp58
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h6
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp6
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp227
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h23
-rw-r--r--src/plugins/qmldesigner/components/createtexture.cpp55
-rw-r--r--src/plugins/qmldesigner/components/createtexture.h28
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp8
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditorconstants.h14
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp101
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.h7
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.cpp9
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp75
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dactions.h42
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp2
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp320
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h13
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp168
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.h16
-rw-r--r--src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp6
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp4
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp10
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp89
-rw-r--r--src/plugins/qmldesigner/components/formeditor/seekerslider.cpp138
-rw-r--r--src/plugins/qmldesigner/components/formeditor/seekerslider.h64
-rw-r--r--src/plugins/qmldesigner/components/formeditor/toolbox.cpp33
-rw-r--r--src/plugins/qmldesigner/components/formeditor/toolbox.h4
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocument.cpp8
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocumentview.cpp1
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.pngbin312 -> 677 bytes
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon@2x.pngbin346 -> 1333 bytes
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp65
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h1
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp39
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp7
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp45
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h12
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp26
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h7
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp12
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h2
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp164
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h7
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp142
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h28
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialutils.cpp71
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialutils.h20
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.h4
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp1
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditortransaction.h7
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp115
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h18
-rw-r--r--src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp8
-rw-r--r--src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp20
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp65
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp80
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.h3
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp23
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp100
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorwidget.h2
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.cpp50
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.h (renamed from src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h)12
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp107
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.h25
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp45
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h2
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp103
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h23
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp53
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp30
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h3
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp260
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h75
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp42
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h16
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp7
-rw-r--r--src/plugins/qmldesigner/components/resources/dockwidgets.css5
-rw-r--r--src/plugins/qmldesigner/components/resources/stylesheet.css41
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.cpp17
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.h4
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp63
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h2
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp82
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorview.h15
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp43
-rw-r--r--src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h11
-rw-r--r--src/plugins/qmldesigner/components/stateseditornew/stateseditorwidget.cpp2
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorview.cpp8
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp14
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/images/texture_ktx.pngbin0 -> 3706 bytes
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/images/texture_ktx@2x.pngbin0 -> 6625 bytes
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditor.qrc2
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp3
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.h4
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp5
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h5
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditortransaction.h1
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp12
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorview.h9
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp43
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineutils.h6
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp3
-rw-r--r--src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp7
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbar.cpp132
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbar.h17
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp614
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.h159
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp13
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp3
-rw-r--r--src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp45
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp58
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp45
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.h5
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp35
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h6
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachecollectorinterface.h10
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachedispatchcollector.h25
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.h6
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.cpp15
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.h6
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachegeneratorinterface.h2
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.cpp25
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.h30
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h51
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachestorageinterface.h3
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp5
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h6
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp50
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h28
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp26
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h19
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/synchronousimagecache.cpp33
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.cpp54
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.h31
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h96
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h7
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h5
-rw-r--r--src/plugins/qmldesigner/designercore/include/model.h5
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeinstanceview.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodemetainfo.h1
-rw-r--r--src/plugins/qmldesigner/designercore/include/propertymetainfo.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/synchronousimagecache.h3
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp28
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp225
-rw-r--r--src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/model/model.cpp19
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp26
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp1
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriterview.cpp6
-rw-r--r--src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp1
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp214
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp98
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h89
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h49
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp325
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h80
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h3
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp78
-rw-r--r--src/plugins/qmldesigner/designmodecontext.cpp17
-rw-r--r--src/plugins/qmldesigner/designmodecontext.h9
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp179
-rw-r--r--src/plugins/qmldesigner/designmodewidget.h23
-rw-r--r--src/plugins/qmldesigner/dynamiclicensecheck.h39
-rw-r--r--src/plugins/qmldesigner/puppetenvironmentbuilder.cpp25
-rw-r--r--src/plugins/qmldesigner/puppetenvironmentbuilder.h8
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h31
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp60
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.h1
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp121
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.h13
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.cpp136
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.h1
-rw-r--r--src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp8
-rw-r--r--src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp23
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-16.pngbin0 -> 315 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24.pngbin0 -> 514 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24@2x.pngbin0 -> 1846 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-engine-16.pngbin0 -> 363 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24.pngbin0 -> 472 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24@2x.pngbin0 -> 803 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-listener-16.pngbin0 -> 311 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24.pngbin0 -> 924 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24@2x.pngbin0 -> 1691 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-room-16.pngbin0 -> 276 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-room-24.pngbin0 -> 419 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/audio-room-24@2x.pngbin0 -> 878 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/default3d.pngbin0 -> 375 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/default3d16.pngbin0 -> 253 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/default3d@2x.pngbin0 -> 499 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-16.pngbin0 -> 319 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24.pngbin0 -> 664 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24@2x.pngbin0 -> 1536 bytes
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc18
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/quick.metainfo132
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.cpp22
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.h4
-rw-r--r--src/plugins/qmldesigner/studioplugin/studioplugin.metainfo1
-rw-r--r--src/plugins/qmldesigner/utils/asset.cpp99
-rw-r--r--src/plugins/qmldesigner/utils/asset.h21
-rw-r--r--src/plugins/qmldesigner/utils/designersettings.h82
-rw-r--r--src/plugins/qmldesigner/utils/filedownloader.cpp288
-rw-r--r--src/plugins/qmldesigner/utils/filedownloader.h91
-rw-r--r--src/plugins/qmldesigner/utils/fileextractor.cpp236
-rw-r--r--src/plugins/qmldesigner/utils/fileextractor.h92
-rw-r--r--src/plugins/qmldesigner/utils/hdrimage.cpp2
-rw-r--r--src/plugins/qmldesigner/utils/imageutils.cpp26
-rw-r--r--src/plugins/qmldesigner/utils/imageutils.h2
-rw-r--r--src/plugins/qmldesigner/utils/ktximage.cpp100
-rw-r--r--src/plugins/qmldesigner/utils/ktximage.h29
-rw-r--r--src/plugins/qmldesigner/utils/multifiledownloader.cpp132
-rw-r--r--src/plugins/qmldesigner/utils/multifiledownloader.h77
-rw-r--r--src/plugins/qmldesignerbase/CMakeLists.txt17
-rw-r--r--src/plugins/qmldesignerbase/QmlDesignerBase.json.in19
-rw-r--r--src/plugins/qmldesignerbase/qmldesignerbase_global.h14
-rw-r--r--src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp272
-rw-r--r--src/plugins/qmldesignerbase/qmldesignerbaseplugin.h74
-rw-r--r--src/plugins/qmldesignerbase/utils/designersettings.cpp (renamed from src/plugins/qmldesigner/utils/designersettings.cpp)3
-rw-r--r--src/plugins/qmldesignerbase/utils/designersettings.h88
-rw-r--r--src/plugins/qmldesignerbase/utils/qmlpuppetpaths.cpp70
-rw-r--r--src/plugins/qmldesignerbase/utils/qmlpuppetpaths.h20
-rw-r--r--src/plugins/qmldesignerbase/utils/studioquickwidget.cpp84
-rw-r--r--src/plugins/qmldesignerbase/utils/studioquickwidget.h52
-rw-r--r--src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp7
-rw-r--r--src/plugins/qmljseditor/qmljscomponentfromobjectdef.h7
-rw-r--r--src/plugins/qmlprojectmanager/CMakeLists.txt3
-rw-r--r--src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp63
-rw-r--r--src/plugins/qmlprojectmanager/qdslandingpage.cpp2
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp36
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.h3
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp15
-rw-r--r--src/plugins/qnx/qnxqtversion.cpp2
-rw-r--r--src/plugins/qnx/qnxqtversion.h2
-rw-r--r--src/plugins/qtsupport/baseqtversion.cpp7
-rw-r--r--src/plugins/qtsupport/baseqtversion.h2
-rw-r--r--src/plugins/qtsupport/qtversionfactory.h2
-rw-r--r--src/plugins/qtsupport/qtversionmanager.cpp6
-rw-r--r--src/plugins/studiowelcome/examplecheckout.cpp466
-rw-r--r--src/plugins/studiowelcome/examplecheckout.h134
-rw-r--r--src/plugins/studiowelcome/qdsnewdialog.cpp6
-rw-r--r--src/plugins/studiowelcome/qml/downloaddialog/main.qml2
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.cpp230
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.h34
-rw-r--r--src/tools/qml2puppet/CMakeLists.txt31
-rw-r--r--src/tools/qml2puppet/instances/nodeinstanceclientproxy.cpp8
-rw-r--r--src/tools/qml2puppet/qml2puppet/configcrashpad.h16
-rw-r--r--src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp25
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp13
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/quickitemnodeinstance.cpp9
-rw-r--r--src/tools/qml2puppet/qml2puppet/qmlbase.h19
-rw-r--r--src/tools/qml2puppet/qml2puppet/qmlpuppet.cpp23
-rw-r--r--src/tools/qml2puppet/qmlprivategate/qmlprivategate.cpp10
-rw-r--r--src/tools/qml2puppet/windows_application_icon/qml2puppet.rc30
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp1
m---------tests/unit/unittest/3rdparty/googletest0
-rw-r--r--tests/unit/unittest/CMakeLists.txt13
-rw-r--r--tests/unit/unittest/asynchronousexplicitimagecache-test.cpp77
-rw-r--r--tests/unit/unittest/asynchronousimagecache-test.cpp174
-rw-r--r--tests/unit/unittest/asynchronousimagefactory-test.cpp8
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp2
-rw-r--r--tests/unit/unittest/imagecachecollectormock.h2
-rw-r--r--tests/unit/unittest/imagecachedispatchcollector-test.cpp41
-rw-r--r--tests/unit/unittest/imagecachegenerator-test.cpp192
-rw-r--r--tests/unit/unittest/imagecachestorage-test.cpp223
-rw-r--r--tests/unit/unittest/mockimagecachegenerator.h2
-rw-r--r--tests/unit/unittest/mockimagecachestorage.h6
-rw-r--r--tests/unit/unittest/projectstoragepathwatcher-test.cpp317
-rw-r--r--tests/unit/unittest/projectstoragepathwatchermock.h2
-rw-r--r--tests/unit/unittest/projectstorageupdater-test.cpp1242
-rw-r--r--tests/unit/unittest/qmldocumentparser-test.cpp53
-rw-r--r--tests/unit/unittest/qmltypesparser-test.cpp199
-rw-r--r--tests/unit/unittest/smallstring-test.cpp18
-rw-r--r--tests/unit/unittest/sqlitedatabase-test.cpp53
-rw-r--r--tests/unit/unittest/sqlitedatabasebackend-test.cpp25
-rw-r--r--tests/unit/unittest/sqlitedatabasemock.h5
-rw-r--r--tests/unit/unittest/sqlitefunctionregistry-test.cpp41
-rw-r--r--tests/unit/unittest/sqlitetransaction-test.cpp34
-rw-r--r--tests/unit/unittest/sqlitewritestatementmock.h4
-rw-r--r--tests/unit/unittest/synchronousimagecache-test.cpp60
858 files changed, 30493 insertions, 12288 deletions
diff --git a/.gitignore-blame b/.gitignore-blame
new file mode 100644
index 0000000000..156cb8d806
--- /dev/null
+++ b/.gitignore-blame
@@ -0,0 +1,2 @@
+#bulk clang-format for src/plugins/qmldesigner/components/stateseditor/
+fef7852da53b84c7fb960b18fef8cda0b6663703
diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake
index 7b8a5c47f7..a50e9be59f 100644
--- a/cmake/QtCreatorAPI.cmake
+++ b/cmake/QtCreatorAPI.cmake
@@ -821,7 +821,7 @@ endfunction()
function(add_qtc_test name)
cmake_parse_arguments(_arg "GTEST;MANUALTEST;EXCLUDE_FROM_PRECHECK" "TIMEOUT"
- "DEFINES;DEPENDS;INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;SKIP_PCH;CONDITION" ${ARGN})
+ "DEFINES;DEPENDS;INCLUDES;SOURCES;EXPLICIT_MOC;SKIP_AUTOMOC;SKIP_PCH;CONDITION;PROPERTIES" ${ARGN})
if (${_arg_UNPARSED_ARGUMENTS})
message(FATAL_ERROR "add_qtc_test had unparsed arguments!")
@@ -881,6 +881,7 @@ function(add_qtc_test name)
VISIBILITY_INLINES_HIDDEN ON
BUILD_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_BUILD_RPATH}"
INSTALL_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_INSTALL_RPATH}"
+ ${_arg_PROPERTIES}
)
if (NOT _arg_SKIP_PCH)
enable_pch(${name})
diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf
index 4ae4dc1617..97e6fa7593 100644
--- a/doc/config/macros.qdocconf
+++ b/doc/config/macros.qdocconf
@@ -50,6 +50,7 @@ macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">"
macro.endfloat.HTML = "</div>"
macro.clearfloat.HTML = "<br style=\"clear: both\" />"
macro.emptyspan.HTML = "<span></span>"
+macro.externallink.HTML = "<a href=\"\1\" target=\"_blank\">\2</a>"
# Embed YouTube content by video ID - Example: \youtube dQw4w9WgXcQ
# Also requires a <ID>.jpg thumbnail for offline docs. In .qdocconf, add:
diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc
index 1e233283fd..315720275a 100644
--- a/doc/qtcreator/src/user-interface/creator-ui.qdoc
+++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc
@@ -299,6 +299,14 @@
style.
\endif
+ \if defined(qtdesignstudio)
+ The mode selector is hidden by default.
+
+ To show the mode selector, go to \uicontrol Views >
+ \uicontrol {Mode Selector Style} and select \uicontrol {Icons and Text}
+ or \uicontrol {Icons Only}.
+ \endif
+
You can use \QC in the following modes:
diff --git a/doc/qtdesignstudio/examples/doc/images/material-bundle-example.webp b/doc/qtdesignstudio/examples/doc/images/material-bundle-example.webp
new file mode 100644
index 0000000000..6dcab85469
--- /dev/null
+++ b/doc/qtdesignstudio/examples/doc/images/material-bundle-example.webp
Binary files differ
diff --git a/doc/qtdesignstudio/examples/doc/materialbundle.qdoc b/doc/qtdesignstudio/examples/doc/materialbundle.qdoc
new file mode 100644
index 0000000000..4f808b14f2
--- /dev/null
+++ b/doc/qtdesignstudio/examples/doc/materialbundle.qdoc
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page material-bundle-example.html
+ \ingroup studioexamples
+ \sa {Content Library}
+
+ \title Material Bundle
+ \brief Showcases the materials in \uicontrol {Content Library} and the real-time rendering
+ capabilities of \QDS.
+
+ \image material-bundle-example.webp
+
+ The \e{Material Bundle} example showcases the materials included in the \QDS
+ \uicontrol {Content Library} and the real-time 3D rendering capabilities of \QDS.
+
+ Run the project to:
+
+ \list
+ \li Select the material for two different meshes; all material bundle materials are available.
+ \li Navigate (rotate and zoom) with the mouse.
+ \li Choose between two different environment light options.
+ \endlist
+
+ \section1 The Material Bundle
+
+ The material bundle is included in \uicontrol {Content Library} which is
+ included in the \QDS Enterprise license. It contains a ready-made set of materials that you
+ can apply to your 3D models by dragging and dropping.
+
+ \image content-library.webp
+*/
diff --git a/doc/qtdesignstudio/images/3d-view-context-menu.png b/doc/qtdesignstudio/images/3d-view-context-menu.png
index c2e35e0019..5b08c568cb 100644
--- a/doc/qtdesignstudio/images/3d-view-context-menu.png
+++ b/doc/qtdesignstudio/images/3d-view-context-menu.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/assets-view-effect.png b/doc/qtdesignstudio/images/assets-view-effect.png
deleted file mode 100644
index b229f8ddb6..0000000000
--- a/doc/qtdesignstudio/images/assets-view-effect.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/content-library-add-texture.png b/doc/qtdesignstudio/images/content-library-add-texture.png
index ae820a39c8..75cc1bec0f 100644
--- a/doc/qtdesignstudio/images/content-library-add-texture.png
+++ b/doc/qtdesignstudio/images/content-library-add-texture.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/3d-background-color.png b/doc/qtdesignstudio/images/icons/3d-background-color.png
index d896907b30..37c68e632c 100644
--- a/doc/qtdesignstudio/images/icons/3d-background-color.png
+++ b/doc/qtdesignstudio/images/icons/3d-background-color.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/align-camera-on.png b/doc/qtdesignstudio/images/icons/align-camera-on.png
index 382a2ac6b3..a813dcaff7 100644
--- a/doc/qtdesignstudio/images/icons/align-camera-on.png
+++ b/doc/qtdesignstudio/images/icons/align-camera-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/align-view-on.png b/doc/qtdesignstudio/images/icons/align-view-on.png
index 3617416f6f..c7534664b1 100644
--- a/doc/qtdesignstudio/images/icons/align-view-on.png
+++ b/doc/qtdesignstudio/images/icons/align-view-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/apply-material.png b/doc/qtdesignstudio/images/icons/apply-material.png
deleted file mode 100644
index d0b347470b..0000000000
--- a/doc/qtdesignstudio/images/icons/apply-material.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/apply.png b/doc/qtdesignstudio/images/icons/apply.png
new file mode 100644
index 0000000000..baf72e3664
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/apply.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/arrowleft.png b/doc/qtdesignstudio/images/icons/arrowleft.png
index cdf5b0cc7c..d45ee098fe 100644
--- a/doc/qtdesignstudio/images/icons/arrowleft.png
+++ b/doc/qtdesignstudio/images/icons/arrowleft.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/arrowright.png b/doc/qtdesignstudio/images/icons/arrowright.png
index 627b2eccf9..b5a2c92dc4 100644
--- a/doc/qtdesignstudio/images/icons/arrowright.png
+++ b/doc/qtdesignstudio/images/icons/arrowright.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/back_one_frame.png b/doc/qtdesignstudio/images/icons/back_one_frame.png
index 69c93ebe3e..f7220acbf6 100644
--- a/doc/qtdesignstudio/images/icons/back_one_frame.png
+++ b/doc/qtdesignstudio/images/icons/back_one_frame.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/create_component.png b/doc/qtdesignstudio/images/icons/create_component.png
new file mode 100644
index 0000000000..75438ce56f
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/create_component.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/curve_editor.png b/doc/qtdesignstudio/images/icons/curve_editor.png
index bda4dc0095..35e019d931 100644
--- a/doc/qtdesignstudio/images/icons/curve_editor.png
+++ b/doc/qtdesignstudio/images/icons/curve_editor.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/easing-curve-linear-icon.png b/doc/qtdesignstudio/images/icons/easing-curve-linear-icon.png
index d6f56990d7..463a9bc038 100644
--- a/doc/qtdesignstudio/images/icons/easing-curve-linear-icon.png
+++ b/doc/qtdesignstudio/images/icons/easing-curve-linear-icon.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/easing-curve-spline-icon.png b/doc/qtdesignstudio/images/icons/easing-curve-spline-icon.png
index f6420d9174..c5328bed8a 100644
--- a/doc/qtdesignstudio/images/icons/easing-curve-spline-icon.png
+++ b/doc/qtdesignstudio/images/icons/easing-curve-spline-icon.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/easing-curve-step-icon.png b/doc/qtdesignstudio/images/icons/easing-curve-step-icon.png
index 5d6523f1c7..11be1b00de 100644
--- a/doc/qtdesignstudio/images/icons/easing-curve-step-icon.png
+++ b/doc/qtdesignstudio/images/icons/easing-curve-step-icon.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/edit.png b/doc/qtdesignstudio/images/icons/edit.png
index 28134d1887..f6ac1e0f1f 100644
--- a/doc/qtdesignstudio/images/icons/edit.png
+++ b/doc/qtdesignstudio/images/icons/edit.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/edit_component.png b/doc/qtdesignstudio/images/icons/edit_component.png
new file mode 100644
index 0000000000..071971b6bc
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/edit_component.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/edit_light_off.png b/doc/qtdesignstudio/images/icons/edit_light_off.png
new file mode 100644
index 0000000000..8b99d32d70
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/edit_light_off.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/edit_light_on.png b/doc/qtdesignstudio/images/icons/edit_light_on.png
new file mode 100644
index 0000000000..45be252860
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/edit_light_on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/fit_selected.png b/doc/qtdesignstudio/images/icons/fit_selected.png
new file mode 100644
index 0000000000..547a2fd603
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/fit_selected.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/forward_one_frame.png b/doc/qtdesignstudio/images/icons/forward_one_frame.png
index 0846f194e0..9a2d092e88 100644
--- a/doc/qtdesignstudio/images/icons/forward_one_frame.png
+++ b/doc/qtdesignstudio/images/icons/forward_one_frame.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/global.png b/doc/qtdesignstudio/images/icons/global.png
new file mode 100644
index 0000000000..3ff69a4506
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/global.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/global_record_keyframes.png b/doc/qtdesignstudio/images/icons/global_record_keyframes.png
index 64a28ca075..fb8d09dfaf 100644
--- a/doc/qtdesignstudio/images/icons/global_record_keyframes.png
+++ b/doc/qtdesignstudio/images/icons/global_record_keyframes.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/home.png b/doc/qtdesignstudio/images/icons/home.png
new file mode 100644
index 0000000000..8af251cf2c
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/home.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/move_off.png b/doc/qtdesignstudio/images/icons/move_off.png
new file mode 100644
index 0000000000..9d63a51cb0
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/move_off.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/navigator-arrowdown.png b/doc/qtdesignstudio/images/icons/navigator-arrowdown.png
index 894a29ca6f..31cb5a6b38 100644
--- a/doc/qtdesignstudio/images/icons/navigator-arrowdown.png
+++ b/doc/qtdesignstudio/images/icons/navigator-arrowdown.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/navigator-arrowup.png b/doc/qtdesignstudio/images/icons/navigator-arrowup.png
index 85f248f894..80d8f12cfb 100644
--- a/doc/qtdesignstudio/images/icons/navigator-arrowup.png
+++ b/doc/qtdesignstudio/images/icons/navigator-arrowup.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/orthographic_camera.png b/doc/qtdesignstudio/images/icons/orthographic_camera.png
new file mode 100644
index 0000000000..f041caf3d9
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/orthographic_camera.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-animation-on.png b/doc/qtdesignstudio/images/icons/particle-animation-on.png
index d240b34c2a..a752cb164c 100644
--- a/doc/qtdesignstudio/images/icons/particle-animation-on.png
+++ b/doc/qtdesignstudio/images/icons/particle-animation-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-pause.png b/doc/qtdesignstudio/images/icons/particle-pause.png
index 442a77211f..eb922eeedd 100644
--- a/doc/qtdesignstudio/images/icons/particle-pause.png
+++ b/doc/qtdesignstudio/images/icons/particle-pause.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-play.png b/doc/qtdesignstudio/images/icons/particle-play.png
index cc04c94897..aada059579 100644
--- a/doc/qtdesignstudio/images/icons/particle-play.png
+++ b/doc/qtdesignstudio/images/icons/particle-play.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-restart.png b/doc/qtdesignstudio/images/icons/particle-restart.png
index dc1c06bd49..b8d89b73e1 100644
--- a/doc/qtdesignstudio/images/icons/particle-restart.png
+++ b/doc/qtdesignstudio/images/icons/particle-restart.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particles-seek.png b/doc/qtdesignstudio/images/icons/particles-seek.png
index c6c76fe4ca..2ffc0bb266 100644
--- a/doc/qtdesignstudio/images/icons/particles-seek.png
+++ b/doc/qtdesignstudio/images/icons/particles-seek.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/perspective_camera.png b/doc/qtdesignstudio/images/icons/perspective_camera.png
new file mode 100644
index 0000000000..b3c602da76
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/perspective_camera.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/reset.png b/doc/qtdesignstudio/images/icons/reset.png
new file mode 100644
index 0000000000..b7de014ceb
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/reset.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/rotate_off.png b/doc/qtdesignstudio/images/icons/rotate_off.png
new file mode 100644
index 0000000000..444262b487
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/rotate_off.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/scale_off.png b/doc/qtdesignstudio/images/icons/scale_off.png
new file mode 100644
index 0000000000..553dfa4a5e
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/scale_off.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/select_group.png b/doc/qtdesignstudio/images/icons/select_group.png
new file mode 100644
index 0000000000..3075d37344
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/select_group.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/select_item.png b/doc/qtdesignstudio/images/icons/select_item.png
new file mode 100644
index 0000000000..717c54c41c
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/select_item.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/settings.png b/doc/qtdesignstudio/images/icons/settings.png
new file mode 100644
index 0000000000..8f7f59714d
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/settings.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/start_playback.png b/doc/qtdesignstudio/images/icons/start_playback.png
index 0cf0865c48..9f7194bf16 100644
--- a/doc/qtdesignstudio/images/icons/start_playback.png
+++ b/doc/qtdesignstudio/images/icons/start_playback.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/to_first_frame.png b/doc/qtdesignstudio/images/icons/to_first_frame.png
index 910b856638..c9b9ed4ec0 100644
--- a/doc/qtdesignstudio/images/icons/to_first_frame.png
+++ b/doc/qtdesignstudio/images/icons/to_first_frame.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/to_last_frame.png b/doc/qtdesignstudio/images/icons/to_last_frame.png
index d6bc429196..9dfa631165 100644
--- a/doc/qtdesignstudio/images/icons/to_last_frame.png
+++ b/doc/qtdesignstudio/images/icons/to_last_frame.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/visibilityon.png b/doc/qtdesignstudio/images/icons/visibilityon.png
index 8fc4ca3c36..802096a62e 100644
--- a/doc/qtdesignstudio/images/icons/visibilityon.png
+++ b/doc/qtdesignstudio/images/icons/visibilityon.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/zoomAll.png b/doc/qtdesignstudio/images/icons/zoomAll.png
index 7917d5253c..b7c5b4d7eb 100644
--- a/doc/qtdesignstudio/images/icons/zoomAll.png
+++ b/doc/qtdesignstudio/images/icons/zoomAll.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/zoomIn.png b/doc/qtdesignstudio/images/icons/zoomIn.png
index dae425382d..520719bfec 100644
--- a/doc/qtdesignstudio/images/icons/zoomIn.png
+++ b/doc/qtdesignstudio/images/icons/zoomIn.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/zoomOut.png b/doc/qtdesignstudio/images/icons/zoomOut.png
index 3e889fded1..635475e771 100644
--- a/doc/qtdesignstudio/images/icons/zoomOut.png
+++ b/doc/qtdesignstudio/images/icons/zoomOut.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/zoomSelection.png b/doc/qtdesignstudio/images/icons/zoomSelection.png
index 407e21d271..313bceec9a 100644
--- a/doc/qtdesignstudio/images/icons/zoomSelection.png
+++ b/doc/qtdesignstudio/images/icons/zoomSelection.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/loader3d-navigator.png b/doc/qtdesignstudio/images/loader3d-navigator.png
index 0c049a6146..4c9345d462 100644
--- a/doc/qtdesignstudio/images/loader3d-navigator.png
+++ b/doc/qtdesignstudio/images/loader3d-navigator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/material-copy-properties.png b/doc/qtdesignstudio/images/material-copy-properties.png
index aae3020929..d454685a85 100644
--- a/doc/qtdesignstudio/images/material-copy-properties.png
+++ b/doc/qtdesignstudio/images/material-copy-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/navigator-material-texture.png b/doc/qtdesignstudio/images/navigator-material-texture.png
index 4256e959c6..849625e1eb 100644
--- a/doc/qtdesignstudio/images/navigator-material-texture.png
+++ b/doc/qtdesignstudio/images/navigator-material-texture.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/navigator-show-all-loader.png b/doc/qtdesignstudio/images/navigator-show-all-loader.png
index 2052be66b3..40f3fe0866 100644
--- a/doc/qtdesignstudio/images/navigator-show-all-loader.png
+++ b/doc/qtdesignstudio/images/navigator-show-all-loader.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/new-effect-file.png b/doc/qtdesignstudio/images/new-effect-file.png
deleted file mode 100644
index 521c36152c..0000000000
--- a/doc/qtdesignstudio/images/new-effect-file.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/qml-shapes-rectangle.png b/doc/qtdesignstudio/images/qml-shapes-rectangle.png
index a2f5eaee0f..0dde7e33f6 100644
--- a/doc/qtdesignstudio/images/qml-shapes-rectangle.png
+++ b/doc/qtdesignstudio/images/qml-shapes-rectangle.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qml-shapes.png b/doc/qtdesignstudio/images/qml-shapes.png
index cc0f2c3324..6aaa46a07e 100644
--- a/doc/qtdesignstudio/images/qml-shapes.png
+++ b/doc/qtdesignstudio/images/qml-shapes.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-alignment.png b/doc/qtdesignstudio/images/qmldesigner-alignment.png
index 70ad846850..ffc4109c57 100644
--- a/doc/qtdesignstudio/images/qmldesigner-alignment.png
+++ b/doc/qtdesignstudio/images/qmldesigner-alignment.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-anchors.png b/doc/qtdesignstudio/images/qmldesigner-anchors.png
index 3b4d7d632d..6038027d70 100644
--- a/doc/qtdesignstudio/images/qmldesigner-anchors.png
+++ b/doc/qtdesignstudio/images/qmldesigner-anchors.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-bindings.png b/doc/qtdesignstudio/images/qmldesigner-bindings.png
index ad7dde04b7..3ac0964f76 100644
--- a/doc/qtdesignstudio/images/qmldesigner-bindings.png
+++ b/doc/qtdesignstudio/images/qmldesigner-bindings.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-breadcrumbs.png b/doc/qtdesignstudio/images/qmldesigner-breadcrumbs.png
index 2745134bd3..d57d36b9d9 100644
--- a/doc/qtdesignstudio/images/qmldesigner-breadcrumbs.png
+++ b/doc/qtdesignstudio/images/qmldesigner-breadcrumbs.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-button.png b/doc/qtdesignstudio/images/qmldesigner-button.png
index 6af7d03ee3..bd8720a021 100644
--- a/doc/qtdesignstudio/images/qmldesigner-button.png
+++ b/doc/qtdesignstudio/images/qmldesigner-button.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-canvas-color.png b/doc/qtdesignstudio/images/qmldesigner-canvas-color.png
index af6ce61224..6baef3eb90 100644
--- a/doc/qtdesignstudio/images/qmldesigner-canvas-color.png
+++ b/doc/qtdesignstudio/images/qmldesigner-canvas-color.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-connections.png b/doc/qtdesignstudio/images/qmldesigner-connections.png
index 827359bf49..605dc83578 100644
--- a/doc/qtdesignstudio/images/qmldesigner-connections.png
+++ b/doc/qtdesignstudio/images/qmldesigner-connections.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-dynamicprops.png b/doc/qtdesignstudio/images/qmldesigner-dynamicprops.png
index 460be93f2b..565dc26b0e 100644
--- a/doc/qtdesignstudio/images/qmldesigner-dynamicprops.png
+++ b/doc/qtdesignstudio/images/qmldesigner-dynamicprops.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-editing-components.png b/doc/qtdesignstudio/images/qmldesigner-editing-components.png
deleted file mode 100644
index 6184d706dd..0000000000
--- a/doc/qtdesignstudio/images/qmldesigner-editing-components.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-editing-components.webp b/doc/qtdesignstudio/images/qmldesigner-editing-components.webp
new file mode 100644
index 0000000000..9b725ae546
--- /dev/null
+++ b/doc/qtdesignstudio/images/qmldesigner-editing-components.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-element-size.png b/doc/qtdesignstudio/images/qmldesigner-element-size.png
deleted file mode 100644
index 550eb01dfa..0000000000
--- a/doc/qtdesignstudio/images/qmldesigner-element-size.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-element-size.webp b/doc/qtdesignstudio/images/qmldesigner-element-size.webp
new file mode 100644
index 0000000000..90d61b5fa4
--- /dev/null
+++ b/doc/qtdesignstudio/images/qmldesigner-element-size.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-export-item.png b/doc/qtdesignstudio/images/qmldesigner-export-item.png
index 567a9c5fa4..62e7422208 100644
--- a/doc/qtdesignstudio/images/qmldesigner-export-item.png
+++ b/doc/qtdesignstudio/images/qmldesigner-export-item.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-form-editor-move-cursor.png b/doc/qtdesignstudio/images/qmldesigner-form-editor-move-cursor.png
index 5aa3a6c3fb..018a94c88f 100644
--- a/doc/qtdesignstudio/images/qmldesigner-form-editor-move-cursor.png
+++ b/doc/qtdesignstudio/images/qmldesigner-form-editor-move-cursor.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-form-editor.png b/doc/qtdesignstudio/images/qmldesigner-form-editor.png
index b042afe44e..f32f6965ba 100644
--- a/doc/qtdesignstudio/images/qmldesigner-form-editor.png
+++ b/doc/qtdesignstudio/images/qmldesigner-form-editor.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-mcu-support.png b/doc/qtdesignstudio/images/qmldesigner-mcu-support.png
index a9981017fb..98ee56b2a3 100644
--- a/doc/qtdesignstudio/images/qmldesigner-mcu-support.png
+++ b/doc/qtdesignstudio/images/qmldesigner-mcu-support.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-navigator-arrows.png b/doc/qtdesignstudio/images/qmldesigner-navigator-arrows.png
index e1fd5283bf..45754e4519 100644
--- a/doc/qtdesignstudio/images/qmldesigner-navigator-arrows.png
+++ b/doc/qtdesignstudio/images/qmldesigner-navigator-arrows.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-navigator.png b/doc/qtdesignstudio/images/qmldesigner-navigator.png
index ace30596e2..8ec9cd0ddd 100644
--- a/doc/qtdesignstudio/images/qmldesigner-navigator.png
+++ b/doc/qtdesignstudio/images/qmldesigner-navigator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-preview-size.png b/doc/qtdesignstudio/images/qmldesigner-preview-size.png
index d6a481ef73..1a4a5e01ee 100644
--- a/doc/qtdesignstudio/images/qmldesigner-preview-size.png
+++ b/doc/qtdesignstudio/images/qmldesigner-preview-size.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qmldesigner-tutorial-user-icon.png b/doc/qtdesignstudio/images/qmldesigner-tutorial-user-icon.png
index a115cf8fbf..7350ce4339 100644
--- a/doc/qtdesignstudio/images/qmldesigner-tutorial-user-icon.png
+++ b/doc/qtdesignstudio/images/qmldesigner-tutorial-user-icon.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.png b/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.png
deleted file mode 100644
index c0bd0f897e..0000000000
--- a/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp b/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp
new file mode 100644
index 0000000000..ee6d6f54aa
--- /dev/null
+++ b/doc/qtdesignstudio/images/qtcreator-workspace-attaching-views.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtds-running-emulator.png b/doc/qtdesignstudio/images/qtds-running-emulator.png
index ecd3054db3..b8d7470166 100644
--- a/doc/qtdesignstudio/images/qtds-running-emulator.png
+++ b/doc/qtdesignstudio/images/qtds-running-emulator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-annotations.png b/doc/qtdesignstudio/images/qtquick-annotations.png
index 4fc9ddff3d..114cf80ada 100644
--- a/doc/qtdesignstudio/images/qtquick-annotations.png
+++ b/doc/qtdesignstudio/images/qtquick-annotations.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-assets-tab.png b/doc/qtdesignstudio/images/qtquick-assets-tab.png
index a7e02bab9e..11c4fe54b4 100644
--- a/doc/qtdesignstudio/images/qtquick-assets-tab.png
+++ b/doc/qtdesignstudio/images/qtquick-assets-tab.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-components-context-menu-hide.png b/doc/qtdesignstudio/images/qtquick-components-context-menu-hide.png
index 61ee2fe02d..1681bd2fa3 100644
--- a/doc/qtdesignstudio/images/qtquick-components-context-menu-hide.png
+++ b/doc/qtdesignstudio/images/qtquick-components-context-menu-hide.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-components-context-menu.png b/doc/qtdesignstudio/images/qtquick-components-context-menu.png
index 0b163fd3d2..d333456149 100644
--- a/doc/qtdesignstudio/images/qtquick-components-context-menu.png
+++ b/doc/qtdesignstudio/images/qtquick-components-context-menu.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-components-tab-add.png b/doc/qtdesignstudio/images/qtquick-components-tab-add.png
index 3e3d0ccf98..e208d97203 100644
--- a/doc/qtdesignstudio/images/qtquick-components-tab-add.png
+++ b/doc/qtdesignstudio/images/qtquick-components-tab-add.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-components-tab.png b/doc/qtdesignstudio/images/qtquick-components-tab.png
index b2011c9c77..4ee36abf04 100644
--- a/doc/qtdesignstudio/images/qtquick-components-tab.png
+++ b/doc/qtdesignstudio/images/qtquick-components-tab.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-custom-properties.png b/doc/qtdesignstudio/images/qtquick-custom-properties.png
index ce9fc5d400..ea5567fa06 100644
--- a/doc/qtdesignstudio/images/qtquick-custom-properties.png
+++ b/doc/qtdesignstudio/images/qtquick-custom-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-button-types.png b/doc/qtdesignstudio/images/qtquick-designer-button-types.png
index 5cb551dfd9..3d07baec39 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-button-types.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-button-types.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-image-type.png b/doc/qtdesignstudio/images/qtquick-designer-image-type.png
index 0d09670693..5817e48834 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-image-type.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-image-type.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-indicator-types.png b/doc/qtdesignstudio/images/qtquick-designer-indicator-types.png
index 4fd045bb0d..67a03eab94 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-indicator-types.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-indicator-types.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-qtquickcontrols-types.png b/doc/qtdesignstudio/images/qtquick-designer-qtquickcontrols-types.png
index 4cb28e50e2..bf089813e6 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-qtquickcontrols-types.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-qtquickcontrols-types.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-rotating-items.png b/doc/qtdesignstudio/images/qtquick-designer-rotating-items.png
index b9b8936240..f20669be4e 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-rotating-items.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-rotating-items.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-scaling-items.png b/doc/qtdesignstudio/images/qtquick-designer-scaling-items.png
index 291b4e9e68..891915dae8 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-scaling-items.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-scaling-items.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-selector-types.png b/doc/qtdesignstudio/images/qtquick-designer-selector-types.png
index 759eb79d81..84e9758430 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-selector-types.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-selector-types.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-designer-stacked-view.png b/doc/qtdesignstudio/images/qtquick-designer-stacked-view.png
index 5ede90aed6..ab9756a98d 100644
--- a/doc/qtdesignstudio/images/qtquick-designer-stacked-view.png
+++ b/doc/qtdesignstudio/images/qtquick-designer-stacked-view.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-library-context-menu.png b/doc/qtdesignstudio/images/qtquick-library-context-menu.png
index fa9a293e37..f611ea6f1c 100644
--- a/doc/qtdesignstudio/images/qtquick-library-context-menu.png
+++ b/doc/qtdesignstudio/images/qtquick-library-context-menu.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-positioner-column-properties.png b/doc/qtdesignstudio/images/qtquick-positioner-column-properties.png
index b025b5fe58..2bf25d425c 100644
--- a/doc/qtdesignstudio/images/qtquick-positioner-column-properties.png
+++ b/doc/qtdesignstudio/images/qtquick-positioner-column-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-positioner-flow-properties.png b/doc/qtdesignstudio/images/qtquick-positioner-flow-properties.png
index c027a81817..943e66b76a 100644
--- a/doc/qtdesignstudio/images/qtquick-positioner-flow-properties.png
+++ b/doc/qtdesignstudio/images/qtquick-positioner-flow-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-positioner-grid-properties.png b/doc/qtdesignstudio/images/qtquick-positioner-grid-properties.png
index 4588e39a23..ec6dab0163 100644
--- a/doc/qtdesignstudio/images/qtquick-positioner-grid-properties.png
+++ b/doc/qtdesignstudio/images/qtquick-positioner-grid-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qtquick-text-editor.png b/doc/qtdesignstudio/images/qtquick-text-editor.png
index 0d1acf87f0..3597860c35 100644
--- a/doc/qtdesignstudio/images/qtquick-text-editor.png
+++ b/doc/qtdesignstudio/images/qtquick-text-editor.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/repeater3d-listmodel-navigator.png b/doc/qtdesignstudio/images/repeater3d-listmodel-navigator.png
index 0f3f768e14..f4b3093bbb 100644
--- a/doc/qtdesignstudio/images/repeater3d-listmodel-navigator.png
+++ b/doc/qtdesignstudio/images/repeater3d-listmodel-navigator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-2d-effects.png b/doc/qtdesignstudio/images/studio-2d-effects.png
index ebf2106280..7fd69ea805 100644
--- a/doc/qtdesignstudio/images/studio-2d-effects.png
+++ b/doc/qtdesignstudio/images/studio-2d-effects.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-area-light.png b/doc/qtdesignstudio/images/studio-3d-area-light.png
deleted file mode 100644
index 24fbfcbe33..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-area-light.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-area-light.webp b/doc/qtdesignstudio/images/studio-3d-area-light.webp
new file mode 100644
index 0000000000..9dee95bcaf
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-area-light.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-directional-light.png b/doc/qtdesignstudio/images/studio-3d-directional-light.png
deleted file mode 100644
index f739e5bba4..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-directional-light.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-directional-light.webp b/doc/qtdesignstudio/images/studio-3d-directional-light.webp
new file mode 100644
index 0000000000..4709c8642a
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-directional-light.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png b/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png
deleted file mode 100644
index 788b498991..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.webp b/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.webp
new file mode 100644
index 0000000000..d0a13907e5
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-move.png b/doc/qtdesignstudio/images/studio-3d-editor-move.png
deleted file mode 100644
index 1e8be3f865..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-editor-move.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-move.webp b/doc/qtdesignstudio/images/studio-3d-editor-move.webp
new file mode 100644
index 0000000000..d2ff9b9aac
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-editor-move.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-rotate.png b/doc/qtdesignstudio/images/studio-3d-editor-rotate.png
deleted file mode 100644
index b6c4ce167a..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-editor-rotate.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-rotate.webp b/doc/qtdesignstudio/images/studio-3d-editor-rotate.webp
new file mode 100644
index 0000000000..7cd8fe1bf6
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-editor-rotate.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-scale.png b/doc/qtdesignstudio/images/studio-3d-editor-scale.png
deleted file mode 100644
index 19d4258275..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-editor-scale.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-scale.webp b/doc/qtdesignstudio/images/studio-3d-editor-scale.webp
new file mode 100644
index 0000000000..be0270d34b
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-editor-scale.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor.png b/doc/qtdesignstudio/images/studio-3d-editor.png
deleted file mode 100644
index a62a6deb76..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-editor.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor.webp b/doc/qtdesignstudio/images/studio-3d-editor.webp
new file mode 100644
index 0000000000..903ad69b25
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-editor.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-effects.png b/doc/qtdesignstudio/images/studio-3d-effects.png
index e47cab97aa..485976b0f7 100644
--- a/doc/qtdesignstudio/images/studio-3d-effects.png
+++ b/doc/qtdesignstudio/images/studio-3d-effects.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-instancing-instance-list.png b/doc/qtdesignstudio/images/studio-3d-instancing-instance-list.png
index f7bb9f8f1f..ff2593162e 100644
--- a/doc/qtdesignstudio/images/studio-3d-instancing-instance-list.png
+++ b/doc/qtdesignstudio/images/studio-3d-instancing-instance-list.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-models.png b/doc/qtdesignstudio/images/studio-3d-models.png
index d7c0708672..de4f65d5e8 100644
--- a/doc/qtdesignstudio/images/studio-3d-models.png
+++ b/doc/qtdesignstudio/images/studio-3d-models.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-particles-fire-assets.png b/doc/qtdesignstudio/images/studio-3d-particles-fire-assets.png
index 733f61bc12..496db801e5 100644
--- a/doc/qtdesignstudio/images/studio-3d-particles-fire-assets.png
+++ b/doc/qtdesignstudio/images/studio-3d-particles-fire-assets.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-particles-fire-components.png b/doc/qtdesignstudio/images/studio-3d-particles-fire-components.png
index e0f112b33b..f859f9f636 100644
--- a/doc/qtdesignstudio/images/studio-3d-particles-fire-components.png
+++ b/doc/qtdesignstudio/images/studio-3d-particles-fire-components.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-particles-fire-emitter1.png b/doc/qtdesignstudio/images/studio-3d-particles-fire-emitter1.png
index 6972f27021..37a7b12ea7 100644
--- a/doc/qtdesignstudio/images/studio-3d-particles-fire-emitter1.png
+++ b/doc/qtdesignstudio/images/studio-3d-particles-fire-emitter1.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png b/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png
index dd0ce67de4..d27331fe73 100644
--- a/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png
+++ b/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-point-light.png b/doc/qtdesignstudio/images/studio-3d-point-light.png
deleted file mode 100644
index a5eb5a888a..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-point-light.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-point-light.webp b/doc/qtdesignstudio/images/studio-3d-point-light.webp
new file mode 100644
index 0000000000..e4cbfe19d7
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-point-light.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-spot-light.png b/doc/qtdesignstudio/images/studio-3d-spot-light.png
deleted file mode 100644
index 7ebc673e18..0000000000
--- a/doc/qtdesignstudio/images/studio-3d-spot-light.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-spot-light.webp b/doc/qtdesignstudio/images/studio-3d-spot-light.webp
new file mode 100644
index 0000000000..347675a60e
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-3d-spot-light.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-animation.png b/doc/qtdesignstudio/images/studio-animation.png
index c8ef86cfa8..b08a6deed8 100644
--- a/doc/qtdesignstudio/images/studio-animation.png
+++ b/doc/qtdesignstudio/images/studio-animation.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-connection-view-properties.png b/doc/qtdesignstudio/images/studio-connection-view-properties.png
index 6ce6c3479f..ddfade2227 100644
--- a/doc/qtdesignstudio/images/studio-connection-view-properties.png
+++ b/doc/qtdesignstudio/images/studio-connection-view-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-custom-material-uniform-properties.png b/doc/qtdesignstudio/images/studio-custom-material-uniform-properties.png
index b69d456182..5a20aa65c8 100644
--- a/doc/qtdesignstudio/images/studio-custom-material-uniform-properties.png
+++ b/doc/qtdesignstudio/images/studio-custom-material-uniform-properties.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-design-mode-states-timeline.png b/doc/qtdesignstudio/images/studio-design-mode-states-timeline.png
index 3b2b8b173a..71356b5020 100644
--- a/doc/qtdesignstudio/images/studio-design-mode-states-timeline.png
+++ b/doc/qtdesignstudio/images/studio-design-mode-states-timeline.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-design-mode.png b/doc/qtdesignstudio/images/studio-design-mode.png
deleted file mode 100644
index e4a03c583a..0000000000
--- a/doc/qtdesignstudio/images/studio-design-mode.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-design-mode.webp b/doc/qtdesignstudio/images/studio-design-mode.webp
new file mode 100644
index 0000000000..c739d88f99
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-design-mode.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-dial.png b/doc/qtdesignstudio/images/studio-dial.png
index 3d7b75fa89..f6bf5d4501 100644
--- a/doc/qtdesignstudio/images/studio-dial.png
+++ b/doc/qtdesignstudio/images/studio-dial.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-editing-3d-scenes.png b/doc/qtdesignstudio/images/studio-editing-3d-scenes.png
deleted file mode 100644
index 8566b6171c..0000000000
--- a/doc/qtdesignstudio/images/studio-editing-3d-scenes.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-flipable.png b/doc/qtdesignstudio/images/studio-flipable.png
index c9de7404b2..8122416239 100644
--- a/doc/qtdesignstudio/images/studio-flipable.png
+++ b/doc/qtdesignstudio/images/studio-flipable.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.png b/doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.png
index 414cd705a6..56cd080e30 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-and-checkbox3.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-and.png b/doc/qtdesignstudio/images/studio-logic-helper-and.png
index 0d32952fdd..63f2e454af 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-and.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-and.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-bidirectional-binding.png b/doc/qtdesignstudio/images/studio-logic-helper-bidirectional-binding.png
index 39ca5af0f3..596eb86068 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-bidirectional-binding.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-bidirectional-binding.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-input.png b/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-input.png
index 06e7e4c0cd..92858fb429 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-input.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-input.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-string-mapper-input.png b/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-string-mapper-input.png
index 0a21eaccd5..e6bff57d9b 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-string-mapper-input.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-minmax-mapper-string-mapper-input.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-not-check-box.png b/doc/qtdesignstudio/images/studio-logic-helper-not-check-box.png
index 9411437e9b..cfe4f0e50d 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-not-check-box.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-not-check-box.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-not.png b/doc/qtdesignstudio/images/studio-logic-helper-not.png
index 05ad631b62..5966a470bb 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-not.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-not.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-range-mapper-inputmin.png b/doc/qtdesignstudio/images/studio-logic-helper-range-mapper-inputmin.png
index 2144e58f92..d91b2eebb3 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-range-mapper-inputmin.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-range-mapper-inputmin.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-logic-helper-string-mapper-text.png b/doc/qtdesignstudio/images/studio-logic-helper-string-mapper-text.png
index 43a240fc5b..84754a44d1 100644
--- a/doc/qtdesignstudio/images/studio-logic-helper-string-mapper-text.png
+++ b/doc/qtdesignstudio/images/studio-logic-helper-string-mapper-text.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-navigator-view3d.png b/doc/qtdesignstudio/images/studio-navigator-view3d.png
index 1fa65c10dc..92ce85e965 100644
--- a/doc/qtdesignstudio/images/studio-navigator-view3d.png
+++ b/doc/qtdesignstudio/images/studio-navigator-view3d.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-qml-imports-slconnector.png b/doc/qtdesignstudio/images/studio-qml-imports-slconnector.png
index 03241cea9b..a94176e971 100644
--- a/doc/qtdesignstudio/images/studio-qml-imports-slconnector.png
+++ b/doc/qtdesignstudio/images/studio-qml-imports-slconnector.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-custom-effect-navigator.png b/doc/qtdesignstudio/images/studio-qtquick-3d-custom-effect-navigator.png
index 21a34f1e1a..9f3fd2f272 100644
--- a/doc/qtdesignstudio/images/studio-qtquick-3d-custom-effect-navigator.png
+++ b/doc/qtdesignstudio/images/studio-qtquick-3d-custom-effect-navigator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.png b/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.png
deleted file mode 100644
index 627561fd59..0000000000
--- a/doc/qtdesignstudio/images/studio-qtquick-3d-default-material.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-qtquick-3d-material.png b/doc/qtdesignstudio/images/studio-qtquick-3d-material.png
deleted file mode 100644
index 597f47e22b..0000000000
--- a/doc/qtdesignstudio/images/studio-qtquick-3d-material.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-shapes.png b/doc/qtdesignstudio/images/studio-shapes.png
index 9ac71d7669..b9fb24c88d 100644
--- a/doc/qtdesignstudio/images/studio-shapes.png
+++ b/doc/qtdesignstudio/images/studio-shapes.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.png b/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.png
deleted file mode 100644
index 3bea1a7a6b..0000000000
--- a/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.webp b/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.webp
new file mode 100644
index 0000000000..f8734e98de
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-timeline-keyframe-track-colors.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-no-tracks.png b/doc/qtdesignstudio/images/studio-timeline-no-tracks.png
deleted file mode 100644
index 85a03a00b0..0000000000
--- a/doc/qtdesignstudio/images/studio-timeline-no-tracks.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-no-tracks.webp b/doc/qtdesignstudio/images/studio-timeline-no-tracks.webp
new file mode 100644
index 0000000000..543fa3274f
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-timeline-no-tracks.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.png b/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.png
deleted file mode 100644
index d116d43e36..0000000000
--- a/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.webp b/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.webp
new file mode 100644
index 0000000000..183a344812
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-timeline-with-empty-tracks.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-with-tracks.png b/doc/qtdesignstudio/images/studio-timeline-with-tracks.png
deleted file mode 100644
index 060db8aa2b..0000000000
--- a/doc/qtdesignstudio/images/studio-timeline-with-tracks.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline-with-tracks.webp b/doc/qtdesignstudio/images/studio-timeline-with-tracks.webp
new file mode 100644
index 0000000000..55827cc9e5
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-timeline-with-tracks.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline.png b/doc/qtdesignstudio/images/studio-timeline.png
deleted file mode 100644
index 18e85ca5c1..0000000000
--- a/doc/qtdesignstudio/images/studio-timeline.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-timeline.webp b/doc/qtdesignstudio/images/studio-timeline.webp
new file mode 100644
index 0000000000..4c786bc6a8
--- /dev/null
+++ b/doc/qtdesignstudio/images/studio-timeline.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/timeline-per-property-recording.png b/doc/qtdesignstudio/images/timeline-per-property-recording.png
deleted file mode 100644
index 7daa337aa1..0000000000
--- a/doc/qtdesignstudio/images/timeline-per-property-recording.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/timeline-per-property-recording.webp b/doc/qtdesignstudio/images/timeline-per-property-recording.webp
new file mode 100644
index 0000000000..19c705e5d7
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-per-property-recording.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/timeline-states.png b/doc/qtdesignstudio/images/timeline-states.png
deleted file mode 100644
index 0ef1f7da95..0000000000
--- a/doc/qtdesignstudio/images/timeline-states.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtdesignstudio/images/timeline-states.webp b/doc/qtdesignstudio/images/timeline-states.webp
new file mode 100644
index 0000000000..ccaabfc6dc
--- /dev/null
+++ b/doc/qtdesignstudio/images/timeline-states.webp
Binary files differ
diff --git a/doc/qtdesignstudio/images/toolbar-show-live-preview.png b/doc/qtdesignstudio/images/toolbar-show-live-preview.png
index b942fcf5c1..b8741f9d41 100644
--- a/doc/qtdesignstudio/images/toolbar-show-live-preview.png
+++ b/doc/qtdesignstudio/images/toolbar-show-live-preview.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-change-file.png b/doc/qtdesignstudio/images/web-navigation-change-file.png
new file mode 100644
index 0000000000..efa9131d3e
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-change-file.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-column-layout.png b/doc/qtdesignstudio/images/web-navigation-column-layout.png
new file mode 100644
index 0000000000..dde2bc1c2b
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-column-layout.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-components-2.png b/doc/qtdesignstudio/images/web-navigation-components-2.png
new file mode 100644
index 0000000000..d8a02960bf
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-components-2.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-components.png b/doc/qtdesignstudio/images/web-navigation-components.png
new file mode 100644
index 0000000000..602e0b9e4c
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-components.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-new-file.png b/doc/qtdesignstudio/images/web-navigation-new-file.png
new file mode 100644
index 0000000000..ff08d0c50b
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-new-file.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-page-components.png b/doc/qtdesignstudio/images/web-navigation-page-components.png
new file mode 100644
index 0000000000..7cfde0fa19
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-page-components.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-page-margins.png b/doc/qtdesignstudio/images/web-navigation-page-margins.png
new file mode 100644
index 0000000000..b307f07e60
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-page-margins.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-size-binding-2.png b/doc/qtdesignstudio/images/web-navigation-size-binding-2.png
new file mode 100644
index 0000000000..12bf6b9903
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-size-binding-2.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/web-navigation-size-binding.png b/doc/qtdesignstudio/images/web-navigation-size-binding.png
new file mode 100644
index 0000000000..b7461581eb
--- /dev/null
+++ b/doc/qtdesignstudio/images/web-navigation-size-binding.png
Binary files differ
diff --git a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
index 088e133d8b..d2a1a1760d 100644
--- a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
@@ -238,9 +238,9 @@
pressed down.
\image qmldesigner-borderimage-bindings1.png "Inactive state when condition"
\li Press \key {Ctrl+S} to save the button.
- \li Select the \inlineimage icons/live_preview.png
- (\uicontrol {Show Live Preview}) button to check how the
- button behaves when you click it. You can drag the preview
+ \li Select the
+ \uicontrol {Live Preview} button on the top toolbar to see how the
+ button behaves when you select it. Drag the preview
window borders to see what happens when you resize the
component.
\endlist
diff --git a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
index 5c48c80972..1d6b1cd08a 100644
--- a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
+++ b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
@@ -63,7 +63,7 @@
\li Go to Implementation
\li \l{Using UI Files}
\row
- \li Go into Component
+ \li Edit Component
\li \l{Moving Within Components}
\endtable
//! [context-menu]
diff --git a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
index ada17fae01..0cdced17c7 100644
--- a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
@@ -11,7 +11,7 @@
\QDS comes with \e {preset components} that you can use in your UI by
creating instances of them.
- \image qmldesigner-editing-components.png "Creating Component Instances"
+ \image qmldesigner-editing-components.webp "Creating Component Instances"
To create component instances and edit their properties:
diff --git a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
index 923428779b..7d394de29e 100644
--- a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
@@ -90,7 +90,7 @@
component instances into custom components by moving them into
separate component files (.ui.qml). Right-click a component instance
in \uicontrol Navigator or the \uicontrol {2D} view, and select
- \uicontrol {Move Component into Separate File} in the context menu.
+ \uicontrol {Create Component} in the context menu.
\image qtcreator-move-component-into-separate-file.png
diff --git a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
index 5ea37b040c..a71831fdd1 100644
--- a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
@@ -407,12 +407,6 @@
\uicontrol {Stack Layout}, select the components in the \l {2D} view,
and then select \uicontrol Layout in the context menu.
- You can also click the \inlineimage column.png
- (\uicontrol {Column Layout}), \inlineimage row.png
- (\uicontrol {Row Layout}), and \inlineimage grid.png
- (\uicontrol {Grid Layout}) toolbar buttons to apply
- layouts to the selected components.
-
To make a component within a layout as wide as possible while respecting the
given constraints, select the component in the \uicontrol {2D} view, and
then select \uicontrol Layout > \uicontrol {Fill Width} in the context menu.
diff --git a/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc b/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc
new file mode 100644
index 0000000000..567650a137
--- /dev/null
+++ b/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc
@@ -0,0 +1,289 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+
+ \page design-viewer-single-page-navigation.html
+ \previouspage qt-design-viewer.html
+ \nextpage studio-exporting-and-importing.html
+
+
+ \title Creating a Single Page Navigation Web Application
+
+ This example explains how you can create a single page navigation web
+ application suitable to run in Qt Design Viewer. In this project,
+ you create the structure and navigation for the web application.
+
+ \section1 Setting up the Project
+
+ To set up the project:
+ \list 1
+ \li
+ In \QDS, create a new project where you set:
+ \list
+ \li \uicontrol Preset to \uicontrol Desktop > \uicontrol Launcher.
+ \li \uicontrol Resolution to 1024 x 768.
+ \li \uicontrol {Target Version} to 6.2.
+ \endlist
+ \li In \uicontrol Navigator:
+ \list
+ \li Select and delete \e Text.
+ \li Select \e Rectangle and in \uicontrol Properties, set
+ \uicontrol {Fill color} to #ffffff.
+ \endlist
+ \endlist
+
+ \section1 Adding Components
+
+ Next, add the needed components to create the structure for your web
+ application.
+
+ Add the \uicontrol {QtQuick Layouts} module:
+ \list 1
+ \li In \uicontrol Components, select
+ \inlineimage icons/plus.png
+ \li Select \uicontrol {QtQuick.Layouts}.
+ \endlist
+
+ To add the structure for the web application,
+ drag and drop the following components from \uicontrol Components
+ to \e rectangle in \uicontrol Navigator.
+ \list
+ \li \uicontrol Rectangle
+ \list
+ \li \uicontrol Rectangle
+ \list
+ \li \uicontrol Row
+ \list
+ \li \uicontrol Button
+ \li \uicontrol Button
+ \li \uicontrol Button
+ \endlist
+ \endlist
+ \li \uicontrol Flickable
+ \list
+ \li \uicontrol ColumnLayout
+ \endlist
+ \endlist
+
+ \endlist
+
+ \image web-navigation-components.png
+
+ \section1 Creating the Pages
+
+ Next, create the separate pages for your web application. In this example,
+ you create pages for \e Home, \e {About Us}, and \e {Contact Us}.
+
+ You create each page as a separate component and then add it to the main
+ application.
+
+ To create the first page:
+
+ \list 1
+ \li Go to \uicontrol File > \uicontrol {New File}.
+ \li On the \uicontrol {Qt Quick Files} tab,
+ select \uicontrol {Qt Quick File}.
+ \li Select \uicontrol {Choose} and enter a name, for example, \e Page1.
+ \li Set \uicontrol {Root Item} to \e Rectangle.
+ \endlist
+
+ \image web-navigation-new-file.png
+
+ When you have created the new page, select \e rectangle in
+ \uicontrol Navigator, and in the \uicontrol Properties view:
+ \list
+ \li Set \uicontrol Size > \uicontrol H to 1024.
+ \li Next to \uicontrol Size > \uicontrol W, select
+ \inlineimage icons/action-icon.png
+ and select \uicontrol Reset.
+ \endlist
+
+ Next, create a header for the page:
+ \list 1
+ \li From \uicontrol Components, drag a \uicontrol Text component
+ to \e Rectangle in \uicontrol Navigator.
+ \li In \uicontrol Properties, go to the \uicontrol Text tab and set:
+ \list
+ \li \uicontrol Text to \e Welcome.
+ \li \uicontrol {Style Name} to Bold.
+ \li \uicontrol Size to 32 px.
+ \endlist
+ \li On the \uicontrol Layout tab set the anchors and margins to:
+ \list
+ \li Top, 100
+ \li Left, 50
+ \endlist
+ \image web-navigation-page-margins.png
+ \endlist
+
+Now, with the first page done, create two more pages in the same way. For these
+pages, set the text to \e {About Us} and \e {Contact Us} respectively.
+
+You can change the file that you are working on from the drop-down menu in the
+toolbar. Now, select \e Screen01.ui.qml from this menu to go back to your
+main page.
+
+\image web-navigation-change-file.png
+
+You can see the pages you created under \uicontrol {My Components} in the
+\uicontrol Components view. To edit a component, right-click it in
+\uicontrol Components and select \uicontrol {Edit Component}
+
+\image web-navigation-page-components.png
+
+\section1 Organizing the Pages
+
+To organize the pages vertically:
+
+\list 1
+ \li From \uicontrol Components, drag each of the pages to
+ \e columnLayout in \uicontrol Navigator.
+ \image web-navigation-components-2.png
+ \li Select \e columnLayout in Navigator and in \uicontrol Properties:
+ \list
+ \li Next to \uicontrol Size > \uicontrol W and \uicontrol Size >
+ \uicontrol H, select \inlineimage icons/action-icon.png
+ and select \uicontrol Reset.
+ \li Set \uicontrol {Column Spacing} to 0.
+ \endlist
+ \li Select \e flickable in \uicontrol Navigator, and in \uicontrol Properties:
+ \list
+ \li Next to \uicontrol Size > \uicontrol W and \uicontrol Size >
+ \uicontrol H, select \inlineimage icons/action-icon.png
+ and select \uicontrol Reset.
+ \li Set \uicontrol {Content size} > \uicontrol H to 3072.
+ \li On the \uicontrol Layout tab, select
+ \uicontrol {Fill parent component}.
+ \endlist
+\endlist
+
+You must also create a scrollbar to scroll the web application. You create
+vertical and horizontal scrollbars that are visible only when the content
+doesn't fit in the window, similar to web browser scrollbars.
+
+To create the scrollbar, go to the \uicontrol Code view and enter the scrollbar
+code inside the \e Flickable component:
+\code
+ Flickable {
+ id: flickable
+ anchors.fill: parent
+ contentHeight: 3072
+ ScrollBar.vertical: ScrollBar {
+ policy: flickable.contentHeight > flickable.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
+ width: 20
+ }
+ ScrollBar.horizontal: ScrollBar {
+ policy: flickable.contentWidth > flickable.width ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
+ height: 20
+ }
+ ...
+\endcode
+
+To align the scrollbar to the right and bottom side of the window, set the height and width of the
+main rectangle so that it adapts to the window size.
+
+\list 1
+ \li In \uicontrol Navigator, select \e Rectangle.
+ \li In \uicontrol Properties, select
+ \inlineimage icons/action-icon-binding.png
+ next to \uicontrol Width and select \uicontrol {Set Binding}.
+ \li Enter \c {Window.width}
+ \image web-navigation-size-binding.png
+ \li Repeat step 2 and 3 for \uicontrol Height and set the value to
+ \c {Window.height}.
+\endlist
+
+\section1 Creating the Navigation
+
+The final step is to create the navigation for the web page. To do this, use the buttons
+that you created earlier.
+
+First, create an animation to use when scrolling between the different pages:
+
+\list 1
+ \li From \uicontrol Components, drag a \uicontrol {Number Animation} to
+ \e Rectangle in \uicontrol Navigator.
+ \li In \uicontrol Properties, set:
+ \list
+ \li \uicontrol Target to \e flickable.
+ \li \uicontrol Property to \e contentY.
+ \li \uicontrol Duration to \e 200.
+ \endlist
+\endlist
+
+Next, connect the buttons to the number animation to scroll the content
+vertically to the correct place.
+
+\list 1
+ \li In \uicontrol Navigator, select \e rectangle and in \uicontrol Properties
+ set:
+ \list
+ \li \uicontrol Height to 40.
+ \li \uicontrol {Fill color} to #e0e0e0.
+ \li \uicontrol {Z stack} to 1.
+ \endlist
+ \li Select \inlineimage icons/action-icon-binding.png
+ next to \uicontrol Width and select \uicontrol {Set Binding}.
+ \li Enter \c {parent.width}.
+ \image web-navigation-size-binding-2.png
+ \li In \uicontrol Navigator:
+ \list 1
+ \li Select \e Button and on the \uicontrol Button tab in \uicontrol Properties,
+ set \uicontrol Text to \e {Home}.
+ \li Select \e Button1 and on the \uicontrol Button tab in \uicontrol Properties,
+ set \uicontrol Name to \e {About Us}.
+ \li Select \e Button2 and on the \uicontrol Button tab in \uicontrol Properties,
+ set \uicontrol Name to \e {Contact Us}.
+ \endlist
+ \li In \uicontrol Code, enter \e connections for each of the buttons to run
+ the number animation when pressed.
+ \code
+ Button {
+ id: button
+ text: qsTr("Home")
+ Connections {
+ target: button
+
+ onPressed: {
+ numberAnimation.to = 0
+ numberAnimation.start()
+ }
+ }
+ }
+
+ Button {
+ id: button1
+ text: qsTr("About Us")
+ Connections {
+ target: button1
+
+ onPressed: {
+ numberAnimation.to = 1024
+ numberAnimation.start()
+ }
+ }
+ }
+
+ Button {
+ id: button2
+ text: qsTr("Contact Us")
+ Connections {
+ target: button2
+
+ onPressed: {
+ numberAnimation.to = 2048
+ numberAnimation.start()
+ }
+ }
+ }
+ \endcode
+\endlist
+
+\section1 Previewing the application
+
+To preview your application in the live preview, select \key Alt + \key P. You
+can also go to \uicontrol File > \uicontrol {Share Application Online} to
+share and preview your application in a web browser.
+
+*/
diff --git a/doc/qtdesignstudio/src/overviews/qt-design-viewer.qdoc b/doc/qtdesignstudio/src/overviews/qt-design-viewer.qdoc
index 069ad71f27..1120bc6106 100644
--- a/doc/qtdesignstudio/src/overviews/qt-design-viewer.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qt-design-viewer.qdoc
@@ -4,7 +4,7 @@
/*!
\page qt-design-viewer.html
\previouspage creator-live-preview-android.html
- \nextpage studio-exporting-and-importing.html
+ \nextpage design-viewer-single-page-navigation.html
\title Sharing Applications Online
@@ -44,4 +44,8 @@
applications.
\image share-online-manage.webp
+
+ \section1 Best Practices
+
+ \l {Creating a Single Page Navigation Web Application}
*/
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
index fa268b530d..d5f19de7a4 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
@@ -21,8 +21,8 @@
An annotation consist of an annotation name and one or several comments.
The comments have a title, author, and comment text.
- To add or edit global annotations, select \inlineimage icons/annotation.png
- on the top menu bar in the Design mode.
+ To add or edit global annotations, right-click in the \uicontrol 2D or
+ \uicontrol Navigator view and select \uicontrol {Edit Annotations}.
Global annotations have an additional status property, which enables you
to indicate whether you are still working on the design, you have submitted
diff --git a/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc
index ec7243d004..c4cdec1ea5 100644
--- a/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc
+++ b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc
@@ -150,13 +150,14 @@
Next, to run the emulator, do one of the following:
\list
- \li Select \uicontrol{Show Live Preview} in the the \uicontrol {2D} view toolbar.
+ \li Select \uicontrol{Live Preview} in the top toolbar.
\image toolbar-show-live-preview.png
\li Select \uicontrol Build > \uicontrol{QML Preview}.
\note The \uicontrol Build menu option is not visible by default. To show
it, go to \uicontrol Edit > \uicontrol Preferences > \uicontrol Environment
> \uicontrol {Qt Design Studio Configuration}.
\image menu-build-qml-preview.png
+ \li Select \key Alt + \key P.
\endlist
Now the emulator runs, the qtdesignviewer APK delivered with the \QDS installation
diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-template.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-template.qdoc
new file mode 100644
index 0000000000..29b161562d
--- /dev/null
+++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-template.qdoc
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \previouspage qtbridge-figma-using.html
+ \page qtbridge-figma-template.html
+ \nextpage exporting-3d-assets.html
+
+ \title Using Figma Quick Control Template Components in \QDS
+
+ You can design with the template components created by \QDS in Figma
+ and import them to \QDS with \QBF. These template components are structured
+ specifically for Figma. When you design in Figma using them, and import the design with
+ \QBF, they generate functional QML components for \QDS. So, you can edit components both in
+ \QDS and Figma.
+
+ \section1 Using Figma Template Components
+
+ You should have these prerequisites available:
+ \list
+ \li A Figma professional account.
+ \li \QDS Enterprise license.
+ \li \QDS 3.9 or above.
+
+ \note You can try out the template features with a Figma starter account as well. However,
+ if you want to publish template assets in Figma, you need a Figma professional account
+ for that.
+ \endlist
+
+ \section2 Creating Figma Design with Template Components
+
+ \list 1
+ \li Sign in to Figma.
+ \li Go to the Template provided by \QDS team
+ \externallink {https://www.figma.com/community/file/1185200043286168239}{here}.
+ \li Select \uicontrol {Get a copy} and then your account to have a copy
+ on your Figma workspace.
+
+ \note From the \uicontrol {Layers} tab you can find pages of contents. Here,
+ select \uicontrol {Introduction} to access all the knowledge about the
+ templates workflow and key concepts.
+ \li There are templates for individual components in separate pages.
+ Select the page you want to work on from template and copy
+ all of its contents.
+ \li Create a new Figma design file. In Figma, select \uicontrol Menu
+ > \uicontrol File > \uicontrol {New design file}.
+ \li Paste the copied content to this file and save.
+ Here, do all the modification you need using Figma tools.
+ \li Next, publish this template assets. In Figma, select \uicontrol Menu
+ > \uicontrol Libraries. Then select \uicontrol Publish. You don't need to
+ publish the template itself, just publish the components. You can clear
+ \uicontrol Template from the \uicontrol {Changes} section to have it removed from
+ publishing assets.
+ \li Create another new project, where you would use this published component.
+ Or, you can use this component in one of your existing projects in Figma.
+
+ \note In Figma, select \uicontrol Menu > \uicontrol Libraries to find the
+ published components. You can find these components under \uicontrol {Your teams}.
+ Toggle them active to use in a project.
+ \endlist
+
+ \section2 Importing the Figma Design to \QDS with \QBF
+
+ \list 1
+ \li In Figma, do one of the following:
+ \list
+ \li Select \uicontrol Menu > \uicontrol Plugins > \uicontrol {Qt Bridge for Figma}.
+ \li Select \uicontrol Resources \e(Shift + I) > \uicontrol {Qt Bridge for Figma}
+ > \uicontrol Run.
+ \endlist
+ \li Save the file to your local system.
+ \li Import the \QBF file to a project in \QDS. You can drag the file to project.
+ Then, select \uicontrol Import, and wait until the process is finished.
+ \li Drag the imported \QBF file to the \QDS open project. Select \uicontrol Import, and
+ wait until the process is finished.
+ \li You can find the imported design as QML files in \QDS. Figma
+ assets are also imported as components in \QDS. You can manipulate
+ \uicontrol states or \uicontrol properties natively.
+
+ \note You can also edit the design in Figma and bring it again to \QDS using \QBF.
+ However, you need to name this imported file exactly same as before. Then import it to
+ the project in \QDS to have it synchronized. \QDS lets you have the
+ updates you have made locally on top of the imported component updates.
+ \endlist
+
+
+*/
diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc
index 8a00c8833c..1af2351e7d 100644
--- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc
+++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc
@@ -4,7 +4,7 @@
/*!
\previouspage qtbridge-figma-setup.html
\page qtbridge-figma-using.html
- \nextpage exporting-3d-assets.html
+ \nextpage qtbridge-figma-template.html
\title Using \QBF
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
index 5514acd2f2..05906cba86 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
@@ -282,9 +282,9 @@
and transition line.
\endlist
- To preview the flow, select the \inlineimage icons/live_preview.png
- (\uicontrol {Show Live Preview}) button on the Design mode
- \l{Summary of Main Toolbar Actions}{toolbar} or press \key {Alt+P}.
+ To preview the flow, select the
+ \uicontrol {Live Preview} button on the top toolbar or press \key Alt +
+ \key P.
\section1 Common Properties
@@ -485,9 +485,8 @@
To create an event list:
\list 1
- \li Select the \inlineimage icons/edit.png
- (\uicontrol {Show Event List}) button on the Design mode
- \l{Summary of Main Toolbar Actions}{toolbar}, or press \key {Alt+E}.
+ \li Right-click in the \uicontrol 2D or \uicontrol Navigator view and select
+ \uicontrol {Event List} > \uicontrol {Show Event List}.
\li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png
to add a keyboard shortcut for triggering an event to the list.
\image studio-flow-event-list.png "Event List dialog"
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc
index e00bb35486..06b3ea1590 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc
@@ -34,36 +34,20 @@
\section1 Creating an Effect File
- You can create empty Qt Quick Effect Maker effect (.qep) files in \QDS and
+ You can create Qt Quick Effect Maker effect (.qep) files in \QDS and
then edit them in Qt Quick Effect Maker.
To create an effect file:
\list 1
- \li In \QDS, go to \uicontrol File > \uicontrol {New File}.
- \li Go to the \uicontrol Effects tab and select
- \uicontrol {Effect file (Effect Maker)}.
- \image new-effect-file.png
- \li Select \uicontrol Choose and follow the wizard to create the file.
- \endlist
-
- After you have created the effect file, it is available in the
- \uicontrol Assets view.
-
- \image assets-view-effect.png
-
- \section2 Editing and Re-importing an Effect File
-
- To edit an effect file in Qt Quick Effect Maker, double-click it in
- the \uicontrol Assets view. This opens the effect in Qt Quick Effect
- Maker where you can make your changes.
-
- When you have edited the effect file in Qt Quick Effect Maker, you need
- to save and export it:
- \list 1
+ \li In \QDS, right-click in the \uicontrol Assets view and
+ select \uicontrol {New Effect}.
+ \QDS creates an effect file and opens it in Qt Quick Effect Maker.
+ \image qt-quick-effect-maker.webp
+ \li Edit the effect.
\li In Qt Quick Effect Maker, go to \uicontrol File > \uicontrol Save.
\li Select \uicontrol File > \uicontrol Export.
- \li With the default settings, select \uicontrol Ok.
+ \li With the default settings, select \uicontrol OK.
\image effect-maker-export.png
\endlist
@@ -73,7 +57,8 @@
\section1 Applying an Effect
You can apply effects to components in \QDS. To do so, drag the effect
- from the \uicontrol Assets view to the component in the \uicontrol 2D view.
+ from the \uicontrol Assets view to the component in the \uicontrol 2D or
+ \uicontrol Navigator view.
\image apply-effect-maker-effect.webp
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc
index 38c6cf5695..c5f9ef4276 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \previouspage qt-design-viewer.html
+ \previouspage design-viewer-single-page-navigation.html
\page studio-exporting-and-importing.html
\nextpage qtbridge-overview.html
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
index d9be56eacd..ffb23d35f2 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
@@ -183,7 +183,7 @@
\li Wizard Template
\li Purpose
\row
- \li {1,4} Qt Quick Files
+ \li {1,5} Qt Quick Files
\li Flow Item and Flow View
\li Generate components that you can use to design the
\l{Designing Application Flows}{application flow}.
@@ -203,6 +203,10 @@
\li Generates a Grid View or a List View. For more information, see
\l{List and Grid Views}.
\row
+ \li Qt Quick UI Form
+ \li Creates a UI file along with a matching QML file for
+ implementation purposes.
+ \row
\li {1,9} Qt Quick Controls
\li Custom Button
\li Creates a \l {Button}{push button} with a text label.
@@ -225,7 +229,7 @@
\li \l Pane
\li Provides a background that matches the UI style and theme.
\row
- \li StackView
+ \li Stacked Layout
\li Provides a stack-based navigation model.
\row
\li SwipeView
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc
index 77c63d5fe1..6bad9919d5 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc
@@ -23,7 +23,7 @@
\section1 The Qt Blockset for Simulink
- Install the Simulink \l {https://git.qt.io/qt-design-studio/simulink-plugin-dependencies}
+ Install the Simulink \l {https://git.qt.io/design-studio/simulink/simulink-plugin-dependencies}
{Qt Blockset} to your computer in order to connect a Simulink model to your
application. The Qt Blockset installer adds the Simulink blocks needed to
establish connectivity to your application. After installation, the
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
index dd5c1609b1..4859c20488 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
@@ -149,7 +149,7 @@
\uicontrol Help for reading documentation. The other modes are mostly
needed for application development.
- \image studio-design-mode.png "Design mode"
+ \image studio-design-mode.webp "Design mode"
Read more about modes:
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
index 68769528e8..89a93a4d43 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
@@ -134,6 +134,9 @@
\li \l{Previewing on Devices}
\li \l{Previewing Android Applications}
\li \l{Sharing Applications Online}
+ \list
+ \li \l{Creating a Single Page Navigation Web Application}
+ \endlist
\endlist
\li \l {Asset Creation with Other Tools}
\list
@@ -159,6 +162,7 @@
\list
\li \l{Setting Up Qt Bridge for Figma}
\li \l{Using Qt Bridge for Figma}
+ \li \l{Using Figma Quick Control Template in Qt Design Studio}
\endlist
\endlist
\li \l {Exporting 3D Assets}
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
index 2910cf2a9b..e861133efd 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
@@ -5,7 +5,7 @@
/*!
\page exporting-3d-assets.html
\if defined(qtdesignstudio)
- \previouspage figmaqtbridge.html
+ \previouspage qtbridge-figma-template.html
\else
\previouspage quick-states.html
\endif
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
index 810692e89b..1f69fe95cd 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
@@ -62,7 +62,7 @@
select the \inlineimage icons/reset.png
(\uicontrol {Reset View}) button.
- \image studio-3d-editor.png "The 3D view"
+ \image studio-3d-editor.webp "The 3D view"
The following video illustrates navigating in the \uicontrol{3D} view and
using the toolbar:
@@ -104,7 +104,7 @@
selected, the camera is pointed at the world origin. This does not affect
the camera zoom level.
- \image studio-3d-editor-axis-helper.png "Axis helper in the 3D view"
+ \image studio-3d-editor-axis-helper.webp "Axis helper in the 3D view"
You can use scene cameras (2) to view the \uicontrol View3D component from a
specific angle in the \l {2D} view while editing scenes. Different types of
@@ -116,8 +116,7 @@
\section1 Using Global and Local Orientation
To switch between local and global orientation, select
- \inlineimage local.png
- or \inlineimage global.png
+ \inlineimage global.png
(\uicontrol {Toggle Local/Global Orientation})
or press \key Y.
@@ -170,13 +169,13 @@
\target moving components 3d view
\section1 Moving Components
- \image studio-3d-editor-move.png "The 3D view in move mode"
+ \image studio-3d-editor-move.webp "The 3D view in move mode"
You can move components in relation to their coordinate system, along the x,
y, or z axis or on the top, bottom, left, and right clip planes of the
the \uicontrol{3D} view.
- To move components, select \inlineimage move_on.png
+ To move components, select \inlineimage move_off.png
or press \key W:
\list
@@ -190,9 +189,9 @@
\section1 Rotating Components
- \image studio-3d-editor-rotate.png "The 3D view in rotate mode"
+ \image studio-3d-editor-rotate.webp "The 3D view in rotate mode"
- To rotate components, select \inlineimage rotate_on.png
+ To rotate components, select \inlineimage rotate_off.png
or press \key E:
\list
@@ -204,13 +203,13 @@
\section1 Scaling Components
- \image studio-3d-editor-scale.png "The 3D view in scale mode"
+ \image studio-3d-editor-scale.webp "The 3D view in scale mode"
You can use the scale handles to adjust the local x, y, or z scale of a
component. You can adjust the scale across one, two, or three axes,
depending on the handle.
- To scale components, select \inlineimage scale_on.png
+ To scale components, select \inlineimage scale_off.png
or press \key R:
\list
@@ -330,49 +329,45 @@
\li Keyboard Shortcut
\li Read More
\row
- \li \inlineimage select_group.png
- \inlineimage select_item.png
+ \li \inlineimage icons/select_group.png
+ \inlineimage icons/select_item.png
\li Toggle Group/Single Selection Mode
\li \key Q
\li \l{Selecting Components}
\row
- \li \inlineimage move_off.png
- \inlineimage move_on.png
+ \li \inlineimage icons/move_off.png
\li Activate the Move Tool
\li \key W
\li \l{moving components 3d view}{Moving Components}
\row
- \li \inlineimage rotate_off.png
- \inlineimage rotate_on.png
+ \li \inlineimage icons/rotate_off.png
\li Activate Rotate Tool
\li \key E
\li \l{Rotating Components}
\row
- \li \inlineimage scale_off.png
- \inlineimage scale_on.png
+ \li \inlineimage icons/scale_off.png
\li Activate Scale Tool
\li \key R
\li \l{Scaling Components}
\row
- \li \inlineimage fit_selected.png
+ \li \inlineimage icons/fit_selected.png
\li Fit Selected Object to View
\li \key F
\li \l{Controlling the 3D View Camera}
\row
- \li \inlineimage perspective_camera.png
- \inlineimage orthographic_camera.png
+ \li \inlineimage icons/perspective_camera.png
+ \inlineimage icons/orthographic_camera.png
\li Toggle Perspective/Orthographic Edit Camera
\li \key T
\li \l{Controlling the 3D View Camera}
\row
- \li \inlineimage global.png
- \inlineimage local.png
+ \li \inlineimage icons/global.png
\li Toggle Global/Local Orientation
\li \key Y
\li \l{Using Global and Local Orientation}
\row
- \li \inlineimage edit_light_off.png
- \inlineimage edit_light_on.png
+ \li \inlineimage icons/edit_light_off.png
+ \inlineimage icons/edit_light_on.png
\li Toggle Edit Light On/Off
\li \key U
\li \l{Using Edit Light}
@@ -403,7 +398,6 @@
\li \l{Particle Editor}
\row
\li \inlineimage icons/particle-animation-on.png
- \inlineimage icons/particle-animation-off.png
\li Toggle Particle Animation
\li \key V
\li \l{Particle Editor}
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
index 6d1fbc5bd1..47e39f3211 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
@@ -93,7 +93,7 @@
Use the \uicontrol Brightness handle of the light gizmo (1) to adjust the
\uicontrol Brightness property of any of the light components.
- \image studio-3d-directional-light.png "Models lit by a directional light."
+ \image studio-3d-directional-light.webp "Models lit by a directional light."
If the \uicontrol {Casts shadow} property is enabled, shadows are positioned
parallel to the light direction. A directional light has infinite range and
@@ -118,7 +118,7 @@
strength in all directions from the center of the light. This is similar
to the way a light bulb emits light.
- \image studio-3d-point-light.png "Models lit by a point light."
+ \image studio-3d-point-light.webp "Models lit by a point light."
Lighting is applied outwards from the center of a point light, becoming
increasingly dim away from the center. Moving a point light changes the
@@ -158,7 +158,7 @@
\uicontrol {Inner cone angle} (4), and \uicontrol {Quadratic fade} (5)
properties.
- \image studio-3d-spot-light.png "A model lit by a spot light."
+ \image studio-3d-spot-light.webp "A model lit by a spot light."
Inside the inner cone angle, the spot light behaves similarly to the point
light. There the light intensity diminishes according to inverse-square-law.
@@ -176,7 +176,7 @@
gizmo or the \uicontrol Properties view to set the \uicontrol Width (6)
and \uicontrol Height (7) properties to determine the size of the area light.
- \image studio-3d-area-light.png "A model lit by two area lights."
+ \image studio-3d-area-light.webp "A model lit by two area lights."
Aside from the size, an area light has the same properties as a directional
light.
diff --git a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
index d7af982392..a324c6f562 100644
--- a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
@@ -23,7 +23,7 @@
\uicontrol View > \uicontrol Views. The following images present the
views that you are likely to use most often while designing UIs.
- \image studio-design-mode.png "Design views"
+ \image studio-design-mode.webp "Design views"
\image studio-design-mode-states-timeline.png "The States and Timeline views"
You can move the views anywhere on the screen and save them as
@@ -150,6 +150,33 @@
\li Action
\li Keyboard Shortcut
\li Read More
+
+ \if defined(qtdesignstudio)
+ \row
+ \li \inlineimage icons/home.png
+ \li \uicontrol {Home}: opens the welcome page.
+ \li
+ \li
+ \row
+ \li \inlineimage icons/start_playback.png
+ \li \uicontrol {Play}: runs the application.
+ \li
+ \li
+ \row
+ \li \uicontrol {Live Preview}
+ \li Shows a preview of the current file or the entire UI. The changes you
+ make to the UI are instantly visible to you in the preview.
+ \li \key Alt+P (\key Opt+P on \macos)
+ \li \l{Validating with Target Hardware}
+ \endif
+
+ \row
+ \li Currently open file
+ \li Displays the location and filename of the currently open file. You
+ can select another file in the list of open files to view it in
+ the \uicontrol {2D} and \uicontrol Navigator views.
+ \li
+ \li \l{Open Documents}
\row
\li \inlineimage icons/prev.png
\li \uicontrol {Go Back}: moves a step backwards in your location history.
@@ -163,130 +190,20 @@
\li \key Alt+> (\key Opt+Cmd+> on \macos)
\li \l{Navigating Between Open Files and Symbols}
\row
- \li \inlineimage icons/unlocked.png
- \li File is writable: the currently open file can be modified and saved.
- \li
- \li \l{Open Documents}
- \row
- \li File type icon
- \li Indicates the type of the currently open file. Design views cannot
- be split, so the icon cannot be dragged, contrary to the tooltip.
- \li
- \li \l{Open Documents}
- \row
- \li Currently open file
- \li Displays the location and filename of the currently open file. You
- can select another file in the list of open files to view it in
- the \uicontrol {2D} and \uicontrol Navigator views.
- \li
- \li \l{Open Documents}
- \row
\li \inlineimage icons/close.png
\li \uicontrol {Close Document}: closes the current file.
\li \key Ctrl+W (\key Cmd+W on \macos)
\li
\row
- \li \inlineimage icons/live_preview.png
- \li \uicontrol {Show Live Preview} shows a preview of the current file
- or the entire UI. The changes you make to the UI are instantly
- visible to you in the preview.
- \li \key Alt+P (\key Opt+P on \macos)
- \li \l{Validating with Target Hardware}
- \row
- \li Preview size
- \li Displays the size of the preview dialog as a percentage. You can
- select another percentage in the list to view the UI in different
- sizes.
- \li
- \li \l{Previewing on Desktop}
- \row
- \li FPS
- \li Displays the frames-per-second (FPS) refresh rate of previewed
- animations.
- \li
- \li \l{Previewing on Desktop}
- \row
- \li Preview language
- \li Displays the language used for a localized application during
- preview. You can select another language in the list of languages
- that the application has been localized to.
- \li
- \li
- \row
- \li \inlineimage icons/qtcreator-reset-position-icon.png
- \li Returns a component to its \e {implicit position} after
- being moved.
- \li \key Ctrl+D (\key Cmd+D on \macos)
- \li \l{Resetting Component Position and Size}
- \row
- \li \inlineimage icons/qtcreator-reset-size-icon.png
- \li Returns a component to its implicit size after it was scaled.
- \li \key Shift+S
- \li \l{Resetting Component Position and Size}
- \row
- \li \inlineimage icons/anchor-fill.png
- \li Fills the selected component to its parent component.
- \li \key Shift+F
- \li \l{Setting Anchors and Margins}
- \row
- \li \inlineimage icons/qtcreator-anchors-reset-icon.png
- \li Resets anchors to their saved state for the selected component.
- \li \key Ctrl+Shift+R (\key Shift+Cmd+R on \macos)
- \li \l{Setting Anchors and Margins}
- \row
- \li \inlineimage icons/copy-formatting.png
- \li Copies property values from the selected component.
- \li
- \li \l{Copying and Pasting Formatting}
- \row
- \li \inlineimage icons/paste-formatting.png
- \li Applies copied property values to one or several selected
- components.
+ \li \inlineimage icons/create_component.png
+ \li Creates a custom component from the selected item.
\li
- \li \l{Copying and Pasting Formatting}
- \row
- \li \inlineimage row.png
- \li Uses a \uicontrol Row component to lay out the selected components.
- \li \key Ctrl+U (\key Cmd+U on \macos)
- \li \l{Using Layouts}
- \row
- \li \inlineimage column.png
- \li Uses a \uicontrol Column component to lay out the selected
- components.
- \li \key Ctrl+L (\key Cmd+L on \macos)
- \li \l{Using Layouts}
- \row
- \li \inlineimage grid.png
- \li Uses a \uicontrol Grid component to lay out the selected
- components.
- \li \key Shift+G
- \li \l{Using Layouts}
- \if defined(qtdesignstudio)
+ \li \l{Creating Custom Components}
\row
- \li \inlineimage icons/edit.png
- \li \uicontrol {Show Event List}: opens a dialog for viewing and
- creating an event list for an application flow.
- \li \key Alt+E (\key Opt+E on \macos)
- \li \l{Simulating Events}
- \row
- \li \inlineimage icons/assign.png
- \li \uicontrol {Assign Events to Actions}: assigns events to actions in
- an application flow.
- \li \key Alt+A (\key Opt+A on \macos)
- \li \l{Simulating Events}
- \endif
- \row
- \li Styling
- \li Displays the UI style used for UI controls.
+ \li \inlineimage icons/edit_component.png
+ \li Edits the selected custom component.
\li
- \li \l{Styling Controls}
- \row
- \li Subcomponents
- \li Displays the components referred to in the current file. Select a
- component in the list to open it in the \uicontrol {2D} and
- \uicontrol Navigator views.
- \li
- \li \l{Using Components}
+ \li \l{Creating Custom Components}
\row
\li Workspace
\li Displays the currently selected workspace. To switch to another
@@ -294,9 +211,9 @@
\li
\li \l{Managing Workspaces}
\row
- \li \inlineimage icons/annotation.png
- \li Enables you to add or edit global annotations.
+ \li \uicontrol Share
+ \li Shares the application online using Qt Design Viewer.
\li
- \li \l{Annotating Designs}
+ \li \l{Sharing Applications Online}
\endtable
*/
diff --git a/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc
index 64305f3e82..fc6d8c0223 100644
--- a/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc
@@ -36,24 +36,6 @@
\li Tooltip
\li Read More
\row
- \li \inlineimage icons/no_snapping.png
- \li Disables snapping.
- \li \l{Snapping to Parent and Sibling Components}
- \row
- \li \inlineimage icons/snapping_and_anchoring.png
- \li Anchors the component instance to the component instances that it
- is snapped to.
- \li \l{Snapping to Parent and Sibling Components}
- \row
- \li \inlineimage icons/snapping.png
- \li Snaps component instances to their parent or siblings when you
- align them.
- \li \l{Snapping to Parent and Sibling Components}
- \row
- \li \inlineimage icons/boundingrect.png
- \li Hides and shows component instance boundaries.
- \li \l{Hiding Component Boundaries}
- \row
\li \uicontrol {Override Width}
\li Shows a preview of the component using the specified width.
\li \l{Previewing Component Size}
@@ -149,13 +131,16 @@
\section1 Snapping to Parent and Sibling Components
You can use snapping to align component instances in
- the \uicontrol {2D} view. Select the \inlineimage icons/snapping.png
- button to have the component instances snap to their parent or siblings.
+ the \uicontrol {2D} view. With snapping turned on, all component instances
+ snap to their parent and siblings. If you use snapping with anchors, anchors are created
+ when you snap a component to another.
+
+ To turn on snapping, right-click in the \uicontrol 2D view and select
+ \uicontrol Snapping > \uicontrol {Snap with Anchors} or
+ \uicontrol {Snap without Anchors}.
+
Snapping lines automatically appear to help you position the component
- instances. Click the \inlineimage icons/snapping_and_anchoring.png
- button to anchor the selected component instance to those that you snap to.
- Only one snapping button can be selected at the time. Selecting
- one snapping button automatically deselects the others.
+ instances.
Choose \uicontrol Edit > \uicontrol Preferences > \uicontrol {Qt Quick} >
\uicontrol {Qt Quick Designer} to specify settings for snapping. In the
@@ -177,8 +162,8 @@
\section1 Hiding Component Boundaries
The \uicontrol {2D} view displays the boundaries of component instances.
- To hide them, select the \inlineimage icons/boundingrect.png
- button.
+ To hide them, right-click in the \uicontrol 2D view and select
+ \uicontrol {Show Bounds} from the context menu.
\section1 Previewing Component Size
diff --git a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
index 0c322c750d..f0cd1fe235 100644
--- a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
@@ -26,7 +26,7 @@
fit inside the parent component. For example, you might want to make a
mouse area larger than the rectangle or image beneath it.
- \image qmldesigner-element-size.png "Mouse area for a button"
+ \image qmldesigner-element-size.webp "Mouse area for a button"
When you copy a component, all its child components are also copied. When
you remove a component, the child components are also removed.
@@ -90,7 +90,7 @@
To change the visibility of a component in the application code, select the
\uicontrol Visibility check box in the \uicontrol Properties view or select
- \uicontrol Edit > \uicontrol Visibility in the context menu.
+ \uicontrol Visibility in the context menu.
You can also set the \uicontrol Opacity field to 0 in \uicontrol Properties
to hide components in the UI that you want to apply animation to.
@@ -224,7 +224,7 @@
\list
\li In the \uicontrol {2D} or \uicontrol Navigator view,
right-click an instance of a component and then select
- \uicontrol {Go into Component} in the context menu or
+ \uicontrol {Edit Component} in the context menu or
press \key F2.
\li In \uicontrol Properties, select \uicontrol {Edit Base Component}.
\endlist
diff --git a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
index 8f8a1da66b..8ce14eba6b 100644
--- a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
@@ -90,11 +90,11 @@
\section2 Resetting Component Position and Size
To return a component to its default position after moving it,
- select the \inlineimage icons/qtcreator-reset-position-icon.png
- (\uicontrol {Reset Position}) button on the \l{Design Views}
- {Design mode toolbar}. To return it to its default size, select
- \inlineimage icons/qtcreator-reset-size-icon.png
- (\uicontrol {Reset Size}) button.
+ right-click in the \uicontrol 2D or \uicontrol Navigator view and select
+ \uicontrol Edit > \uicontrol {Reset Position}.
+ To return it to its default size, right-click in the \uicontrol 2D or
+ \uicontrol Navigator view and select \uicontrol Edit >
+ \uicontrol {Reset Size}.
\section2 Managing 2D Transformations
@@ -448,15 +448,13 @@
several other components. The values are applied if the target components
have those particular properties.
- To copy property values from the selected component, select
- \inlineimage icons/copy-formatting.png
- on the \uicontrol Design mode \l{Summary of Main Toolbar Actions}
- {main toolbar}.
+ To copy property values from a component, right-click it in the
+ \uicontrol 2D or \uicontrol Navigator view and select \uicontrol Edit >
+ \uicontrol {Copy Formatting}.
To apply the values to one or several other components, select
- them in the \l Navigator or \l {2D} view, and then select
- \inlineimage icons/paste-formatting.png
- .
+ them in the \l Navigator or \l {2D} view, and then right-click and select
+ \uicontrol Edit > \uicontrol {Apply Formatting}.
\section1 Editing Properties Inline
diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
index 455c680cd1..1fcf4ef908 100644
--- a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
@@ -26,7 +26,7 @@
It now displays a \l{Timeline Toolbar}{toolbar} and a ruler but no
keyframe tracks.
- \image studio-timeline-no-tracks.png "Timeline view without keyframe tracks"
+ \image studio-timeline-no-tracks.webp "Timeline view without keyframe tracks"
To animate component properties in the \uicontrol Timeline view, you
must \l{Setting Keyframe Values}{insert keyframes} for them. In the
@@ -35,7 +35,7 @@
want to animate. A keyframe track is generated for each component that you
insert keyframes for.
- \image studio-timeline-with-empty-tracks.png "Timeline view with a property"
+ \image studio-timeline-with-empty-tracks.webp "Timeline view with a property"
You can now select \inlineimage icons/local_record_keyframes.png
to \l{Setting Keyframe Values}{record changes} in component properties
@@ -56,7 +56,7 @@
\section1 Navigating in Timeline
- \image studio-timeline.png "Timeline view"
+ \image studio-timeline.webp "Timeline view"
You can navigate the timeline in the following ways:
@@ -87,7 +87,7 @@
in the context menu, and then select a color in the \l{Picking Colors}
{color picker}. To reset the color, select \uicontrol {Reset Color}.
- \image studio-timeline-keyframe-track-colors.png "Keyframe track colors in Timeline"
+ \image studio-timeline-keyframe-track-colors.webp "Keyframe track colors in Timeline"
\section1 Timeline Toolbar
@@ -99,7 +99,7 @@
\li Action
\li Read More
\row
- \li \inlineimage icons/animation.png
+ \li \inlineimage icons/settings.png
\li Opens the \uicontrol {Timeline Settings} dialog for editing
timeline settings.
\li \l{Creating a Timeline}
@@ -150,7 +150,7 @@
determines the duration of the animation.
\li \l{Creating a Timeline}
\row
- \li \inlineimage icons/zoom_small.png
+ \li \inlineimage icons/zoomOut.png
\li \uicontrol {Zoom Out} (\key Ctrl+-) zooms out of the view.
\li \l{Zooming in Timeline}
\row
@@ -158,7 +158,7 @@
\li Sets the zooming level.
\li \l{Zooming in Timeline}
\row
- \li \inlineimage icons/zoom_big.png
+ \li \inlineimage icons/zoomIn.png
\li \uicontrol {Zoom In} (\key Ctrl++) zooms into the view.
\li \l{Zooming in Timeline}
\row
diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
index 0891df05a1..12b1fc1463 100644
--- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
@@ -93,7 +93,7 @@
state in \uicontrol {States} and the timeline is available in
\uicontrol{Timelines}.
- \image timeline-states.png
+ \image timeline-states.webp
\section2 Setting Keyframe Values
@@ -118,7 +118,7 @@
\li In the \l Timeline view, select the
\uicontrol {Per Property Recording} button
to start recording property changes.
- \image timeline-per-property-recording.png
+ \image timeline-per-property-recording.webp
\li Ensure that the playhead is in frame 0 and enter the value of the
property in the field next to the property name on the timeline.
Press \key Enter to save the value.
@@ -180,7 +180,7 @@
\section1 Managing Keyframes
- \image studio-timeline-with-tracks.png "Timeline view"
+ \image studio-timeline-with-tracks.webp "Timeline view"
\section2 Editing Keyframes
@@ -240,9 +240,8 @@
\endlist
To preview the whole UI, select the
- \inlineimage icons/live_preview.png
- (\uicontrol {Show Live Preview}) button on the canvas toolbar
- or press \key {Alt+P}.
+ \uicontrol {Live Preview} button on the top toolbar
+ or press \key Alt + \key P.
\section1 Animating Rotation
diff --git a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
index ba8375e365..3ee43335d6 100644
--- a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
@@ -39,7 +39,7 @@
\li Action
\li Read More
\row
- \li \inlineimage icons/animation.png
+ \li \inlineimage icons/settings.png
\li Opens \uicontrol {Transition Settings} dialog for editing
transition settings.
\li \l{Specifying Transition Settings}
@@ -54,7 +54,7 @@
curve to the selected transition.
\li \l{Editing Easing Curves}
\row
- \li \inlineimage icons/zoom_small.png
+ \li \inlineimage icons/zoomOut.png
\li \uicontrol {Zoom Out} (\key Ctrl+-): zooms out of the view.
\li \l{Zooming in Transitions}
\row
@@ -62,7 +62,7 @@
\li Sets the zooming level.
\li \l{Zooming in Transitions}
\row
- \li \inlineimage icons/zoom_big.png
+ \li \inlineimage icons/zoomIn.png
\li \uicontrol {Zoom In} (\key Ctrl++): zooms into the view.
\li \l{Zooming in Transitions}
\row
@@ -94,7 +94,7 @@
\section1 Specifying Transition Settings
- To modify transition settings, select the \inlineimage icons/animation.png
+ To modify transition settings, select the \inlineimage icons/settings.png
(\uicontrol {Transition Settings (S)}) button in
\uicontrol {Transition Editor}.
diff --git a/doc/qtdesignstudio/src/views/studio-material-editor.qdoc b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc
index 94209c7bcb..bb2923a7ab 100644
--- a/doc/qtdesignstudio/src/views/studio-material-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/studio-material-editor.qdoc
@@ -55,7 +55,7 @@
to the object, you can select whether to replace the material or to add
another material to the object.
\li In \uicontrol {Material Editor}, select
- \inlineimage icons/apply-material.png
+ \inlineimage icons/apply.png
. This replaces any material already assigned to the object.
\endlist
diff --git a/doc/qtdesignstudio/src/views/studio-texture-editor.qdoc b/doc/qtdesignstudio/src/views/studio-texture-editor.qdoc
index 95a99401a9..4d644706e5 100644
--- a/doc/qtdesignstudio/src/views/studio-texture-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/studio-texture-editor.qdoc
@@ -35,7 +35,7 @@
To apply a texture to a material, first select the material in the
\uicontrol {Material Browser} view and then:
\list 1
- \li Select \inlineimage icons/apply-material.png
+ \li Select \inlineimage icons/apply.png
.
\li Select the material and property that you want to add the texture to.
\image select-material-property.png
diff --git a/doc/qtdesignstudio/src/views/studio-translations.qdoc b/doc/qtdesignstudio/src/views/studio-translations.qdoc
index 6972dc1ffb..a2a610b313 100644
--- a/doc/qtdesignstudio/src/views/studio-translations.qdoc
+++ b/doc/qtdesignstudio/src/views/studio-translations.qdoc
@@ -115,7 +115,7 @@
You need to generate Qt compiled translation source files (\e{.qm})
and Qt translation source files (\e{.ts}) for your project to have the
- translations working in the actual application and \uicontrol{Live Preview}.
+ translations working in the actual application and live preview.
To generate these files, select
\inlineimage icons/generate-translation-files.png
diff --git a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
index fdc359d96d..8d29b1f74f 100644
--- a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
+++ b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
@@ -30,7 +30,7 @@
where you want to attach the view is highlighted, and then drop them into
the dock area.
- \image qtcreator-workspace-attaching-views.png "Attaching views"
+ \image qtcreator-workspace-attaching-views.webp "Attaching views"
To close groups of views, select the \uicontrol {Close Group} button.
diff --git a/scripts/makedmg.py b/scripts/makedmg.py
index e90846176f..9d7fd7f5f5 100755
--- a/scripts/makedmg.py
+++ b/scripts/makedmg.py
@@ -18,6 +18,11 @@ def parse_arguments():
parser.add_argument('dmg_volumename', help='volume name to use for the disk image')
parser.add_argument('source_directory', help='directory with the Qt Creator sources')
parser.add_argument('binary_directory', help='directory that contains the Qt Creator.app')
+ parser.add_argument('--dmg-size', default='1500m', required=False)
+ parser.add_argument('--license-replacement', default=None,
+ help='Absolute path to a license file which replaces the default LICENSE.GPL3-EXCEPT from Qt Creator source directory.')
+ parser.add_argument('--keep-signed-content-at', default=None,
+ help='For online installer we want to keep the signed .app without the dmg. This is used to create a 7z.')
return parser.parse_args()
def main():
@@ -30,13 +35,19 @@ def main():
app_path = [app for app in os.listdir(tempdir) if app.endswith('.app')][0]
common.codesign(os.path.join(tempdir, app_path))
os.symlink('/Applications', os.path.join(tempdir, 'Applications'))
- shutil.copy(os.path.join(arguments.source_directory, 'LICENSE.GPL3-EXCEPT'), tempdir)
+ license_file = os.path.join(arguments.source_directory, 'LICENSE.GPL3-EXCEPT')
+ if (arguments.license_replacement):
+ license_file = arguments.license_replacement
+ shutil.copy(license_file, tempdir)
dmg_cmd = ['hdiutil', 'create', '-srcfolder', tempdir, '-volname', arguments.dmg_volumename,
- '-format', 'UDBZ', arguments.target_diskimage, '-ov', '-scrub', '-size', '1500m', '-verbose']
+ '-format', 'UDBZ', arguments.target_diskimage, '-ov', '-scrub', '-size', arguments.dmg_size, '-verbose']
subprocess.check_call(dmg_cmd)
# sleep a few seconds to make sure disk image is fully unmounted etc
time.sleep(5)
finally:
- shutil.rmtree(tempdir_base)
+ if arguments.keep_signed_content_at:
+ shutil.move(tempdir, arguments.keep_signed_content_at)
+ else:
+ shutil.rmtree(tempdir_base)
if __name__ == "__main__":
main()
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml
index 1d5d2434c6..7c017476cd 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetDelegate.qml
@@ -1,9 +1,10 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
TreeViewDelegate {
id: root
@@ -11,6 +12,9 @@ TreeViewDelegate {
required property Item assetsView
required property Item assetsRoot
+ property var assetsModel: AssetsLibraryBackend.assetsModel
+ property var rootView: AssetsLibraryBackend.rootView
+
property bool hasChildWithDropHover: false
property bool isHighlighted: false
readonly property string suffix: model.fileName.substr(-4)
@@ -22,7 +26,7 @@ TreeViewDelegate {
property int __currentRow: model.index
property string __itemPath: model.filePath
- readonly property int __fileItemHeight: thumbnailImage.height
+ readonly property int __fileItemHeight: thumbnailImage.height + 2 * StudioTheme.Values.border
readonly property int __dirItemHeight: 21
implicitHeight: root.__isDirectory ? root.__dirItemHeight : root.__fileItemHeight
@@ -67,14 +71,15 @@ TreeViewDelegate {
background: Rectangle {
id: bg
- width: root.implicitWidth
+ x: root.indentation * root.depth
+ width: root.implicitWidth - bg.x
color: {
if (root.__isDirectory && (root.isHighlighted || root.hasChildWithDropHover))
return StudioTheme.Values.themeInteraction
if (!root.__isDirectory && root.assetsView.selectedAssets[root.__itemPath])
- return StudioTheme.Values.themeInteraction
+ return StudioTheme.Values.themeSectionHeadBackground
if (mouseArea.containsMouse)
return StudioTheme.Values.themeSectionHeadBackground
@@ -83,18 +88,20 @@ TreeViewDelegate {
? StudioTheme.Values.themeSectionHeadBackground
: "transparent"
}
+ border.width: StudioTheme.Values.border
+ border.color: {
+ if (root.__isDirectory && (root.isHighlighted || root.hasChildWithDropHover))
+ return StudioTheme.Values.themeInteraction
+
+ if (!root.__isDirectory && root.assetsView.selectedAssets[root.__itemPath])
+ return StudioTheme.Values.themeInteraction
- // this rectangle exists so as to have some visual indentation for the directories
- // We prepend a default pane-colored rectangle so that the nested directory will
- // look moved a bit to the right
- Rectangle {
- anchors.top: bg.top
- anchors.bottom: bg.bottom
- anchors.left: bg.left
-
- width: root.indentation * root.depth
- implicitWidth: root.indentation * root.depth
- color: StudioTheme.Values.themePanelBackground
+ if (mouseArea.containsMouse)
+ return StudioTheme.Values.themeSectionHeadBackground
+
+ return root.__isDirectory
+ ? StudioTheme.Values.themeSectionHeadBackground
+ : "transparent"
}
}
@@ -102,12 +109,11 @@ TreeViewDelegate {
id: assetLabel
text: assetLabel.__computeText()
color: StudioTheme.Values.themeTextColor
- font.pixelSize: 14
+ font.pixelSize: StudioTheme.Values.mediumFont
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Qt.AlignVCenter
- function __computeText()
- {
+ function __computeText() {
return root.__isDirectory
? (root.hasChildren
? model.display.toUpperCase()
@@ -125,20 +131,20 @@ TreeViewDelegate {
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
- onExited: tooltipBackend.hideTooltip()
+ onExited: AssetsLibraryBackend.tooltipBackend.hideTooltip()
onEntered: mouseArea.allowTooltip = true
onCanceled: {
- tooltipBackend.hideTooltip()
+ AssetsLibraryBackend.tooltipBackend.hideTooltip()
mouseArea.allowTooltip = true
}
onPositionChanged: tooltipBackend.reposition()
onPressed: (mouse) => {
- forceActiveFocus()
+ mouseArea.forceActiveFocus()
mouseArea.allowTooltip = false
- tooltipBackend.hideTooltip()
+ AssetsLibraryBackend.tooltipBackend.hideTooltip()
if (root.__isDirectory)
return
@@ -152,7 +158,7 @@ TreeViewDelegate {
if (root.currFileSelected) {
let selectedPaths = root.assetsView.selectedPathsAsList()
- rootView.startDragAsset(selectedPaths, mapToGlobal(mouse.x, mouse.y))
+ AssetsLibraryBackend.rootView.startDragAsset(selectedPaths, mapToGlobal(mouse.x, mouse.y))
}
} else {
if (!root.assetsView.isAssetSelected(root.__itemPath) && !ctrlDown)
@@ -165,20 +171,25 @@ TreeViewDelegate {
onReleased: (mouse) => {
mouseArea.allowTooltip = true
+ if (root.__isDirectory)
+ return
+
if (mouse.button === Qt.LeftButton) {
if (!(mouse.modifiers & Qt.ControlModifier))
root.assetsView.selectedAssets = {}
root.assetsView.selectedAssets[root.__itemPath] = root.currFileSelected
root.assetsView.selectedAssetsChanged()
+
+ root.assetsView.currentFilePath = root.__itemPath
}
}
onDoubleClicked: (mouse) => {
- forceActiveFocus()
- allowTooltip = false
- tooltipBackend.hideTooltip()
- if (mouse.button === Qt.LeftButton && isEffect)
- rootView.openEffectMaker(filePath)
+ mouseArea.forceActiveFocus()
+ mouseArea.allowTooltip = false
+ AssetsLibraryBackend.tooltipBackend.hideTooltip()
+ if (mouse.button === Qt.LeftButton && root.isEffect)
+ AssetsLibraryBackend.rootView.openEffectMaker(filePath)
}
ToolTip {
@@ -187,14 +198,16 @@ TreeViewDelegate {
text: assetTooltip.__computeText()
delay: 1000
- function __computeText()
- {
+ function __computeText() {
let filePath = model.filePath.replace(assetsModel.contentDirPath(), "")
let fileSize = rootView.assetFileSize(model.filePath)
let fileExtMatches = model.filePath.match(/\.(.*)$/)
let fileExt = fileExtMatches ? "(" + fileExtMatches[1] + ")" : ""
- if (rootView.assetIsImage(model.filePath)) {
+ if (root.__isDirectory)
+ return filePath
+
+ if (rootView.assetIsImageOrTexture(model.filePath)) {
let size = rootView.imageSize(model.filePath)
return filePath + "\n"
@@ -208,9 +221,8 @@ TreeViewDelegate {
}
}
- function refresh()
- {
- text = assetTooltip.__computeText()
+ function refresh() {
+ assetTooltip.text = assetTooltip.__computeText()
}
}
@@ -218,53 +230,42 @@ TreeViewDelegate {
interval: 1000
running: mouseArea.containsMouse && mouseArea.allowTooltip
onTriggered: {
- if (suffix === ".ttf" || suffix === ".otf") {
- tooltipBackend.name = model.fileName
- tooltipBackend.path = model.filePath
- tooltipBackend.showTooltip()
+ if (root.isFont) {
+ AssetsLibraryBackend.tooltipBackend.name = model.fileName
+ AssetsLibraryBackend.tooltipBackend.path = model.filePath
+ AssetsLibraryBackend.tooltipBackend.showTooltip()
}
}
- } // Timer
+ }
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton)
root.__toggleExpandCurrentRow()
else
root.__openContextMenuForCurrentRow()
-
-
}
- } // MouseArea
+ }
- function getDirPath()
- {
+ function getDirPath() {
if (root.__isDirectory)
return model.filePath
else
return assetsModel.parentDirPath(model.filePath)
}
- function __openContextMenuForCurrentRow()
- {
+ function __openContextMenuForCurrentRow() {
let modelIndex = assetsModel.indexForPath(model.filePath)
function onFolderCreated(path) {
- root.assetsView.addCreatedFolder(path)
+ if (path)
+ root.assetsView.addCreatedFolder(path)
}
if (root.__isDirectory) {
- var row = root.assetsView.rowAtIndex(modelIndex)
- var expanded = root.assetsView.isExpanded(row)
-
var allExpandedState = root.assetsView.computeAllExpandedState()
- function onFolderRenamed() {
- if (expanded)
- root.assetsView.rowToExpand = row
- }
-
root.assetsView.contextMenu.openContextMenuForDir(modelIndex, model.filePath,
- model.fileName, allExpandedState, onFolderCreated, onFolderRenamed)
+ model.fileName, allExpandedState, onFolderCreated)
} else {
let parentDirIndex = assetsModel.parentDirIndex(model.filePath)
let selectedPaths = root.assetsView.selectedPathsAsList()
@@ -273,8 +274,7 @@ TreeViewDelegate {
}
}
- function __toggleExpandCurrentRow()
- {
+ function __toggleExpandCurrentRow() {
if (!root.__isDirectory)
return
@@ -291,8 +291,7 @@ TreeViewDelegate {
}
}
- function reloadImage()
- {
+ function reloadImage() {
if (root.__isDirectory)
return
@@ -303,7 +302,8 @@ TreeViewDelegate {
Image {
id: thumbnailImage
visible: !root.__isDirectory
- x: root.depth * root.indentation
+ y: StudioTheme.Values.border
+ x: root.depth * root.indentation + StudioTheme.Values.border
width: 48
height: 48
cache: false
@@ -313,8 +313,7 @@ TreeViewDelegate {
fillMode: Image.PreserveAspectFit
source: thumbnailImage.__computeSource()
- function __computeSource()
- {
+ function __computeSource() {
return root.__isDirectory
? ""
: "image://qmldesigner_assets/" + model.filePath
@@ -324,6 +323,5 @@ TreeViewDelegate {
if (thumbnailImage.status === Image.Ready)
assetTooltip.refresh()
}
-
- } // Image
-} // TreeViewDelegate
+ }
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml
index 23210ae4b5..211d3449a8 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml
@@ -1,21 +1,25 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
Item {
id: root
+ property var assetsModel: AssetsLibraryBackend.assetsModel
+ property var rootView: AssetsLibraryBackend.rootView
+
// Array of supported externally dropped files that are imported as-is
property var dropSimpleExtFiles: []
// Array of supported externally dropped files that trigger custom import process
property var dropComplexExtFiles: []
- readonly property int qtVersionAtLeast6_4: rootView.qtVersionIsAtLeast6_4()
+ readonly property int qtVersion: rootView.qtVersion()
property bool __searchBoxEmpty: true
AssetsContextMenu {
@@ -23,19 +27,20 @@ Item {
assetsView: assetsView
}
- function clearSearchFilter()
- {
- searchBox.clear();
+ function clearSearchFilter() {
+ searchBox.clear()
}
- function updateDropExtFiles(drag)
- {
+ function updateDropExtFiles(drag) {
root.dropSimpleExtFiles = []
root.dropComplexExtFiles = []
- var simpleSuffixes = rootView.supportedAssetSuffixes(false);
- var complexSuffixes = rootView.supportedAssetSuffixes(true);
+ var simpleSuffixes = rootView.supportedAssetSuffixes(false)
+ var complexSuffixes = rootView.supportedAssetSuffixes(true)
for (const u of drag.urls) {
- var url = u.toString();
+ var url = u.toString()
+ if (assetsModel.urlPathExistsInModel(url))
+ continue;
+
var ext = '*.' + url.slice(url.lastIndexOf('.') + 1).toLowerCase()
if (simpleSuffixes.includes(ext))
root.dropSimpleExtFiles.push(url)
@@ -48,22 +53,26 @@ Item {
DropArea { // handles external drop on empty area of the view (goes to root folder)
id: dropArea
- y: assetsView.y + assetsView.contentHeight + 5
+ y: assetsView.y + assetsView.contentHeight - assetsView.rowSpacing
width: parent.width
height: parent.height - y
- onEntered: (drag)=> {
+ onEntered: (drag) => {
root.updateDropExtFiles(drag)
}
- onDropped: {
- rootView.handleExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles,
+ onDropped: (drag) => {
+ drag.accept()
+ rootView.handleExtFilesDrop(root.dropSimpleExtFiles,
+ root.dropComplexExtFiles,
assetsModel.rootPath())
}
Canvas { // marker for the drop area
id: dropCanvas
- anchors.fill: parent
+ y: 5
+ width: parent.width
+ height: parent.height - y
visible: dropArea.containsDrag && root.dropSimpleExtFiles.length > 0
onWidthChanged: dropCanvas.requestPaint()
@@ -99,99 +108,120 @@ Item {
}
// called from C++ to close context menu on focus out
- function handleViewFocusOut()
- {
+ function handleViewFocusOut() {
contextMenu.close()
assetsView.selectedAssets = {}
assetsView.selectedAssetsChanged()
}
+ Timer {
+ id: updateSearchFilterTimer
+ interval: 200
+ repeat: false
+
+ onTriggered: {
+ assetsView.resetVerticalScrollPosition()
+ rootView.handleSearchFilterChanged(searchBox.text)
+ assetsView.expandAll()
+
+ if (root.__searchBoxEmpty && searchBox.text)
+ root.__searchBoxEmpty = false
+ else if (!root.__searchBoxEmpty && !searchBox.text)
+ root.__searchBoxEmpty = true
+ }
+ }
+
Column {
+ id: column
anchors.fill: parent
- anchors.topMargin: 5
spacing: 5
- Row {
- id: searchRow
-
+ Rectangle {
+ id: toolbar
width: parent.width
+ height: StudioTheme.Values.doubleToolbarHeight
+ color: StudioTheme.Values.themeToolbarBackground
- StudioControls.SearchBox {
- id: searchBox
-
- width: parent.width - addAssetButton.width - 5
-
- onSearchChanged: (searchText) => {
- updateSearchFilterTimer.restart()
+ Column {
+ id: toolbarColumn
+ anchors.fill: parent
+ anchors.topMargin: 6
+ anchors.bottomMargin: 6
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+ spacing: 12
+
+ StudioControls.SearchBox {
+ id: searchBox
+ width: parent.width
+ style: StudioTheme.Values.searchControlStyle
+ onSearchChanged: (searchText) => {
+ updateSearchFilterTimer.restart()
+ }
}
- }
- Timer {
- id: updateSearchFilterTimer
- interval: 200
- repeat: false
-
- onTriggered: {
- assetsView.resetVerticalScrollPosition()
- rootView.handleSearchFilterChanged(searchBox.text)
- assetsView.expandAll()
-
- if (root.__searchBoxEmpty && searchBox.text)
- root.__searchBoxEmpty = false
- else if (!root.__searchBoxEmpty && !searchBox.text)
- root.__searchBoxEmpty = true
+ Row {
+ id: buttonRow
+ width: parent.width
+ height: StudioTheme.Values.toolbarHeight
+ spacing: 6
+
+ HelperWidgets.AbstractButton {
+ id: addModuleButton
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.add_medium
+ tooltip: qsTr("Add a new asset to the project.")
+ onClicked: rootView.handleAddAsset()
+ }
}
}
-
- HelperWidgets.IconButton {
- id: addAssetButton
- anchors.verticalCenter: parent.verticalCenter
- tooltip: qsTr("Add a new asset to the project.")
- icon: StudioTheme.Constants.plus
- buttonSize: parent.height
-
- onClicked: rootView.handleAddAsset()
- }
}
Text {
text: qsTr("No match found.")
leftPadding: 10
color: StudioTheme.Values.themeTextColor
- font.pixelSize: 12
+ font.pixelSize: StudioTheme.Values.baseFont
visible: !assetsModel.haveFiles && !root.__searchBoxEmpty
}
Item { // placeholder when the assets library is empty
width: parent.width
- height: parent.height - searchRow.height
+ height: parent.height - toolbar.height - column.spacing
visible: !assetsModel.haveFiles && root.__searchBoxEmpty
clip: true
+ MouseArea { // right clicking the empty area of the view
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ contextMenu.openContextMenuForEmpty(assetsModel.rootPath())
+ }
+ }
+
DropArea { // handles external drop (goes into default folder based on suffix)
anchors.fill: parent
- onEntered: (drag)=> {
+ onEntered: (drag) => {
root.updateDropExtFiles(drag)
}
- onDropped: {
+ onDropped: (drag) => {
+ drag.accept()
rootView.emitExtFilesDrop(root.dropSimpleExtFiles, root.dropComplexExtFiles)
}
Column {
- id: colNoAssets
-
+ id: noAssetsColumn
spacing: 20
- x: 20
- width: root.width - 2 * x
- anchors.verticalCenter: parent.verticalCenter
+ width: root.width - 40
+ anchors.centerIn: parent
Text {
text: qsTr("Looks like you don't have any assets yet.")
color: StudioTheme.Values.themeTextColor
- font.pixelSize: 18
- width: colNoAssets.width
+ font.pixelSize: StudioTheme.Values.bigFont
+ width: noAssetsColumn.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
@@ -200,6 +230,7 @@ Item {
source: "image://qmldesigner_assets/browse"
anchors.horizontalCenter: parent.horizontalCenter
scale: maBrowse.containsMouse ? 1.2 : 1
+
Behavior on scale {
NumberAnimation {
duration: 300
@@ -218,8 +249,8 @@ Item {
Text {
text: qsTr("Drag-and-drop your assets here or click the '+' button to browse assets from the file system.")
color: StudioTheme.Values.themeTextColor
- font.pixelSize: 18
- width: colNoAssets.width
+ font.pixelSize: StudioTheme.Values.bigFont
+ width: noAssetsColumn.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
@@ -231,9 +262,8 @@ Item {
id: assetsView
assetsRoot: root
contextMenu: contextMenu
-
width: parent.width
- height: parent.height - y
+ height: parent.height - assetsView.y
}
- } // Column
+ }
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml
index 6c13a3c0b1..391c622048 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml
@@ -5,26 +5,34 @@ import QtQuick
import QtQuick.Controls
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
StudioControls.Menu {
id: root
required property Item assetsView
+ property var assetsModel: AssetsLibraryBackend.assetsModel
+ property var rootView: AssetsLibraryBackend.rootView
+
property bool __isDirectory: false
property var __fileIndex: null
property string __dirPath: ""
property string __dirName: ""
property var __onFolderCreated: null
- property var __onFolderRenamed: null
property var __dirIndex: null
property string __allExpandedState: ""
property var __selectedAssetPathsList: null
+ property bool __showInGraphicalShellEnabled: false
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
function openContextMenuForRoot(rootModelIndex, dirPath, dirName, onFolderCreated)
{
+ root.__showInGraphicalShellEnabled = true
+
+ rootView.updateContextMenuActionsEnableState()
+
root.__onFolderCreated = onFolderCreated
root.__fileIndex = ""
root.__dirPath = dirPath
@@ -34,11 +42,13 @@ StudioControls.Menu {
root.popup()
}
- function openContextMenuForDir(dirModelIndex, dirPath, dirName, allExpandedState,
- onFolderCreated, onFolderRenamed)
+ function openContextMenuForDir(dirModelIndex, dirPath, dirName, allExpandedState, onFolderCreated)
{
+ root.__showInGraphicalShellEnabled = true
+
+ rootView.updateContextMenuActionsEnableState()
+
root.__onFolderCreated = onFolderCreated
- root.__onFolderRenamed = onFolderRenamed
root.__dirPath = dirPath
root.__dirName = dirName
root.__fileIndex = ""
@@ -50,6 +60,15 @@ StudioControls.Menu {
function openContextMenuForFile(fileIndex, dirModelIndex, selectedAssetPathsList, onFolderCreated)
{
+ // check that all assets are in the same folder
+ let asset0 = selectedAssetPathsList[0]
+ let asset0Folder = asset0.substring(0, asset0.lastIndexOf('/'))
+
+ root.__showInGraphicalShellEnabled = selectedAssetPathsList.every(v => {
+ let assetFolder = v.substring(0, v.lastIndexOf('/'))
+ return assetFolder === asset0Folder
+ })
+
if (selectedAssetPathsList.length > 1) {
deleteFileItem.text = qsTr("Delete Files")
addTexturesItem.text = qsTr("Add Textures")
@@ -58,11 +77,24 @@ StudioControls.Menu {
addTexturesItem.text = qsTr("Add Texture")
}
+ rootView.updateContextMenuActionsEnableState()
+
root.__onFolderCreated = onFolderCreated
root.__selectedAssetPathsList = selectedAssetPathsList
root.__fileIndex = fileIndex
root.__dirIndex = dirModelIndex
- root.__dirPath = assetsModel.filePath(dirModelIndex)
+ root.__dirPath = AssetsLibraryBackend.assetsModel.filePath(dirModelIndex)
+ root.__isDirectory = false
+ root.popup()
+ }
+
+ function openContextMenuForEmpty(dirPath)
+ {
+ __showInGraphicalShellEnabled = true
+
+ root.__dirPath = dirPath
+ root.__fileIndex = ""
+ root.__dirIndex = ""
root.__isDirectory = false
root.popup()
}
@@ -91,16 +123,18 @@ StudioControls.Menu {
StudioControls.MenuItem {
id: addTexturesItem
text: qsTr("Add Texture")
- visible: root.__fileIndex && assetsModel.allFilePathsAreImages(root.__selectedAssetPathsList)
+ enabled: rootView.hasMaterialLibrary
+ visible: root.__fileIndex && AssetsLibraryBackend.assetsModel.allFilePathsAreTextures(root.__selectedAssetPathsList)
height: addTexturesItem.visible ? addTexturesItem.implicitHeight : 0
- onTriggered: rootView.addTextures(root.__selectedAssetPathsList)
+ onTriggered: AssetsLibraryBackend.rootView.addTextures(root.__selectedAssetPathsList)
}
StudioControls.MenuItem {
id: addLightProbes
text: qsTr("Add Light Probe")
+ enabled: rootView.hasMaterialLibrary && rootView.hasSceneEnv
visible: root.__fileIndex && root.__selectedAssetPathsList.length === 1
- && assetsModel.allFilePathsAreImages(root.__selectedAssetPathsList)
+ && AssetsLibraryBackend.assetsModel.allFilePathsAreTextures(root.__selectedAssetPathsList)
height: addLightProbes.visible ? addLightProbes.implicitHeight : 0
onTriggered: rootView.addLightProbe(root.__selectedAssetPathsList[0])
}
@@ -111,7 +145,7 @@ StudioControls.Menu {
visible: root.__fileIndex
height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
onTriggered: {
- let deleted = assetsModel.requestDeleteFiles(root.__selectedAssetPathsList)
+ let deleted = AssetsLibraryBackend.assetsModel.requestDeleteFiles(root.__selectedAssetPathsList)
if (!deleted)
confirmDeleteFiles.open()
}
@@ -142,12 +176,14 @@ StudioControls.Menu {
dirPath: root.__dirPath
dirName: root.__dirName
- onAccepted: root.__onFolderRenamed()
+ onAccepted: root.__onFolderCreated(renameFolderDialog.renamedDirPath)
}
}
StudioControls.MenuItem {
text: qsTr("New Folder")
+ visible: AssetsLibraryBackend.assetsModel.haveFiles
+ height: visible ? implicitHeight : 0
NewFolderDialog {
id: newFolderDialog
@@ -173,11 +209,11 @@ StudioControls.Menu {
}
onTriggered: {
- if (!assetsModel.hasChildren(root.__dirIndex)) {
+ if (!AssetsLibraryBackend.assetsModel.hasChildren(root.__dirIndex)) {
// NOTE: the folder may still not be empty -- it doesn't have files visible to the
// user, but that doesn't mean that there are no other files (e.g. files of unknown
// types) on disk in this directory.
- assetsModel.deleteFolderRecursively(root.__dirIndex)
+ AssetsLibraryBackend.assetsModel.deleteFolderRecursively(root.__dirIndex)
} else {
confirmDeleteFolderDialog.open()
}
@@ -186,14 +222,28 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("New Effect")
- visible: assetsModel.canCreateEffects()
+ visible: rootView.canCreateEffects()
+ height: visible ? implicitHeight : 0
NewEffectDialog {
id: newEffectDialog
- parent: root.assetsView
+ parent: root.assetsView.parent
dirPath: root.__dirPath
}
onTriggered: newEffectDialog.open()
}
+
+ StudioControls.MenuItem {
+ text: rootView.showInGraphicalShellMsg()
+
+ enabled: root.__showInGraphicalShellEnabled
+
+ onTriggered: {
+ if (!root.__fileIndex || root.__selectedAssetPathsList.length > 1)
+ rootView.showInGraphicalShell(root.__dirPath)
+ else
+ rootView.showInGraphicalShell(root.__selectedAssetPathsList[0])
+ }
+ }
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml
index 9056a802d5..ede7f58caf 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml
@@ -5,20 +5,27 @@ import QtQuick
import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
+import AssetsLibraryBackend
TreeView {
id: root
clip: true
- interactive: verticalScrollBar.visible && !root.contextMenu.opened
+ interactive: verticalScrollBar.visible && !root.contextMenu.opened && !rootView.isDragging
reuseItems: false
boundsBehavior: Flickable.StopAtBounds
rowSpacing: 5
+ property var assetsModel: AssetsLibraryBackend.assetsModel
+ property var rootView: AssetsLibraryBackend.rootView
+ property var tooltipBackend: AssetsLibraryBackend.tooltipBackend
+
required property Item assetsRoot
required property StudioControls.Menu contextMenu
property alias verticalScrollBar: verticalScrollBar
property var selectedAssets: ({})
+ // the latest file that was clicked, or changed to via Up or Down keys
+ property string currentFilePath: ""
// used to see if the op requested is to expand or to collapse.
property int lastRowCount: -1
@@ -29,7 +36,7 @@ TreeView {
property int rootPathRow: 0
// i.e. first child of the root path
readonly property int firstRow: root.rootPathRow + 1
- property int rowToExpand: -1
+ readonly property int lastRow: root.rows - 1
property var __createdDirectories: []
rowHeightProvider: (row) => {
@@ -52,7 +59,7 @@ TreeView {
assetsModel.syncHaveFiles()
}
- updateRows()
+ root.updateRows()
}
Timer {
@@ -74,6 +81,19 @@ TreeView {
updateRowsTimer.restart()
}
+
+ function onDeleteSelectedAssetsRequested()
+ {
+ let selectedPaths = root.selectedPathsAsList()
+ if (!selectedPaths.length)
+ return
+
+ let deleted = assetsModel.requestDeleteFiles(selectedPaths)
+ if (!deleted) {
+ confirmDeleteFiles.files = selectedPaths
+ confirmDeleteFiles.open()
+ }
+ }
}
Connections {
@@ -170,11 +190,6 @@ TreeView {
if (root.requestedExpandAll)
root.__doExpandAll()
} else {
- if (root.rowToExpand > 0) {
- root.expand(root.rowToExpand)
- root.rowToExpand = -1
- }
-
// on collapsing, set expandAll flag to false.
root.requestedExpandAll = false;
}
@@ -309,14 +324,84 @@ TreeView {
function __modelIndex(row)
{
// The modelIndex() function exists since 6.3. In Qt 6.3, this modelIndex() function was a
- // member of the TreeView, while in Qt6.4 it was moved to TableView. In Qt6.4, the order of
- // the arguments was changed.
- if (assetsRoot.qtVersionAtLeast6_4)
+ // member of the TreeView, while in Qt6.4 it was moved to TableView. In Qt 6.4, the order of
+ // the arguments was changed, and in Qt 6.5 the order was changed again. Due to this mess,
+ // the whole function was deprecated in Qt 6.4.3 and replaced with index() function.
+ if (assetsRoot.qtVersion >= 0x060403)
+ return root.index(row, 0)
+ else if (assetsRoot.qtVersion >= 0x060400)
return root.modelIndex(0, row)
else
return root.modelIndex(row, 0)
}
+ function __selectRow(row: int)
+ {
+ let index = root.__modelIndex(row)
+ if (assetsModel.isDirectory(index))
+ return
+
+ let filePath = assetsModel.filePath(index)
+
+ root.clearSelectedAssets()
+ root.setAssetSelected(filePath, true)
+ root.currentFilePath = filePath
+ }
+
+ Keys.enabled: true
+
+ Keys.onUpPressed: {
+ if (!root.currentFilePath)
+ return
+
+ let index = assetsModel.indexForPath(root.currentFilePath)
+ let row = root.rowAtIndex(index)
+ let nextRow = row
+ let nextIndex = index
+
+ do {
+ if (nextRow <= root.firstRow)
+ return // don't select hidden rows
+
+ nextRow--
+ nextIndex = root.__modelIndex(nextRow)
+ } while (assetsModel.isDirectory(nextIndex))
+
+ root.__selectRow(nextRow)
+ root.positionViewAtRow(nextRow, TableView.Contain)
+ }
+
+ Keys.onDownPressed: {
+ if (!root.currentFilePath)
+ return
+
+ let index = assetsModel.indexForPath(root.currentFilePath)
+ let row = root.rowAtIndex(index)
+
+ let nextRow = row
+ let nextIndex = index
+
+ do {
+ if (nextRow >= root.lastRow)
+ return // don't select hidden rows
+
+ nextRow++
+ nextIndex = root.__modelIndex(nextRow)
+ } while (assetsModel.isDirectory(nextIndex))
+
+ root.__selectRow(nextRow)
+ root.positionViewAtRow(nextRow, TableView.Contain)
+ }
+
+ ConfirmDeleteFilesDialog {
+ id: confirmDeleteFiles
+ parent: root
+ files: []
+
+ onAccepted: root.clearSelectedAssets()
+ onClosed: confirmDeleteFiles.files = []
+ }
+
DropArea {
id: dropArea
enabled: true
@@ -350,13 +435,14 @@ TreeView {
let [row, item] = dropArea.__rowAndItem(drag)
if (item) {
- root.endDropHover(row)
+ drag.accept()
+ root.endDropHover(row)
- let dirPath = item.getDirPath()
+ let dirPath = item.getDirPath()
- rootView.emitExtFilesDrop(root.assetsRoot.dropSimpleExtFiles,
- root.assetsRoot.dropComplexExtFiles,
- dirPath)
+ rootView.emitExtFilesDrop(root.assetsRoot.dropSimpleExtFiles,
+ root.assetsRoot.dropComplexExtFiles,
+ dirPath)
}
dropArea.__isHoveringDrop = false
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFilesDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml
index 0ab2ce533a..756176dcca 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFilesDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioTheme as StudioTheme
import StudioControls as StudioControls
+import AssetsLibraryBackend
Dialog {
id: root
@@ -61,7 +62,7 @@ Dialog {
text: qsTr("Delete")
onClicked: {
- assetsModel.deleteFiles(root.files, dontAskAgain.checked)
+ AssetsLibraryBackend.assetsModel.deleteFiles(root.files, dontAskAgain.checked)
root.accept()
}
}
@@ -98,7 +99,7 @@ Dialog {
delegate: Text {
elide: Text.ElideLeft
- text: model.modelData.replace(assetsModel.currentProjectDirPath(), "")
+ text: model.modelData.replace(AssetsLibraryBackend.assetsModel.currentProjectDirPath(), "")
color: StudioTheme.Values.themeTextColor
width: parent.width - (verticalScrollBar.scrollBarVisible ? verticalScrollBar.width : 0)
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml
index f75a094a7f..6faef2434a 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml
@@ -5,6 +5,7 @@ import QtQuick
import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
Dialog {
id: root
@@ -53,7 +54,7 @@ Dialog {
text: qsTr("Delete")
onClicked: {
- assetsModel.deleteFolderRecursively(root.dirIndex)
+ AssetsLibraryBackend.assetsModel.deleteFolderRecursively(root.dirIndex)
root.accept()
}
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ErrorDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ErrorDialog.qml
index 58e1910b18..58e1910b18 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ErrorDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ErrorDialog.qml
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewEffectDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml
index e34237a0c3..a5a1235587 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewEffectDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
Dialog {
id: root
@@ -18,10 +19,7 @@ Dialog {
required property string dirPath
readonly property int __maxPath: 32
- HelperWidgets.RegExpValidator {
- id: effectNameValidator
- regExp: /^[A-Z]\w[A-Za-z0-9_]*$/
- }
+ property var rootView: AssetsLibraryBackend.rootView
ErrorDialog {
id: creationFailedDialog
@@ -44,10 +42,16 @@ Dialog {
actionIndicator.visible: false
translationIndicator.visible: false
- validator: effectNameValidator
Keys.onEnterPressed: btnCreate.onClicked()
Keys.onReturnPressed: btnCreate.onClicked()
+ Keys.onEscapePressed: root.reject()
+
+ onTextChanged: {
+ let validator = /^[A-Z]\w{2,}[A-Za-z0-9_]*$/
+ txtNameValidatorMsg.visible = text.length > 0 && !validator.test(text)
+ btnCreate.enabled = !txtNameValidatorMsg.visible
+ }
}
}
@@ -65,6 +69,17 @@ Dialog {
visible: effectName.text.length > root.__maxPath
}
+ Text {
+ id: txtNameValidatorMsg
+ text: qsTr('The name must start with a capital letter, ' +
+ 'contain at least three characters, ' +
+ 'and cannot have any special characters.')
+ color: "#ff0000"
+ anchors.right: parent.right
+ anchors.left: parent.left
+ wrapMode: "WordWrap"
+ }
+
Item { // spacer
width: 1
height: 20
@@ -81,8 +96,8 @@ Dialog {
&& effectName.length >=3
&& effectName.text.length <= root.__maxPath
onClicked: {
- const path = assetsModel.getUniqueEffectPath(root.dirPath, effectName.text)
- if (assetsModel.createNewEffect(path))
+ const path = AssetsLibraryBackend.rootView.getUniqueEffectPath(root.dirPath, effectName.text)
+ if (AssetsLibraryBackend.rootView.createNewEffect(path))
root.accept()
else
creationFailedDialog.open()
@@ -97,7 +112,7 @@ Dialog {
}
onOpened: {
- const path = assetsModel.getUniqueEffectPath(root.dirPath, "Effect01")
+ const path = AssetsLibraryBackend.rootView.getUniqueEffectPath(root.dirPath, "Effect01")
effectName.text = path.split('/').pop().replace(".qep", '')
effectName.selectAll()
effectName.forceActiveFocus()
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml
index c1966a9748..a1afe46491 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
Dialog {
id: root
@@ -49,6 +50,7 @@ Dialog {
Keys.onEnterPressed: btnCreate.onClicked()
Keys.onReturnPressed: btnCreate.onClicked()
+ Keys.onEscapePressed: root.reject()
onTextChanged: {
root.createdDirPath = root.dirPath + '/' + folderName.text
@@ -85,7 +87,7 @@ Dialog {
enabled: folderName.text !== "" && root.createdDirPath.length <= root.__maxPath
onClicked: {
root.createdDirPath = root.dirPath + '/' + folderName.text
- if (assetsModel.addNewFolder(root.createdDirPath))
+ if (AssetsLibraryBackend.assetsModel.addNewFolder(root.createdDirPath))
root.accept()
else
creationFailedDialog.open()
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml
index a19b7a6ee0..0b9ae30255 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import AssetsLibraryBackend
Dialog {
id: root
@@ -17,6 +18,7 @@ Dialog {
modal: true
property bool renameError: false
+ property string renamedDirPath: ""
required property string dirPath
required property string dirName
@@ -83,9 +85,11 @@ Dialog {
text: qsTr("Rename")
enabled: folderRename.text !== ""
onClicked: {
- var success = assetsModel.renameFolder(root.dirPath, folderRename.text)
- if (success)
+ var success = AssetsLibraryBackend.assetsModel.renameFolder(root.dirPath, folderRename.text)
+ if (success) {
+ root.renamedDirPath = root.dirPath.replace(/(.*\/)[^/]+$/, "$1" + folderRename.text)
root.accept()
+ }
root.renameError = !success
}
@@ -104,4 +108,8 @@ Dialog {
folderRename.forceActiveFocus()
root.renameError = false
}
+
+ onRejected: {
+ root.renamedDirPath = ""
+ }
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml
index e9d18d9ded..37154ec170 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibrary.qml
@@ -1,13 +1,14 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuickDesignerTheme
-import HelperWidgets as HelperWidgets
-import StudioControls as StudioControls
-import StudioTheme as StudioTheme
+import HelperWidgets 2.0 as HelperWidgets
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
+import ContentLibraryBackend
Item {
id: root
@@ -18,6 +19,7 @@ Item {
materialsView.closeContextMenu()
texturesView.closeContextMenu()
environmentsView.closeContextMenu()
+ HelperWidgets.Controller.closeContextMenu()
}
// Called from C++
@@ -28,30 +30,54 @@ Item {
Column {
id: col
- y: 5
+ anchors.fill: parent
spacing: 5
- StudioControls.SearchBox {
- id: searchBox
-
- width: root.width
- enabled: {
- if (tabBar.currIndex == 0) { // Materials tab
- materialsModel.matBundleExists
- && rootView.hasMaterialLibrary
- && materialsModel.hasRequiredQuick3DImport
- } else { // Textures / Environments tabs
- texturesModel.texBundleExists
+ Rectangle {
+ width: parent.width
+ height: StudioTheme.Values.doubleToolbarHeight
+ color: StudioTheme.Values.themeToolbarBackground
+
+ Column {
+ anchors.fill: parent
+ anchors.topMargin: 6
+ anchors.bottomMargin: 6
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+ spacing: 12
+
+ StudioControls.SearchBox {
+ id: searchBox
+ width: parent.width
+ style: StudioTheme.Values.searchControlStyle
+ enabled: {
+ if (tabBar.currIndex === 0) { // Materials tab
+ ContentLibraryBackend.materialsModel.matBundleExists
+ && ContentLibraryBackend.rootView.hasMaterialLibrary
+ && ContentLibraryBackend.materialsModel.hasRequiredQuick3DImport
+ } else { // Textures / Environments tabs
+ ContentLibraryBackend.texturesModel.texBundleExists
+ }
+ }
+
+ onSearchChanged: (searchText) => {
+ ContentLibraryBackend.rootView.handleSearchFilterChanged(searchText)
+
+ // make sure categories with matches are expanded
+ materialsView.expandVisibleSections()
+ texturesView.expandVisibleSections()
+ environmentsView.expandVisibleSections()
+ }
}
- }
-
- onSearchChanged: (searchText) => {
- rootView.handleSearchFilterChanged(searchText)
- // make sure categories with matches are expanded
- materialsView.expandVisibleSections()
- texturesView.expandVisibleSections()
- environmentsView.expandVisibleSections()
+ ContentLibraryTabBar {
+ id: tabBar
+ width: parent.width
+ height: StudioTheme.Values.toolbarHeight
+ tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.material_medium},
+ {name: qsTr("Textures"), icon: StudioTheme.Constants.textures_medium},
+ {name: qsTr("Environments"), icon: StudioTheme.Constants.languageList_medium}]
+ }
}
}
@@ -59,14 +85,6 @@ Item {
id: confirmUnimportDialog
}
- ContentLibraryTabBar {
- id: tabBar
- // TODO: update icons
- tabsModel: [{name: qsTr("Materials"), icon: StudioTheme.Constants.gradient},
- {name: qsTr("Textures"), icon: StudioTheme.Constants.materialPreviewEnvironment},
- {name: qsTr("Environments"), icon: StudioTheme.Constants.translationSelectLanguages}]
- }
-
StackLayout {
width: root.width
height: root.height - y
@@ -89,7 +107,8 @@ Item {
id: texturesView
width: root.width
- model: texturesModel
+ model: ContentLibraryBackend.texturesModel
+ sectionCategory: "ContentLib_Tex"
searchBox: searchBox
}
@@ -98,7 +117,8 @@ Item {
id: environmentsView
width: root.width
- model: environmentsModel
+ model: ContentLibraryBackend.environmentsModel
+ sectionCategory: "ContentLib_Env"
searchBox: searchBox
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
index f582094666..5bafd1d052 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
@@ -8,26 +8,36 @@ import HelperWidgets 2.0
import QtQuick.Controls
import StudioTheme 1.0 as StudioTheme
+import ContentLibraryBackend
+
+import WebFetcher 1.0
Item {
id: root
signal showContextMenu()
+ // Download states: "" (ie default, not downloaded), "unavailable", "downloading", "downloaded",
+ // "failed"
+ property string downloadState: modelData.isDownloaded() ? "downloaded" : ""
+
visible: modelData.bundleMaterialVisible
MouseArea {
id: mouseArea
+ enabled: root.downloadState !== "downloading"
hoverEnabled: true
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
- if (mouse.button === Qt.LeftButton && !materialsModel.importerRunning)
- rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
- else if (mouse.button === Qt.RightButton)
+ if (mouse.button === Qt.LeftButton && !materialsModel.importerRunning) {
+ if (root.downloadState === "downloaded")
+ ContentLibraryBackend.rootView.startDragMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
+ } else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") {
root.showContextMenu()
+ }
}
}
@@ -37,6 +47,15 @@ Item {
Item { width: 1; height: 5 } // spacer
+ DownloadPane {
+ id: downloadPane
+ width: root.width - 10
+ height: img.width
+ visible: root.downloadState === "downloading"
+
+ onRequestCancel: downloader.cancel()
+ }
+
Image {
id: img
@@ -45,6 +64,7 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
source: modelData.bundleMaterialIcon
cache: false
+ visible: root.downloadState != "downloading"
Rectangle { // circular indicator for imported bundle materials
width: 10
@@ -81,14 +101,61 @@ Item {
pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
anchors.right: img.right
anchors.bottom: img.bottom
- enabled: !materialsModel.importerRunning
- visible: containsMouse || mouseArea.containsMouse
+ enabled: !ContentLibraryBackend.materialsModel.importerRunning
+ visible: root.downloadState === "downloaded"
+ && (containsMouse || mouseArea.containsMouse)
onClicked: {
- materialsModel.addToProject(modelData)
+ ContentLibraryBackend.materialsModel.addToProject(modelData)
+ }
+ } // IconButton
+
+ IconButton {
+ id: downloadIcon
+ icon: root.downloadState === "unavailable"
+ ? StudioTheme.Constants.downloadUnavailable
+ : StudioTheme.Constants.download
+
+ iconColor: root.downloadState === "unavailable" || root.downloadState === "failed"
+ ? StudioTheme.Values.themeRedLight
+ : StudioTheme.Values.themeTextColor
+
+ iconSize: 22
+ iconScale: downloadIcon.containsMouse ? 1.2 : 1
+ iconStyle: Text.Outline
+ iconStyleColor: "black"
+
+ tooltip: qsTr("Click to download material")
+ buttonSize: 22
+
+ transparentBg: true
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ visible: root.downloadState !== "downloaded"
+
+ anchors.bottomMargin: 0
+ anchors.rightMargin: 4
+
+ Rectangle { // arrow fill
+ anchors.centerIn: parent
+ z: -1
+
+ width: parent.width / 2
+ height: parent.height / 2
+ color: "black"
}
- }
- }
+
+ onClicked: {
+ if (root.downloadState !== "" && root.downloadState !== "failed")
+ return
+
+ downloadPane.beginDownload(Qt.binding(function() { return downloader.progress }))
+
+ root.downloadState = ""
+ downloader.start()
+ }
+ } // IconButton
+ } // Image
TextInput {
id: matName
@@ -109,5 +176,44 @@ Item {
selectionColor: StudioTheme.Values.themeTextSelectionColor
selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
}
- }
+ } // Column
+
+ MultiFileDownloader {
+ id: downloader
+
+ baseUrl: modelData.bundleMaterialBaseWebUrl
+ files: modelData.bundleMaterialFiles
+
+ targetDirPath: modelData.bundleMaterialParentPath
+
+ onDownloadStarting: {
+ root.downloadState = "downloading"
+ }
+
+ onFinishedChanged: {
+ downloadPane.endDownload()
+
+ root.downloadState = "downloaded"
+ }
+
+ onDownloadCanceled: {
+ downloadPane.endDownload()
+
+ root.downloadState = ""
+ }
+
+ onDownloadFailed: {
+ downloadPane.endDownload()
+
+ root.downloadState = "failed"
+ }
+
+ downloader: FileDownloader {
+ id: fileDownloader
+ url: downloader.nextUrl
+ probeUrl: false
+ downloadEnabled: true
+ targetFilePath: downloader.nextTargetPath
+ } // FileDownloader
+ } // MultiFileDownloader
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml
index 4e4b72bb06..ca3a05bdd1 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialContextMenu.qml
@@ -29,13 +29,13 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("Apply to selected (replace)")
enabled: root.targetAvailable && root.hasModelSelection
- onTriggered: root.applyToSelected(root.targetMaterial, false)
+ onTriggered: materialsModel.applyToSelected(root.targetMaterial, false)
}
StudioControls.MenuItem {
text: qsTr("Apply to selected (add)")
enabled: root.targetAvailable && root.hasModelSelection
- onTriggered: root.applyToSelected(root.targetMaterial, true)
+ onTriggered: materialsModel.applyToSelected(root.targetMaterial, true)
}
StudioControls.MenuSeparator {}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
index 5f171db464..2c6a5256f4 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
@@ -5,18 +5,20 @@ import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import ContentLibraryBackend
HelperWidgets.ScrollView {
id: root
clip: true
- interactive: !ctxMenu.opened
+ interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
readonly property int cellWidth: 100
readonly property int cellHeight: 120
property var currMaterialItem: null
property var rootItem: null
+ property var materialsModel: ContentLibraryBackend.materialsModel
required property var searchBox
@@ -60,6 +62,8 @@ HelperWidgets.ScrollView {
visible: bundleCategoryVisible && !materialsModel.isEmpty
expanded: bundleCategoryExpanded
expandOnClick: false
+ category: "ContentLib_Mat"
+
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
onExpand: bundleCategoryExpanded = true
onCollapse: bundleCategoryExpanded = false
@@ -93,12 +97,12 @@ HelperWidgets.ScrollView {
id: infoText
text: {
if (!materialsModel.matBundleExists)
- qsTr("<b>Content Library</b> materials are not installed.")
- else if (!rootView.hasQuick3DImport)
+ qsTr("No materials available. Make sure you have internet connection.")
+ else if (!ContentLibraryBackend.rootView.hasQuick3DImport)
qsTr("To use <b>Content Library</b>, first add the QtQuick3D module in the <b>Components</b> view.")
else if (!materialsModel.hasRequiredQuick3DImport)
qsTr("To use <b>Content Library</b>, version 6.3 or later of the QtQuick3D module is required.")
- else if (!rootView.hasMaterialLibrary)
+ else if (!ContentLibraryBackend.rootView.hasMaterialLibrary)
qsTr("<b>Content Library</b> is disabled inside a non-visual component.")
else if (!searchBox.isEmpty())
qsTr("No match found.")
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml
index 0ee7ce8f08..ca8fb64ecc 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml
@@ -1,33 +1,29 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
-import StudioTheme as StudioTheme
+import HelperWidgets 2.0 as HelperWidgets
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
-Rectangle {
+Row {
id: root
- width: parent.width
- height: 50
- color: StudioTheme.Values.themeSectionHeadBackground
-
property int currIndex: 0
property alias tabsModel: repeater.model
- Row {
- spacing: 1
-
- Repeater {
- id: repeater
+ spacing: 6
- ContentLibraryTabButton {
- height: root.height
+ Repeater {
+ id: repeater
- name: modelData.name
- icon: modelData.icon
- selected: root.currIndex === index
- onClicked: root.currIndex = index
- }
+ ContentLibraryTabButton {
+ required property int index
+ required property var modelData
+ name: modelData.name
+ icon: modelData.icon
+ selected: root.currIndex === index
+ onClicked: root.currIndex = index
}
}
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml
index 4dda92592e..587f846a10 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml
@@ -2,51 +2,51 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
-import StudioTheme as StudioTheme
+import HelperWidgets 2.0 as HelperWidgets
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
Rectangle {
id: root
signal clicked()
- property alias icon: icon.text
- property alias name: name.text
+ property alias icon: button.buttonIcon
+ property alias name: label.text
property bool selected: false
- width: 100
- height: 100
- color: root.selected ? StudioTheme.Values.themePanelBackground
- : mouseArea.containsMouse ? Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.3)
- : StudioTheme.Values.themeSectionHeadBackground
+ height: button.height
+ width: button.width + label.width + contentRow.spacing + 6
+ color: StudioTheme.Values.themeToolbarBackground
+ radius: StudioTheme.Values.smallRadius
- Text {
- id: icon
+ state: "default"
- color: root.selected ? StudioTheme.Values.themeInteraction : StudioTheme.Values.themeTextColor
+ Row {
+ id: contentRow
+ spacing: 6
- font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.mediumIconFontSize
- anchors.horizontalCenter: parent.horizontalCenter
- y: 8
- }
-
- Text {
- id: name
-
- font.weight: Font.DemiBold
- font.pixelSize: StudioTheme.Values.baseFontSize
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 6
+ HelperWidgets.AbstractButton {
+ id: button
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.material_medium
+ hover: mouseArea.containsMouse
+ checked: root.selected
+ checkable: true
+ checkedInverted: true
+ autoExclusive: true
+ }
- color: root.selected ? StudioTheme.Values.themeInteraction : StudioTheme.Values.themeTextColor
- }
-
- Rectangle { // strip
- width: root.width
- height: 4
- color: root.selected ? StudioTheme.Values.themeInteraction : "transparent"
- anchors.bottom: parent.bottom
+ Text {
+ id: label
+ height: StudioTheme.Values.statusbarButtonStyle.controlSize.height
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("Materials")
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
}
MouseArea {
@@ -55,4 +55,43 @@ Rectangle {
hoverEnabled: true
onClicked: root.clicked()
}
+
+ states: [
+ State {
+ name: "default"
+ when: !mouseArea.containsMouse && !button.checked
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !button.checked
+ PropertyChanges {
+ target: root
+ color: StudioTheme.Values.themeControlBackground_topToolbarHover
+ }
+ },
+ State {
+ name: "checked"
+ when: !mouseArea.containsMouse && button.checked
+ PropertyChanges {
+ target: root
+ color: StudioTheme.Values.themeInteraction
+ }
+ PropertyChanges {
+ target: label
+ color: StudioTheme.Values.themeTextSelectedTextColor
+ }
+ },
+ State {
+ name: "hoverChecked"
+ when: mouseArea.containsMouse && button.checked
+ PropertyChanges {
+ target: root
+ color: StudioTheme.Values.themeInteractionHover
+ }
+ PropertyChanges {
+ target: label
+ color: StudioTheme.Values.themeTextSelectedTextColor
+ }
+ }
+ ]
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
index ae691775e4..a556aad72a 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
@@ -9,43 +9,243 @@ import QtQuick.Controls
import StudioTheme 1.0 as StudioTheme
-Image {
+import WebFetcher 1.0
+import ContentLibraryBackend
+
+Item {
id: root
- source: modelData.textureIcon
- visible: modelData.textureVisible
- cache: false
+ // Download states: "" (ie default, not downloaded), "unavailable", "downloading", "downloaded",
+ // "failed"
+ property string downloadState: modelData.isDownloaded() ? "downloaded" : ""
+ property bool delegateVisible: modelData.textureVisible
+
+ property alias allowCancel: progressBar.closeButtonVisible
+ property alias progressValue: progressBar.value
+ property alias progressText: progressLabel.text
+
+ visible: root.delegateVisible
signal showContextMenu()
+ function statusText()
+ {
+ if (root.downloadState === "downloaded")
+ return qsTr("Texture was already downloaded.")
+ if (root.downloadState === "unavailable")
+ return qsTr("Network/Texture unavailable or broken Link.")
+ if (root.downloadState === "failed")
+ return qsTr("Could not download texture.")
+
+ return qsTr("Click to download the texture.")
+ }
+
+ Rectangle {
+ id: downloadPane
+ anchors.fill: parent
+ color: StudioTheme.Values.themeThumbnailBackground
+ border.color: "#00000000"
+
+ visible: root.downloadState === "downloading"
+
+ TextureProgressBar {
+ id: progressBar
+ anchors.rightMargin: 10
+ anchors.leftMargin: 10
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ visible: false
+
+ onCancelRequested: {
+ downloader.cancel()
+ }
+
+ Text {
+ id: progressLabel
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("Progress:")
+ anchors.bottom: parent.top
+ anchors.bottomMargin: 5
+ anchors.left: parent.left
+ font.pixelSize: 12
+ }
+
+ Row {
+ anchors.top: parent.bottom
+ anchors.topMargin: 5
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Text {
+ id: progressAmount
+ color: StudioTheme.Values.themeTextColor
+ text: progressBar.value.toFixed(1)
+
+ font.pixelSize: 12
+ }
+
+ Text {
+ id: percentSign
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("%")
+ font.pixelSize: 12
+ }
+ }
+ } // TextureProgressBar
+ } // Rectangle
+
+ Image {
+ id: image
+ anchors.fill: parent
+
+ source: modelData.textureIcon
+ visible: root.delegateVisible && root.downloadState != "downloading"
+ cache: false
+
+ property string webUrl: modelData.textureWebUrl
+
+ IconButton {
+ id: downloadIcon
+ icon: root.downloadState === "unavailable"
+ ? StudioTheme.Constants.downloadUnavailable
+ : StudioTheme.Constants.download
+
+ iconColor: root.downloadState === "unavailable" || root.downloadState === "failed"
+ ? StudioTheme.Values.themeRedLight
+ : StudioTheme.Values.themeTextColor
+
+ iconSize: 22
+ iconScale: downloadIcon.containsMouse ? 1.2 : 1
+ iconStyle: Text.Outline
+ iconStyleColor: "black"
+
+ tooltip: modelData.textureToolTip + (downloadIcon.visible
+ ? "\n\n" + root.statusText()
+ : "")
+ buttonSize: 22
+
+ transparentBg: true
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ visible: root.downloadState !== "downloaded"
+
+ anchors.bottomMargin: 0
+ anchors.rightMargin: 4
+
+ Rectangle { // Arrow Fill
+ anchors.centerIn: parent
+ z: -1
+
+ width: parent.width / 2
+ height: parent.height / 2
+ color: "black"
+ }
+
+ onClicked: {
+ if (root.downloadState !== "" && root.downloadState !== "failed")
+ return
+
+ if (!ContentLibraryBackend.rootView.markTextureDownloading())
+ return
+
+ progressBar.visible = true
+ tooltip.visible = false
+ root.progressText = qsTr("Downloading...")
+ root.allowCancel = true
+ root.progressValue = Qt.binding(function() { return downloader.progress })
+
+ root.downloadState = ""
+ downloader.start()
+ }
+ } // IconButton
+
+ ToolTip {
+ id: tooltip
+ // contentWidth is not calculated correctly by the toolTip (resulting in a wider tooltip than
+ // needed). Using a helper Text to calculate the correct width
+ contentWidth: helperText.width
+ bottomInset: -2
+ text: modelData.textureToolTip + (downloadIcon.visible
+ ? "\n\n" + root.statusText()
+ : "")
+ delay: 1000
+
+ Text {
+ id: helperText
+ text: tooltip.text
+ visible: false
+ }
+ }
+ } // Image
+
MouseArea {
id: mouseArea
anchors.fill: parent
+ hoverEnabled: !downloadIcon.visible
+ propagateComposedEvents: downloadIcon.visible
acceptedButtons: Qt.LeftButton | Qt.RightButton
- hoverEnabled: true
+
+ onEntered: tooltip.visible = image.visible
+ onExited: tooltip.visible = false
onPressed: (mouse) => {
- if (mouse.button === Qt.LeftButton)
- rootView.startDragTexture(modelData, mapToGlobal(mouse.x, mouse.y))
- else if (mouse.button === Qt.RightButton)
+ if (mouse.button === Qt.LeftButton) {
+ if (root.downloadState === "downloaded")
+ ContentLibraryBackend.rootView.startDragTexture(modelData, mapToGlobal(mouse.x, mouse.y))
+ } else if (mouse.button === Qt.RightButton && root.downloadState === "downloaded") {
root.showContextMenu()
+ }
+ }
+ }
+
+ FileDownloader {
+ id: downloader
+ url: image.webUrl
+ probeUrl: false
+ downloadEnabled: true
+ onDownloadStarting: {
+ root.downloadState = "downloading"
+ }
+
+ onFinishedChanged: {
+ root.progressText = qsTr("Extracting...")
+ root.allowCancel = false
+ root.progressValue = Qt.binding(function() { return extractor.progress })
+
+ extractor.extract()
+ }
+
+ onDownloadCanceled: {
+ root.progressText = ""
+ root.progressValue = 0
+
+ root.downloadState = ""
+
+ ContentLibraryBackend.rootView.markNoTextureDownloading()
+ }
+
+ onDownloadFailed: {
+ root.downloadState = "failed"
+
+ ContentLibraryBackend.rootView.markNoTextureDownloading()
}
}
- ToolTip {
- visible: mouseArea.containsMouse
- // contentWidth is not calculated correctly by the toolTip (resulting in a wider tooltip than
- // needed). Using a helper Text to calculate the correct width
- contentWidth: helperText.width
- bottomInset: -2
- text: modelData.textureToolTip
- delay: 1000
-
- Text {
- id: helperText
- text: modelData.textureToolTip
- visible: false
+ FileExtractor {
+ id: extractor
+ archiveName: downloader.completeBaseName
+ sourceFile: downloader.outputFile
+ targetPath: modelData.textureParentPath
+ alwaysCreateDir: false
+ clearTargetPathContents: false
+ onFinishedChanged: {
+ modelData.setDownloaded()
+ root.downloadState = modelData.isDownloaded() ? "downloaded" : "failed"
+
+ ContentLibraryBackend.rootView.markNoTextureDownloading()
}
}
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml
index 5e2c1d3ff3..f804f16d89 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml
@@ -5,6 +5,7 @@ import QtQuick 2.15
import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
+import ContentLibraryBackend
StudioControls.Menu {
id: root
@@ -12,12 +13,12 @@ StudioControls.Menu {
property var targetTexture: null
property bool hasSceneEnv: false
- property bool canUse3D: targetTexture && rootView.hasQuick3DImport && rootView.hasMaterialLibrary
+ property bool canUse3D: targetTexture && ContentLibraryBackend.rootView.hasQuick3DImport && ContentLibraryBackend.rootView.hasMaterialLibrary
function popupMenu(targetTexture = null)
{
this.targetTexture = targetTexture
- rootView.updateSceneEnvState();
+ ContentLibraryBackend.rootView.updateSceneEnvState();
popup()
}
@@ -26,18 +27,18 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("Add image")
enabled: root.targetTexture
- onTriggered: rootView.addImage(root.targetTexture)
+ onTriggered: ContentLibraryBackend.rootView.addImage(root.targetTexture)
}
StudioControls.MenuItem {
text: qsTr("Add texture")
enabled: canUse3D
- onTriggered: rootView.addTexture(root.targetTexture)
+ onTriggered: ContentLibraryBackend.rootView.addTexture(root.targetTexture)
}
StudioControls.MenuItem {
text: qsTr("Add light probe")
enabled: root.hasSceneEnv && canUse3D
- onTriggered: rootView.addLightProbe(root.targetTexture)
+ onTriggered: ContentLibraryBackend.rootView.addLightProbe(root.targetTexture)
}
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
index ac77570cb8..1c24f9bc43 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
@@ -5,12 +5,13 @@ import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import ContentLibraryBackend
HelperWidgets.ScrollView {
id: root
clip: true
- interactive: !ctxMenu.opened
+ interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
readonly property int cellWidth: 100
readonly property int cellHeight: 100
@@ -20,6 +21,7 @@ HelperWidgets.ScrollView {
required property var searchBox
required property var model
+ required property string sectionCategory
signal unimport(var bundleMat);
@@ -56,6 +58,8 @@ HelperWidgets.ScrollView {
visible: bundleCategoryVisible && !root.model.isEmpty
expanded: bundleCategoryExpanded
expandOnClick: false
+ category: root.sectionCategory
+
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
onExpand: bundleCategoryExpanded = true
onCollapse: bundleCategoryExpanded = false
@@ -90,7 +94,7 @@ HelperWidgets.ScrollView {
id: infoText
text: {
if (!root.model.texBundleExists)
- qsTr("<b>Content Library</b> textures are not installed.")
+ qsTr("No textures available. Make sure you have internet connection.")
else if (!searchBox.isEmpty())
qsTr("No match found.")
else
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/DownloadPane.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/DownloadPane.qml
new file mode 100644
index 0000000000..d7e040efa8
--- /dev/null
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/DownloadPane.qml
@@ -0,0 +1,81 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+import StudioTheme 1.0 as StudioTheme
+
+Rectangle {
+ id: root
+
+ color: StudioTheme.Values.themeThumbnailBackground
+ border.color: "#00000000"
+
+ signal requestCancel
+
+ property alias allowCancel: progressBar.closeButtonVisible
+ property alias progressValue: progressBar.value
+ property alias progressLabel: progressLabel.text
+
+ function beginDownload(progressFunction)
+ {
+ progressBar.visible = true
+ root.progressLabel = qsTr("Downloading...")
+ root.allowCancel = true
+ root.progressValue = progressFunction
+ }
+
+ function endDownload()
+ {
+ root.allowCancel = false
+ root.progressLabel = ""
+ root.progressValue = 0
+ }
+
+ TextureProgressBar {
+ id: progressBar
+ anchors.rightMargin: 10
+ anchors.leftMargin: 10
+
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ visible: false
+
+ onCancelRequested: {
+ root.requestCancel()
+ }
+
+ Text {
+ id: progressLabel
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("Progress:")
+ anchors.bottom: parent.top
+ anchors.bottomMargin: 5
+ anchors.left: parent.left
+ font.pixelSize: 12
+ }
+
+ Row {
+ anchors.top: parent.bottom
+ anchors.topMargin: 5
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Text {
+ id: progressAmount
+ color: StudioTheme.Values.themeTextColor
+ text: progressBar.value.toFixed(1)
+
+ font.pixelSize: 12
+ }
+
+ Text {
+ id: percentSign
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("%")
+ font.pixelSize: 12
+ }
+ }
+ } // TextureProgressBar
+} // Rectangle
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/TextureProgressBar.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/TextureProgressBar.qml
new file mode 100644
index 0000000000..fcd7437961
--- /dev/null
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/TextureProgressBar.qml
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+
+import StudioTheme as StudioTheme
+
+Item {
+ id: root
+ width: 272
+ height: 25
+ property int value: 0
+ property bool closeButtonVisible
+
+ readonly property int margin: 4
+
+ readonly property string qdsBrand: "#57B9FC"
+
+ signal cancelRequested
+
+ Rectangle {
+ id: progressBarGroove
+ color: StudioTheme.Values.themeThumbnailLabelBackground
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ id: progressBarTrack
+ width: root.value * ((root.width - closeButton.width) - 2 * root.margin) / 100
+ color: root.qdsBrand
+ border.color: "#002e769e"
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: root.margin
+ }
+
+ Text {
+ id: closeButton
+ visible: root.closeButtonVisible
+ width: 20
+ text: StudioTheme.Constants.closeCross
+ color: root.qdsBrand
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: StudioTheme.Values.myIconFontSize
+
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: root.margin
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ root.cancelRequested()
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml
index b742f98577..a8c3758eb5 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/UnimportBundleMaterialDialog.qml
@@ -8,6 +8,7 @@ import QtQuickDesignerTheme
import HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import ContentLibraryBackend
Dialog {
id: root
@@ -47,7 +48,7 @@ Dialog {
text: qsTr("Remove")
onClicked: {
- materialsModel.removeFromProject(root.targetBundleMaterial)
+ ContentLibraryBackend.materialsModel.removeFromProject(root.targetBundleMaterial)
root.accept()
}
}
diff --git a/share/qtcreator/qmldesigner/designericons.json b/share/qtcreator/qmldesigner/designericons.json
index e4201291c6..f695e63b56 100644
--- a/share/qtcreator/qmldesigner/designericons.json
+++ b/share/qtcreator/qmldesigner/designericons.json
@@ -2,59 +2,145 @@
"ContextMenuArea": {
"size": "28x28",
"Off": {
- "Disabled": { "color": "DSiconColorDisabled" },
- "Hovered": { "color": "DSnavigatorIconHover" },
- "Normal": { "color": "DSnavigatorIcon" },
- "Selected": { "color": "DSnavigatorIconSelected" }
+ "Disabled": { "color": "DStextColorDisabled" },
+ "Hovered": { "color": "DSpanelBackground" },
+ "Normal": { "color": "DStextColor" },
+ "Selected": { "color": "DStextSelectedTextColor" }
},
"On": {
- "Disabled": { "color": "DSiconColorDisabled" },
- "Hovered": { "color": "DSnavigatorIconHover" },
- "Normal": { "color": "DSnavigatorIcon" },
- "Selected": { "color": "DSnavigatorIconSelected" }
+ "Disabled": { "color": "DStextColorDisabled" },
+ "Hovered": { "color": "DSsubPanelBackground" },
+ "Normal": { "color": "DStextColor" },
+ "Selected": { "color": "DStextSelectedTextColor" }
}
},
"AddMouseAreaIcon": {
- "iconName": "s_mouseArea"
+ "iconName": "mouseArea_small"
+ },
+ "AlignCameraToViewIcon": {
+ "iconName": "alignToCamera_small"
+ },
+ "AlignViewToCameraIcon": {
+ "iconName": "alignToObject_small"
},
"AnchorsIcon": {
- "iconName": "s_anchors"
+ "iconName": "anchors_small"
},
"AnnotationIcon": {
- "iconName": "s_annotations"
+ "iconName": "annotations_small"
},
"ArrangeIcon": {
- "iconName": "s_arrange"
+ "iconName": "arrange_small"
+ },
+ "CameraIcon": {
+ "iconName": "camera_small"
+ },
+ "CameraOrthographicIcon": {
+ "iconName": "orthCam_small"
+ },
+ "CameraPerspectiveIcon": {
+ "iconName": "perspectiveCam_small"
},
"ConnectionsIcon": {
- "iconName": "s_connections"
+ "iconName": "connection_small"
+ },
+ "CopyIcon": {
+ "iconName": "copy_small"
+ },
+ "CreateIcon": {
+ "iconName": "create_small"
+ },
+ "DeleteIcon": {
+ "iconName": "delete_small"
+ },
+ "DuplicateIcon": {
+ "iconName": "duplicate_small"
+ },
+ "EditComponentIcon": {
+ "iconName": "editComponent_small"
},
"EditIcon": {
- "iconName": "s_edit"
+ "iconName": "edit_small"
},
"EnterComponentIcon": {
- "iconName": "s_enterComponent"
+ "iconName": "editComponent_small"
},
"EventListIcon": {
- "iconName": "s_eventList"
+ "iconName": "events_small"
+ },
+ "FitSelectedIcon": {
+ "iconName": "fitSelected_small"
},
"GroupSelectionIcon": {
- "iconName": "s_group"
+ "iconName": "group_small"
+ },
+ "ImportedModelsIcon": {
+ "iconName": "importedModels_small"
},
"LayoutsIcon": {
- "iconName": "s_layouts"
+ "iconName": "layouts_small"
+ },
+ "LightIcon": {
+ "Off": {
+ "iconName": "editLightOff_medium"
+ },
+ "On": {
+ "iconName": "editLightOn_medium"
+ }
+ },
+ "LightDirectionalIcon": {
+ "iconName": "directionalLight_small"
+ },
+ "LightPointIcon": {
+ "iconName": "pointLight_small"
+ },
+ "LightSpotIcon": {
+ "iconName": "spotLight_small"
},
"MakeComponentIcon": {
- "iconName": "s_component"
+ "iconName": "createComponent_small"
+ },
+ "MaterialIcon": {
+ "iconName": "material_medium"
},
"MergeWithTemplateIcon": {
- "iconName": "s_merging"
+ "iconName": "merge_small"
+ },
+ "MinimalDownArrowIcon" : {
+ "iconName": "upDownSquare2"
+ },
+ "ModelConeIcon": {
+ "iconName": "cone_small"
+ },
+ "ModelCubeIcon": {
+ "iconName": "cube_small"
+ },
+ "ModelCylinderIcon": {
+ "iconName": "cylinder_small"
+ },
+ "ModelPlaneIcon": {
+ "iconName": "plane_small"
+ },
+ "ModelSphereIcon": {
+ "iconName": "sphere_small"
+ },
+ "ParentIcon": {
+ "iconName": "selectParent_small"
+ },
+ "PasteIcon": {
+ "iconName": "paste_small"
},
"PositionsersIcon": {
- "iconName": "s_positioners"
+ "iconName": "positioners_small"
+ },
+ "PrimitivesIcon": {
+ "iconName": "cube_small"
+ },
+ "ResetViewIcon": {
+ "iconName": "reload_medium"
},
"SelecionIcon": {
- "iconName": "s_selection"
+ "iconName": "selection_small"
},
"ShowBoundsIcon": {
"Off": {
@@ -65,10 +151,26 @@
}
},
"SnappingIcon": {
- "iconName": "s_snapping"
+ "iconName": "snapping_small"
+ },
+ "SimpleCheckIcon": {
+ "Off": {
+ "iconName": "transparent"
+ },
+ "On": {
+ "iconName": "tickMark_small"
+ }
},
"TimelineIcon": {
- "iconName": "s_timeline"
+ "iconName": "timeline_small"
+ },
+ "ToggleGroupIcon": {
+ "Off": {
+ "iconName": "selectOutline_medium"
+ },
+ "On": {
+ "iconName": "selectFill_medium"
+ }
},
"VisibilityIcon": {
"Off": {
diff --git a/share/qtcreator/qmldesigner/feedback/FeedbackPopup.qml b/share/qtcreator/qmldesigner/feedback/FeedbackPopup.qml
new file mode 100644
index 0000000000..8497626798
--- /dev/null
+++ b/share/qtcreator/qmldesigner/feedback/FeedbackPopup.qml
@@ -0,0 +1,143 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Window 2.15
+
+Rectangle {
+ id: root_rectangle
+
+ property int rating: 0
+
+ signal submitFeedback(string feedback, int rating)
+ signal closeClicked()
+
+ width: 740
+ height: 382
+ border { color: "#0094ce"; width: 1 }
+
+ Text {
+ id: h1
+ objectName: "title"
+ color: "#333333"
+ text: "Enjoying Qt Design Studio?"
+ font { family: "Titillium"; pixelSize: 21 }
+ anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 50 }
+ }
+
+ Text {
+ id: h2
+ color: "#333333"
+ text: "Select the level of your satisfaction."
+ font { family: "Titillium"; pixelSize: 21 }
+ anchors { horizontalCenter: parent.horizontalCenter; top: h1.bottom; topMargin: 12 }
+ }
+
+ Row {
+ id: starRow
+ width: 246; height: 42; spacing: 6.5
+ anchors { horizontalCenter: parent.horizontalCenter; top: h2.bottom; topMargin: 32 }
+
+ Repeater { // create the stars
+ id: rep
+ model: 5
+ Image {
+ source: "star_empty.png"
+ fillMode: Image.PreserveAspectFit
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ for (var i = 0; i < 5; ++i) {
+ rep.itemAt(i).source = i <= index ? "star_filled.png"
+ : "star_empty.png"
+ }
+ rating = index + 1
+ }
+ }
+ }
+ }
+ }
+
+ ScrollView {
+ id: scroll_textarea
+ width: 436
+ height: 96
+ anchors { horizontalCenter: parent.horizontalCenter; top: starRow.bottom; topMargin: 28 }
+
+ TextEdit {
+ id: textarea
+ width: 426
+ height: 90
+ color: "#333333";
+ font { pixelSize: 14; family: "Titillium" }
+ wrapMode: Text.Wrap
+ property string placeholderText: "We highly appreciate additional feedback.\nBouquets, brickbats, or suggestions, all feedback is welcome!"
+
+ Text {
+ text: textarea.placeholderText
+ color: "gray"
+ visible: !textarea.text
+ font: parent.font
+ }
+ }
+
+ background: Rectangle {
+ border { color: "#e6e6e6"; width: 1 }
+ }
+ }
+
+ Row {
+ id: buttonRow
+ anchors { horizontalCenter: parent.horizontalCenter; top: scroll_textarea.bottom; topMargin: 28 }
+ spacing: 10
+
+ Button {
+ id: buttonSkip
+ width: 80
+ height: 28
+
+ contentItem: Text {
+ text: "Skip"
+ color: parent.hovered ? Qt.darker("#999999", 1.9) : Qt.darker("#999999", 1.2)
+ font { family: "Titillium"; pixelSize: 14 }
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: "#ffffff"
+ border { color: "#999999"; width: 1 }
+ }
+
+ onClicked: root_rectangle.closeClicked()
+ }
+
+ Button {
+ id: buttonSubmit
+
+ width: 80
+ height: 28
+ enabled: rating > 0
+
+ contentItem: Text {
+ text: "Submit";
+ color: enabled ? "white" : Qt.lighter("#999999", 1.3)
+ font { family: "Titillium"; pixelSize: 14 }
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ color: enabled ? parent.hovered ? Qt.lighter("#0094ce", 1.2) : "#0094ce" : "white"
+ border { color: enabled ? "#999999" : Qt.lighter("#999999", 1.3); width: 1 }
+ }
+
+ onClicked: {
+ root_rectangle.submitFeedback(textarea.text, rating);
+ root_rectangle.closeClicked();
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/feedback/star_empty.png b/share/qtcreator/qmldesigner/feedback/star_empty.png
new file mode 100644
index 0000000000..f9ab459a02
--- /dev/null
+++ b/share/qtcreator/qmldesigner/feedback/star_empty.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/feedback/star_empty@2x.png b/share/qtcreator/qmldesigner/feedback/star_empty@2x.png
new file mode 100644
index 0000000000..d5b772517f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/feedback/star_empty@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/feedback/star_filled.png b/share/qtcreator/qmldesigner/feedback/star_filled.png
new file mode 100644
index 0000000000..f213d09c84
--- /dev/null
+++ b/share/qtcreator/qmldesigner/feedback/star_filled.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/feedback/star_filled@2x.png b/share/qtcreator/qmldesigner/feedback/star_filled@2x.png
new file mode 100644
index 0000000000..19e8491868
--- /dev/null
+++ b/share/qtcreator/qmldesigner/feedback/star_filled@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml
index c77f995634..585c6a6d14 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
import StudioTheme 1.0 as StudioTheme
+import ItemLibraryBackend
Column {
id: root
@@ -43,7 +44,7 @@ Column {
spacing: 2
Repeater {
- model: addModuleModel
+ model: ItemLibraryBackend.addModuleModel
delegate: Rectangle {
id: itemBackground
@@ -67,7 +68,7 @@ Column {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
- onClicked: rootView.handleAddImport(index)
+ onClicked: ItemLibraryBackend.rootView.handleAddImport(index)
enabled: !isSeparator
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
index 524aca6841..1178de4a87 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
import StudioTheme 1.0 as StudioTheme
+import ItemLibraryBackend
Item {
id: delegateRoot
@@ -34,8 +35,8 @@ Item {
anchors.topMargin: styleConstants.cellVerticalMargin
anchors.horizontalCenter: parent.horizontalCenter
- width: itemLibraryIconWidth // to be set in Qml context
- height: itemLibraryIconHeight // to be set in Qml context
+ width: ItemLibraryBackend.itemLibraryIconWidth // to be set in Qml context
+ height: ItemLibraryBackend.itemLibraryIconHeight // to be set in Qml context
source: itemLibraryIconPath // to be set by model
// Icons generated for components can change if the component is edited,
@@ -75,12 +76,12 @@ Item {
allowTooltip = false
hide()
if (mouse.button === Qt.LeftButton)
- rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y))
+ ItemLibraryBackend.rootView.startDragAndDrop(itemLibraryEntry, mapToGlobal(mouse.x, mouse.y))
}
onDoubleClicked: (mouse)=> {
if (mouse.button === Qt.LeftButton && itemComponentSource) {
hide()
- rootView.goIntoComponent(itemComponentSource)
+ ItemLibraryBackend.rootView.goIntoComponent(itemComponentSource)
}
}
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
index 9d8e677b5b..05d8d6db9c 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml
@@ -1,24 +1,20 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Layouts
import QtQuickDesignerTheme 1.0
-import HelperWidgets 2.0
+import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
-
+import ItemLibraryBackend
/* The view displaying the item grid.
-
The following Qml context properties have to be set:
- ItemLibraryModel itemLibraryModel
- int itemLibraryIconWidth
- int itemLibraryIconHeight
- ItemLibraryWidget rootView
- QColor highlightColor
-
itemLibraryModel structure:
-
itemLibraryModel [
ItemLibraryImport {
string importName
@@ -26,13 +22,11 @@ itemLibraryModel [
bool importVisible
bool importUsed
bool importExpanded
-
list categoryModel [
ItemLibraryCategory {
string categoryName
bool categoryVisible
bool categoryExpanded
-
list itemModel [
ItemLibraryItem {
string itemName
@@ -50,10 +44,8 @@ itemLibraryModel [
... more imports
]
*/
-
Item {
id: itemsView
-
property string importToRemove
property string importToAdd
property string componentSource
@@ -62,192 +54,182 @@ Item {
property bool isHorizontalView: false
property bool isAddModuleView: false
+ property var tooltipBackend: ItemLibraryBackend.tooltipBackend
+
// Called also from C++ to close context menu on focus out
function closeContextMenu()
{
moduleContextMenu.close()
itemContextMenu.close()
}
-
// Called from C++
function clearSearchFilter()
{
searchBox.clear();
}
-
// Called also from C++
function switchToComponentsView()
{
- isAddModuleView = false
+ ItemLibraryBackend.isAddModuleView = false
}
-
onWidthChanged: {
- itemsView.isHorizontalView = itemsView.width > widthLimit
+ itemsView.isHorizontalView = itemsView.width > ItemLibraryBackend.widthLimit
}
-
onIsHorizontalViewChanged: closeContextMenu()
-
Item {
id: styleConstants
property int textWidth: 58
property int textHeight: Theme.smallFontPixelSize() * 2
-
property int cellHorizontalMargin: 1
property int cellVerticalSpacing: 2
property int cellVerticalMargin: 4
-
// the following depend on the actual shape of the item delegate
property int cellWidth: styleConstants.textWidth + 2 * styleConstants.cellHorizontalMargin
- property int cellHeight: itemLibraryIconHeight + styleConstants.textHeight +
+ property int cellHeight: ItemLibraryBackend.itemLibraryIconHeight + styleConstants.textHeight +
2 * styleConstants.cellVerticalMargin + styleConstants.cellVerticalSpacing
-
StudioControls.Menu {
id: moduleContextMenu
-
StudioControls.MenuItem {
text: qsTr("Remove Module")
visible: itemsView.currentCategory === null
height: visible ? implicitHeight : 0
- enabled: itemsView.importToRemove && !rootView.subCompEditMode
- onTriggered: rootView.removeImport(itemsView.importToRemove)
+ enabled: itemsView.importToRemove && !ItemLibraryBackend.rootView.subCompEditMode
+ onTriggered: ItemLibraryBackend.rootView.removeImport(itemsView.importToRemove)
}
-
StudioControls.MenuSeparator {
- visible: itemsView.currentCategory === null && !rootView.searchActive
+ visible: itemsView.currentCategory === null && !ItemLibraryBackend.rootView.searchActive
height: visible ? StudioTheme.Values.border : 0
}
-
StudioControls.MenuItem {
text: qsTr("Expand All")
- visible: itemsView.currentCategory === null && !rootView.searchActive
+ visible: itemsView.currentCategory === null && !ItemLibraryBackend.rootView.searchActive
height: visible ? implicitHeight : 0
- onTriggered: itemLibraryModel.expandAll()
+ onTriggered: ItemLibraryBackend.itemLibraryModel.expandAll()
}
-
StudioControls.MenuItem {
text: qsTr("Collapse All")
- visible: itemsView.currentCategory === null && !rootView.searchActive
+ visible: itemsView.currentCategory === null && !ItemLibraryBackend.rootView.searchActive
height: visible ? implicitHeight : 0
- onTriggered: itemLibraryModel.collapseAll()
+ onTriggered: ItemLibraryBackend.itemLibraryModel.collapseAll()
}
-
StudioControls.MenuSeparator {
- visible: itemsView.currentCategory === null && !rootView.searchActive
+ visible: itemsView.currentCategory === null && !ItemLibraryBackend.rootView.searchActive
height: visible ? StudioTheme.Values.border : 0
}
-
StudioControls.MenuItem {
text: qsTr("Hide Category")
visible: itemsView.currentCategory
height: visible ? implicitHeight : 0
- onTriggered: itemLibraryModel.hideCategory(itemsView.currentImport.importUrl,
+ onTriggered: ItemLibraryBackend.itemLibraryModel.hideCategory(itemsView.currentImport.importUrl,
itemsView.currentCategory.categoryName)
}
-
StudioControls.MenuSeparator {
visible: itemsView.currentCategory
height: visible ? StudioTheme.Values.border : 0
}
-
StudioControls.MenuItem {
text: qsTr("Show Module Hidden Categories")
- visible: !rootView.searchActive
+ visible: !ItemLibraryBackend.rootView.searchActive
enabled: itemsView.currentImport && !itemsView.currentImport.allCategoriesVisible
height: visible ? implicitHeight : 0
- onTriggered: itemLibraryModel.showImportHiddenCategories(itemsView.currentImport.importUrl)
+ onTriggered: ItemLibraryBackend.itemLibraryModel.showImportHiddenCategories(itemsView.currentImport.importUrl)
}
-
StudioControls.MenuItem {
text: qsTr("Show All Hidden Categories")
- visible: !rootView.searchActive
- enabled: itemLibraryModel.isAnyCategoryHidden
+ visible: !ItemLibraryBackend.rootView.searchActive
+ enabled: ItemLibraryBackend.itemLibraryModel.isAnyCategoryHidden
height: visible ? implicitHeight : 0
- onTriggered: itemLibraryModel.showAllHiddenCategories()
+ onTriggered: ItemLibraryBackend.itemLibraryModel.showAllHiddenCategories()
}
}
-
StudioControls.Menu {
id: itemContextMenu
// Workaround for menu item implicit width not properly propagating to menu
width: Math.max(importMenuItem.implicitWidth, openSourceItem.implicitWidth)
-
StudioControls.MenuItem {
id: importMenuItem
text: qsTr("Add Module: ") + itemsView.importToAdd
visible: itemsView.importToAdd
height: visible ? implicitHeight : 0
- onTriggered: rootView.addImportForItem(itemsView.importToAdd)
+ onTriggered: ItemLibraryBackend.rootView.addImportForItem(itemsView.importToAdd)
}
-
StudioControls.MenuItem {
id: openSourceItem
- text: qsTr("Go into Component")
+ text: qsTr("Edit Component")
visible: itemsView.componentSource
height: visible ? implicitHeight : 0
- onTriggered: rootView.goIntoComponent(itemsView.componentSource)
+ onTriggered: ItemLibraryBackend.rootView.goIntoComponent(itemsView.componentSource)
}
}
}
-
Column {
id: col
width: parent.width
height: parent.height
- y: 5
spacing: 5
- Row {
+ Rectangle {
width: parent.width
+ height: StudioTheme.Values.doubleToolbarHeight
+ color: StudioTheme.Values.themeToolbarBackground
- StudioControls.SearchBox {
- id: searchBox
-
- width: parent.width - addModuleButton.width - 5
-
- onSearchChanged: (searchText) => rootView.handleSearchFilterChanged(searchText)
- }
+ Column {
+ anchors.fill: parent
+ anchors.topMargin: 6
+ anchors.bottomMargin: 6
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+ spacing: 12
+
+ StudioControls.SearchBox {
+ id: searchBox
+ width: parent.width
+ style: StudioTheme.Values.searchControlStyle
- IconButton {
- id: addModuleButton
- anchors.verticalCenter: parent.verticalCenter
- tooltip: qsTr("Add a module.")
- icon: StudioTheme.Constants.plus
- buttonSize: parent.height
+ onSearchChanged: (searchText) => ItemLibraryBackend.rootView.handleSearchFilterChanged(searchText)
+ }
- onClicked: isAddModuleView = true
+ Row {
+ width: parent.width
+ height: StudioTheme.Values.toolbarHeight
+ spacing: 6
+
+ HelperWidgets.AbstractButton {
+ id: addModuleButton
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.add_medium
+ tooltip: qsTr("Add a module.")
+ onClicked: isAddModuleView = true
+ }
+ }
}
}
Loader {
id: loader
-
width: col.width
height: col.height - y - 5
sourceComponent: isAddModuleView ? addModuleView
: itemsView.isHorizontalView ? horizontalView : verticalView
}
}
-
Component {
id: verticalView
-
- ScrollView {
+ HelperWidgets.ScrollView {
id: verticalScrollView
anchors.fill: parent
clip: true
- interactive: !itemContextMenu.opened && !moduleContextMenu.opened
-
+ interactive: !itemContextMenu.opened && !moduleContextMenu.opened && !ItemLibraryBackend.rootView.isDragging
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0)
if (contentY > maxPosition)
contentY = maxPosition
}
-
Column {
spacing: 2
Repeater {
- model: itemLibraryModel // to be set in Qml context
- delegate: Section {
+ model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
+ delegate: HelperWidgets.Section {
width: itemsView.width -
(verticalScrollView.verticalScrollBarVisible
? verticalScrollView.verticalThickness : 0)
@@ -263,6 +245,8 @@ Item {
expanded: importExpanded
expandOnClick: false
useDefaulContextMenu: false
+ category: "ItemsView"
+
onToggleExpand: {
if (categoryModel.rowCount() > 0)
importExpanded = !importExpanded
@@ -273,13 +257,12 @@ Item {
itemsView.currentCategory = null
moduleContextMenu.popup()
}
-
Column {
spacing: 2
property var currentImportModel: model // allows accessing the import model from inside the category section
Repeater {
model: categoryModel
- delegate: Section {
+ delegate: HelperWidgets.Section {
width: itemsView.width -
(verticalScrollView.verticalScrollBarVisible
? verticalScrollView.verticalThickness : 0)
@@ -296,24 +279,22 @@ Item {
expandOnClick: false
onToggleExpand: categoryExpanded = !categoryExpanded
useDefaulContextMenu: false
+ category: "ItemsView"
+
onShowContextMenu: {
- if (!rootView.searchActive) {
+ if (!ItemLibraryBackend.rootView.searchActive) {
itemsView.currentCategory = model
itemsView.currentImport = parent.currentImportModel
moduleContextMenu.popup()
}
}
-
Grid {
id: itemGrid
-
property real actualWidth: parent.width - itemGrid.leftPadding - itemGrid.rightPadding
-
leftPadding: 6
rightPadding: 6
columns: itemGrid.actualWidth / styleConstants.cellWidth
rowSpacing: 7
-
Repeater {
model: itemModel
delegate: ItemDelegate {
@@ -340,32 +321,28 @@ Item {
}
}
}
-
Component {
id: horizontalView
-
Row {
leftPadding: 5
-
- ScrollView {
+ HelperWidgets.ScrollView {
id: horizontalScrollView
width: 270
height: parent.height
clip: true
- interactive: !itemContextMenu.opened && !moduleContextMenu.opened
+ interactive: !itemContextMenu.opened && !moduleContextMenu.opened && !ItemLibraryBackend.rootView.isDragging
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - horizontalScrollView.height, 0)
if (contentY > maxPosition)
contentY = maxPosition
}
-
Column {
width: parent.width
spacing: 2
Repeater {
- model: itemLibraryModel // to be set in Qml context
- delegate: Section {
+ model: ItemLibraryBackend.itemLibraryModel // to be set in Qml context
+ delegate: HelperWidgets.Section {
width: 265 -
(horizontalScrollView.verticalScrollBarVisible
? horizontalScrollView.verticalThickness : 0)
@@ -381,6 +358,8 @@ Item {
expanded: importExpanded
expandOnClick: false
useDefaulContextMenu: false
+ category: "ItemsView"
+
onToggleExpand: {
if (categoryModel.rowCount() > 0)
importExpanded = !importExpanded
@@ -391,7 +370,6 @@ Item {
itemsView.currentCategory = null
moduleContextMenu.popup()
}
-
Column {
spacing: 2
property var currentImportModel: model // allows accessing the import model from inside the category section
@@ -409,7 +387,6 @@ Item {
? StudioTheme.Values.themeControlBackgroundHover
: categoryMouseArea.containsMouse ? Qt.darker(StudioTheme.Values.themeControlBackgroundHover, 1.5)
: StudioTheme.Values.themeControlBackground
-
Text {
anchors.fill: parent
text: categoryName
@@ -419,19 +396,16 @@ Item {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
-
MouseArea {
id: categoryMouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
-
onClicked: (mouse) => {
- itemLibraryModel.selectImportCategory(parent.parent.currentImportModel.importUrl, model.index)
-
+ ItemLibraryBackend.itemLibraryModel.selectImportCategory(parent.parent.currentImportModel.importUrl, model.index)
if (mouse.button === Qt.RightButton
&& categoryModel.rowCount() !== 1
- && !rootView.searchActive) {
+ && !ItemLibraryBackend.rootView.searchActive) {
itemsView.currentCategory = model
itemsView.currentImport = parent.parent.currentImportModel
moduleContextMenu.popup()
@@ -445,39 +419,36 @@ Item {
}
}
}
-
Rectangle { // separator between import/category column and item grid
id: separatingLine
height: itemsView.height - 10
width: 1
color: StudioTheme.Values.themeControlOutline
}
-
- ScrollView {
+ HelperWidgets.ScrollView {
id: itemScrollView
width: itemsView.width - 275
height: itemsView.height
+ interactive: !itemContextMenu.opened && !moduleContextMenu.opened && !ItemLibraryBackend.rootView.isDragging
+
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - itemScrollView.height, 0)
if (contentY > maxPosition)
contentY = maxPosition
}
-
Grid {
id: hItemGrid
property real actualWidth: itemsView.width - 294
-
leftPadding: 9
rightPadding: 9
bottomPadding: 15
columns: hItemGrid.actualWidth / styleConstants.cellWidth
rowSpacing: 7
-
Repeater {
- model: itemLibraryModel.itemsModel
+ model: ItemLibraryBackend.itemLibraryModel.itemsModel
delegate: ItemDelegate {
visible: itemVisible
- textColor: itemLibraryModel.importUnimportedSelected
+ textColor: ItemLibraryBackend.itemLibraryModel.importUnimportedSelected
? StudioTheme.Values.themeUnimportedModuleColor : StudioTheme.Values.themeTextColor
width: styleConstants.cellWidth
height: styleConstants.cellHeight
@@ -494,10 +465,8 @@ Item {
}
}
}
-
Component {
id: addModuleView
-
AddModuleView {
onBack: isAddModuleView = false
}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
index fbcaa06489..620feb3b11 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
@@ -1,14 +1,16 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
import QtQuickDesignerTheme 1.0
-import HelperWidgets 2.0
+import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
+import MaterialBrowserBackend
Item {
id: root
+ focus: true
readonly property int cellWidth: 100
readonly property int cellHeight: 120
@@ -16,12 +18,16 @@ Item {
&& materialBrowserModel.hasQuick3DImport
property var currMaterialItem: null
+ property var rootView: MaterialBrowserBackend.rootView
+ property var materialBrowserModel: MaterialBrowserBackend.materialBrowserModel
+ property var materialBrowserTexturesModel: MaterialBrowserBackend.materialBrowserTexturesModel
// Called also from C++ to close context menu on focus out
function closeContextMenu()
{
ctxMenu.close()
ctxMenuTextures.close()
+ HelperWidgets.Controller.closeContextMenu()
}
// Called from C++ to refresh a preview material after it changes
@@ -38,9 +44,192 @@ Item {
searchBox.clear();
}
+ function nextVisibleItem(idx, count, itemModel)
+ {
+ if (count === 0)
+ return idx
+
+ let pos = 0
+ let newIdx = idx
+ let direction = 1
+ if (count < 0)
+ direction = -1
+
+ while (pos !== count) {
+ newIdx += direction
+ if (newIdx < 0 || newIdx >= itemModel.rowCount())
+ return -1
+ if (itemModel.isVisible(newIdx))
+ pos += direction
+ }
+
+ return newIdx
+ }
+
+ function visibleItemCount(itemModel)
+ {
+ let curIdx = 0
+ let count = 0
+
+ for (; curIdx < itemModel.rowCount(); ++curIdx) {
+ if (itemModel.isVisible(curIdx))
+ ++count
+ }
+
+ return count
+ }
+
+ function rowIndexOfItem(idx, rowSize, itemModel)
+ {
+ if (rowSize === 1)
+ return 1
+
+ let curIdx = 0
+ let count = -1
+
+ while (curIdx <= idx) {
+ if (curIdx >= itemModel.rowCount())
+ break
+ if (itemModel.isVisible(curIdx))
+ ++count
+ ++curIdx
+ }
+
+ return count % rowSize
+ }
+
+ function selectNextVisibleItem(delta)
+ {
+ if (searchBox.activeFocus)
+ return
+
+ let targetIdx = -1
+ let newTargetIdx = -1
+ let origRowIdx = -1
+ let rowIdx = -1
+ let matSecFocused = rootView.materialSectionFocused && materialsSection.expanded
+ let texSecFocused = !rootView.materialSectionFocused && texturesSection.expanded
+
+ if (delta < 0) {
+ if (matSecFocused) {
+ targetIdx = nextVisibleItem(materialBrowserModel.selectedIndex,
+ delta, materialBrowserModel)
+ if (targetIdx >= 0)
+ materialBrowserModel.selectMaterial(targetIdx)
+ } else if (texSecFocused) {
+ targetIdx = nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
+ delta, materialBrowserTexturesModel)
+ if (targetIdx >= 0) {
+ materialBrowserTexturesModel.selectTexture(targetIdx)
+ } else if (!materialBrowserModel.isEmpty && materialsSection.expanded) {
+ targetIdx = nextVisibleItem(materialBrowserModel.rowCount(), -1, materialBrowserModel)
+ if (targetIdx >= 0) {
+ if (delta !== -1) {
+ // Try to match column when switching between materials/textures
+ origRowIdx = rowIndexOfItem(materialBrowserTexturesModel.selectedIndex,
+ -delta, materialBrowserTexturesModel)
+ if (visibleItemCount(materialBrowserModel) > origRowIdx) {
+ rowIdx = rowIndexOfItem(targetIdx, -delta, materialBrowserModel)
+ if (rowIdx >= origRowIdx) {
+ newTargetIdx = nextVisibleItem(targetIdx,
+ -(rowIdx - origRowIdx),
+ materialBrowserModel)
+ } else {
+ newTargetIdx = nextVisibleItem(targetIdx,
+ -(-delta - origRowIdx + rowIdx),
+ materialBrowserModel)
+ }
+ } else {
+ newTargetIdx = nextVisibleItem(materialBrowserModel.rowCount(),
+ -1, materialBrowserModel)
+ }
+ if (newTargetIdx >= 0)
+ targetIdx = newTargetIdx
+ }
+ materialBrowserModel.selectMaterial(targetIdx)
+ rootView.focusMaterialSection(true)
+ }
+ }
+ }
+ } else if (delta > 0) {
+ if (matSecFocused) {
+ targetIdx = nextVisibleItem(materialBrowserModel.selectedIndex,
+ delta, materialBrowserModel)
+ if (targetIdx >= 0) {
+ materialBrowserModel.selectMaterial(targetIdx)
+ } else if (!materialBrowserTexturesModel.isEmpty && texturesSection.expanded) {
+ targetIdx = nextVisibleItem(-1, 1, materialBrowserTexturesModel)
+ if (targetIdx >= 0) {
+ if (delta !== 1) {
+ // Try to match column when switching between materials/textures
+ origRowIdx = rowIndexOfItem(materialBrowserModel.selectedIndex,
+ delta, materialBrowserModel)
+ if (visibleItemCount(materialBrowserTexturesModel) > origRowIdx) {
+ if (origRowIdx > 0) {
+ newTargetIdx = nextVisibleItem(targetIdx, origRowIdx,
+ materialBrowserTexturesModel)
+ }
+ } else {
+ newTargetIdx = nextVisibleItem(materialBrowserTexturesModel.rowCount(),
+ -1, materialBrowserTexturesModel)
+ }
+ if (newTargetIdx >= 0)
+ targetIdx = newTargetIdx
+ }
+ materialBrowserTexturesModel.selectTexture(targetIdx)
+ rootView.focusMaterialSection(false)
+ }
+ }
+ } else if (texSecFocused) {
+ targetIdx = nextVisibleItem(materialBrowserTexturesModel.selectedIndex,
+ delta, materialBrowserTexturesModel)
+ if (targetIdx >= 0)
+ materialBrowserTexturesModel.selectTexture(targetIdx)
+ }
+ }
+ }
+
+ Keys.enabled: true
+ Keys.onDownPressed: {
+ selectNextVisibleItem(gridMaterials.columns)
+ }
+
+ Keys.onUpPressed: {
+ selectNextVisibleItem(-gridMaterials.columns)
+ }
+
+ Keys.onLeftPressed: {
+ selectNextVisibleItem(-1)
+ }
+
+ Keys.onRightPressed: {
+ selectNextVisibleItem(1)
+ }
+
+ function handleEnterPress()
+ {
+ if (searchBox.activeFocus)
+ return
+
+ if (!materialBrowserModel.isEmpty && rootView.materialSectionFocused && materialsSection.expanded)
+ materialBrowserModel.openMaterialEditor()
+ else if (!materialBrowserTexturesModel.isEmpty && !rootView.materialSectionFocused && texturesSection.expanded)
+ materialBrowserTexturesModel.openTextureEditor()
+ }
+
+ Keys.onEnterPressed: {
+ handleEnterPress()
+ }
+
+ Keys.onReturnPressed: {
+ handleEnterPress()
+ }
+
MouseArea {
id: focusGrabber
- anchors.fill: parent
+ y: searchBox.height
+ width: parent.width
+ height: parent.height - searchBox.height
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
forceActiveFocus() // Steal focus from name edit
@@ -52,7 +241,9 @@ Item {
MouseArea {
id: rootMouseArea
- anchors.fill: parent
+ y: topContent.height
+ width: parent.width
+ height: parent.height - topContent.height
acceptedButtons: Qt.RightButton
@@ -70,42 +261,322 @@ Item {
}
}
+ function ensureVisible(yPos, itemHeight)
+ {
+ let currentY = contentYBehavior.targetValue && scrollViewAnim.running
+ ? contentYBehavior.targetValue : scrollView.contentY
+
+ if (currentY > yPos) {
+ if (yPos < itemHeight)
+ scrollView.contentY = 0
+ else
+ scrollView.contentY = yPos
+ return true
+ } else {
+ let adjustedY = yPos + itemHeight - scrollView.height + 8
+ if (currentY < adjustedY) {
+ if (scrollView.contentHeight - scrollView.height < adjustedY )
+ scrollView.contentY = scrollView.contentHeight - scrollView.height
+ else
+ scrollView.contentY = adjustedY
+ return true
+ }
+ }
+
+ return false
+ }
+
+ function ensureSelectedVisible()
+ {
+ if (rootView.materialSectionFocused && materialsSection.expanded && root.currMaterialItem
+ && materialBrowserModel.isVisible(materialBrowserModel.selectedIndex)) {
+ return ensureVisible(root.currMaterialItem.mapToItem(scrollView.contentItem, 0, 0).y,
+ root.currMaterialItem.height)
+ } else if (!rootView.materialSectionFocused && texturesSection.expanded) {
+ let currItem = texturesRepeater.itemAt(materialBrowserTexturesModel.selectedIndex)
+ if (currItem && materialBrowserTexturesModel.isVisible(materialBrowserTexturesModel.selectedIndex))
+ return ensureVisible(currItem.mapToItem(scrollView.contentItem, 0, 0).y, currItem.height)
+ } else {
+ return ensureVisible(0, 90)
+ }
+ }
+
+ Timer {
+ id: ensureTimer
+ interval: 20
+ repeat: true
+ triggeredOnStart: true
+
+ onTriggered: {
+ // Redo until ensuring didn't change things
+ if (!root.ensureSelectedVisible()) {
+ stop()
+ interval = 20
+ triggeredOnStart = true
+ }
+ }
+ }
+
+ function startDelayedEnsureTimer(delay)
+ {
+ // Ensuring visibility immediately in some cases like before new search results are rendered
+ // causes mapToItem return incorrect values, leading to undesirable flicker,
+ // so delay ensuring visibility a bit.
+ ensureTimer.interval = delay
+ ensureTimer.triggeredOnStart = false
+ ensureTimer.restart()
+ }
+
Connections {
target: materialBrowserModel
- function onSelectedIndexChanged() {
+ function onSelectedIndexChanged()
+ {
// commit rename upon changing selection
if (root.currMaterialItem)
root.currMaterialItem.commitRename();
root.currMaterialItem = materialRepeater.itemAt(materialBrowserModel.selectedIndex);
+
+ ensureTimer.start()
+ }
+
+ function onIsEmptyChanged()
+ {
+ ensureTimer.start()
+ }
+ }
+
+ Connections {
+ target: materialBrowserTexturesModel
+
+ function onSelectedIndexChanged()
+ {
+ ensureTimer.start()
+ }
+
+ function onIsEmptyChanged()
+ {
+ ensureTimer.start()
+ }
+ }
+
+ Connections {
+ target: rootView
+
+ function onMaterialSectionFocusedChanged()
+ {
+ ensureTimer.start()
}
}
MaterialBrowserContextMenu {
id: ctxMenu
+ onClosed: {
+ if (restoreFocusOnClose)
+ scrollView.forceActiveFocus()
+ }
}
TextureBrowserContextMenu {
id: ctxMenuTextures
+ onClosed: {
+ scrollView.forceActiveFocus()
+ }
+ }
+
+ component DoubleButton: Rectangle {
+ id: doubleButton
+
+ signal clicked()
+
+ property alias icon: iconLabel.text
+ property alias tooltip: mouseArea.tooltip
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle
+
+ width: doubleButton.style.squareControlSize.width * 2
+ height: doubleButton.style.squareControlSize.height
+ radius: StudioTheme.Values.smallRadius
+
+ Row {
+ id: contentRow
+ spacing: 0
+
+ Text {
+ id: iconLabel
+ width: doubleButton.style.squareControlSize.width
+ height: doubleButton.height
+ text: StudioTheme.Constants.material_medium
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: doubleButton.style.baseIconFontSize
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Text {
+ id: plusLabel
+ width: doubleButton.style.squareControlSize.width
+ height: doubleButton.height
+ text: StudioTheme.Constants.add_medium
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: doubleButton.style.baseIconFontSize
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ HelperWidgets.ToolTipArea {
+ id: mouseArea
+ anchors.fill: parent
+ onClicked: doubleButton.clicked()
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: doubleButton.enabled && !mouseArea.containsMouse && !mouseArea.pressed
+ PropertyChanges {
+ target: doubleButton
+ color: doubleButton.style.background.idle
+ border.color: doubleButton.style.border.idle
+ }
+ PropertyChanges {
+ target: iconLabel
+ color: doubleButton.style.icon.idle
+ }
+ PropertyChanges {
+ target: plusLabel
+ color: doubleButton.style.icon.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: doubleButton.enabled && mouseArea.containsMouse && !mouseArea.pressed
+ PropertyChanges {
+ target: doubleButton
+ color: doubleButton.style.background.hover
+ border.color: doubleButton.style.border.hover
+ }
+ PropertyChanges {
+ target: iconLabel
+ color: doubleButton.style.icon.hover
+ }
+ PropertyChanges {
+ target: plusLabel
+ color: doubleButton.style.icon.hover
+ }
+ },
+ State {
+ name: "pressed"
+ when: doubleButton.enabled && mouseArea.containsMouse && mouseArea.pressed
+ PropertyChanges {
+ target: doubleButton
+ color: doubleButton.style.interaction
+ border.color: doubleButton.style.interaction
+ }
+ PropertyChanges {
+ target: iconLabel
+ color: doubleButton.style.icon.interaction
+ }
+ PropertyChanges {
+ target: plusLabel
+ color: doubleButton.style.icon.interaction
+ }
+ },
+ State {
+ name: "pressedButNotHovered"
+ when: doubleButton.enabled && !mouseArea.containsMouse && mouseArea.pressed
+ extend: "hover"
+ },
+ State {
+ name: "disable"
+ when: !doubleButton.enabled
+ PropertyChanges {
+ target: doubleButton
+ color: doubleButton.style.background.disabled
+ border.color: doubleButton.style.border.disabled
+ }
+ PropertyChanges {
+ target: iconLabel
+ color: doubleButton.style.icon.disabled
+ }
+ PropertyChanges {
+ target: plusLabel
+ color: doubleButton.style.icon.disabled
+ }
+ }
+ ]
}
Column {
id: col
- y: 5
+ anchors.fill: parent
spacing: 5
- Row {
- width: root.width
- enabled: root.enableUiElements
+ Rectangle {
+ id: topContent
+ width: parent.width
+ height: StudioTheme.Values.doubleToolbarHeight
+ color: StudioTheme.Values.themeToolbarBackground
- StudioControls.SearchBox {
- id: searchBox
+ Column {
+ anchors.fill: parent
+ anchors.topMargin: 6
+ anchors.bottomMargin: 6
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+ spacing: 12
+
+ StudioControls.SearchBox {
+ id: searchBox
+ width: parent.width
+ style: StudioTheme.Values.searchControlStyle
+
+ property string previousSearchText: ""
+ property bool materialsExpanded: true
+ property bool texturesExpanded: true
+
+ onSearchChanged: (searchText) => {
+ if (searchText !== "") {
+ if (previousSearchText === "") {
+ materialsExpanded = materialsSection.expanded
+ texturesExpanded = texturesSection.expanded
+ }
+ materialsSection.expanded = true
+ texturesSection.expanded = true
+ } else if (previousSearchText !== "") {
+ materialsSection.expanded = materialsExpanded
+ texturesSection.expanded = texturesExpanded
+ }
+ previousSearchText = searchText
+
+ root.startDelayedEnsureTimer(50)
+
+ rootView.handleSearchFilterChanged(searchText)
+ }
+ }
+
+ Row {
+ width: parent.width
+ height: StudioTheme.Values.toolbarHeight
+ spacing: 6
- width: root.width
+ DoubleButton {
+ id: addMaterial
+ icon: StudioTheme.Constants.material_medium
+ tooltip: qsTr("Add a Material.")
+ onClicked: materialBrowserModel.addNewMaterial()
+ enabled: root.enableUiElements
+ }
- onSearchChanged: (searchText) => {
- rootView.handleSearchFilterChanged(searchText)
+ DoubleButton {
+ id: addTexture
+ icon: StudioTheme.Constants.textures_medium
+ tooltip: qsTr("Add a Texture.")
+ onClicked: materialBrowserTexturesModel.addNewTexture()
+ enabled: root.enableUiElements
+ }
}
}
}
@@ -130,26 +601,35 @@ Item {
visible: text !== ""
}
- ScrollView {
+ HelperWidgets.ScrollView {
id: scrollView
width: root.width
- height: root.height - searchBox.height
+ height: root.height - topContent.height
clip: true
visible: root.enableUiElements
- interactive: !ctxMenu.opened && !ctxMenuTextures.opened
+ interactive: !ctxMenu.opened && !ctxMenuTextures.opened && !rootView.isDragging
+
+ Behavior on contentY {
+ id: contentYBehavior
+ PropertyAnimation {
+ id: scrollViewAnim
+ easing.type: Easing.InOutQuad
+ }
+ }
Column {
Item {
width: root.width
height: materialsSection.height
- Section {
+ HelperWidgets.Section {
id: materialsSection
width: root.width
caption: qsTr("Materials")
dropEnabled: true
+ category: "MaterialBrowser"
onDropEnter: (drag) => {
drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundlematerial"
@@ -160,13 +640,26 @@ Item {
materialsSection.highlight = false
}
- onDrop: {
+ onDrop: (drag) => {
+ drag.accept()
materialsSection.highlight = false
rootView.acceptBundleMaterialDrop()
}
+ onExpandedChanged: {
+ if (expanded) {
+ if (root.visibleItemCount(materialBrowserModel) > 0)
+ rootView.focusMaterialSection(true)
+ if (!searchBox.activeFocus)
+ scrollView.forceActiveFocus()
+ } else {
+ root.startDelayedEnsureTimer(300) // wait for section collapse animation
+ rootView.focusMaterialSection(false)
+ }
+ }
+
Grid {
- id: grid
+ id: gridMaterials
width: scrollView.width
leftPadding: 5
@@ -178,6 +671,12 @@ Item {
id: materialRepeater
model: materialBrowserModel
+
+ onItemRemoved: (index, item) => {
+ if (item === root.currMaterialItem)
+ root.currMaterialItem = null
+ }
+
delegate: MaterialItem {
width: root.cellWidth
height: root.cellHeight
@@ -208,36 +707,26 @@ Item {
width: root.width
}
}
-
- IconButton {
- id: addMaterialButton
-
- tooltip: qsTr("Add a material.")
-
- anchors.right: parent.right
- anchors.rightMargin: scrollView.verticalScrollBarVisible ? 10 : 0
- icon: StudioTheme.Constants.plus
- normalColor: "transparent"
- buttonSize: StudioTheme.Values.sectionHeadHeight
- onClicked: materialBrowserModel.addNewMaterial()
- enabled: root.enableUiElements
- }
}
Item {
width: root.width
height: texturesSection.height
- Section {
+ HelperWidgets.Section {
id: texturesSection
width: root.width
caption: qsTr("Textures")
+ category: "MaterialBrowser"
dropEnabled: true
onDropEnter: (drag) => {
- drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture"
+ let accepted = drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture"
+ if (drag.formats[0] === "application/vnd.qtdesignstudio.assets")
+ accepted = rootView.hasAcceptableAssets(drag.urls)
+ drag.accepted = accepted
highlight = drag.accepted
}
@@ -245,12 +734,30 @@ Item {
highlight = false
}
- onDrop: {
+ onDrop: (drag) => {
+ drag.accept()
highlight = false
- rootView.acceptBundleTextureDrop()
+ if (drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture")
+ rootView.acceptBundleTextureDrop()
+ else if (drag.formats[0] === "application/vnd.qtdesignstudio.assets")
+ rootView.acceptAssetsDrop(drag.urls)
+ }
+
+ onExpandedChanged: {
+ if (expanded) {
+ if (root.visibleItemCount(materialBrowserTexturesModel) > 0)
+ rootView.focusMaterialSection(false)
+ if (!searchBox.activeFocus)
+ scrollView.forceActiveFocus()
+ } else {
+ root.startDelayedEnsureTimer(300) // wait for section collapse animation
+ rootView.focusMaterialSection(true)
+ }
}
Grid {
+ id: gridTextures
+
width: scrollView.width
leftPadding: 5
rightPadding: 5
@@ -291,20 +798,6 @@ Item {
width: root.width
}
}
-
- IconButton {
- id: addTextureButton
-
- tooltip: qsTr("Add a texture.")
-
- anchors.right: parent.right
- anchors.rightMargin: scrollView.verticalScrollBarVisible ? 10 : 0
- icon: StudioTheme.Constants.plus
- normalColor: "transparent"
- buttonSize: StudioTheme.Values.sectionHeadHeight
- onClicked: materialBrowserTexturesModel.addNewTexture()
- enabled: root.enableUiElements
- }
}
DropArea {
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml
index 36d3ca50ea..f72d21b35b 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserContextMenu.qml
@@ -5,6 +5,7 @@ import QtQuick
import HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import MaterialBrowserBackend
StudioControls.Menu {
id: root
@@ -13,11 +14,15 @@ StudioControls.Menu {
property var targetItem: null
property int copiedMaterialInternalId: -1
property var matSectionsModel: []
+ property bool restoreFocusOnClose: true
+
+ property var materialBrowserModel: MaterialBrowserBackend.materialBrowserModel
function popupMenu(targetItem = null, targetMaterial = null)
{
this.targetItem = targetItem
this.targetMaterial = targetMaterial
+ restoreFocusOnClose = true
popup()
}
@@ -102,7 +107,10 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("Rename")
enabled: root.targetItem
- onTriggered: root.targetItem.startRename();
+ onTriggered: {
+ restoreFocusOnClose = false
+ root.targetItem.startRename()
+ }
}
StudioControls.MenuItem {
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
index 6fdd3f5d61..abf3717e20 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
@@ -6,6 +6,7 @@ import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
import StudioTheme 1.0 as StudioTheme
+import MaterialBrowserBackend
Rectangle {
id: root
@@ -32,12 +33,12 @@ Rectangle {
if (matName.readOnly)
return;
- materialBrowserModel.renameMaterial(index, matName.text);
+ MaterialBrowserBackend.materialBrowserModel.renameMaterial(index, matName.text);
mouseArea.forceActiveFocus()
}
- border.width: materialBrowserModel.selectedIndex === index ? rootView.materialSectionFocused ? 3 : 1 : 0
- border.color: materialBrowserModel.selectedIndex === index
+ border.width: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index ? MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
+ border.color: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index
? StudioTheme.Values.themeControlOutlineInteraction
: "transparent"
color: "transparent"
@@ -48,10 +49,20 @@ Rectangle {
onEntered: (drag) => {
drag.accepted = drag.formats[0] === "application/vnd.qtdesignstudio.texture"
+ || drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture"
+ || (drag.formats[0] === "application/vnd.qtdesignstudio.assets"
+ && rootView.hasAcceptableAssets(drag.urls))
}
onDropped: (drag) => {
- rootView.acceptTextureDropOnMaterial(index, drag.getDataAsString(drag.keys[0]))
+ drag.accept()
+
+ if (drag.formats[0] === "application/vnd.qtdesignstudio.texture")
+ MaterialBrowserBackend.rootView.acceptTextureDropOnMaterial(index, drag.getDataAsString(drag.keys[0]))
+ else if (drag.formats[0] === "application/vnd.qtdesignstudio.bundletexture")
+ MaterialBrowserBackend.rootView.acceptBundleTextureDropOnMaterial(index, drag.urls[0])
+ else if (drag.formats[0] === "application/vnd.qtdesignstudio.assets")
+ MaterialBrowserBackend.rootView.acceptAssetsDropOnMaterial(index, drag.urls)
}
}
@@ -62,16 +73,16 @@ Rectangle {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
- rootView.focusMaterialSection(true)
- materialBrowserModel.selectMaterial(index)
+ MaterialBrowserBackend.materialBrowserModel.selectMaterial(index)
+ MaterialBrowserBackend.rootView.focusMaterialSection(true)
if (mouse.button === Qt.LeftButton)
- rootView.startDragMaterial(index, mapToGlobal(mouse.x, mouse.y))
+ MaterialBrowserBackend.rootView.startDragMaterial(index, mapToGlobal(mouse.x, mouse.y))
else if (mouse.button === Qt.RightButton)
root.showContextMenu()
}
- onDoubleClicked: materialBrowserModel.openMaterialEditor();
+ onDoubleClicked: MaterialBrowserBackend.materialBrowserModel.openMaterialEditor();
}
Column {
@@ -90,6 +101,11 @@ Rectangle {
cache: false
}
+ // Eat keys so they are not passed to parent while editing name
+ Keys.onPressed: (e) => {
+ e.accepted = true;
+ }
+
TextInput {
id: matName
@@ -130,8 +146,8 @@ Rectangle {
anchors.fill: parent
onClicked: {
- rootView.focusMaterialSection(true)
- materialBrowserModel.selectMaterial(index)
+ MaterialBrowserBackend.materialBrowserModel.selectMaterial(index)
+ MaterialBrowserBackend.rootView.focusMaterialSection(true)
}
onDoubleClicked: root.startRename()
}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureBrowserContextMenu.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureBrowserContextMenu.qml
index 658b7e7a51..714c004370 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureBrowserContextMenu.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureBrowserContextMenu.qml
@@ -5,6 +5,7 @@ import QtQuick
import HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
+import MaterialBrowserBackend
StudioControls.Menu {
id: root
@@ -12,6 +13,8 @@ StudioControls.Menu {
property var targetTexture: null
property int copiedTextureInternalId: -1
+ property var materialBrowserTexturesModel: MaterialBrowserBackend.materialBrowserTexturesModel
+
function popupMenu(targetTexture = null)
{
this.targetTexture = targetTexture
@@ -30,7 +33,7 @@ StudioControls.Menu {
StudioControls.MenuItem {
text: qsTr("Apply to selected material")
- enabled: root.targetTexture && materialBrowserModel.selectedIndex >= 0
+ enabled: root.targetTexture && MaterialBrowserBackend.materialBrowserModel.selectedIndex >= 0
onTriggered: materialBrowserTexturesModel.applyToSelectedMaterial(root.targetTexture.textureInternalId)
}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
index 002fcb0d7d..99970bc266 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
@@ -7,6 +7,7 @@ import QtQuick.Layouts
import QtQuickDesignerTheme
import HelperWidgets
import StudioTheme as StudioTheme
+import MaterialBrowserBackend
Rectangle {
id: root
@@ -14,9 +15,9 @@ Rectangle {
visible: textureVisible
color: "transparent"
- border.width: materialBrowserTexturesModel.selectedIndex === index
- ? !rootView.materialSectionFocused ? 3 : 1 : 0
- border.color: materialBrowserTexturesModel.selectedIndex === index
+ border.width: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
+ ? !MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
+ border.color: MaterialBrowserBackend.materialBrowserTexturesModel.selectedIndex === index
? StudioTheme.Values.themeControlOutlineInteraction
: "transparent"
@@ -30,16 +31,16 @@ Rectangle {
hoverEnabled: true
onPressed: (mouse) => {
- rootView.focusMaterialSection(false)
- materialBrowserTexturesModel.selectTexture(index)
+ MaterialBrowserBackend.materialBrowserTexturesModel.selectTexture(index)
+ MaterialBrowserBackend.rootView.focusMaterialSection(false)
if (mouse.button === Qt.LeftButton)
- rootView.startDragTexture(index, mapToGlobal(mouse.x, mouse.y))
+ MaterialBrowserBackend.rootView.startDragTexture(index, mapToGlobal(mouse.x, mouse.y))
else if (mouse.button === Qt.RightButton)
root.showContextMenu()
}
- onDoubleClicked: materialBrowserTexturesModel.openTextureEditor();
+ onDoubleClicked: MaterialBrowserBackend.materialBrowserTexturesModel.openTextureEditor();
}
ToolTip {
@@ -61,9 +62,10 @@ Rectangle {
Image {
source: "image://materialBrowserTex/" + textureSource
asynchronous: true
- sourceSize.width: root.width - 10
- sourceSize.height: root.height - 10
+ width: root.width - 10
+ height: root.height - 10
anchors.centerIn: parent
smooth: true
+ fillMode: Image.PreserveAspectFit
}
}
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
index 3a28de2c94..52e4907448 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorPane.qml
@@ -18,10 +18,11 @@ PropertyEditorPane {
topSection.refreshPreview()
}
- // Called also from C++ to close context menu on focus out
+ // Called from C++ to close context menu on focus out
function closeContextMenu()
{
topSection.closeContextMenu()
+ Controller.closeContextMenu()
}
// Called from C++ to initialize preview menu checkmarks
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml
index 6ff49ad2cf..d5a9acf974 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorToolBar.qml
@@ -1,69 +1,57 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
import QtQuickDesignerTheme 1.0
-import HelperWidgets 2.0
+import HelperWidgets 2.0 as HelperWidgets
+import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
import MaterialToolBarAction 1.0
Rectangle {
id: root
- color: StudioTheme.Values.themeSectionHeadBackground
- width: row.width
- height: 40
+ color: StudioTheme.Values.themeToolbarBackground
+ height: StudioTheme.Values.toolbarHeight
signal toolBarAction(int action)
Row {
id: row
-
+ spacing: StudioTheme.Values.toolbarSpacing
anchors.verticalCenter: parent.verticalCenter
leftPadding: 6
- IconButton {
- icon: StudioTheme.Constants.applyMaterialToSelected
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.apply_medium
enabled: hasMaterial && hasModelSelection && hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
tooltip: qsTr("Apply material to selected model.")
+ onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
}
- IconButton {
- icon: StudioTheme.Constants.newMaterial
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.create_medium
enabled: hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
tooltip: qsTr("Create new material.")
+ onClicked: root.toolBarAction(ToolBarAction.AddNewMaterial)
}
- IconButton {
- icon: StudioTheme.Constants.deleteMaterial
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.delete_medium
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
tooltip: qsTr("Delete current material.")
+ onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentMaterial)
}
- IconButton {
- icon: StudioTheme.Constants.openMaterialBrowser
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.materialBrowser_medium
enabled: hasMaterial && hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
tooltip: qsTr("Open material browser.")
+ onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
}
}
}
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
index e4d37650e1..dbc023d83b 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
@@ -1,12 +1,11 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Controls 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
import QtQuickDesignerTheme 1.0
-import QtQuick.Templates 2.15 as T
-import HelperWidgets 2.0
+import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
@@ -17,6 +16,11 @@ Column {
property string previewEnv
property string previewModel
+ property StudioTheme.ControlStyle buttonStyle: StudioTheme.ViewBarButtonStyle {
+ //This is how you can override stuff from the control styles
+ controlSize: Qt.size(previewOptions.width, previewOptions.width)
+ baseIconFontSize: StudioTheme.Values.bigIconFontSize
+ }
function refreshPreview()
{
@@ -153,17 +157,17 @@ Column {
Column {
anchors.horizontalCenter: parent.horizontalCenter
- IconButton {
- icon: StudioTheme.Constants.materialPreviewEnvironment
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: previewOptions.width
+
+ HelperWidgets.AbstractButton {
+ style: root.buttonStyle
+ buttonIcon: StudioTheme.Constants.textures_medium
tooltip: qsTr("Select preview environment.")
onClicked: envMenu.popup()
}
- IconButton {
- icon: StudioTheme.Constants.materialPreviewModel
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: previewOptions.width
+
+ HelperWidgets.AbstractButton {
+ style: root.buttonStyle
+ buttonIcon: StudioTheme.Constants.cube_medium
tooltip: qsTr("Select preview model.")
onClicked: modelMenu.popup()
}
@@ -172,19 +176,19 @@ Column {
}
- Section {
+ HelperWidgets.Section {
// Section with hidden header is used so properties are aligned with the other sections' properties
hideHeader: true
width: parent.width
collapsible: false
- SectionLayout {
- PropertyLabel { text: qsTr("Name") }
+ HelperWidgets.SectionLayout {
+ HelperWidgets.PropertyLabel { text: qsTr("Name") }
- SecondColumnLayout {
- Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
+ HelperWidgets.SecondColumnLayout {
+ HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
- LineEdit {
+ HelperWidgets.LineEdit {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: StudioTheme.Values.singleControlColumnWidth
backendValue: backendValues.objectName
@@ -195,18 +199,18 @@ Column {
showExtendedFunctionButton: false
// allow only alphanumeric characters, underscores, no space at start, and 1 space between words
- validator: RegExpValidator { regExp: /^(\w+\s)*\w+$/ }
+ validator: HelperWidgets.RegExpValidator { regExp: /^(\w+\s)*\w+$/ }
}
- ExpandingSpacer {}
+ HelperWidgets.ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Type") }
+ HelperWidgets.PropertyLabel { text: qsTr("Type") }
- SecondColumnLayout {
- Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
+ HelperWidgets.SecondColumnLayout {
+ HelperWidgets.Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
- ComboBox {
+ HelperWidgets.ComboBox {
currentIndex: possibleTypeIndex
model: possibleTypes
showExtendedFunctionButton: false
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
index 84ccff7429..d89d2d5157 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
@@ -140,11 +140,15 @@ Item {
height: DialogValues.styleImageHeight
+ 2 * DialogValues.styleImageBorderWidth
- border.color: delegateId.hovered
- ? DialogValues.textColor
- : (index === stylesList.currentIndex
- ? DialogValues.textColorInteraction
- : "transparent")
+ border.color: {
+ if (index === stylesList.currentIndex)
+ return DialogValues.textColorInteraction
+
+ if (delegateId.hovered)
+ return DialogValues.textColor
+ else
+ return "transparent"
+ }
border.width: index === stylesList.currentIndex || delegateId.hovered
? DialogValues.styleImageBorderWidth
diff --git a/share/qtcreator/qmldesigner/newstateseditor/Main.qml b/share/qtcreator/qmldesigner/newstateseditor/Main.qml
index 0176cc79f6..4cd85bb1ad 100644
--- a/share/qtcreator/qmldesigner/newstateseditor/Main.qml
+++ b/share/qtcreator/qmldesigner/newstateseditor/Main.qml
@@ -40,7 +40,7 @@ Rectangle {
property bool isLandscape: true
- color: StudioTheme.Values.themeStatePanelBackground
+ color: StudioTheme.Values.themePanelBackground
onWidthChanged: root.responsiveResize(root.width, root.height)
onHeightChanged: root.responsiveResize(root.width, root.height)
@@ -374,7 +374,7 @@ Rectangle {
}
}
- color: StudioTheme.Values.themeSectionHeadBackground
+ color: StudioTheme.Values.themeToolbarBackground
width: root.width
height: (toolBar.doubleRow ? 2 : 1) * StudioTheme.Values.toolbarHeight
@@ -403,6 +403,7 @@ Rectangle {
}
StudioControls.ComboBox {
+ style: StudioTheme.Values.viewBarControlStyle
id: stateGroupComboBox
actionIndicatorVisible: false
model: statesEditorModel.stateGroups
@@ -458,14 +459,16 @@ Rectangle {
leftPadding: toolBar.doubleRow ? root.padding : 0
HelperWidgets.AbstractButton {
- buttonIcon: StudioTheme.Constants.plus
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.add_medium
anchors.verticalCenter: parent.verticalCenter
tooltip: qsTr("Create State Group")
onClicked: statesEditorModel.addStateGroup("stateGroup")
}
HelperWidgets.AbstractButton {
- buttonIcon: StudioTheme.Constants.minus
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.remove_medium
anchors.verticalCenter: parent.verticalCenter
enabled: statesEditorModel.activeStateGroupIndex !== 0
tooltip: qsTr("Remove State Group")
@@ -474,7 +477,8 @@ Rectangle {
HelperWidgets.AbstractButton {
id: editButton
- buttonIcon: StudioTheme.Constants.edit
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.edit_medium
anchors.verticalCenter: parent.verticalCenter
enabled: statesEditorModel.activeStateGroupIndex !== 0
checked: editDialog.visible
@@ -502,7 +506,8 @@ Rectangle {
rightPadding: root.padding
HelperWidgets.AbstractButton {
- buttonIcon: StudioTheme.Constants.gridView
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.grid_medium
anchors.verticalCenter: parent.verticalCenter
enabled: !root.tinyMode
tooltip: qsTr("Show thumbnails")
@@ -513,7 +518,8 @@ Rectangle {
}
HelperWidgets.AbstractButton {
- buttonIcon: StudioTheme.Constants.textFullJustification
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.list_medium
anchors.verticalCenter: parent.verticalCenter
enabled: !root.tinyMode
tooltip: qsTr("Show property changes")
@@ -677,7 +683,7 @@ Rectangle {
onEntered: function (drag) {
let dragSource = (drag.source as StateThumbnail)
- if (dragSource === undefined)
+ if (!dragSource)
return
if (dragSource.extendString !== stateThumbnail.extendString
@@ -692,7 +698,7 @@ Rectangle {
onDropped: function (drop) {
let dropSource = (drop.source as StateThumbnail)
- if (dropSource === undefined)
+ if (!dropSource)
return
if (dropSource.extendString !== stateThumbnail.extendString
diff --git a/share/qtcreator/qmldesigner/newstateseditor/MenuButton.qml b/share/qtcreator/qmldesigner/newstateseditor/MenuButton.qml
index 6eda458212..a7a78b5e44 100644
--- a/share/qtcreator/qmldesigner/newstateseditor/MenuButton.qml
+++ b/share/qtcreator/qmldesigner/newstateseditor/MenuButton.qml
@@ -52,25 +52,15 @@ Item {
property color iconColor: StudioTheme.Values.themeTextColor
- Rectangle {
- id: rectangle
- width: 19
- height: 3
- color: menuIcon.iconColor
- }
-
- Rectangle {
- id: rectangle1
- width: 19
- height: 3
- color: menuIcon.iconColor
- }
-
- Rectangle {
- id: rectangle2
- width: 19
- height: 3
- color: menuIcon.iconColor
+ Label {
+ id: moreMenu
+ anchors.fill: parent
+ text: StudioTheme.Constants.more_medium
+ color: StudioTheme.Values.themeTextColor
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: 16 //StudioTheme.Values.myIconFontSize
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
}
}
@@ -123,7 +113,7 @@ Item {
PropertyChanges {
target: background
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: StudioTheme.Values.themeControlBackground_topToolbarHover
}
PropertyChanges {
target: menuIcon
diff --git a/share/qtcreator/qmldesigner/newstateseditor/StateScrollBar.qml b/share/qtcreator/qmldesigner/newstateseditor/StateScrollBar.qml
index 1591d3ecb7..51e884aa5a 100644
--- a/share/qtcreator/qmldesigner/newstateseditor/StateScrollBar.qml
+++ b/share/qtcreator/qmldesigner/newstateseditor/StateScrollBar.qml
@@ -41,7 +41,7 @@ T.ScrollBar {
radius: width / 2
opacity: 0.0
color: scrollBar.pressed ? StudioTheme.Values.themeScrollBarHandle //"#4C4C4C"//DARK
- : StudioTheme.Values.themeScrollBarTrack //"#3E3E3E"//DARK
+ : StudioTheme.Values.themeScrollBarHandle //"#3E3E3E"//DARK
states: State {
name: "active"
diff --git a/share/qtcreator/qmldesigner/newstateseditor/StateThumbnail.qml b/share/qtcreator/qmldesigner/newstateseditor/StateThumbnail.qml
index 6d4a84e44c..e54732c8d0 100644
--- a/share/qtcreator/qmldesigner/newstateseditor/StateThumbnail.qml
+++ b/share/qtcreator/qmldesigner/newstateseditor/StateThumbnail.qml
@@ -127,7 +127,8 @@ Item {
id: stateBackground
color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeInteraction
- border.width: root.isChecked ? 4 : 0
+ border.width: root.isChecked ? 3 : 0
+ radius: 10
anchors.fill: parent
readonly property int controlHeight: 25
@@ -159,6 +160,7 @@ Item {
HelperWidgets.AbstractButton {
id: defaultButton
+ style: StudioTheme.Values.statesControlStyle
width: 50
height: stateBackground.controlHeight
checkedInverted: true
@@ -173,6 +175,7 @@ Item {
StudioControls.TextField {
id: stateNameField
+ style: StudioTheme.Values.statesControlStyle
property string previousText
@@ -648,6 +651,7 @@ Item {
StudioControls.TextField {
id: whenCondition
+ style: StudioTheme.Values.statesControlStyle
property string previousCondition
@@ -656,7 +660,7 @@ Item {
visible: !root.baseState
indicatorVisible: true
- indicator.icon.text: StudioTheme.Constants.edit
+ indicator.icon.text: StudioTheme.Constants.edit_medium
indicator.onClicked: {
whenCondition.previousCondition = whenCondition.text
@@ -755,7 +759,7 @@ Item {
PropertyChanges {
target: stateBackground
- color: StudioTheme.Values.themeControlBackground
+ color: StudioTheme.Values.themeToolbarBackground
}
},
State {
@@ -764,7 +768,7 @@ Item {
PropertyChanges {
target: stateBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: StudioTheme.Values.themeStateBackgroundColor_hover
}
},
State {
@@ -774,7 +778,7 @@ Item {
PropertyChanges {
target: stateBackground
- color: StudioTheme.Values.themeStateHighlight
+ color: StudioTheme.Values.themeThumbnailBackground_baseState
}
},
State {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml
index e67df362c8..4b66032bcf 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml
@@ -49,7 +49,6 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
typeFilter: "QtQuick.AudioOutput"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.audioOutput
}
@@ -70,7 +69,6 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
typeFilter: "QtQuick.VideoOutput"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.videoOutput
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
index 6cac5c6f15..e9be2285c5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AdvancedSection.qml
@@ -15,6 +15,7 @@ Section {
PropertyLabel {
visible: majorQtQuickVersion > 1
text: qsTr("Enabled")
+ tooltip: qsTr("Toggles if the component is enabled to receive mouse and keyboard input.")
}
SecondColumnLayout {
@@ -32,6 +33,7 @@ Section {
PropertyLabel {
text: qsTr("Smooth")
+ tooltip: qsTr("Uses smooth filtering when the image is scaled or transformed.")
blockedByTemplate: !backendValues.smooth.isAvailable
}
@@ -49,6 +51,7 @@ Section {
PropertyLabel {
text: qsTr("Antialiasing")
+ tooltip: qsTr("Refines the edges of the image.")
blockedByTemplate: !backendValues.antialiasing.isAvailable
}
@@ -102,7 +105,7 @@ Section {
PropertyLabel {
text: qsTr("Baseline offset")
- tooltip: qsTr("Position of the component's baseline in local coordinates.")
+ tooltip: qsTr("Sets the position of the component's baseline in local coordinates.")
blockedByTemplate: !backendValues.baselineOffset.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml
index 4d1ef5711b..00b97f9942 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimatedImageSpecifics.qml
@@ -24,6 +24,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Speed")
+ tooltip: qsTr("Sets the speed of the animation.")
blockedByTemplate: !backendValues.speed.isAvailable
}
@@ -47,7 +48,7 @@ Column {
PropertyLabel {
text: qsTr("Playing")
- tooltip: qsTr("Whether the animation is playing or paused.")
+ tooltip: qsTr("Toggles if the animation is playing.")
blockedByTemplate: !backendValues.playing.isAvailable && !backendValues.paused.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimationTargetSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimationTargetSection.qml
index f835522596..aef4aa5269 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimationTargetSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/AnimationTargetSection.qml
@@ -23,7 +23,6 @@ Section {
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "QtQuick.QtObject"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.target
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
index a80dcf73e9..0862b7e6d8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/BorderImageSpecifics.qml
@@ -18,7 +18,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Source") }
+ PropertyLabel {
+ text: qsTr("Source")
+ tooltip: qsTr("Sets the source image for the border.")
+ }
SecondColumnLayout {
UrlChooser {
@@ -30,6 +33,7 @@ Column {
PropertyLabel {
text: qsTr("Source size")
+ tooltip: qsTr("Sets the dimension of the border image.")
blockedByTemplate: !backendValues.sourceSize.isAvailable
}
@@ -49,6 +53,7 @@ Column {
ControlLabel {
//: The width of the object
text: qsTr("W", "width")
+ tooltip: qsTr("Width")
enabled: backendValues.sourceSize_width.isAvailable
}
@@ -69,6 +74,7 @@ Column {
ControlLabel {
//: The height of the object
text: qsTr("H", "height")
+ tooltip: qsTr("Height")
enabled: backendValues.sourceSize_height.isAvailable
}
/*
@@ -82,6 +88,7 @@ Column {
PropertyLabel {
text: qsTr("Tile mode H")
+ tooltip: qsTr("Sets the horizontal tiling mode.")
blockedByTemplate: !backendValues.horizontalTileMode.isAvailable
}
@@ -101,6 +108,7 @@ Column {
PropertyLabel {
text: qsTr("Tile mode V")
+ tooltip: qsTr("Sets the vertical tiling mode.")
blockedByTemplate: !backendValues.verticalTileMode.isAvailable
}
@@ -118,7 +126,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Border left") }
+ PropertyLabel {
+ text: qsTr("Border left")
+ tooltip: qsTr("Sets the left border.")
+ }
SecondColumnLayout {
SpinBox {
@@ -133,7 +144,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Border right") }
+ PropertyLabel {
+ text: qsTr("Border right")
+ tooltip: qsTr("Sets the right border.")
+ }
SecondColumnLayout {
SpinBox {
@@ -148,7 +162,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Border top") }
+ PropertyLabel {
+ text: qsTr("Border top")
+ tooltip: qsTr("Sets the top border.")
+ }
SecondColumnLayout {
SpinBox {
@@ -163,7 +180,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Border bottom") }
+ PropertyLabel {
+ text: qsTr("Border bottom")
+ tooltip: qsTr("Sets the bottom border.")
+ }
SecondColumnLayout {
SpinBox {
@@ -180,7 +200,7 @@ Column {
PropertyLabel {
text: qsTr("Mirror")
- tooltip: qsTr("Specifies whether the image should be horizontally inverted.")
+ tooltip: qsTr("Toggles if the image should be inverted horizontally.")
blockedByTemplate: !backendValues.mirror.isAvailable
}
@@ -198,7 +218,7 @@ Column {
PropertyLabel {
text: qsTr("Smooth")
- tooltip: qsTr("Specifies whether the image is smoothly filtered when scaled or transformed.")
+ tooltip: qsTr("Toggles if the image should be filtered smoothly when transformed.")
blockedByTemplate: !backendValues.smooth.isAvailable
}
@@ -216,7 +236,7 @@ Column {
PropertyLabel {
text: qsTr("Cache")
- tooltip: qsTr("Specifies whether the image should be cached.")
+ tooltip: qsTr("Toggles if the image is saved to the cache memory.")
blockedByTemplate: !backendValues.cache.isAvailable
}
@@ -234,7 +254,7 @@ Column {
PropertyLabel {
text: qsTr("Asynchronous")
- tooltip: qsTr("Specifies that images on the local filesystem should be loaded asynchronously in a separate thread.")
+ tooltip: qsTr("Toggles if the image is loaded after all the components in the design.")
blockedByTemplate: !backendValues.asynchronous.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ColumnSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ColumnSpecifics.qml
index c8a298ec41..d385a19f87 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ColumnSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ColumnSpecifics.qml
@@ -18,7 +18,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Spacing") }
+ PropertyLabel {
+ text: qsTr("Spacing")
+ tooltip: qsTr("Sets the spacing between column items.")
+ }
SecondColumnLayout {
SpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ConnectionsSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ConnectionsSpecifics.qml
index 2c97b8e7e4..a4a3099146 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ConnectionsSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ConnectionsSpecifics.qml
@@ -52,7 +52,6 @@ Section {
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "QtQuick.Item"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.target
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml
index 57b12f6dc9..e625e5c842 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/AbstractButtonSection.qml
@@ -52,7 +52,7 @@ Section {
PropertyLabel {
text: qsTr("Checkable")
- tooltip: qsTr("Whether the button is checkable.")
+ tooltip: qsTr("Toggles if the button is checkable.")
}
SecondColumnLayout {
@@ -68,7 +68,7 @@ Section {
PropertyLabel {
text: qsTr("Checked")
- tooltip: qsTr("Whether the button is checked.")
+ tooltip: qsTr("Toggles if the button is checked.")
}
SecondColumnLayout {
@@ -84,7 +84,7 @@ Section {
PropertyLabel {
text: qsTr("Exclusive")
- tooltip: qsTr("Whether the button is exclusive.")
+ tooltip: qsTr("Toggles if the button is exclusive. Non-exclusive checkable buttons that belong to the same parent behave as if they are part of the same button group; only one button can be checked at any time.")
blockedByTemplate: !backendValues.autoExclusive.isAvailable
}
@@ -102,7 +102,7 @@ Section {
PropertyLabel {
text: qsTr("Auto-repeat")
- tooltip: qsTr("Whether the button repeats pressed(), released() and clicked() signals while the button is pressed and held down.")
+ tooltip: qsTr("Toggles if pressed, released, and clicked actions are repeated while the button is pressed and held down.")
}
SecondColumnLayout {
@@ -119,7 +119,7 @@ Section {
PropertyLabel {
text: qsTr("Repeat delay")
- tooltip: qsTr("Initial delay of auto-repetition in milliseconds.")
+ tooltip: qsTr("Sets the initial delay of auto-repetition in milliseconds.")
enabled: autoRepeat.checked
}
@@ -148,7 +148,7 @@ Section {
PropertyLabel {
text: qsTr("Repeat interval")
- tooltip: qsTr("Interval of auto-repetition in milliseconds.")
+ tooltip: qsTr("Sets the interval between auto-repetitions in milliseconds.")
enabled: autoRepeat.checked
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml
index b56a968789..9cffbc9b44 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/BusyIndicatorSpecifics.qml
@@ -18,7 +18,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Running")
- tooltip: qsTr("Whether the busy indicator is currently indicating activity.")
+ tooltip: qsTr("Toggles if the busy indicator indicates activity.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml
index 1d4cc66f50..dbfbfd1fd4 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ButtonSection.qml
@@ -17,7 +17,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Appearance")
- tooltip: qsTr("Whether the button is flat and/or highlighted.")
+ tooltip: qsTr("Toggles if the button is flat or highlighted.")
blockedByTemplate: !backendValues.flat.isAvailable
&& !backendValues.highlighted.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckSection.qml
index 0bde6f5568..c70c8c925d 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/CheckSection.qml
@@ -16,7 +16,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Check state")
- tooltip: qsTr("The current check state.")
+ tooltip: qsTr("Sets the state of the check box.")
}
SecondColumnLayout {
@@ -34,7 +34,7 @@ Section {
PropertyLabel {
text: qsTr("Tri-state")
- tooltip: qsTr("Whether the checkbox has three states.")
+ tooltip: qsTr("Toggles if the check box can have an intermediate state.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml
index 3518760ff7..7c97b865f9 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ComboBoxSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Text role")
- tooltip: qsTr("The model role used for displaying text.")
+ tooltip: qsTr("Sets the model role for populating the combo box.")
}
SecondColumnLayout {
@@ -33,7 +33,7 @@ Column {
PropertyLabel {
text: qsTr("Display text")
- tooltip: qsTr("Holds the text that is displayed on the combo box button.")
+ tooltip: qsTr("Sets the initial display text for the combo box.")
}
SecondColumnLayout {
@@ -49,7 +49,7 @@ Column {
PropertyLabel {
text: qsTr("Current index")
- tooltip: qsTr("The index of the current item.")
+ tooltip: qsTr("Sets the current item.")
}
SecondColumnLayout {
@@ -68,7 +68,7 @@ Column {
PropertyLabel {
text: qsTr("Flat")
- tooltip: qsTr("Whether the combo box button is flat.")
+ tooltip: qsTr("Toggles if the combo box button is flat.")
}
SecondColumnLayout {
@@ -84,7 +84,7 @@ Column {
PropertyLabel {
text: qsTr("Editable")
- tooltip: qsTr("Whether the combo box is editable.")
+ tooltip: qsTr("Toggles if the combo box is editable.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ContainerSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ContainerSection.qml
index e73e522cda..6a7dc753d5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ContainerSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ContainerSection.qml
@@ -14,7 +14,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Current index")
- tooltip: qsTr("The index of the current item.")
+ tooltip: qsTr("Sets the index of the current item.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSection.qml
index 96233fc86e..2295eb1c1a 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ControlSection.qml
@@ -16,7 +16,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Enable")
- tooltip: qsTr("Whether the control is enabled and hover events are received.")
+ tooltip: qsTr("Toggles if the component can receive hover events.")
}
SecondColumnLayout {
@@ -42,7 +42,7 @@ Section {
PropertyLabel {
text: qsTr("Focus policy")
- tooltip: qsTr("Focus policy of the control.")
+ tooltip: qsTr("Sets focus method.")
blockedByTemplate: !backendValues.focusPolicy.isAvailable
}
@@ -62,7 +62,7 @@ Section {
PropertyLabel {
text: qsTr("Spacing")
- tooltip: qsTr("Spacing between internal elements of the control.")
+ tooltip: qsTr("Sets the spacing between internal elements of the component.")
}
SecondColumnLayout {
@@ -81,7 +81,7 @@ Section {
PropertyLabel {
text: qsTr("Wheel")
- tooltip: qsTr("Whether control accepts wheel events.")
+ tooltip: qsTr("Toggles if the component supports mouse wheel events.")
blockedByTemplate: !backendValues.wheelEnabled.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml
index 2f19d26b00..36f69faee8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DelayButtonSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Delay")
- tooltip: qsTr("The delay in milliseconds.")
+ tooltip: qsTr("Sets the delay before the button activates.")
}
SecondColumnLayout {
@@ -36,6 +36,7 @@ Column {
ControlLabel {
text: "ms"
+ tooltip: qsTr("Milliseconds.")
elide: Text.ElideNone
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml
index 4c90f26aba..a8536e8ca3 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/DialSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Value")
- tooltip: qsTr("The current value of the dial and whether it provides live value updates.")
+ tooltip: qsTr("Sets the value of the dial.")
}
SecondColumnLayout {
@@ -46,7 +46,7 @@ Column {
PropertyLabel {
text: qsTr("From")
- tooltip: qsTr("The starting value of the dial range.")
+ tooltip: qsTr("Sets the minimum value of the dial.")
}
SecondColumnLayout {
@@ -66,7 +66,7 @@ Column {
PropertyLabel {
text: qsTr("To")
- tooltip: qsTr("The ending value of the dial range.")
+ tooltip: qsTr("Sets the maximum value of the dial.")
}
SecondColumnLayout {
@@ -86,7 +86,7 @@ Column {
PropertyLabel {
text: qsTr("Step size")
- tooltip: qsTr("The step size of the dial.")
+ tooltip: qsTr("Sets the number by which the dial value changes.")
}
SecondColumnLayout {
@@ -106,7 +106,8 @@ Column {
PropertyLabel {
text: qsTr("Snap mode")
- tooltip: qsTr("The snap mode of the dial.")
+ tooltip: qsTr("Sets how the dial's handle snaps to the steps\n"
+ + "defined in <b>Step size</b>.")
}
SecondColumnLayout {
@@ -124,7 +125,7 @@ Column {
PropertyLabel {
text: qsTr("Input mode")
- tooltip: qsTr("How the dial tracks movement.")
+ tooltip: qsTr("Sets how the user can interact with the dial.")
}
SecondColumnLayout {
@@ -142,7 +143,7 @@ Column {
PropertyLabel {
text: qsTr("Wrap")
- tooltip: qsTr("Whether the dial wraps when dragged.")
+ tooltip: qsTr("Toggles if the dial wraps around when it reaches the start or end.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml
index 4e998f582a..645eac3312 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/GroupBoxSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Title")
- tooltip: qsTr("The title of the group box.")
+ tooltip: qsTr("Sets the title for the group box.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml
index 83d6db4ae1..a01406fce0 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/IconSection.qml
@@ -20,6 +20,7 @@ Section {
PropertyLabel {
text: qsTr("Source")
+ tooltip: qsTr("Sets a background image for the icon.")
blockedByTemplate: !backendValues.icon_source.isAvailable
enabled: !root.blockedByContext
}
@@ -35,6 +36,7 @@ Section {
PropertyLabel {
text: qsTr("Color")
+ tooltip: qsTr("Sets the color for the icon.")
blockedByTemplate: !backendValues.icon_color.isAvailable
enabled: !root.blockedByContext
}
@@ -47,6 +49,7 @@ Section {
PropertyLabel {
text: qsTr("Size")
+ tooltip: qsTr("Sets the height and width of the icon.")
blockedByTemplate: !backendValues.icon_width.isAvailable
enabled: !root.blockedByContext
}
@@ -102,7 +105,7 @@ Section {
PropertyLabel {
text: qsTr("Cache")
- tooltip: qsTr("Whether the icon should be cached.")
+ tooltip: qsTr("Toggles if the icon is saved to the cache memory.")
blockedByTemplate: !backendValues.icon_cache.isAvailable
enabled: !root.blockedByContext
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml
index 5f7f11e6f3..084b789ae2 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/InsetSection.qml
@@ -12,7 +12,10 @@ Section {
width: parent.width
SectionLayout {
- PropertyLabel { text: qsTr("Vertical") }
+ PropertyLabel {
+ text: qsTr("Vertical")
+ tooltip: qsTr("Sets the space from the top and bottom of the area to the background top and bottom.")
+ }
SecondColumnLayout {
SpinBox {
@@ -59,7 +62,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Horizontal") }
+ PropertyLabel {
+ text: qsTr("Horizontal")
+ tooltip: qsTr("Sets the space from the left and right of the area to the background left and right.")
+ }
SecondColumnLayout {
SpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSection.qml
index 3ce7e84eba..556f2d924c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ItemDelegateSection.qml
@@ -17,7 +17,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Highlight")
- tooltip: qsTr("Whether the delegate is highlighted.")
+ tooltip: qsTr("Toggles if the delegate is highlighted.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml
index 21f5c1559f..f8b78ec5b8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageIndicatorSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Count")
- tooltip: qsTr("The number of pages.")
+ tooltip: qsTr("Sets the number of pages.")
}
SecondColumnLayout {
@@ -35,7 +35,7 @@ Column {
PropertyLabel {
text: qsTr("Current")
- tooltip: qsTr("The index of the current page.")
+ tooltip: qsTr("Sets the current page.")
}
SecondColumnLayout {
@@ -54,7 +54,7 @@ Column {
PropertyLabel {
text: qsTr("Interactive")
- tooltip: qsTr("Whether the control is interactive.")
+ tooltip: qsTr("Toggles if the user can interact with the page indicator.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml
index db7db41024..a240b0a45e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PageSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Title")
- tooltip: qsTr("Title of the page.")
+ tooltip: qsTr("Sets the title of the page.")
}
SecondColumnLayout {
@@ -33,7 +33,8 @@ Column {
PropertyLabel {
text: qsTr("Content size")
- tooltip: qsTr("Content width and height used for calculating the total implicit size.")
+ tooltip: qsTr("Sets the size of the page. This is used to\n"
+ + "calculate the total implicit size.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSection.qml
index 02b4081ae6..1d1e29a1c8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/PaneSection.qml
@@ -14,7 +14,9 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Content size")
- tooltip: qsTr("Content width and height used for calculating the total implicit size.")
+ tooltip: qsTr("Sets the size of the %1. This is used to calculate\n"
+ + "the total implicit size.").arg(caption.charAt(0).toLowerCase()
+ + caption.slice(1))
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml
index 9cc3444cab..7c1abbcb89 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ProgressBarSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Value")
- tooltip: qsTr("The current value of the progress.")
+ tooltip: qsTr("Sets the value of the progress bar.")
}
SecondColumnLayout {
@@ -37,7 +37,7 @@ Column {
PropertyLabel {
text: qsTr("From")
- tooltip: qsTr("The starting value for the progress.")
+ tooltip: qsTr("Sets the minimum value of the progress bar.")
}
SecondColumnLayout {
@@ -57,7 +57,7 @@ Column {
PropertyLabel {
text: qsTr("To")
- tooltip: qsTr("The ending value for the progress.")
+ tooltip: qsTr("Sets the maximum value of the progress bar.")
}
SecondColumnLayout {
@@ -77,7 +77,9 @@ Column {
PropertyLabel {
text: qsTr("Indeterminate")
- tooltip: qsTr("Whether the progress is indeterminate.")
+ tooltip: qsTr("Toggles if the progress bar is in indeterminate mode.\n"
+ +"A progress bar in indeterminate mode displays that an\n"
+ + "operation is in progress.")
blockedByTemplate: !backendValues.indeterminate.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml
index 0a76d39bca..26e2f65954 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RadioDelegateSpecifics.qml
@@ -9,9 +9,7 @@ import StudioTheme 1.0 as StudioTheme
Column {
width: parent.width
- ItemDelegateSection {
- caption: qsTr("Radio Delegate")
- }
+ ItemDelegateSection {}
AbstractButtonSection {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml
index 5dc377fe61..f70a1220dd 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RangeSliderSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Value 1")
- tooltip: qsTr("The value of the first range slider handle.")
+ tooltip: qsTr("Sets the value of the first range slider handle.")
}
SecondColumnLayout {
@@ -38,7 +38,7 @@ Column {
implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
backendValue: backendValues.live
- tooltip: qsTr("Whether the range slider provides live value updates.")
+ tooltip: qsTr("Toggles if the range slider provides live value updates.")
}
ExpandingSpacer {}
@@ -47,7 +47,7 @@ Column {
PropertyLabel {
text: qsTr("Value 2")
- tooltip: qsTr("The value of the second range slider handle.")
+ tooltip: qsTr("Sets the value of the second range slider handle.")
}
SecondColumnLayout {
@@ -66,7 +66,7 @@ Column {
PropertyLabel {
text: qsTr("From")
- tooltip: qsTr("The starting value of the range slider range.")
+ tooltip: qsTr("Sets the minimum value of the range slider.")
}
SecondColumnLayout {
@@ -85,7 +85,7 @@ Column {
PropertyLabel {
text: qsTr("To")
- tooltip: qsTr("The ending value of the range slider range.")
+ tooltip: qsTr("Sets the maximum value of the range slider.")
}
SecondColumnLayout {
@@ -104,7 +104,8 @@ Column {
PropertyLabel {
text: qsTr("Step size")
- tooltip: qsTr("The step size of the range slider.")
+ tooltip: qsTr("Sets the interval between the steps.\n"
+ + "This functions if <b>Snap mode</b> is selected.")
}
SecondColumnLayout {
@@ -123,7 +124,7 @@ Column {
PropertyLabel {
text: qsTr("Drag threshold")
- tooltip: qsTr("The threshold (in logical pixels) at which a drag event will be initiated.")
+ tooltip: qsTr("Sets the threshold at which a drag event begins.")
}
SecondColumnLayout {
@@ -141,7 +142,8 @@ Column {
PropertyLabel {
text: qsTr("Snap mode")
- tooltip: qsTr("The snap mode of the range slider.")
+ tooltip: qsTr("Sets how the slider handles snaps to the steps\n"
+ + "defined in step size.")
}
SecondColumnLayout {
@@ -159,7 +161,7 @@ Column {
PropertyLabel {
text: qsTr("Orientation")
- tooltip: qsTr("The orientation of the range slider.")
+ tooltip: qsTr("Sets the orientation of the range slider.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml
index 39c1348dd7..067936b7f0 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/RoundButtonSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Appearance")
- tooltip: qsTr("Whether the button is flat and/or highlighted.")
+ tooltip: qsTr("Toggles if the button is flat or highlighted.")
blockedByTemplate: !backendValues.flat.isAvailable
&& !backendValues.highlighted.isAvailable
}
@@ -45,7 +45,7 @@ Column {
PropertyLabel {
text: qsTr("Radius")
- tooltip: qsTr("Radius of the button.")
+ tooltip: qsTr("Sets the radius of the button.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml
index 6e93cef487..9dc06b7969 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ScrollViewSpecifics.qml
@@ -14,7 +14,11 @@ Column {
caption: qsTr("Scroll View")
SectionLayout {
- PropertyLabel { text: qsTr("Content size") }
+ PropertyLabel {
+ text: qsTr("Content size")
+ tooltip: qsTr("Sets the width and height of the view.\n"
+ + "This is used for calculating the total implicit size.")
+ }
SecondColumnLayout {
SpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml
index 09ccdc29dc..1402a5382c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SpinBoxSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Value")
- tooltip: qsTr("The current value of the spin box.")
+ tooltip: qsTr("Sets the current value of the spin box.")
}
SecondColumnLayout {
@@ -34,7 +34,7 @@ Column {
PropertyLabel {
text: qsTr("From")
- tooltip: qsTr("The starting value of the spin box range.")
+ tooltip: qsTr("Sets the lowest value of the spin box range.")
}
SecondColumnLayout {
@@ -52,7 +52,7 @@ Column {
PropertyLabel {
text: qsTr("To")
- tooltip: qsTr("The ending value of the spin box range.")
+ tooltip: qsTr("Sets the highest value of the spin box range.")
}
SecondColumnLayout {
@@ -70,7 +70,7 @@ Column {
PropertyLabel {
text: qsTr("Step size")
- tooltip: qsTr("The step size of the spin box.")
+ tooltip: qsTr("Sets the number by which the spin box value changes.")
}
SecondColumnLayout {
@@ -88,7 +88,7 @@ Column {
PropertyLabel {
text: qsTr("Editable")
- tooltip: qsTr("Whether the spin box is editable.")
+ tooltip: qsTr("Toggles if the spin box is editable.")
}
SecondColumnLayout {
@@ -104,7 +104,8 @@ Column {
PropertyLabel {
text: qsTr("Wrap")
- tooltip: qsTr("Whether the spin box values wrap.")
+ tooltip: qsTr("Toggles if the spin box wraps around when \n"
+ + "it reaches the start or end.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml
index b12edde3ad..d5a300223d 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/SwipeViewSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Interactive")
- tooltip: qsTr("Whether the view is interactive.")
+ tooltip: qsTr("Toggles if the user can interact with the view.")
}
SecondColumnLayout {
@@ -32,7 +32,7 @@ Column {
PropertyLabel {
text: qsTr("Orientation")
- tooltip: qsTr("Orientation of the view.")
+ tooltip: qsTr("Sets the orientation of the view.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml
index 6281843fbe..86ee896483 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TabBarSpecifics.qml
@@ -17,7 +17,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Position")
- tooltip: qsTr("Position of the tab bar.")
+ tooltip: qsTr("Sets the position of the tab bar.")
}
SecondColumnLayout {
@@ -35,7 +35,8 @@ Column {
PropertyLabel {
text: qsTr("Content size")
- tooltip: qsTr("Content width and height used for calculating the total implicit size.")
+ tooltip: qsTr("Sets the width and height of the tab bar.\n"
+ + "This is used for calculating the total implicit size.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml
index 5236477342..e38460aa6c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/ToolSeparatorSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Orientation")
- tooltip: qsTr("The orientation of the separator.")
+ tooltip: qsTr("Sets the orientation of the separator.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml
index ad0f126d37..e461300a7d 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TumblerSpecifics.qml
@@ -16,7 +16,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Visible count")
- tooltip: qsTr("The count of visible items.")
+ tooltip: qsTr("Sets the number of items in the model.")
}
SecondColumnLayout {
@@ -34,7 +34,7 @@ Column {
PropertyLabel {
text: qsTr("Current index")
- tooltip: qsTr("The index of the current item.")
+ tooltip: qsTr("Sets the index of the current item.")
}
SecondColumnLayout {
@@ -52,7 +52,8 @@ Column {
PropertyLabel {
text: qsTr("Wrap")
- tooltip: qsTr("Whether the tumbler values wrap.")
+ tooltip: qsTr("Toggles if the tumbler wraps around when it reaches the\n"
+ + "top or bottom.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/FlowSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/FlowSpecifics.qml
index 3429f03e79..32e90d9660 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/FlowSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/FlowSpecifics.qml
@@ -18,7 +18,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Spacing") }
+ PropertyLabel {
+ text: qsTr("Spacing")
+ tooltip: qsTr("Sets the spacing between flow items.")
+ }
SecondColumnLayout {
SpinBox {
@@ -33,7 +36,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Flow") }
+ PropertyLabel {
+ text: qsTr("Flow")
+ tooltip: qsTr("Sets the direction of flow items.")
+ }
SecondColumnLayout {
ComboBox {
@@ -48,7 +54,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Layout direction") }
+ PropertyLabel {
+ text: qsTr("Layout direction")
+ tooltip: qsTr("Sets in which direction items in the flow are placed.")
+ }
SecondColumnLayout {
ComboBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
index 1b6cb3b52b..978612e19c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridSpecifics.qml
@@ -18,7 +18,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Columns") }
+ PropertyLabel {
+ text: qsTr("Columns")
+ tooltip: qsTr("Sets the number of columns in the grid.")
+ }
SecondColumnLayout {
SpinBox {
@@ -33,7 +36,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Rows") }
+ PropertyLabel {
+ text: qsTr("Rows")
+ tooltip: qsTr("Sets the number of rows in the grid.")
+ }
SecondColumnLayout {
SpinBox {
@@ -48,7 +54,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Spacing") }
+ PropertyLabel {
+ text: qsTr("Spacing")
+ tooltip: qsTr("Sets the space between grid items. The same space is applied for both rows and columns.")
+ }
SecondColumnLayout {
SpinBox {
@@ -63,7 +72,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Flow") }
+ PropertyLabel {
+ text: qsTr("Flow")
+ tooltip: qsTr("Sets in which direction items in the grid are placed.")
+ }
SecondColumnLayout {
ComboBox {
@@ -78,7 +90,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Layout direction") }
+ PropertyLabel {
+ text: qsTr("Layout direction")
+ tooltip: qsTr("Sets in which direction items in the grid are placed.")
+ }
SecondColumnLayout {
ComboBox {
@@ -93,7 +108,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Alignment H") }
+ PropertyLabel {
+ text: qsTr("Alignment H")
+ tooltip: qsTr("Sets the horizontal alignment of items in the grid.")
+ }
SecondColumnLayout {
ComboBox {
@@ -108,7 +126,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Alignment V") }
+ PropertyLabel {
+ text: qsTr("Alignment V")
+ tooltip: qsTr("Sets the vertical alignment of items in the grid.")
+ }
SecondColumnLayout {
ComboBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridViewSpecifics.qml
index ee0f49606f..0c7085bc2c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridViewSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GridViewSpecifics.qml
@@ -23,7 +23,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Cell size") }
+ PropertyLabel {
+ text: qsTr("Cell size")
+ tooltip: qsTr("Sets the dimensions of cells in the grid.")
+ }
SecondColumnLayout {
SpinBox {
@@ -39,6 +42,7 @@ Column {
ControlLabel {
//: The width of the object
text: qsTr("W", "width")
+ tooltip: qsTr("Width")
}
Spacer { implicitWidth: StudioTheme.Values.controlGap }
@@ -56,6 +60,7 @@ Column {
ControlLabel {
//: The height of the object
text: qsTr("H", "height")
+ tooltip: qsTr("Height")
}
/*
TODO QDS-4836
@@ -66,7 +71,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Flow") }
+ PropertyLabel {
+ text: qsTr("Flow")
+ tooltip: qsTr("Sets the directions of the cells.")
+ }
SecondColumnLayout {
ComboBox {
@@ -81,7 +89,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Layout direction") }
+ PropertyLabel {
+ text: qsTr("Layout direction")
+ tooltip: qsTr("Sets in which direction items in the grid view are placed.")
+ }
SecondColumnLayout {
ComboBox {
@@ -98,7 +109,7 @@ Column {
PropertyLabel {
text: qsTr("Snap mode")
- tooltip: qsTr("Determines how the view scrolling will settle following a drag or flick.")
+ tooltip: qsTr("Sets how the view scrolling will settle following a drag or flick.")
}
SecondColumnLayout {
@@ -116,7 +127,7 @@ Column {
PropertyLabel {
text: qsTr("Cache")
- tooltip: qsTr("Cache buffer")
+ tooltip: qsTr("Sets in pixels how far the components are kept loaded outside the view's visible area.")
blockedByTemplate: !backendValues.cacheBuffer.isAvailable
}
@@ -163,7 +174,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Range")
- tooltip: qsTr("Highlight range")
+ tooltip: qsTr("Sets the highlight range mode.")
}
SecondColumnLayout {
@@ -181,7 +192,7 @@ Column {
PropertyLabel {
text: qsTr("Move duration")
- tooltip: qsTr("Move animation duration of the highlight delegate.")
+ tooltip: qsTr("Sets the animation duration of the highlight delegate.")
}
SectionLayout {
@@ -199,7 +210,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred begin")
- tooltip: qsTr("Preferred highlight begin - must be smaller than Preferred end.")
+ tooltip: qsTr("Sets the preferred highlight beginning. It must be smaller than\n"
+ + "the <b>Preferred end</b>. Note that the user has to add a\n"
+ + "highlight component.")
}
SectionLayout {
@@ -217,7 +230,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred end")
- tooltip: qsTr("Preferred highlight end - must be larger than Preferred begin.")
+ tooltip: qsTr("Sets the preferred highlight end. It must be larger than\n"
+ + "the <b>Preferred begin</b>. Note that the user has to add\n"
+ + "a highlight component.")
}
SectionLayout {
@@ -235,7 +250,7 @@ Column {
PropertyLabel {
text: qsTr("Follows current")
- tooltip: qsTr("Whether the highlight is managed by the view.")
+ tooltip: qsTr("Toggles if the view manages the highlight.")
}
SectionLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml
index 95f0560f40..943b35aeed 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml
@@ -54,7 +54,10 @@ PropertyEditorPane {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Opacity") }
+ PropertyLabel {
+ text: qsTr("Opacity")
+ tooltip: qsTr("Sets the transparency of the component.")
+ }
SecondColumnLayout {
SpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LayerSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LayerSection.qml
index e340ea9283..bfb2f51a3b 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LayerSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LayerSection.qml
@@ -15,7 +15,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Enabled")
- tooltip: qsTr("Whether the component is layered or not.")
+ tooltip: qsTr("Toggles if the component is layered.")
}
SecondColumnLayout {
@@ -31,7 +31,7 @@ Section {
PropertyLabel {
text: qsTr("Sampler name")
- tooltip: qsTr("Name of the effect's source texture property.")
+ tooltip: qsTr("Sets the name of the effect's source texture property.")
}
SecondColumnLayout {
@@ -49,7 +49,7 @@ Section {
PropertyLabel {
text: qsTr("Samples")
- tooltip: qsTr("Allows requesting multisampled rendering in the layer.")
+ tooltip: qsTr("Sets the number of multisample renderings in the layer.")
}
SecondColumnLayout {
@@ -91,7 +91,7 @@ Section {
PropertyLabel {
text: qsTr("Effect")
- tooltip: qsTr("Applies the effect to this layer.")
+ tooltip: qsTr("Sets which effect is applied.")
}
SecondColumnLayout {
@@ -100,7 +100,6 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
typeFilter: "QtQuick.Item"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.layer_effect
}
@@ -109,7 +108,7 @@ Section {
PropertyLabel {
text: qsTr("Format")
- tooltip: qsTr("Internal OpenGL format of the texture.")
+ tooltip: qsTr("Sets the internal OpenGL format for the texture.")
}
SecondColumnLayout {
@@ -127,7 +126,7 @@ Section {
PropertyLabel {
text: qsTr("Texture size")
- tooltip: qsTr("Requested pixel size of the layer's texture.")
+ tooltip: qsTr("Sets the requested pixel size of the layer's texture.")
}
SecondColumnLayout {
@@ -145,6 +144,7 @@ Section {
ControlLabel {
//: The width of the object
text: qsTr("W", "width")
+ tooltip: qsTr("Width.")
}
Spacer { implicitWidth: StudioTheme.Values.controlGap }
@@ -163,6 +163,7 @@ Section {
ControlLabel {
//: The height of the object
text: qsTr("H", "height")
+ tooltip: qsTr("Height.")
}
ExpandingSpacer {}
@@ -188,7 +189,7 @@ Section {
PropertyLabel {
text: qsTr("Wrap mode")
- tooltip: qsTr("OpenGL wrap modes associated with the texture.")
+ tooltip: qsTr("Sets the OpenGL wrap modes associated with the texture.")
}
SecondColumnLayout {
@@ -206,7 +207,7 @@ Section {
PropertyLabel {
text: qsTr("Mipmap")
- tooltip: qsTr("Generates mipmaps for the texture.")
+ tooltip: qsTr("Toggles if mipmaps are generated for the texture.")
}
SecondColumnLayout {
@@ -222,7 +223,7 @@ Section {
PropertyLabel {
text: qsTr("Smooth")
- tooltip: qsTr("Transforms the layer smoothly.")
+ tooltip: qsTr("Toggles if the layer transforms smoothly.")
}
SecondColumnLayout {
@@ -238,7 +239,8 @@ Section {
PropertyLabel {
text: qsTr("Source rectangle")
- tooltip: qsTr("Sets the rectangular area of the component that should be rendered into the texture.")
+ tooltip: qsTr("Sets the rectangular area of the component that should\n"
+ + "be rendered into the texture.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ListViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ListViewSpecifics.qml
index f4c6e62c3f..ec86f2f606 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ListViewSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ListViewSpecifics.qml
@@ -21,7 +21,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Orientation")
- tooltip: qsTr("Orientation of the list.")
+ tooltip: qsTr("Sets the orientation of the list.")
}
SecondColumnLayout {
@@ -39,6 +39,7 @@ Column {
PropertyLabel {
text: qsTr("Layout direction")
+ tooltip: qsTr("Sets the direction that the cells flow inside a list.")
blockedByTemplate: !backendValues.layoutDirection.isAvailable
}
@@ -58,7 +59,7 @@ Column {
PropertyLabel {
text: qsTr("Snap mode")
- tooltip: qsTr("Determines how the view scrolling will settle following a drag or flick.")
+ tooltip: qsTr("Sets how the view scrolling settles following a drag or flick.")
blockedByTemplate: !backendValues.snapMode.isAvailable
}
@@ -78,7 +79,7 @@ Column {
PropertyLabel {
text: qsTr("Spacing")
- tooltip: qsTr("Spacing between components.")
+ tooltip: qsTr("Sets the spacing between components.")
}
SecondColumnLayout {
@@ -96,7 +97,7 @@ Column {
PropertyLabel {
text: qsTr("Cache")
- tooltip: qsTr("Cache buffer.")
+ tooltip: qsTr("Sets in pixels how far the components are kept loaded outside the view's visible area.")
blockedByTemplate: !backendValues.cacheBuffer.isAvailable
}
@@ -116,7 +117,7 @@ Column {
PropertyLabel {
text: qsTr("Navigation wraps")
- tooltip: qsTr("Whether the grid wraps key navigation.")
+ tooltip: qsTr("Toggles if the grid wraps key navigation.")
blockedByTemplate: !backendValues.keyNavigationWraps.isAvailable
}
@@ -143,7 +144,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Range")
- tooltip: qsTr("Highlight range.")
+ tooltip: qsTr("Sets the highlight range mode.")
blockedByTemplate: !backendValues.highlightRangeMode.isAvailable
}
@@ -163,7 +164,8 @@ Column {
PropertyLabel {
text: qsTr("Move duration")
- tooltip: qsTr("Move animation duration of the highlight delegate.")
+ tooltip: qsTr("Sets the animation duration of the highlight delegate when\n"
+ + "it is moved.")
blockedByTemplate: !backendValues.highlightMoveDuration.isAvailable
}
@@ -183,7 +185,8 @@ Column {
PropertyLabel {
text: qsTr("Move velocity")
- tooltip: qsTr("Move animation velocity of the highlight delegate.")
+ tooltip: qsTr("Sets the animation velocity of the highlight delegate when\n"
+ + "it is moved.")
blockedByTemplate: !backendValues.highlightMoveVelocity.isAvailable
}
@@ -203,7 +206,8 @@ Column {
PropertyLabel {
text: qsTr("Resize duration")
- tooltip: qsTr("Resize animation duration of the highlight delegate.")
+ tooltip: qsTr("Sets the animation duration of the highlight delegate when\n"
+ + "it is resized.")
blockedByTemplate: !backendValues.highlightResizeDuration.isAvailable
}
@@ -223,7 +227,8 @@ Column {
PropertyLabel {
text: qsTr("Resize velocity")
- tooltip: qsTr("Resize animation velocity of the highlight delegate.")
+ tooltip: qsTr("Sets the animation velocity of the highlight delegate when\n"
+ + "it is resized.")
blockedByTemplate: !backendValues.highlightResizeVelocity.isAvailable
}
@@ -243,7 +248,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred begin")
- tooltip: qsTr("Preferred highlight begin - must be smaller than Preferred end.")
+ tooltip: qsTr("Sets the preferred highlight beginning. It must be smaller than\n"
+ + "the <b>Preferred end</b>. Note that the user has to add\n"
+ + "a highlight component.")
blockedByTemplate: !backendValues.preferredHighlightBegin.isAvailable
}
@@ -263,7 +270,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred end")
- tooltip: qsTr("Preferred highlight end - must be larger than Preferred begin.")
+ tooltip: qsTr("Sets the preferred highlight end. It must be larger than\n"
+ + "the <b>Preferred begin</b>. Note that the user has to add\n"
+ + "a highlight component.")
blockedByTemplate: !backendValues.preferredHighlightEnd.isAvailable
}
@@ -283,7 +292,7 @@ Column {
PropertyLabel {
text: qsTr("Follows current")
- tooltip: qsTr("Whether the highlight is managed by the view.")
+ tooltip: qsTr("Toggles if the view manages the highlight.")
blockedByTemplate: !backendValues.highlightFollowsCurrentItem.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LoaderSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LoaderSpecifics.qml
index 2d847e0e50..4d61ee3f35 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LoaderSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/LoaderSpecifics.qml
@@ -55,7 +55,6 @@ Column {
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "Component"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.sourceComponent
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
index 176ed009df..ecb82f807e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/MouseAreaSpecifics.qml
@@ -20,7 +20,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Enable")
- tooltip: qsTr("Accepts mouse events.")
+ tooltip: qsTr("Sets how the mouse can interact with the area.")
blockedByTemplate: !backendValues.enabled.isAvailable
}
@@ -48,7 +48,7 @@ Column {
PropertyLabel {
text: qsTr("Accepted buttons")
- tooltip: qsTr("Mouse buttons that the mouse area reacts to.")
+ tooltip: qsTr("Sets which mouse buttons the area reacts to.")
blockedByTemplate: !backendValues.acceptedButtons.isAvailable
}
@@ -68,7 +68,7 @@ Column {
PropertyLabel {
text: qsTr("Cursor shape")
- tooltip: qsTr("Cursor shape for this mouse area.")
+ tooltip: qsTr("Sets which mouse cursor to display on this area.")
blockedByTemplate: !backendValues.cursorShape.isAvailable
}
@@ -93,7 +93,7 @@ Column {
PropertyLabel {
text: qsTr("Hold interval")
- tooltip: qsTr("Overrides the elapsed time in milliseconds before pressAndHold signal is emitted.")
+ tooltip: qsTr("Sets the time before the pressAndHold signal is registered when you press the area.")
}
SecondColumnLayout {
@@ -111,7 +111,7 @@ Column {
PropertyLabel {
text: qsTr("Scroll gesture")
- tooltip: qsTr("Responds to scroll gestures from non-mouse devices.")
+ tooltip: qsTr("Toggles if scroll gestures from non-mouse devices are supported.")
blockedByTemplate: !backendValues.scrollGestureEnabled.isAvailable
}
@@ -129,7 +129,7 @@ Column {
PropertyLabel {
text: qsTr("Prevent stealing")
- tooltip: qsTr("Stops mouse events from being stolen from this mouse area.")
+ tooltip: qsTr("Toggles if mouse events can be stolen from this area.")
blockedByTemplate: !backendValues.preventStealing.isAvailable
}
@@ -147,7 +147,7 @@ Column {
PropertyLabel {
text: qsTr("Propagate events")
- tooltip: qsTr("Automatically propagates composed mouse events to other mouse areas.")
+ tooltip: qsTr("Toggles if composed mouse events should be propagated to other mouse areas overlapping this area.")
blockedByTemplate: !backendValues.propagateComposedEvents.isAvailable
}
@@ -175,13 +175,12 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Target")
- tooltip: qsTr("ID of the component to drag.")
+ tooltip: qsTr("Sets the component to have drag functionalities.")
}
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "QtQuick.QtObject"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.drag_target
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
@@ -192,7 +191,7 @@ Column {
PropertyLabel {
text: qsTr("Axis")
- tooltip: qsTr("Whether dragging can be done horizontally, vertically, or both.")
+ tooltip: qsTr("Sets in which directions the dragging work.")
}
SecondColumnLayout {
@@ -210,7 +209,7 @@ Column {
PropertyLabel {
text: qsTr("Threshold")
- tooltip: qsTr("Threshold in pixels of when the drag operation should start.")
+ tooltip: qsTr("Sets a threshold after which the drag starts to work.")
}
SecondColumnLayout {
@@ -228,7 +227,7 @@ Column {
PropertyLabel {
text: qsTr("Filter children")
- tooltip: qsTr("Whether dragging overrides descendant mouse areas.")
+ tooltip: qsTr("Toggles if the dragging overrides descendant mouse areas.")
}
SecondColumnLayout {
@@ -244,8 +243,7 @@ Column {
PropertyLabel {
text: qsTr("Smoothed")
- tooltip: qsTr("Moves targets only after the drag operation has started.\n"
- + "When disabled, moves targets straight to the current mouse position.")
+ tooltip: qsTr("Toggles if the move is smoothly animated.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/PathViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/PathViewSpecifics.qml
index 2f80266697..d2eae62c5b 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/PathViewSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/PathViewSpecifics.qml
@@ -20,7 +20,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Interactive")
- tooltip: qsTr("Allows users to drag or flick a path view.")
+ tooltip: qsTr("Toggles if the path view allows drag or flick.")
}
SecondColumnLayout {
@@ -34,7 +34,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Drag margin") }
+ PropertyLabel {
+ text: qsTr("Drag margin")
+ tooltip: qsTr("Sets a margin within which the drag function also works even without clicking the item itself.")
+ }
SecondColumnLayout {
SpinBox {
@@ -49,7 +52,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Flick deceleration") }
+ PropertyLabel {
+ text: qsTr("Flick deceleration")
+ tooltip: qsTr("Sets the rate by which a flick action slows down after performing.")
+ }
SecondColumnLayout {
SpinBox {
@@ -66,7 +72,7 @@ Column {
PropertyLabel {
text: qsTr("Offset")
- tooltip: qsTr("Specifies how far along the path the items are from their initial positions. This is a real number that ranges from 0.0 to the count of items in the model.")
+ tooltip: qsTr("Sets how far along the path the items are from their initial position.")
}
SecondColumnLayout {
@@ -84,7 +90,7 @@ Column {
PropertyLabel {
text: qsTr("Item count")
- tooltip: qsTr("Number of items visible on the path at any one time.")
+ tooltip: qsTr("Sets the number of items visible at once along the path.")
}
SecondColumnLayout {
@@ -111,7 +117,7 @@ Column {
SectionLayout {
PropertyLabel {
text: qsTr("Range")
- tooltip: qsTr("Highlight range")
+ tooltip: qsTr("Sets the highlight range mode.")
}
SecondColumnLayout {
@@ -129,7 +135,8 @@ Column {
PropertyLabel {
text: qsTr("Move duration")
- tooltip: qsTr("Move animation duration of the highlight delegate.")
+ tooltip: qsTr("Sets the animation duration of the highlight delegate when\n"
+ + "it is moved.")
}
SecondColumnLayout {
@@ -147,7 +154,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred begin")
- tooltip: qsTr("Preferred highlight begin - must be smaller than Preferred end. Note that the user has to add a highlight component.")
+ tooltip: qsTr("Sets the preferred highlight beginning. It must be smaller than\n"
+ + "the <b>Preferred end</b>. Note that the user has to add\n"
+ + "a highlight component.")
}
SecondColumnLayout {
@@ -166,7 +175,9 @@ Column {
PropertyLabel {
text: qsTr("Preferred end")
- tooltip: qsTr("Preferred highlight end - must be larger than Preferred begin. Note that the user has to add a highlight component.")
+ tooltip: qsTr("Sets the preferred highlight end. It must be larger than\n"
+ + "the <b>Preferred begin</b>. Note that the user has to add\n"
+ + "a highlight component.")
}
SecondColumnLayout {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml
index 1f5189e6a5..cdcea69e06 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml
@@ -16,7 +16,10 @@ Column {
caption: qsTr("Rectangle")
SectionLayout {
- PropertyLabel { text: qsTr("Fill color") }
+ PropertyLabel {
+ text: qsTr("Fill color")
+ tooltip: qsTr("Sets the color for the background.")
+ }
ColorEditor {
backendValue: backendValues.color
@@ -25,6 +28,7 @@ Column {
PropertyLabel {
text: qsTr("Border color")
+ tooltip: qsTr("Sets the color for the border.")
visible: backendValues.border_color.isAvailable
}
@@ -36,6 +40,7 @@ Column {
PropertyLabel {
text: qsTr("Border width")
+ tooltip: qsTr("Sets the border width.")
blockedByTemplate: !backendValues.border_width.isAvailable
}
@@ -51,7 +56,10 @@ Column {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Radius") }
+ PropertyLabel {
+ text: qsTr("Radius")
+ tooltip: qsTr("Sets the radius by which the corners get rounded.")
+ }
SecondColumnLayout {
SpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RepeaterSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RepeaterSpecifics.qml
index 363a70b470..a70beeb224 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RepeaterSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RepeaterSpecifics.qml
@@ -42,7 +42,6 @@ Column {
SecondColumnLayout {
ItemFilterComboBox {
typeFilter: "Component"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: backendValues.delegate
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RowSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RowSpecifics.qml
index 388a3c0dc8..ae03cb0512 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RowSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RowSpecifics.qml
@@ -18,7 +18,10 @@ Column {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Spacing") }
+ PropertyLabel {
+ text: qsTr("Spacing")
+ tooltip: qsTr("Sets the spacing between items in the row.")
+ }
SecondColumnLayout {
SpinBox {
@@ -35,6 +38,7 @@ Column {
PropertyLabel {
text: qsTr("Layout direction")
+ tooltip: qsTr("Sets in which direction items in the row are placed.")
blockedByTemplate: !backendValues.layoutDirection.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
index cf9d67860a..b76666f7bc 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
@@ -15,21 +15,30 @@ Section {
property bool isTextInput: false
SectionLayout {
- PropertyLabel { text: qsTr("Selection color") }
+ PropertyLabel {
+ text: qsTr("Selection color")
+ tooltip: qsTr("Sets the background color of selected text.")
+ }
ColorEditor {
backendValue: backendValues.selectionColor
supportGradient: false
}
- PropertyLabel { text: qsTr("Selected text color") }
+ PropertyLabel {
+ text: qsTr("Selected text color")
+ tooltip: qsTr("Sets the color of selected text.")
+ }
ColorEditor {
backendValue: backendValues.selectedTextColor
supportGradient: false
}
- PropertyLabel { text: qsTr("Selection mode") }
+ PropertyLabel {
+ text: qsTr("Selection mode")
+ tooltip: qsTr("Sets the way text is selected with the mouse.")
+ }
SecondColumnLayout {
ComboBox {
@@ -47,6 +56,7 @@ Section {
PropertyLabel {
visible: textInputSection.isTextInput
text: qsTr("Input mask")
+ tooltip: qsTr("Sets the allowed characters.")
}
SecondColumnLayout {
@@ -66,6 +76,7 @@ Section {
PropertyLabel {
visible: textInputSection.isTextInput
text: qsTr("Echo mode")
+ tooltip: qsTr("Sets the visibility mode.")
}
SecondColumnLayout {
@@ -86,7 +97,7 @@ Section {
PropertyLabel {
visible: textInputSection.isTextInput
text: qsTr("Password character")
- tooltip: qsTr("Character displayed when users enter passwords.")
+ tooltip: qsTr("Sets which character to display when passwords are entered.")
}
SecondColumnLayout {
@@ -154,7 +165,7 @@ Section {
PropertyLabel {
visible: textInputSection.isTextInput
text: qsTr("Maximum length")
- tooltip: qsTr("Maximum permitted length of the text in the Text Input.")
+ tooltip: qsTr("Sets the maximum length of the text.")
}
SecondColumnLayout {
@@ -183,21 +194,31 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Read only") }
+ PropertyLabel {
+ text: qsTr("Read only")
+ tooltip: qsTr("Toggles if the text allows edits.")
+ }
FlagItem { backendValue: backendValues.readOnly }
- PropertyLabel { text: qsTr("Cursor visible") }
+ PropertyLabel {
+ text: qsTr("Cursor visible")
+ tooltip: qsTr("Toggles if the cursor is visible.")
+ }
FlagItem { backendValue: backendValues.cursorVisible }
- PropertyLabel { text: qsTr("Focus on press") }
+ PropertyLabel {
+ text: qsTr("Focus on press")
+ tooltip: qsTr("Toggles if the text is focused on mouse click.")
+ }
FlagItem { backendValue: backendValues.activeFocusOnPress }
PropertyLabel {
visible: textInputSection.isTextInput
text: qsTr("Auto scroll")
+ tooltip: qsTr("Toggles if the text scrolls when it exceeds its boundary.")
}
FlagItem {
@@ -205,15 +226,24 @@ Section {
backendValue: backendValues.autoScroll
}
- PropertyLabel { text: qsTr("Overwrite mode") }
+ PropertyLabel {
+ text: qsTr("Overwrite mode")
+ tooltip: qsTr("Toggles if overwriting text is allowed.")
+ }
FlagItem { backendValue: backendValues.overwriteMode }
- PropertyLabel { text: qsTr("Persistent selection") }
+ PropertyLabel {
+ text: qsTr("Persistent selection")
+ tooltip: qsTr("Toggles if the text should remain selected after moving the focus elsewhere.")
+ }
FlagItem { backendValue: backendValues.persistentSelection }
- PropertyLabel { text: qsTr("Select by mouse") }
+ PropertyLabel {
+ text: qsTr("Select by mouse")
+ tooltip: qsTr("Toggles if the text can be selected with the mouse.")
+ }
FlagItem { backendValue: backendValues.selectByMouse }
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSection.qml
new file mode 100644
index 0000000000..ceb4179360
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSection.qml
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Section {
+ caption: qsTr("Baked Lightmap")
+ width: parent.width
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Enabled")
+ tooltip: qsTr("When false, the lightmap generated for the model is not stored during lightmap baking,\neven if the key is set to a non-empty value.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.enabled.valueToString
+ backendValue: backendValues.enabled
+ implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Key")
+ tooltip: qsTr("Sets the filename base for baked lightmap files for the model.\nNo other Model in the scene can use the same key.")
+ }
+
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.key
+ showTranslateCheckBox: false
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ width: implicitWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Load Prefix")
+ tooltip: qsTr("Sets the folder where baked lightmap files are generated.\nIt should be a relative path.")
+ }
+
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.loadPrefix
+ showTranslateCheckBox: false
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ width: implicitWidth
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSpecifics.qml
new file mode 100644
index 0000000000..cca06c421a
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/BakedLightmapSpecifics.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ BakedLightmapSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSection.qml
new file mode 100644
index 0000000000..30a69e23b4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSection.qml
@@ -0,0 +1,83 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Section {
+ caption: qsTr("Ambient Sound")
+ width: parent.width
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Source")
+ tooltip: qsTr("The source file for the sound to be played.")
+ }
+
+ SecondColumnLayout {
+ UrlChooser {
+ id: sourceUrlChooser
+ backendValue: backendValues.source
+ filter: "*.wav *.mp3"
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Volume")
+ tooltip: qsTr("Set the overall volume for this sound source.\nValues between 0 and 1 will attenuate the sound, while values above 1 provide an additional gain boost.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.volume
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Loops")
+ tooltip: qsTr("Sets how often the sound is played before the player stops.\nBind to AmbientSound.Infinite to loop the current sound forever.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 1
+ maximumValue: 999999
+ decimals: 0
+ stepSize: 1
+ backendValue: backendValues.loops
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Auto Play")
+ tooltip: qsTr("Sets whether the sound should automatically start playing when a source gets specified.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.autoPlay.valueToString
+ backendValue: backendValues.autoPlay
+ implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSpecifics.qml
new file mode 100644
index 0000000000..8b3946ab87
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AmbientSoundSpecifics.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ AmbientSoundSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSection.qml
new file mode 100644
index 0000000000..88b50c7872
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSection.qml
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Section {
+ caption: qsTr("Audio Engine")
+ width: parent.width
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Master Volume")
+ tooltip: qsTr("Sets or returns overall volume being used to render the sound field.\nValues between 0 and 1 will attenuate the sound, while values above 1 provide an additional gain boost.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.masterVolume
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Output Mode")
+ tooltip: qsTr("Sets the current output mode of the engine.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioEngine"
+ model: ["Surround", "Stereo", "Headphone"]
+ backendValue: backendValues.outputMode
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Output Device")
+ tooltip: qsTr("Sets the device that is being used for outputting the sound field.")
+ }
+
+ SecondColumnLayout {
+ ItemFilterComboBox {
+ typeFilter: "QtMultimedia.AudioDevice"
+ backendValue: backendValues.outputDevice
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSpecifics.qml
new file mode 100644
index 0000000000..b3764868d3
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioEngineSpecifics.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ AudioEngineSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioListenerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioListenerSpecifics.qml
new file mode 100644
index 0000000000..9be94856de
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioListenerSpecifics.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ // AudioListener doesn't have any properties itself, just ones inherited from Node
+
+ NodeSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSection.qml
new file mode 100644
index 0000000000..bfe814211f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSection.qml
@@ -0,0 +1,277 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Section {
+ id: root
+ caption: qsTr("Audio Room")
+ width: parent.width
+
+ property var materialModel: [
+ "Transparent", "AcousticCeilingTiles", "BrickBare", "BrickPainted",
+ "ConcreteBlockCoarse", "ConcreteBlockPainted", "CurtainHeavy",
+ "FiberGlassInsulation", "GlassThin", "GlassThick", "Grass",
+ "LinoleumOnConcrete", "Marble", "Metal", "ParquetOnConcrete",
+ "PlasterRough", "PlasterSmooth", "PlywoodPanel", "PolishedConcreteOrTile",
+ "Sheetrock", "WaterOrIceSurface", "WoodCeiling", "WoodPanel", "Uniform"
+ ]
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Dimensions")
+ tooltip: qsTr("Sets the dimensions of the room in 3D space.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.dimensions_x
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "X"
+ color: StudioTheme.Values.theme3DAxisXColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.dimensions_y
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Y"
+ color: StudioTheme.Values.theme3DAxisYColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.dimensions_z
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Z"
+ color: StudioTheme.Values.theme3DAxisZColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Reflection Gain")
+ tooltip: qsTr("Sets the gain factor for reflections generated in this room.\nA value from 0 to 1 will dampen reflections, while a value larger than 1 will apply a gain to reflections, making them louder.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.reflectionGain
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Reverb Gain")
+ tooltip: qsTr("Sets the gain factor for reverb generated in this room.\nA value from 0 to 1 will dampen reverb, while a value larger than 1 will apply a gain to the reverb, making it louder.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.reverbGain
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Reverb Time")
+ tooltip: qsTr("Sets the factor to be applies to all reverb timings generated for this room.\nLarger values will lead to longer reverb timings, making the room sound larger.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.reverbTime
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Reverb Brightness")
+ tooltip: qsTr("Sets the brightness factor to be applied to the generated reverb.\nA positive value will increase reverb for higher frequencies and dampen lower frequencies, a negative value does the reverse.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -999999
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.reverbBrightness
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Left Material")
+ tooltip: qsTr("Sets the material to use for the left (negative x) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.leftMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Right Material")
+ tooltip: qsTr("Sets the material to use for the right (positive x) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.rightMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Floor Material")
+ tooltip: qsTr("Sets the material to use for the floor (negative y) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.floorMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Ceiling Material")
+ tooltip: qsTr("Sets the material to use for the ceiling (positive y) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.ceilingMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Back Material")
+ tooltip: qsTr("Sets the material to use for the back (negative z) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.backMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Front Material")
+ tooltip: qsTr("Sets the material to use for the front (positive z) side of the room.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "AudioRoom"
+ model: root.materialModel
+ backendValue: backendValues.frontMaterial
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSpecifics.qml
new file mode 100644
index 0000000000..6f8afd7e5d
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/AudioRoomSpecifics.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ AudioRoomSection {
+ width: parent.width
+ }
+
+ NodeSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/NodeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/NodeSection.qml
new file mode 100644
index 0000000000..b48b8e24f4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/NodeSection.qml
@@ -0,0 +1,350 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("Visibility")
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Visibility")
+ tooltip: qsTr("Sets the local visibility of the node.")
+ }
+
+ SecondColumnLayout {
+ // ### should be a slider
+ CheckBox {
+ text: qsTr("Visible")
+ backendValue: backendValues.visible
+ implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Opacity")
+ tooltip: qsTr("Sets the local opacity value of the node.")
+ }
+
+ SecondColumnLayout {
+ // ### should be a slider
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 1
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.opacity
+ sliderIndicatorVisible: true
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+ }
+
+ Section {
+ id: transformSection
+ width: parent.width
+ caption: qsTr("Transform")
+
+ ColumnLayout {
+ spacing: StudioTheme.Values.transform3DSectionSpacing
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Translation")
+ tooltip: qsTr("Sets the translation of the node.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.x
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "X"
+ color: StudioTheme.Values.theme3DAxisXColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.y
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Y"
+ color: StudioTheme.Values.theme3DAxisYColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.z
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Z"
+ color: StudioTheme.Values.theme3DAxisZColor
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Rotation")
+ tooltip: qsTr("Sets the rotation of the node in degrees.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.eulerRotation_x
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "X"
+ color: StudioTheme.Values.theme3DAxisXColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.eulerRotation_y
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Y"
+ color: StudioTheme.Values.theme3DAxisYColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.eulerRotation_z
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Z"
+ color: StudioTheme.Values.theme3DAxisZColor
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Scale")
+ tooltip: qsTr("Sets the scale of the node.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.scale_x
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "X"
+ color: StudioTheme.Values.theme3DAxisXColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.scale_y
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Y"
+ color: StudioTheme.Values.theme3DAxisYColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.scale_z
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Z"
+ color: StudioTheme.Values.theme3DAxisZColor
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Pivot")
+ tooltip: qsTr("Sets the pivot of the node.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.pivot_x
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "X"
+ color: StudioTheme.Values.theme3DAxisXColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.pivot_y
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Y"
+ color: StudioTheme.Values.theme3DAxisYColor
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {}
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: -9999999
+ maximumValue: 9999999
+ decimals: 2
+ backendValue: backendValues.pivot_z
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
+
+ ControlLabel {
+ text: "Z"
+ color: StudioTheme.Values.theme3DAxisZColor
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSection.qml
new file mode 100644
index 0000000000..9d753700df
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSection.qml
@@ -0,0 +1,234 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+
+Section {
+ caption: qsTr("Spatial Sound")
+ width: parent.width
+
+ SectionLayout {
+ PropertyLabel {
+ text: qsTr("Source")
+ tooltip: qsTr("The source file for the sound to be played.")
+ }
+
+ SecondColumnLayout {
+ UrlChooser {
+ id: sourceUrlChooser
+ backendValue: backendValues.source
+ filter: "*.wav *.mp3"
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Volume")
+ tooltip: qsTr("Set the overall volume for this sound source.\nValues between 0 and 1 will attenuate the sound, while values above 1 provide an additional gain boost.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.volume
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Loops")
+ tooltip: qsTr("Sets how often the sound is played before the player stops.\nBind to SpatialSound.Infinite to loop the current sound forever.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 1
+ maximumValue: 999999
+ decimals: 0
+ stepSize: 1
+ backendValue: backendValues.loops
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Auto Play")
+ tooltip: qsTr("Sets whether the sound should automatically start playing when a source gets specified.")
+ }
+
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.autoPlay.valueToString
+ backendValue: backendValues.autoPlay
+ implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Distance Model")
+ tooltip: qsTr("Sets thow the volume of the sound scales with distance to the listener.")
+ }
+
+ SecondColumnLayout {
+ ComboBox {
+ scope: "SpatialSound"
+ model: ["Logarithmic", "Linear", "ManualAttenuation"]
+ backendValue: backendValues.distanceModel
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+
+ }
+
+ PropertyLabel {
+ text: qsTr("Size")
+ tooltip: qsTr("Set the size of the sound source.\nIf the listener is closer to the sound object than the size, volume will stay constant.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 1
+ backendValue: backendValues.size
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Distance Cutoff")
+ tooltip: qsTr("Set the distance beyond which sound coming from the source will cutoff.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 1
+ backendValue: backendValues.distanceCutoff
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Manual Attenuation")
+ tooltip: qsTr("Set the manual attenuation factor if distanceModel is set to ManualAttenuation.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.manualAttenuation
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Occlusion Intensity")
+ tooltip: qsTr("Set how much the object is occluded.\n0 implies the object is not occluded at all, while a large number implies a large occlusion.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.occlusionIntensity
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Directivity")
+ tooltip: qsTr("Set the directivity of the sound source.\nA value of 0 implies that the sound is emitted equally in all directions, while a value of 1 implies that the source mainly emits sound in the forward direction.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 1
+ decimals: 2
+ stepSize: 0.01
+ backendValue: backendValues.directivity
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Directivity Order")
+ tooltip: qsTr("Set the order of the directivity of the sound source.\nA higher order implies a sharper localization of the sound cone.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 1
+ maximumValue: 999999
+ decimals: 2
+ stepSize: 1
+ backendValue: backendValues.directivityOrder
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: qsTr("Near Field Gain")
+ tooltip: qsTr("Set the near field gain for the sound source.\nA near field gain of 1 will raise the volume of the sound signal by approx 20 dB for distances very close to the listener.")
+ }
+
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 1
+ decimals: 2
+ stepSize: 0.01
+ backendValue: backendValues.nearFieldGain
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ }
+
+ ExpandingSpacer {}
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSpecifics.qml
new file mode 100644
index 0000000000..1699b3b66e
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/SpatialAudio/SpatialSoundSpecifics.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import HelperWidgets 2.0
+
+Column {
+ width: parent.width
+
+ SpatialSoundSection {
+ width: parent.width
+ }
+
+ NodeSection {
+ width: parent.width
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml
index 5c71f5a765..85ce6f57e8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml
@@ -38,7 +38,10 @@ Section {
onPixelSizeChanged: sizeWidget.setPointPixelSize()
SectionLayout {
- PropertyLabel { text: qsTr("Text") }
+ PropertyLabel {
+ text: qsTr("Text")
+ tooltip: qsTr("Sets the text to display.")
+ }
SecondColumnLayout {
LineEdit {
@@ -103,7 +106,10 @@ Section {
}
}
- PropertyLabel { text: qsTr("Font") }
+ PropertyLabel {
+ text: qsTr("Font")
+ tooltip: qsTr("Sets the font of the text.")
+ }
SecondColumnLayout {
FontComboBox {
@@ -120,7 +126,7 @@ Section {
PropertyLabel {
text: qsTr("Style name")
- tooltip: qsTr("Font's style.")
+ tooltip: qsTr("Sets the style of the selected font. This is prioritized over <b>Weight</b> and <b>Emphasis</b>.")
enabled: styleNameComboBox.model.length
blockedByTemplate: !styleNameComboBox.backendValue.isAvailable
}
@@ -141,7 +147,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Size") }
+ PropertyLabel {
+ text: qsTr("Size")
+ tooltip: qsTr("Sets the font size in pixels or points.")
+ }
SecondColumnLayout {
id: sizeWidget
@@ -220,7 +229,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Text color") }
+ PropertyLabel {
+ text: qsTr("Text color")
+ tooltip: qsTr("Sets the text color.")
+ }
ColorEditor {
backendValue: backendValues.color
@@ -229,7 +241,7 @@ Section {
PropertyLabel {
text: qsTr("Weight")
- tooltip: qsTr("Font's weight.")
+ tooltip: qsTr("Sets the overall thickness of the font.")
enabled: !styleNameComboBox.styleSet
}
@@ -249,6 +261,7 @@ Section {
PropertyLabel {
text: qsTr("Emphasis")
+ tooltip: qsTr("Sets the text to bold, italic, underlined, or strikethrough.")
enabled: !styleNameComboBox.styleSet
}
@@ -260,7 +273,10 @@ Section {
enabled: !styleNameComboBox.styleSet
}
- PropertyLabel { text: qsTr("Alignment H") }
+ PropertyLabel {
+ text: qsTr("Alignment H")
+ tooltip: qsTr("Sets the horizontal alignment position.")
+ }
SecondColumnLayout {
AlignmentHorizontalButtons {}
@@ -268,7 +284,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Alignment V") }
+ PropertyLabel {
+ text: qsTr("Alignment V")
+ tooltip: qsTr("Sets the vertical alignment position.")
+ }
SecondColumnLayout {
AlignmentVerticalButtons { visible: root.showVerticalAlignment }
@@ -278,7 +297,7 @@ Section {
PropertyLabel {
text: qsTr("Letter spacing")
- tooltip: qsTr("Letter spacing for the font.")
+ tooltip: qsTr("Sets the letter spacing for the text.")
blockedByTemplate: !root.getBackendValue("letterSpacing").isAvailable
}
@@ -299,7 +318,7 @@ Section {
PropertyLabel {
text: qsTr("Word spacing")
- tooltip: qsTr("Word spacing for the font.")
+ tooltip: qsTr("Sets the word spacing for the text.")
blockedByTemplate: !root.getBackendValue("wordSpacing").isAvailable
}
@@ -321,7 +340,7 @@ Section {
PropertyLabel {
visible: root.showLineHeight
text: qsTr("Line height")
- tooltip: qsTr("Line height for the text.")
+ tooltip: qsTr("Sets the line height for the text.")
blockedByTemplate: !lineHeightSpinBox.enabled
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml
index d8520d5cad..96745a2502 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml
@@ -15,18 +15,20 @@ SecondColumnLayout {
property color color
property bool supportGradient: false
property variant backendValue
+
property variant value: {
- if (colorEditor.backendValue === undefined
- || colorEditor.backendValue.value === undefined)
+ if (!colorEditor.backendValue || !colorEditor.backendValue.value)
return "white" // default color for Rectangle
- if (colorEditor.isVector3D)
+ if (colorEditor.isVector3D) {
return Qt.rgba(colorEditor.backendValue.value.x,
colorEditor.backendValue.value.y,
colorEditor.backendValue.value.z, 1)
- else
- return colorEditor.backendValue.value
+ }
+
+ return colorEditor.backendValue.value
}
+
property alias gradientPropertyName: popupLoader.gradientPropertyName
property alias gradientThumbnail: gradientThumbnail
@@ -40,6 +42,8 @@ SecondColumnLayout {
property bool __block: false
+ property string caption // Legacy Qt5 specifics sheets compatibility
+
function resetShapeColor() {
colorEditor.backendValue.resetValue()
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorLogic.qml
index ed3331d296..f72a69ed42 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorLogic.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorLogic.qml
@@ -9,20 +9,11 @@ QtObject {
property variant backendValue
property color textColor: StudioTheme.Values.themeTextColor
- property variant valueFromBackend: root.backendValue === undefined ? 0 : root.backendValue.value
+ property variant valueFromBackend: root.backendValue?.value ?? 0
property bool baseStateFlag: isBaseState
- property bool isInModel: {
- if (root.backendValue !== undefined && root.backendValue.isInModel !== undefined)
- return root.backendValue.isInModel
+ property bool isInModel: root.backendValue?.isInModel ?? false
+ property bool isInSubState: root.backendValue?.isInSubState ?? false
- return false
- }
- property bool isInSubState: {
- if (root.backendValue !== undefined && root.backendValue.isInSubState !== undefined)
- return root.backendValue.isInSubState
-
- return false
- }
property bool highlight: root.textColor === root.__changedTextColor
property bool errorState: false
@@ -38,7 +29,7 @@ QtObject {
onErrorStateChanged: root.evaluate()
function evaluate() {
- if (root.backendValue === undefined)
+ if (!root.backendValue)
return
if (root.errorState) {
@@ -47,15 +38,11 @@ QtObject {
}
if (root.baseStateFlag) {
- if (root.backendValue.isInModel)
- root.textColor = root.__changedTextColor
- else
- root.textColor = root.__defaultTextColor
+ root.textColor = root.backendValue.isInModel ? root.__changedTextColor
+ : root.__defaultTextColor
} else {
- if (root.backendValue.isInSubState)
- root.textColor = StudioTheme.Values.themeChangedStateText
- else
- root.textColor = root.__defaultTextColor
+ root.textColor = root.backendValue.isInSubState ? StudioTheme.Values.themeChangedStateText
+ : root.__defaultTextColor
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
index e91a8f86aa..1820af7958 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
@@ -19,7 +19,7 @@ StudioControls.ComboBox {
onModelChanged: colorLogic.invalidate()
- hasActiveDrag: comboBox.backendValue !== undefined && comboBox.backendValue.hasActiveDrag
+ hasActiveDrag: comboBox.backendValue?.hasActiveDrag ?? false
// This is available in all editors.
@@ -69,7 +69,8 @@ StudioControls.ComboBox {
onExited: comboBox.hasActiveHoverDrag = false
- onDropped: {
+ onDropped: (drag) => {
+ drag.accept()
comboBox.backendValue.commitDrop(dropArea.dropData)
comboBox.hasActiveHoverDrag = false
}
@@ -119,7 +120,7 @@ StudioControls.ComboBox {
break
case ComboBox.ValueType.Enum:
default:
- if (comboBox.backendValue === undefined)
+ if (!comboBox.backendValue)
break
var enumString = comboBox.backendValue.enumeration
@@ -145,11 +146,15 @@ StudioControls.ComboBox {
if (!comboBox.__isCompleted)
return
- let inputValue = comboBox.editText
-
- let index = comboBox.find(inputValue)
- if (index !== -1)
- inputValue = comboBox.textAt(index)
+ let inputText = comboBox.editText
+ let inputValue = inputText;
+ let index = comboBox.find(inputText)
+ if (index !== -1) {
+ let modelIdx = comboBox.model.index(index)
+ inputValue = comboBox.valueRole
+ ? comboBox.model.data(modelIdx, comboBox.valueRole)
+ : comboBox.textAt(index)
+ }
comboBox.backendValue.value = inputValue
@@ -166,6 +171,18 @@ StudioControls.ComboBox {
if (comboBox.manualMapping)
return
+ if (comboBox.valueRole && comboBox.textRole !== comboBox.valueRole) {
+ let inputText = comboBox.currentText
+ let inputValue = comboBox.currentValue
+ let index = comboBox.find(inputText)
+ if (index !== -1) {
+ let modelIdx = comboBox.model.index(index)
+ inputValue = comboBox.model.data(modelIdx, comboBox.valueRole)
+ }
+ comboBox.backendValue.value = inputValue
+ return
+ }
+
switch (comboBox.valueType) {
case ComboBox.ValueType.String:
comboBox.backendValue.value = comboBox.currentText
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
index 8310e3c40d..7b9be3890e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
@@ -9,6 +9,7 @@ QtObject {
property Item mainScrollView
- signal collapseAll()
- signal expandAll()
+ signal collapseAll(string category)
+ signal expandAll(string category)
+ signal closeContextMenu()
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DynamicPropertiesSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DynamicPropertiesSection.qml
index 4e2ef4b044..b3353f2fba 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DynamicPropertiesSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DynamicPropertiesSection.qml
@@ -266,7 +266,6 @@ Section {
ItemFilterComboBox {
typeFilter: "QtQuick3D.TextureInput"
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
backendValue: layoutTextureInput.backendValue
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
index ad62ff4b87..7b0ed94191 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
@@ -7,11 +7,11 @@ import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Item {
- id: editableListView
+ id: root
ExtendedFunctionLogic {
id: extFuncLogic
- backendValue: editableListView.backendValue
+ backendValue: root.backendValue
}
property var backendValue
@@ -23,10 +23,16 @@ Item {
property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth
property real __actionIndicatorHeight: StudioTheme.Values.height
property string typeFilter: "QtQuick3D.Material"
+ property string textRole: "IdAndNameRole"
+ property string valueRole: "IdRole"
property int activatedReason: ComboBox.ActivatedReason.Other
property bool delegateHover: false
+ property string extraButtonIcon: "" // setting this will show an extra button
+ property string extraButtonToolTip: ""
+ signal extraButtonClicked(int idx)
+
signal add(string value)
signal remove(int idx)
signal replace(int idx, string value)
@@ -48,37 +54,50 @@ Item {
validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
actionIndicatorVisible: false
- typeFilter: editableListView.typeFilter
- editText: modelData
+ typeFilter: root.typeFilter
initialModelData: modelData
+ textRole: root.textRole
+ valueRole: root.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: implicitWidth
+ textElidable: true
onFocusChanged: {
if (itemFilterComboBox.focus)
myColumn.currentIndex = index
- if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") {
+ var curValue = itemFilterComboBox.availableValue()
+ if (itemFilterComboBox.empty && curValue !== "") {
myRepeater.dirty = false
- editableListView.add(itemFilterComboBox.editText)
+ root.add(curValue)
}
}
- onCompressedActivated: {
- editableListView.activatedReason = reason
+ onCompressedActivated: function(index, reason) {
+ root.activatedReason = reason
- if (itemFilterComboBox.empty && itemFilterComboBox.editText !== "") {
+ var curValue = itemFilterComboBox.availableValue()
+ if (itemFilterComboBox.empty && curValue) {
myRepeater.dirty = false
- editableListView.add(itemFilterComboBox.editText)
+ root.add(curValue)
} else {
- editableListView.replace(itemFilterComboBox.myIndex, itemFilterComboBox.editText)
+ root.replace(itemFilterComboBox.myIndex, curValue)
}
}
- onHoverChanged: editableListView.delegateHover = itemFilterComboBox.hover
+ onHoverChanged: root.delegateHover = itemFilterComboBox.hover
}
- Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
+ Spacer { implicitWidth: extraButton.visible ? 5 : StudioTheme.Values.twoControlColumnGap }
+
+ IconIndicator {
+ id: extraButton
+ icon: root.extraButtonIcon
+ tooltip: root.extraButtonToolTip
+ onClicked: root.extraButtonClicked(index)
+ visible: root.extraButtonIcon !== ""
+ enabled: root.model[index]
+ }
IconIndicator {
id: closeIndicator
@@ -90,12 +109,12 @@ Item {
myRepeater.dirty = false
myRepeater.model = myRepeater.localModel // trigger on change handler
} else {
- editableListView.remove(index)
+ root.remove(index)
}
if (!lastItem)
myColumn.currentIndex = index - 1
}
- onHoveredChanged: editableListView.delegateHover = closeIndicator.hovered
+ onHoveredChanged: root.delegateHover = closeIndicator.hovered
}
}
}
@@ -103,7 +122,7 @@ Item {
Row {
ActionIndicator {
id: actionIndicator
- icon.visible: editableListView.delegateHover
+ icon.visible: root.delegateHover
icon.color: extFuncLogic.color
icon.text: extFuncLogic.glyph
onClicked: extFuncLogic.show()
@@ -141,7 +160,7 @@ Item {
myColumn.currentIndex = -1
myRepeater.localModel = []
- editableListView.model.forEach(function(item) {
+ root.model.forEach(function(item) {
myRepeater.localModel.push(item)
});
@@ -158,7 +177,7 @@ Item {
else
myColumn.currentIndex = myRepeater.localModel.length - 1
- if (editableListView.activatedReason === ComboBox.ActivatedReason.Other
+ if (root.activatedReason === ComboBox.ActivatedReason.Other
&& myColumn.currentItem !== null)
myColumn.currentItem.forceActiveFocus()
}
@@ -169,32 +188,36 @@ Item {
visible: myRepeater.count === 0
validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
actionIndicatorVisible: false
- typeFilter: editableListView.typeFilter
+ typeFilter: root.typeFilter
+ textRole: root.textRole
+ valueRole: root.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth
width: implicitWidth
onFocusChanged: {
- if (dummyComboBox.editText !== "")
- editableListView.add(dummyComboBox.editText)
+ var curValue = dummyComboBox.availableValue()
+ if (curValue !== "")
+ root.add(curValue)
}
onCompressedActivated: {
- editableListView.activatedReason = reason
+ root.activatedReason = reason
- if (dummyComboBox.editText !== "")
- editableListView.add(dummyComboBox.editText)
+ var curValue = dummyComboBox.availableValue()
+ if (curValue !== "")
+ root.add(curValue)
else
- editableListView.replace(dummyComboBox.myIndex, dummyComboBox.editText)
+ root.replace(dummyComboBox.myIndex, curValue)
}
- onHoverChanged: editableListView.delegateHover = dummyComboBox.hover
+ onHoverChanged: root.delegateHover = dummyComboBox.hover
}
StudioControls.AbstractButton {
id: plusButton
buttonIcon: StudioTheme.Constants.plus
- enabled: !myRepeater.dirty && !(editableListView.backendValue.isInModel
- && !editableListView.backendValue.isIdList)
+ enabled: !myRepeater.dirty && !(root.backendValue.isInModel
+ && !root.backendValue.isIdList)
onClicked: {
var idx = myRepeater.localModel.push("") - 1
myRepeater.model = myRepeater.localModel // trigger on change handler
@@ -203,7 +226,7 @@ Item {
myColumn.currentItem.forceActiveFocus()
}
- onHoveredChanged: editableListView.delegateHover = plusButton.hovered
+ onHoveredChanged: root.delegateHover = plusButton.hovered
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
index de230b6825..c82aa2cea5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionLogic.qml
@@ -11,18 +11,8 @@ Item {
id: extendedFunctionButton
property variant backendValue
- property bool isBoundBackend: {
- if (backendValue !== undefined && backendValue.isBound !== undefined)
- return backendValue.isBound
-
- return false
- }
- property string backendExpression: {
- if (backendValue !== undefined && backendValue.expression !== undefined)
- return backendValue.expression
-
- return ""
- }
+ property bool isBoundBackend: backendValue?.isBound ?? false
+ property string backendExpression: backendValue?.expression ?? ""
property string glyph: StudioTheme.Constants.actionIcon
property string color: StudioTheme.Values.themeTextColor
@@ -38,7 +28,7 @@ Item {
function setIcon() {
extendedFunctionButton.color = StudioTheme.Values.themeTextColor
- if (backendValue === undefined) {
+ if (!backendValue) {
extendedFunctionButton.glyph = StudioTheme.Constants.actionIcon
} else if (backendValue.isBound) {
if (backendValue.isTranslated) {
@@ -49,12 +39,8 @@ Item {
extendedFunctionButton.color = StudioTheme.Values.themeInteraction
}
} else {
- if (backendValue.complexNode !== undefined
- && backendValue.complexNode.exists) {
-
- } else {
+ if (!backendValue.complexNode || !backendValue.complexNode.exists)
extendedFunctionButton.glyph = StudioTheme.Constants.actionIcon
- }
}
}
@@ -77,8 +63,8 @@ Item {
id: menu
onAboutToShow: {
- exportMenuItem.checked = backendValue.hasPropertyAlias()
- exportMenuItem.enabled = !backendValue.isAttachedProperty()
+ exportMenuItem.checked = backendValue?.hasPropertyAlias() ?? false
+ exportMenuItem.enabled = !(backendValue?.isAttachedProperty() ?? false)
extendedFunctionButton.menuVisible = true
}
onAboutToHide: extendedFunctionButton.menuVisible = false
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableGeometrySection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableGeometrySection.qml
index 7b0a29900a..991016041a 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableGeometrySection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableGeometrySection.qml
@@ -15,7 +15,10 @@ Section {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Content size") }
+ PropertyLabel {
+ text: qsTr("Content size")
+ tooltip: qsTr("Sets the size of the content (the surface controlled by the flickable).")
+ }
SecondColumnLayout {
SpinBox {
@@ -60,7 +63,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Content") }
+ PropertyLabel {
+ text: qsTr("Content")
+ tooltip: qsTr("Sets the current position of the component.")
+ }
SecondColumnLayout {
SpinBox {
@@ -73,7 +79,10 @@ Section {
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
- ControlLabel { text: "X" }
+ ControlLabel {
+ text: "X"
+ tooltip: qsTr("Horizontal position.")
+ }
Spacer { implicitWidth: StudioTheme.Values.controlGap }
@@ -87,7 +96,10 @@ Section {
Spacer { implicitWidth: StudioTheme.Values.controlLabelGap }
- ControlLabel { text: "Y" }
+ ControlLabel {
+ text: "Y"
+ tooltip: qsTr("Vertical position.")
+ }
/*
TODO QDS-4836
Spacer { implicitWidth: StudioTheme.Values.controlGap }
@@ -99,6 +111,7 @@ Section {
PropertyLabel {
text: qsTr("Origin")
+ tooltip: qsTr("Sets the origin point of the content.")
blockedByTemplate: !backendValues.originX.isAvailable
&& !backendValues.originY.isAvailable
}
@@ -117,6 +130,7 @@ Section {
ControlLabel {
text: "X"
+ tooltip: qsTr("Horizontal position.")
enabled: backendValues.originX.isAvailable
}
@@ -135,6 +149,7 @@ Section {
ControlLabel {
text: "Y"
+ tooltip: qsTr("Vertical position.")
enabled: backendValues.originY.isAvailable
}
/*
@@ -148,6 +163,7 @@ Section {
PropertyLabel {
text: qsTr("Left margin")
+ tooltip: qsTr("Sets an additional left margin in the flickable area.")
blockedByTemplate: !backendValues.leftMargin.isAvailable
}
@@ -167,6 +183,7 @@ Section {
PropertyLabel {
text: qsTr("Right margin")
+ tooltip: qsTr("Sets an additional right margin in the flickable area.")
blockedByTemplate: !backendValues.rightMargin.isAvailable
}
@@ -186,6 +203,7 @@ Section {
PropertyLabel {
text: qsTr("Top margin")
+ tooltip: qsTr("Sets an additional top margin in the flickable area.")
blockedByTemplate: !backendValues.topMargin.isAvailable
}
@@ -205,6 +223,7 @@ Section {
PropertyLabel {
text: qsTr("Bottom margin")
+ tooltip: qsTr("Sets an additional bottom margin in the flickable area.")
blockedByTemplate: !backendValues.bottomMargin.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
index 324658b502..4442cc6088 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FlickableSection.qml
@@ -16,7 +16,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Interactive")
- tooltip: qsTr("Allows users to drag or flick a flickable component.")
+ tooltip: qsTr("Toggles if the flickable supports drag and flick actions.")
}
SecondColumnLayout {
@@ -32,6 +32,7 @@ Section {
PropertyLabel {
text: qsTr("Flick direction")
+ tooltip: qsTr("Sets which directions the view can be flicked.")
blockedByTemplate: !backendValues.flickableDirection.isAvailable
}
@@ -51,7 +52,7 @@ Section {
PropertyLabel {
text: qsTr("Behavior")
- tooltip: qsTr("Whether the surface may be dragged beyond the Flickable's boundaries, or overshoot the Flickable's boundaries when flicked.")
+ tooltip: qsTr("Sets how the flickable behaves when it is dragged beyond its boundaries.")
blockedByTemplate: !backendValues.boundsBehavior.isAvailable
}
@@ -71,7 +72,7 @@ Section {
PropertyLabel {
text: qsTr("Movement")
- tooltip: qsTr("Whether the Flickable will give a feeling that the edges of the view are soft, rather than a hard physical boundary.")
+ tooltip: qsTr("Sets if the edges of the flickable should be soft or hard.")
blockedByTemplate: !backendValues.boundsMovement.isAvailable
}
@@ -91,7 +92,7 @@ Section {
PropertyLabel {
text: qsTr("Max. velocity")
- tooltip: qsTr("Maximum flick velocity")
+ tooltip: qsTr("Sets how fast an item can be flicked.")
}
SecondColumnLayout {
@@ -109,7 +110,7 @@ Section {
PropertyLabel {
text: qsTr("Deceleration")
- tooltip: qsTr("Flick deceleration")
+ tooltip: qsTr("Sets the rate by which a flick should slow down.")
blockedByTemplate: !backendValues.flickDeceleration.isAvailable
}
@@ -129,7 +130,7 @@ Section {
PropertyLabel {
text: qsTr("Press delay")
- tooltip: qsTr("Time to delay delivering a press to children of the Flickable in milliseconds.")
+ tooltip: qsTr("Sets the time to delay delivering a press to children of the flickable in milliseconds.")
blockedByTemplate: !backendValues.pressDelay.isAvailable
}
@@ -149,7 +150,7 @@ Section {
PropertyLabel {
text: qsTr("Pixel aligned")
- tooltip: qsTr("Sets the alignment of contentX and contentY to pixels (true) or subpixels (false).")
+ tooltip: qsTr("Toggles if the component is being moved by complete pixel length.")
blockedByTemplate: !backendValues.pixelAligned.isAvailable
}
@@ -167,9 +168,7 @@ Section {
PropertyLabel {
text: qsTr("Synchronous drag")
- tooltip: qsTr("If set to true, then when the mouse or touchpoint moves far enough to begin dragging\n"
- + "the content, the content will jump, such that the content pixel which was under the\n"
- + "cursor or touchpoint when pressed remains under that point.")
+ tooltip: qsTr("Toggles if the content should move instantly or not when the mouse or touchpoint is dragged to a new position.")
blockedByTemplate: !backendValues.synchronousDrag.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml
index 64a5a12071..b13e22d30e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml
@@ -30,7 +30,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Capitalization")
- tooltip: qsTr("Capitalization for the text.")
+ tooltip: qsTr("Sets capitalization rules for the text.")
blockedByTemplate: !getBackendValue("capitalization").isAvailable
}
@@ -51,6 +51,7 @@ Section {
PropertyLabel {
visible: root.showStyle
text: qsTr("Style")
+ tooltip: qsTr("Sets the font style.")
blockedByTemplate: !styleComboBox.enabled
}
@@ -74,6 +75,7 @@ Section {
PropertyLabel {
text: qsTr("Style color")
+ tooltip: qsTr("Sets the color for the font style.")
visible: root.isBackendValueAvailable("styleColor")
}
@@ -85,7 +87,7 @@ Section {
PropertyLabel {
text: qsTr("Hinting")
- tooltip: qsTr("Preferred hinting on the text.")
+ tooltip: qsTr("Sets how to interpolate the text to render it more clearly when scaled.")
blockedByTemplate: !getBackendValue("hintingPreference").isAvailable
}
@@ -105,8 +107,7 @@ Section {
PropertyLabel {
text: qsTr("Auto kerning")
- tooltip: qsTr("Enables or disables the kerning OpenType feature when shaping the text. Disabling this may " +
- "improve performance when creating or changing the text, at the expense of some cosmetic features.")
+ tooltip: qsTr("Resolves the gap between texts if turned true.")
blockedByTemplate: !getBackendValue("kerning").isAvailable
}
@@ -124,9 +125,7 @@ Section {
PropertyLabel {
text: qsTr("Prefer shaping")
- tooltip: qsTr("Sometimes, a font will apply complex rules to a set of characters in order to display them correctly.\n" +
- "In some writing systems, such as Brahmic scripts, this is required in order for the text to be legible, whereas in " +
- "Latin script,\n it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features\nwhen they are not required, which will improve performance in most cases.")
+ tooltip: qsTr("Toggles the font-specific special features.")
blockedByTemplate: !getBackendValue("preferShaping").isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
index 0862f18f8b..f1f7dfc07f 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontSection.qml
@@ -34,7 +34,10 @@ Section {
onPixelSizeChanged: sizeWidget.setPointPixelSize()
SectionLayout {
- PropertyLabel { text: qsTr("Font") }
+ PropertyLabel {
+ text: qsTr("Font")
+ tooltip: qsTr("Sets the font of the text.")
+ }
SecondColumnLayout {
FontComboBox {
@@ -49,7 +52,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Size") }
+ PropertyLabel {
+ text: qsTr("Size")
+ tooltip: qsTr("Sets the font size in pixels or points.")
+ }
SecondColumnLayout {
id: sizeWidget
@@ -129,6 +135,7 @@ Section {
PropertyLabel {
text: qsTr("Emphasis")
+ tooltip: qsTr("Sets the text to bold, italic, underlined, or strikethrough.")
blockedByTemplate: !fontSection.boldStyle.isAvailable
&& !fontSection.italicStyle.isAvailable
&& !fontSection.underlineStyle.isAvailable
@@ -145,7 +152,7 @@ Section {
PropertyLabel {
text: qsTr("Capitalization")
- tooltip: qsTr("Capitalization for the text.")
+ tooltip: qsTr("Sets capitalization rules for the text.")
blockedByTemplate: !getBackendValue("capitalization").isAvailable
}
@@ -165,7 +172,7 @@ Section {
PropertyLabel {
text: qsTr("Weight")
- tooltip: qsTr("Font's weight.")
+ tooltip: qsTr("Sets the overall thickness of the font.")
blockedByTemplate: styleNameComboBox.styleSet
}
@@ -185,7 +192,7 @@ Section {
PropertyLabel {
text: qsTr("Style name")
- tooltip: qsTr("Font's style.")
+ tooltip: qsTr("Sets the style of the selected font. This is prioritized over <b>Weight</b> and <b>Emphasis</b>.")
blockedByTemplate: !styleNameComboBox.enabled
}
@@ -208,6 +215,7 @@ Section {
PropertyLabel {
visible: fontSection.showStyle
text: qsTr("Style")
+ tooltip: qsTr("Sets the font style.")
blockedByTemplate: !styleComboBox.enabled
}
@@ -230,6 +238,7 @@ Section {
PropertyLabel {
text: qsTr("Style color")
+ tooltip: qsTr("Sets the color for the font style.")
visible: fontSection.showStyle && backendValues.styleColor.isAvailable
}
@@ -241,7 +250,7 @@ Section {
PropertyLabel {
text: qsTr("Hinting")
- tooltip: qsTr("Preferred hinting on the text.")
+ tooltip: qsTr("Sets how to interpolate the text to render it more clearly when scaled.")
blockedByTemplate: !getBackendValue("hintingPreference").isAvailable
}
@@ -261,7 +270,7 @@ Section {
PropertyLabel {
text: qsTr("Letter spacing")
- tooltip: qsTr("Letter spacing for the font.")
+ tooltip: qsTr("Sets the letter spacing for the text.")
blockedByTemplate: !getBackendValue("letterSpacing").isAvailable
}
@@ -282,7 +291,7 @@ Section {
PropertyLabel {
text: qsTr("Word spacing")
- tooltip: qsTr("Word spacing for the font.")
+ tooltip: qsTr("Sets the word spacing for the text.")
blockedByTemplate: !getBackendValue("wordSpacing").isAvailable
}
@@ -303,8 +312,7 @@ Section {
PropertyLabel {
text: qsTr("Auto kerning")
- tooltip: qsTr("Enables or disables the kerning OpenType feature when shaping the text. Disabling this may " +
- "improve performance when creating or changing the text, at the expense of some cosmetic features.")
+ tooltip: qsTr("Resolves the gap between texts if turned true.")
blockedByTemplate: !getBackendValue("kerning").isAvailable
}
@@ -322,9 +330,7 @@ Section {
PropertyLabel {
text: qsTr("Prefer shaping")
- tooltip: qsTr("Sometimes, a font will apply complex rules to a set of characters in order to display them correctly.\n" +
- "In some writing systems, such as Brahmic scripts, this is required in order for the text to be legible, whereas in " +
- "Latin script,\n it is merely a cosmetic feature. Setting the preferShaping property to false will disable all such features\nwhen they are not required, which will improve performance in most cases.")
+ tooltip: qsTr("Toggles the disables font-specific special features.")
blockedByTemplate: !getBackendValue("preferShaping").isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml
index 0a0c6e5888..08a560baa2 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/IconButton.qml
@@ -14,13 +14,19 @@ Rectangle {
property alias icon: icon.text
property alias tooltip: toolTip.text
property alias iconSize: icon.font.pixelSize
+ property alias iconScale: icon.scale
+ property alias iconColor: icon.color
+ property alias iconStyle: icon.style
+ property alias iconStyleColor: icon.styleColor
+
property alias containsMouse: mouseArea.containsMouse
property bool enabled: true
+ property bool transparentBg: false
property int buttonSize: StudioTheme.Values.height
- property color normalColor: StudioTheme.Values.themeControlBackground
- property color hoverColor: StudioTheme.Values.themeControlBackgroundHover
- property color pressColor: StudioTheme.Values.themeControlBackgroundInteraction
+ property color normalColor: root.transparentBg ? "transparent" : StudioTheme.Values.themeControlBackground
+ property color hoverColor: root.transparentBg ? "transparent" : StudioTheme.Values.themeControlBackgroundHover
+ property color pressColor: root.transparentBg ? "transparent" : StudioTheme.Values.themeControlBackgroundInteraction
width: buttonSize
height: buttonSize
@@ -32,18 +38,18 @@ Rectangle {
Text {
id: icon
+ anchors.centerIn: root
color: root.enabled ? StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColorDisabled
font.family: StudioTheme.Constants.iconFont.family
font.pixelSize: StudioTheme.Values.baseIconFontSize
- anchors.centerIn: root
}
MouseArea {
id: mouseArea
anchors.fill: parent
- hoverEnabled: true
+ hoverEnabled: root.visible
onClicked: {
// We need to keep mouse area enabled even when button is disabled to make tooltip work
if (root.enabled)
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImageSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImageSection.qml
index 1fbd7a23b6..520a47f0ba 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImageSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ImageSection.qml
@@ -13,7 +13,10 @@ Section {
anchors.right: parent.right
SectionLayout {
- PropertyLabel { text: qsTr("Source") }
+ PropertyLabel {
+ text: qsTr("Source")
+ tooltip: qsTr("Adds an image from the local file system.")
+ }
SecondColumnLayout {
UrlChooser {
@@ -23,7 +26,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Fill mode") }
+ PropertyLabel {
+ text: qsTr("Fill mode")
+ tooltip: qsTr("Sets how the image fits in the content box.")
+ }
SecondColumnLayout {
ComboBox {
@@ -40,6 +46,7 @@ Section {
PropertyLabel {
text: qsTr("Source size")
+ tooltip: qsTr("Sets the width and height of the image.")
blockedByTemplate: !backendValues.sourceSize.isAvailable
}
@@ -59,6 +66,7 @@ Section {
ControlLabel {
//: The width of the object
text: qsTr("W", "width")
+ tooltip: qsTr("Width.")
enabled: backendValues.sourceSize_width.isAvailable
}
@@ -79,6 +87,7 @@ Section {
ControlLabel {
//: The height of the object
text: qsTr("H", "height")
+ tooltip: qsTr("Height.")
enabled: backendValues.sourceSize_height.isAvailable
}
/*
@@ -90,7 +99,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Alignment H") }
+ PropertyLabel {
+ text: qsTr("Alignment H")
+ tooltip: qsTr("Sets the horizontal alignment of the image.")
+ }
SecondColumnLayout {
ComboBox {
@@ -105,7 +117,10 @@ Section {
ExpandingSpacer {}
}
- PropertyLabel { text: qsTr("Alignment V") }
+ PropertyLabel {
+ text: qsTr("Alignment V")
+ tooltip: qsTr("Sets the vertical alignment of the image.")
+ }
SecondColumnLayout {
ComboBox {
@@ -212,7 +227,7 @@ Section {
PropertyLabel {
text: qsTr("Smooth")
- tooltip: qsTr("Smoothly filters the image when it is scaled or transformed.")
+ tooltip: qsTr("Uses smooth filtering when the image is scaled or transformed.")
blockedByTemplate: !backendValues.smooth.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
index 1ec942d6b9..2f749271d7 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
@@ -13,13 +13,15 @@ HelperWidgets.ComboBox {
editable: true
model: comboBox.addDefaultItem(itemFilterModel.itemModel)
+ validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
+
HelperWidgets.ItemFilterModel {
id: itemFilterModel
modelNodeBackendProperty: modelNodeBackend
}
property string defaultItem: qsTr("[None]")
- property string textValue: comboBox.backendValue.expression
+ property string textValue: comboBox.backendValue?.expression ?? ""
property bool block: false
property bool dirty: true
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml
index 456c76e1d4..b73bde2931 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LineEdit.qml
@@ -65,7 +65,7 @@ StudioControls.TextField {
lineEdit.text = ""
} else {
if (lineEdit.writeValueManually)
- lineEdit.text = convertColorToString(colorLogic.valueFromBackend)
+ lineEdit.text = convertColorToString?.(colorLogic.valueFromBackend) ?? ""
else
lineEdit.text = colorLogic.valueFromBackend
}
@@ -111,8 +111,7 @@ StudioControls.TextField {
lineEdit.__dirty = false
}
- property bool isTranslated: colorLogic.backendValue === undefined ? false
- : colorLogic.backendValue.isTranslated
+ property bool isTranslated: colorLogic.backendValue?.isTranslated ?? false
translationIndicator.onClicked: {
if (lineEdit.translationIndicator.checked) {
@@ -124,19 +123,12 @@ StudioControls.TextField {
colorLogic.evaluate()
}
- property variant backendValueValueInternal: lineEdit.backendValue === undefined ? 0
- : lineEdit.backendValue.value
+ property variant backendValueValueInternal: lineEdit.backendValue?.value ?? 0
onBackendValueValueInternalChanged: {
- if (lineEdit.backendValue === undefined)
- lineEdit.translationIndicator.checked = false
- else
- lineEdit.translationIndicator.checked = lineEdit.backendValue.isTranslated
+ lineEdit.translationIndicator.checked = lineEdit.backendValue?.isTranslated ?? false
}
onIsTranslatedChanged: {
- if (lineEdit.backendValue === undefined)
- lineEdit.translationIndicator.checked = false
- else
- lineEdit.translationIndicator.checked = lineEdit.backendValue.isTranslated
+ lineEdit.translationIndicator.checked = lineEdit.backendValue?.isTranslated ?? false
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
index c90ba1c2aa..0512b0861b 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
@@ -6,7 +6,7 @@ import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
StudioControls.ComboBox {
- id: comboBox
+ id: root
property alias typeFilter: itemFilterModel.typeFilter
@@ -14,7 +14,9 @@ StudioControls.ComboBox {
property bool __isCompleted: false
editable: true
- model: itemFilterModel.itemModel
+ model: itemFilterModel
+ textRole: "IdRole"
+ valueRole: "IdRole"
HelperWidgets.ItemFilterModel {
id: itemFilterModel
@@ -22,13 +24,49 @@ StudioControls.ComboBox {
}
Component.onCompleted: {
- comboBox.__isCompleted = true
+ root.__isCompleted = true
+ root.resetInitialIndex()
+ }
+
+ onInitialModelDataChanged: root.resetInitialIndex()
+ onValueRoleChanged: root.resetInitialIndex()
+ onModelChanged: root.resetInitialIndex()
+ onTextRoleChanged: root.resetInitialIndex()
+
+ function resetInitialIndex() {
+ let currentSelectedDataIndex = -1
// Workaround for proper initialization. Use the initial modelData value and search for it
// in the model. If nothing was found, set the editText to the initial modelData.
- comboBox.currentIndex = comboBox.find(comboBox.initialModelData)
+ if (root.textRole === root.valueRole) {
+ currentSelectedDataIndex = root.find(root.initialModelData)
+ } else {
+ for (let i = 0; i < root.count; ++i) {
+ let movingModelIndex = root.model.index(i)
+ let movingModelValueData = root.model.data(movingModelIndex, root.valueRole)
+ if (movingModelValueData === root.initialModelData) {
+ currentSelectedDataIndex = i
+ break
+ }
+ }
+ }
+ root.currentIndex = currentSelectedDataIndex
+ if (root.currentIndex === -1)
+ root.editText = root.initialModelData
+ }
+
+ function currentData(role = root.valueRole) {
+ if (root.currentIndex !== -1) {
+ let currentModelIndex = root.model.index(root.currentIndex)
+ return root.model.data(currentModelIndex, role)
+ }
+ return root.editText
+ }
+
+ function availableValue() {
+ if (root.currentIndex !== -1 && root.currentValue !== "")
+ return root.currentValue
- if (comboBox.currentIndex === -1)
- comboBox.editText = comboBox.initialModelData
+ return root.editText
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OriginControl.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OriginControl.qml
index 201a0de6a6..f4d4f7af85 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OriginControl.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OriginControl.qml
@@ -36,7 +36,7 @@ Row {
ActionIndicator {
id: actionIndicator
- myControl: myButton
+ __parentControl: myButton
x: 0
y: 0
width: actionIndicator.visible ? myButton.__actionIndicatorWidth : 0
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PaddingSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PaddingSection.qml
index 5dc978a811..e1def65263 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PaddingSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PaddingSection.qml
@@ -15,6 +15,7 @@ Section {
SectionLayout {
PropertyLabel {
text: qsTr("Vertical")
+ tooltip: qsTr("Sets the padding on top and bottom of the item.")
blockedByTemplate: !backendValues.topPadding.isAvailable
&& !backendValues.bottomPadding.isAvailable
}
@@ -66,6 +67,7 @@ Section {
PropertyLabel {
text: qsTr("Horizontal")
+ tooltip: qsTr("Sets the paddding on the left and right sides of the item.")
blockedByTemplate: !backendValues.leftPadding.isAvailable
&& !backendValues.rightPadding.isAvailable
}
@@ -118,7 +120,7 @@ Section {
PropertyLabel {
text: qsTr("Global")
- tooltip: qsTr("Padding between the content and the edges of the items.")
+ tooltip: qsTr("Sets the padding for all sides of the item.")
blockedByTemplate: !backendValues.padding.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
index 07d628eb66..5317d909e8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
@@ -18,6 +18,12 @@ Rectangle {
default property alias content: mainColumn.children
+ // Called from C++ to close context menu on focus out
+ function closeContextMenu()
+ {
+ Controller.closeContextMenu()
+ }
+
MouseArea {
anchors.fill: parent
onClicked: forceActiveFocus()
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
index 7724aef49d..b965e8becd 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
@@ -38,6 +38,8 @@ Item {
property bool useDefaulContextMenu: true
+ property string category: "properties"
+
clip: true
Connections {
@@ -49,19 +51,24 @@ Item {
Connections {
target: Controller
- function onCollapseAll() {
- if (collapsible) {
+ function onCollapseAll(cat) {
+ if (collapsible && cat === section.category) {
if (section.expandOnClick)
section.expanded = false
else
section.collapse()
}
}
- function onExpandAll() {
- if (section.expandOnClick)
- section.expanded = true
- else
- section.expand()
+ function onExpandAll(cat) {
+ if (cat === section.category) {
+ if (section.expandOnClick)
+ section.expanded = true
+ else
+ section.expand()
+ }
+ }
+ function onCloseContextMenu() {
+ contextMenu.close()
}
}
@@ -100,12 +107,12 @@ Item {
StudioControls.MenuItem {
text: qsTr("Expand All")
- onTriggered: Controller.expandAll()
+ onTriggered: Controller.expandAll(section.category)
}
StudioControls.MenuItem {
text: qsTr("Collapse All")
- onTriggered: Controller.collapseAll()
+ onTriggered: Controller.collapseAll(section.category)
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
index 6dd21fd791..f125c459c5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/SpinBox.qml
@@ -31,18 +31,18 @@ Item {
}
Component.onCompleted: {
- spinBox.enabled = backendValue === undefined ? false : !isBlocked(backendValue.name)
+ spinBox.enabled = backendValue ? !isBlocked(backendValue.name) : false
}
Connections {
target: modelNodeBackend
function onSelectionChanged() {
- spinBox.enabled = backendValue === undefined ? false : !isBlocked(backendValue.name)
+ spinBox.enabled = backendValue ? !isBlocked(backendValue.name) : false
}
}
onBackendValueChanged: {
- spinBox.enabled = backendValue === undefined ? false : !isBlocked(backendValue.name)
+ spinBox.enabled = backendValue ? !isBlocked(backendValue.name) : false
}
StudioControls.RealSpinBox {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
index 09cb03f871..f1c4844e35 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml
@@ -98,6 +98,7 @@ Section {
PropertyLabel {
visible: root.showVerticalAlignment
text: qsTr("Wrap mode")
+ tooltip: qsTr("Sets how overflowing text is handled.")
blockedByTemplate: !backendValues.wrapMode.isAvailable
}
@@ -119,6 +120,7 @@ Section {
PropertyLabel {
visible: root.showElide
text: qsTr("Elide")
+ tooltip: qsTr("Sets how to indicate that more text is available.")
blockedByTemplate: !backendValues.elide.isAvailable
}
@@ -140,7 +142,7 @@ Section {
PropertyLabel {
visible: root.showElide
text: qsTr("Max line count")
- tooltip: qsTr("Limits the number of lines that the text component will show.")
+ tooltip: qsTr("Sets the max number of lines that the text component shows.")
blockedByTemplate: !backendValues.maximumLineCount.isAvailable
}
@@ -178,6 +180,7 @@ Section {
PropertyLabel {
visible: root.showFormatProperty
text: qsTr("Format")
+ tooltip: qsTr("Sets the formatting method of the text.")
blockedByTemplate: !backendValues.textFormat.isAvailable
}
@@ -198,7 +201,7 @@ Section {
PropertyLabel {
text: qsTr("Render type")
- tooltip: qsTr("Overrides the default rendering type for this component.")
+ tooltip: qsTr("Sets the rendering type for this component.")
blockedByTemplate: !backendValues.renderType.isAvailable
}
@@ -219,7 +222,7 @@ Section {
PropertyLabel {
visible: root.showFontSizeMode
text: qsTr("Size mode")
- tooltip: qsTr("Specifies how the font size of the displayed text is determined.")
+ tooltip: qsTr("Sets how the font size is determined.")
blockedByTemplate: !backendValues.fontSizeMode.isAvailable
}
@@ -242,6 +245,7 @@ Section {
PropertyLabel {
visible: root.showFontSizeMode
text: qsTr("Min size")
+ tooltip: qsTr("Sets the minimum font size to use. This has no effect when <b>Size</b> mode is set to Fixed.")
blockedByTemplate: !backendValues.minimumPixelSize.isAvailable
&& !backendValues.minimumPointSize.isAvailable
}
@@ -320,7 +324,7 @@ Section {
PropertyLabel {
visible: root.showLineHeight
text: qsTr("Line height mode")
- tooltip: qsTr("Determines how the line height is specified.")
+ tooltip: qsTr("Sets how to calculate the line height based on the <b>Line height</b> value.")
blockedByTemplate: !backendValues.lineHeightMode.isAvailable
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml
index 6ede474df0..28875547e0 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml
@@ -32,6 +32,7 @@ Section {
PropertyLabel {
visible: root.showWrapMode
text: qsTr("Wrap mode")
+ tooltip: qsTr("Sets how overflowing text is handled.")
blockedByTemplate: !root.isBackendValueAvailable("wrapMode")
}
@@ -54,6 +55,7 @@ Section {
PropertyLabel {
visible: root.showElide
text: qsTr("Elide")
+ tooltip: qsTr("Sets how to indicate that more text is available.")
blockedByTemplate: !root.isBackendValueAvailable("elide")
}
@@ -76,6 +78,7 @@ Section {
PropertyLabel {
visible: root.showFormatProperty
text: qsTr("Format")
+ tooltip: qsTr("Sets the formatting method of the text.")
blockedByTemplate: !root.isBackendValueAvailable("textFormat")
}
@@ -97,7 +100,7 @@ Section {
PropertyLabel {
text: qsTr("Render type")
- tooltip: qsTr("Overrides the default rendering type for this component.")
+ tooltip: qsTr("Sets the rendering type for this component.")
blockedByTemplate: !root.isBackendValueAvailable("renderType")
}
@@ -117,7 +120,7 @@ Section {
PropertyLabel {
text: qsTr("Render type quality")
- tooltip: qsTr("Overrides the default rendering type quality for this component.")
+ tooltip: qsTr("Sets the quality of the render. This only has an effect when <b>Render type</b> is set to QtRendering.")
blockedByTemplate: !root.isBackendValueAvailable("renderTypeQuality")
enabled: root.isBackendValueAvailable("renderTypeQuality")
&& (backendValues.renderType.value === "QtRendering"
@@ -144,7 +147,7 @@ Section {
PropertyLabel {
visible: root.showLineHeight
text: qsTr("Line height mode")
- tooltip: qsTr("Determines how the line height is specified.")
+ tooltip: qsTr("Sets how to calculate the line height based on the <b>Line height</b> value.")
blockedByTemplate: !root.isBackendValueAvailable("lineHeightMode")
}
@@ -167,7 +170,7 @@ Section {
PropertyLabel {
visible: root.showFontSizeMode
text: qsTr("Size mode")
- tooltip: qsTr("Specifies how the font size of the displayed text is determined.")
+ tooltip: qsTr("Sets how the font size is determined.")
blockedByTemplate: !root.isBackendValueAvailable("fontSizeMode")
}
@@ -191,6 +194,7 @@ Section {
PropertyLabel {
visible: root.showFontSizeMode
text: qsTr("Min size")
+ tooltip: qsTr("Sets the minimum font size to use. This has no effect when <b>Size</b> mode is set to Fixed.")
blockedByTemplate: !root.isBackendValueAvailable("minimumPixelSize")
&& !root.isBackendValueAvailable("minimumPointSize")
}
@@ -244,7 +248,7 @@ Section {
PropertyLabel {
visible: root.showElide
text: qsTr("Max line count")
- tooltip: qsTr("Limits the number of lines that the text component will show.")
+ tooltip: qsTr("Sets the max number of lines that the text component shows.")
blockedByTemplate: !root.isBackendValueAvailable("maximumLineCount")
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml
index f41a2b0c2d..b754022780 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml
@@ -88,7 +88,7 @@ Row {
ToolTip {
id: toolTip
visible: comboBox.hover && toolTip.text !== ""
- text: root.backendValue.valueToString
+ text: root.backendValue?.valueToString ?? ""
delay: StudioTheme.Values.toolTipDelay
background: Rectangle {
@@ -116,8 +116,6 @@ Row {
Image {
id: thumbnail
asynchronous: true
- sourceSize.height: 96
- sourceSize.width: 96
height: 96
width: 96
fillMode: Image.PreserveAspectFit
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml
index 7b0ca95f39..0acf8418f7 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml
@@ -1,15 +1,17 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.AbstractButton {
- id: myButton
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property bool globalHover: false
- property bool hover: myButton.hovered
+ property bool hover: control.hovered
property alias buttonIcon: buttonIcon.text
property alias iconColor: buttonIcon.color
@@ -28,34 +30,35 @@ T.AbstractButton {
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
- height: StudioTheme.Values.height
- width: StudioTheme.Values.height
- z: myButton.checked ? 10 : 3
+ width: control.style.squareControlSize.width
+ height: control.style.squareControlSize.height
+ z: control.checked ? 10 : 3
activeFocusOnTab: false
onHoverChanged: {
- if (parent !== undefined && parent.hoverCallback !== undefined && myButton.enabled)
+ if (parent !== undefined && parent.hoverCallback !== undefined && control.enabled)
parent.hoverCallback()
}
background: Rectangle {
id: buttonBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
+ radius: control.style.radius
}
indicator: Item {
x: 0
y: 0
- width: myButton.width
- height: myButton.height
+ width: control.width
+ height: control.height
T.Label {
id: buttonIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
@@ -64,35 +67,43 @@ T.AbstractButton {
states: [
State {
name: "default"
- when: myButton.enabled && !myButton.pressed && !myButton.checked
+ when: control.enabled && !control.pressed && !control.checked && !control.hover
+ PropertyChanges {
+ target: buttonIcon
+ color: control.style.icon.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && !control.pressed && !control.checked && control.hover
PropertyChanges {
target: buttonIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.hover
}
},
State {
name: "press"
- when: myButton.enabled && myButton.pressed
+ when: control.enabled && control.pressed
PropertyChanges {
target: buttonIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.interaction
}
},
State {
name: "check"
- when: myButton.enabled && !myButton.pressed && myButton.checked
+ when: control.enabled && !control.pressed && control.checked
PropertyChanges {
target: buttonIcon
- color: myButton.checkedInverted ? StudioTheme.Values.themeTextSelectedTextColor
- : StudioTheme.Values.themeIconColorSelected
+ color: control.checkedInverted ? control.style.text.selectedText // TODO rather something in icon
+ : control.style.icon.selected
}
},
State {
name: "disable"
- when: !myButton.enabled
+ when: !control.enabled
PropertyChanges {
target: buttonIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
}
]
@@ -102,78 +113,86 @@ T.AbstractButton {
states: [
State {
name: "default"
- when: myButton.enabled && !myButton.globalHover && !myButton.hover
- && !myButton.pressed && !myButton.checked
+ when: control.enabled && !control.globalHover && !control.hover
+ && !control.pressed && !control.checked
PropertyChanges {
target: buttonBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
- target: myButton
+ target: control
z: 3
}
},
State {
name: "globalHover"
- when: myButton.globalHover && !myButton.hover && !myButton.pressed && myButton.enabled
+ when: control.globalHover && !control.hover && !control.pressed && control.enabled
PropertyChanges {
target: buttonBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
},
State {
name: "hover"
- when: !myButton.checked && myButton.hover && !myButton.pressed && myButton.enabled
+ when: !control.checked && control.hover && !control.pressed && control.enabled
PropertyChanges {
target: buttonBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.hover
+ border.color: control.style.border.hover
+ }
+ PropertyChanges {
+ target: control
+ z: 100
}
},
State {
name: "hoverCheck"
- when: myButton.checked && myButton.hover && !myButton.pressed && myButton.enabled
+ when: control.checked && control.hover && !control.pressed && control.enabled
PropertyChanges {
target: buttonBackground
- color: myButton.checkedInverted ? StudioTheme.Values.themeInteractionHover
- : StudioTheme.Values.themeControlBackgroundHover
- border.color: myButton.checkedInverted ? StudioTheme.Values.themeInteractionHover
- : StudioTheme.Values.themeControlOutline
+ color: control.checkedInverted ? control.style.interactionHover
+ : control.style.background.hover
+ border.color: control.checkedInverted ? control.style.interactionHover
+ : control.style.border.hover
+ }
+ PropertyChanges {
+ target: control
+ z: 100
}
},
State {
name: "press"
- when: myButton.hover && myButton.pressed && myButton.enabled
+ when: control.hover && control.pressed && control.enabled
PropertyChanges {
target: buttonBackground
- color: StudioTheme.Values.themeInteraction
- border.color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
+ border.color: control.style.interaction
}
PropertyChanges {
- target: myButton
+ target: control
z: 100
}
},
State {
name: "check"
- when: myButton.enabled && !myButton.pressed && myButton.checked
+ when: control.enabled && !control.pressed && control.checked
PropertyChanges {
target: buttonBackground
- color: myButton.checkedInverted ? StudioTheme.Values.themeInteraction
- : StudioTheme.Values.themeControlBackground
- border.color: myButton.checkedInverted ? StudioTheme.Values.themeInteraction
- : StudioTheme.Values.themeControlOutline
+ color: control.checkedInverted ? control.style.interaction
+ : control.style.background.idle
+ border.color: control.checkedInverted ? control.style.interaction
+ : control.style.border.idle
}
},
State {
name: "disable"
- when: !myButton.enabled
+ when: !control.enabled
PropertyChanges {
target: buttonBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml
index 618c1e536f..1d52ac9244 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ActionIndicator.qml
@@ -1,16 +1,18 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: actionIndicator
+ id: control
- property Item myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property alias icon: actionIndicatorIcon
+ property Item __parentControl
+
+ property alias icon: icon
property bool hover: false
property bool pressed: false
@@ -18,55 +20,56 @@ Rectangle {
color: "transparent"
- implicitWidth: StudioTheme.Values.actionIndicatorWidth
- implicitHeight: StudioTheme.Values.actionIndicatorHeight
+ implicitWidth: control.style.actionIndicatorSize.width
+ implicitHeight: control.style.actionIndicatorSize.height
signal clicked
z: 10
T.Label {
- id: actionIndicatorIcon
+ id: icon
anchors.fill: parent
text: StudioTheme.Constants.actionIcon
- visible: text !== StudioTheme.Constants.actionIcon || actionIndicator.forceVisible
- || (myControl !== undefined &&
- ((myControl.edit !== undefined && myControl.edit)
- || (myControl.hover !== undefined && myControl.hover)
- || (myControl.drag !== undefined && myControl.drag)))
- color: StudioTheme.Values.themeTextColor
+ visible: text !== StudioTheme.Constants.actionIcon || control.forceVisible
+ || (control.__parentControl !== undefined &&
+ ((control.__parentControl.edit !== undefined && control.__parentControl.edit)
+ || (control.__parentControl.hover !== undefined && control.__parentControl.hover)
+ || (control.__parentControl.drag !== undefined && control.__parentControl.drag)))
+ color: control.style.icon.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
states: [
State {
name: "hover"
- when: actionIndicator.hover && !actionIndicator.pressed
- && (!myControl || (!myControl.edit && !myControl.drag))
- && actionIndicator.enabled
+ when: control.hover && !control.pressed
+ && (!control.__parentControl
+ || (!control.__parentControl.edit && !control.__parentControl.drag))
+ && control.enabled
PropertyChanges {
- target: actionIndicatorIcon
+ target: icon
scale: 1.2
visible: true
}
},
State {
name: "disable"
- when: !actionIndicator.enabled
+ when: !control.enabled
PropertyChanges {
- target: actionIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ target: icon
+ color: control.style.icon.disabled
}
}
]
}
MouseArea {
- id: actionIndicatorMouseArea
+ id: mouseArea
anchors.fill: parent
hoverEnabled: true
- onContainsMouseChanged: actionIndicator.hover = containsMouse
- onClicked: actionIndicator.clicked()
+ onContainsMouseChanged: control.hover = mouseArea.containsMouse
+ onClicked: control.clicked()
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Button.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Button.qml
index df6d0b4e27..099ed20ee8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Button.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Button.qml
@@ -1,24 +1,25 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import StudioControls 1.0
+import QtQuick
ButtonRow {
- id: myButtonRow
+ id: control
- property alias buttonIcon: myAbstractButton.buttonIcon
- property alias iconColor: myAbstractButton.iconColor
- property alias iconRotation: myAbstractButton.iconRotation
- property alias checkable: myAbstractButton.checkable
- property alias checked: myAbstractButton.checked
+ property alias style: button.style
+
+ property alias buttonIcon: button.buttonIcon
+ property alias iconColor: button.iconColor
+ property alias iconRotation: button.iconRotation
+ property alias checkable: button.checkable
+ property alias checked: button.checked
signal onCheckedChanged()
signal clicked
AbstractButton {
- id: myAbstractButton
- onCheckedChanged: myButtonRow.onCheckedChanged()
- onClicked: myButtonRow.clicked()
+ id: button
+ onCheckedChanged: control.onCheckedChanged()
+ onClicked: control.clicked()
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonGroup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonGroup.qml
index 0dbe42b810..dc5274873c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonGroup.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonGroup.qml
@@ -1,8 +1,8 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
T.ButtonGroup {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonRow.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonRow.qml
index 15644cb3af..dffe70e9fa 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonRow.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ButtonRow.qml
@@ -1,51 +1,54 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Row {
- id: myButtonRow
+ id: control
- property bool hover: (actionIndicator.hover || myButtonRow.childHover) && myButtonRow.enabled
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property bool hover: (actionIndicator.hover || control.childHover) && control.enabled
property bool childHover: false
property alias actionIndicator: actionIndicator
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
ActionIndicator {
id: actionIndicator
- myControl: myButtonRow
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- // + StudioTheme.Values.border on width because of negative spacing on the row
- width: actionIndicator.visible ? myButtonRow.__actionIndicatorWidth + StudioTheme.Values.border : 0
- height: actionIndicator.visible ? myButtonRow.__actionIndicatorHeight : 0
+ // + borderWidth because of negative spacing on the row
+ width: actionIndicator.visible ? control.__actionIndicatorWidth + control.style.borderWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
- onHoverChanged: myButtonRow.hoverCallback()
+ onHoverChanged: control.hoverCallback()
}
- spacing: -StudioTheme.Values.border
+ spacing: -control.style.borderWidth
function hoverCallback() {
var hover = false
- for (var i = 0; i < children.length; ++i) {
- if (children[i].hover !== undefined)
- hover = hover || children[i].hover
+ for (var i = 0; i < control.children.length; ++i) {
+ if (control.children[i].hover !== undefined)
+ hover = hover || control.children[i].hover
}
- myButtonRow.childHover = hover
+ control.childHover = hover
}
onHoverChanged: {
- for (var i = 0; i < children.length; ++i)
- if (children[i].globalHover !== undefined)
- children[i].globalHover = myButtonRow.hover
+ for (var i = 0; i < control.children.length; ++i)
+ if (control.children[i].globalHover !== undefined)
+ control.children[i].globalHover = control.hover
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckBox.qml
index aed2cd07d1..573b78012f 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckBox.qml
@@ -1,30 +1,32 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.CheckBox {
- id: myCheckBox
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias actionIndicator: actionIndicator
// This property is used to indicate the global hover state
- property bool hover: myCheckBox.hovered && myCheckBox.enabled
+ property bool hover: control.hovered && control.enabled
property bool edit: false
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
- property alias labelVisible: checkBoxLabel.visible
- property alias labelColor: checkBoxLabel.color
+ property alias labelVisible: label.visible
+ property alias labelColor: label.color
- property alias fontFamily: checkBoxLabel.font.family
- property alias fontPixelSize: checkBoxLabel.font.pixelSize
+ property alias fontFamily: label.font.family
+ property alias fontPixelSize: label.font.pixelSize
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -32,15 +34,16 @@ T.CheckBox {
implicitContentHeight + topPadding + bottomPadding,
implicitIndicatorHeight + topPadding + bottomPadding)
- spacing: checkBoxLabel.visible ? StudioTheme.Values.checkBoxSpacing : 0
+ spacing: label.visible ? control.style.controlSpacing : 0
hoverEnabled: true
activeFocusOnTab: false
ActionIndicator {
id: actionIndicator
- myControl: myCheckBox
- width: actionIndicator.visible ? myCheckBox.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? myCheckBox.__actionIndicatorHeight : 0
+ style: control.style
+ __parentControl: control
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
indicator: Rectangle {
@@ -48,20 +51,20 @@ T.CheckBox {
x: actionIndicator.width
y: 0
z: 5
- implicitWidth: StudioTheme.Values.height
- implicitHeight: StudioTheme.Values.height
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ implicitWidth: control.style.squareControlSize.width
+ implicitHeight: control.style.squareControlSize.height
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
T.Label {
id: checkedIcon
x: (parent.width - checkedIcon.width) / 2
y: (parent.height - checkedIcon.height) / 2
text: StudioTheme.Constants.tickIcon
- visible: myCheckBox.checkState === Qt.Checked
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.sliderControlSizeMulti
+ visible: control.checkState === Qt.Checked
+ color: control.style.icon.idle
+ font.pixelSize: control.style.baseIconFontSize
font.family: StudioTheme.Constants.iconFont.family
}
@@ -70,113 +73,113 @@ T.CheckBox {
x: (parent.width - checkedIcon.width) / 2
y: (parent.height - checkedIcon.height) / 2
text: StudioTheme.Constants.triState
- visible: myCheckBox.checkState === Qt.PartiallyChecked
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.sliderControlSizeMulti
+ visible: control.checkState === Qt.PartiallyChecked
+ color: control.style.icon.idle
+ font.pixelSize: control.style.baseIconFontSize
font.family: StudioTheme.Constants.iconFont.family
}
}
contentItem: T.Label {
- id: checkBoxLabel
- leftPadding: checkBoxBackground.x + checkBoxBackground.width + myCheckBox.spacing
+ id: label
+ leftPadding: checkBoxBackground.x + checkBoxBackground.width + control.spacing
rightPadding: 0
verticalAlignment: Text.AlignVCenter
- text: myCheckBox.text
- font: myCheckBox.font
- color: StudioTheme.Values.themeTextColor
- visible: checkBoxLabel.text !== ""
+ text: control.text
+ font: control.font
+ color: control.style.text.idle
+ visible: label.text !== ""
}
states: [
State {
name: "default"
- when: myCheckBox.enabled && !myCheckBox.hover
- && !myCheckBox.pressed && !actionIndicator.hover
+ when: control.enabled && !control.hover
+ && !control.pressed && !actionIndicator.hover
PropertyChanges {
target: checkBoxBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
target: checkedIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
PropertyChanges {
target: partiallyCheckedIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
},
State {
name: "globalHover"
- when: actionIndicator.hover && !myCheckBox.pressed && myCheckBox.enabled
+ when: actionIndicator.hover && !control.pressed && control.enabled
PropertyChanges {
target: checkBoxBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.globalHover
+ border.color: control.style.border.idle
}
PropertyChanges {
target: checkedIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
PropertyChanges {
target: partiallyCheckedIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
},
State {
name: "hover"
- when: myCheckBox.hover && !actionIndicator.hover && !myCheckBox.pressed
+ when: control.hover && !actionIndicator.hover && !control.pressed
PropertyChanges {
target: checkBoxBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.hover
+ border.color: control.style.border.hover
}
PropertyChanges {
target: checkedIcon
- color: StudioTheme.Values.themeIconColor // TODO naming
+ color: control.style.icon.hover
}
PropertyChanges {
target: partiallyCheckedIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.hover
}
},
State {
name: "press"
- when: myCheckBox.hover && myCheckBox.pressed
+ when: control.hover && control.pressed
PropertyChanges {
target: checkBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
target: checkedIcon
- color: StudioTheme.Values.themeIconColorInteraction
+ color: control.style.icon.interaction
}
PropertyChanges {
target: partiallyCheckedIcon
- color: StudioTheme.Values.themeIconColorInteraction
+ color: control.style.icon.interaction
}
},
State {
name: "disable"
- when: !myCheckBox.enabled
+ when: !control.enabled
PropertyChanges {
target: checkBoxBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
target: checkedIcon
- color: StudioTheme.Values.themeIconColorDisabled
+ color: control.style.icon.disabled
}
PropertyChanges {
target: partiallyCheckedIcon
- color: StudioTheme.Values.themeIconColorDisabled
+ color: control.style.icon.disabled
}
PropertyChanges {
- target: checkBoxLabel
- color: StudioTheme.Values.themeTextColorDisabled
+ target: label
+ color: control.style.text.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml
index a0e048a3d3..7cba51ce33 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/CheckIndicator.qml
@@ -1,156 +1,168 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: checkIndicator
+ id: control
- property T.Control myControl
- property T.Popup myPopup
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool hover: checkIndicatorMouseArea.containsMouse && checkIndicator.enabled
- property bool pressed: checkIndicatorMouseArea.containsPress
+ property T.Control __parentControl
+ property T.Popup __parentPopup
+
+ property bool hover: mouseArea.containsMouse && control.enabled
+ property bool pressed: mouseArea.containsPress
property bool checked: false
- property bool hasActiveDrag: myControl.hasActiveDrag ?? false
- property bool hasActiveHoverDrag: myControl.hasActiveHoverDrag ?? false
+ property bool hasActiveDrag: control.__parentControl.hasActiveDrag ?? false
+ property bool hasActiveHoverDrag: control.__parentControl.hasActiveHoverDrag ?? false
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
border.width: 0
Connections {
- target: myPopup
- function onClosed() { checkIndicator.checked = false }
- function onOpened() { checkIndicator.checked = true }
+ target: control.__parentPopup
+ function onClosed() { control.checked = false }
+ function onOpened() { control.checked = true }
}
MouseArea {
- id: checkIndicatorMouseArea
+ id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
- if (myControl.activeFocus)
- myControl.focus = false
+ if (control.__parentControl.activeFocus)
+ control.__parentControl.focus = false
- if (myPopup.opened) {
- myPopup.close()
+ if (control.__parentPopup.opened) {
+ control.__parentPopup.close()
} else {
- myPopup.open()
- myPopup.forceActiveFocus()
+ control.__parentPopup.open()
+ control.__parentPopup.forceActiveFocus()
}
}
}
T.Label {
- id: checkIndicatorIcon
+ id: icon
anchors.fill: parent
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
text: StudioTheme.Constants.upDownSquare2
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
- font.pixelSize: StudioTheme.Values.sliderControlSizeMulti
+ font.pixelSize: control.style.baseIconFontSize
font.family: StudioTheme.Constants.iconFont.family
}
states: [
State {
name: "default"
- when: myControl.enabled && checkIndicator.enabled && !myControl.edit
- && !checkIndicator.hover && !myControl.hover && !myControl.drag
- && !checkIndicator.checked && !checkIndicator.hasActiveDrag
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.drag
+ && !control.checked && !control.hasActiveDrag
+ PropertyChanges {
+ target: icon
+ color: control.style.icon.idle
+ }
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "dragHover"
- when: myControl.enabled && checkIndicator.hasActiveHoverDrag
+ when: control.__parentControl.enabled && control.hasActiveHoverDrag
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: control
+ color: control.style.background.interaction
}
},
State {
name: "globalHover"
- when: myControl.enabled && checkIndicator.enabled && !myControl.drag
- && !checkIndicator.hover && myControl.hover && !myControl.edit
- && !checkIndicator.checked
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && control.__parentControl.hover && !control.__parentControl.edit
+ && !control.checked
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ target: control
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: myControl.enabled && checkIndicator.enabled && !myControl.drag
- && checkIndicator.hover && myControl.hover && !checkIndicator.pressed
- && !checkIndicator.checked
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.hover && control.__parentControl.hover
+ && !control.pressed && !control.checked
+ PropertyChanges {
+ target: icon
+ color: control.style.icon.hover
+ }
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundHover
+ target: control
+ color: control.style.background.hover
}
},
State {
name: "check"
- when: checkIndicator.checked
+ when: control.checked
PropertyChanges {
- target: checkIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ target: icon
+ color: control.style.icon.interaction
}
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "edit"
- when: myControl.edit && !checkIndicator.checked
- && !(checkIndicator.hover && myControl.hover)
+ when: control.__parentControl.edit && !control.checked
+ && !(control.hover && control.__parentControl.hover)
PropertyChanges {
- target: checkIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ target: icon
+ color: control.style.icon.idle
}
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "press"
- when: myControl.enabled && checkIndicator.enabled && !myControl.drag
- && checkIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.pressed
PropertyChanges {
- target: checkIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ target: icon
+ color: control.style.icon.interaction
}
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "drag"
- when: (myControl.drag !== undefined && myControl.drag) && !checkIndicator.checked
- && !(checkIndicator.hover && myControl.hover)
+ when: (control.__parentControl.drag !== undefined && control.__parentControl.drag)
+ && !control.checked && !(control.hover && control.__parentControl.hover)
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
- target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ target: control
+ color: control.style.background.disabled
}
PropertyChanges {
- target: checkIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ target: icon
+ color: control.style.icon.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml
index 7182bca704..39b1ac8a1c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml
@@ -1,21 +1,24 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Window 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.ComboBox {
- id: myComboBox
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias actionIndicator: actionIndicator
property alias labelColor: comboBoxInput.color
+ property alias textElidable: comboBoxInput.elidable
// This property is used to indicate the global hover state
property bool hover: (comboBoxInput.hover || actionIndicator.hover || popupIndicator.hover)
- && myComboBox.enabled
- property bool edit: myComboBox.activeFocus && myComboBox.editable
+ && control.enabled
+ property bool edit: control.activeFocus && control.editable
property bool open: comboBoxPopup.opened
property bool hasActiveDrag: false // an item that can be dropped on the combobox is being dragged
property bool hasActiveHoverDrag: false // an item that can be dropped on the combobox is being hovered on the combobox
@@ -23,40 +26,44 @@ T.ComboBox {
property bool dirty: false // user modification flag
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property alias textInput: comboBoxInput
+ property alias suffix: comboBoxInput.suffix
+
+ property int maximumPopupHeight: control.style.maxComboBoxPopupHeight
signal compressedActivated(int index, int reason)
enum ActivatedReason { EditingFinished, Other }
- width: StudioTheme.Values.defaultControlWidth
- height: StudioTheme.Values.defaultControlHeight
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
leftPadding: actionIndicator.width
- rightPadding: popupIndicator.width + StudioTheme.Values.border
- font.pixelSize: StudioTheme.Values.myFontSize
+ rightPadding: popupIndicator.width + control.style.borderWidth
+ font.pixelSize: control.style.baseFontSize
wheelEnabled: false
onFocusChanged: {
- if (!myComboBox.focus)
+ if (!control.focus)
comboBoxPopup.close()
}
onActiveFocusChanged: {
- if (myComboBox.activeFocus)
- comboBoxInput.preFocusText = myComboBox.editText
+ if (control.activeFocus)
+ comboBoxInput.preFocusText = control.editText
}
ActionIndicator {
id: actionIndicator
- myControl: myComboBox
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? myComboBox.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? myComboBox.__actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
contentItem: ComboBoxInput {
@@ -64,98 +71,102 @@ T.ComboBox {
property string preFocusText: ""
- myControl: myComboBox
- text: myComboBox.editText
+ style: control.style
+ __parentControl: control
+ text: control.editText
onEditingFinished: {
comboBoxInput.deselect()
comboBoxInput.focus = false
- myComboBox.focus = false
+ control.focus = false
// Only trigger the signal, if the value was modified
- if (myComboBox.dirty) {
- myTimer.stop()
- myComboBox.dirty = false
- myComboBox.accepted()
+ if (control.dirty) {
+ timer.stop()
+ control.dirty = false
+ control.accepted()
}
}
- onTextEdited: myComboBox.dirty = true
+ onTextEdited: control.dirty = true
}
indicator: CheckIndicator {
id: popupIndicator
- myControl: myComboBox
- myPopup: myComboBox.popup
+ style: control.style
+ __parentControl: control
+ __parentPopup: control.popup
x: comboBoxInput.x + comboBoxInput.width
- y: StudioTheme.Values.border
- width: StudioTheme.Values.checkIndicatorWidth - StudioTheme.Values.border
- height: StudioTheme.Values.checkIndicatorHeight - StudioTheme.Values.border * 2
+ y: control.style.borderWidth
+ width: control.style.squareControlSize.width - control.style.borderWidth
+ height: control.style.squareControlSize.height - control.style.borderWidth * 2
}
background: Rectangle {
id: comboBoxBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
x: actionIndicator.width
- width: myComboBox.width - actionIndicator.width
- height: myComboBox.height
+ width: control.width - actionIndicator.width
+ height: control.height
}
Timer {
- id: myTimer
+ id: timer
property int activatedIndex
repeat: false
running: false
interval: 100
- onTriggered: myComboBox.compressedActivated(myTimer.activatedIndex,
- ComboBox.ActivatedReason.Other)
+ onTriggered: control.compressedActivated(timer.activatedIndex,
+ ComboBox.ActivatedReason.Other)
}
onActivated: function(index) {
- myTimer.activatedIndex = index
- myTimer.restart()
+ timer.activatedIndex = index
+ timer.restart()
}
delegate: ItemDelegate {
- id: myItemDelegate
+ id: itemDelegate
width: comboBoxPopup.width - comboBoxPopup.leftPadding - comboBoxPopup.rightPadding
- (comboBoxPopupScrollBar.visible ? comboBoxPopupScrollBar.contentItem.implicitWidth
+ 2 : 0) // TODO Magic number
- height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
+ height: control.style.controlSize.height - 2 * control.style.borderWidth
padding: 0
enabled: model.enabled === undefined ? true : model.enabled
contentItem: Text {
leftPadding: itemDelegateIconArea.width
- text: myComboBox.textRole ? (Array.isArray(myComboBox.model) ? modelData[myComboBox.textRole]
- : model[myComboBox.textRole]) : modelData
+ text: control.textRole ? (Array.isArray(control.model)
+ ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
color: {
- if (!myItemDelegate.enabled)
- return StudioTheme.Values.themeTextColorDisabled
+ if (!itemDelegate.enabled)
+ return control.style.text.disabled
- return myItemDelegate.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
- : StudioTheme.Values.themeTextColor
+ return itemDelegate.highlighted ? control.style.text.selectedText
+ : control.style.text.idle
}
- font: myComboBox.font
+ font: control.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
Item {
id: itemDelegateIconArea
- width: myItemDelegate.height
- height: myItemDelegate.height
+ width: itemDelegate.height
+ height: itemDelegate.height
T.Label {
id: itemDelegateIcon
text: StudioTheme.Constants.tickIcon
- color: myItemDelegate.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
- : StudioTheme.Values.themeTextColor
+ color: itemDelegate.highlighted ? control.style.text.selectedText
+ : control.style.text.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
- visible: myComboBox.currentIndex === index ? true : false
+ font.pixelSize: control.style.smallIconFontSize
+ visible: control.currentIndex === index
anchors.fill: parent
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
@@ -163,31 +174,31 @@ T.ComboBox {
}
}
- highlighted: myComboBox.highlightedIndex === index
+ highlighted: control.highlightedIndex === index
background: Rectangle {
id: itemDelegateBackground
x: 0
y: 0
- width: myItemDelegate.width
- height: myItemDelegate.height
- color: myItemDelegate.highlighted ? StudioTheme.Values.themeInteraction : "transparent"
+ width: itemDelegate.width
+ height: itemDelegate.height
+ color: itemDelegate.highlighted ? control.style.interaction : "transparent"
}
}
popup: T.Popup {
id: comboBoxPopup
- x: actionIndicator.width + StudioTheme.Values.border
- y: myComboBox.height
- width: myComboBox.width - actionIndicator.width - StudioTheme.Values.border * 2
+ x: actionIndicator.width
+ y: control.height
+ width: control.width - actionIndicator.width
// TODO Setting the height on the popup solved the problem with the popup of height 0,
// but it has the problem that it sometimes extend over the border of the actual window
// and is then cut off.
height: Math.min(contentItem.implicitHeight + comboBoxPopup.topPadding
+ comboBoxPopup.bottomPadding,
- myComboBox.Window.height - topMargin - bottomMargin,
- StudioTheme.Values.maxComboBoxPopupHeight)
- padding: StudioTheme.Values.border
+ control.Window.height - topMargin - bottomMargin,
+ control.maximumPopupHeight)
+ padding: control.style.borderWidth
margins: 0 // If not defined margin will be -1
closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent
| T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside
@@ -197,8 +208,8 @@ T.ComboBox {
id: listView
clip: true
implicitHeight: listView.contentHeight
- model: myComboBox.popup.visible ? myComboBox.delegateModel : null
- currentIndex: myComboBox.highlightedIndex
+ model: control.popup.visible ? control.delegateModel : null
+ currentIndex: control.highlightedIndex
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ScrollBar {
id: comboBoxPopupScrollBar
@@ -207,7 +218,7 @@ T.ComboBox {
}
background: Rectangle {
- color: StudioTheme.Values.themePopupBackground
+ color: control.style.popup.background
border.width: 0
}
@@ -218,10 +229,10 @@ T.ComboBox {
states: [
State {
name: "default"
- when: myComboBox.enabled && !myComboBox.hover && !myComboBox.edit && !myComboBox.open
- && !myComboBox.activeFocus && !myComboBox.hasActiveDrag
+ when: control.enabled && !control.hover && !control.edit && !control.open
+ && !control.activeFocus && !control.hasActiveDrag
PropertyChanges {
- target: myComboBox
+ target: control
wheelEnabled: false
}
PropertyChanges {
@@ -230,34 +241,41 @@ T.ComboBox {
}
PropertyChanges {
target: comboBoxBackground
- color: StudioTheme.Values.themeControlBackground
+ border.color: control.style.border.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && control.hover && !control.edit && !control.open
+ && !control.activeFocus && !control.hasActiveDrag
+ PropertyChanges {
+ target: comboBoxBackground
+ border.color: control.style.border.hover
}
},
State {
name: "acceptsDrag"
- when: myComboBox.enabled && myComboBox.hasActiveDrag && !myComboBox.hasActiveHoverDrag
+ when: control.enabled && control.hasActiveDrag && !control.hasActiveHoverDrag
PropertyChanges {
target: comboBoxBackground
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
},
State {
name: "dragHover"
- when: myComboBox.enabled && myComboBox.hasActiveHoverDrag
+ when: control.enabled && control.hasActiveHoverDrag
PropertyChanges {
target: comboBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
},
// This state is intended for ComboBoxes which aren't editable, but have focus e.g. via
// tab focus. It is therefor possible to use the mouse wheel to scroll through the items.
State {
name: "focus"
- when: myComboBox.enabled && myComboBox.activeFocus && !myComboBox.editable
- && !myComboBox.open
+ when: control.enabled && control.activeFocus && !control.editable && !control.open
PropertyChanges {
- target: myComboBox
+ target: control
wheelEnabled: true
}
PropertyChanges {
@@ -267,9 +285,9 @@ T.ComboBox {
},
State {
name: "edit"
- when: myComboBox.enabled && myComboBox.edit && !myComboBox.open
+ when: control.enabled && control.edit && !control.open
PropertyChanges {
- target: myComboBox
+ target: control
wheelEnabled: true
}
PropertyChanges {
@@ -279,8 +297,7 @@ T.ComboBox {
}
PropertyChanges {
target: comboBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
StateChangeScript {
script: comboBoxPopup.close()
@@ -288,9 +305,9 @@ T.ComboBox {
},
State {
name: "popup"
- when: myComboBox.enabled && myComboBox.open
+ when: control.enabled && control.open
PropertyChanges {
- target: myComboBox
+ target: control
wheelEnabled: true
}
PropertyChanges {
@@ -300,26 +317,24 @@ T.ComboBox {
}
PropertyChanges {
target: comboBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
},
State {
name: "disable"
- when: !myComboBox.enabled
+ when: !control.enabled
PropertyChanges {
target: comboBoxBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ border.color: control.style.border.disabled
}
}
]
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) {
- myComboBox.editText = comboBoxInput.preFocusText
- myComboBox.dirty = true
- myComboBox.focus = false
+ control.editText = comboBoxInput.preFocusText
+ control.dirty = true
+ control.focus = false
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml
index 4405fcd2f3..12dd3b1fbc 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml
@@ -1,44 +1,76 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
TextInput {
- id: textInput
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool edit: textInput.activeFocus
- property bool hover: mouseArea.containsMouse && textInput.enabled
+ property T.ComboBox __parentControl
+
+ property bool edit: control.activeFocus
+ property bool hover: mouseArea.containsMouse && control.enabled
+ property bool elidable: false
+ property string suffix: ""
z: 2
- font: myControl.font
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+ font: control.__parentControl.font
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
- leftPadding: StudioTheme.Values.inputHorizontalPadding
- rightPadding: StudioTheme.Values.inputHorizontalPadding
+ leftPadding: control.style.inputHorizontalPadding
+ rightPadding: control.style.inputHorizontalPadding
- readOnly: !myControl.editable
- validator: myControl.validator
- inputMethodHints: myControl.inputMethodHints
+ readOnly: !control.__parentControl.editable
+ validator: control.__parentControl.validator
+ inputMethodHints: control.__parentControl.inputMethodHints
selectByMouse: false
activeFocusOnPress: false
clip: true
+ echoMode: control.elidable ? TextInput.NoEcho : TextInput.Normal
+
+ Text {
+ id: elidableText
+ anchors.fill: control
+ leftPadding: control.leftPadding
+ rightPadding: control.rightPadding
+ horizontalAlignment: control.horizontalAlignment
+ verticalAlignment: control.verticalAlignment
+ font: control.font
+ color: control.color
+ text: control.text + control.suffix
+ visible: control.elidable
+ elide: Text.ElideRight
+ }
+
+ Text {
+ id: nonElidableSuffix
+ anchors.fill: control
+ leftPadding: control.implicitWidth - control.rightPadding
+ rightPadding: control.rightPadding
+ horizontalAlignment: control.horizontalAlignment
+ verticalAlignment: control.verticalAlignment
+ font: control.font
+ color: control.color
+ text: control.suffix
+ visible: !control.elidable
+ }
Rectangle {
- id: textInputBackground
- x: StudioTheme.Values.border
- y: StudioTheme.Values.border
+ id: background
+ x: control.style.borderWidth
+ y: control.style.borderWidth
z: -1
- width: textInput.width
- height: StudioTheme.Values.height - StudioTheme.Values.border * 2
- color: StudioTheme.Values.themeControlBackground
+ width: control.width
+ height: control.style.controlSize.height - control.style.borderWidth * 2
+ color: control.style.background.idle
border.width: 0
}
@@ -51,16 +83,16 @@ TextInput {
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
onPressed: function(mouse) {
- if (!textInput.myControl.editable) {
- if (myControl.popup.opened) {
- myControl.popup.close()
- myControl.focus = false
+ if (!control.__parentControl.editable) {
+ if (control.__parentControl.popup.opened) {
+ control.__parentControl.popup.close()
+ control.__parentControl.focus = false
} else {
- myControl.popup.open()
- //myControl.forceActiveFocus()
+ control.__parentControl.popup.open()
+ //textInput.__control.forceActiveFocus()
}
} else {
- textInput.forceActiveFocus()
+ control.forceActiveFocus()
}
mouse.accepted = false
@@ -70,11 +102,12 @@ TextInput {
states: [
State {
name: "default"
- when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover
- && !myControl.open && !myControl.hasActiveDrag
+ when: control.__parentControl.enabled && !control.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.open
+ && !control.__parentControl.hasActiveDrag
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
+ target: background
+ color: control.style.background.idle
}
PropertyChanges {
target: mouseArea
@@ -84,44 +117,58 @@ TextInput {
},
State {
name: "dragHover"
- when: myControl.enabled && myControl.hasActiveHoverDrag
+ when: control.__parentControl.enabled
+ && (control.__parentControl.hasActiveHoverDrag ?? false)
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: background
+ color: control.style.background.interaction
}
},
State {
name: "globalHover"
- when: myControl.hover && !textInput.hover && !textInput.edit && !myControl.open
+ when: control.__parentControl.hover && !control.hover && !control.edit
+ && !control.__parentControl.open
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ target: background
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: textInput.hover && myControl.hover && !textInput.edit
+ when: control.hover && control.__parentControl.hover && !control.edit
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ target: background
+ color: control.style.background.hover
}
},
// This state is intended for ComboBoxes which aren't editable, but have focus e.g. via
// tab focus. It is therefor possible to use the mouse wheel to scroll through the items.
State {
name: "focus"
- when: textInput.edit && !myControl.editable
+ when: control.edit && !control.__parentControl.editable
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: background
+ color: control.style.background.interaction
}
},
State {
name: "edit"
- when: textInput.edit && myControl.editable
+ when: control.edit && control.__parentControl.editable
+ PropertyChanges {
+ target: background
+ color: control.style.background.interaction
+ }
+ PropertyChanges {
+ target: control
+ echoMode: TextInput.Normal
+ }
+ PropertyChanges {
+ target: elidableText
+ visible: false
+ }
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: nonElidableSuffix
+ visible: false
}
PropertyChanges {
target: mouseArea
@@ -131,22 +178,22 @@ TextInput {
},
State {
name: "popup"
- when: myControl.open
+ when: control.__parentControl.open
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ target: background
+ color: control.style.background.hover
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
- target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ target: background
+ color: control.style.background.disabled
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeTextColorDisabled
+ target: control
+ color: control.style.text.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ContextMenu.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ContextMenu.qml
index 37cf37d7e0..6865453d69 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ContextMenu.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ContextMenu.qml
@@ -1,69 +1,75 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
Menu {
- id: contextMenu
+ id: control
- property Item myTextEdit
+ required property Item __parentControl // TextInput or TextEdit
MenuItem {
- text: "Undo"
- enabled: myTextEdit.canUndo
- onTriggered: myTextEdit.undo()
+ style: control.style
+ text: qsTr("Undo")
+ enabled: control.__parentControl.canUndo
+ onTriggered: control.__parentControl.undo()
/* shortcut: StandardKey.Undo Shortcuts in QQC2 seem to override global shortcuts */
}
MenuItem {
- text: "Redo"
- enabled: myTextEdit.canRedo
- onTriggered: myTextEdit.redo()
+ style: control.style
+ text: qsTr("Redo")
+ enabled: control.__parentControl.canRedo
+ onTriggered: control.__parentControl.redo()
/* shortcut: StandardKey.Redo Shortcuts in QQC2 seem to override global shortcuts */
}
- MenuSeparator {
- }
+ MenuSeparator { style: control.style }
MenuItem {
- text: "Copy"
- enabled: myTextEdit.selectedText !== ""
- onTriggered: myTextEdit.copy()
+ style: control.style
+ text: qsTr("Copy")
+ enabled: control.__parentControl.selectedText !== ""
+ onTriggered: control.__parentControl.copy()
/* shortcut: StandardKey.Copy Shortcuts in QQC2 seem to override global shortcuts */
}
MenuItem {
- text: "Cut"
- enabled: myTextEdit.selectedText !== "" && !myTextEdit.readOnly
- onTriggered: myTextEdit.cut()
+ style: control.style
+ text: qsTr("Cut")
+ enabled: control.__parentControl.selectedText !== "" && !control.__parentControl.readOnly
+ onTriggered: control.__parentControl.cut()
/* shortcut: StandardKey.Cut Shortcuts in QQC2 seem to override global shortcuts */
}
MenuItem {
- text: "Paste"
- enabled: myTextEdit.canPaste
- onTriggered: myTextEdit.paste()
+ style: control.style
+ text: qsTr("Paste")
+ enabled: control.__parentControl.canPaste
+ onTriggered: control.__parentControl.paste()
/* shortcut: StandardKey.Paste Shortcuts in QQC2 seem to override global shortcuts */
}
MenuItem {
- text: "Delete"
- enabled: myTextEdit.selectedText !== ""
- onTriggered: myTextEdit.remove(myTextEdit.selectionStart,
- myTextEdit.selectionEnd)
+ style: control.style
+ text: qsTr("Delete")
+ enabled: control.__parentControl.selectedText !== ""
+ onTriggered: control.__parentControl.remove(control.__parentControl.selectionStart,
+ control.__parentControl.selectionEnd)
/* shortcut: StandardKey.Delete Shortcuts in QQC2 seem to override global shortcuts */
}
MenuItem {
- text: "Clear"
- enabled: myTextEdit.text !== ""
- onTriggered: myTextEdit.clear()
+ style: control.style
+ text: qsTr("Clear")
+ enabled: control.__parentControl.text !== ""
+ onTriggered: control.__parentControl.clear()
/* shortcut: StandardKey.DeleteCompleteLine Shortcuts in QQC2 seem to override global shortcuts */
}
- MenuSeparator {
- }
+ MenuSeparator { style: control.style }
MenuItem {
- text: "Select All"
- enabled: myTextEdit.text !== ""
- && myTextEdit.selectedText !== myTextEdit.text
- onTriggered: myTextEdit.selectAll()
+ style: control.style
+ text: qsTr("Select All")
+ enabled: control.__parentControl.text !== ""
+ && control.__parentControl.selectedText !== control.__parentControl.text
+ onTriggered: control.__parentControl.selectAll()
/* shortcut: StandardKey.SelectAll Shortcuts in QQC2 seem to override global shortcuts */
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Dialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Dialog.qml
index 4320021f9d..64e6ebfd4d 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Dialog.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Dialog.qml
@@ -1,34 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Dialog {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding,
@@ -39,36 +19,37 @@ T.Dialog {
+ (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
- padding: StudioTheme.Values.dialogPadding
+ padding: control.style.dialogPadding
background: Rectangle {
- color: StudioTheme.Values.themeDialogBackground
- border.color: StudioTheme.Values.themeDialogOutline
- border.width: StudioTheme.Values.border
+ color: control.style.dialog.background
+ border.color: control.style.dialog.border
+ border.width: control.style.borderWidth
}
header: T.Label {
- text: root.title
- visible: root.title
+ text: control.title
+ visible: control.title
elide: T.Label.ElideRight
font.bold: true
- padding: StudioTheme.Values.dialogPadding
- color: StudioTheme.Values.themeTextColor
+ padding: control.padding
+ color: control.style.text.idle
background: Rectangle {
- x: StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: parent.width - (2 * StudioTheme.Values.border)
- height: parent.height - (2 * StudioTheme.Values.border)
- color: StudioTheme.Values.themeDialogBackground
+ x: control.style.borderWidth
+ y: control.style.borderWidth
+ width: parent.width - (2 * control.style.borderWidth)
+ height: parent.height - (2 * control.style.borderWidth)
+ color: control.style.dialog.background
}
}
footer: DialogButtonBox {
+ style: control.style
visible: count > 0
}
T.Overlay.modal: Rectangle {
- color: Qt.alpha(StudioTheme.Values.themeDialogBackground, 0.5)
+ color: Qt.alpha(control.style.dialog.overlay, 0.5)
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButton.qml
index 173b4ffdf3..cce9679772 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButton.qml
@@ -1,58 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Button {
- id: root
+ id: control
- implicitWidth: Math.max(
- background ? background.implicitWidth : 0,
- textItem.implicitWidth + leftPadding + rightPadding)
- implicitHeight: Math.max(
- background ? background.implicitHeight : 0,
- textItem.implicitHeight + topPadding + bottomPadding)
- leftPadding: StudioTheme.Values.dialogButtonPadding
- rightPadding: StudioTheme.Values.dialogButtonPadding
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ implicitWidth: Math.max(buttonBackground ? buttonBackground.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(buttonBackground ? buttonBackground.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: control.style.dialogPadding
+ rightPadding: control.style.dialogPadding
background: Rectangle {
- id: background
+ id: buttonBackground
implicitWidth: 70
implicitHeight: 20
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
anchors.fill: parent
}
contentItem: Text {
id: textItem
- text: root.text
- font.pixelSize: StudioTheme.Values.baseFontSize
- color: StudioTheme.Values.themeTextColor
+ text: control.text
+ font.pixelSize: control.style.baseFontSize
+ color: control.style.text.idle
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
@@ -60,58 +38,58 @@ T.Button {
states: [
State {
name: "default"
- when: root.enabled && !root.down && !root.hovered && !root.checked
+ when: control.enabled && !control.down && !control.hovered && !control.checked
PropertyChanges {
- target: background
- color: root.highlighted ? StudioTheme.Values.themeInteraction
- : StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ target: buttonBackground
+ color: control.highlighted ? control.style.interaction
+ : control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
target: textItem
- color: StudioTheme.Values.themeTextColor
+ color: control.style.text.idle
}
},
State {
name: "hover"
- when: root.enabled && root.hovered && !root.checked && !root.down
+ when: control.enabled && control.hovered && !control.checked && !control.down
PropertyChanges {
- target: background
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ target: buttonBackground
+ color: control.style.background.hover
+ border.color: control.style.border.hover
}
PropertyChanges {
target: textItem
- color: StudioTheme.Values.themeTextColor
+ color: control.style.text.hover
}
},
State {
name: "press"
- when: root.enabled && (root.checked || root.down)
+ when: control.enabled && (control.checked || control.down)
PropertyChanges {
- target: background
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ target: buttonBackground
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
target: textItem
- color: StudioTheme.Values.themeTextColor
+ color: control.style.text.interaction
}
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
- target: background
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ target: buttonBackground
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
target: textItem
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.text.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButtonBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButtonBox.qml
index c32eae2e98..199c8fbe6c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButtonBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/DialogButtonBox.qml
@@ -1,27 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Templates as T
@@ -30,20 +8,23 @@ import StudioTheme 1.0 as StudioTheme
T.DialogButtonBox {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
(control.count === 1 ? implicitContentWidth * 2 : implicitContentWidth) + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
contentWidth: contentItem.contentWidth
- spacing: StudioTheme.Values.dialogButtonSpacing
- padding: StudioTheme.Values.dialogPadding
+ spacing: control.style.dialogButtonSpacing
+ padding: control.style.dialogPadding
alignment: Qt.AlignRight | Qt.AlignBottom
delegate: DialogButton {
+ style: control.style
width: control.count === 1 ? control.availableWidth / 2 : undefined
- implicitHeight: StudioTheme.Values.height
+ implicitHeight: control.style.controlSize.height
highlighted: DialogButtonBox.buttonRole === DialogButtonBox.AcceptRole
|| DialogButtonBox.buttonRole === DialogButtonBox.ApplyRole
}
@@ -59,10 +40,10 @@ T.DialogButtonBox {
background: Rectangle {
implicitHeight: 30
- x: StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: parent.width - (2 * StudioTheme.Values.border)
- height: parent.height - (2 * StudioTheme.Values.border)
- color: StudioTheme.Values.themeDialogBackground
+ x: control.style.borderWidth
+ y: control.style.borderWidth
+ width: parent.width - (2 * control.style.borderWidth)
+ height: parent.height - (2 * control.style.borderWidthr)
+ color: control.style.dialog.background
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
index 583947e7ec..5593f46db0 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
@@ -6,7 +6,9 @@ import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Item {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
enum Interaction { None, TextEdit, Key }
@@ -23,7 +25,7 @@ Item {
// This is the actual filter that is applied on the model
property string filter: ""
- property bool filterActive: root.filter !== ""
+ property bool filterActive: control.filter !== ""
// Accept arbitrary input or only items from the model
property bool allowUserInput: false
@@ -40,13 +42,13 @@ Item {
// This property is used to indicate the global hover state
property bool hover: (actionIndicator.hover || textInput.hover || checkIndicator.hover)
- && root.enabled
+ && control.enabled
property alias edit: textInput.edit
property alias open: popup.visible
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property bool dirty: false // user modification flag
@@ -65,43 +67,43 @@ Item {
property bool hasActiveDrag: false // an item that can be dropped here is being dragged
property bool hasActiveHoverDrag: false // an item that can be dropped her is being hovered on top
- width: StudioTheme.Values.defaultControlWidth
- height: StudioTheme.Values.defaultControlHeight
- implicitHeight: StudioTheme.Values.defaultControlHeight
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
+ implicitHeight: control.style.controlSize.width
function selectItem(itemsIndex) {
textInput.text = sortFilterModel.items.get(itemsIndex).model.name
- root.currentIndex = itemsIndex
- root.finishEditing()
- root.activated(itemsIndex)
+ control.currentIndex = itemsIndex
+ control.finishEditing()
+ control.activated(itemsIndex)
}
function submitValue() {
- if (!root.allowUserInput) {
+ if (!control.allowUserInput) {
// If input isn't according to any item in the model, don't finish editing
- if (root.highlightedIndex === -1)
+ if (control.highlightedIndex === -1)
return
- root.selectItem(root.highlightedIndex)
+ control.selectItem(control.highlightedIndex)
} else {
- root.currentIndex = -1
+ control.currentIndex = -1
// Only trigger the signal, if the value was modified
- if (root.dirty) {
+ if (control.dirty) {
myTimer.stop()
- root.dirty = false
- root.editText = root.editText.trim()
+ control.dirty = false
+ control.editText = control.editText.trim()
}
- root.finishEditing()
- root.accepted()
+ control.finishEditing()
+ control.accepted()
}
}
function finishEditing() {
- root.editing = false
- root.filter = ""
- root.autocompleteString = ""
+ control.editing = false
+ control.filter = ""
+ control.autocompleteString = ""
textInput.focus = false // Remove focus from text field
popup.close()
}
@@ -111,16 +113,16 @@ Item {
if (!numItems)
return
- if (root.highlightedIndex === -1) // Nothing is selected
- root.setHighlightedIndexVisible(0)
+ if (control.highlightedIndex === -1) // Nothing is selected
+ control.setHighlightedIndexVisible(0)
else {
- let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex
+ let currentVisibleIndex = sortFilterModel.items.get(control.highlightedIndex).visibleIndex
++currentVisibleIndex
if (currentVisibleIndex > numItems - 1)
currentVisibleIndex = 0
- root.setHighlightedIndexVisible(currentVisibleIndex)
+ control.setHighlightedIndexVisible(currentVisibleIndex)
}
}
@@ -129,32 +131,32 @@ Item {
if (!numItems)
return
- if (root.highlightedIndex === -1) // Nothing is selected
- root.setHighlightedIndexVisible(numItems - 1)
+ if (control.highlightedIndex === -1) // Nothing is selected
+ control.setHighlightedIndexVisible(numItems - 1)
else {
- let currentVisibleIndex = sortFilterModel.items.get(root.highlightedIndex).visibleIndex
+ let currentVisibleIndex = sortFilterModel.items.get(control.highlightedIndex).visibleIndex
--currentVisibleIndex
if (currentVisibleIndex < 0)
currentVisibleIndex = numItems - 1
- root.setHighlightedIndexVisible(currentVisibleIndex)
+ control.setHighlightedIndexVisible(currentVisibleIndex)
}
}
function updateHighlightedIndex() {
// Check if current index is still part of the filtered list, if not set it to 0
- if (root.highlightedIndex !== -1 && !sortFilterModel.items.get(root.highlightedIndex).inVisible) {
- root.setHighlightedIndexVisible(0)
+ if (control.highlightedIndex !== -1 && !sortFilterModel.items.get(control.highlightedIndex).inVisible) {
+ control.setHighlightedIndexVisible(0)
} else {
// Needs to be set in order for ListView to keep its currenIndex up to date, so
// scroll position gets updated according to the higlighted item
- root.setHighlightedIndexItems(root.highlightedIndex)
+ control.setHighlightedIndexItems(control.highlightedIndex)
}
}
function setHighlightedIndexItems(itemsIndex) { // items group index
- root.highlightedIndex = itemsIndex
+ control.highlightedIndex = itemsIndex
if (itemsIndex === -1)
listView.currentIndex = -1
@@ -164,19 +166,19 @@ Item {
function setHighlightedIndexVisible(visibleIndex) { // visible group index
if (visibleIndex === -1)
- root.highlightedIndex = -1
+ control.highlightedIndex = -1
else
- root.highlightedIndex = sortFilterModel.visibleGroup.get(visibleIndex).itemsIndex
+ control.highlightedIndex = sortFilterModel.visibleGroup.get(visibleIndex).itemsIndex
listView.currentIndex = visibleIndex
}
function updateAutocomplete() {
- if (root.highlightedIndex === -1)
- root.autocompleteString = ""
+ if (control.highlightedIndex === -1)
+ control.autocompleteString = ""
else {
- let suggestion = sortFilterModel.items.get(root.highlightedIndex).model.name
- root.autocompleteString = suggestion.substring(textInput.text.length)
+ let suggestion = sortFilterModel.items.get(control.highlightedIndex).model.name
+ control.autocompleteString = suggestion.substring(textInput.text.length)
}
}
@@ -195,8 +197,8 @@ Item {
repeat: false
running: false
interval: 100
- onTriggered: root.compressedActivated(myTimer.activatedIndex,
- ComboBox.ActivatedReason.Other)
+ onTriggered: control.compressedActivated(myTimer.activatedIndex,
+ ComboBox.ActivatedReason.Other)
}
onActivated: function(index) {
@@ -205,8 +207,8 @@ Item {
}
onHighlightedIndexChanged: {
- if (root.editing || (root.editText === "" && root.allowUserInput))
- root.updateAutocomplete()
+ if (control.editing || (control.editText === "" && control.allowUserInput))
+ control.updateAutocomplete()
}
DelegateModel {
@@ -221,14 +223,14 @@ Item {
width: popup.width - popup.leftPadding - popup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2
: 0) // TODO Magic number
- height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
+ height: control.style.controlSize.height - 2 * control.style.borderWidth
padding: 0
contentItem: Text {
- leftPadding: StudioTheme.Values.inputHorizontalPadding
+ leftPadding: control.style.inputHorizontalPadding
text: name
font.italic: true
- color: StudioTheme.Values.themeTextColor
+ color: control.style.text.idle
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
@@ -247,7 +249,7 @@ Item {
id: sortFilterModel
filterAcceptsItem: function(item) {
- return item.name.toLowerCase().startsWith(root.filter.toLowerCase())
+ return item.name.toLowerCase().startsWith(control.filter.toLowerCase())
}
lessThan: function(left, right) {
@@ -263,17 +265,17 @@ Item {
width: popup.width - popup.leftPadding - popup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth + 2
: 0) // TODO Magic number
- height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
+ height: control.style.controlSize.height - 2 * control.style.borderWidth
padding: 0
hoverEnabled: true
- highlighted: root.highlightedIndex === delegateRoot.DelegateModel.itemsIndex
+ highlighted: control.highlightedIndex === delegateRoot.DelegateModel.itemsIndex
onHoveredChanged: {
if (delegateRoot.hovered && !popupMouseArea.active)
- root.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex)
+ control.setHighlightedIndexItems(delegateRoot.DelegateModel.itemsIndex)
}
- onClicked: root.selectItem(delegateRoot.DelegateModel.itemsIndex)
+ onClicked: control.selectItem(delegateRoot.DelegateModel.itemsIndex)
indicator: Item {
id: itemDelegateIconArea
@@ -283,12 +285,12 @@ Item {
T.Label {
id: itemDelegateIcon
text: StudioTheme.Constants.tickIcon
- color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
- : StudioTheme.Values.themeTextColor
+ color: delegateRoot.highlighted ? control.style.text.selectedText
+ : control.style.text.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
- visible: root.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true
- : false
+ font.pixelSize: control.style.smallIconFontSize
+ visible: control.currentIndex === delegateRoot.DelegateModel.itemsIndex ? true
+ : false
anchors.fill: parent
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
@@ -299,8 +301,8 @@ Item {
contentItem: Text {
leftPadding: itemDelegateIconArea.width
text: name
- color: delegateRoot.highlighted ? StudioTheme.Values.themeTextSelectedTextColor
- : StudioTheme.Values.themeTextColor
+ color: delegateRoot.highlighted ? control.style.text.selectedText
+ : control.style.text.idle
font: textInput.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
@@ -311,20 +313,19 @@ Item {
y: 0
width: delegateRoot.width
height: delegateRoot.height
- color: delegateRoot.highlighted ? StudioTheme.Values.themeInteraction
- : "transparent"
+ color: delegateRoot.highlighted ? control.style.interaction : "transparent"
}
}
onUpdated: {
- if (!root.__isCompleted)
+ if (!control.__isCompleted)
return
if (sortFilterModel.count === 0)
- root.setHighlightedIndexVisible(-1)
+ control.setHighlightedIndexVisible(-1)
else {
- if (root.highlightedIndex === -1 && !root.allowUserInput)
- root.setHighlightedIndexVisible(0)
+ if (control.highlightedIndex === -1 && !control.allowUserInput)
+ control.setHighlightedIndexVisible(0)
}
}
}
@@ -332,11 +333,12 @@ Item {
Row {
ActionIndicator {
id: actionIndicator
- myControl: root
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
TextInput {
@@ -349,16 +351,16 @@ Item {
x: 0
y: 0
z: 2
- width: root.width - actionIndicator.width
- height: root.height
- leftPadding: StudioTheme.Values.inputHorizontalPadding
- rightPadding: StudioTheme.Values.inputHorizontalPadding + checkIndicator.width
- + StudioTheme.Values.border
+ width: control.width - actionIndicator.width
+ height: control.height
+ leftPadding: control.style.inputHorizontalPadding
+ rightPadding: control.style.inputHorizontalPadding + checkIndicator.width
+ + control.style.borderWidth
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
selectByMouse: true
clip: true
@@ -367,9 +369,9 @@ Item {
z: -1
width: textInput.width
height: textInput.height
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
}
MouseArea {
@@ -388,20 +390,20 @@ Item {
// Stop scrollable views from scrolling while ComboBox is in edit mode and the mouse
// pointer is on top of it. We might add wheel selection in the future.
onWheel: function(wheel) {
- wheel.accepted = root.edit
+ wheel.accepted = control.edit
}
}
onEditingFinished: {
- if (root.escapePressed) {
- root.escapePressed = false
- root.editText = textInput.preFocusText
+ if (control.escapePressed) {
+ control.escapePressed = false
+ control.editText = textInput.preFocusText
} else {
- if (root.currentInteraction === FilterComboBox.Interaction.TextEdit) {
- if (root.dirty)
- root.submitValue()
- } else if (root.currentInteraction === FilterComboBox.Interaction.Key) {
- root.selectItem(root.highlightedIndex)
+ if (control.currentInteraction === FilterComboBox.Interaction.TextEdit) {
+ if (control.dirty)
+ control.submitValue()
+ } else if (control.currentInteraction === FilterComboBox.Interaction.Key) {
+ control.selectItem(control.highlightedIndex)
}
}
@@ -409,16 +411,16 @@ Item {
}
onTextEdited: {
- root.currentInteraction = FilterComboBox.Interaction.TextEdit
- root.editing = true
+ control.currentInteraction = FilterComboBox.Interaction.TextEdit
+ control.editing = true
popupMouseArea.active = true
- root.dirty = true
+ control.dirty = true
if (textInput.text !== "")
- root.filter = textInput.text
+ control.filter = textInput.text
else {
- root.filter = ""
- root.autocompleteString = ""
+ control.filter = ""
+ control.autocompleteString = ""
}
if (!popup.visible)
@@ -426,12 +428,12 @@ Item {
sortFilterModel.update()
- if (!root.allowUserInput)
- root.updateHighlightedIndex()
+ if (!control.allowUserInput)
+ control.updateHighlightedIndex()
else
- root.setHighlightedIndexVisible(-1)
+ control.setHighlightedIndexVisible(-1)
- root.updateAutocomplete()
+ control.updateAutocomplete()
}
onActiveFocusChanged: {
@@ -445,12 +447,12 @@ Item {
states: [
State {
name: "default"
- when: root.enabled && !textInput.edit && !root.hover && !root.open
- && !root.hasActiveDrag
+ when: control.enabled && !textInput.edit && !control.hover && !control.open
+ && !control.hasActiveDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
target: textInputMouseArea
@@ -460,44 +462,44 @@ Item {
},
State {
name: "acceptsDrag"
- when: root.enabled && root.hasActiveDrag && !root.hasActiveHoverDrag
+ when: control.enabled && control.hasActiveDrag && !control.hasActiveHoverDrag
PropertyChanges {
target: textInputBackground
- border.color: StudioTheme.Values.themeInteraction
+ border.color: control.style.interaction
}
},
State {
name: "dragHover"
- when: root.enabled && root.hasActiveHoverDrag
+ when: control.enabled && control.hasActiveHoverDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeInteraction
+ color: control.style.background.interaction
+ border.color: control.style.interaction
}
},
State {
name: "globalHover"
- when: root.hover && !textInput.hover && !textInput.edit && !root.open
+ when: control.hover && !textInput.hover && !textInput.edit && !control.open
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: textInput.hover && root.hover && !textInput.edit
+ when: textInput.hover && control.hover && !textInput.edit
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: control.style.background.hover
}
},
State {
name: "edit"
- when: root.edit
+ when: control.edit
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
target: textInputMouseArea
@@ -507,23 +509,23 @@ Item {
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
target: textInput
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.text.disabled
}
}
]
Text {
id: tmpSelectionName
- visible: root.autocompleteString !== "" && root.open
- text: root.autocompleteString
+ visible: control.autocompleteString !== "" && control.open
+ text: control.autocompleteString
x: textInput.leftPadding + textMetrics.advanceWidth
y: (textInput.height - Math.ceil(tmpSelectionTextMetrics.height)) / 2
color: "gray" // TODO proper color value
@@ -542,7 +544,6 @@ Item {
}
}
-
Rectangle {
id: checkIndicator
@@ -550,11 +551,11 @@ Item {
property bool pressed: checkIndicatorMouseArea.containsPress
property bool checked: popup.visible
- x: textInput.width - checkIndicator.width - StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: StudioTheme.Values.height - StudioTheme.Values.border
- height: textInput.height - (StudioTheme.Values.border * 2)
- color: StudioTheme.Values.themeControlBackground
+ x: textInput.width - checkIndicator.width - control.style.borderWidth
+ y: control.style.borderWidth
+ width: control.style.squareControlSize.width - control.style.borderWidth
+ height: textInput.height - (control.style.borderWidth * 2)
+ color: control.style.background.idle
border.width: 0
MouseArea {
@@ -577,51 +578,51 @@ Item {
T.Label {
id: checkIndicatorIcon
anchors.fill: parent
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
text: StudioTheme.Constants.upDownSquare2
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
- font.pixelSize: StudioTheme.Values.sliderControlSizeMulti
+ font.pixelSize: control.style.baseIconFontSize
font.family: StudioTheme.Constants.iconFont.family
}
states: [
State {
name: "default"
- when: root.enabled && checkIndicator.enabled && !root.edit
- && !checkIndicator.hover && !root.hover
- && !checkIndicator.checked && !root.hasActiveHoverDrag
+ when: control.enabled && checkIndicator.enabled && !control.edit
+ && !checkIndicator.hover && !control.hover
+ && !checkIndicator.checked && !control.hasActiveHoverDrag
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
}
},
State {
name: "dragHover"
- when: root.enabled && root.hasActiveHoverDrag
+ when: control.enabled && control.hasActiveHoverDrag
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ color: control.style.background.interaction
}
},
State {
name: "globalHover"
- when: root.enabled && checkIndicator.enabled
- && !checkIndicator.hover && root.hover && !root.edit
+ when: control.enabled && checkIndicator.enabled
+ && !checkIndicator.hover && control.hover && !control.edit
&& !checkIndicator.checked
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: root.enabled && checkIndicator.enabled
- && checkIndicator.hover && root.hover && !checkIndicator.pressed
+ when: control.enabled && checkIndicator.enabled
+ && checkIndicator.hover && control.hover && !checkIndicator.pressed
&& !checkIndicator.checked
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: control.style.background.hover
}
},
State {
@@ -629,36 +630,36 @@ Item {
when: checkIndicator.checked
PropertyChanges {
target: checkIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "press"
- when: root.enabled && checkIndicator.enabled
+ when: control.enabled && checkIndicator.enabled
&& checkIndicator.pressed
PropertyChanges {
target: checkIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
target: checkIndicator
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ color: control.style.background.disabled
}
PropertyChanges {
target: checkIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
}
]
@@ -668,13 +669,13 @@ Item {
T.Popup {
id: popup
- x: textInput.x + StudioTheme.Values.border
+ x: textInput.x + control.style.borderWidth
y: textInput.height
- width: textInput.width - (StudioTheme.Values.border * 2)
+ width: textInput.width - (control.style.borderWidth * 2)
height: Math.min(popup.contentItem.implicitHeight + popup.topPadding + popup.bottomPadding,
- root.Window.height - popup.topMargin - popup.bottomMargin,
- StudioTheme.Values.maxComboBoxPopupHeight)
- padding: StudioTheme.Values.border
+ control.Window.height - popup.topMargin - popup.bottomMargin,
+ control.style.maxComboBoxPopupHeight)
+ padding: control.style.borderWidth
margins: 0 // If not defined margin will be -1
closePolicy: T.Popup.NoAutoClose
@@ -700,20 +701,20 @@ Item {
}
background: Rectangle {
- color: StudioTheme.Values.themePopupBackground
+ color: control.style.popup.background
border.width: 0
}
onOpened: {
// Reset the highlightedIndex of ListView as binding with condition didn't work
- if (root.highlightedIndex !== -1)
- root.setHighlightedIndexItems(root.highlightedIndex)
+ if (control.highlightedIndex !== -1)
+ control.setHighlightedIndexItems(control.highlightedIndex)
}
onAboutToShow: {
// Select first item in list
- if (root.highlightedIndex === -1 && sortFilterModel.count && !root.allowUserInput)
- root.setHighlightedIndexVisible(0)
+ if (control.highlightedIndex === -1 && sortFilterModel.count && !control.allowUserInput)
+ control.setHighlightedIndexVisible(0)
}
MouseArea {
@@ -734,8 +735,8 @@ Item {
if (!sortFilterModel.visibleGroup.count)
return
- root.currentInteraction = FilterComboBox.Interaction.Key
- root.increaseVisibleIndex()
+ control.currentInteraction = FilterComboBox.Interaction.Key
+ control.increaseVisibleIndex()
popupMouseArea.active = true
}
@@ -744,22 +745,21 @@ Item {
if (!sortFilterModel.visibleGroup.count)
return
- root.currentInteraction = FilterComboBox.Interaction.Key
- root.decreaseVisibleIndex()
+ control.currentInteraction = FilterComboBox.Interaction.Key
+ control.decreaseVisibleIndex()
popupMouseArea.active = true
}
Keys.onEscapePressed: {
- root.escapePressed = true
- root.finishEditing()
+ control.escapePressed = true
+ control.finishEditing()
}
Component.onCompleted: {
- let index = root.find(root.editText)
- root.currentIndex = index
- root.highlightedIndex = index // TODO might not be intended
-
- root.__isCompleted = true
+ let index = control.find(control.editText)
+ control.currentIndex = index
+ control.highlightedIndex = index // TODO might not be intended
+ control.__isCompleted = true
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Indicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Indicator.qml
index cc5cf43b86..3ffab90ac9 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Indicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Indicator.qml
@@ -1,41 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Item {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias icon: icon
property bool hover: mouseArea.containsMouse
property bool pressed: mouseArea.pressed
- implicitWidth: StudioTheme.Values.height
- implicitHeight: StudioTheme.Values.height
+ implicitWidth: control.style.squareControlSize.width
+ implicitHeight: control.style.squareControlSize.height
signal clicked
z: 10
@@ -44,16 +24,16 @@ Item {
id: icon
anchors.fill: parent
text: StudioTheme.Constants.actionIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
states: [
State {
name: "hover"
- when: root.hover && !root.pressed && root.enabled
+ when: control.hover && !control.pressed && control.enabled
PropertyChanges {
target: icon
scale: 1.2
@@ -62,10 +42,10 @@ Item {
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
target: icon
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
}
]
@@ -75,6 +55,6 @@ Item {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
- onClicked: root.clicked()
+ onClicked: control.clicked()
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/InfinityLoopIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/InfinityLoopIndicator.qml
index f31ac454b9..d6346788f8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/InfinityLoopIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/InfinityLoopIndicator.qml
@@ -1,33 +1,35 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: infinityLoopIndicator
+ id: control
- property Item myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property Item __parentControl
property bool infinite: false
color: "transparent"
border.color: "transparent"
- implicitWidth: StudioTheme.Values.infinityControlWidth
- implicitHeight: StudioTheme.Values.infinityControlHeight
+ implicitWidth: control.style.indicatorIconSize.width
+ implicitHeight: control.style.indicatorIconSize.height
z: 10
T.Label {
- id: infinityLoopIndicatorIcon
+ id: icon
anchors.fill: parent
text: StudioTheme.Constants.infinity
visible: true
- color: StudioTheme.Values.themeTextColor
+ color: control.style.indicator.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -36,32 +38,32 @@ Rectangle {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
- onClicked: infinityLoopIndicator.infinite = !infinityLoopIndicator.infinite
+ onClicked: control.infinite = !control.infinite
}
states: [
State {
name: "active"
- when: infinityLoopIndicator.infinite && !mouseArea.containsMouse
+ when: control.infinite && !mouseArea.containsMouse
PropertyChanges {
- target: infinityLoopIndicatorIcon
- color: StudioTheme.Values.themeInfiniteLoopIndicatorColorInteraction
+ target: icon
+ color: control.style.indicator.interaction
}
},
State {
name: "default"
when: !mouseArea.containsMouse
PropertyChanges {
- target: infinityLoopIndicatorIcon
- color: StudioTheme.Values.themeInfiniteLoopIndicatorColor
+ target: icon
+ color: control.style.indicator.idle
}
},
State {
name: "hover"
when: mouseArea.containsMouse
PropertyChanges {
- target: infinityLoopIndicatorIcon
- color: StudioTheme.Values.themeInfiniteLoopIndicatorColorHover
+ target: icon
+ color: control.style.indicator.hover
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ItemDelegate.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ItemDelegate.qml
index 78211d73dd..f0d33d4b99 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ItemDelegate.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ItemDelegate.qml
@@ -1,8 +1,8 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
T.ItemDelegate {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator2D.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator2D.qml
index bfcd710b32..b0e6e52bd6 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator2D.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator2D.qml
@@ -1,34 +1,36 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: linkIndicator
+ id: control
- property Item myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property Item __parentControl
property bool linked: false
color: "transparent"
border.color: "transparent"
- implicitWidth: StudioTheme.Values.linkControlWidth
- implicitHeight: StudioTheme.Values.linkControlHeight
+ implicitWidth: control.style.indicatorIconSize.width
+ implicitHeight: control.style.indicatorIconSize.height
z: 10
T.Label {
- id: linkIndicatorIcon
+ id: icon
anchors.fill: parent
- text: linkIndicator.linked ? StudioTheme.Constants.linked
- : StudioTheme.Constants.unLinked
+ text: control.linked ? StudioTheme.Constants.linked
+ : StudioTheme.Constants.unLinked
visible: true
- color: StudioTheme.Values.themeTextColor
+ color: control.style.indicator.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -37,7 +39,7 @@ Rectangle {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
- onPressed: linkIndicator.linked = !linkIndicator.linked
+ onPressed: control.linked = !control.linked
}
states: [
@@ -45,16 +47,16 @@ Rectangle {
name: "default"
when: !mouseArea.containsMouse
PropertyChanges {
- target: linkIndicatorIcon
- color: StudioTheme.Values.themeLinkIndicatorColor
+ target: icon
+ color: control.style.indicator.idle
}
},
State {
name: "hover"
when: mouseArea.containsMouse
PropertyChanges {
- target: linkIndicatorIcon
- color: StudioTheme.Values.themeLinkIndicatorColorHover
+ target: icon
+ color: control.style.indicator.hover
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3D.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3D.qml
index 8d590a5315..8a483a04c3 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3D.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3D.qml
@@ -1,23 +1,25 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Shapes 1.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Shapes
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: linkIndicator
+ id: control
- property Item myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property Item __parentControl
property bool linked: linkXZ.linked || linkYZ.linked || linkXY.linked
color: "transparent"
border.color: "transparent"
- implicitWidth: StudioTheme.Values.height
- implicitHeight: StudioTheme.Values.height
+ implicitWidth: control.style.squareControlSize.width
+ implicitHeight: control.style.squareControlSize.height
z: 10
@@ -32,12 +34,12 @@ Rectangle {
T.Label {
id: linkIndicatorIcon
anchors.fill: parent
- text: linkIndicator.linked ? StudioTheme.Constants.linked
- : StudioTheme.Constants.unLinked
+ text: control.linked ? StudioTheme.Constants.linked
+ : StudioTheme.Constants.unLinked
visible: true
- color: StudioTheme.Values.themeTextColor
+ color: control.style.indicator.idle
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -56,10 +58,10 @@ Rectangle {
y: 0
// TODO proper size
- width: 20 + (3 * StudioTheme.Values.height)
- height: 20 + (3 * StudioTheme.Values.height)
+ width: 20 + (3 * control.style.squareControlSize.width)
+ height: 20 + (3 * control.style.squareControlSize.height)
- padding: StudioTheme.Values.border
+ padding: control.style.borderWidth
margins: 0 // If not defined margin will be -1
closePolicy: T.Popup.CloseOnPressOutside | T.Popup.CloseOnPressOutsideParent
@@ -99,7 +101,7 @@ Rectangle {
property vector2d center: Qt.vector2d(triangle.radius, triangle.radius)
- strokeWidth: StudioTheme.Values.border
+ strokeWidth: control.style.borderWidth
strokeColor: triangleMouseArea.containsMouse ? "white" : "gray"
strokeStyle: ShapePath.SolidLine
fillColor: "transparent"
@@ -149,9 +151,9 @@ Rectangle {
onClicked: {
if (linkXZ.linked && linkYZ.linked && linkXY.linked)
- linkIndicator.unlinkAll()
+ control.unlinkAll()
else
- linkIndicator.linkAll()
+ control.linkAll()
}
MouseArea {
@@ -177,13 +179,14 @@ Rectangle {
visible: true
color: triangleMouseArea.containsMouse ? "white" : "gray"
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize * 3
+ font.pixelSize: control.style.baseIconFontSize * 3
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
LinkIndicator3DComponent {
id: linkXZ
+ style: control.style
pointA: path.pX
pointB: path.pZ
rotation: 105 // 60
@@ -191,6 +194,7 @@ Rectangle {
LinkIndicator3DComponent {
id: linkYZ
+ style: control.style
pointA: path.pZ
pointB: path.pY
rotation: 45 // -180
@@ -198,6 +202,7 @@ Rectangle {
LinkIndicator3DComponent {
id: linkXY
+ style: control.style
pointA: path.pY
pointB: path.pX
rotation: -15 // -60
@@ -211,7 +216,7 @@ Rectangle {
color: StudioTheme.Values.theme3DAxisXColor
font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -223,7 +228,7 @@ Rectangle {
color: StudioTheme.Values.theme3DAxisYColor
font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -235,7 +240,7 @@ Rectangle {
color: StudioTheme.Values.theme3DAxisZColor
font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -244,9 +249,9 @@ Rectangle {
}
background: Rectangle {
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeInteraction
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.interaction
+ border.width: control.style.borderWidth
}
enter: Transition {}
@@ -259,7 +264,7 @@ Rectangle {
when: !mouseArea.containsMouse && !linkPopup.opened
PropertyChanges {
target: linkIndicatorIcon
- color: StudioTheme.Values.themeLinkIndicatorColor
+ color: control.style.indicator.idle
}
},
State {
@@ -267,7 +272,7 @@ Rectangle {
when: mouseArea.containsMouse && !linkPopup.opened
PropertyChanges {
target: linkIndicatorIcon
- color: StudioTheme.Values.themeLinkIndicatorColorHover
+ color: control.style.indicator.hover
}
},
State {
@@ -275,7 +280,7 @@ Rectangle {
when: linkPopup.opened
PropertyChanges {
target: linkIndicatorIcon
- color: StudioTheme.Values.themeLinkIndicatorColorInteraction
+ color: control.style.indicator.interaction
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3DComponent.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3DComponent.qml
index 5347ad4e39..c6f3df59e1 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3DComponent.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/LinkIndicator3DComponent.qml
@@ -1,12 +1,14 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property var pointA: Qt.vector2d()
property var pointB: Qt.vector2d()
@@ -14,14 +16,14 @@ Rectangle {
property bool linked: false
property var middle: {
- var ab = root.pointB.minus(root.pointA) // B - A
- return root.pointA.plus(ab.normalized().times(ab.length() * 0.5))
+ var ab = control.pointB.minus(control.pointA) // B - A
+ return control.pointA.plus(ab.normalized().times(ab.length() * 0.5))
}
property var position: {
// Calculate the middle point between A and B
- var ab = root.pointB.minus(root.pointA) // B - A
- var midAB = root.pointA.plus(ab.normalized().times(ab.length() * 0.5))
+ var ab = control.pointB.minus(control.pointA) // B - A
+ var midAB = control.pointA.plus(ab.normalized().times(ab.length() * 0.5))
var perpendicularAB = Qt.vector2d(ab.y, -ab.x)
return midAB.plus(perpendicularAB.normalized().times(8.0 * StudioTheme.Values.scaleFactor))
}
@@ -29,23 +31,23 @@ Rectangle {
color: "transparent"
border.color: "transparent"
- x: root.position.x - (StudioTheme.Values.height * 0.5)
- y: root.position.y - (StudioTheme.Values.height * 0.5)
+ x: control.position.x - (control.style.squareControlSize.width * 0.5)
+ y: control.position.y - (control.style.squareControlSize.height * 0.5)
- implicitWidth: StudioTheme.Values.height
- implicitHeight: StudioTheme.Values.height
+ implicitWidth: control.style.squareControlSize.width
+ implicitHeight: control.style.squareControlSize.height
transformOrigin: Item.Center
T.Label {
id: icon
anchors.fill: parent
- text: root.linked ? StudioTheme.Constants.linked
- : StudioTheme.Constants.unLinked
+ text: control.linked ? StudioTheme.Constants.linked
+ : StudioTheme.Constants.unLinked
visible: true
color: "grey"
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
@@ -55,7 +57,7 @@ Rectangle {
anchors.fill: parent
anchors.margins: 4.0 * StudioTheme.Values.scaleFactor
hoverEnabled: true
- onPressed: root.linked = !root.linked
+ onPressed: control.linked = !control.linked
}
states: [
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml
index 65d3b0cc75..f5aef1ca17 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Menu.qml
@@ -1,21 +1,23 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Window 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Menu {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
contentHeight + topPadding + bottomPadding)
font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
margins: 0
overlap: 1
@@ -25,7 +27,7 @@ T.Menu {
| T.Popup.CloseOnEscape | T.Popup.CloseOnReleaseOutside
| T.Popup.CloseOnReleaseOutsideParent
- delegate: MenuItem {}
+ delegate: MenuItem { style: control.style }
contentItem: ListView {
model: control.contentModel
@@ -37,9 +39,10 @@ T.Menu {
background: Rectangle {
implicitWidth: contentItem.childrenRect.width
implicitHeight: contentItem.childrenRect.height
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.popup.background
+ border.color: control.style.popup.background
+ border.width: control.style.borderWidth
+
MouseArea {
// This mouse area is here to eat clicks that are not handled by menu items
// to prevent them going through to the underlying view.
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
index 92de52b44f..16a76c2e64 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
@@ -1,15 +1,17 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Controls 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.MenuItem {
id: control
- property int labelSpacing: StudioTheme.Values.contextMenuLabelSpacing
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property int labelSpacing: control.style.contextMenuLabelSpacing
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -19,7 +21,7 @@ T.MenuItem {
padding: 0
spacing: 0
- horizontalPadding: StudioTheme.Values.contextMenuHorizontalPadding
+ horizontalPadding: control.style.contextMenuHorizontalPadding
action: Action {}
contentItem: Item {
@@ -27,8 +29,9 @@ T.MenuItem {
id: textLabel
text: control.text
font: control.font
- color: control.enabled ? StudioTheme.Values.themeTextColor
- : StudioTheme.Values.themeTextColorDisabled
+ color: control.enabled ? control.highlighted ? control.style.text.selectedText
+ : control.style.text.idle
+ : control.style.text.disabled
anchors.verticalCenter: parent.verticalCenter
}
@@ -42,19 +45,19 @@ T.MenuItem {
Shortcut {
id: shortcut
- property int shortcutWorkaround: control.action.shortcut ? control.action.shortcut : 0
- sequence: shortcutWorkaround
+ property int shortcutWorkaround: control.action.shortcut ?? 0
+ sequence: shortcut.shortcutWorkaround
}
}
}
arrow: T.Label {
id: arrow
- x: parent.width - (StudioTheme.Values.height + arrow.width) / 2
+ x: parent.width - (control.style.controlSize.height + arrow.width) / 2
y: (parent.height - arrow.height) / 2
visible: control.subMenu
text: StudioTheme.Constants.startNode
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
font.pixelSize: 8
font.family: StudioTheme.Constants.iconFont.family
}
@@ -62,13 +65,11 @@ T.MenuItem {
background: Rectangle {
implicitWidth: textLabel.implicitWidth + control.labelSpacing + shortcutLabel.implicitWidth
+ control.leftPadding + control.rightPadding
- implicitHeight: StudioTheme.Values.height
- x: StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: control.menu.width - (StudioTheme.Values.border * 2)
- height: control.height - (StudioTheme.Values.border * 2)
- color: control.down ? control.palette.midlight
- : control.highlighted ? StudioTheme.Values.themeInteraction
- : "transparent"
+ implicitHeight: control.style.controlSize.height
+ x: control.style.borderWidth
+ y: control.style.borderWidth
+ width: (control.menu?.width ?? 0) - (control.style.borderWidth * 2)
+ height: control.height - (control.style.borderWidth * 2)
+ color: control.highlighted ? control.style.interaction : "transparent"
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItemWithIcon.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItemWithIcon.qml
index 14588ad556..e6bd35e8c4 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItemWithIcon.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItemWithIcon.qml
@@ -1,15 +1,17 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Controls 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.MenuItem {
id: control
- property int labelSpacing: StudioTheme.Values.contextMenuLabelSpacing
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property int labelSpacing: control.style.contextMenuLabelSpacing
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -20,7 +22,7 @@ T.MenuItem {
padding: 0
spacing: 0
- horizontalPadding: StudioTheme.Values.contextMenuHorizontalPadding
+ horizontalPadding: control.style.contextMenuHorizontalPadding
action: Action {}
contentItem: Item {
@@ -28,18 +30,18 @@ T.MenuItem {
id: iconLabel
text: control.checked ? StudioTheme.Constants.tickIcon : ""
visible: true
- color: control.enabled ? StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColorDisabled
+ color: control.enabled ? control.highlighted ? control.style.text.selectedText : control.style.text.idle : control.style.text.disabled
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: textLabel
- x: StudioTheme.Values.height
+ x: control.style.squareControlSize.width
text: control.text
font: control.font
- color: control.enabled ? StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColorDisabled
+ color: control.enabled ? control.highlighted ? control.style.text.selectedText : control.style.text.idle : control.style.text.disabled
anchors.verticalCenter: parent.verticalCenter
}
}
@@ -47,11 +49,11 @@ T.MenuItem {
background: Rectangle {
implicitWidth: iconLabel.implicitWidth + textLabel.implicitWidth + control.labelSpacing
+ control.leftPadding + control.rightPadding
- implicitHeight: StudioTheme.Values.height
- x: StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: control.menu.width - (StudioTheme.Values.border * 2)
- height: control.height - (StudioTheme.Values.border * 2)
- color: control.down ? control.palette.midlight : control.highlighted ? StudioTheme.Values.themeInteraction : "transparent"
+ implicitHeight: control.style.controlSize.height
+ x: control.style.borderWidth
+ y: control.style.borderWidth
+ width: control.menu.width - (control.style.borderWidth * 2)
+ height: control.height - (control.style.borderWidth * 2)
+ color: control.highlighted ? control.style.interaction : "transparent"
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuSeparator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuSeparator.qml
index 47ad358b4f..b1c662a65c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuSeparator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuSeparator.qml
@@ -1,13 +1,15 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.MenuSeparator {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
@@ -16,7 +18,7 @@ T.MenuSeparator {
contentItem: Rectangle {
implicitWidth: control.parent.width
- implicitHeight: StudioTheme.Values.border
- color: StudioTheme.Values.themeControlOutline
+ implicitHeight: control.style.borderWidth
+ color: control.style.border.idle
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ProgressBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ProgressBar.qml
index 01e2a3a1c5..6e98d60fc9 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ProgressBar.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ProgressBar.qml
@@ -1,27 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Templates as T
@@ -30,6 +8,8 @@ import StudioTheme 1.0 as StudioTheme
T.ProgressBar {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
@@ -42,13 +22,13 @@ T.ProgressBar {
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
}
background: Rectangle {
implicitWidth: 200
implicitHeight: 6
- color: StudioTheme.Values.themeThumbnailLabelBackground
+ color: control.style.thumbnailLabelBackground
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RadioButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RadioButton.qml
index 04914f1590..d1744ab5da 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RadioButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RadioButton.qml
@@ -1,22 +1,24 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.RadioButton {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias actionIndicator: actionIndicator
// This property is used to indicate the global hover state
- property bool hover: root.hovered && root.enabled
+ property bool hover: control.hovered && control.enabled
property bool edit: false
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property alias labelVisible: radioButtonLabel.visible
property alias labelColor: radioButtonLabel.color
@@ -24,7 +26,7 @@ T.RadioButton {
property alias fontFamily: radioButtonLabel.font.family
property alias fontPixelSize: radioButtonLabel.font.pixelSize
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -32,119 +34,120 @@ T.RadioButton {
implicitContentHeight + topPadding + bottomPadding,
implicitIndicatorHeight + topPadding + bottomPadding)
- spacing: StudioTheme.Values.radioButtonSpacing
+ spacing: control.style.controlSpacing
hoverEnabled: true
activeFocusOnTab: false
ActionIndicator {
id: actionIndicator
- myControl: root
- width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
+ style: control.style
+ __parentControl: control
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
indicator: Rectangle {
id: radioButtonBackground
- implicitWidth: StudioTheme.Values.radioButtonWidth
- implicitHeight: StudioTheme.Values.radioButtonHeight
+ implicitWidth: control.style.squareControlSize.width
+ implicitHeight: control.style.squareControlSize.height
x: actionIndicator.width
y: 0
z: 5
radius: width / 2
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
Rectangle {
id: radioButtonIndicator
x: (parent.width - width) / 2
y: (parent.height - height) / 2
- width: StudioTheme.Values.radioButtonIndicatorWidth
- height: StudioTheme.Values.radioButtonIndicatorHeight
+ width: control.style.radioButtonIndicatorSize.width
+ height: control.style.radioButtonIndicatorSize.height
radius: width / 2
- color: StudioTheme.Values.themeInteraction
- visible: root.checked
+ color: control.style.interaction
+ visible: control.checked
}
}
contentItem: T.Label {
id: radioButtonLabel
- leftPadding: radioButtonBackground.x + radioButtonBackground.width + root.spacing
+ leftPadding: radioButtonBackground.x + radioButtonBackground.width + control.spacing
rightPadding: 0
verticalAlignment: Text.AlignVCenter
- text: root.text
- font: root.font
- color: StudioTheme.Values.themeTextColor
+ text: control.text
+ font: control.font
+ color: control.style.text.idle
visible: text !== ""
}
states: [
State {
name: "default"
- when: root.enabled && !root.hover && !root.pressed && !actionIndicator.hover
+ when: control.enabled && !control.hover && !control.pressed && !actionIndicator.hover
PropertyChanges {
target: radioButtonBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
target: radioButtonIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "globalHover"
- when: actionIndicator.hover && !root.pressed && root.enabled
+ when: actionIndicator.hover && !control.pressed && control.enabled
PropertyChanges {
target: radioButtonBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.globalHover
+ border.color: control.style.border.idle
}
PropertyChanges {
target: radioButtonIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "hover"
- when: root.hover && !actionIndicator.hover && !root.pressed
+ when: control.hover && !actionIndicator.hover && !control.pressed
PropertyChanges {
target: radioButtonBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.hover
+ border.color: control.style.border.hover
}
PropertyChanges {
target: radioButtonIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "press"
- when: root.hover && root.pressed
+ when: control.hover && control.pressed
PropertyChanges {
target: radioButtonBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
target: radioButtonIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
target: radioButtonBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
target: radioButtonIndicator
- color: StudioTheme.Values.themeIconColorDisabled
+ color: control.style.icon.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml
index 60b20b4238..38ea960b88 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSliderPopup.qml
@@ -1,14 +1,16 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Popup {
- id: sliderPopup
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property T.Control __parentControl
property bool drag: slider.pressed
@@ -18,7 +20,7 @@ T.Popup {
| T.Popup.CloseOnReleaseOutsideParent
background: Rectangle {
- color: StudioTheme.Values.themePopupBackground
+ color: control.style.popup.background
border.width: 0
}
@@ -31,41 +33,41 @@ T.Popup {
rightPadding: 3
leftPadding: 3
- from: myControl.realFrom
- value: myControl.realValue
- to: myControl.realTo
+ from: control.__parentControl.realFrom
+ value: control.__parentControl.realValue
+ to: control.__parentControl.realTo
focusPolicy: Qt.NoFocus
handle: Rectangle {
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
y: slider.topPadding + (slider.availableHeight / 2) - (height / 2)
- width: StudioTheme.Values.sliderHandleWidth
- height: StudioTheme.Values.sliderHandleHeight
+ width: control.style.sliderHandleSize.width
+ height: control.style.sliderHandleSize.height
radius: 0
- color: slider.pressed ? StudioTheme.Values.themeSliderHandleInteraction
- : StudioTheme.Values.themeSliderHandle
+ color: slider.pressed ? control.style.slider.handleInteraction
+ : control.style.slider.handle
}
background: Rectangle {
x: slider.leftPadding
y: slider.topPadding + (slider.availableHeight / 2) - (height / 2)
width: slider.availableWidth
- height: StudioTheme.Values.sliderTrackHeight
+ height: control.style.sliderTrackHeight
radius: 0
- color: StudioTheme.Values.themeSliderInactiveTrack
+ color: control.style.slider.inactiveTrack
Rectangle {
width: slider.visualPosition * parent.width
height: parent.height
- color: StudioTheme.Values.themeSliderActiveTrack
+ color: control.style.slider.activeTrack
radius: 0
}
}
onMoved: {
- myControl.realValue = slider.value
- myControl.realValueModified()
+ control.__parentControl.realValue = slider.value
+ control.__parentControl.realValueModified()
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
index dfdd08742a..aba99f75ff 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
@@ -1,12 +1,14 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.SpinBox {
- id: mySpinBox
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property real realFrom: 0.0
property real realTo: 99.0
@@ -19,38 +21,38 @@ T.SpinBox {
property int decimals: 0
property real minStepSize: {
- var tmpMinStepSize = Number((mySpinBox.realStepSize * 0.1).toFixed(mySpinBox.decimals))
- return (tmpMinStepSize) ? tmpMinStepSize : mySpinBox.realStepSize
+ var tmpMinStepSize = Number((control.realStepSize * 0.1).toFixed(control.decimals))
+ return (tmpMinStepSize) ? tmpMinStepSize : control.realStepSize
}
property real maxStepSize: {
- var tmpMaxStepSize = Number((mySpinBox.realStepSize * 10.0).toFixed(mySpinBox.decimals))
- return (tmpMaxStepSize < mySpinBox.realTo) ? tmpMaxStepSize : mySpinBox.realStepSize
+ var tmpMaxStepSize = Number((control.realStepSize * 10.0).toFixed(control.decimals))
+ return (tmpMaxStepSize < control.realTo) ? tmpMaxStepSize : control.realStepSize
}
property bool edit: spinBoxInput.activeFocus
// This property is used to indicate the global hover state
property bool hover: (spinBoxInput.hover || actionIndicator.hover || spinBoxIndicatorUp.hover
|| spinBoxIndicatorDown.hover || sliderIndicator.hover)
- && mySpinBox.enabled
+ && control.enabled
property bool drag: false
property bool sliderDrag: sliderPopup.drag
property bool dirty: false // user modification flag
// TODO Not used anymore. Will be removed when all dependencies were removed.
- property real realDragRange: mySpinBox.realTo - mySpinBox.realFrom
+ property real realDragRange: control.realTo - control.realFrom
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property bool spinBoxIndicatorVisible: true
- property real __spinBoxIndicatorWidth: StudioTheme.Values.spinBoxIndicatorWidth
- property real __spinBoxIndicatorHeight: StudioTheme.Values.spinBoxIndicatorHeight
+ property real __spinBoxIndicatorWidth: control.style.spinBoxIndicatorSize.width
+ property real __spinBoxIndicatorHeight: control.style.spinBoxIndicatorSize.height
property alias sliderIndicatorVisible: sliderIndicator.visible
- property real __sliderIndicatorWidth: StudioTheme.Values.sliderIndicatorWidth
- property real __sliderIndicatorHeight: StudioTheme.Values.sliderIndicatorHeight
+ property real __sliderIndicatorWidth: control.style.squareControlSize.width
+ property real __sliderIndicatorHeight: control.style.squareControlSize.height
property alias __devicePixelRatio: spinBoxInput.devicePixelRatio
property alias pixelsPerUnit: spinBoxInput.pixelsPerUnit
@@ -71,13 +73,13 @@ T.SpinBox {
wheelEnabled: false
hoverEnabled: true
- width: StudioTheme.Values.defaultControlWidth
- height: StudioTheme.Values.defaultControlHeight
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
leftPadding: spinBoxIndicatorDown.x + spinBoxIndicatorDown.width
- rightPadding: sliderIndicator.width + StudioTheme.Values.border
+ rightPadding: sliderIndicator.width + control.style.borderWidth
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
editable: true
// Leave this in for now
@@ -87,107 +89,113 @@ T.SpinBox {
validator: DoubleValidator {
id: doubleValidator
- locale: mySpinBox.locale.name
+ locale: control.locale.name
notation: DoubleValidator.StandardNotation
- decimals: mySpinBox.decimals
- bottom: Math.min(mySpinBox.realFrom, mySpinBox.realTo)
- top: Math.max(mySpinBox.realFrom, mySpinBox.realTo)
+ decimals: control.decimals
+ bottom: Math.min(control.realFrom, control.realTo)
+ top: Math.max(control.realFrom, control.realTo)
}
ActionIndicator {
id: actionIndicator
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? mySpinBox.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? mySpinBox.__actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
up.indicator: RealSpinBoxIndicator {
id: spinBoxIndicatorUp
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
iconFlip: -1
- visible: mySpinBox.spinBoxIndicatorVisible
- onRealPressed: mySpinBox.indicatorPressed()
- onRealReleased: mySpinBox.realIncrease()
- onRealPressAndHold: mySpinBox.realIncrease()
- x: actionIndicator.width + StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorWidth : 0
- height: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorHeight : 0
-
- realEnabled: (mySpinBox.realFrom < mySpinBox.realTo) ? (mySpinBox.realValue < mySpinBox.realTo)
- : (mySpinBox.realValue > mySpinBox.realTo)
+ visible: control.spinBoxIndicatorVisible
+ onRealPressed: control.indicatorPressed()
+ onRealReleased: control.realIncrease()
+ onRealPressAndHold: control.realIncrease()
+ x: actionIndicator.width + control.style.borderWidth
+ y: control.style.borderWidth
+ width: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorWidth : 0
+ height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
+
+ realEnabled: (control.realFrom < control.realTo) ? (control.realValue < control.realTo)
+ : (control.realValue > control.realTo)
}
down.indicator: RealSpinBoxIndicator {
id: spinBoxIndicatorDown
- myControl: mySpinBox
- visible: mySpinBox.spinBoxIndicatorVisible
- onRealPressed: mySpinBox.indicatorPressed()
- onRealReleased: mySpinBox.realDecrease()
- onRealPressAndHold: mySpinBox.realDecrease()
- x: actionIndicator.width + StudioTheme.Values.border
+ style: control.style
+ __parentControl: control
+ visible: control.spinBoxIndicatorVisible
+ onRealPressed: control.indicatorPressed()
+ onRealReleased: control.realDecrease()
+ onRealPressAndHold: control.realDecrease()
+ x: actionIndicator.width + control.style.borderWidth
y: spinBoxIndicatorUp.y + spinBoxIndicatorUp.height
- width: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorWidth : 0
- height: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorHeight : 0
+ width: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorWidth : 0
+ height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
- realEnabled: (mySpinBox.realFrom < mySpinBox.realTo) ? (mySpinBox.realValue > mySpinBox.realFrom)
- : (mySpinBox.realValue < mySpinBox.realFrom)
+ realEnabled: (control.realFrom < control.realTo) ? (control.realValue > control.realFrom)
+ : (control.realValue < control.realFrom)
}
contentItem: RealSpinBoxInput {
id: spinBoxInput
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
validator: doubleValidator
function handleEditingFinished() {
- mySpinBox.focus = false
+ control.focus = false
// Keep the dirty state before calling setValueFromInput(),
// it will be set to false (cleared) internally
- var valueModified = mySpinBox.dirty
+ var valueModified = control.dirty
- mySpinBox.setValueFromInput()
+ control.setValueFromInput()
myTimer.stop()
// Only trigger the signal, if the value was modified
if (valueModified)
- mySpinBox.compressedRealValueModified()
+ control.compressedRealValueModified()
}
onEditingFinished: spinBoxInput.handleEditingFinished()
- onTextEdited: mySpinBox.dirty = true
+ onTextEdited: control.dirty = true
}
background: Rectangle {
id: spinBoxBackground
- color: StudioTheme.Values.themeControlOutline
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
x: actionIndicator.width
- width: mySpinBox.width - actionIndicator.width
- height: mySpinBox.height
+ width: control.width - actionIndicator.width
+ height: control.height
}
CheckIndicator {
id: sliderIndicator
- myControl: mySpinBox
- myPopup: sliderPopup
+ style: control.style
+ __parentControl: control
+ __parentPopup: sliderPopup
x: spinBoxInput.x + spinBoxInput.width
- y: StudioTheme.Values.border
- width: sliderIndicator.visible ? mySpinBox.__sliderIndicatorWidth - StudioTheme.Values.border : 0
- height: sliderIndicator.visible ? mySpinBox.__sliderIndicatorHeight - (StudioTheme.Values.border * 2) : 0
+ y: control.style.borderWidth
+ width: sliderIndicator.visible ? control.__sliderIndicatorWidth - control.style.borderWidth : 0
+ height: sliderIndicator.visible ? control.__sliderIndicatorHeight - (control.style.borderWidth * 2) : 0
visible: false // reasonable default
}
RealSliderPopup {
id: sliderPopup
- myControl: mySpinBox
- x: actionIndicator.width + StudioTheme.Values.border
- y: StudioTheme.Values.height
- width: mySpinBox.width - actionIndicator.width - (StudioTheme.Values.border * 2)
- height: StudioTheme.Values.sliderHeight
+ style: control.style
+ __parentControl: control
+ x: actionIndicator.width + control.style.borderWidth
+ y: control.style.controlSize.height
+ width: control.width - actionIndicator.width - (control.style.borderWidth * 2)
+ height: control.style.smallControlSize.height
enter: Transition {}
exit: Transition {}
@@ -195,21 +203,21 @@ T.SpinBox {
textFromValue: function (value, locale) {
locale.numberOptions = Locale.OmitGroupSeparator
- return Number(mySpinBox.realValue).toLocaleString(locale, 'f', mySpinBox.decimals)
+ return Number(control.realValue).toLocaleString(locale, 'f', control.decimals)
}
valueFromText: function (text, locale) {
- mySpinBox.setRealValue(Number.fromLocaleString(locale, spinBoxInput.text))
+ control.setRealValue(Number.fromLocaleString(locale, spinBoxInput.text))
return 0
}
states: [
State {
name: "default"
- when: mySpinBox.enabled && !mySpinBox.hover && !mySpinBox.hovered
- && !mySpinBox.edit && !mySpinBox.drag && !mySpinBox.sliderDrag
+ when: control.enabled && !control.hover && !control.hovered
+ && !control.edit && !control.drag && !control.sliderDrag
PropertyChanges {
- target: mySpinBox
+ target: control
__wheelEnabled: false
}
PropertyChanges {
@@ -218,15 +226,23 @@ T.SpinBox {
}
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ border.color: control.style.border.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && control.hover && control.hovered
+ && !control.edit && !control.drag && !control.sliderDrag
+ PropertyChanges {
+ target: spinBoxBackground
+ border.color: control.style.border.hover
}
},
State {
name: "edit"
- when: mySpinBox.edit
+ when: control.edit
PropertyChanges {
- target: mySpinBox
+ target: control
__wheelEnabled: true
}
PropertyChanges {
@@ -235,26 +251,23 @@ T.SpinBox {
}
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutline
+ border.color: control.style.border.idle
}
},
State {
name: "drag"
- when: mySpinBox.drag || mySpinBox.sliderDrag
+ when: control.drag || control.sliderDrag
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
},
State {
name: "disable"
- when: !mySpinBox.enabled
+ when: !control.enabled
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlOutlineDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ border.color: control.style.border.disabled
}
}
]
@@ -264,32 +277,32 @@ T.SpinBox {
repeat: false
running: false
interval: 400
- onTriggered: mySpinBox.compressedRealValueModified()
+ onTriggered: control.compressedRealValueModified()
}
onRealValueChanged: {
- mySpinBox.setRealValue(mySpinBox.realValue) // sanitize and clamp realValue
- spinBoxInput.text = mySpinBox.textFromValue(mySpinBox.realValue, mySpinBox.locale)
- mySpinBox.value = 0 // Without setting value back to 0, it can happen that one of
+ control.setRealValue(control.realValue) // sanitize and clamp realValue
+ spinBoxInput.text = control.textFromValue(control.realValue, control.locale)
+ control.value = 0 // Without setting value back to 0, it can happen that one of
// the indicator will be disabled due to range logic.
}
onRealValueModified: myTimer.restart()
onFocusChanged: {
- if (mySpinBox.focus) {
- mySpinBox.dirty = false
+ if (control.focus) {
+ control.dirty = false
} else {
// Make sure displayed value is correct after focus loss, as onEditingFinished
// doesn't trigger when value is something validator doesn't accept.
- spinBoxInput.text = mySpinBox.textFromValue(mySpinBox.realValue, mySpinBox.locale)
+ spinBoxInput.text = control.textFromValue(control.realValue, control.locale)
- if (mySpinBox.dirty)
+ if (control.dirty)
spinBoxInput.handleEditingFinished()
}
}
- onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText
+ onDisplayTextChanged: spinBoxInput.text = control.displayText
onActiveFocusChanged: {
- if (mySpinBox.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
- mySpinBox.preFocusText = spinBoxInput.text
+ if (control.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
+ control.preFocusText = spinBoxInput.text
spinBoxInput.selectAll()
}
}
@@ -299,27 +312,27 @@ T.SpinBox {
event.accepted = true
// Store current step size
- var currStepSize = mySpinBox.realStepSize
+ var currStepSize = control.realStepSize
// Set realStepSize according to used modifier key
if (event.modifiers & Qt.ControlModifier)
- mySpinBox.realStepSize = mySpinBox.minStepSize
+ control.realStepSize = control.minStepSize
if (event.modifiers & Qt.ShiftModifier)
- mySpinBox.realStepSize = mySpinBox.maxStepSize
+ control.realStepSize = control.maxStepSize
if (event.key === Qt.Key_Up)
- mySpinBox.realIncrease()
+ control.realIncrease()
else
- mySpinBox.realDecrease()
+ control.realDecrease()
// Reset realStepSize
- mySpinBox.realStepSize = currStepSize
+ control.realStepSize = currStepSize
}
if (event.key === Qt.Key_Escape) {
- spinBoxInput.text = mySpinBox.preFocusText
- mySpinBox.dirty = true
+ spinBoxInput.text = control.preFocusText
+ control.dirty = true
spinBoxInput.handleEditingFinished()
}
}
@@ -329,60 +342,60 @@ T.SpinBox {
}
function setValueFromInput() {
- if (!mySpinBox.dirty)
+ if (!control.dirty)
return
// FIX: This is a temporary fix for QTBUG-74239
- var currValue = mySpinBox.realValue
+ var currValue = control.realValue
// Call the function but don't use return value. The realValue property
// will be implicitly set inside the function/procedure.
- mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+ control.valueFromText(spinBoxInput.text, control.locale)
- if (mySpinBox.realValue !== currValue) {
- mySpinBox.realValueModified()
+ if (control.realValue !== currValue) {
+ control.realValueModified()
} else {
// Check if input text differs in format from the current value
- var tmpInputValue = mySpinBox.textFromValue(mySpinBox.realValue, mySpinBox.locale)
+ var tmpInputValue = control.textFromValue(control.realValue, control.locale)
if (tmpInputValue !== spinBoxInput.text)
spinBoxInput.text = tmpInputValue
}
- mySpinBox.dirty = false
+ control.dirty = false
}
function setRealValue(value) {
if (Number.isNaN(value))
value = 0
- if (mySpinBox.decimals === 0)
+ if (control.decimals === 0)
value = Math.round(value)
- mySpinBox.realValue = mySpinBox.clamp(value,
- mySpinBox.validator.bottom,
- mySpinBox.validator.top)
+ control.realValue = control.clamp(value,
+ control.validator.bottom,
+ control.validator.top)
}
function realDecrease() {
// Store the current value for comparison
- var currValue = mySpinBox.realValue
- mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+ var currValue = control.realValue
+ control.valueFromText(spinBoxInput.text, control.locale)
- mySpinBox.setRealValue(mySpinBox.realValue - mySpinBox.realStepSize)
+ control.setRealValue(control.realValue - control.realStepSize)
- if (mySpinBox.realValue !== currValue)
- mySpinBox.realValueModified()
+ if (control.realValue !== currValue)
+ control.realValueModified()
}
function realIncrease() {
// Store the current value for comparison
- var currValue = mySpinBox.realValue
- mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+ var currValue = control.realValue
+ control.valueFromText(spinBoxInput.text, control.locale)
- mySpinBox.setRealValue(mySpinBox.realValue + mySpinBox.realStepSize)
+ control.setRealValue(control.realValue + control.realStepSize)
- if (mySpinBox.realValue !== currValue)
- mySpinBox.realValueModified()
+ if (control.realValue !== currValue)
+ control.realValueModified()
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxIndicator.qml
index 8587709201..6bafb9c11e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxIndicator.qml
@@ -1,14 +1,16 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: spinBoxIndicator
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property T.Control __parentControl
property bool hover: spinBoxIndicatorMouseArea.containsMouse
property bool pressed: spinBoxIndicatorMouseArea.containsPress
@@ -21,13 +23,13 @@ Rectangle {
property alias iconFlip: spinBoxIndicatorIconScale.yScale
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
border.width: 0
- onEnabledChanged: syncEnabled()
+ onEnabledChanged: control.syncEnabled()
onRealEnabledChanged: {
- syncEnabled()
- if (spinBoxIndicator.realEnabled === false) {
+ control.syncEnabled()
+ if (control.realEnabled === false) {
pressAndHoldTimer.stop()
spinBoxIndicatorMouseArea.pressedAndHeld = false
}
@@ -36,7 +38,7 @@ Rectangle {
// This function is meant to synchronize enabled with realEnabled to avoid
// the internal logic messing with the actual state.
function syncEnabled() {
- spinBoxIndicator.enabled = spinBoxIndicator.realEnabled
+ control.enabled = control.realEnabled
}
Timer {
@@ -44,7 +46,7 @@ Rectangle {
repeat: true
running: false
interval: 100
- onTriggered: spinBoxIndicator.realPressAndHold()
+ onTriggered: control.realPressAndHold()
}
// This MouseArea is a workaround to avoid some hover state related bugs
@@ -58,26 +60,26 @@ Rectangle {
hoverEnabled: true
pressAndHoldInterval: 500
onPressed: function(mouse) {
- if (myControl.activeFocus)
- spinBoxIndicator.forceActiveFocus()
+ if (control.__parentControl.activeFocus)
+ control.forceActiveFocus()
- spinBoxIndicator.realPressed()
+ control.realPressed()
mouse.accepted = true
}
onPressAndHold: {
pressAndHoldTimer.restart()
- pressedAndHeld = true
+ spinBoxIndicatorMouseArea.pressedAndHeld = true
}
onReleased: function(mouse) {
// Only trigger real released when pressAndHold isn't active
if (!pressAndHoldTimer.running && containsMouse)
- spinBoxIndicator.realReleased()
+ control.realReleased()
pressAndHoldTimer.stop()
mouse.accepted = true
- pressedAndHeld = false
+ spinBoxIndicatorMouseArea.pressedAndHeld = false
}
onEntered: {
- if (pressedAndHeld)
+ if (spinBoxIndicatorMouseArea.pressedAndHeld)
pressAndHoldTimer.restart()
}
onExited: {
@@ -89,10 +91,10 @@ Rectangle {
T.Label {
id: spinBoxIndicatorIcon
text: StudioTheme.Constants.upDownSquare2
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
- font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
+ font.pixelSize: control.style.smallIconFontSize
font.family: StudioTheme.Constants.iconFont.family
anchors.fill: parent
transform: Scale {
@@ -105,54 +107,57 @@ Rectangle {
states: [
State {
name: "default"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.edit
- && !spinBoxIndicator.hover && !myControl.hover && !myControl.drag
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "globalHover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && !spinBoxIndicator.hover && myControl.hover && !myControl.edit
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && control.__parentControl.hover && !control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "hover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.hover && myControl.hover && !spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.hover
+ && control.__parentControl.hover && !control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeIconColorHover
+ color: control.style.icon.hover
}
},
State {
name: "press"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ color: control.style.icon.idle
}
},
State {
name: "edit"
- when: myControl.edit && spinBoxIndicator.enabled
+ when: control.__parentControl.edit && control.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "disable"
- when: !myControl.enabled || !spinBoxIndicator.enabled
+ when: !control.__parentControl.enabled || !control.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
}
]
@@ -161,102 +166,104 @@ Rectangle {
states: [
State {
name: "default"
- when: myControl.enabled && !myControl.edit
- && !spinBoxIndicator.hover && !myControl.hover && !myControl.drag
+ when: control.__parentControl.enabled && !control.__parentControl.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.drag
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "globalHover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && !spinBoxIndicator.hover && myControl.hover && !myControl.edit
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && control.__parentControl.hover && !control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ target: control
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: myControl.enabled && !myControl.drag && spinBoxIndicator.enabled
- && spinBoxIndicator.hover && myControl.hover && !spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && !control.__parentControl.drag
+ && control.enabled && control.hover && control.__parentControl.hover
+ && !control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundHover
+ target: control
+ color: control.style.background.hover
}
},
State {
name: "press"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "edit"
- when: myControl.edit && myControl.enabled && spinBoxIndicator.enabled
+ when: control.__parentControl.edit && control.__parentControl.enabled && control.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "drag"
- when: myControl.drag && myControl.enabled
+ when: control.__parentControl.drag && control.__parentControl.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: control
+ color: control.style.background.interaction
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ target: control
+ color: control.style.background.disabled
}
},
State {
name: "limit"
- when: !spinBoxIndicator.enabled && !spinBoxIndicator.realEnabled && myControl.hover
+ when: !control.enabled && !control.realEnabled && control.__parentControl.hover
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml
index bf752d464b..c9344c4d42 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBoxInput.qml
@@ -1,36 +1,38 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
TextInput {
- id: textInput
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool edit: textInput.activeFocus
+ property T.Control __parentControl
+
+ property bool edit: control.activeFocus
property bool drag: false
- property bool hover: mouseArea.containsMouse && textInput.enabled
+ property bool hover: mouseArea.containsMouse && control.enabled
property int devicePixelRatio: 1
property int pixelsPerUnit: 10
z: 2
- font: myControl.font
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+ font: control.__parentControl.font
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
horizontalAlignment: Qt.AlignRight
verticalAlignment: Qt.AlignVCenter
- leftPadding: StudioTheme.Values.inputHorizontalPadding
- rightPadding: StudioTheme.Values.inputHorizontalPadding
+ leftPadding: control.style.inputHorizontalPadding
+ rightPadding: control.style.inputHorizontalPadding
- readOnly: !myControl.editable
- validator: myControl.validator
- inputMethodHints: myControl.inputMethodHints
+ readOnly: !control.__parentControl.editable
+ validator: control.__parentControl.validator
+ inputMethodHints: control.__parentControl.inputMethodHints
selectByMouse: false
activeFocusOnPress: false
clip: true
@@ -38,16 +40,16 @@ TextInput {
// TextInput focus needs to be set to activeFocus whenever it changes,
// otherwise TextInput will get activeFocus whenever the parent SpinBox gets
// activeFocus. This will lead to weird side effects.
- onActiveFocusChanged: textInput.focus = textInput.activeFocus
+ onActiveFocusChanged: control.focus = control.activeFocus
Rectangle {
id: textInputBackground
x: 0
- y: StudioTheme.Values.border
+ y: control.style.borderWidth
z: -1
- width: textInput.width
- height: StudioTheme.Values.height - (StudioTheme.Values.border * 2)
- color: StudioTheme.Values.themeControlBackground
+ width: control.width
+ height: control.style.controlSize.height - (control.style.borderWidth * 2)
+ color: control.style.background.idle
border.width: 0
}
@@ -57,22 +59,22 @@ TextInput {
event.accepted = true
if (event.modifiers & Qt.ControlModifier) {
- mouseArea.stepSize = myControl.minStepSize
+ mouseArea.stepSize = control.__parentControl.minStepSize
mouseArea.calcValue()
- myControl.realValueModified()
+ control.__parentControl.realValueModified()
}
if (event.modifiers & Qt.ShiftModifier) {
- mouseArea.stepSize = myControl.maxStepSize
+ mouseArea.stepSize = control.__parentControl.maxStepSize
mouseArea.calcValue()
- myControl.realValueModified()
+ control.__parentControl.realValueModified()
}
}
Keys.onReleased: function(event) {
event.accepted = true
- mouseArea.stepSize = myControl.realStepSize
+ mouseArea.stepSize = control.__parentControl.realStepSize
mouseArea.calcValue()
- myControl.realValueModified()
+ control.__parentControl.realValueModified()
}
}
@@ -84,14 +86,14 @@ TextInput {
MouseArea {
id: mouseArea
- property real stepSize: myControl.realStepSize
+ property real stepSize: control.__parentControl.realStepSize
// Properties to store the state of a drag operation
property bool dragging: false
property bool hasDragged: false
property bool potentialDragStart: false
- property real initialValue: myControl.realValue // value on drag operation starts
+ property real initialValue: control.__parentControl.realValue // value on drag operation starts
property real pressStartX: 0.0
property real dragStartX: 0.0
@@ -101,7 +103,7 @@ TextInput {
property real totalUnits: 0.0 // total number of units dragged
property real units: 0.0
- property real __pixelsPerUnit: textInput.devicePixelRatio * textInput.pixelsPerUnit
+ property real __pixelsPerUnit: control.devicePixelRatio * control.pixelsPerUnit
anchors.fill: parent
enabled: true
@@ -113,21 +115,21 @@ TextInput {
onPositionChanged: function(mouse) {
if (!mouseArea.dragging
- && !myControl.edit
+ && !control.__parentControl.edit
&& Math.abs(mouseArea.pressStartX - mouse.x) > StudioTheme.Values.dragThreshold
&& mouse.buttons === Qt.LeftButton
&& mouseArea.potentialDragStart) {
mouseArea.dragging = true
mouseArea.potentialDragStart = false
- mouseArea.initialValue = myControl.realValue
+ mouseArea.initialValue = control.__parentControl.realValue
mouseArea.cursorShape = Qt.ClosedHandCursor
mouseArea.dragStartX = mouse.x
- myControl.drag = true
- myControl.dragStarted()
+ control.__parentControl.drag = true
+ control.__parentControl.dragStarted()
// Force focus on the non visible component to receive key events
dragModifierWorkaround.forceActiveFocus()
- textInput.deselect()
+ control.deselect()
}
if (!mouseArea.dragging)
@@ -152,11 +154,11 @@ TextInput {
mouseArea.translationX += translationX
mouseArea.calcValue()
- myControl.realValueModified()
+ control.__parentControl.realValueModified()
}
onClicked: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
if (mouseArea.hasDragged) {
@@ -164,12 +166,12 @@ TextInput {
return
}
- textInput.forceActiveFocus()
- textInput.deselect() // QTBUG-75862
+ control.forceActiveFocus()
+ control.deselect() // QTBUG-75862
}
onPressed: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
mouseArea.potentialDragStart = true
@@ -177,7 +179,7 @@ TextInput {
}
onReleased: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
mouseArea.endDrag()
@@ -190,18 +192,18 @@ TextInput {
mouseArea.dragging = false
mouseArea.hasDragged = true
- if (myControl.compressedValueTimer.running) {
- myControl.compressedValueTimer.stop()
+ if (control.__parentControl.compressedValueTimer.running) {
+ control.__parentControl.compressedValueTimer.stop()
mouseArea.calcValue()
- myControl.compressedRealValueModified()
+ control.__parentControl.compressedRealValueModified()
}
mouseArea.cursorShape = Qt.PointingHandCursor
- myControl.drag = false
- myControl.dragEnded()
+ control.__parentControl.drag = false
+ control.__parentControl.dragEnded()
// Avoid active focus on the component after dragging
dragModifierWorkaround.focus = false
- textInput.focus = false
- myControl.focus = false
+ control.focus = false
+ control.__parentControl.focus = false
mouseArea.translationX = 0.0
mouseArea.units = 0.0
@@ -209,47 +211,48 @@ TextInput {
}
function calcValue() {
- var minUnit = (myControl.realFrom - mouseArea.initialValue) / mouseArea.stepSize
- var maxUnit = (myControl.realTo - mouseArea.initialValue) / mouseArea.stepSize
+ var minUnit = (control.__parentControl.realFrom - mouseArea.initialValue) / mouseArea.stepSize
+ var maxUnit = (control.__parentControl.realTo - mouseArea.initialValue) / mouseArea.stepSize
var units = Math.trunc(mouseArea.translationX / mouseArea.__pixelsPerUnit)
mouseArea.units = Math.min(Math.max(mouseArea.totalUnits + units, minUnit), maxUnit)
- myControl.setRealValue(mouseArea.initialValue + (mouseArea.units * mouseArea.stepSize))
+ control.__parentControl.setRealValue(mouseArea.initialValue + (mouseArea.units * mouseArea.stepSize))
if (mouseArea.dragging)
- myControl.dragging()
+ control.__parentControl.dragging()
}
onWheel: function(wheel) {
- if (!myControl.__wheelEnabled) {
+ if (!control.__parentControl.__wheelEnabled) {
wheel.accepted = false
return
}
// Set stepSize according to used modifier key
if (wheel.modifiers & Qt.ControlModifier)
- mouseArea.stepSize = myControl.minStepSize
+ mouseArea.stepSize = control.__parentControl.minStepSize
if (wheel.modifiers & Qt.ShiftModifier)
- mouseArea.stepSize = myControl.maxStepSize
+ mouseArea.stepSize = control.__parentControl.maxStepSize
- myControl.valueFromText(textInput.text, myControl.locale)
- myControl.setRealValue(myControl.realValue + (wheel.angleDelta.y / 120.0 * mouseArea.stepSize))
- myControl.realValueModified()
+ control.__parentControl.valueFromText(control.text, control.__parentControl.locale)
+ control.__parentControl.setRealValue(__parentControl.realValue + (wheel.angleDelta.y / 120.0 * mouseArea.stepSize))
+ control.__parentControl.realValueModified()
// Reset stepSize
- mouseArea.stepSize = myControl.realStepSize
+ mouseArea.stepSize = control.__parentControl.realStepSize
}
}
states: [
State {
name: "default"
- when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover
- && !myControl.drag && !myControl.sliderDrag
+ when: control.__parentControl.enabled && !control.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.drag
+ && !control.__parentControl.sliderDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
}
PropertyChanges {
target: mouseArea
@@ -258,27 +261,28 @@ TextInput {
},
State {
name: "globalHover"
- when: myControl.hover && !textInput.hover
- && !textInput.edit && !myControl.drag
+ when: control.__parentControl.hover && !control.hover
+ && !control.edit && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: textInput.hover && myControl.hover && !textInput.edit && !myControl.drag
+ when: control.hover && control.__parentControl.hover && !control.edit
+ && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: control.style.background.hover
}
},
State {
name: "edit"
- when: textInput.edit && !myControl.drag
+ when: control.edit && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ color: control.style.background.interaction
}
PropertyChanges {
target: mouseArea
@@ -287,38 +291,38 @@ TextInput {
},
State {
name: "drag"
- when: myControl.drag
+ when: control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ color: control.style.background.interaction
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "sliderDrag"
- when: myControl.sliderDrag
+ when: control.__parentControl.sliderDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ color: control.style.background.disabled
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeTextColorDisabled
+ target: control
+ color: control.style.text.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollBar.qml
index e761c32541..7c1126e90d 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollBar.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollBar.qml
@@ -1,13 +1,15 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.ScrollBar {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
// This needs to be set, when using T.ScrollBar
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -31,11 +33,11 @@ T.ScrollBar {
implicitWidth: 4
implicitHeight: 4
radius: width / 2 // TODO 0
- color: StudioTheme.Values.themeScrollBarHandle
+ color: control.style.scrollBar.handle
}
background: Rectangle {
id: controlTrack
- color: StudioTheme.Values.themeScrollBarTrack
+ color: control.style.scrollBar.track
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollView.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollView.qml
index 4ee53fa0e7..bf71dfbc28 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollView.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ScrollView.qml
@@ -1,13 +1,15 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.ScrollView {
id: control
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
property alias horizontalThickness: horizontalScrollBar.height
property alias verticalThickness: verticalScrollBar.width
property bool bothVisible: verticalScrollBar.visible
@@ -20,20 +22,22 @@ T.ScrollView {
ScrollBar.vertical: ScrollBar {
id: verticalScrollBar
+ style: control.style
parent: control
- x: control.width - verticalScrollBar.width - StudioTheme.Values.border
- y: StudioTheme.Values.border
- height: control.availableHeight - (2 * StudioTheme.Values.border)
+ x: control.width - verticalScrollBar.width - control.style.borderWidth
+ y: control.style.borderWidth
+ height: control.availableHeight - (2 * control.style.borderWidth)
- (control.bothVisible ? control.horizontalThickness : 0)
active: control.ScrollBar.horizontal.active
}
ScrollBar.horizontal: ScrollBar {
id: horizontalScrollBar
+ style: control.style
parent: control
- x: StudioTheme.Values.border
- y: control.height - horizontalScrollBar.height - StudioTheme.Values.border
- width: control.availableWidth - (2 * StudioTheme.Values.border)
+ x: control.style.borderWidth
+ y: control.height - horizontalScrollBar.height - control.style.borderWidth
+ width: control.availableWidth - (2 * control.style.borderWidth)
- (control.bothVisible ? control.verticalThickness : 0)
active: control.ScrollBar.vertical.active
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml
index e84880617c..3449fda86a 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SearchBox.qml
@@ -1,146 +1,182 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Controls 2.15
+import QtQuick
+import QtQuick.Templates as T
import QtQuickDesignerTheme 1.0
import StudioTheme 1.0 as StudioTheme
-Item {
- id: root
+T.TextField {
+ id: control
- property alias text: searchFilterText.text
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- signal searchChanged(string searchText);
+ signal searchChanged(string searchText)
- function clear()
- {
- searchFilterText.text = "";
+ function isEmpty() {
+ return control.text === ""
}
- function isEmpty()
- {
- return searchFilterText.text === "";
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
+
+ horizontalAlignment: Qt.AlignLeft
+ verticalAlignment: Qt.AlignVCenter
+
+ leftPadding: 32
+ rightPadding: 30
+
+ font.pixelSize: control.style.baseFontSize
+
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
+ placeholderTextColor: control.style.text.placeholder
+
+ placeholderText: qsTr("Search")
+
+ selectByMouse: true
+ readOnly: false
+ hoverEnabled: true
+ clip: true
+
+ Text {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ visible: !control.length && !control.preeditText
+ && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
}
- implicitWidth: searchFilterText.width
- implicitHeight: searchFilterText.height
-
- TextField {
- id: searchFilterText
-
- placeholderText: qsTr("Search")
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
- background: Rectangle {
- id: textFieldBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
-
- Behavior on color {
- ColorAnimation {
- duration: StudioTheme.Values.hoverDuration
- easing.type: StudioTheme.Values.hoverEasing
- }
+ background: Rectangle {
+ id: textFieldBackground
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
+ radius: control.style.radius
+
+ /* TODO: Lets do this when the widget controls are removed so they remain consistent
+ Behavior on color {
+ ColorAnimation {
+ duration: StudioTheme.Values.hoverDuration
+ easing.type: StudioTheme.Values.hoverEasing
}
}
+ */
+ }
- height: StudioTheme.Values.defaultControlHeight
+ onTextChanged: control.searchChanged(text)
- leftPadding: 32
- rightPadding: 30
- topPadding: 6
+ T.Label {
+ id: searchIcon
+ text: StudioTheme.Constants.search_small
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: control.style.baseIconFontSize
anchors.left: parent.left
+ anchors.leftMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ color: control.style.icon.idle
+ }
+
+ Rectangle { // x button
+ width: 16
+ height: 15
anchors.right: parent.right
- anchors.leftMargin: 5
anchors.rightMargin: 5
- selectByMouse: true
- hoverEnabled: true
+ anchors.verticalCenter: parent.verticalCenter
+ visible: control.text !== ""
+ color: xMouseArea.containsMouse ? control.style.panel.background : "transparent"
- onTextChanged: root.searchChanged(text)
-
- Label {
- text: StudioTheme.Constants.search
+ T.Label {
+ text: StudioTheme.Constants.close_small
font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
- anchors.left: parent.left
- anchors.leftMargin: 7
- anchors.verticalCenter: parent.verticalCenter
- color: StudioTheme.Values.themeIconColor
+ font.pixelSize: control.style.baseIconFontSize
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ anchors.centerIn: parent
+ color: control.style.icon.idle
}
- Rectangle { // x button
- width: 16
- height: 15
- anchors.right: parent.right
- anchors.rightMargin: 5
- anchors.verticalCenter: parent.verticalCenter
- visible: searchFilterText.text !== ""
- color: xMouseArea.containsMouse ? StudioTheme.Values.themePanelBackground
- : "transparent"
-
- Label {
- text: StudioTheme.Constants.closeCross
- font.family: StudioTheme.Constants.iconFont.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- anchors.centerIn: parent
- color: StudioTheme.Values.themeIconColor
- }
-
- MouseArea {
- id: xMouseArea
- hoverEnabled: true
- anchors.fill: parent
- onClicked: searchFilterText.text = ""
- }
+ MouseArea {
+ id: xMouseArea
+ hoverEnabled: true
+ anchors.fill: parent
+ onClicked: control.text = ""
}
+ }
- states: [
- State {
- name: "default"
- when: !searchFilterText.hovered && !searchFilterText.activeFocus
- PropertyChanges {
- target: textFieldBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- }
- PropertyChanges {
- target: searchFilterText
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
- }
- },
- State {
- name: "hover"
- when: root.enabled && searchFilterText.hovered && !searchFilterText.activeFocus
- PropertyChanges {
- target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
- }
-
- PropertyChanges {
- target: searchFilterText
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
- }
- },
- State {
- name: "edit"
- when: searchFilterText.activeFocus
- PropertyChanges {
- target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
- }
- PropertyChanges {
- target: searchFilterText
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction
- }
+ states: [
+ State {
+ name: "default"
+ when: control.enabled && !control.hovered && !control.activeFocus
+ PropertyChanges {
+ target: textFieldBackground
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
- ]
- }
+ PropertyChanges {
+ target: control
+ placeholderTextColor: control.style.text.placeholder
+ }
+ PropertyChanges {
+ target: searchIcon
+ color: control.style.icon.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && control.hovered && !control.activeFocus
+ PropertyChanges {
+ target: textFieldBackground
+ color: control.style.background.hover
+ border.color: control.style.border.hover
+ }
+ PropertyChanges {
+ target: control
+ placeholderTextColor: control.style.text.placeholderHover
+ }
+ PropertyChanges {
+ target: searchIcon
+ color: control.style.icon.idle
+ }
+ },
+ State {
+ name: "edit"
+ when: control.enabled && control.activeFocus
+ PropertyChanges {
+ target: textFieldBackground
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
+ }
+ PropertyChanges {
+ target: control
+ placeholderTextColor: control.style.text.placeholderInteraction
+ }
+ PropertyChanges {
+ target: searchIcon
+ color: control.style.icon.idle
+ }
+ },
+ State {
+ name: "disabled"
+ when: !control.enabled
+ PropertyChanges {
+ target: control
+ placeholderTextColor: control.style.text.disabled
+ }
+ PropertyChanges {
+ target: searchIcon
+ color: control.style.icon.disabled
+ }
+ }
+ ]
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SecondColumnLayout.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SecondColumnLayout.qml
index e35317d014..c90884f919 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SecondColumnLayout.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SecondColumnLayout.qml
@@ -1,8 +1,8 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Layouts
RowLayout {
Layout.fillWidth: true
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml
index 188ca3bee6..5b2fc32845 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml
@@ -1,12 +1,15 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Layouts
import StudioTheme 1.0 as StudioTheme
Item {
- id: section
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
property alias caption: label.text
property alias captionPixelSize: label.font.pixelSize
property alias captionColor: header.color
@@ -23,34 +26,36 @@ Item {
id: header
anchors.left: parent.left
anchors.right: parent.right
- height: StudioTheme.Values.sectionHeadHeight
- color: StudioTheme.Values.themeSectionHeadBackground
+ height: control.style.sectionHeadHeight
+ color: control.style.section.head
SectionLabel {
id: label
+ style: control.style
anchors.verticalCenter: parent.verticalCenter
- color: StudioTheme.Values.themeTextColor
+ color: control.style.text.idle
x: 22
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
font.capitalization: Font.AllUppercase
}
SectionLabel {
id: arrow
- width: StudioTheme.Values.spinControlIconSizeMulti
- height: StudioTheme.Values.spinControlIconSizeMulti
+ style: control.style
+ width: control.style.smallIconSize.width
+ height: control.style.smallIconSize.height
text: StudioTheme.Constants.sectionToggle
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
renderType: Text.NativeRendering
anchors.left: parent.left
anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter
- font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
+ font.pixelSize: control.style.smallIconFontSize
font.family: StudioTheme.Constants.iconFont.family
Behavior on rotation {
NumberAnimation {
easing.type: Easing.OutCubic
- duration: section.animationDuration
+ duration: control.animationDuration
}
}
}
@@ -58,9 +63,9 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: {
- section.expanded = !section.expanded
- if (!section.expanded) // TODO
- section.forceActiveFocus()
+ control.expanded = !control.expanded
+ if (!control.expanded) // TODO
+ control.forceActiveFocus()
}
}
}
@@ -73,7 +78,7 @@ Item {
Row {
id: topRow
- height: StudioTheme.Values.sectionHeadSpacerHeight
+ height: control.style.sectionHeadSpacerHeight
anchors.top: header.bottom
}
@@ -88,21 +93,21 @@ Item {
Row {
id: bottomRow
- height: StudioTheme.Values.sectionHeadSpacerHeight
+ height: control.style.sectionHeadSpacerHeight
anchors.top: column.bottom
}
Behavior on implicitHeight {
NumberAnimation {
easing.type: Easing.OutCubic
- duration: section.animationDuration
+ duration: control.animationDuration
}
}
states: [
State {
name: "Expanded"
- when: section.expanded
+ when: control.expanded
PropertyChanges {
target: arrow
rotation: 0
@@ -110,9 +115,9 @@ Item {
},
State {
name: "Collapsed"
- when: !section.expanded
+ when: !control.expanded
PropertyChanges {
- target: section
+ target: control
implicitHeight: header.height
}
PropertyChanges {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml
index 1346581bd5..b8586d9621 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml
@@ -1,17 +1,19 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Label {
- id: label
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
width: Math.max(Math.min(240, parent.width - 220), 90)
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.myFontSize // TODO
+ color: control.style.text.idle
+ font.pixelSize: control.style.baseFontSize
elide: Text.ElideRight
Layout.preferredWidth: width
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLayout.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLayout.qml
index 1710b76066..ddd4bf1ac9 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLayout.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLayout.qml
@@ -1,13 +1,17 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Layouts
import StudioTheme 1.0 as StudioTheme
GridLayout {
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
columns: 2
- columnSpacing: StudioTheme.Values.sectionColumnSpacing
- rowSpacing: StudioTheme.Values.sectionRowSpacing
+ columnSpacing: control.style.sectionColumnSpacing
+ rowSpacing: control.style.sectionRowSpacing
width: parent.width - 16 // TODO parameterize
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Slider.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Slider.qml
index 8bf54b577e..3cd5266dce 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Slider.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Slider.qml
@@ -1,13 +1,15 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Shapes 1.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Shapes
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Slider {
- id: slider
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property int decimals: 0
property bool labels: true
@@ -15,66 +17,68 @@ T.Slider {
property real tickMarkStepSize: 0.0 // StepSize bug QTBUG-76136
property real tickMarkWidth: 1.0
property real tickMarkHeight: 4.0
- readonly property int tickMarkCount: tickMarkStepSize
- !== 0.0 ? (to - from) / tickMarkStepSize + 1 : 0
- readonly property real tickMarkSpacing: tickMarkCount
- !== 0 ? (sliderTrack.width - tickMarkWidth
- * tickMarkCount) / (tickMarkCount - 1) : 0.0
+ readonly property int tickMarkCount: control.tickMarkStepSize !== 0.0
+ ? (control.to - control.from) / control.tickMarkStepSize + 1 : 0
+ readonly property real tickMarkSpacing: control.tickMarkCount !== 0
+ ? (sliderTrack.width - control.tickMarkWidth
+ * control.tickMarkCount) / (control.tickMarkCount - 1) : 0.0
- property string __activeColor: StudioTheme.Values.themeSliderActiveTrack
- property string __inactiveColor: StudioTheme.Values.themeSliderInactiveTrack
+ property string __activeColor: control.style.slider.activeTrack
+ property string __inactiveColor: control.style.slider.inactiveTrack
property bool hover: false // This property is used to indicate the global hover state
- property bool edit: slider.activeFocus
+ property bool edit: control.activeFocus
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitHandleWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitHandleHeight + topPadding + bottomPadding,
- StudioTheme.Values.height)
+ control.style.controlSize.height)
padding: 0
leftPadding: actionIndicator.width
- - (actionIndicatorVisible ? StudioTheme.Values.border
- - StudioTheme.Values.sliderPadding : 0)
+ - (control.actionIndicatorVisible ? control.style.borderWidth
+ - control.style.sliderPadding : 0)
wheelEnabled: false
ActionIndicator {
id: actionIndicator
- myControl: slider
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? __actionIndicatorWidth : 0
- height: actionIndicator.visible ? __actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
handle: Rectangle {
id: sliderHandle
- x: slider.leftPadding + (slider.visualPosition * slider.availableWidth)
+ x: control.leftPadding + (control.visualPosition * control.availableWidth)
- (sliderHandle.width / 2)
- y: slider.topPadding + (slider.availableHeight / 2) - (sliderHandle.height / 2)
+ y: control.topPadding + (control.availableHeight / 2) - (sliderHandle.height / 2)
z: 20
- implicitWidth: StudioTheme.Values.sliderHandleWidth
- implicitHeight: StudioTheme.Values.sliderHandleHeight
- color: StudioTheme.Values.themeSliderHandle
+ implicitWidth: control.style.sliderHandleSize.width
+ implicitHeight: control.style.sliderHandleSize.height
+ color: control.style.slider.handle
Shape {
id: sliderHandleLabelPointer
- property real __width: StudioTheme.Values.sliderPointerWidth
- property real __height: StudioTheme.Values.sliderPointerHeight
+ property real __width: control.style.sliderPointerSize.width
+ property real __height: control.style.sliderPointerSize.height
property bool antiAlias: true
- layer.enabled: antiAlias
- layer.smooth: antiAlias
- layer.textureSize: Qt.size(width * 2, height * 2)
+ layer.enabled: sliderHandleLabelPointer.antiAlias
+ layer.smooth: sliderHandleLabelPointer.antiAlias
+ layer.textureSize: Qt.size(sliderHandleLabelPointer.width * 2,
+ sliderHandleLabelPointer.height * 2)
- implicitWidth: __width
- implicitHeight: __height
+ implicitWidth: sliderHandleLabelPointer.__width
+ implicitHeight: sliderHandleLabelPointer.__height
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: sliderHandleLabelBackground.bottom
@@ -83,7 +87,7 @@ T.Slider {
id: sliderHandleLabelPointerPath
strokeColor: "transparent"
strokeWidth: 0
- fillColor: StudioTheme.Values.themeInteraction
+ fillColor: control.style.interaction
startX: 0
startY: 0
@@ -102,20 +106,20 @@ T.Slider {
Rectangle {
id: sliderHandleLabelBackground
x: -(sliderHandleLabelBackground.width / 2) + (sliderHandle.width / 2)
- width: makeEven(
- sliderHandleLabel.width + StudioTheme.Values.inputHorizontalPadding)
+ width: control.makeEven(
+ sliderHandleLabel.width + control.style.inputHorizontalPadding)
height: sliderHandleLabel.height
anchors.bottom: parent.top
- anchors.bottomMargin: StudioTheme.Values.sliderMargin
- color: StudioTheme.Values.themeInteraction
+ anchors.bottomMargin: control.style.sliderMargin
+ color: control.style.interaction
Text {
id: sliderHandleLabel
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
- text: Number.parseFloat(slider.value).toFixed(slider.decimals)
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.sliderFontSize
+ text: Number.parseFloat(control.value).toFixed(control.decimals)
+ color: control.style.text.idle
+ font.pixelSize: control.style.smallFontSize
}
}
}
@@ -127,16 +131,16 @@ T.Slider {
background: Rectangle {
id: sliderTrack
- x: slider.leftPadding
- y: slider.topPadding + slider.availableHeight / 2 - height / 2
- width: slider.availableWidth
- height: StudioTheme.Values.sliderTrackHeight
- color: __inactiveColor
+ x: control.leftPadding
+ y: control.topPadding + control.availableHeight / 2 - sliderTrack.height / 2
+ width: control.availableWidth
+ height: control.style.sliderTrackHeight
+ color: control.__inactiveColor
Rectangle {
- width: slider.visualPosition * parent.width
+ width: control.visualPosition * parent.width
height: parent.height
- color: __activeColor
+ color: control.__activeColor
}
}
@@ -148,36 +152,37 @@ T.Slider {
Text {
id: tickmarkFromLabel
x: 0
- y: StudioTheme.Values.sliderPadding
- text: Number.parseFloat(slider.from).toFixed(slider.decimals)
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.sliderFontSize
- visible: slider.labels
+ y: control.style.sliderPadding
+ text: Number.parseFloat(control.from).toFixed(control.decimals)
+ color: control.style.text.idle
+ font.pixelSize: control.style.smallFontSize
+ visible: control.labels
}
Text {
id: tickmarkToLabel
- x: slider.availableWidth - width
- y: StudioTheme.Values.sliderPadding
- text: Number.parseFloat(slider.to).toFixed(slider.decimals)
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: StudioTheme.Values.sliderFontSize
- visible: slider.labels
+ x: control.availableWidth - tickmarkToLabel.width
+ y: control.style.sliderPadding
+ text: Number.parseFloat(control.to).toFixed(control.decimals)
+ color: control.style.text.idle
+ font.pixelSize: control.style.smallFontSize
+ visible: control.labels
}
Row {
id: tickmarkRow
- spacing: tickMarkSpacing
- visible: slider.tickMarks
+ spacing: control.tickMarkSpacing
+ visible: control.tickMarks
Repeater {
id: tickmarkRepeater
- model: tickMarkCount
+ model: control.tickMarkCount
delegate: Rectangle {
- implicitWidth: tickMarkWidth
- implicitHeight: StudioTheme.Values.sliderTrackHeight
- color: x < (slider.visualPosition
- * slider.availableWidth) ? __inactiveColor : __activeColor
+ implicitWidth: control.tickMarkWidth
+ implicitHeight: control.style.sliderTrackHeight
+ color: x < (control.visualPosition
+ * control.availableWidth) ? control.__inactiveColor
+ : control.__activeColor
}
}
}
@@ -187,85 +192,85 @@ T.Slider {
id: mouseArea
x: actionIndicator.width
y: 0
- width: slider.width - actionIndicator.width
- height: slider.height
+ width: control.width - actionIndicator.width
+ height: control.height
enabled: true
hoverEnabled: true
propagateComposedEvents: true
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
// Sets the global hover
- onContainsMouseChanged: slider.hover = mouseArea.containsMouse
+ onContainsMouseChanged: control.hover = mouseArea.containsMouse
onPressed: function(mouse) { mouse.accepted = false }
}
states: [
State {
name: "default"
- when: slider.enabled && !slider.hover && !slider.edit
+ when: control.enabled && !control.hover && !control.edit
PropertyChanges {
- target: slider
+ target: control
wheelEnabled: false
}
},
State {
name: "hover"
- when: slider.enabled && slider.hover && !slider.edit
+ when: control.enabled && control.hover && !control.edit
PropertyChanges {
- target: slider
- __activeColor: StudioTheme.Values.themeSliderActiveTrackHover
- __inactiveColor: StudioTheme.Values.themeSliderInactiveTrackHover
+ target: control
+ __activeColor: control.style.slider.activeTrackHover
+ __inactiveColor: control.style.slider.inactiveTrackHover
}
PropertyChanges {
target: sliderHandle
- color: StudioTheme.Values.themeSliderHandleHover
+ color: control.style.slider.handleHover
}
},
State {
name: "focus"
- when: slider.enabled && slider.edit
+ when: control.enabled && control.edit
PropertyChanges {
- target: slider
+ target: control
wheelEnabled: true
- __activeColor: StudioTheme.Values.themeSliderActiveTrackFocus
- __inactiveColor: StudioTheme.Values.themeSliderInactiveTrackFocus
+ __activeColor: control.style.slider.activeTrackFocus
+ __inactiveColor: control.style.slider.inactiveTrackFocus
}
PropertyChanges {
target: sliderHandle
- color: StudioTheme.Values.themeSliderHandleFocus
+ color: control.style.slider.handleFocus
}
},
State {
name: "disable"
- when: !slider.enabled
+ when: !control.enabled
PropertyChanges {
target: tickmarkFromLabel
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.text.disabled
}
PropertyChanges {
target: tickmarkToLabel
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.text.disabled
}
PropertyChanges {
target: sliderHandleLabel
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.text.disabled
}
PropertyChanges {
- target: slider
- __activeColor: StudioTheme.Values.themeControlBackgroundDisabled
- __inactiveColor: StudioTheme.Values.themeControlBackgroundDisabled
+ target: control
+ __activeColor: control.style.background.disabled
+ __inactiveColor: control.style.background.disabled
}
PropertyChanges {
target: sliderHandleLabelBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ color: control.style.background.disabled
}
PropertyChanges {
target: sliderHandleLabelPointerPath
- fillColor: StudioTheme.Values.themeControlBackgroundDisabled
+ fillColor: control.style.background.disabled
}
PropertyChanges {
target: sliderHandle
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ color: control.style.background.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SliderPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SliderPopup.qml
index e550d52c17..aea63df482 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SliderPopup.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SliderPopup.qml
@@ -1,14 +1,16 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Popup {
- id: sliderPopup
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property T.Control __parentControl
property bool drag: slider.pressed
@@ -18,7 +20,7 @@ T.Popup {
| T.Popup.CloseOnReleaseOutsideParent
background: Rectangle {
- color: StudioTheme.Values.themePopupBackground
+ color: control.style.popup.background
border.width: 0
}
@@ -31,54 +33,54 @@ T.Popup {
rightPadding: 3
leftPadding: 3
- from: myControl.from
- value: myControl.value
- to: myControl.to
+ from: control.__parentControl.from
+ value: control.__parentControl.value
+ to: control.__parentControl.to
focusPolicy: Qt.NoFocus
handle: Rectangle {
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
y: slider.topPadding + (slider.availableHeight / 2) - (height / 2)
- width: StudioTheme.Values.sliderHandleWidth
- height: StudioTheme.Values.sliderHandleHeight
+ width: control.style.sliderHandleSize.width
+ height: control.style.sliderHandleSize.height
radius: 0
- color: slider.pressed ? StudioTheme.Values.themeSliderHandleInteraction
- : StudioTheme.Values.themeSliderHandle
+ color: slider.pressed ? control.style.slider.handleInteraction
+ : control.style.slider.handle
}
background: Rectangle {
x: slider.leftPadding
y: slider.topPadding + (slider.availableHeight / 2) - (height / 2)
width: slider.availableWidth
- height: StudioTheme.Values.sliderTrackHeight
+ height: control.style.sliderTrackHeight
radius: 0
- color: StudioTheme.Values.themeSliderInactiveTrack
+ color: control.style.slider.inactiveTrack
Rectangle {
width: slider.visualPosition * parent.width
height: parent.height
- color: StudioTheme.Values.themeSliderActiveTrack
+ color: control.style.slider.activeTrack
radius: 0
}
}
onMoved: {
- var currValue = myControl.value
- myControl.value = slider.value
+ var currValue = control.__parentControl.value
+ control.__parentControl.value = slider.value
- if (currValue !== myControl.value)
- myControl.valueModified()
+ if (currValue !== control.__parentControl.value)
+ control.__parentControl.valueModified()
}
}
onOpened: {
// Check if value is in sync with text input, if not sync it!
- var val = myControl.valueFromText(myControl.contentItem.text,
- myControl.locale)
- if (myControl.value !== val) {
- myControl.value = val
- myControl.valueModified()
+ var val = control.__parentControl.valueFromText(control.__parentControl.contentItem.text,
+ control.__parentControl.locale)
+ if (control.__parentControl.value !== val) {
+ control.__parentControl.value = val
+ control.__parentControl.valueModified()
}
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml
index 8a5a5e8c51..fb3959f4cf 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SortFilterModel.qml
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBox.qml
index 9ba334bbf5..a0c7244c79 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBox.qml
@@ -1,18 +1,20 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.SpinBox {
- id: mySpinBox
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias labelColor: spinBoxInput.color
property alias actionIndicator: actionIndicator
property int decimals: 0
- property int factor: Math.pow(10, decimals)
+ property int factor: Math.pow(10, control.decimals)
property real minStepSize: 1
property real maxStepSize: 10
@@ -21,23 +23,23 @@ T.SpinBox {
// This property is used to indicate the global hover state
property bool hover: (spinBoxInput.hover || actionIndicator.hover || spinBoxIndicatorUp.hover
|| spinBoxIndicatorDown.hover || sliderIndicator.hover)
- && mySpinBox.enabled
+ && control.enabled
property bool drag: false
property bool sliderDrag: sliderPopup.drag
property bool dirty: false // user modification flag
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property bool spinBoxIndicatorVisible: true
- property real __spinBoxIndicatorWidth: StudioTheme.Values.spinBoxIndicatorWidth
- property real __spinBoxIndicatorHeight: StudioTheme.Values.spinBoxIndicatorHeight
+ property real __spinBoxIndicatorWidth: control.style.spinBoxIndicatorSize.width
+ property real __spinBoxIndicatorHeight: control.style.spinBoxIndicatorSize.height
property alias sliderIndicatorVisible: sliderIndicator.visible
- property real __sliderIndicatorWidth: StudioTheme.Values.sliderIndicatorWidth
- property real __sliderIndicatorHeight: StudioTheme.Values.sliderIndicatorHeight
+ property real __sliderIndicatorWidth: control.style.squareControlSize.width
+ property real __sliderIndicatorHeight: control.style.squareControlSize.height
property alias __devicePixelRatio: spinBoxInput.devicePixelRatio
property alias pixelsPerUnit: spinBoxInput.pixelsPerUnit
@@ -56,87 +58,91 @@ T.SpinBox {
wheelEnabled: false
hoverEnabled: true
- width: StudioTheme.Values.defaultControlWidth
- height: StudioTheme.Values.defaultControlHeight
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
leftPadding: spinBoxIndicatorDown.x + spinBoxIndicatorDown.width
- rightPadding: sliderIndicator.width + StudioTheme.Values.border
+ rightPadding: sliderIndicator.width + control.style.borderWidth
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
editable: true
- validator: mySpinBox.decimals ? doubleValidator : intValidator
+ validator: control.decimals ? doubleValidator : intValidator
DoubleValidator {
id: doubleValidator
- locale: mySpinBox.locale.name
+ locale: control.locale.name
notation: DoubleValidator.StandardNotation
- decimals: mySpinBox.decimals
- bottom: Math.min(mySpinBox.from, mySpinBox.to) / mySpinBox.factor
- top: Math.max(mySpinBox.from, mySpinBox.to) / mySpinBox.factor
+ decimals: control.decimals
+ bottom: Math.min(control.from, control.to) / control.factor
+ top: Math.max(control.from, control.to) / control.factor
}
IntValidator {
id: intValidator
- locale: mySpinBox.locale.name
- bottom: Math.min(mySpinBox.from, mySpinBox.to)
- top: Math.max(mySpinBox.from, mySpinBox.to)
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
}
ActionIndicator {
id: actionIndicator
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? mySpinBox.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? mySpinBox.__actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
up.indicator: SpinBoxIndicator {
id: spinBoxIndicatorUp
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
iconFlip: -1
- visible: mySpinBox.spinBoxIndicatorVisible
- pressed: mySpinBox.up.pressed
- x: actionIndicator.width + StudioTheme.Values.border
- y: StudioTheme.Values.border
- width: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorWidth : 0
- height: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorHeight : 0
-
- enabled: (mySpinBox.from < mySpinBox.to) ? mySpinBox.value < mySpinBox.to
- : mySpinBox.value > mySpinBox.to
+ visible: control.spinBoxIndicatorVisible
+ pressed: control.up.pressed
+ x: actionIndicator.width + control.style.borderWidth
+ y: control.style.borderWidth
+ width: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorWidth : 0
+ height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
+
+ enabled: (control.from < control.to) ? control.value < control.to
+ : control.value > control.to
}
down.indicator: SpinBoxIndicator {
id: spinBoxIndicatorDown
- myControl: mySpinBox
- visible: mySpinBox.spinBoxIndicatorVisible
- pressed: mySpinBox.down.pressed
- x: actionIndicator.width + StudioTheme.Values.border
+ style: control.style
+ __parentControl: control
+ visible: control.spinBoxIndicatorVisible
+ pressed: control.down.pressed
+ x: actionIndicator.width + control.style.borderWidth
y: spinBoxIndicatorUp.y + spinBoxIndicatorUp.height
- width: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorWidth : 0
- height: mySpinBox.spinBoxIndicatorVisible ? mySpinBox.__spinBoxIndicatorHeight : 0
+ width: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorWidth : 0
+ height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
- enabled: (mySpinBox.from < mySpinBox.to) ? mySpinBox.value > mySpinBox.from
- : mySpinBox.value < mySpinBox.from
+ enabled: (control.from < control.to) ? control.value > control.from
+ : control.value < control.from
}
contentItem: SpinBoxInput {
id: spinBoxInput
- myControl: mySpinBox
+ style: control.style
+ __parentControl: control
function handleEditingFinished() {
- mySpinBox.focus = false
+ control.focus = false
// Keep the dirty state before calling setValueFromInput(),
// it will be set to false (cleared) internally
- var valueModified = mySpinBox.dirty
+ var valueModified = control.dirty
- mySpinBox.setValueFromInput()
+ control.setValueFromInput()
myTimer.stop()
// Only trigger the signal, if the value was modified
if (valueModified)
- mySpinBox.compressedValueModified()
+ control.compressedValueModified()
}
onEditingFinished: spinBoxInput.handleEditingFinished()
@@ -144,32 +150,34 @@ T.SpinBox {
background: Rectangle {
id: spinBoxBackground
- color: StudioTheme.Values.themeControlOutline
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
x: actionIndicator.width
- width: mySpinBox.width - actionIndicator.width
- height: mySpinBox.height
+ width: control.width - actionIndicator.width
+ height: control.height
}
CheckIndicator {
id: sliderIndicator
- myControl: mySpinBox
- myPopup: sliderPopup
+ style: control.style
+ __parentControl: control
+ __parentPopup: sliderPopup
x: spinBoxInput.x + spinBoxInput.width
- y: StudioTheme.Values.border
- width: sliderIndicator.visible ? mySpinBox.__sliderIndicatorWidth - StudioTheme.Values.border : 0
- height: sliderIndicator.visible ? mySpinBox.__sliderIndicatorHeight - (StudioTheme.Values.border * 2) : 0
+ y: control.style.borderWidth
+ width: sliderIndicator.visible ? control.__sliderIndicatorWidth - control.style.borderWidth : 0
+ height: sliderIndicator.visible ? control.__sliderIndicatorHeight - (control.style.borderWidth * 2) : 0
visible: false // reasonable default
}
SliderPopup {
id: sliderPopup
- myControl: mySpinBox
- x: actionIndicator.width + StudioTheme.Values.border
- y: StudioTheme.Values.height
- width: mySpinBox.width - actionIndicator.width - (StudioTheme.Values.border * 2)
- height: StudioTheme.Values.sliderHeight
+ style: control.style
+ __parentControl: control
+ x: actionIndicator.width + control.style.borderWidth
+ y: control.style.controlSize.height
+ width: control.width - actionIndicator.width - (control.style.borderWidth * 2)
+ height: control.style.smallControlSize.height
enter: Transition {}
exit: Transition {}
@@ -177,21 +185,21 @@ T.SpinBox {
textFromValue: function (value, locale) {
locale.numberOptions = Locale.OmitGroupSeparator
- return Number(value / mySpinBox.factor).toLocaleString(locale, 'f',
- mySpinBox.decimals)
+ return Number(value / control.factor).toLocaleString(locale, 'f',
+ control.decimals)
}
valueFromText: function (text, locale) {
- return Number.fromLocaleString(locale, text) * mySpinBox.factor
+ return Number.fromLocaleString(locale, text) * control.factor
}
states: [
State {
name: "default"
- when: mySpinBox.enabled && !mySpinBox.hover && !mySpinBox.hovered
- && !mySpinBox.edit && !mySpinBox.drag && !mySpinBox.sliderDrag
+ when: control.enabled && !control.hover && !control.hovered
+ && !control.edit && !control.drag && !control.sliderDrag
PropertyChanges {
- target: mySpinBox
+ target: control
__wheelEnabled: false
}
PropertyChanges {
@@ -200,15 +208,23 @@ T.SpinBox {
}
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ border.color: control.style.border.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && control.hover && control.hovered
+ && !control.edit && !control.drag && !control.sliderDrag
+ PropertyChanges {
+ target: spinBoxBackground
+ border.color: control.style.border.hover
}
},
State {
name: "edit"
- when: mySpinBox.edit
+ when: control.edit
PropertyChanges {
- target: mySpinBox
+ target: control
__wheelEnabled: true
}
PropertyChanges {
@@ -217,26 +233,23 @@ T.SpinBox {
}
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutline
+ border.color: control.style.border.idle
}
},
State {
name: "drag"
- when: mySpinBox.drag || mySpinBox.sliderDrag
+ when: control.drag || control.sliderDrag
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ border.color: control.style.border.interaction
}
},
State {
name: "disable"
- when: !mySpinBox.enabled
+ when: !control.enabled
PropertyChanges {
target: spinBoxBackground
- color: StudioTheme.Values.themeControlOutlineDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ border.color: control.style.border.disabled
}
}
]
@@ -246,19 +259,19 @@ T.SpinBox {
repeat: false
running: false
interval: 400
- onTriggered: mySpinBox.compressedValueModified()
+ onTriggered: control.compressedValueModified()
}
onValueModified: myTimer.restart()
- onFocusChanged: mySpinBox.setValueFromInput()
- onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText
+ onFocusChanged: control.setValueFromInput()
+ onDisplayTextChanged: spinBoxInput.text = control.displayText
onActiveFocusChanged: {
- if (mySpinBox.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
- mySpinBox.preFocusText = spinBoxInput.text
+ if (control.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
+ control.preFocusText = spinBoxInput.text
spinBoxInput.selectAll()
}
- if (sliderPopup.opened && !mySpinBox.activeFocus)
+ if (sliderPopup.opened && !control.activeFocus)
sliderPopup.close()
}
@@ -267,43 +280,43 @@ T.SpinBox {
event.accepted = true
// Store current step size
- var currStepSize = mySpinBox.stepSize
+ var currStepSize = control.stepSize
if (event.modifiers & Qt.ControlModifier)
- mySpinBox.stepSize = mySpinBox.minStepSize
+ control.stepSize = control.minStepSize
if (event.modifiers & Qt.ShiftModifier)
- mySpinBox.stepSize = mySpinBox.maxStepSize
+ control.stepSize = control.maxStepSize
// Check if value is in sync with text input, if not sync it!
- var val = mySpinBox.valueFromText(spinBoxInput.text,
- mySpinBox.locale)
- if (mySpinBox.value !== val)
- mySpinBox.value = val
+ var val = control.valueFromText(spinBoxInput.text,
+ control.locale)
+ if (control.value !== val)
+ control.value = val
- var currValue = mySpinBox.value
+ var currValue = control.value
if (event.key === Qt.Key_Up)
- mySpinBox.increase()
+ control.increase()
else
- mySpinBox.decrease()
+ control.decrease()
- if (currValue !== mySpinBox.value)
- mySpinBox.valueModified()
+ if (currValue !== control.value)
+ control.valueModified()
// Reset step size
- mySpinBox.stepSize = currStepSize
+ control.stepSize = currStepSize
}
if (event.key === Qt.Key_Escape) {
- spinBoxInput.text = mySpinBox.preFocusText
- mySpinBox.dirty = true
+ spinBoxInput.text = control.preFocusText
+ control.dirty = true
spinBoxInput.handleEditingFinished()
}
// FIX: This is a temporary fix for QTBUG-74239
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
- mySpinBox.setValueFromInput()
+ control.setValueFromInput()
}
function clamp(v, lo, hi) {
@@ -311,27 +324,27 @@ T.SpinBox {
}
function setValueFromInput() {
- if (!mySpinBox.dirty)
+ if (!control.dirty)
return
// FIX: This is a temporary fix for QTBUG-74239
- var currValue = mySpinBox.value
+ var currValue = control.value
if (!spinBoxInput.acceptableInput)
- mySpinBox.value = clamp(valueFromText(spinBoxInput.text,
- mySpinBox.locale),
- mySpinBox.validator.bottom * mySpinBox.factor,
- mySpinBox.validator.top * mySpinBox.factor)
+ control.value = clamp(valueFromText(spinBoxInput.text,
+ control.locale),
+ control.validator.bottom * control.factor,
+ control.validator.top * control.factor)
else
- mySpinBox.value = valueFromText(spinBoxInput.text,
- mySpinBox.locale)
+ control.value = valueFromText(spinBoxInput.text,
+ control.locale)
- if (spinBoxInput.text !== mySpinBox.displayText)
- spinBoxInput.text = mySpinBox.displayText
+ if (spinBoxInput.text !== control.displayText)
+ spinBoxInput.text = control.displayText
- if (mySpinBox.value !== currValue)
- mySpinBox.valueModified()
+ if (control.value !== currValue)
+ control.valueModified()
- mySpinBox.dirty = false
+ control.dirty = false
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxIndicator.qml
index ef855b18d4..a70cc1302a 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxIndicator.qml
@@ -1,21 +1,23 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Rectangle {
- id: spinBoxIndicator
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool hover: spinBoxIndicatorMouseArea.containsMouse && spinBoxIndicator.enabled
+ property T.Control __parentControl
+
+ property bool hover: spinBoxIndicatorMouseArea.containsMouse && control.enabled
property bool pressed: spinBoxIndicatorMouseArea.containsPress
property alias iconFlip: spinBoxIndicatorIconScale.yScale
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
border.width: 0
// This MouseArea is a workaround to avoid some hover state related bugs
@@ -25,8 +27,8 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
onPressed: function(mouse) {
- if (myControl.activeFocus)
- spinBoxIndicator.forceActiveFocus()
+ if (control.__parentControl.activeFocus)
+ control.forceActiveFocus()
mouse.accepted = false
}
@@ -35,11 +37,11 @@ Rectangle {
T.Label {
id: spinBoxIndicatorIcon
text: StudioTheme.Constants.upDownSquare2
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
renderType: Text.NativeRendering
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
- font.pixelSize: StudioTheme.Values.spinControlIconSizeMulti
+ font.pixelSize: control.style.smallIconFontSize
font.family: StudioTheme.Constants.iconFont.family
anchors.fill: parent
transform: Scale {
@@ -51,46 +53,58 @@ Rectangle {
states: [
State {
+ name: "default"
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.edit
+ PropertyChanges {
+ target: spinBoxIndicatorIcon
+ color: control.style.icon.idle
+ }
+ },
+ State {
name: "globalHover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && !spinBoxIndicator.hover && myControl.hover && !myControl.edit
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && control.__parentControl.hover && !control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "hover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.hover && myControl.hover && !spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.hover
+ && control.__parentControl.hover && !control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeIconColorHover
+ color: control.style.icon.hover
}
},
State {
name: "press"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
- color: "#323232" // TODO
+ color: control.style.icon.idle
}
},
State {
name: "edit"
- when: myControl.edit
+ when: control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "disable"
- when: !myControl.enabled || !spinBoxIndicator.enabled
+ when: !control.__parentControl.enabled || !control.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
}
]
@@ -99,102 +113,104 @@ Rectangle {
states: [
State {
name: "default"
- when: myControl.enabled && !myControl.edit
- && !spinBoxIndicator.hover && !myControl.hover && !myControl.drag
+ when: control.__parentControl.enabled && !control.__parentControl.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.drag
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "globalHover"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && !spinBoxIndicator.hover && myControl.hover && !myControl.edit
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && !control.hover
+ && control.__parentControl.hover && !control.__parentControl.edit
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ target: control
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: myControl.enabled && !myControl.drag
- && spinBoxIndicator.hover && myControl.hover && !spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && !control.__parentControl.drag
+ && control.enabled && control.hover && control.__parentControl.hover
+ && !control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundHover
+ target: control
+ color: control.style.background.hover
}
},
State {
name: "press"
- when: myControl.enabled && spinBoxIndicator.enabled && !myControl.drag
- && spinBoxIndicator.pressed
+ when: control.__parentControl.enabled && control.enabled
+ && !control.__parentControl.drag && control.pressed
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: "#2aafd3" // TODO
+ target: control
+ color: control.style.interaction
}
},
State {
name: "edit"
- when: myControl.edit
+ when: control.__parentControl.edit && control.__parentControl.enabled && control.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
},
State {
name: "drag"
- when: myControl.drag
+ when: control.__parentControl.drag && control.__parentControl.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ target: control
+ color: control.style.background.interaction
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
target: spinBoxIndicatorIcon
visible: false
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.disabled
}
},
State {
name: "limit"
- when: !spinBoxIndicator.enabled && !spinBoxIndicator.realEnabled && myControl.hover
+ when: !control.enabled && !control.realEnabled && control.__parentControl.hover
PropertyChanges {
target: spinBoxIndicatorIcon
visible: true
}
PropertyChanges {
- target: spinBoxIndicator
- color: StudioTheme.Values.themeControlBackground
+ target: control
+ color: control.style.background.idle
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxInput.qml
index 446bfc1c26..8db9578991 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxInput.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SpinBoxInput.qml
@@ -1,36 +1,38 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
TextInput {
- id: textInput
+ id: control
- property T.Control myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool edit: textInput.activeFocus
+ property T.Control __parentControl
+
+ property bool edit: control.activeFocus
property bool drag: false
- property bool hover: mouseArea.containsMouse && textInput.enabled
+ property bool hover: mouseArea.containsMouse && control.enabled
property int devicePixelRatio: 1
property int pixelsPerUnit: 10
z: 2
- font: myControl.font
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+ font: control.__parentControl.font
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
horizontalAlignment: Qt.AlignRight
verticalAlignment: Qt.AlignVCenter
- leftPadding: StudioTheme.Values.inputHorizontalPadding
- rightPadding: StudioTheme.Values.inputHorizontalPadding
+ leftPadding: control.style.inputHorizontalPadding
+ rightPadding: control.style.inputHorizontalPadding
- readOnly: !myControl.editable
- validator: myControl.validator
- inputMethodHints: myControl.inputMethodHints
+ readOnly: !control.__parentControl.editable
+ validator: control.__parentControl.validator
+ inputMethodHints: control.__parentControl.inputMethodHints
selectByMouse: false
activeFocusOnPress: false
clip: true
@@ -38,16 +40,16 @@ TextInput {
// TextInput focus needs to be set to activeFocus whenever it changes,
// otherwise TextInput will get activeFocus whenever the parent SpinBox gets
// activeFocus. This will lead to weird side effects.
- onActiveFocusChanged: textInput.focus = textInput.activeFocus
+ onActiveFocusChanged: control.focus = control.activeFocus
Rectangle {
id: textInputBackground
x: 0
- y: StudioTheme.Values.border
+ y: control.style.borderWidth
z: -1
- width: textInput.width
- height: StudioTheme.Values.height - (StudioTheme.Values.border * 2)
- color: StudioTheme.Values.themeControlBackground
+ width: control.width
+ height: control.style.controlSize.height - (control.style.borderWidth * 2)
+ color: control.style.background.idle
border.width: 0
}
@@ -57,22 +59,22 @@ TextInput {
event.accepted = true
if (event.modifiers & Qt.ControlModifier) {
- mouseArea.stepSize = myControl.minStepSize
+ mouseArea.stepSize = control.__parentControl.minStepSize
mouseArea.calcValue()
- myControl.valueModified()
+ control.__parentControl.valueModified()
}
if (event.modifiers & Qt.ShiftModifier) {
- mouseArea.stepSize = myControl.maxStepSize
+ mouseArea.stepSize = control.__parentControl.maxStepSize
mouseArea.calcValue()
- myControl.valueModified()
+ control.__parentControl.valueModified()
}
}
Keys.onReleased: function(event) {
event.accepted = true
- mouseArea.stepSize = myControl.stepSize
+ mouseArea.stepSize = control.__parentControl.stepSize
mouseArea.calcValue()
- myControl.valueModified()
+ control.__parentControl.valueModified()
}
}
@@ -84,14 +86,14 @@ TextInput {
MouseArea {
id: mouseArea
- property real stepSize: myControl.stepSize
+ property real stepSize: control.__parentControl.stepSize
// Properties to store the state of a drag operation
property bool dragging: false
property bool hasDragged: false
property bool potentialDragStart: false
- property int initialValue: myControl.value // value on drag operation starts
+ property int initialValue: control.__parentControl.value // value on drag operation starts
property real pressStartX: 0.0
property real dragStartX: 0.0
@@ -101,7 +103,7 @@ TextInput {
property real totalUnits: 0.0 // total number of units dragged
property real units: 0.0
- property real __pixelsPerUnit: textInput.devicePixelRatio * textInput.pixelsPerUnit
+ property real __pixelsPerUnit: control.devicePixelRatio * control.pixelsPerUnit
anchors.fill: parent
enabled: true
@@ -113,21 +115,21 @@ TextInput {
onPositionChanged: function(mouse) {
if (!mouseArea.dragging
- && !myControl.edit
+ && !control.__parentControl.edit
&& Math.abs(mouseArea.pressStartX - mouse.x) > StudioTheme.Values.dragThreshold
&& mouse.buttons === Qt.LeftButton
&& mouseArea.potentialDragStart) {
mouseArea.dragging = true
mouseArea.potentialDragStart = false
- mouseArea.initialValue = myControl.value
+ mouseArea.initialValue = control.__parentControl.value
mouseArea.cursorShape = Qt.ClosedHandCursor
mouseArea.dragStartX = mouse.x
- myControl.drag = true
- myControl.dragStarted()
+ control.__parentControl.drag = true
+ control.__parentControl.dragStarted()
// Force focus on the non visible component to receive key events
dragModifierWorkaround.forceActiveFocus()
- textInput.deselect()
+ control.deselect()
}
if (!mouseArea.dragging)
@@ -152,11 +154,11 @@ TextInput {
mouseArea.translationX += translationX
mouseArea.calcValue()
- myControl.valueModified()
+ control.__parentControl.valueModified()
}
onClicked: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
if (mouseArea.hasDragged) {
@@ -164,12 +166,12 @@ TextInput {
return
}
- textInput.forceActiveFocus()
- textInput.deselect() // QTBUG-75862
+ control.forceActiveFocus()
+ control.deselect() // QTBUG-75862
}
onPressed: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
mouseArea.potentialDragStart = true
@@ -177,7 +179,7 @@ TextInput {
}
onReleased: function(mouse) {
- if (textInput.edit)
+ if (control.edit)
mouse.accepted = false
mouseArea.endDrag()
@@ -190,18 +192,18 @@ TextInput {
mouseArea.dragging = false
mouseArea.hasDragged = true
- if (myControl.compressedValueTimer.running) {
- myControl.compressedValueTimer.stop()
+ if (control.__parentControl.compressedValueTimer.running) {
+ control.__parentControl.compressedValueTimer.stop()
mouseArea.calcValue()
- myControl.compressedValueModified()
+ control.__parentControl.compressedValueModified()
}
mouseArea.cursorShape = Qt.PointingHandCursor
- myControl.drag = false
- myControl.dragEnded()
+ control.__parentControl.drag = false
+ control.__parentControl.dragEnded()
// Avoid active focus on the component after dragging
dragModifierWorkaround.focus = false
- textInput.focus = false
- myControl.focus = false
+ control.focus = false
+ control.__parentControl.focus = false
mouseArea.translationX = 0
mouseArea.units = 0
@@ -209,53 +211,55 @@ TextInput {
}
function calcValue() {
- var minUnit = (myControl.from - mouseArea.initialValue) / mouseArea.stepSize
- var maxUnit = (myControl.to - mouseArea.initialValue) / mouseArea.stepSize
+ var minUnit = (control.__parentControl.from - mouseArea.initialValue) / mouseArea.stepSize
+ var maxUnit = (control.__parentControl.to - mouseArea.initialValue) / mouseArea.stepSize
var units = Math.trunc(mouseArea.translationX / mouseArea.__pixelsPerUnit)
mouseArea.units = Math.min(Math.max(mouseArea.totalUnits + units, minUnit), maxUnit)
- myControl.value = mouseArea.initialValue + (mouseArea.units * mouseArea.stepSize)
+ control.__parentControl.value = mouseArea.initialValue + (mouseArea.units * mouseArea.stepSize)
if (mouseArea.dragging)
- myControl.dragging()
+ control.__parentControl.dragging()
}
onWheel: function(wheel) {
- if (!myControl.__wheelEnabled) {
+ if (!control.__parentControl.__wheelEnabled) {
wheel.accepted = false
return
}
// Set stepSize according to used modifier key
if (wheel.modifiers & Qt.ControlModifier)
- mouseArea.stepSize = myControl.minStepSize
+ mouseArea.stepSize = control.__parentControl.minStepSize
if (wheel.modifiers & Qt.ShiftModifier)
- mouseArea.stepSize = myControl.maxStepSize
+ mouseArea.stepSize = control.__parentControl.maxStepSize
- var val = myControl.valueFromText(textInput.text, myControl.locale)
- if (myControl.value !== val)
- myControl.value = val
+ var val = control.__parentControl.valueFromText(control.text,
+ control.__parentControl.locale)
+ if (control.__parentControl.value !== val)
+ control.__parentControl.value = val
- var currValue = myControl.value
- myControl.value += (wheel.angleDelta.y / 120 * mouseArea.stepSize)
+ var currValue = control.__parentControl.value
+ control.__parentControl.value += (wheel.angleDelta.y / 120 * mouseArea.stepSize)
- if (currValue !== myControl.value)
- myControl.valueModified()
+ if (currValue !== control.__parentControl.value)
+ control.__parentControl.valueModified()
// Reset stepSize
- mouseArea.stepSize = myControl.stepSize
+ mouseArea.stepSize = control.__parentControl.stepSize
}
}
states: [
State {
name: "default"
- when: myControl.enabled && !textInput.edit && !textInput.hover && !myControl.hover
- && !myControl.drag && !myControl.sliderDrag
+ when: control.__parentControl.enabled && !control.edit && !control.hover
+ && !control.__parentControl.hover && !control.__parentControl.drag
+ && !control.__parentControl.sliderDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
}
PropertyChanges {
target: mouseArea
@@ -264,27 +268,28 @@ TextInput {
},
State {
name: "globalHover"
- when: myControl.hover && !textInput.hover && !textInput.edit && !myControl.drag
+ when: control.__parentControl.hover && !control.hover && !control.edit
+ && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
+ color: control.style.background.globalHover
}
},
State {
name: "hover"
- when: textInput.hover && myControl.hover
- && !textInput.edit && !myControl.drag
+ when: control.hover && control.__parentControl.hover
+ && !control.edit && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundHover
+ color: control.style.background.hover
}
},
State {
name: "edit"
- when: textInput.edit && !myControl.drag
+ when: control.edit && !control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ color: control.style.background.interaction
}
PropertyChanges {
target: mouseArea
@@ -293,38 +298,38 @@ TextInput {
},
State {
name: "drag"
- when: myControl.drag
+ when: control.__parentControl.drag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
+ color: control.style.background.interaction
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "sliderDrag"
- when: myControl.sliderDrag
+ when: control.__parentControl.sliderDrag
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackground
+ color: control.style.background.idle
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeInteraction
+ target: control
+ color: control.style.interaction
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
target: textInputBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
+ color: control.style.background.disabled
}
PropertyChanges {
- target: textInput
- color: StudioTheme.Values.themeTextColorDisabled
+ target: control
+ color: control.style.text.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Switch.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Switch.qml
index 092b4633da..8742bfd8c2 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Switch.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Switch.qml
@@ -1,28 +1,30 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.Switch {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property alias actionIndicator: actionIndicator
// This property is used to indicate the global hover state
- property bool hover: root.hovered && root.enabled
+ property bool hover: control.hovered && control.enabled
property bool edit: false
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
- property alias labelVisible: switchLabel.visible
- property alias labelColor: switchLabel.color
+ property alias labelVisible: label.visible
+ property alias labelColor: label.color
- property alias fontFamily: switchLabel.font.family
- property alias fontPixelSize: switchLabel.font.pixelSize
+ property alias fontFamily: label.font.family
+ property alias fontPixelSize: label.font.pixelSize
font.pixelSize: StudioTheme.Values.myFontSize
@@ -32,15 +34,16 @@ T.Switch {
implicitContentHeight + topPadding + bottomPadding,
implicitIndicatorHeight + topPadding + bottomPadding)
- spacing: StudioTheme.Values.switchSpacing
+ spacing: label.visible ? control.style.controlSpacing : 0
hoverEnabled: true
activeFocusOnTab: false
ActionIndicator {
id: actionIndicator
- myControl: root
- width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
+ style: control.style
+ __parentControl: control
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
indicator: Rectangle {
@@ -48,12 +51,12 @@ T.Switch {
x: actionIndicator.width
y: 0
z: 5
- implicitWidth: StudioTheme.Values.height * 2
- implicitHeight: StudioTheme.Values.height
- radius: StudioTheme.Values.height * 0.5
- color: StudioTheme.Values.themeControlBackground
- border.width: StudioTheme.Values.border
- border.color: StudioTheme.Values.themeControlOutline
+ implicitWidth: control.style.squareControlSize.width * 2
+ implicitHeight: control.style.squareControlSize.height
+ radius: control.style.squareControlSize.height * 0.5
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
Rectangle {
id: switchIndicator
@@ -61,142 +64,142 @@ T.Switch {
readonly property real gap: 5
property real size: switchBackground.implicitHeight - switchIndicator.gap * 2
- x: root.checked ? parent.width - width - switchIndicator.gap
+ x: control.checked ? parent.width - width - switchIndicator.gap
: switchIndicator.gap
y: switchIndicator.gap
width: switchIndicator.size
height: switchIndicator.size
radius: switchIndicator.size * 0.5
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
border.width: 0
}
}
contentItem: T.Label {
- id: switchLabel
- leftPadding: switchBackground.x + switchBackground.width + root.spacing
+ id: label
+ leftPadding: switchBackground.x + switchBackground.width + control.spacing
rightPadding: 0
verticalAlignment: Text.AlignVCenter
- text: root.text
- font: root.font
- color: StudioTheme.Values.themeTextColor
- visible: text !== ""
+ text: control.text
+ font: control.font
+ color: control.style.text.idle
+ visible: control.text !== ""
}
- property bool __default: root.enabled && !root.hover && !actionIndicator.hover && !root.pressed
- property bool __globalHover: root.enabled && actionIndicator.hover && !root.pressed
- property bool __hover: root.hover && !actionIndicator.hover && !root.pressed
- property bool __press: root.hover && root.pressed
+ property bool __default: control.enabled && !control.hover && !actionIndicator.hover && !control.pressed
+ property bool __globalHover: control.enabled && actionIndicator.hover && !control.pressed
+ property bool __hover: control.hover && !actionIndicator.hover && !control.pressed
+ property bool __press: control.hover && control.pressed
states: [
State {
name: "default"
- when: root.__default && !root.checked
+ when: control.__default && !control.checked
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
target: switchIndicator
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "globalHover"
- when: root.__globalHover && !root.checked
+ when: control.__globalHover && !control.checked
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.globalHover
+ border.color: control.style.border.idle
}
PropertyChanges {
target: switchIndicator
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
}
},
State {
name: "hover"
- when: root.__hover && !root.checked
+ when: control.__hover && !control.checked
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.hover
+ border.color: control.style.border.hover
}
PropertyChanges {
target: switchIndicator
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.hover
}
},
State {
name: "press"
- when: root.__press && !root.checked
+ when: control.__press && !control.checked
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
target: switchIndicator
- color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
}
},
State {
name: "disable"
- when: !root.enabled && !root.checked
+ when: !control.enabled && !control.checked
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
target: switchIndicator
- color: StudioTheme.Values.themeTextColorDisabled
+ color: control.style.icon.disabled
}
PropertyChanges {
- target: switchLabel
- color: StudioTheme.Values.themeTextColorDisabled
+ target: label
+ color: control.style.text.disabled
}
},
State {
name: "defaultChecked"
- when: root.__default && root.checked
+ when: control.__default && control.checked
extend: "default"
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeInteraction
- border.color: StudioTheme.Values.themeInteraction
+ color: control.style.interaction
+ border.color: control.style.interaction
}
},
State {
name: "globalHoverChecked"
- when: root.__globalHover && root.checked
+ when: control.__globalHover && control.checked
extend: "globalHover"
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeInteractionHover
- border.color: StudioTheme.Values.themeInteractionHover
+ color: control.style.interactionHover
+ border.color: control.style.interactionHover
}
},
State {
name: "hoverChecked"
- when: root.__hover && root.checked
+ when: control.__hover && control.checked
extend: "hover"
PropertyChanges {
target: switchBackground
- color: StudioTheme.Values.themeInteractionHover
- border.color: StudioTheme.Values.themeInteractionHover
+ color: control.style.interactionHover
+ border.color: control.style.interactionHover
}
},
State {
name: "pressChecked"
- when: root.__press && root.checked
+ when: control.__press && control.checked
extend: "press"
},
State {
name: "disableChecked"
- when: !root.enabled && root.checked
+ when: !control.enabled && control.checked
extend: "disable"
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabBar.qml
index 7376e2c2e2..8404f9190a 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabBar.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabBar.qml
@@ -1,12 +1,14 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.TabBar {
- id: myButton
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -15,9 +17,9 @@ T.TabBar {
spacing: 0
contentItem: ListView {
- model: myButton.contentModel
- currentIndex: myButton.currentIndex
- spacing: myButton.spacing
+ model: control.contentModel
+ currentIndex: control.currentIndex
+ spacing: control.spacing
orientation: ListView.Horizontal
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.AutoFlickIfNeeded
@@ -25,6 +27,6 @@ T.TabBar {
}
background: Rectangle {
- color: StudioTheme.Values.themePanelBackground
+ color: control.style.panel.background
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabButton.qml
index d448ea5775..4074d54634 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TabButton.qml
@@ -1,12 +1,14 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.TabButton {
- id: myButton
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
@@ -17,24 +19,19 @@ T.TabButton {
background: Rectangle {
id: buttonBackground
- color: myButton.checked ? StudioTheme.Values.themeInteraction
- : "transparent"
- border.width: StudioTheme.Values.border
- border.color: StudioTheme.Values.themeInteraction
+ color: control.checked ? control.style.interaction : "transparent"
+ border.width: control.style.borderWidth
+ border.color: control.style.interaction
}
contentItem: T.Label {
id: buttonIcon
- color: myButton.checked ? StudioTheme.Values.themeControlBackground
- : StudioTheme.Values.themeInteraction
- //font.weight: Font.Bold
- //font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myFontSize
+ color: control.checked ? control.style.background.idle : control.style.interaction
+ font.pixelSize: control.style.baseFontSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
anchors.fill: parent
renderType: Text.QtRendering
-
- text: myButton.text
+ text: control.text
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextArea.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextArea.qml
index 47dcfb7eec..abd5f73284 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextArea.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextArea.qml
@@ -1,37 +1,40 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
TextField {
- id: myTextField
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
property real relativePopupX: 0 // TODO Maybe call it leftPadding
- property real popupWidth: myTextField.width
+ property real popupWidth: control.width
property string txtStorage
property int temp: 0
T.Popup {
id: popup
- x: myTextField.relativePopupX
- y: myTextField.height - StudioTheme.Values.border
- width: myTextField.popupWidth
+ x: control.relativePopupX
+ y: control.height - control.style.borderWidth
+ width: control.popupWidth
height: scrollView.height
background: Rectangle {
- color: StudioTheme.Values.themePopupBackground
- border.color: StudioTheme.Values.themeInteraction
- border.width: StudioTheme.Values.border
+ color: control.style.popup.background
+ border.color: control.style.interaction
+ border.width: control.style.borderWidth
}
contentItem: ScrollView {
id: scrollView
+ style: control.style
padding: 0
height: Math.min(textAreaPopup.contentHeight + scrollView.topPadding
+ scrollView.bottomPadding,
- StudioTheme.Values.maxTextAreaPopupHeight)
+ control.style.maxTextAreaPopupHeight)
ScrollBar.horizontal.policy: ScrollBar.AlwaysOn
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
@@ -41,10 +44,10 @@ TextField {
width: textAreaPopup.contentWidth + textAreaPopup.leftPadding
+ textAreaPopup.rightPadding
anchors.fill: parent
- font.pixelSize: StudioTheme.Values.myFontSize
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+ font.pixelSize: control.style.baseFontSize
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
selectByMouse: true
persistentSelection: textAreaPopup.focus
@@ -61,56 +64,60 @@ TextField {
ContextMenu {
id: contextMenu
- myTextEdit: textAreaPopup
+ style: control.style
+ __parentControl: textAreaPopup
}
AbstractButton {
id: acceptButton
+ style: control.style
x: popup.width - acceptButton.width
- y: popup.height - StudioTheme.Values.border
- width: Math.round(StudioTheme.Values.smallRectWidth)
- height: Math.round(StudioTheme.Values.smallRectWidth)
+ y: popup.height - control.style.borderWidth
+ width: Math.round(control.style.smallControlSize.width)
+ height: Math.round(control.style.smallControlSize.height)
buttonIcon: StudioTheme.Constants.tickIcon
}
AbstractButton {
id: discardButton
- x: popup.width - acceptButton.width - discardButton.width + StudioTheme.Values.border
- y: popup.height - StudioTheme.Values.border
- width: Math.round(StudioTheme.Values.smallRectWidth)
- height: Math.round(StudioTheme.Values.smallRectWidth)
+ style: control.style
+ x: popup.width - acceptButton.width - discardButton.width + control.style.borderWidth
+ y: popup.height - control.style.borderWidth
+ width: Math.round(control.style.smallControlSize.width)
+ height: Math.round(control.style.smallControlSize.height)
buttonIcon: StudioTheme.Constants.closeCross
}
- Component.onCompleted: {
- storeAndFormatTextInput(myTextField.text)
- }
+ Component.onCompleted: control.storeAndFormatTextInput(control.text)
onOpened: {
- textAreaPopup.text = txtStorage
- myTextField.clear()
+ textAreaPopup.text = control.txtStorage
+ control.clear()
}
onClosed: {
- storeAndFormatTextInput(textAreaPopup.text)
- myTextField.forceActiveFocus()
+ control.storeAndFormatTextInput(textAreaPopup.text)
+ control.forceActiveFocus()
textAreaPopup.deselect()
}
}
function storeAndFormatTextInput(inputText) {
- txtStorage = inputText
- var pos = txtStorage.search(/\n/g)
+ control.txtStorage = inputText
+ var pos = control.txtStorage.search(/\n/g)
var sliceAt = Math.min(pos, 15)
- myTextField.text = txtStorage.slice(0, sliceAt).padEnd(sliceAt + 3, '.')
+ control.text = control.txtStorage.slice(0, sliceAt).padEnd(sliceAt + 3, '.')
}
Keys.onPressed: function(event) {
- if (event.key === Qt.Key_Escape)
- popup.opened ? popup.close() : myTextField.focus = false
+ if (event.key === Qt.Key_Escape) {
+ if (popup.opened)
+ popup.close()
+ else
+ control.focus = false
+ }
- if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
- && !popup.opened) {
+ if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && !popup.opened) {
popup.open()
textAreaPopup.forceActiveFocus()
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml
index 517bf0f4eb..0180aa06ad 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml
@@ -1,27 +1,29 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
T.TextField {
- id: root
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
// This property is used to indicate the global hover state
property bool hover: (actionIndicator.hover || mouseArea.containsMouse || indicator.hover
- || translationIndicator.hover) && root.enabled
- property bool edit: root.activeFocus
+ || translationIndicator.hover) && control.enabled
+ property bool edit: control.activeFocus
property alias actionIndicator: actionIndicator
property alias actionIndicatorVisible: actionIndicator.visible
- property real __actionIndicatorWidth: StudioTheme.Values.actionIndicatorWidth
- property real __actionIndicatorHeight: StudioTheme.Values.actionIndicatorHeight
+ property real __actionIndicatorWidth: control.style.actionIndicatorSize.width
+ property real __actionIndicatorHeight: control.style.actionIndicatorSize.height
property alias translationIndicator: translationIndicator
property alias translationIndicatorVisible: translationIndicator.visible
- property real __translationIndicatorWidth: StudioTheme.Values.translationIndicatorWidth
- property real __translationIndicatorHeight: StudioTheme.Values.translationIndicatorHeight
+ property real __translationIndicatorWidth: control.style.squareControlSize.width
+ property real __translationIndicatorHeight: control.style.squareControlSize.height
property alias indicator: indicator
property alias indicatorVisible: indicator.visible
@@ -35,24 +37,24 @@ T.TextField {
horizontalAlignment: Qt.AlignLeft
verticalAlignment: Qt.AlignVCenter
- font.pixelSize: StudioTheme.Values.myFontSize
+ font.pixelSize: control.style.baseFontSize
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
+ color: control.style.text.idle
+ selectionColor: control.style.text.selection
+ selectedTextColor: control.style.text.selectedText
+ placeholderTextColor: control.style.text.placeholder
readOnly: false
selectByMouse: true
- persistentSelection: contextMenu.visible || root.focus
+ persistentSelection: contextMenu.visible || control.focus
clip: true
- width: StudioTheme.Values.defaultControlWidth
- height: StudioTheme.Values.defaultControlHeight
- implicitHeight: StudioTheme.Values.defaultControlHeight
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
+ implicitHeight: control.style.controlSize.height
- leftPadding: StudioTheme.Values.inputHorizontalPadding + actionIndicator.width
- rightPadding: StudioTheme.Values.inputHorizontalPadding + translationIndicator.width + indicator.width
+ leftPadding: control.style.inputHorizontalPadding + actionIndicator.width
+ rightPadding: control.style.inputHorizontalPadding + translationIndicator.width + indicator.width
MouseArea {
id: mouseArea
@@ -66,80 +68,84 @@ T.TextField {
onPressed: function(event) {
if (event.button === Qt.RightButton)
- contextMenu.popup(root)
+ contextMenu.popup(control)
}
ContextMenu {
id: contextMenu
- myTextEdit: root
+ style: control.style
+ __parentControl: control
- onClosed: root.forceActiveFocus()
- onAboutToShow: root.contextMenuAboutToShow = true
- onAboutToHide: root.contextMenuAboutToShow = false
+ onClosed: control.forceActiveFocus()
+ onAboutToShow: control.contextMenuAboutToShow = true
+ onAboutToHide: control.contextMenuAboutToShow = false
}
onActiveFocusChanged: {
// OtherFocusReason in this case means, if the TextField gets focus after the context menu
// was closed due to an menu item click.
- if (root.activeFocus && root.focusReason !== Qt.OtherFocusReason)
- root.preFocusText = root.text
+ if (control.activeFocus && control.focusReason !== Qt.OtherFocusReason)
+ control.preFocusText = control.text
}
onEditChanged: {
- if (root.edit)
+ if (control.edit)
contextMenu.close()
}
- onEditingFinished: root.focus = false
+ onEditingFinished: control.focus = false
ActionIndicator {
id: actionIndicator
- myControl: root
+ style: control.style
+ __parentControl: control
x: 0
y: 0
- width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
- height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
+ width: actionIndicator.visible ? control.__actionIndicatorWidth : 0
+ height: actionIndicator.visible ? control.__actionIndicatorHeight : 0
}
Text {
id: placeholder
- x: root.leftPadding
- y: root.topPadding
- width: root.width - (root.leftPadding + root.rightPadding)
- height: root.height - (root.topPadding + root.bottomPadding)
-
- text: root.placeholderText
- font: root.font
- color: root.placeholderTextColor
- verticalAlignment: root.verticalAlignment
- visible: !root.length && !root.preeditText
- && (!root.activeFocus || root.horizontalAlignment !== Qt.AlignHCenter)
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ visible: !control.length && !control.preeditText
+ && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
elide: Text.ElideRight
- renderType: root.renderType
+ renderType: control.renderType
}
background: Rectangle {
id: textFieldBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
x: actionIndicator.width
- width: root.width - actionIndicator.width
- height: root.height
+ width: control.width - actionIndicator.width
+ height: control.height
}
Indicator {
id: indicator
+ style: control.style
visible: false
- x: root.width - translationIndicator.width - indicator.width
- width: indicator.visible ? root.height : 0
- height: indicator.visible ? root.height : 0
+ x: control.width - translationIndicator.width - indicator.width
+ width: indicator.visible ? control.height : 0
+ height: indicator.visible ? control.height : 0
}
TranslationIndicator {
id: translationIndicator
- myControl: root
- x: root.width - translationIndicator.width
+ style: control.style
+ __parentControl: control
+ x: control.width - translationIndicator.width
width: translationIndicator.visible ? __translationIndicatorWidth : 0
height: translationIndicator.visible ? __translationIndicatorHeight : 0
}
@@ -147,16 +153,16 @@ T.TextField {
states: [
State {
name: "default"
- when: root.enabled && !root.hover && !root.edit && !contextMenu.visible
+ when: control.enabled && !control.hover && !control.edit && !contextMenu.visible
PropertyChanges {
target: textFieldBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
PropertyChanges {
- target: root
- color: StudioTheme.Values.themeTextColor
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
+ target: control
+ color: control.style.text.idle
+ placeholderTextColor: control.style.text.placeholder
}
PropertyChanges {
target: mouseArea
@@ -166,45 +172,45 @@ T.TextField {
State {
name: "globalHover"
when: (actionIndicator.hover || translationIndicator.hover || indicator.hover)
- && !root.edit && root.enabled && !contextMenu.visible
+ && !control.edit && control.enabled && !contextMenu.visible
PropertyChanges {
target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.globalHover
+ border.color: control.style.border.idle
}
PropertyChanges {
- target: root
- color: StudioTheme.Values.themeTextColor
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
+ target: control
+ color: control.style.text.idle
+ placeholderTextColor: control.style.text.placeholder
}
},
State {
name: "hover"
when: mouseArea.containsMouse && !actionIndicator.hover && !translationIndicator.hover
- && !indicator.hover && !root.edit && root.enabled && !contextMenu.visible
+ && !indicator.hover && !control.edit && control.enabled && !contextMenu.visible
PropertyChanges {
target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ color: control.style.background.hover
+ border.color: control.style.border.hover
}
PropertyChanges {
- target: root
- color: StudioTheme.Values.themeTextColor
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor
+ target: control
+ color: control.style.text.hover
+ placeholderTextColor: control.style.text.placeholder
}
},
State {
name: "edit"
- when: root.edit || contextMenu.visible
+ when: control.edit || contextMenu.visible
PropertyChanges {
target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
PropertyChanges {
- target: root
- color: StudioTheme.Values.themeTextColor
- placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction
+ target: control
+ color: control.style.text.idle
+ placeholderTextColor: control.style.text.placeholder
}
PropertyChanges {
target: mouseArea
@@ -213,24 +219,24 @@ T.TextField {
},
State {
name: "disable"
- when: !root.enabled
+ when: !control.enabled
PropertyChanges {
target: textFieldBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
PropertyChanges {
- target: root
- color: StudioTheme.Values.themeTextColorDisabled
- placeholderTextColor: StudioTheme.Values.themeTextColorDisabled
+ target: control
+ color: control.style.text.disabled
+ placeholderTextColor: control.style.text.disabled
}
}
]
Keys.onEscapePressed: function(event) {
event.accepted = true
- root.text = root.preFocusText
- root.rejected()
- root.focus = false
+ control.text = control.preFocusText
+ control.rejected()
+ control.focus = false
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml
index 0c99890e6b..b39fb6881c 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml
@@ -1,27 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Templates as T
@@ -30,8 +8,10 @@ import StudioTheme 1.0 as StudioTheme
T.ToolTip {
id: control
- x: parent ? (parent.width - implicitWidth) / 2 : 0
- y: -implicitHeight - 3
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ x: parent ? (parent.width - control.implicitWidth) / 2 : 0
+ y: -control.implicitHeight - 3
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding)
@@ -42,19 +22,20 @@ T.ToolTip {
padding: 4
delay: 1000
timeout: 5000
- closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent
+ | T.Popup.CloseOnReleaseOutsideParent
contentItem: Text {
text: control.text
wrapMode: Text.Wrap
- font.pixelSize: StudioTheme.Values.myFontSize
- color: StudioTheme.Values.themeToolTipText
+ font.pixelSize: control.style.baseFontSize
+ color: control.style.toolTip.text
}
background: Rectangle {
- color: StudioTheme.Values.themeToolTipBackground
- border.width: StudioTheme.Values.border
- border.color: StudioTheme.Values.themeToolTipOutline
+ color: control.style.toolTip.background
+ border.width: control.style.borderWidth
+ border.color: control.style.toolTip.border
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml
new file mode 100644
index 0000000000..1dddfec0b4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml
@@ -0,0 +1,266 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Templates as T
+import StudioTheme 1.0 as StudioTheme
+import QtQuickDesignerTheme 1.0
+
+T.ComboBox {
+ id: control
+
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
+
+ property bool hover: (comboBoxInput.hover || window.visible || popupIndicator.hover)
+ && control.enabled
+ property bool edit: false
+ property bool open: window.visible
+ property bool openUpwards: false
+ property alias suffix: comboBoxInput.suffix
+
+ editable: false
+ width: control.style.controlSize.width
+ height: control.style.controlSize.height
+
+ leftPadding: 0
+ rightPadding: popupIndicator.width + control.style.borderWidth
+ font.pixelSize: control.style.baseFontSize
+
+ delegate: ItemDelegate {
+ required property int index
+ required property var modelData
+
+ width: control.width
+ highlighted: control.highlightedIndex === index
+ contentItem: Text {
+ text: modelData
+ color: "#21be2b"
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ indicator: CheckIndicator {
+ id: popupIndicator
+ style: control.style
+ __parentControl: control
+ __parentPopup: comboBoxPopup
+ x: comboBoxInput.x + comboBoxInput.width
+ y: control.style.borderWidth
+ width: control.style.squareControlSize.width - control.style.borderWidth
+ height: control.style.squareControlSize.height - control.style.borderWidth * 2
+ }
+
+ contentItem: ComboBoxInput {
+ id: comboBoxInput
+ style: control.style
+ __parentControl: control
+ text: control.editText
+ }
+
+ background: Rectangle {
+ id: comboBoxBackground
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
+ width: control.width
+ height: control.height
+ }
+
+ popup: T.Popup {
+ id: comboBoxPopup
+ width: 0
+ height: 0
+ closePolicy: T.Popup.CloseOnEscape
+ onAboutToShow: {
+ control.listView.parent = window.contentItem
+ control.listView.visible = true
+
+ var originMapped = control.mapToGlobal(0,0)
+
+ if (control.openUpwards) {
+ window.x = originMapped.x + 1 // This is a workaround for the status bar
+ window.y = originMapped.y - window.height
+ } else {
+ window.x = originMapped.x
+ window.y = originMapped.y + control.height
+ }
+
+ window.show()
+ window.requestActivate()
+
+ control.listView.focus = true
+ }
+
+ onAboutToHide: window.hide()
+ }
+
+ // Close popup when application goes to background
+ Connections {
+ target: Qt.application
+ function onStateChanged() {
+ if (Qt.application.state === Qt.ApplicationInactive)
+ comboBoxPopup.close()
+ }
+ }
+
+ Window {
+ id: window
+ width: control.listView.width
+ height: control.listView.height + 2 * control.style.borderWidth
+ visible: false
+ flags: Qt.FramelessWindowHint | Qt.Dialog | Qt.NoDropShadowWindowHint
+ modality: Qt.NonModal
+ transientParent: null
+ color: "transparent"
+
+ onActiveFocusItemChanged: {
+ if (window.activeFocusItem === null && !comboBoxInput.hover
+ && !popupIndicator.hover && comboBoxPopup.opened)
+ comboBoxPopup.close()
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: control.style.popup.background
+ }
+ }
+
+ property ListView listView: ListView {
+ x: 0
+ y: control.style.borderWidth
+ width: control.width
+ height: control.listView.contentHeight
+ interactive: false
+ model: control.model
+ Keys.onEscapePressed: comboBoxPopup.close()
+ currentIndex: control.highlightedIndex
+
+ delegate: ItemDelegate {
+ id: itemDelegate
+
+ onClicked: {
+ control.currentIndex = index
+ control.activated(index)
+ comboBoxPopup.close()
+ }
+
+ width: control.width
+ height: control.style.controlSize.height
+ padding: 0
+
+ contentItem: Text {
+ leftPadding: itemDelegateIconArea.width
+ text: modelData
+ color: {
+ if (!itemDelegate.enabled)
+ return control.style.text.disabled
+
+ return itemDelegate.hovered ? control.style.text.selectedText
+ : control.style.text.idle
+ }
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Item {
+ id: itemDelegateIconArea
+ width: itemDelegate.height
+ height: itemDelegate.height
+
+ T.Label {
+ id: itemDelegateIcon
+ text: StudioTheme.Constants.tickIcon
+ color: itemDelegate.hovered ? control.style.text.selectedText
+ : control.style.text.idle
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: control.style.smallIconFontSize
+ visible: control.currentIndex === index
+ anchors.fill: parent
+ renderType: Text.NativeRendering
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ background: Rectangle {
+ id: itemDelegateBackground
+ x: control.style.borderWidth
+ y: 0
+ width: itemDelegate.width - 2 * control.style.borderWidth
+ height: itemDelegate.height
+ color: itemDelegate.hovered ? control.style.interaction : "transparent"
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: control.enabled && !control.hover && !control.edit && !control.open
+ && !control.activeFocus && !control.hasActiveDrag
+ PropertyChanges {
+ target: control
+ wheelEnabled: false
+ }
+ PropertyChanges {
+ target: comboBoxInput
+ selectByMouse: false
+ }
+ PropertyChanges {
+ target: comboBoxBackground
+ border.color: control.style.border.idle
+ }
+ },
+ State {
+ name: "hover"
+ when: control.enabled && control.hover && !control.edit && !control.open
+ && !control.activeFocus && !control.hasActiveDrag
+ PropertyChanges {
+ target: comboBoxBackground
+ border.color: control.style.border.hover
+ }
+ },
+ // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via
+ // tab focus. It is therefor possible to use the mouse wheel to scroll through the items.
+ State {
+ name: "focus"
+ when: control.enabled && control.activeFocus && !control.editable && !control.open
+ PropertyChanges {
+ target: control
+ wheelEnabled: true
+ }
+ PropertyChanges {
+ target: comboBoxInput
+ focus: true
+ }
+ },
+ State {
+ name: "popup"
+ when: control.enabled && control.open
+ PropertyChanges {
+ target: control
+ wheelEnabled: true
+ }
+ PropertyChanges {
+ target: comboBoxInput
+ selectByMouse: false
+ readOnly: true
+ }
+ PropertyChanges {
+ target: comboBoxBackground
+ border.color: control.style.border.interaction
+ }
+ },
+ State {
+ name: "disable"
+ when: !control.enabled
+ PropertyChanges {
+ target: comboBoxBackground
+ border.color: control.style.border.disabled
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TranslationIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TranslationIndicator.qml
index 09d00eb901..8b3962ffcd 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TranslationIndicator.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TranslationIndicator.qml
@@ -1,31 +1,33 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Templates 2.15 as T
+import QtQuick
+import QtQuick.Templates as T
import StudioTheme 1.0 as StudioTheme
Item {
- id: translationIndicator
+ id: control
- property Item myControl
+ property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
- property bool hover: translationIndicatorMouseArea.containsMouse && translationIndicator.enabled
- property bool pressed: translationIndicatorMouseArea.pressed
+ property Item __parentControl
+
+ property bool hover: mouseArea.containsMouse && control.enabled
+ property bool pressed: mouseArea.pressed
property bool checked: false
signal clicked
Rectangle {
- id: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
- border.width: StudioTheme.Values.border
+ id: background
+ color: control.style.background.idle
+ border.color: control.style.border.idle
+ border.width: control.style.borderWidth
anchors.centerIn: parent
- width: matchParity(translationIndicator.height, StudioTheme.Values.smallRectWidth)
- height: matchParity(translationIndicator.height, StudioTheme.Values.smallRectWidth)
+ width: background.matchParity(control.height, control.style.smallControlSize.width)
+ height: background.matchParity(control.height, control.style.smallControlSize.height)
function matchParity(root, value) {
var v = Math.round(value)
@@ -37,23 +39,23 @@ Item {
}
MouseArea {
- id: translationIndicatorMouseArea
+ id: mouseArea
anchors.fill: parent
hoverEnabled: true
onPressed: function(mouse) { mouse.accepted = true }
onClicked: {
- translationIndicator.checked = !translationIndicator.checked
- translationIndicator.clicked()
+ control.checked = !control.checked
+ control.clicked()
}
}
}
T.Label {
- id: translationIndicatorIcon
+ id: icon
text: "tr"
- color: StudioTheme.Values.themeTextColor
+ color: control.style.icon.idle
font.family: StudioTheme.Constants.font.family
- font.pixelSize: StudioTheme.Values.myIconFontSize
+ font.pixelSize: control.style.baseIconFontSize
font.italic: true
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
@@ -62,36 +64,35 @@ Item {
states: [
State {
name: "default"
- when: translationIndicator.enabled && !translationIndicator.pressed
- && !translationIndicator.checked
+ when: control.enabled && !control.pressed && !control.checked
PropertyChanges {
- target: translationIndicatorIcon
- color: StudioTheme.Values.themeIconColor
+ target: icon
+ color: control.style.icon.idle
}
},
State {
name: "press"
- when: translationIndicator.enabled && translationIndicator.pressed
+ when: control.enabled && control.pressed
PropertyChanges {
- target: translationIndicatorIcon
- color: StudioTheme.Values.themeIconColorInteraction
+ target: icon
+ color: control.style.icon.interaction
}
},
State {
name: "check"
- when: translationIndicator.enabled && !translationIndicator.pressed
- && translationIndicator.checked
+ when: control.enabled && !control.pressed
+ && control.checked
PropertyChanges {
- target: translationIndicatorIcon
- color: StudioTheme.Values.themeIconColorSelected
+ target: icon
+ color: control.style.icon.selected
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
- target: translationIndicatorIcon
- color: StudioTheme.Values.themeTextColorDisabled
+ target: icon
+ color: control.style.icon.disabled
}
}
]
@@ -100,49 +101,49 @@ Item {
states: [
State {
name: "default"
- when: myControl.enabled && !translationIndicator.hover
- && !translationIndicator.pressed && !myControl.hover
- && !myControl.edit && !translationIndicator.checked
+ when: control.__parentControl.enabled && !control.hover && !control.pressed
+ && !control.__parentControl.hover && !control.__parentControl.edit
+ && !control.checked
PropertyChanges {
- target: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackground
- border.color: StudioTheme.Values.themeControlOutline
+ target: background
+ color: control.style.background.idle
+ border.color: control.style.border.idle
}
},
State {
name: "globalHover"
- when: myControl.hover && !translationIndicator.hover
+ when: control.__parentControl.hover && !control.hover
PropertyChanges {
- target: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackgroundGlobalHover
- border.color: StudioTheme.Values.themeControlOutline
+ target: background
+ color: control.style.background.globalHover
+ border.color: control.style.border.idle
}
},
State {
name: "hover"
- when: translationIndicator.hover && !translationIndicator.pressed
+ when: control.hover && !control.pressed
PropertyChanges {
- target: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackgroundHover
- border.color: StudioTheme.Values.themeControlOutline
+ target: background
+ color: control.style.background.hover
+ border.color: control.style.border.idle
}
},
State {
name: "press"
- when: translationIndicator.hover && translationIndicator.pressed
+ when: control.hover && control.pressed
PropertyChanges {
- target: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackgroundInteraction
- border.color: StudioTheme.Values.themeControlOutlineInteraction
+ target: background
+ color: control.style.background.interaction
+ border.color: control.style.border.interaction
}
},
State {
name: "disable"
- when: !myControl.enabled
+ when: !control.__parentControl.enabled
PropertyChanges {
- target: translationIndicatorBackground
- color: StudioTheme.Values.themeControlBackgroundDisabled
- border.color: StudioTheme.Values.themeControlOutlineDisabled
+ target: background
+ color: control.style.background.disabled
+ border.color: control.style.border.disabled
}
}
]
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
index 2c23fa33dd..752f2bc6e4 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
@@ -1,38 +1,38 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Controls 2.15
+import QtQuick
+//import QtQuick.Controls
import StudioTheme 1.0 as StudioTheme
ScrollBar {
- id: scrollBar
+ id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
- property bool scrollBarVisible: parent.contentHeight > scrollBar.height
+ property bool scrollBarVisible: parent.contentHeight > control.height
- minimumSize: scrollBar.width / scrollBar.height
+ minimumSize: control.width / control.height
orientation: Qt.Vertical
- policy: scrollBar.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
+ policy: control.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
height: parent.availableHeight
- (parent.bothVisible ? parent.horizontalThickness : 0)
- padding: scrollBar.active ? StudioTheme.Values.scrollBarActivePadding
- : StudioTheme.Values.scrollBarInactivePadding
+ padding: control.active ? control.style.scrollBarActivePadding
+ : control.style.scrollBarInactivePadding
background: Rectangle {
- implicitWidth: StudioTheme.Values.scrollBarThickness
- implicitHeight: StudioTheme.Values.scrollBarThickness
- color: StudioTheme.Values.themeScrollBarTrack
+ implicitWidth: control.style.scrollBarThickness
+ implicitHeight: control.style.scrollBarThickness
+ color: control.style.scrollBar.track
}
contentItem: Rectangle {
- implicitWidth: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
- implicitHeight: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
- color: StudioTheme.Values.themeScrollBarHandle
+ implicitWidth: control.style.scrollBarThickness - 2 * control.padding
+ implicitHeight: control.style.scrollBarThickness - 2 * control.padding
+ color: control.style.scrollBar.handle
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir
index fea940d878..d6071b6ff2 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir
@@ -49,3 +49,4 @@ TextField 1.0 TextField.qml
ToolTip 1.0 ToolTip.qml
TranslationIndicator 1.0 TranslationIndicator.qml
VerticalScrollBar 1.0 VerticalScrollBar.qml
+TopLevelComboBox 1.0 TopLevelComboBox.qml
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
index 6bbaf1cb35..750fb77d35 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml
@@ -1,7 +1,7 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
pragma Singleton
-import QtQuick 2.10
+import QtQuick
InternalConstants {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml
new file mode 100644
index 0000000000..f8e959d825
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml
@@ -0,0 +1,190 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+QtObject {
+ id: root
+
+ property real smallFontSize: Values.smallFontSize
+ property real baseFontSize: Values.baseFontSize
+ property real mediumFontSize: Values.mediumFontSize
+ property real bigFontSize: Values.bigFontSize
+
+ property real smallIconFontSize: Values.smallIconFontSize
+ property real baseIconFontSize: Values.baseIconFontSize
+ property real mediumIconFontSize: Values.mediumIconFontSize
+ property real bigIconFontSize: Values.bigIconFontSize
+
+ property real borderWidth: Values.border
+ property real radius: Values.radius
+
+ property size smallControlSize: Qt.size(Values.smallRectWidth,
+ Values.smallRectWidth)
+ property size squareControlSize: Qt.size(root.controlSize.height,
+ root.controlSize.height)
+ property size controlSize: Qt.size(Values.defaultControlWidth,
+ Values.defaultControlHeight)
+
+ property size smallIconSize: Qt.size(Values.spinControlIconSizeMulti,
+ Values.spinControlIconSizeMulti)
+
+ // TODO only used once
+ property size spinBoxIndicatorSize: Qt.size(Values.spinBoxIndicatorWidth,
+ Values.spinBoxIndicatorHeight)
+
+ property size actionIndicatorSize: Qt.size(Values.actionIndicatorWidth,
+ Values.actionIndicatorHeight)
+
+ property size indicatorIconSize: Qt.size(Values.iconAreaWidth,
+ Values.height)
+
+ property size radioButtonIndicatorSize: Qt.size(Values.radioButtonIndicatorWidth,
+ Values.radioButtonIndicatorHeight)
+
+ // Special properties
+ property real maxTextAreaPopupHeight: Values.maxTextAreaPopupHeight
+ property real maxComboBoxPopupHeight: Values.maxComboBoxPopupHeight
+ property real inputHorizontalPadding: Values.inputHorizontalPadding
+ property real controlSpacing: Values.checkBoxSpacing
+ property real dialogPadding: Values.dialogPadding
+ property real dialogButtonSpacing: Values.dialogButtonSpacing
+
+ property real contextMenuLabelSpacing: Values.contextMenuLabelSpacing
+ property real contextMenuHorizontalPadding: Values.contextMenuHorizontalPadding
+
+ property real sliderTrackHeight: Values.sliderTrackHeight
+ property size sliderHandleSize: Qt.size(Values.sliderHandleWidth,
+ Values.sliderHandleHeight)
+ property real sliderFontSize: Values.sliderFontSize
+ property real sliderPadding: Values.sliderPadding
+ property real sliderMargin: Values.sliderMargin
+ property size sliderPointerSize: Qt.size(Values.sliderPointerWidth,
+ Values.sliderPointerHeight)
+
+ property real sectionColumnSpacing: Values.sectionColumnSpacing
+ property real sectionRowSpacing: Values.sectionRowSpacing
+ property real sectionHeadHeight: Values.sectionHeadHeight
+ property real sectionHeadSpacerHeight: Values.sectionHeadSpacerHeight
+
+ property real scrollBarThickness: Values.scrollBarThickness
+ property real scrollBarActivePadding: Values.scrollBarActivePadding
+ property real scrollBarInactivePadding: Values.scrollBarInactivePadding
+
+ // Special colors
+ property color interaction: Values.themeInteraction
+ property color interactionHover: Values.themeInteractionHover
+ // TODO needs to removed in the future
+ property color thumbnailLabelBackground: Values.themeThumbnailLabelBackground
+
+ // Colors
+ component BackgroundColors: QtObject {
+ property color idle: Values.themeControlBackground
+ property color interaction: Values.themeControlBackgroundInteraction
+ property color globalHover: Values.themeControlBackground_toolbarHover
+ property color hover: Values.themeControlBackground_toolbarHover
+ property color disabled: Values.themeControlBackgroundDisabled
+ }
+
+ property BackgroundColors background: BackgroundColors {}
+
+ component BorderColors: QtObject {
+ property color idle: Values.themeControlOutline
+ property color interaction: Values.themeControlOutlineInteraction
+ property color hover: Values.controlOutline_toolbarHover
+ property color disabled: Values.themeControlBackground
+ }
+
+ property BorderColors border: BorderColors {}
+
+ component TextColors: QtObject {
+ property color idle: Values.themeTextColor
+ property color interaction: Values.themeTextSelectedTextColor
+ property color hover: Values.themeTextColor
+ property color disabled: Values.themeTextColorDisabled
+ property color selection: Values.themeTextSelectionColor
+ property color selectedText: Values.themeTextSelectedTextColor
+ property color placeholder: Values.themePlaceholderTextColor
+ property color placeholderHover: Values.themePlaceholderTextColor
+ property color placeholderInteraction: Values.themePlaceholderTextColorInteraction
+ }
+
+ property TextColors text: TextColors {}
+
+ component IconColors: QtObject {
+ property color idle: Values.themeIconColor
+ property color interaction: Values.themeIconColor
+ property color selected: Values.themeIconColorSelected
+ property color hover: Values.themeIconColorHover
+ property color disabled: Values.themeIconColorDisabled
+ }
+
+ property IconColors icon: IconColors {}
+
+ // Link- and InfinityLoopIndicator
+ component IndicatorColors: QtObject {
+ property color idle: Values.themeLinkIndicatorColor
+ property color interaction: Values.themeLinkIndicatorColorHover
+ property color hover: Values.themeLinkIndicatorColorInteraction
+ property color disabled: Values.themeLinkIndicatorColorDisabled
+ }
+
+ property IndicatorColors indicator: IndicatorColors {}
+
+ component SliderColors: QtObject {
+ property color activeTrack: Values.themeSliderActiveTrack
+ property color activeTrackHover: Values.themeSliderActiveTrackHover
+ property color activeTrackFocus: Values.themeSliderActiveTrackFocus
+ property color inactiveTrack: Values.themeSliderInactiveTrack
+ property color inactiveTrackHover: Values.themeSliderInactiveTrackHover
+ property color inactiveTrackFocus: Values.themeSliderInactiveTrackFocus
+ property color handle: Values.themeSliderHandle
+ property color handleHover: Values.themeSliderHandleHover
+ property color handleFocus: Values.themeSliderHandleFocus
+ property color handleInteraction: Values.themeSliderHandleInteraction
+ }
+
+ property SliderColors slider: SliderColors {}
+
+ component ScrollBarColors: QtObject {
+ property color track: Values.themeScrollBarTrack
+ property color handle: Values.themeScrollBarHandle
+ }
+
+ property ScrollBarColors scrollBar: ScrollBarColors {}
+
+ component SectionColors: QtObject {
+ property color head: Values.themeSectionHeadBackground
+ }
+
+ property SectionColors section: SectionColors {}
+
+ component PanelColors: QtObject {
+ property color background: Values.themePanelBackground
+ }
+
+ property PanelColors panel: PanelColors {}
+
+ component PopupColors: QtObject {
+ property color background: Values.themePopupBackground
+ property color overlay: Values.themePopupOverlayColor
+ }
+
+ property PopupColors popup: PopupColors {}
+
+ component DialogColors: QtObject {
+ property color background: Values.themeDialogBackground
+ property color border: Values.themeDialogOutline
+ property color overlay: Values.themeDialogBackground
+ }
+
+ property DialogColors dialog: DialogColors {}
+
+ component ToolTipColors: QtObject {
+ property color background: Values.themeToolTipBackground
+ property color border: Values.themeToolTipOutline
+ property color text: Values.themeToolTipText
+ }
+
+ property ToolTipColors toolTip: ToolTipColors {}
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/DefaultStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/DefaultStyle.qml
new file mode 100644
index 0000000000..46c25ad4d5
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/DefaultStyle.qml
@@ -0,0 +1,6 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
index 3df7a9e5dd..1a07944b24 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
@@ -1,7 +1,7 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
QtObject {
readonly property int width: 1920
@@ -21,183 +21,321 @@ QtObject {
readonly property string addRowAfter: "\u0026"
readonly property string addRowBefore: "\u0027"
readonly property string addTable: "\u0028"
- readonly property string adsClose: "\u0029"
- readonly property string adsDetach: "\u002A"
- readonly property string adsDropDown: "\u002B"
- readonly property string alias: "\u002C"
- readonly property string aliasAnimated: "\u002D"
- readonly property string alignBottom: "\u002E"
- readonly property string alignCenterHorizontal: "\u002F"
- readonly property string alignCenterVertical: "\u0030"
- readonly property string alignLeft: "\u0031"
- readonly property string alignRight: "\u0032"
- readonly property string alignTo: "\u0033"
- readonly property string alignTop: "\u0034"
- readonly property string anchorBaseline: "\u0035"
- readonly property string anchorBottom: "\u0036"
- readonly property string anchorFill: "\u0037"
- readonly property string anchorLeft: "\u0038"
- readonly property string anchorRight: "\u0039"
- readonly property string anchorTop: "\u003A"
- readonly property string animatedProperty: "\u003B"
- readonly property string annotationBubble: "\u003C"
- readonly property string annotationDecal: "\u003D"
- readonly property string applyMaterialToSelected: "\u003E"
- readonly property string assign: "\u003F"
- readonly property string bevelAll: "\u0040"
- readonly property string bevelCorner: "\u0041"
- readonly property string centerHorizontal: "\u0042"
- readonly property string centerVertical: "\u0043"
- readonly property string closeCross: "\u0044"
- readonly property string closeLink: "\u0045"
- readonly property string colorPopupClose: "\u0046"
- readonly property string columnsAndRows: "\u0047"
- readonly property string copyLink: "\u0048"
- readonly property string copyStyle: "\u0049"
- readonly property string cornerA: "\u004A"
- readonly property string cornerB: "\u004B"
- readonly property string cornersAll: "\u004C"
- readonly property string curveDesigner: "\u004D"
- readonly property string curveEditor: "\u004E"
- readonly property string customMaterialEditor: "\u004F"
- readonly property string decisionNode: "\u0050"
- readonly property string deleteColumn: "\u0051"
- readonly property string deleteMaterial: "\u0052"
- readonly property string deleteRow: "\u0053"
- readonly property string deleteTable: "\u0054"
- readonly property string detach: "\u0055"
- readonly property string distributeBottom: "\u0056"
- readonly property string distributeCenterHorizontal: "\u0057"
- readonly property string distributeCenterVertical: "\u0058"
- readonly property string distributeLeft: "\u0059"
- readonly property string distributeOriginBottomRight: "\u005A"
- readonly property string distributeOriginCenter: "\u005B"
- readonly property string distributeOriginNone: "\u005C"
- readonly property string distributeOriginTopLeft: "\u005D"
- readonly property string distributeRight: "\u005E"
- readonly property string distributeSpacingHorizontal: "\u005F"
- readonly property string distributeSpacingVertical: "\u0060"
- readonly property string distributeTop: "\u0061"
- readonly property string download: "\u0062"
- readonly property string downloadUnavailable: "\u0063"
- readonly property string downloadUpdate: "\u0064"
- readonly property string downloaded: "\u0065"
- readonly property string edit: "\u0066"
- readonly property string eyeDropper: "\u0067"
- readonly property string favorite: "\u0068"
- readonly property string flowAction: "\u0069"
- readonly property string flowTransition: "\u006A"
- readonly property string fontStyleBold: "\u006B"
- readonly property string fontStyleItalic: "\u006C"
- readonly property string fontStyleStrikethrough: "\u006D"
- readonly property string fontStyleUnderline: "\u006E"
- readonly property string gradient: "\u006F"
- readonly property string gridView: "\u0070"
- readonly property string idAliasOff: "\u0071"
- readonly property string idAliasOn: "\u0072"
- readonly property string imported: "\u0073"
- readonly property string infinity: "\u0074"
- readonly property string keyframe: "\u0075"
- readonly property string linkTriangle: "\u0076"
- readonly property string linked: "\u0077"
- readonly property string listView: "\u0078"
- readonly property string lockOff: "\u0079"
- readonly property string lockOn: "\u007A"
- readonly property string materialPreviewEnvironment: "\u007B"
- readonly property string materialPreviewModel: "\u007C"
- readonly property string mergeCells: "\u007D"
- readonly property string minus: "\u007E"
- readonly property string mirror: "\u007F"
- readonly property string newMaterial: "\u0080"
- readonly property string openLink: "\u0081"
- readonly property string openMaterialBrowser: "\u0082"
- readonly property string orientation: "\u0083"
- readonly property string paddingEdge: "\u0084"
- readonly property string paddingFrame: "\u0085"
- readonly property string pasteStyle: "\u0086"
- readonly property string pause: "\u0087"
- readonly property string pin: "\u0088"
- readonly property string play: "\u0089"
- readonly property string plus: "\u008A"
- readonly property string promote: "\u008B"
- readonly property string readOnly: "\u008C"
- readonly property string redo: "\u008D"
- readonly property string rotationFill: "\u008E"
- readonly property string rotationOutline: "\u008F"
- readonly property string s_anchors: "\u0090"
- readonly property string s_annotations: "\u0091"
- readonly property string s_arrange: "\u0092"
- readonly property string s_boundingBox: "\u0093"
- readonly property string s_component: "\u0094"
- readonly property string s_connections: "\u0095"
- readonly property string s_edit: "\u0096"
- readonly property string s_enterComponent: "\u0097"
- readonly property string s_eventList: "\u0098"
- readonly property string s_group: "\u0099"
- readonly property string s_layouts: "\u009A"
- readonly property string s_merging: "\u009B"
- readonly property string s_mouseArea: "\u009D"
- readonly property string s_positioners: "\u009E"
- readonly property string s_selection: "\u009F"
- readonly property string s_snapping: "\u00A0"
- readonly property string s_timeline: "\u00A1"
- readonly property string s_visibility: "\u00A2"
- readonly property string search: "\u00A3"
- readonly property string sectionToggle: "\u00A4"
- readonly property string splitColumns: "\u00A5"
- readonly property string splitRows: "\u00A6"
- readonly property string startNode: "\u00A7"
- readonly property string testIcon: "\u00A8"
- readonly property string textAlignBottom: "\u00A9"
- readonly property string textAlignCenter: "\u00AA"
- readonly property string textAlignJustified: "\u00AB"
- readonly property string textAlignLeft: "\u00AC"
- readonly property string textAlignMiddle: "\u00AE"
- readonly property string textAlignRight: "\u00AF"
- readonly property string textAlignTop: "\u00B0"
- readonly property string textBulletList: "\u00B1"
- readonly property string textFullJustification: "\u00B2"
- readonly property string textNumberedList: "\u00B3"
- readonly property string tickIcon: "\u00B4"
- readonly property string topToolbar_annotations: "\u00B5"
- readonly property string topToolbar_closeFile: "\u00B6"
- readonly property string topToolbar_designMode: "\u00B7"
- readonly property string topToolbar_enterComponent: "\u00B8"
- readonly property string topToolbar_home: "\u00B9"
- readonly property string topToolbar_makeComponent: "\u00BA"
- readonly property string topToolbar_navFile: "\u00BB"
- readonly property string topToolbar_runProject: "\u00BC"
- readonly property string translationCreateFiles: "\u00BD"
- readonly property string translationCreateReport: "\u00BE"
- readonly property string translationExport: "\u00BF"
- readonly property string translationImport: "\u00C0"
- readonly property string translationSelectLanguages: "\u00C1"
- readonly property string translationTest: "\u00C2"
- readonly property string transparent: "\u00C3"
- readonly property string triState: "\u00C4"
- readonly property string triangleArcA: "\u00C5"
- readonly property string triangleArcB: "\u00C6"
- readonly property string triangleCornerA: "\u00C7"
- readonly property string triangleCornerB: "\u00C8"
- readonly property string unLinked: "\u00C9"
- readonly property string undo: "\u00CA"
- readonly property string unpin: "\u00CB"
- readonly property string upDownIcon: "\u00CC"
- readonly property string upDownSquare2: "\u00CD"
- readonly property string visibilityOff: "\u00CE"
- readonly property string visibilityOn: "\u00CF"
- readonly property string wildcard: "\u00D0"
- readonly property string wizardsAutomotive: "\u00D1"
- readonly property string wizardsDesktop: "\u00D2"
- readonly property string wizardsGeneric: "\u00D3"
- readonly property string wizardsMcuEmpty: "\u00D4"
- readonly property string wizardsMcuGraph: "\u00D5"
- readonly property string wizardsMobile: "\u00D6"
- readonly property string wizardsUnknown: "\u00D7"
- readonly property string zoomAll: "\u00D8"
- readonly property string zoomIn: "\u00D9"
- readonly property string zoomOut: "\u00DA"
- readonly property string zoomSelection: "\u00DB"
+ readonly property string add_medium: "\u0029"
+ readonly property string add_small: "\u002A"
+ readonly property string adsClose: "\u002B"
+ readonly property string adsDetach: "\u002C"
+ readonly property string adsDropDown: "\u002D"
+ readonly property string alias: "\u002E"
+ readonly property string aliasAnimated: "\u002F"
+ readonly property string alignBottom: "\u0030"
+ readonly property string alignCenterHorizontal: "\u0031"
+ readonly property string alignCenterVertical: "\u0032"
+ readonly property string alignLeft: "\u0033"
+ readonly property string alignRight: "\u0034"
+ readonly property string alignTo: "\u0035"
+ readonly property string alignToCam_medium: "\u0036"
+ readonly property string alignToCamera_small: "\u0037"
+ readonly property string alignToObject_small: "\u0038"
+ readonly property string alignToView_medium: "\u0039"
+ readonly property string alignTop: "\u003A"
+ readonly property string anchorBaseline: "\u003B"
+ readonly property string anchorBottom: "\u003C"
+ readonly property string anchorFill: "\u003D"
+ readonly property string anchorLeft: "\u003E"
+ readonly property string anchorRight: "\u003F"
+ readonly property string anchorTop: "\u0040"
+ readonly property string anchors_small: "\u0041"
+ readonly property string animatedProperty: "\u0042"
+ readonly property string annotationBubble: "\u0043"
+ readonly property string annotationDecal: "\u0044"
+ readonly property string annotations_large: "\u0045"
+ readonly property string annotations_small: "\u0046"
+ readonly property string applyMaterialToSelected: "\u0047"
+ readonly property string apply_medium: "\u0048"
+ readonly property string apply_small: "\u0049"
+ readonly property string arrange_small: "\u004A"
+ readonly property string arrow_small: "\u004B"
+ readonly property string assign: "\u004C"
+ readonly property string attach_medium: "\u004D"
+ readonly property string back_medium: "\u004E"
+ readonly property string backspace_small: "\u004F"
+ readonly property string bevelAll: "\u0050"
+ readonly property string bevelCorner: "\u0051"
+ readonly property string bezier_medium: "\u0052"
+ readonly property string binding_medium: "\u0053"
+ readonly property string bounds_small: "\u0054"
+ readonly property string branch_medium: "\u0055"
+ readonly property string camera_small: "\u0056"
+ readonly property string centerHorizontal: "\u0057"
+ readonly property string centerVertical: "\u0058"
+ readonly property string cleanLogs_medium: "\u0059"
+ readonly property string closeCross: "\u005A"
+ readonly property string closeFile_large: "\u005B"
+ readonly property string closeLink: "\u005C"
+ readonly property string close_small: "\u005D"
+ readonly property string colorPopupClose: "\u005E"
+ readonly property string colorSelection_medium: "\u005F"
+ readonly property string columnsAndRows: "\u0060"
+ readonly property string cone_medium: "\u0061"
+ readonly property string cone_small: "\u0062"
+ readonly property string connection_small: "\u0063"
+ readonly property string connections_medium: "\u0064"
+ readonly property string copyLink: "\u0065"
+ readonly property string copyStyle: "\u0066"
+ readonly property string copy_small: "\u0067"
+ readonly property string cornerA: "\u0068"
+ readonly property string cornerB: "\u0069"
+ readonly property string cornersAll: "\u006A"
+ readonly property string createComponent_large: "\u006B"
+ readonly property string createComponent_small: "\u006C"
+ readonly property string create_medium: "\u006D"
+ readonly property string create_small: "\u006E"
+ readonly property string cube_medium: "\u006F"
+ readonly property string cube_small: "\u0070"
+ readonly property string curveDesigner: "\u0071"
+ readonly property string curveDesigner_medium: "\u0072"
+ readonly property string curveEditor: "\u0073"
+ readonly property string customMaterialEditor: "\u0074"
+ readonly property string cylinder_medium: "\u0075"
+ readonly property string cylinder_small: "\u0076"
+ readonly property string decisionNode: "\u0077"
+ readonly property string deleteColumn: "\u0078"
+ readonly property string deleteMaterial: "\u0079"
+ readonly property string deleteRow: "\u007A"
+ readonly property string deleteTable: "\u007B"
+ readonly property string delete_medium: "\u007C"
+ readonly property string delete_small: "\u007D"
+ readonly property string designMode_large: "\u007E"
+ readonly property string detach: "\u007F"
+ readonly property string directionalLight_small: "\u0080"
+ readonly property string distributeBottom: "\u0081"
+ readonly property string distributeCenterHorizontal: "\u0082"
+ readonly property string distributeCenterVertical: "\u0083"
+ readonly property string distributeLeft: "\u0084"
+ readonly property string distributeOriginBottomRight: "\u0085"
+ readonly property string distributeOriginCenter: "\u0086"
+ readonly property string distributeOriginNone: "\u0087"
+ readonly property string distributeOriginTopLeft: "\u0088"
+ readonly property string distributeRight: "\u0089"
+ readonly property string distributeSpacingHorizontal: "\u008A"
+ readonly property string distributeSpacingVertical: "\u008B"
+ readonly property string distributeTop: "\u008C"
+ readonly property string download: "\u008D"
+ readonly property string downloadUnavailable: "\u008E"
+ readonly property string downloadUpdate: "\u008F"
+ readonly property string downloaded: "\u0090"
+ readonly property string duplicate_small: "\u0091"
+ readonly property string edit: "\u0092"
+ readonly property string editComponent_large: "\u0093"
+ readonly property string editComponent_small: "\u0094"
+ readonly property string editLightOff_medium: "\u0095"
+ readonly property string editLightOn_medium: "\u0096"
+ readonly property string edit_medium: "\u0097"
+ readonly property string edit_small: "\u0098"
+ readonly property string events_small: "\u0099"
+ readonly property string export_medium: "\u009A"
+ readonly property string eyeDropper: "\u009B"
+ readonly property string favorite: "\u009D"
+ readonly property string fitAll_medium: "\u009E"
+ readonly property string fitSelected_small: "\u009F"
+ readonly property string fitSelection_medium: "\u00A0"
+ readonly property string fitToView_medium: "\u00A1"
+ readonly property string flowAction: "\u00A2"
+ readonly property string flowTransition: "\u00A3"
+ readonly property string fontStyleBold: "\u00A4"
+ readonly property string fontStyleItalic: "\u00A5"
+ readonly property string fontStyleStrikethrough: "\u00A6"
+ readonly property string fontStyleUnderline: "\u00A7"
+ readonly property string forward_medium: "\u00A8"
+ readonly property string globalOrient_medium: "\u00A9"
+ readonly property string gradient: "\u00AA"
+ readonly property string gridView: "\u00AB"
+ readonly property string grid_medium: "\u00AC"
+ readonly property string group_small: "\u00AE"
+ readonly property string home_large: "\u00AF"
+ readonly property string idAliasOff: "\u00B0"
+ readonly property string idAliasOn: "\u00B1"
+ readonly property string import_medium: "\u00B2"
+ readonly property string imported: "\u00B3"
+ readonly property string importedModels_small: "\u00B4"
+ readonly property string infinity: "\u00B5"
+ readonly property string invisible_medium: "\u00B6"
+ readonly property string keyframe: "\u00B7"
+ readonly property string languageList_medium: "\u00B8"
+ readonly property string layouts_small: "\u00B9"
+ readonly property string lights_small: "\u00BA"
+ readonly property string linear_medium: "\u00BB"
+ readonly property string linkTriangle: "\u00BC"
+ readonly property string linked: "\u00BD"
+ readonly property string listView: "\u00BE"
+ readonly property string list_medium: "\u00BF"
+ readonly property string localOrient_medium: "\u00C0"
+ readonly property string lockOff: "\u00C1"
+ readonly property string lockOn: "\u00C2"
+ readonly property string loopPlayback_medium: "\u00C3"
+ readonly property string materialBrowser_medium: "\u00C4"
+ readonly property string materialPreviewEnvironment: "\u00C5"
+ readonly property string materialPreviewModel: "\u00C6"
+ readonly property string material_medium: "\u00C7"
+ readonly property string mergeCells: "\u00C8"
+ readonly property string merge_small: "\u00C9"
+ readonly property string minus: "\u00CA"
+ readonly property string mirror: "\u00CB"
+ readonly property string more_medium: "\u00CC"
+ readonly property string mouseArea_small: "\u00CD"
+ readonly property string moveDown_medium: "\u00CE"
+ readonly property string moveInwards_medium: "\u00CF"
+ readonly property string moveUp_medium: "\u00D0"
+ readonly property string moveUpwards_medium: "\u00D1"
+ readonly property string move_medium: "\u00D2"
+ readonly property string newMaterial: "\u00D3"
+ readonly property string nextFile_large: "\u00D4"
+ readonly property string openLink: "\u00D5"
+ readonly property string openMaterialBrowser: "\u00D6"
+ readonly property string orientation: "\u00D7"
+ readonly property string orthCam_medium: "\u00D8"
+ readonly property string orthCam_small: "\u00D9"
+ readonly property string paddingEdge: "\u00DA"
+ readonly property string paddingFrame: "\u00DB"
+ readonly property string particleAnimation_medium: "\u00DC"
+ readonly property string pasteStyle: "\u00DD"
+ readonly property string paste_small: "\u00DE"
+ readonly property string pause: "\u00DF"
+ readonly property string perspectiveCam_medium: "\u00E0"
+ readonly property string perspectiveCam_small: "\u00E1"
+ readonly property string pin: "\u00E2"
+ readonly property string plane_medium: "\u00E3"
+ readonly property string plane_small: "\u00E4"
+ readonly property string play: "\u00E5"
+ readonly property string playFill_medium: "\u00E6"
+ readonly property string playOutline_medium: "\u00E7"
+ readonly property string plus: "\u00E8"
+ readonly property string pointLight_small: "\u00E9"
+ readonly property string positioners_small: "\u00EA"
+ readonly property string previewEnv_medium: "\u00EB"
+ readonly property string previousFile_large: "\u00EC"
+ readonly property string promote: "\u00ED"
+ readonly property string properties_medium: "\u00EE"
+ readonly property string readOnly: "\u00EF"
+ readonly property string recordFill_medium: "\u00F0"
+ readonly property string recordOutline_medium: "\u00F1"
+ readonly property string redo: "\u00F2"
+ readonly property string reload_medium: "\u00F3"
+ readonly property string remove_medium: "\u00F4"
+ readonly property string remove_small: "\u00F5"
+ readonly property string rename_small: "\u00F6"
+ readonly property string replace_small: "\u00F7"
+ readonly property string resetView_small: "\u00F8"
+ readonly property string restartParticles_medium: "\u00F9"
+ readonly property string reverseOrder_medium: "\u00FA"
+ readonly property string roatate_medium: "\u00FB"
+ readonly property string rotationFill: "\u00FC"
+ readonly property string rotationOutline: "\u00FD"
+ readonly property string runProjFill_large: "\u00FE"
+ readonly property string runProjOutline_large: "\u00FF"
+ readonly property string s_anchors: "\u0100"
+ readonly property string s_annotations: "\u0101"
+ readonly property string s_arrange: "\u0102"
+ readonly property string s_boundingBox: "\u0103"
+ readonly property string s_component: "\u0104"
+ readonly property string s_connections: "\u0105"
+ readonly property string s_edit: "\u0106"
+ readonly property string s_enterComponent: "\u0107"
+ readonly property string s_eventList: "\u0108"
+ readonly property string s_group: "\u0109"
+ readonly property string s_layouts: "\u010A"
+ readonly property string s_merging: "\u010B"
+ readonly property string s_mouseArea: "\u010C"
+ readonly property string s_positioners: "\u010D"
+ readonly property string s_selection: "\u010E"
+ readonly property string s_snapping: "\u010F"
+ readonly property string s_timeline: "\u0110"
+ readonly property string s_visibility: "\u0111"
+ readonly property string saveLogs_medium: "\u0112"
+ readonly property string scale_medium: "\u0113"
+ readonly property string search: "\u0114"
+ readonly property string search_small: "\u0115"
+ readonly property string sectionToggle: "\u0116"
+ readonly property string selectFill_medium: "\u0117"
+ readonly property string selectOutline_medium: "\u0118"
+ readonly property string selectParent_small: "\u0119"
+ readonly property string selection_small: "\u011A"
+ readonly property string settings_medium: "\u011B"
+ readonly property string signal_small: "\u011C"
+ readonly property string snapping_small: "\u011D"
+ readonly property string sphere_medium: "\u011E"
+ readonly property string sphere_small: "\u011F"
+ readonly property string splitColumns: "\u0120"
+ readonly property string splitRows: "\u0121"
+ readonly property string spotLight_small: "\u0122"
+ readonly property string stackedContainer_small: "\u0123"
+ readonly property string startNode: "\u0124"
+ readonly property string step_medium: "\u0125"
+ readonly property string stop_medium: "\u0126"
+ readonly property string testIcon: "\u0127"
+ readonly property string textAlignBottom: "\u0128"
+ readonly property string textAlignCenter: "\u0129"
+ readonly property string textAlignJustified: "\u012A"
+ readonly property string textAlignLeft: "\u012B"
+ readonly property string textAlignMiddle: "\u012C"
+ readonly property string textAlignRight: "\u012D"
+ readonly property string textAlignTop: "\u012E"
+ readonly property string textBulletList: "\u012F"
+ readonly property string textFullJustification: "\u0130"
+ readonly property string textNumberedList: "\u0131"
+ readonly property string textures_medium: "\u0132"
+ readonly property string tickIcon: "\u0133"
+ readonly property string tickMark_small: "\u0134"
+ readonly property string timeline_small: "\u0135"
+ readonly property string toEndFrame_medium: "\u0136"
+ readonly property string toNextFrame_medium: "\u0137"
+ readonly property string toPrevFrame_medium: "\u0138"
+ readonly property string toStartFrame_medium: "\u0139"
+ readonly property string topToolbar_annotations: "\u013A"
+ readonly property string topToolbar_closeFile: "\u013B"
+ readonly property string topToolbar_designMode: "\u013C"
+ readonly property string topToolbar_enterComponent: "\u013D"
+ readonly property string topToolbar_home: "\u013E"
+ readonly property string topToolbar_makeComponent: "\u013F"
+ readonly property string topToolbar_navFile: "\u0140"
+ readonly property string topToolbar_runProject: "\u0141"
+ readonly property string translationCreateFiles: "\u0142"
+ readonly property string translationCreateReport: "\u0143"
+ readonly property string translationExport: "\u0144"
+ readonly property string translationImport: "\u0145"
+ readonly property string translationSelectLanguages: "\u0146"
+ readonly property string translationTest: "\u0147"
+ readonly property string transparent: "\u0148"
+ readonly property string triState: "\u0149"
+ readonly property string triangleArcA: "\u014A"
+ readonly property string triangleArcB: "\u014B"
+ readonly property string triangleCornerA: "\u014C"
+ readonly property string triangleCornerB: "\u014D"
+ readonly property string unLinked: "\u014E"
+ readonly property string undo: "\u014F"
+ readonly property string unify_medium: "\u0150"
+ readonly property string unpin: "\u0151"
+ readonly property string upDownIcon: "\u0152"
+ readonly property string upDownSquare2: "\u0153"
+ readonly property string visibilityOff: "\u0154"
+ readonly property string visibilityOn: "\u0155"
+ readonly property string visible_medium: "\u0156"
+ readonly property string visible_small: "\u0157"
+ readonly property string wildcard: "\u0158"
+ readonly property string wizardsAutomotive: "\u0159"
+ readonly property string wizardsDesktop: "\u015A"
+ readonly property string wizardsGeneric: "\u015B"
+ readonly property string wizardsMcuEmpty: "\u015C"
+ readonly property string wizardsMcuGraph: "\u015D"
+ readonly property string wizardsMobile: "\u015E"
+ readonly property string wizardsUnknown: "\u015F"
+ readonly property string zoomAll: "\u0160"
+ readonly property string zoomIn: "\u0161"
+ readonly property string zoomIn_medium: "\u0162"
+ readonly property string zoomOut: "\u0163"
+ readonly property string zoomOut_medium: "\u0164"
+ readonly property string zoomSelection: "\u0165"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/PrimaryButtonStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/PrimaryButtonStyle.qml
new file mode 100644
index 0000000000..c1cf5be9cf
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/PrimaryButtonStyle.qml
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+ controlSize: Qt.size(Values.topLevelComboWidth, Values.topLevelComboHeight)
+ baseIconFontSize: Values.baseFontSize
+ radius: Values.smallRadius
+
+ icon: ControlStyle.IconColors {
+ idle: Values.themeTextSelectedTextColor
+ hover: Values.themeTextSelectedTextColor
+ disabled: Values.themeToolbarIcon_blocked
+ }
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themeInteraction
+ hover: Values.themePrimaryButton_hoverHighlight
+ interaction: Values.themeInteraction
+ disabled: Values.themeInteraction
+ }
+
+ border: ControlStyle.BorderColors {
+ idle: Values.themeInteraction
+ hover: Values.themePrimaryButton_hoverHighlight
+ interaction: Values.themePrimaryButton_hoverHighlight
+ disabled: Values.themeToolbarIcon_blocked
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/SearchControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/SearchControlStyle.qml
new file mode 100644
index 0000000000..f44fb0fa56
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/SearchControlStyle.qml
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+ radius: Values.smallRadius
+ baseIconFontSize: Values.miniIcon
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.viewBarComboIcon
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themeToolbarBackground
+ hover: Values.themeControlBackground_toolbarHover
+ globalHover: Values.themeControlBackground_toolbarHover
+ interaction: Values.themeToolbarBackground
+ }
+
+ text: ControlStyle.TextColors {
+ idle: Values.themeTextColor
+ interaction: Values.themeTextSelectedTextColor
+ hover: Values.themeTextColor
+ disabled: Values.themeToolbarIcon_blocked
+ selection: Values.themeTextSelectionColor
+ selectedText: Values.themeTextSelectedTextColor
+ //placeholder: Values.themeTextColorDisabled
+ //placeholderHover: Values.themeTextColor
+ placeholderInteraction: Values.themeTextColor
+ }
+
+ border: ControlStyle.BorderColors {
+ idle: Values.controlOutline_toolbarIdle
+ hover: Values.controlOutline_toolbarHover
+ interaction: Values.themeInteraction
+ }
+
+ icon: ControlStyle.IconColors {
+ idle: Values.themeIconColor
+ interaction: Values.themeIconColorInteraction
+ selected: Values.themeIconColorSelected
+ hover: Values.themeIconColorHover
+ disabled: Values.themeToolbarIcon_blocked
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatesControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatesControlStyle.qml
new file mode 100644
index 0000000000..848d9f55c0
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatesControlStyle.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+ radius: Values.smallRadius
+ baseIconFontSize: Values.baseFont
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.viewBarComboIcon
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themeToolbarBackground
+ hover: Values.themeStateControlBackgroundColor_globalHover
+ globalHover: Values.themeStateControlBackgroundColor_globalHover
+ interaction: Values.themeToolbarBackground
+ }
+ text: ControlStyle.TextColors {
+ idle: Values.themeTextColor
+ interaction: Values.themeTextSelectedTextColor
+ hover: Values.themeTextColor
+ disabled: Values.themeTextColorDisabled
+ selection: Values.themeTextSelectionColor
+ selectedText: Values.themeTextSelectedTextColor
+ placeholder: Values.themeTextColor
+ placeholderInteraction: Values.themeTextColor
+ }
+ border: ControlStyle.BorderColors {
+ idle: Values.controlOutline_toolbarIdle
+ hover: Values.themeStateHighlight
+ interaction: Values.themeInteraction
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarButtonStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarButtonStyle.qml
new file mode 100644
index 0000000000..d0ced4298d
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarButtonStyle.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+
+ baseIconFontSize: Values.bigFont
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.viewBarComboIcon
+
+ radius: Values.smallRadius
+
+ icon: ControlStyle.IconColors {
+ idle: Values.themeTextColor
+ hover: Values.themeTextColor
+ interaction: Values.themeIconColor
+ disabled: "#636363"
+ }
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themecontrolBackground_statusbarIdle
+ hover: Values.themecontrolBackground_statusbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themecontrolBackground_statusbarIdle
+ }
+
+ border: ControlStyle.BorderColors {
+ idle: Values.themecontrolBackground_statusbarIdle
+ hover: Values.themeControlBackground_toolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themecontrolBackground_statusbarIdle
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarControlStyle.qml
new file mode 100644
index 0000000000..c9c2c1abce
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/StatusBarControlStyle.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+
+ radius: Values.smallRadius
+
+ baseIconFontSize: Values.baseFont
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.baseFont
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themecontrolBackground_statusbarIdle
+ hover: Values.themecontrolBackground_statusbarHover
+ globalHover: Values.themecontrolBackground_statusbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themecontrolBackground_statusbarIdle
+ }
+ icon: ControlStyle.IconColors {
+ idle: Values.themeTextColor
+ hover: Values.themeTextColor
+ interaction: Values.themeTextSelectedTextColor
+ disabled: Values.themeTextColorDisabled
+ }
+
+ border: ControlStyle.BorderColors {
+ hover: Values.themeControlBackground_toolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themecontrolBackground_statusbarIdle
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml
new file mode 100644
index 0000000000..af7b641cfe
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+ controlSize: Qt.size(Values.topLevelComboWidth, Values.topLevelComboHeight)
+ baseIconFontSize: Values.topLevelComboIcon
+ smallIconFontSize: Values.baseFont
+ background.idle: Values.themeControlBackground_toolbarIdle
+ background.hover: Values.themeControlBackground_topToolbarHover
+ background.globalHover: Values.themeControlBackground_topToolbarHover
+ border.idle: Values.controlOutline_toolbarIdle
+ border.hover: Values.themeControlBackground_topToolbarHover
+ text.hover: Values.themeTextColor
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/TopToolbarButtonStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/TopToolbarButtonStyle.qml
new file mode 100644
index 0000000000..594dc03336
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/TopToolbarButtonStyle.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+
+ controlSize: Qt.size(Values.topLevelComboWidth, Values.topLevelComboHeight)
+ borderWidth: Values.border
+ baseIconFontSize: Values.topLevelComboIcon
+ radius: Values.smallRadius
+
+ icon: ControlStyle.IconColors {
+ idle: Values.themeTextColor
+ hover: Values.themeTextColor
+ interaction: Values.themeIconColor
+ disabled: Values.themeToolbarIcon_blocked
+ }
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themeControlBackground_toolbarIdle
+ hover: Values.themeControlBackground_topToolbarHover
+ globalHover: Values.themeControlBackground_topToolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themeControlBackground_toolbarIdle
+ }
+
+ border: ControlStyle.BorderColors {
+ idle: Values.themeControlBackground_toolbarIdle
+ hover: Values.themeControlBackground_topToolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themeControlBackground_toolbarIdle
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
index ae1bd543c5..ed47402de7 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
@@ -1,17 +1,30 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
pragma Singleton
-import QtQuick 2.15
+import QtQuick
import QtQuickDesignerTheme 1.0
QtObject {
id: values
property real baseHeight: 29
+
+ property real topLevelComboWidth: 210
+ property real topLevelComboHeight: 36
+ property real topLevelComboIcon: 20
+
+ property real viewBarComboWidth: 210
+ property real viewBarComboHeight: 29
+ property real viewBarComboIcon: 16
+
+ property real smallFont: 8
+ property real miniIcon: 10
property real baseFont: 12
property real mediumFont: 14
property real bigFont: 16
+
+ property real smallIconFont: 8
property real baseIconFont: 12
property real mediumIconFont: 18
property real bigIconFont: 26
@@ -19,21 +32,27 @@ QtObject {
property real scaleFactor: 1.0
property real height: Math.round(values.baseHeight * values.scaleFactor)
- property real baseFontSize: Math.round(values.baseFont * values.scaleFactor)
+
property real myFontSize: values.baseFontSize // TODO: rename all refs to myFontSize -> baseFontSize then remove myFontSize
+
+ property real smallFontSize: Math.round(values.smallFont * values.scaleFactor)
+ property real baseFontSize: Math.round(values.baseFont * values.scaleFactor)
property real mediumFontSize: Math.round(values.mediumFont * values.scaleFactor)
property real bigFontSize: Math.round(values.bigFont * values.scaleFactor)
+
+ property real myIconFontSize: values.baseIconFontSize // TODO: rename all refs to myIconFontSize -> baseIconFontSize then remove myIconFontSize
+
+ property real smallIconFontSize: Math.round(values.smallIconFont * values.scaleFactor)
property real baseIconFontSize: Math.round(values.baseIconFont * values.scaleFactor)
- property real myIconFontSize: values.baseIconFontSize; // TODO: rename all refs to myIconFontSize -> baseIconFontSize then remove myIconFontSize
property real mediumIconFontSize: Math.round(values.mediumIconFont * values.scaleFactor)
property real bigIconFontSize: Math.round(values.bigIconFont * values.scaleFactor)
property real squareComponentWidth: values.height
- property real smallRectWidth: values.height / 2 * 1.5
+ property real smallRectWidth: values.height * 0.75// / 2 * 1.5
property real inputWidth: values.height * 4
- property real sliderHeight: values.height / 2 * 1.5 // TODO:Have a look at -> sliderAreaHeight: Data.Values.height/2*1.5
+ property real sliderHeight: values.height * 0.75// / 2 * 1.5 // TODO:Have a look at -> sliderAreaHeight: Data.Values.height/2*1.5
property real sliderControlSize: 12
property real sliderControlSizeMulti: values.sliderControlSize * values.scaleFactor
@@ -43,8 +62,8 @@ QtObject {
property real spinControlIconSizeMulti: values.spinControlIconSize * values.scaleFactor
property real sliderTrackHeight: values.height / 3
- property real sliderHandleHeight: values.sliderTrackHeight * 1.8
property real sliderHandleWidth: values.sliderTrackHeight * 0.5
+ property real sliderHandleHeight: values.sliderTrackHeight * 1.8
property real sliderFontSize: Math.round(8 * values.scaleFactor)
property real sliderPadding: Math.round(6 * values.scaleFactor)
property real sliderMargin: Math.round(3 * values.scaleFactor)
@@ -55,10 +74,10 @@ QtObject {
property real checkBoxSpacing: Math.round(6 * values.scaleFactor)
property real radioButtonSpacing: values.checkBoxSpacing
- property real radioButtonWidth: values.height
- property real radioButtonHeight: values.height
- property real radioButtonIndicatorWidth: 14
- property real radioButtonIndicatorHeight: 14
+ //property real radioButtonWidth: values.height
+ //property real radioButtonHeight: values.height
+ property real radioButtonIndicatorWidth: Math.round(14 * values.scaleFactor)
+ property real radioButtonIndicatorHeight: Math.round(14 * values.scaleFactor)
property real switchSpacing: values.checkBoxSpacing
@@ -67,6 +86,9 @@ QtObject {
property real marginTopBottom: 4
property real border: 1
property real borderHover: 3
+ property real radius: 0 //adding specific radiuses
+
+ property real smallRadius: 4
property real maxComboBoxPopupHeight: Math.round(300 * values.scaleFactor)
property real maxTextAreaPopupHeight: Math.round(150 * values.scaleFactor)
@@ -139,13 +161,13 @@ QtObject {
+ values.twoControlColumnGap
+ values.actionIndicatorWidth
- property real twoControlColumnWidthMin: 3 * values.height - 2 * values.border
+ property real twoControlColumnWidthMin: 3 * values.height - 2 * values.border - 10
property real twoControlColumnWidthMax: 3 * values.twoControlColumnWidthMin
property real twoControlColumnWidth: values.twoControlColumnWidthMin
property real controlColumnWithoutControlsWidth: 2 * (values.actionIndicatorWidth
+ values.twoControlColumnGap)
- + values.linkControlWidth
+ + values.linkControlWidth // there could be an issue here with the new style
property real controlColumnWidth: values.controlColumnWithoutControlsWidth
+ 2 * values.twoControlColumnWidth
@@ -197,8 +219,10 @@ QtObject {
property real colorEditorPopupSpinBoxWidth: 54
// Toolbar
- property real toolbarHeight: 35
- property real toolbarSpacing: 8
+ property real toolbarHeight: 41
+ property real doubleToolbarHeight: values.toolbarHeight * 2
+ property real toolbarSpacing: 10
+
// Dialog
property real dialogPadding: 12
@@ -207,134 +231,184 @@ QtObject {
// Theme Colors
- property bool isLightTheme: themeControlBackground.hsvValue > themeTextColor.hsvValue
+ property bool isLightTheme: values.themeControlBackground.hsvValue > values.themeTextColor.hsvValue
+
+ //NEW QtDS 4.0
- property string themePanelBackground: Theme.color(Theme.DSpanelBackground)
+ //Top & View toolbar colors
- property string themeGreenLight: Theme.color(Theme.DSgreenLight)
- property string themeAmberLight: Theme.color(Theme.DSamberLight)
- property string themeRedLight: Theme.color(Theme.DSredLight)
+ //backgrounds
+ property color themeControlBackground_toolbarIdle: Theme.color(Theme.DScontrolBackground_toolbarIdle)
+ property color themeControlBackground_toolbarHover: Theme.color(Theme.DScontrolBackground_toolbarHover)
+ property color themeControlBackground_topToolbarHover: Theme.color(Theme.DScontrolBackground_topToolbarHover)
+ property color themeToolbarBackground: Theme.color(Theme.DStoolbarBackground)
- property string themeInteraction: Theme.color(Theme.DSinteraction)
- property string themeError: Theme.color(Theme.DSerrorColor)
- property string themeWarning: Theme.color(Theme.DSwarningColor)
- property string themeDisabled: Theme.color(Theme.DSdisabledColor)
+ //outlines
+ property color controlOutline_toolbarIdle: Theme.color(Theme.DScontrolOutline_topToolbarIdle)
+ property color controlOutline_toolbarHover: Theme.color(Theme.DScontrolOutline_topToolbarHover)
- property string themeInteractionHover: Theme.color(Theme.DSinteractionHover)
+ //icons
+ property color themeToolbarIcon_blocked: Theme.color(Theme.DStoolbarIcon_blocked)
- property string themeAliasIconChecked: Theme.color(Theme.DSnavigatorAliasIconChecked)
+ //primary buttons
+ property color themePrimaryButton_hoverHighlight: Theme.color(Theme.DSprimaryButton_hoverHighlight)
+
+ //states
+ property color themeStateControlBackgroundColor_hover: Theme.color(Theme.DSstateControlBackgroundColor_hover)
+ property color themeStateBackgroundColor_hover: Theme.color(Theme.DSstateBackgroundColor_hover)
+ property color themeStateControlBackgroundColor_globalHover: Theme.color(Theme.DSstateControlBackgroundColor_globalHover)
+ property color themeThumbnailBackground_baseState: Theme.color(Theme.DSthumbnailBackground_baseState)
+
+ //task bar
+ property color themeStatusbarBackground:Theme.color(Theme.DSstatusbarBackground)
+ property color themecontrolBackground_statusbarIdle:Theme.color(Theme.DScontrolBackground_statusbarIdle)
+ property color themecontrolBackground_statusbarHover:Theme.color(Theme.DSControlBackground_statusbarHover)
+
+ //run project button
+ property color themeIdleGreen: Theme.color(Theme.DSidleGreen)
+ property color themeRunningGreen: Theme.color(Theme.DSrunningGreen)
+
+ //END NEW COLORS QtDS 4.0
+
+ property color themePanelBackground: Theme.color(Theme.DSpanelBackground)
+
+ property color themeGreenLight: Theme.color(Theme.DSgreenLight)
+ property color themeAmberLight: Theme.color(Theme.DSamberLight)
+ property color themeRedLight: Theme.color(Theme.DSredLight)
+
+ property color themeInteraction: Theme.color(Theme.DSinteraction)
+ property color themeError: Theme.color(Theme.DSerrorColor)
+ property color themeWarning: Theme.color(Theme.DSwarningColor)
+ property color themeDisabled: Theme.color(Theme.DSdisabledColor)
+
+ property color themeInteractionHover: Theme.color(Theme.DSinteractionHover)
+
+ property color themeAliasIconChecked: Theme.color(Theme.DSnavigatorAliasIconChecked)
// Control colors
property color themeControlBackground: Theme.color(Theme.DScontrolBackground)
- property string themeControlBackgroundInteraction: Theme.color(Theme.DScontrolBackgroundInteraction)
- property string themeControlBackgroundDisabled: Theme.color(Theme.DScontrolBackgroundDisabled)
- property string themeControlBackgroundGlobalHover: Theme.color(Theme.DScontrolBackgroundGlobalHover)
- property string themeControlBackgroundHover: Theme.color(Theme.DScontrolBackgroundHover)
+ property color themeControlBackgroundInteraction: Theme.color(Theme.DScontrolBackgroundInteraction)
+ property color themeControlBackgroundDisabled: Theme.color(Theme.DScontrolBackgroundDisabled)
+ property color themeControlBackgroundGlobalHover: Theme.color(Theme.DScontrolBackgroundGlobalHover)
+ property color themeControlBackgroundHover: Theme.color(Theme.DScontrolBackgroundHover)
- property string themeControlOutline: Theme.color(Theme.DScontrolOutline)
- property string themeControlOutlineInteraction: Theme.color(Theme.DScontrolOutlineInteraction)
- property string themeControlOutlineDisabled: Theme.color(Theme.DScontrolOutlineDisabled)
+ property color themeControlOutline: Theme.color(Theme.DScontrolOutline)
+ property color themeControlOutlineInteraction: Theme.color(Theme.DScontrolOutlineInteraction)
+ property color themeControlOutlineDisabled: Theme.color(Theme.DScontrolOutlineDisabled)
// Panels & Panes
- property string themeBackgroundColorNormal: Theme.color(Theme.DSBackgroundColorNormal)
- property string themeBackgroundColorAlternate: Theme.color(Theme.DSBackgroundColorAlternate)
+ property color themeBackgroundColorNormal: Theme.color(Theme.DSBackgroundColorNormal)
+ property color themeBackgroundColorAlternate: Theme.color(Theme.DSBackgroundColorAlternate)
// Text colors
property color themeTextColor: Theme.color(Theme.DStextColor)
- property string themeTextColorDisabled: Theme.color(Theme.DStextColorDisabled)
- property string themeTextSelectionColor: Theme.color(Theme.DStextSelectionColor)
- property string themeTextSelectedTextColor: Theme.color(Theme.DStextSelectedTextColor)
- property string themeTextColorDisabledMCU: Theme.color(Theme.DStextColorDisabled)
+ property color themeTextColorDisabled: Theme.color(Theme.DStextColorDisabled)
+ property color themeTextSelectionColor: Theme.color(Theme.DStextSelectionColor)
+ property color themeTextSelectedTextColor: Theme.color(Theme.DStextSelectedTextColor)
+ property color themeTextColorDisabledMCU: Theme.color(Theme.DStextColorDisabled)
- property string themePlaceholderTextColor: Theme.color(Theme.DSplaceholderTextColor)
- property string themePlaceholderTextColorInteraction: Theme.color(Theme.DSplaceholderTextColorInteraction)
+ property color themePlaceholderTextColor: Theme.color(Theme.DSplaceholderTextColor)
+ property color themePlaceholderTextColorInteraction: Theme.color(Theme.DSplaceholderTextColorInteraction)
// Icon colors
- property string themeIconColor: Theme.color(Theme.DSiconColor)
- property string themeIconColorHover: Theme.color(Theme.DSiconColorHover)
- property string themeIconColorInteraction: Theme.color(Theme.DSiconColorInteraction)
- property string themeIconColorDisabled: Theme.color(Theme.DSiconColorDisabled)
- property string themeIconColorSelected: Theme.color(Theme.DSiconColorSelected)
+ property color themeIconColor: Theme.color(Theme.DSiconColor)
+ property color themeIconColorHover: Theme.color(Theme.DSiconColorHover)
+ property color themeIconColorInteraction: Theme.color(Theme.DSiconColorInteraction)
+ property color themeIconColorDisabled: Theme.color(Theme.DSiconColorDisabled)
+ property color themeIconColorSelected: Theme.color(Theme.DSiconColorSelected)
- property string themeLinkIndicatorColor: Theme.color(Theme.DSlinkIndicatorColor)
- property string themeLinkIndicatorColorHover: Theme.color(Theme.DSlinkIndicatorColorHover)
- property string themeLinkIndicatorColorInteraction: Theme.color(Theme.DSlinkIndicatorColorInteraction)
- property string themeLinkIndicatorColorDisabled: Theme.color(Theme.DSlinkIndicatorColorDisabled)
+ property color themeLinkIndicatorColor: Theme.color(Theme.DSlinkIndicatorColor)
+ property color themeLinkIndicatorColorHover: Theme.color(Theme.DSlinkIndicatorColorHover)
+ property color themeLinkIndicatorColorInteraction: Theme.color(Theme.DSlinkIndicatorColorInteraction)
+ property color themeLinkIndicatorColorDisabled: Theme.color(Theme.DSlinkIndicatorColorDisabled)
- property string themeInfiniteLoopIndicatorColor: Theme.color(Theme.DSlinkIndicatorColor)
- property string themeInfiniteLoopIndicatorColorHover: Theme.color(Theme.DSlinkIndicatorColorHover)
- property string themeInfiniteLoopIndicatorColorInteraction: Theme.color(Theme.DSlinkIndicatorColorInteraction)
+ property color themeInfiniteLoopIndicatorColor: Theme.color(Theme.DSlinkIndicatorColor)
+ property color themeInfiniteLoopIndicatorColorHover: Theme.color(Theme.DSlinkIndicatorColorHover)
+ property color themeInfiniteLoopIndicatorColorInteraction: Theme.color(Theme.DSlinkIndicatorColorInteraction)
// Popup background color (ComboBox, SpinBox, TextArea)
- property string themePopupBackground: Theme.color(Theme.DSpopupBackground)
- // GradientPopupDialog modal overly color
- property string themePopupOverlayColor: Theme.color(Theme.DSpopupOverlayColor)
+ property color themePopupBackground: Theme.color(Theme.DSpopupBackground)
+ // GradientPopupDialog modal overlay color
+ property color themePopupOverlayColor: Theme.color(Theme.DSpopupOverlayColor)
// ToolTip (UrlChooser)
- property string themeToolTipBackground: Theme.color(Theme.DStoolTipBackground)
- property string themeToolTipOutline: Theme.color(Theme.DStoolTipOutline)
- property string themeToolTipText: Theme.color(Theme.DStoolTipText)
+ property color themeToolTipBackground: Theme.color(Theme.DStoolTipBackground)
+ property color themeToolTipOutline: Theme.color(Theme.DStoolTipOutline)
+ property color themeToolTipText: Theme.color(Theme.DStoolTipText)
// Slider colors
- property string themeSliderActiveTrack: Theme.color(Theme.DSsliderActiveTrack)
- property string themeSliderActiveTrackHover: Theme.color(Theme.DSsliderActiveTrackHover)
- property string themeSliderActiveTrackFocus: Theme.color(Theme.DSsliderActiveTrackFocus)
- property string themeSliderInactiveTrack: Theme.color(Theme.DSsliderInactiveTrack)
- property string themeSliderInactiveTrackHover: Theme.color(Theme.DSsliderInactiveTrackHover)
- property string themeSliderInactiveTrackFocus: Theme.color(Theme.DSsliderInactiveTrackFocus)
- property string themeSliderHandle: Theme.color(Theme.DSsliderHandle)
- property string themeSliderHandleHover: Theme.color(Theme.DSsliderHandleHover)
- property string themeSliderHandleFocus: Theme.color(Theme.DSsliderHandleFocus)
- property string themeSliderHandleInteraction: Theme.color(Theme.DSsliderHandleInteraction)
-
- property string themeScrollBarTrack: Theme.color(Theme.DSscrollBarTrack)
- property string themeScrollBarHandle: Theme.color(Theme.DSscrollBarHandle)
-
- property string themeSectionHeadBackground: Theme.color(Theme.DSsectionHeadBackground)
-
- property string themeTabActiveBackground: Theme.color(Theme.DStabActiveBackground)
- property string themeTabActiveText: Theme.color(Theme.DStabActiveText)
- property string themeTabInactiveBackground: Theme.color(Theme.DStabInactiveBackground)
- property string themeTabInactiveText: Theme.color(Theme.DStabInactiveText)
+ property color themeSliderActiveTrack: Theme.color(Theme.DSsliderActiveTrack)
+ property color themeSliderActiveTrackHover: Theme.color(Theme.DSsliderActiveTrackHover)
+ property color themeSliderActiveTrackFocus: Theme.color(Theme.DSsliderActiveTrackFocus)
+ property color themeSliderInactiveTrack: Theme.color(Theme.DSsliderInactiveTrack)
+ property color themeSliderInactiveTrackHover: Theme.color(Theme.DSsliderInactiveTrackHover)
+ property color themeSliderInactiveTrackFocus: Theme.color(Theme.DSsliderInactiveTrackFocus)
+ property color themeSliderHandle: Theme.color(Theme.DSsliderHandle)
+ property color themeSliderHandleHover: Theme.color(Theme.DSsliderHandleHover)
+ property color themeSliderHandleFocus: Theme.color(Theme.DSsliderHandleFocus)
+ property color themeSliderHandleInteraction: Theme.color(Theme.DSsliderHandleInteraction)
+
+ property color themeScrollBarTrack: Theme.color(Theme.DSscrollBarTrack)
+ property color themeScrollBarHandle: Theme.color(Theme.DSscrollBarHandle)
+
+ property color themeSectionHeadBackground: Theme.color(Theme.DSsectionHeadBackground)
+
+ property color themeTabActiveBackground: Theme.color(Theme.DStabActiveBackground)
+ property color themeTabActiveText: Theme.color(Theme.DStabActiveText)
+ property color themeTabInactiveBackground: Theme.color(Theme.DStabInactiveBackground)
+ property color themeTabInactiveText: Theme.color(Theme.DStabInactiveText)
+
// State Editor
- property string themeStateSeparator: Theme.color(Theme.DSstateSeparatorColor)
- property string themeStateBackground: Theme.color(Theme.DSstateBackgroundColor)
- property string themeStatePreviewOutline: Theme.color(Theme.DSstatePreviewOutline)
+ property color themeStateSeparator: Theme.color(Theme.DSstateSeparatorColor)
+ property color themeStateBackground: Theme.color(Theme.DSstateBackgroundColor)
+ property color themeStatePreviewOutline: Theme.color(Theme.DSstatePreviewOutline)
// State Editor *new*
property color themeStatePanelBackground: Theme.color(Theme.DSstatePanelBackground)
property color themeStateHighlight: Theme.color(Theme.DSstateHighlight)
- property string themeUnimportedModuleColor: Theme.color(Theme.DSUnimportedModuleColor)
+ property color themeUnimportedModuleColor: Theme.color(Theme.DSUnimportedModuleColor)
// Taken out of Constants.js
- property string themeChangedStateText: Theme.color(Theme.DSchangedStateText)
+ property color themeChangedStateText: Theme.color(Theme.DSchangedStateText)
// 3D
- property string theme3DAxisXColor: Theme.color(Theme.DS3DAxisXColor)
- property string theme3DAxisYColor: Theme.color(Theme.DS3DAxisYColor)
- property string theme3DAxisZColor: Theme.color(Theme.DS3DAxisZColor)
-
- property string themeActionBinding: Theme.color(Theme.DSactionBinding)
- property string themeActionAlias: Theme.color(Theme.DSactionAlias)
- property string themeActionKeyframe: Theme.color(Theme.DSactionKeyframe)
- property string themeActionJIT: Theme.color(Theme.DSactionJIT)
-
- property string themeListItemBackground: Theme.color(Theme.DSnavigatorItemBackground)
- property string themeListItemBackgroundHover: Theme.color(Theme.DSnavigatorItemBackgroundHover)
- property string themeListItemBackgroundPress: Theme.color(Theme.DSnavigatorItemBackgroundSelected)
- property string themeListItemText: Theme.color(Theme.DSnavigatorText)
- property string themeListItemTextHover: Theme.color(Theme.DSnavigatorTextHover)
- property string themeListItemTextPress: Theme.color(Theme.DSnavigatorTextSelected)
+ property color theme3DAxisXColor: Theme.color(Theme.DS3DAxisXColor)
+ property color theme3DAxisYColor: Theme.color(Theme.DS3DAxisYColor)
+ property color theme3DAxisZColor: Theme.color(Theme.DS3DAxisZColor)
+
+ property color themeActionBinding: Theme.color(Theme.DSactionBinding)
+ property color themeActionAlias: Theme.color(Theme.DSactionAlias)
+ property color themeActionKeyframe: Theme.color(Theme.DSactionKeyframe)
+ property color themeActionJIT: Theme.color(Theme.DSactionJIT)
+
+ property color themeListItemBackground: Theme.color(Theme.DSnavigatorItemBackground)
+ property color themeListItemBackgroundHover: Theme.color(Theme.DSnavigatorItemBackgroundHover)
+ property color themeListItemBackgroundPress: Theme.color(Theme.DSnavigatorItemBackgroundSelected)
+ property color themeListItemText: Theme.color(Theme.DSnavigatorText)
+ property color themeListItemTextHover: Theme.color(Theme.DSnavigatorTextHover)
+ property color themeListItemTextPress: Theme.color(Theme.DSnavigatorTextSelected)
// Welcome Page
- property string welcomeScreenBackground: Theme.color(Theme.DSwelcomeScreenBackground)
- property string themeSubPanelBackground: Theme.color(Theme.DSsubPanelBackground)
- property string themeThumbnailBackground: Theme.color(Theme.DSthumbnailBackground)
- property string themeThumbnailLabelBackground: Theme.color(Theme.DSthumbnailLabelBackground)
+ property color welcomeScreenBackground: Theme.color(Theme.DSwelcomeScreenBackground)
+ property color themeSubPanelBackground: Theme.color(Theme.DSsubPanelBackground)
+ property color themeThumbnailBackground: Theme.color(Theme.DSthumbnailBackground)
+ property color themeThumbnailLabelBackground: Theme.color(Theme.DSthumbnailLabelBackground)
// Dialog
property color themeDialogBackground: values.themeThumbnailBackground
property color themeDialogOutline: values.themeInteraction
+
+ // Control Style Mapping
+ property ControlStyle controlStyle: DefaultStyle {}
+ property ControlStyle toolbarStyle: ToolbarStyle {}
+ property ControlStyle primaryToolbarStyle: PrimaryButtonStyle {}
+ property ControlStyle toolbarButtonStyle: TopToolbarButtonStyle {}
+ property ControlStyle viewBarButtonStyle: ViewBarButtonStyle {}
+ property ControlStyle viewBarControlStyle: ViewBarControlStyle {}
+ property ControlStyle statusbarButtonStyle: StatusBarButtonStyle {}
+ property ControlStyle statusbarControlStyle: StatusBarControlStyle {}
+ property ControlStyle statesControlStyle: StatesControlStyle {}
+ property ControlStyle searchControlStyle: SearchControlStyle {}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarButtonStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarButtonStyle.qml
new file mode 100644
index 0000000000..a4de68a3fd
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarButtonStyle.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+
+ baseIconFontSize: Values.bigFont
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.viewBarComboIcon
+ borderWidth: Values.border
+
+ radius: Values.smallRadius
+
+ icon: ControlStyle.IconColors {
+ idle: Values.themeTextColor
+ hover: Values.themeTextColor
+ interaction: Values.themeIconColor
+ disabled: Values.themeToolbarIcon_blocked
+ }
+
+ background: ControlStyle.BackgroundColors {
+ idle: Values.themeControlBackground_toolbarIdle
+ hover: Values.themeControlBackground_topToolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themeControlBackground_toolbarIdle
+ }
+
+ border: ControlStyle.BorderColors {
+ idle: Values.themeControlBackground_toolbarIdle
+ hover: Values.themeControlBackground_topToolbarHover
+ interaction: Values.themeInteraction
+ disabled: Values.themeControlBackground_toolbarIdle
+ }
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarControlStyle.qml
new file mode 100644
index 0000000000..cc634b04a1
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ViewBarControlStyle.qml
@@ -0,0 +1,15 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+
+ControlStyle {
+ baseIconFontSize: Values.baseFont
+ controlSize: Qt.size(Values.viewBarComboWidth, Values.viewBarComboHeight)
+ smallIconFontSize: Values.baseFont
+ background.idle: Values.themeControlBackground_toolbarIdle
+ background.hover: Values.themeControlBackground_topToolbarHover
+ background.globalHover: Values.themeControlBackground_topToolbarHover
+ border.idle: Values.controlOutline_toolbarIdle
+ text.hover: Values.themeTextColor
+}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index cacd0c3cb9..1b1821ae99 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
Binary files differ
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
index 4f689f9f63..2814e7809b 100755
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/qmldir
@@ -1,4 +1,14 @@
singleton Values 1.0 Values.qml
singleton Constants 1.0 Constants.qml
+ControlStyle 1.0 ControlStyle.qml
+DefaultStyle 1.0 DefaultStyle.qml
InternalConstants 1.0 InternalConstants.qml
-
+ToolbarStyle 1.0 ToolbarStyle.qml
+PrimaryButtonStyle 1.0 PrimaryButtonStyle.qml
+StatesControlStyle 1.0 StatesControlStyle.qml
+SearchControlStyle 1.0 SearchControlStyle.qml
+StatusBarButtonStyle 1.0 StatusBarButtonStyle.qml
+StatusBarControlStyle 1.0 StatusBarControlStyle.qml
+TopToolbarButtonStyle 1.0 TopToolbarButtonStyle.qml
+ViewBarButtonStyle 1.0 ViewBarButtonStyle.qml
+ViewBarControlStyle 1.0 ViewBarControlStyle.qml
diff --git a/share/qtcreator/qmldesigner/statusbar/Main.qml b/share/qtcreator/qmldesigner/statusbar/Main.qml
new file mode 100644
index 0000000000..db1a125e10
--- /dev/null
+++ b/share/qtcreator/qmldesigner/statusbar/Main.qml
@@ -0,0 +1,85 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
+import "../toolbar"
+
+import ToolBar 1.0
+
+Item {
+ id: toolbarContainer
+
+ height: 41
+ width: 4048
+
+ ToolBarBackend {
+ id: backend
+ }
+
+ Rectangle {
+ color: StudioTheme.Values.themeStatusbarBackground
+ anchors.fill: parent
+
+ Row {
+ anchors.fill: parent
+ anchors.topMargin: 3
+ anchors.leftMargin: 4
+ spacing: 29
+
+ ToolbarButton {
+ id: settingButton
+ style: StudioTheme.Values.statusbarButtonStyle
+ buttonIcon: StudioTheme.Constants.settings_medium
+ onClicked: backend.triggerProjectSettings()
+ enabled: backend.isInDesignMode || (backend.isInEditMode && backend.projectOpened)
+ }
+
+ Text {
+ height: StudioTheme.Values.statusbarButtonStyle.controlSize.height
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("Kit")
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ StudioControls.TopLevelComboBox {
+ id: kits
+ style: StudioTheme.Values.statusbarControlStyle
+ width: 160
+ model: backend.kits
+ onActivated: backend.setCurrentKit(kits.currentIndex)
+ openUpwards: true
+ enabled: (backend.isInDesignMode || (backend.isInEditMode && backend.projectOpened)) && backend.isQt6
+ property int kitIndex: backend.currentKit
+ onKitIndexChanged: kits.currentIndex = backend.currentKit
+ }
+
+ Text {
+ height: StudioTheme.Values.statusbarButtonStyle.controlSize.height
+ color: StudioTheme.Values.themeTextColor
+ text: qsTr("Style")
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ StudioControls.TopLevelComboBox {
+ id: styles
+ style: StudioTheme.Values.statusbarControlStyle
+ width: 160
+ model: backend.styles
+ onActivated: backend.setCurrentStyle(styles.currentIndex)
+ openUpwards: true
+ enabled: backend.isInDesignMode
+ property int currentStyleIndex: backend.currentStyle
+ onCurrentStyleIndexChanged: currentIndex = backend.currentStyle
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject b/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
index d339fcffb5..bbf848151f 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
@@ -1,6 +1,6 @@
-/* File generated by Qt Creator */
+/* File generated by Qt Design Studio */
-import QmlProject 1.1
+import QmlProject 1.3
Project {
mainFile: "%{MainQmlFileName}"
@@ -32,6 +32,21 @@ Project {
filter: "*.ttf;*.otf"
}
+ ModuleFiles {
+ files: [
+ "imports/Constants/constants_module.qmlproject"
+ ]
+
+ MCU.qulModules: [
+ "Controls",
+ "ControlsTemplates",
+ "Timeline",
+ "Shapes"
+ ]
+ }
+
+
+ /* Following entries are for Qt Design Studio compatibility: */
Environment {
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
}
@@ -39,8 +54,7 @@ Project {
qtForMCUs: true
/* List of plugin directories passed to QML runtime */
- importPaths: [ "imports", "asset_imports" ]
+ importPaths: [ "imports" ]
- /* Required for deployment */
targetDirectory: "/opt/%{ProjectName}"
}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/CMakeLists.txt b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/CMakeLists.txt
index b979c45227..42693c255d 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/CMakeLists.txt
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 3.15)
+cmake_minimum_required (VERSION 3.21.1)
project(%{ProjectName} VERSION 0.0.1 LANGUAGES C CXX ASM)
@@ -6,72 +6,77 @@ if (NOT TARGET Qul::Core)
find_package(Qul)
endif()
-if (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
- qul_add_target(%{ProjectName})
+if (Qul_VERSION VERSION_GREATER_EQUAL "2.4")
+ qul_add_target(%{ProjectName} QML_PROJECT %{ProjectName}.qmlproject GENERATE_ENTRYPOINT)
+ app_target_setup_os(%{ProjectName})
else()
- add_executable(%{ProjectName})
- target_link_libraries(%{ProjectName}
- Qul::QuickUltralite
- Qul::QuickUltralitePlatform)
-endif()
-
-if (Qul_VERSION VERSION_GREATER_EQUAL "2.0")
- file(GLOB_RECURSE fontSources "${CMAKE_CURRENT_SOURCE_DIR}/fonts/*.ttf")
- set_property(TARGET %{ProjectName} APPEND PROPERTY QUL_FONT_FILES ${fontSources})
-elseif (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
- set_property(TARGET %{ProjectName} APPEND PROPERTY QUL_FONTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fonts")
-else()
- set(QUL_FONTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fonts,${QUL_FONTS_DIR}")
-endif()
+ if (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
+ qul_add_target(%{ProjectName})
+ else()
+ add_executable(%{ProjectName})
+ target_link_libraries(%{ProjectName}
+ Qul::QuickUltralite
+ Qul::QuickUltralitePlatform)
+ endif()
-# Using recurse search to find image files in project directory
-# Excluding MCUDefaultStyle because it exists for compatibility purposes with QDS
-file(GLOB_RECURSE imgSources "*.png" "*.svg" "*.jpg" "*.jpeg")
-list(FILTER imgSources EXCLUDE REGEX ".*/MCUDefaultStyle/.*")
+ if (Qul_VERSION VERSION_GREATER_EQUAL "2.0")
+ file(GLOB_RECURSE fontSources "${CMAKE_CURRENT_SOURCE_DIR}/fonts/*.ttf")
+ set_property(TARGET %{ProjectName} APPEND PROPERTY QUL_FONT_FILES ${fontSources})
+ elseif (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
+ set_property(TARGET %{ProjectName} APPEND PROPERTY QUL_FONTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fonts")
+ else()
+ set(QUL_FONTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fonts,${QUL_FONTS_DIR}")
+ endif()
-if(imgSources)
- qul_add_resource(%{ProjectName} FILES ${imgSources})
-endif()
+ # Using recurse search to find image files in project directory
+ # Excluding MCUDefaultStyle because it exists for compatibility purposes with QDS
+ file(GLOB_RECURSE imgSources "*.png" "*.svg" "*.jpg" "*.jpeg")
+ list(FILTER imgSources EXCLUDE REGEX ".*/MCUDefaultStyle/.*")
-# Registering singletons as qml module
-qul_add_qml_module(ConstantsModule
- URI Constants
- QML_FILES
- imports/Constants/Constants.qml
-)
+ if(imgSources)
+ qul_add_resource(%{ProjectName} FILES ${imgSources})
+ endif()
-message(WARNING "It is recommended to replace the recursive search with the actual list of .qml files in your project.")
-file(GLOB_RECURSE qmlSources "*.qml")
-# Excluding Constants folder because it is part of another qml module
-list(FILTER qmlSources EXCLUDE REGEX ".*/imports/Constants/.*")
-# Excluding MCUDefaultStyle because it exists for compatibility purposes with QDS
-list(FILTER qmlSources EXCLUDE REGEX ".*/MCUDefaultStyle/.*")
-# Excluding binary directory because it can break builds in source dir
-list(FILTER qmlSources EXCLUDE REGEX "${CMAKE_CURRENT_BINARY_DIR}/.*")
-qul_target_qml_sources(%{ProjectName} ${qmlSources})
+ # Registering singletons as qml module
+ qul_add_qml_module(ConstantsModule
+ URI Constants
+ QML_FILES
+ imports/Constants/Constants.qml
+ )
-if (Qul_VERSION VERSION_GREATER_EQUAL "2.0")
- target_link_libraries(%{ProjectName} PRIVATE
- Qul::Timeline
- Qul::Controls
- Qul::Shapes
- ConstantsModule)
-else()
- target_link_libraries(%{ProjectName}
- Qul::QuickUltraliteTimeline
- Qul::QuickUltraliteControlsStyleDefault
- ConstantsModule)
+ message(WARNING "It is recommended to replace the recursive search with the actual list of .qml files in your project.")
+ file(GLOB_RECURSE qmlSources "*.qml")
+ # Excluding Constants folder because it is part of another qml module
+ list(FILTER qmlSources EXCLUDE REGEX ".*/imports/Constants/.*")
+ # Excluding MCUDefaultStyle because it exists for compatibility purposes with QDS
+ list(FILTER qmlSources EXCLUDE REGEX ".*/MCUDefaultStyle/.*")
+ # Excluding binary directory because it can break builds in source dir
+ list(FILTER qmlSources EXCLUDE REGEX "${CMAKE_CURRENT_BINARY_DIR}/.*")
+ qul_target_qml_sources(%{ProjectName} ${qmlSources})
- if (Qul_VERSION VERSION_GREATER_EQUAL "1.8")
+ if (Qul_VERSION VERSION_GREATER_EQUAL "2.0")
+ target_link_libraries(%{ProjectName} PRIVATE
+ Qul::Timeline
+ Qul::Controls
+ Qul::Shapes
+ ConstantsModule)
+ else()
target_link_libraries(%{ProjectName}
- Qul::QuickUltraliteShapes)
+ Qul::QuickUltraliteTimeline
+ Qul::QuickUltraliteControlsStyleDefault
+ ConstantsModule)
+
+ if (Qul_VERSION VERSION_GREATER_EQUAL "1.8")
+ target_link_libraries(%{ProjectName}
+ Qul::QuickUltraliteShapes)
+ endif()
endif()
-endif()
-app_target_setup_os(%{ProjectName})
+ app_target_setup_os(%{ProjectName})
-if (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
- app_target_default_entrypoint(%{ProjectName} %{RootItemName})
-else()
- app_target_default_main(%{ProjectName} %{RootItemName})
+ if (Qul_VERSION VERSION_GREATER_EQUAL "1.7")
+ app_target_default_entrypoint(%{ProjectName} %{RootItemName})
+ else()
+ app_target_default_main(%{ProjectName} %{RootItemName})
+ endif()
endif()
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
index ef8bfddcef..524cbd0905 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
@@ -7,26 +7,4 @@ QtObject {
readonly property color backgroundColor: "#e8e8e8"
-
- /* DirectoryFontLoader doesn't work with Qt Ultralite.
- However you may want to uncomment this block to load fonts in real qml environment */
- /*
- property alias fontDirectory: directoryFontLoader.fontDirectory
- property alias relativeFontDirectory: directoryFontLoader.relativeFontDirectory
-
- readonly property font font: Qt.font({
- family: Qt.application.font.family,
- pixelSize: Qt.application.font.pixelSize
- })
- readonly property font largeFont: Qt.font({
- family: Qt.application.font.family,
- pixelSize: Qt.application.font.pixelSize * 1.6
- })
-
-
-
- property DirectoryFontLoader directoryFontLoader: DirectoryFontLoader {
- id: directoryFontLoader
- }
- */
}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/DirectoryFontLoader.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/DirectoryFontLoader.qml.tpl
deleted file mode 100644
index 59a6365df4..0000000000
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/DirectoryFontLoader.qml.tpl
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-
-import QtQuick 2.15
-import Qt.labs.folderlistmodel 2.15
-
-QtObject {
- id: loader
-
- property url fontDirectory: Qt.resolvedUrl("../../" + relativeFontDirectory)
- property string relativeFontDirectory: "fonts"
-
- function loadFont(url) {
- var fontLoader = Qt.createQmlObject('import QtQuick 2.15; FontLoader { source: "' + url + '"; }',
- loader,
- "dynamicFontLoader");
- }
-
- property FolderListModel folderModel: FolderListModel {
- id: folderModel
- folder: loader.fontDirectory
- nameFilters: [ "*.ttf", "*.otf" ]
- showDirs: false
-
- onStatusChanged: {
- if (folderModel.status == FolderListModel.Ready) {
- var i
- for (i = 0; i < count; i++) {
- loadFont(folderModel.get(i, "fileURL"))
- }
- }
- }
- }
-}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/constants_module.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/constants_module.qmlproject.tpl
new file mode 100644
index 0000000000..01711f43ef
--- /dev/null
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/constants_module.qmlproject.tpl
@@ -0,0 +1,13 @@
+import QmlProject 1.3
+
+Project {
+ MCU.Module {
+ uri: "Constants"
+ }
+
+ QmlFiles {
+ files: [
+ "Constants.qml"
+ ]
+ }
+}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/wizard.json
index 45965fad3d..8b54e315b2 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/wizard.json
@@ -161,8 +161,8 @@
"target": "%{ProjectDirectory}/imports/Constants/Constants.qml"
},
{
- "source": "DirectoryFontLoader.qml.tpl",
- "target": "%{ProjectDirectory}/imports/Constants/DirectoryFontLoader.qml"
+ "source": "constants_module.qmlproject.tpl",
+ "target": "%{ProjectDirectory}/imports/Constants/constants_module.qmlproject"
},
{
"source": "Screen01.ui.qml.tpl",
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
index 9daf9759b1..a76765daee 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
@@ -40,3 +40,7 @@ if (${BUILD_QDS_COMPONENTS})
endif ()
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
+
+install(TARGETS ${CMAKE_PROJECT_NAME}
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
index 722b0d72ee..d598f361c1 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
@@ -6,6 +6,7 @@ import QmlProject 1.1
Project {
mainFile: "content/App.qml"
+ mainUiFile: "content/Screen01.ui.qml"
/* Include .qml, .js, and image files from current directory and subdirectories */
QmlFiles {
@@ -100,7 +101,7 @@ Project {
/* Required for deployment */
targetDirectory: "/opt/%{ProjectName}"
- qdsVersion: "3.9"
+ qdsVersion: "4.0"
quickVersion: "%{QtQuickVersion}"
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
index 3619df33d3..50f3db973c 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
@@ -8,7 +8,7 @@ set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
include(FetchContent)
FetchContent_Declare(
ds
- GIT_TAG qds-3.9
+ GIT_TAG qds-4.0
GIT_REPOSITORY https://code.qt.io/qt-labs/qtquickdesigner-components.git
)
diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml
index 14bd44571d..0aa6bd4e09 100644
--- a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml
+++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorPane.qml
@@ -16,10 +16,10 @@ PropertyEditorPane {
topSection.refreshPreview()
}
- // Called also from C++ to close context menu on focus out
+ // Called from C++ to close context menu on focus out
function closeContextMenu()
{
- // Nothing
+ Controller.closeContextMenu()
}
TextureEditorTopSection {
diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml
index 710c6356c8..6a61a76ef6 100644
--- a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml
+++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorToolBar.qml
@@ -1,69 +1,57 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
import QtQuickDesignerTheme 1.0
-import HelperWidgets 2.0
+import HelperWidgets 2.0 as HelperWidgets
import StudioTheme 1.0 as StudioTheme
import TextureToolBarAction 1.0
Rectangle {
id: root
- color: StudioTheme.Values.themeSectionHeadBackground
+ color: StudioTheme.Values.themeToolbarBackground
+ height: StudioTheme.Values.toolbarHeight
width: row.width
- height: 40
signal toolBarAction(int action)
Row {
id: row
-
+ spacing: StudioTheme.Values.toolbarSpacing
anchors.verticalCenter: parent.verticalCenter
leftPadding: 6
- IconButton {
- icon: StudioTheme.Constants.applyMaterialToSelected
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.apply_medium
enabled: hasTexture && hasSingleModelSelection && hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
tooltip: qsTr("Apply texture to selected model's material.")
+ onClicked: root.toolBarAction(ToolBarAction.ApplyToSelected)
}
- IconButton {
- icon: StudioTheme.Constants.newMaterial
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.create_medium
enabled: hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.AddNewTexture)
tooltip: qsTr("Create new texture.")
+ onClicked: root.toolBarAction(ToolBarAction.AddNewTexture)
}
- IconButton {
- icon: StudioTheme.Constants.deleteMaterial
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.delete_medium
enabled: hasTexture && hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentTexture)
tooltip: qsTr("Delete current texture.")
+ onClicked: root.toolBarAction(ToolBarAction.DeleteCurrentTexture)
}
- IconButton {
- icon: StudioTheme.Constants.openMaterialBrowser
-
- normalColor: StudioTheme.Values.themeSectionHeadBackground
- iconSize: StudioTheme.Values.bigIconFontSize
- buttonSize: root.height
- enabled: hasQuick3DImport && hasMaterialLibrary
- onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
+ HelperWidgets.AbstractButton {
+ style: StudioTheme.Values.viewBarButtonStyle
+ buttonIcon: StudioTheme.Constants.materialBrowser_medium
+ enabled: hasTexture && hasQuick3DImport && hasMaterialLibrary
tooltip: qsTr("Open material browser.")
+ onClicked: root.toolBarAction(ToolBarAction.OpenMaterialBrowser)
}
}
}
diff --git a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorTopSection.qml b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorTopSection.qml
index f52d126165..7c03d79571 100644
--- a/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorTopSection.qml
+++ b/share/qtcreator/qmldesigner/textureEditorQmlSource/TextureEditorTopSection.qml
@@ -35,8 +35,9 @@ Column {
Image {
id: texturePreview
asynchronous: true
- sourceSize.width: 150
- sourceSize.height: 150
+ width: 150
+ height: 150
+ fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
source: "image://qmldesigner_thumbnails/" + resolveResourcePath(backendValues.source.valueToString)
}
diff --git a/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml b/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml
new file mode 100644
index 0000000000..930bd4fa77
--- /dev/null
+++ b/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml
@@ -0,0 +1,93 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+
+ListView {
+ id: root
+
+ property real crumbleWidth: 166
+ property real crumbleHeight: 36
+
+ property real inset: 5
+ property real strokeWidth: 1
+ property real textLeftMargin: 18
+ property real textTopMargin: 6
+ property real textRightMargin: 6
+ property real textBottomMargin: 6
+
+ property alias font: fontMetrics.font
+
+ signal clicked(index: int)
+
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.HorizontalFlick
+ interactive: true
+
+ orientation: ListView.Horizontal
+ clip: true
+ focus: true
+
+ function updateContentX() {
+ root.contentX = (root.contentWidth < root.width) ? 0 : root.contentWidth - root.width
+ }
+
+ onCountChanged: root.updateContentX()
+ onWidthChanged: root.updateContentX()
+
+ visible: root.count > 1 && root.width > (root.crumbleWidth) - 24
+
+ delegate: CrumbleBread {
+ text: fileName
+ tooltip: fileAddress
+
+ width: root.crumbleWidth
+ height: root.crumbleHeight
+
+ inset: root.inset
+ strokeWidth: root.strokeWidth
+ textLeftMargin: root.textLeftMargin
+ textTopMargin: root.textTopMargin
+ textRightMargin: root.textRightMargin
+ textBottomMargin: root.textBottomMargin
+
+ font: root.font
+
+ modelSize: root.count
+
+ onClicked: {
+ if (index + 1 < root.count)
+ root.clicked(index)
+ }
+ }
+
+ add: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 0
+ to: 1.0
+ duration: 400
+ }
+ NumberAnimation {
+ property: "scale"
+ from: 0
+ to: 1.0
+ duration: 400
+ }
+ }
+
+ displaced: Transition {
+ NumberAnimation {
+ property: "x"
+ duration: 400
+ easing.type: Easing.OutBack
+ }
+ }
+
+ FontMetrics {
+ id: fontMetrics
+ font.pixelSize: 12
+ font.family: "SF Pro"
+ }
+}
diff --git a/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml
new file mode 100644
index 0000000000..538c135642
--- /dev/null
+++ b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml
@@ -0,0 +1,177 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Shapes
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ id: root
+ antialiasing: true
+
+ property int modelSize
+
+ /* Colors might come from Theme */
+ property color idleBackgroundColor: StudioTheme.Values.themeControlBackground_toolbarIdle
+ property color idleStrokeColor: StudioTheme.Values.controlOutline_toolbarIdle
+ property color idleTextColor: StudioTheme.Values.themeTextColor
+ property color hoverBackgroundColor: StudioTheme.Values.themeControlBackground_topToolbarHover
+ property color hoverStrokeColor: StudioTheme.Values.controlOutline_toolbarHover
+ property color activeColor: StudioTheme.Values.themeInteraction
+ property color activeTextColor: StudioTheme.Values.themeTextSelectedTextColor
+
+ property string tooltip
+
+ property alias text: label.text
+ property alias font: label.font
+ property alias inset: backgroundPath.inset
+ property alias strokeWidth: backgroundPath.strokeWidth
+
+ property real textLeftMargin: 18
+ property real textTopMargin: 6
+ property real textRightMargin: 6
+ property real textBottomMargin: 6
+
+ readonly property int itemIndex: index
+ readonly property bool isFirst: itemIndex === 0
+ readonly property bool isLast: (itemIndex + 1) === modelSize
+
+ signal clicked(int callIdx)
+
+ width: 166
+ height: 36
+
+ Shape {
+ id: backgroundShape
+ anchors.fill: root
+
+ antialiasing: root.antialiasing
+ layer.enabled: antialiasing
+ layer.smooth: antialiasing
+ layer.samples: antialiasing ? 4 : 0
+
+ ShapePath {
+ id: backgroundPath
+
+ joinStyle: ShapePath.MiterJoin
+ fillColor: root.idleBackgroundColor
+ strokeColor: root.idleStrokeColor
+ strokeWidth: 1
+
+ property real inset: 5
+ property real rightOut: root.isLast ? 0 : root.inset
+ property real leftIn: root.isFirst ? 0 : root.inset
+ property real strokeOffset: backgroundPath.strokeWidth / 2
+
+ property real topY: backgroundPath.strokeOffset
+ property real bottomY: backgroundShape.height - backgroundPath.strokeOffset
+ property real halfY: (backgroundPath.topY + backgroundPath.bottomY) / 2
+
+ startX: backgroundPath.strokeOffset
+ startY: backgroundPath.topY
+
+ PathLine {
+ x: backgroundShape.width - backgroundPath.strokeOffset - backgroundPath.rightOut
+ y: backgroundPath.topY
+ }
+ PathLine {
+ x: backgroundShape.width - backgroundPath.strokeOffset
+ y: backgroundPath.halfY
+ }
+ PathLine {
+ x: backgroundShape.width - backgroundPath.strokeOffset - backgroundPath.rightOut
+ y: backgroundPath.bottomY
+ }
+ PathLine {
+ x: backgroundPath.strokeOffset
+ y: backgroundPath.bottomY
+ }
+ PathLine {
+ x: backgroundPath.leftIn + backgroundPath.strokeOffset
+ y: backgroundPath.halfY
+ }
+ PathLine {
+ x: backgroundPath.strokeOffset
+ y: backgroundPath.topY
+ }
+ }
+ }
+
+ Text {
+ id: label
+
+ anchors.fill: parent
+ anchors.leftMargin: root.textLeftMargin
+ anchors.topMargin: root.textTopMargin
+ anchors.rightMargin: root.textRightMargin
+ anchors.bottomMargin: root.textBottomMargin
+
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ color: root.idleTextColor
+
+ wrapMode: Text.Wrap
+ elide: Text.ElideRight
+ maximumLineCount: 1
+
+ text: "Crumble File"
+ font.pixelSize: 12
+ font.family: "SF Pro"
+
+ ToolTip.text: root.tooltip
+ ToolTip.visible: mouseArea.containsMouse
+ ToolTip.delay: 1000
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: root.clicked(root.itemIndex)
+ }
+
+ states: [
+ State {
+ name: "idle"
+ when: !mouseArea.containsMouse && !mouseArea.pressed && !root.isLast
+
+ PropertyChanges {
+ target: backgroundPath
+ fillColor: root.idleBackgroundColor
+ strokeColor: root.idleStrokeColor
+ }
+ },
+ State {
+ name: "active"
+ when: root.isLast
+ extend: "pressed"
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: backgroundPath
+ fillColor: root.hoverBackgroundColor
+ strokeColor: root.hoverStrokeColor
+ }
+ },
+ State {
+ name: "pressed"
+ when: mouseArea.pressed
+
+ PropertyChanges {
+ target: backgroundPath
+ strokeColor: root.activeColor
+ fillColor: root.activeColor
+ }
+
+ PropertyChanges {
+ target: label
+ color: root.activeTextColor
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/toolbar/Main.qml b/share/qtcreator/qmldesigner/toolbar/Main.qml
new file mode 100644
index 0000000000..3daf50c14b
--- /dev/null
+++ b/share/qtcreator/qmldesigner/toolbar/Main.qml
@@ -0,0 +1,403 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
+import QtQuickDesignerTheme 1.0
+
+import ToolBar 1.0
+
+Rectangle {
+ id: root
+ color: StudioTheme.Values.themeToolbarBackground
+
+ readonly property int mediumBreakpoint: 720
+ readonly property int largeBreakpoint: 1200
+ readonly property bool flyoutEnabled: root.width < root.largeBreakpoint
+
+ ToolBarBackend {
+ id: backend
+ }
+
+ Item {
+ id: topToolbarOtherMode
+ anchors.fill: parent
+ visible: !backend.isInDesignMode
+
+ ToolbarButton {
+ id: homeOther
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 10
+ tooltip: backend.isDesignModeEnabled ? qsTr("Switch to Design Mode.")
+ : qsTr("Switch to Welcome Mode.")
+ buttonIcon: backend.isDesignModeEnabled ? StudioTheme.Constants.designMode_large
+ : StudioTheme.Constants.home_large
+ onClicked: backend.triggerModeChange()
+ }
+
+ Text {
+ id: backTo
+ visible: backend.isDesignModeEnabled
+ anchors.verticalCenter: parent.verticalCenter
+ text: qsTr("Return to Design")
+ anchors.left: homeOther.right
+ anchors.leftMargin: 10
+ color: StudioTheme.Values.themeTextColor
+ }
+ }
+
+ Item {
+ id: topToolbar
+ anchors.fill: parent
+ visible: backend.isInDesignMode
+
+ ToolbarButton {
+ id: home
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 10
+ buttonIcon: StudioTheme.Constants.home_large
+ onClicked: backend.triggerModeChange()
+ tooltip: qsTr("Switch to Welcome Mode.")
+ }
+
+ ToolbarButton {
+ id: runProject
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: home.right
+ anchors.leftMargin: 10
+ buttonIcon: StudioTheme.Constants.runProjOutline_large
+ style: StudioTheme.ToolbarStyle {
+ radius: StudioTheme.Values.smallRadius
+
+ icon: StudioTheme.ControlStyle.IconColors {
+ idle: StudioTheme.Values.themeIdleGreen
+ hover: StudioTheme.Values.themeRunningGreen
+ interaction: "#ffffff"
+ disabled: "#636363"
+ }
+
+ background: StudioTheme.ControlStyle.BackgroundColors {
+ idle: StudioTheme.Values.themeControlBackground_toolbarIdle
+ hover: StudioTheme.Values.themeControlBackground_topToolbarHover
+ interaction: StudioTheme.Values.themeInteraction
+ disabled: StudioTheme.Values.themeControlBackground_toolbarIdle
+ }
+
+ border: StudioTheme.ControlStyle.BorderColors {
+ idle: StudioTheme.Values.themeControlBackground_toolbarIdle
+ hover: StudioTheme.Values.themeControlBackground_topToolbarHover
+ interaction: StudioTheme.Values.themeInteraction
+ disabled: StudioTheme.Values.themeControlBackground_toolbarIdle
+ }
+ }
+
+ onClicked: backend.runProject()
+ tooltip: qsTr("Run Project")
+ }
+
+ ToolbarButton {
+ id: livePreviewButton
+ style: StudioTheme.Values.primaryToolbarStyle
+ width: 96
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: runProject.right
+ anchors.leftMargin: 10
+ iconFont: StudioTheme.Constants.font
+ buttonIcon: qsTr("Live Preview")
+
+ onClicked: {
+ livePreview.trigger()
+ }
+
+ MouseArea {
+ acceptedButtons: Qt.RightButton
+ anchors.fill: parent
+
+ onClicked: {
+ var p = livePreviewButton.mapToGlobal(0, 0)
+ backend.showZoomMenu(p.x, p.y)
+ }
+ }
+
+ ActionSubscriber {
+ id: livePreview
+ actionId: "LivePreview"
+ }
+ }
+
+ StudioControls.TopLevelComboBox {
+ id: currentFile
+ style: StudioTheme.Values.toolbarStyle
+ width: 320 - ((root.width > root.mediumBreakpoint) ? 0 : (root.mediumBreakpoint - root.width))
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: livePreviewButton.right
+ anchors.leftMargin: 10
+ model: backend.documentModel
+
+ property int currentDocumentIndex: backend.documentIndex
+ onCurrentDocumentIndexChanged: currentFile.currentIndex = currentFile.currentDocumentIndex
+ onActivated: backend.openFileByIndex(index)
+ }
+
+ ToolbarButton {
+ id: backButton
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: currentFile.right
+ anchors.leftMargin: 10
+ enabled: backend.canGoBack
+ tooltip: qsTr("Go Back")
+ buttonIcon: StudioTheme.Constants.previousFile_large
+ iconRotation: 0
+
+ onClicked: backend.goBackward()
+ }
+
+ ToolbarButton {
+ id: forwardButton
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: backButton.right
+ anchors.leftMargin: 10
+ enabled: backend.canGoForward
+ tooltip: qsTr("Go Forward")
+ buttonIcon: StudioTheme.Constants.nextFile_large
+
+ onClicked: backend.goForward()
+ }
+
+ ToolbarButton {
+ id: closeButton
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: forwardButton.right
+ anchors.leftMargin: 10
+ tooltip: qsTr("Close")
+ buttonIcon: StudioTheme.Constants.closeFile_large
+
+ onClicked: backend.closeCurrentDocument()
+ }
+
+ CrumbleBar {
+ id: flickable
+ height: 36
+ anchors.left: closeButton.right
+ anchors.leftMargin: 10
+ anchors.right: createComponent.left
+ anchors.rightMargin: 10
+ anchors.verticalCenter: parent.verticalCenter
+ model: CrumbleBarModel {
+ id: crumbleBarModel
+ }
+
+ onClicked: crumbleBarModel.onCrumblePathElementClicked(index)
+ }
+
+ ToolbarButton {
+ id: createComponent
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: enterComponent.left
+ anchors.rightMargin: 10
+ enabled: moveToComponentBackend.available
+ tooltip: moveToComponentBackend.tooltip
+ buttonIcon: StudioTheme.Constants.createComponent_large
+ visible: !root.flyoutEnabled
+
+ onClicked: moveToComponentBackend.trigger()
+
+ ActionSubscriber {
+ id: moveToComponentBackend
+ actionId: "MakeComponent"
+ }
+ }
+
+ ToolbarButton {
+ id: enterComponent
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: workspaces.left
+ anchors.rightMargin: 10
+ enabled: goIntoComponentBackend.available
+ tooltip: goIntoComponentBackend.tooltip
+ buttonIcon: StudioTheme.Constants.editComponent_large
+ visible: !root.flyoutEnabled
+
+ onClicked: goIntoComponentBackend.trigger()
+
+ ActionSubscriber {
+ id: goIntoComponentBackend
+ actionId: "GoIntoComponent"
+ }
+ }
+
+ StudioControls.TopLevelComboBox {
+ id: workspaces
+ style: StudioTheme.Values.toolbarStyle
+ width: 210
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: annotations.left
+ anchors.rightMargin: 10
+ model: backend.workspaces
+ suffix: qsTr(" Workspace")
+ property int currentWorkspaceIndex: workspaces.find(backend.currentWorkspace)
+ onCurrentWorkspaceIndexChanged: workspaces.currentIndex = workspaces.currentWorkspaceIndex
+
+ visible: !root.flyoutEnabled
+
+ onActivated: backend.setCurrentWorkspace(workspaces.currentText)
+ }
+
+ ToolbarButton {
+ id: annotations
+ visible: false
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: shareButton.left
+ anchors.rightMargin: 10
+ tooltip: qsTr("Edit Annotations")
+ buttonIcon: StudioTheme.Constants.annotations_large
+ //visible: !root.flyoutEnabled
+
+ onClicked: backend.editGlobalAnnoation()
+ width: 0
+ }
+
+ ToolbarButton {
+ id: shareButton
+ style: StudioTheme.Values.primaryToolbarStyle
+ width: 96
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: moreItems.left
+ anchors.rightMargin: 8
+ iconFont: StudioTheme.Constants.font
+ buttonIcon: qsTr("Share")
+ visible: !root.flyoutEnabled
+
+ onClicked: backend.shareApplicationOnline()
+ }
+
+ ToolbarButton {
+ // this needs a pop-up panel where overflow toolbar content goes when toolbar is not wide enough
+ id: moreItems
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ anchors.rightMargin: 10
+ tooltip: qsTr("More Items")
+ buttonIcon: StudioTheme.Constants.more_medium
+ enabled: root.flyoutEnabled
+ checkable: true
+ checked: window.visible
+ checkedInverted: true
+ onClicked: {
+ if (window.visible) {
+ window.close()
+ } else {
+ var originMapped = moreItems.mapToGlobal(0,0)
+ window.x = originMapped.x + moreItems.width - window.width
+ window.y = originMapped.y + moreItems.height + 7
+ window.show()
+ window.requestActivate()
+ }
+ }
+ }
+
+ Window {
+ id: window
+
+ readonly property int padding: 6
+
+ width: row.width + window.padding * 2
+ height: row.height + workspacesFlyout.height + 3 * window.padding
+ + (workspacesFlyout.popup.opened ? workspacesFlyout.popup.height : 0)
+ visible: false
+ flags: Qt.FramelessWindowHint | Qt.Dialog | Qt.NoDropShadowWindowHint
+ modality: Qt.NonModal
+ transientParent: null
+ color: "transparent"
+
+ onActiveFocusItemChanged: {
+ if (window.activeFocusItem === null && !moreItems.hovered)
+ window.close()
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: StudioTheme.Values.themePopupBackground
+ radius: StudioTheme.Values.smallRadius
+
+ Column {
+ id: column
+ anchors.margins: window.padding
+ anchors.fill: parent
+ spacing: window.padding
+
+ Row {
+ id: row
+ spacing: window.padding
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ ToolbarButton {
+ style: StudioTheme.Values.statusbarButtonStyle
+ anchors.verticalCenter: parent.verticalCenter
+ enabled: moveToComponentBackend.available
+ tooltip: moveToComponentBackend.tooltip
+ buttonIcon: StudioTheme.Constants.createComponent_large
+
+ onClicked: moveToComponentBackend.trigger()
+
+ ActionSubscriber {
+ actionId: "MakeComponent"
+ }
+ }
+
+ ToolbarButton {
+ style: StudioTheme.Values.statusbarButtonStyle
+ anchors.verticalCenter: parent.verticalCenter
+ enabled: goIntoComponentBackend.available
+ tooltip: goIntoComponentBackend.tooltip
+ buttonIcon: StudioTheme.Constants.editComponent_large
+
+ onClicked: goIntoComponentBackend.trigger()
+
+ ActionSubscriber {
+ actionId: "GoIntoComponent"
+ }
+ }
+
+ ToolbarButton {
+ visible: false
+ style: StudioTheme.Values.statusbarButtonStyle
+ anchors.verticalCenter: parent.verticalCenter
+ tooltip: qsTr("Edit Annotations")
+ buttonIcon: StudioTheme.Constants.annotations_large
+
+ onClicked: backend.editGlobalAnnoation()
+ }
+
+ ToolbarButton {
+ anchors.verticalCenter: parent.verticalCenter
+ style: StudioTheme.Values.primaryToolbarStyle
+ width: shareButton.width
+ iconFont: StudioTheme.Constants.font
+ buttonIcon: qsTr("Share")
+
+ onClicked: backend.shareApplicationOnline()
+ }
+ }
+
+ StudioControls.ComboBox {
+ id: workspacesFlyout
+ anchors.horizontalCenter: parent.horizontalCenter
+ actionIndicatorVisible: false
+ style: StudioTheme.Values.statusbarControlStyle
+ width: row.width
+ maximumPopupHeight: 400
+ model: backend.workspaces
+ currentIndex: workspacesFlyout.find(backend.currentWorkspace)
+
+ onCompressedActivated: backend.setCurrentWorkspace(workspacesFlyout.currentText)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml b/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml
new file mode 100644
index 0000000000..706f0f1960
--- /dev/null
+++ b/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import StudioControls 1.0 as StudioControls
+import StudioTheme 1.0 as StudioTheme
+import HelperWidgets 2.0
+
+StudioControls.AbstractButton {
+ id: button
+
+ property alias tooltip: toolTipArea.tooltip
+
+ style: StudioTheme.Values.toolbarButtonStyle
+ hover: toolTipArea.containsMouse
+
+ ToolTipArea {
+ id: toolTipArea
+ anchors.fill: parent
+ // Without setting the acceptedButtons property the clicked event won't
+ // reach the AbstractButton, it will be consumed by the ToolTipArea
+ acceptedButtons: Qt.NoButton
+ }
+}
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk
new file mode 100644
index 0000000000..2336c94ffa
--- /dev/null
+++ b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="DebugView" closed="true"/></area><area tabs="3" current="ContentLibrary"><widget name="ContentLibrary" closed="false"/><widget name="Components" closed="false"/><widget name="Assets" closed="true"/></area><area tabs="3" current="OpenDocuments"><widget name="Projects" closed="true"/><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><sizes>622 527 0</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="2"><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="false"/></area><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><sizes>620 529</sizes></splitter><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><splitter orientation="Vertical" count="2"><area tabs="1" current="MaterialBrowser"><widget name="MaterialBrowser" closed="false"/></area><area tabs="3" current="MaterialEditor"><widget name="MaterialEditor" closed="false"/><widget name="TextureEditor" closed="false"/><widget name="Properties" closed="false"/></area><sizes>575 574</sizes></splitter><sizes>1233 0 533</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="3" current="Timelines"><widget name="TransitionEditor" closed="true"/><widget name="CurveEditorId" closed="true"/><widget name="Timelines" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>1150 0</sizes></splitter><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="true"/></area><sizes>536 1767 0</sizes></splitter><area tabs="1" current="StatesEditor"><widget name="StatesEditor" closed="true"/></area><sizes>1150 0</sizes></splitter></container></QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
index b74da2a048..7282eb1a63 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="FileSystem"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>541 0 426</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="false"/></area><sizes>353 353</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>919 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="3" current="Timelines"><widget name="Timelines" closed="false"/><widget name="CurveEditorId" closed="false"/><widget name="StatesEditor" closed="true"/></area><area tabs="1" current=""><widget name="TransitionEditor" closed="true"/></area><sizes>919 0</sizes></splitter><sizes>707 260</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="true"/></area><sizes>968 0 0</sizes></splitter><sizes>312 919 408</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><area tabs="4" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/><widget name="MaterialBrowser" closed="false"/><widget name="ContentLibrary" closed="false"/></area><area tabs="2" current="Editor3D"><widget name="Editor3D" closed="false"/><widget name="FormEditor" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><sizes>688 2515 0</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><area tabs="3" current="StatesEditor"><widget name="StatesEditor" closed="false"/><widget name="TransitionEditor" closed="false"/><widget name="CurveEditorId" closed="false"/></area><area tabs="1" current="Timelines"><widget name="Timelines" closed="false"/></area><sizes>1604 1599</sizes></splitter><area tabs="3" current="OutputPane"><widget name="OutputPane" closed="false"/><widget name="TextEditor" closed="false"/><widget name="ConnectionView" closed="true"/></area><sizes>544 42</sizes></splitter><sizes>1426 587</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="4" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/><widget name="FileSystem" closed="false"/><widget name="OpenDocuments" closed="true"/></area><area tabs="3" current="Properties"><widget name="Properties" closed="false"/><widget name="MaterialEditor" closed="false"/><widget name="TextureEditor" closed="false"/></area><sizes>994 1019</sizes></splitter><sizes>3204 635</sizes></splitter></container></QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
index aec1d2e294..e7ac0763b1 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="OpenDocuments"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>487 0 480</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>707 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>707 0</sizes></splitter><sizes>914 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="2" current="StatesEditor"><widget name="StatesEditor" closed="false"/><widget name="Timelines" closed="true"/></area><area tabs="2" current="TransitionEditor"><widget name="CurveEditorId" closed="true"/><widget name="TransitionEditor" closed="true"/></area><sizes>914 0</sizes></splitter><sizes>707 260</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>707 0 260</sizes></splitter><sizes>310 914 406</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="OpenDocuments"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>439 0 433</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>873 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>1291 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="1" current=""><widget name="Timelines" closed="true"/></area><area tabs="2" current="TransitionEditor"><widget name="CurveEditorId" closed="true"/><widget name="TransitionEditor" closed="true"/></area><sizes>1291 0</sizes></splitter><sizes>873 0</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>637 0 235</sizes></splitter><sizes>438 1291 573</sizes></splitter><area tabs="1" current="StatesEditor"><widget name="StatesEditor" closed="false"/></area><sizes>873 276</sizes></splitter></container></QtAdvancedDockingSystem>
diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme
index b862ac5fc9..a214688bf9 100644
--- a/share/qtcreator/themes/dark.creatortheme
+++ b/share/qtcreator/themes/dark.creatortheme
@@ -21,9 +21,63 @@ textColorLinkVisited=ffc58af9
backgroundColorDisabled=ff444444
qmlDesignerButtonColor=ff3c3e40
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
-DSpanelBackground=ff2E2F30
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=midnightGrey
+DScontrolBackground_toolbarHover=midnightGrey
+DScontrolBackground_topToolbarHover=ashGrey
+DScontrolBackground_statusbarIdle=offBlack
+DSControlBackground_statusbarHover=dawnGrey
+DScontrolOutline_topToolbarIdle=dawnGrey
+DScontrolOutline_topToolbarHover=raincloudGrey
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=midnightGrey
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=nearBlack
+DStextColor=lightWhite
+DSstatusbarBackground=offBlack
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=ashGrey
+DSstateControlBackgroundColor_globalHover=ashGrey
+DSstateControlBackgroundColor_hover=raincloudGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
+
+DSpanelBackground=dawnGrey
DSwelcomeScreenBackground=ff242424
DSsubPanelBackground=ff1c1c1c
@@ -34,21 +88,21 @@ DSgreenLight=ff5cdc68
DSamberLight=ffffbf00
DSredLight=ffff0401
-DSinteraction=ff2aafd3
+DSinteraction=highlightBlue
DSerrorColor=ffdf3a3a
DSwarningColor=warning
DSdisabledColor=ff707070
DSinteractionHover=ff74cbfc
-DScontrolBackground=ff2e2f30
+DScontrolBackground=dawnGrey
DScontrolBackgroundInteraction=ff3d3d3d
DScontrolBackgroundDisabled=ff2e2f30
DScontrolBackgroundGlobalHover=ff333333
DScontrolBackgroundHover=ff333333
-DScontrolOutline=ff1f1f1f
-DScontrolOutlineInteraction=ff2aafd3
+DScontrolOutline=nearBlack
+DScontrolOutlineInteraction=highlightBlue
DScontrolOutlineDisabled=ff707070
DStextColor=ffffffff
@@ -61,16 +115,16 @@ DSplaceholderTextColorInteraction=ffababab
DSiconColor=ffffffff
DSiconColorHover=ffffffff
-DSiconColorInteraction=ff707070
+DSiconColorInteraction=nearBlack
DSiconColorDisabled=ffC7C7C7
-DSiconColorSelected=ff2aafd3
+DSiconColorSelected=nearBlack
DSlinkIndicatorColor=ff808080
DSlinkIndicatorColorHover=ffffffff
DSlinkIndicatorColorInteraction=ff2aafd3
DSlinkIndicatorColorDisabled=ff707070
-DSpopupBackground=ff474747
+DSpopupBackground=offBlack
DSpopupOverlayColor=99191919
DSsliderActiveTrack=ff7c7b7b
@@ -84,13 +138,13 @@ DSsliderHandleHover=ff606060
DSsliderHandleFocus=ff0492c9
DSsliderHandleInteraction=ff2aafd3
-DSscrollBarTrack=ff3E3E3E
-DSscrollBarHandle=ff4C4C4C
+DSscrollBarTrack=dawnGrey
+DSscrollBarHandle=offBlack
-DSsectionHeadBackground=ff1f1f1f
+DSsectionHeadBackground=midnightGrey
DSstateDefaultHighlight=ffffe400
-DSstateSeparatorColor=ff7c7b7b
+DSstateSeparatorColor=graniteGrey
DSstateBackgroundColor=ff383838
DSstatePreviewOutline=ffaaaaaa
@@ -116,8 +170,8 @@ DSdockContainerSplitter=ff323232
DSdockAreaBackground=ff262728
DSdockWidgetBackground=ff00ff00
-DSdockWidgetSplitter=ff595959
-DSdockWidgetTitleBar=ff1f1f1f
+DSdockWidgetSplitter=fullBlack
+DSdockWidgetTitleBar=dawnGrey
DStitleBarText=ffdadada
DStitleBarIcon=ffffffff
@@ -133,24 +187,24 @@ DStabInactiveIcon=ffffffff
DStabInactiveButtonHover=ff1f1f1f
DStabInactiveButtonPress=ff1f1f1f
-DStabActiveBackground=ffdadada
-DStabActiveText=ff111111
-DStabActiveIcon=ff000000
+DStabActiveBackground=raincloudGrey
+DStabActiveText=offWhite
+DStabActiveIcon=offWhite
DStabActiveButtonHover=ffdadada
DStabActiveButtonPress=ffdadada
-DStabFocusBackground=ff2aafd3
+DStabFocusBackground=highlightBlue
DStabFocusText=ff111111
DStabFocusIcon=ff000000
-DStabFocusButtonHover=ff2aafd3
-DStabFocusButtonPress=ff2aafd3
+DStabFocusButtonHover=highlightBlue
+DStabFocusButtonPress=highlightBlue
DSnavigatorBranch=ff7c7b7b
DSnavigatorBranchIndicator=ff7c7b7b
-DSnavigatorItemBackground=ff2E2F30
-DSnavigatorItemBackgroundHover=ff333333
-DSnavigatorItemBackgroundSelected=ff3D3D3D
-DSnavigatorText=ffffffff
+DSnavigatorItemBackground=dawnGrey
+DSnavigatorItemBackgroundHover=graniteGrey
+DSnavigatorItemBackgroundSelected=midnightGrey
+DSnavigatorText=lightWhite
DSnavigatorTextHover=ffffffff
DSnavigatorTextSelected=ff2aafd3
DSnavigatorIcon=ffffffff
@@ -172,6 +226,8 @@ DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground
DSBackgroundColorNormal=normalBackground
+DStoolbarBackground=midnightGrey
+
;DS controls theme END
BackgroundColorAlternate=alternateBackground
@@ -368,13 +424,13 @@ PaletteWindowTextDisabled=textDisabled
PaletteBaseDisabled=backgroundColorDisabled
PaletteTextDisabled=textDisabled
PaletteMid=ffa0a0a0
-PalettePlaceholderText=ff8d8d8d
+PalettePlaceholderText=slateGrey
QmlDesigner_BackgroundColor=qmlDesignerButtonColor
QmlDesigner_HighlightColor=ff46a2da
QmlDesigner_FormEditorSelectionColor=ff4ba2ff
QmlDesigner_FormEditorForegroundColor=ffffffff
-QmlDesigner_BackgroundColorDarkAlternate=ff323232
+QmlDesigner_BackgroundColorDarkAlternate=dawnGrey
QmlDesigner_BackgroundColorDarker=ff151515
QmlDesigner_BorderColor=splitterColor
QmlDesigner_ButtonColor=ff505050
@@ -421,6 +477,7 @@ FlatMenuBar=true
ToolBarIconShadow=true
WindowColorAsBase=false
DarkUserInterface=true
+QDSTheme=false
[ImageFiles]
IconOverlayCSource=:/cppeditor/images/dark_qt_c.png
diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme
index 31a7dcc8ea..a7095266a8 100644
--- a/share/qtcreator/themes/default.creatortheme
+++ b/share/qtcreator/themes/default.creatortheme
@@ -12,8 +12,64 @@ shadowBackground=ff232323
splitterColor=ff151515
qmlDesignerButtonColor=ff4c4e50
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+concreteGrey=ffbbbbbb
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=offWhite
+DScontrolBackground_toolbarHover=offWhite
+DScontrolBackground_topToolbarHover=concreteGrey
+DScontrolBackground_statusbarIdle=concreteGrey
+DSControlBackground_statusbarHover=lightWhite
+DScontrolOutline_topToolbarIdle=concreteGrey
+DScontrolOutline_topToolbarHover=lightWhite
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=offWhite
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=smokeGrey
+DStextColor=raincloudGrey
+DSstatusbarBackground=concreteGrey
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=concreteGrey
+DSstateControlBackgroundColor_globalHover=concreteGrey
+DSstateControlBackgroundColor_hover=smokeGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
+
DSpanelBackground=ffeaeaea
DSwelcomeScreenBackground=ffEAEAEA
@@ -86,7 +142,7 @@ DSstateBackgroundColor=ffe0e0e0
DSstatePreviewOutline=ff363636
DSstatePanelBackground=ffdadada
-DSstateHighlight=ff8d8d8d
+DSstateHighlight=offWhite
DSchangedStateText=ff99ccff
@@ -163,6 +219,7 @@ DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=ffeaeaea
DSBackgroundColorNormal=ffd8d8d8
+
;DS controls theme END
BackgroundColorAlternate=ff3d3d3d
@@ -389,3 +446,4 @@ FlatMenuBar=false
ToolBarIconShadow=true
WindowColorAsBase=false
DarkUserInterface=false
+QDSTheme=false
diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme
index 253cb5f96a..eeac285a5f 100644
--- a/share/qtcreator/themes/design-light.creatortheme
+++ b/share/qtcreator/themes/design-light.creatortheme
@@ -2,7 +2,6 @@
ThemeName=Design Light
PreferredStyles=
-
[Palette]
shadowBackground=ffd1cfcf
text=ff000000
@@ -26,8 +25,64 @@ textColorLink=ff007af4
textColorLinkVisited=ffa57aff
backgroundColorDisabled=ff8e8e8e
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+concreteGrey=ffbbbbbb
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=offWhite
+DScontrolBackground_toolbarHover=offWhite
+DScontrolBackground_topToolbarHover=concreteGrey
+DScontrolBackground_statusbarIdle=concreteGrey
+DSControlBackground_statusbarHover=lightWhite
+DScontrolOutline_topToolbarIdle=concreteGrey
+DScontrolOutline_topToolbarHover=lightWhite
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=offWhite
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=smokeGrey
+DStextColor=raincloudGrey
+DSstatusbarBackground=concreteGrey
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=concreteGrey
+DSstateControlBackgroundColor_globalHover=concreteGrey
+DSstateControlBackgroundColor_hover=smokeGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
+
DSpanelBackground=ffeaeaea
DSwelcomeScreenBackground=ffEAEAEA
@@ -39,12 +94,12 @@ DSgreenLight=ff5cdc68
DSamberLight=ffffbf00
DSredLight=ffff0401
-DSinteraction=ff2aafd3
+DSinteraction=highlightBlue
DSerrorColor=ffdf3a3a
DSwarningColor=warning
DSdisabledColor=ff8e8e8e
-DSinteractionHover=ff74cbfc
+DSinteractionHover=highlightHover
DScontrolBackground=ffeaeaea
DScontrolBackgroundInteraction=ffc9c9c9
@@ -56,7 +111,6 @@ DScontrolOutline=ffcecccc
DScontrolOutlineInteraction=ff2aafd3
DScontrolOutlineDisabled=ff707070
-DStextColor=ff262626
DStextColorDisabled=ff707070
DStextSelectionColor=ff2aafd3
DStextSelectedTextColor=ff000000
@@ -433,3 +487,4 @@ FlatMenuBar=true
ToolBarIconShadow=false
WindowColorAsBase=false
DarkUserInterface=false
+QDSTheme=true
diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme
index 462d49f7f8..5e8294efa5 100644
--- a/share/qtcreator/themes/design.creatortheme
+++ b/share/qtcreator/themes/design.creatortheme
@@ -23,37 +23,119 @@ textColorLink=ff007af4
textColorLinkVisited=ffa57aff
backgroundColorDisabled=ff444444
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+concreteGrey=ffbbbbbb
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
-;DS controls theme START
-DSpanelBackground=ff2E2F30
+;DS controls theme
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=midnightGrey
+DScontrolBackground_toolbarHover=midnightGrey
+DScontrolBackground_topToolbarHover=ashGrey
+DScontrolBackground_statusbarIdle=offBlack
+DSControlBackground_statusbarHover=dawnGrey
+DScontrolOutline_topToolbarIdle=dawnGrey
+DScontrolOutline_topToolbarHover=raincloudGrey
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=midnightGrey
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=nearBlack
+DStextColor=lightWhite
+DSstatusbarBackground=offBlack
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=ashGrey
+DSstateControlBackgroundColor_globalHover=ashGrey
+DSstateControlBackgroundColor_hover=raincloudGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
+
+;REMAPPED
+DSinteraction=highlightBlue
+DScontrolBackground=dawnGrey
+DScontrolOutlineInteraction=highlightBlue
+DScontrolOutline=nearBlack
+DSiconColorInteraction=nearBlack
+DSiconColorSelected=nearBlack
+DSsectionHeadBackground=midnightGrey
+DSstateSeparatorColor=graniteGrey
+DSnavigatorItemBackground=dawnGrey
+DSnavigatorItemBackgroundHover=graniteGrey
+DSnavigatorItemBackgroundSelected=midnightGrey
+DStabActiveBackground=raincloudGrey
+DStabActiveText=offWhite
+DStabActiveIcon=offWhite
+DStabFocusButtonHover=highlightBlue
+DStabFocusButtonPress=highlightBlue
+DStabFocusBackground=highlightBlue
+DSnavigatorText=lightWhite
+DSpopupBackground=offBlack
+DSinteractionHover=highlightHover
+DSnavigatorTextSelected=highlightBlue
+
+;contentious remap
+;background color for main form view, library, navigator, properties, connections
+QmlDesigner_BackgroundColorDarkAlternate=dawnGrey
+
+;TODO
+DSscrollBarTrack=dawnGrey
+DSscrollBarHandle=offBlack
+
+DSdockWidgetTitleBar=dawnGrey
+DSdockWidgetSplitter=fullBlack
+;LEGACY
DSwelcomeScreenBackground=ff242424
DSsubPanelBackground=ff1c1c1c
DSthumbnailBackground=ff232323
DSthumbnailLabelBackground=ff2b2a2a
-
DSgreenLight=ff5cdc68
DSamberLight=ffffbf00
DSredLight=ffff0401
-DSinteraction=ff2aafd3
DSerrorColor=ffdf3a3a
DSwarningColor=warning
DSdisabledColor=ff707070
-DSinteractionHover=ff74cbfc
-DScontrolBackground=ff2e2f30
DScontrolBackgroundInteraction=ff3d3d3d
DScontrolBackgroundDisabled=ff2e2f30
DScontrolBackgroundGlobalHover=ff333333
DScontrolBackgroundHover=ff333333
-DScontrolOutline=ff1f1f1f
-DScontrolOutlineInteraction=ff2aafd3
DScontrolOutlineDisabled=ff707070
-DStextColor=ffffffff
DStextColorDisabled=ff707070
DStextSelectionColor=ff2aafd3
DStextSelectedTextColor=ff000000
@@ -61,18 +143,16 @@ DStextSelectedTextColor=ff000000
DSplaceholderTextColor=ffffffff
DSplaceholderTextColorInteraction=ffababab
-DSiconColor=ffffffff
+DSiconColor=fullWhite
DSiconColorHover=ffffffff
-DSiconColorInteraction=ff707070
DSiconColorDisabled=ffC7C7C7
DSiconColorSelected=ff2aafd3
-
DSlinkIndicatorColor=ff808080
DSlinkIndicatorColorHover=ffffffff
DSlinkIndicatorColorInteraction=ff2aafd3
DSlinkIndicatorColorDisabled=ff707070
-DSpopupBackground=ff474747
+
DSpopupOverlayColor=99191919
DSsliderActiveTrack=ff7c7b7b
@@ -86,14 +166,8 @@ DSsliderHandleHover=ff606060
DSsliderHandleFocus=ff0492c9
DSsliderHandleInteraction=ff2aafd3
-DSscrollBarTrack=ff3E3E3E
-DSscrollBarHandle=ff4C4C4C
-
-DSsectionHeadBackground=ff1f1f1f
-
DSstateDefaultHighlight=ffffe400
-DSstateSeparatorColor=ff7c7b7b
-DSstateBackgroundColor=ff383838
+DSstateBackgroundColor=fffff000
DSstatePreviewOutline=ffaaaaaa
DSstatePanelBackground=ff252525
@@ -116,11 +190,7 @@ DStableHeaderText=ff00ff00
DSdockContainerBackground=ff242424
DSdockContainerSplitter=ff323232
DSdockAreaBackground=ff262728
-
DSdockWidgetBackground=ff00ff00
-DSdockWidgetSplitter=ff595959
-DSdockWidgetTitleBar=ff1f1f1f
-
DStitleBarText=ffdadada
DStitleBarIcon=ffffffff
DStitleBarButtonHover=40ffffff
@@ -135,26 +205,16 @@ DStabInactiveIcon=ffffffff
DStabInactiveButtonHover=ff1f1f1f
DStabInactiveButtonPress=ff1f1f1f
-DStabActiveBackground=ffdadada
-DStabActiveText=ff111111
-DStabActiveIcon=ff000000
DStabActiveButtonHover=ffdadada
DStabActiveButtonPress=ffdadada
-DStabFocusBackground=ff2aafd3
DStabFocusText=ff111111
DStabFocusIcon=ff000000
-DStabFocusButtonHover=ff2aafd3
-DStabFocusButtonPress=ff2aafd3
DSnavigatorBranch=ff7c7b7b
DSnavigatorBranchIndicator=ff7c7b7b
-DSnavigatorItemBackground=ff2E2F30
-DSnavigatorItemBackgroundHover=ff333333
-DSnavigatorItemBackgroundSelected=ff3D3D3D
-DSnavigatorText=ffffffff
DSnavigatorTextHover=ffffffff
-DSnavigatorTextSelected=ff2aafd3
+
DSnavigatorIcon=ffffffff
DSnavigatorIconHover=ffa1a1a1
DSnavigatorIconSelected=ffffffff
@@ -349,143 +409,85 @@ ProjectExplorer_TaskWarn_TextMarkColor=warning
CodeModel_Error_TextMarkColor=error
CodeModel_Warning_TextMarkColor=warning
-
;Designer Main colors
; Design View panel backgrounds - Library, Form Viewer, Properties, States, Timeline & Connections. - lOOKS LIKE IS NO LONGER USED.
QmlDesigner_BackgroundColor=ff4c4e50
-;QmlDesigner_BackgroundColor=ffd3299a
-
; Design View selected items - Navigator Selection, Timeline Property Selection, TImeline bar, property text highlighted
QmlDesigner_HighlightColor=ff0492c9
-
-
; live selection color for the form editors smart guides.
-;QmlDesigner_FormEditorSelectionColor=ff4ba2ff
QmlDesigner_FormEditorSelectionColor=ffd3299a
-
;color for lable text in form editor
QmlDesigner_FormEditorForegroundColor=ffdadada
-;QmlDesigner_FormEditorForegroundColor=ffd3299a
-
-
-
-
-;new colors
-
-;background color for main form view, library, navigator, properties, connections
-;QmlDesigner_BackgroundColorDarkAlternate=ff4c4e50
-QmlDesigner_BackgroundColorDarkAlternate=ff2e2f30
;filter outlines, override W/H outlines, properties spinbox background, timeline separators.
-;QmlDesigner_BackgroundColorDarker=ff262728
QmlDesigner_BackgroundColorDarker=ff191919
;properties outlines, states thumbnail outlines, add state button outlines.
-;QmlDesigner_BorderColor=splitter
QmlDesigner_BorderColor=ff353535
;background sqaures for components, effects, etc. Handles for scrollbars, type background in properties.
-;QmlDesigner_ButtonColor=ff595b5c
QmlDesigner_ButtonColor=ff353535
;non - selected tabs, text color for selected tabs.
-;QmlDesigner_TabDark=shadowBackground
QmlDesigner_TabDark=ff111111
;active tab backgrounds and non selected tab text.
QmlDesigner_TabLight=text
-;QmlDesigner_TabLight=ff262626
-
-;extra_new_colors
+;extra_new_colors
QmlDesigner_FormeditorBackgroundColor=ff000000
-
QmlDesigner_AlternateBackgroundColor=ffc14fc1
-
QmlDesigner_ScrollBarHandleColor=ff595b5c
-
-
;palette colors
;outline colors on the combo box, zoom slider, dialog outlines, on loading project the whole screen flashes this color
-;PaletteWindow=normalBackground
PaletteWindow=ff262626
-
-
; item text for search results panel and application output panel, twirl down triangles in edit mode, text editor.
PaletteWindowText=text
-;PaletteWindowText=ffd3299a
-
;Search bar background, edit view project list background, style combo box background
PaletteBase=normalBackground
-;PaletteBase=ff191919
-
-
;can't see where this is used. ;Used in plugin dialog
PaletteAlternateBase=normalBackground
-;PaletteAlternateBase=ffd3299a
-
-
;flow tag backgrounds, import combobox background, edit mode scrollbars
-;PaletteButton=shadowBackground
PaletteButton=ff262626
-
-
;alternate text in the search and application output panel - NO LONGER SEEMS TO DO ANYTHING
PaletteBrightText=ffff3333
-;PaletteBrightText=ffd3299a
-
; text inside dropdown combo boxes, styles, connections.
PaletteText=text
-;PaletteText=ffd3299a
-
-
; text for ticks for tick boxes.
PaletteButtonText=text
-;PaletteButtonText=ffd3299a
-
PaletteButtonTextDisabled=textDisabled
-
;background color for the tool tip hover background
PaletteToolTipBase=selectedBackground
-;PaletteToolTipBase=ffd3299a
-
;the selection highlight on the dropdown combo box in the file selection top menu and connections panel and tab mode selector dropdowns
PaletteHighlight=selectedBackgroundText
-
; outline of warning in editor mode, underline of "open a document" page in the edit mode
PaletteDark=shadowBackground
-;PaletteDark=ffd3299a
-
;selected text highlight in edit and design studio modes
PaletteHighlightedText=ffffffff
-;PaletteHighlightedText=ffd3299a
-
; text for for floating tool tips
PaletteToolTipText=text
-;PaletteToolTipText=ffd3299a
-
PaletteLink=textColorLink
PaletteLinkVisited=textColorLinkVisited
@@ -533,3 +535,4 @@ FlatMenuBar=true
ToolBarIconShadow=true
WindowColorAsBase=false
DarkUserInterface=true
+QDSTheme=true
diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme
index b05539d963..bb6b905288 100644
--- a/share/qtcreator/themes/flat-dark.creatortheme
+++ b/share/qtcreator/themes/flat-dark.creatortheme
@@ -25,9 +25,62 @@ textColorLinkVisited=ffa57aff
backgroundColorDisabled=ff444444
qmlDesignerButtonColor=ff4c4e50
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
-DSpanelBackground=ff2E2F30
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=midnightGrey
+DScontrolBackground_toolbarHover=midnightGrey
+DScontrolBackground_topToolbarHover=ashGrey
+DScontrolBackground_statusbarIdle=offBlack
+DSControlBackground_statusbarHover=dawnGrey
+DScontrolOutline_topToolbarIdle=dawnGrey
+DScontrolOutline_topToolbarHover=raincloudGrey
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=midnightGrey
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=nearBlack
+DStextColor=lightWhite
+DSstatusbarBackground=offBlack
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=ashGrey
+DSstateControlBackgroundColor_globalHover=ashGrey
+DSstateControlBackgroundColor_hover=raincloudGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
DSwelcomeScreenBackground=ff242424
DSsubPanelBackground=ff1c1c1c
@@ -38,21 +91,21 @@ DSgreenLight=ff5cdc68
DSamberLight=ffffbf00
DSredLight=ffff0401
-DSinteraction=ff2aafd3
+DSinteraction=highlightBlue
DSerrorColor=ffdf3a3a
DSwarningColor=warning
DSdisabledColor=ff707070
DSinteractionHover=ff74cbfc
-DScontrolBackground=ff2e2f30
+DScontrolBackground=dawnGrey
DScontrolBackgroundInteraction=ff3d3d3d
DScontrolBackgroundDisabled=ff2e2f30
DScontrolBackgroundGlobalHover=ff333333
DScontrolBackgroundHover=ff333333
-DScontrolOutline=ff1f1f1f
-DScontrolOutlineInteraction=ff2aafd3
+DScontrolOutline=nearBlack
+DScontrolOutlineInteraction=highlightBlue
DScontrolOutlineDisabled=ff707070
DStextColor=ffffffff
@@ -65,16 +118,16 @@ DSplaceholderTextColorInteraction=ffababab
DSiconColor=ffffffff
DSiconColorHover=ffffffff
-DSiconColorInteraction=ff707070
+DSiconColorInteraction=nearBlack
DSiconColorDisabled=ffC7C7C7
-DSiconColorSelected=ff2aafd3
+DSiconColorSelected=nearBlack
DSlinkIndicatorColor=ff808080
DSlinkIndicatorColorHover=ffffffff
DSlinkIndicatorColorInteraction=ff2aafd3
DSlinkIndicatorColorDisabled=ff707070
-DSpopupBackground=ff474747
+DSpopupBackground=offBlack
DSpopupOverlayColor=99191919
DSsliderActiveTrack=ff7c7b7b
@@ -88,13 +141,13 @@ DSsliderHandleHover=ff606060
DSsliderHandleFocus=ff0492c9
DSsliderHandleInteraction=ff2aafd3
-DSscrollBarTrack=ff3E3E3E
-DSscrollBarHandle=ff4C4C4C
+DSscrollBarTrack=dawnGrey
+DSscrollBarHandle=offBlack
-DSsectionHeadBackground=ff1f1f1f
+DSsectionHeadBackground=midnightGrey
DSstateDefaultHighlight=ffffe400
-DSstateSeparatorColor=ff7c7b7b
+DSstateSeparatorColor=graniteGrey
DSstateBackgroundColor=ff383838
DSstatePreviewOutline=ffaaaaaa
@@ -120,8 +173,8 @@ DSdockContainerSplitter=ff323232
DSdockAreaBackground=ff262728
DSdockWidgetBackground=ff00ff00
-DSdockWidgetSplitter=ff595959
-DSdockWidgetTitleBar=ff1f1f1f
+DSdockWidgetSplitter=fullBlack
+DSdockWidgetTitleBar=dawnGrey
DStitleBarText=ffdadada
DStitleBarIcon=ffffffff
@@ -137,24 +190,24 @@ DStabInactiveIcon=ffffffff
DStabInactiveButtonHover=ff1f1f1f
DStabInactiveButtonPress=ff1f1f1f
-DStabActiveBackground=ffdadada
-DStabActiveText=ff111111
-DStabActiveIcon=ff000000
+DStabActiveBackground=raincloudGrey
+DStabActiveText=offWhite
+DStabActiveIcon=offWhite
DStabActiveButtonHover=ffdadada
DStabActiveButtonPress=ffdadada
-DStabFocusBackground=ff2aafd3
+DStabFocusBackground=highlightBlue
DStabFocusText=ff111111
DStabFocusIcon=ff000000
-DStabFocusButtonHover=ff2aafd3
-DStabFocusButtonPress=ff2aafd3
+DStabFocusButtonHover=highlightBlue
+DStabFocusButtonPress=highlightBlue
DSnavigatorBranch=ff7c7b7b
DSnavigatorBranchIndicator=ff7c7b7b
-DSnavigatorItemBackground=ff2E2F30
-DSnavigatorItemBackgroundHover=ff333333
-DSnavigatorItemBackgroundSelected=ff3D3D3D
-DSnavigatorText=ffffffff
+DSnavigatorItemBackground=dawnGrey
+DSnavigatorItemBackgroundHover=graniteGrey
+DSnavigatorItemBackgroundSelected=midnightGrey
+DSnavigatorText=lightWhite
DSnavigatorTextHover=ffffffff
DSnavigatorTextSelected=ff2aafd3
DSnavigatorIcon=ffffffff
@@ -176,6 +229,8 @@ DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground
DSBackgroundColorNormal=normalBackground
+DStoolbarBackground=midnightGrey
+
;DS controls theme END
BackgroundColorAlternate=alternateBackground
@@ -355,7 +410,7 @@ QmlDesigner_BackgroundColor=qmlDesignerButtonColor
QmlDesigner_HighlightColor=ff1d545c
QmlDesigner_FormEditorSelectionColor=ff4ba2ff
QmlDesigner_FormEditorForegroundColor=ffffffff
-QmlDesigner_BackgroundColorDarkAlternate=ff323232
+QmlDesigner_BackgroundColorDarkAlternate=dawnGrey
QmlDesigner_BackgroundColorDarker=ff262728
QmlDesigner_BorderColor=splitter
QmlDesigner_ButtonColor=ff595b5c
@@ -425,3 +480,4 @@ FlatMenuBar=true
ToolBarIconShadow=true
WindowColorAsBase=false
DarkUserInterface=true
+QDSTheme=false
diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme
index 23c4d97ffb..cbf4b09ce1 100644
--- a/share/qtcreator/themes/flat-light.creatortheme
+++ b/share/qtcreator/themes/flat-light.creatortheme
@@ -21,8 +21,64 @@ error=ffdf4f4f
warning=ffecbc1c
qmlDesignerButtonColor=fff8f8f8
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+concreteGrey=ffbbbbbb
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=offWhite
+DScontrolBackground_toolbarHover=offWhite
+DScontrolBackground_topToolbarHover=concreteGrey
+DScontrolBackground_statusbarIdle=concreteGrey
+DSControlBackground_statusbarHover=lightWhite
+DScontrolOutline_topToolbarIdle=concreteGrey
+DScontrolOutline_topToolbarHover=lightWhite
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=offWhite
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=smokeGrey
+DStextColor=raincloudGrey
+DSstatusbarBackground=concreteGrey
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=concreteGrey
+DSstateControlBackgroundColor_globalHover=concreteGrey
+DSstateControlBackgroundColor_hover=smokeGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
+
DSpanelBackground=ffeaeaea
DSwelcomeScreenBackground=ffEAEAEA
@@ -172,6 +228,8 @@ DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=ffeaeaea
DSBackgroundColorNormal=ffd8d8d8
+DStoolbarBackground=offWhite
+
;DS controls theme END
BackgroundColorAlternate=alternateBackground
@@ -398,3 +456,4 @@ FlatMenuBar=false
ToolBarIconShadow=false
WindowColorAsBase=false
DarkUserInterface=false
+QDSTheme=false
diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme
index a3d04ba9c5..a252562a56 100644
--- a/share/qtcreator/themes/flat.creatortheme
+++ b/share/qtcreator/themes/flat.creatortheme
@@ -19,9 +19,62 @@ warning=ffecbc1c
splitter=ff313131
qmlDesignerButtonColor=ff4c4e50
+;DS Theme Palette START
+;greyscale
+fullWhite=ffffffff
+lightWhite=ffdfdfdf
+offWhite=ffdcdada
+slateGrey=ff8d8d8d
+smokeGrey=ff8b8b8b
+shadowGrey=ff636363
+duskGrey=ff606060
+raincloudGrey=ff4d4d4d
+graniteGrey=ff343434
+ashGrey=ff434343
+midnightGrey=ff333333
+dawnGrey=ff2a2a2a
+offBlack=ff202020
+nearBlack=ff1b1b1b
+fullBlack=ff000000
+
+;special colors
+idleGreen=ff649a5d
+runningGreen=ff2eff68
+successGreen=ff2bcf32
+idleRed=ff6a4242
+recordingRed=ffcc3c34
+errorRed=ffaf2b2b
+warningOrange=ffca8113
+splitterBlue=ff64daff
+rgbBlue=ff64daff
+highlightBlue=ff57b9fc
+highlightHover=ff74CBFC
+;DS Theme Palette END
+
[Colors]
;DS controls theme START
-DSpanelBackground=ff2E2F30
+
+;NEW FOR QtDS 4.0
+DScontrolBackground_toolbarIdle=midnightGrey
+DScontrolBackground_toolbarHover=midnightGrey
+DScontrolBackground_topToolbarHover=ashGrey
+DScontrolBackground_statusbarIdle=offBlack
+DSControlBackground_statusbarHover=dawnGrey
+DScontrolOutline_topToolbarIdle=dawnGrey
+DScontrolOutline_topToolbarHover=raincloudGrey
+DSidleGreen=idleGreen
+DSrunningGreen=runningGreen
+DStoolbarBackground=midnightGrey
+DStoolbarIcon_blocked=shadowGrey
+DSthumbnailBackground_baseState=nearBlack
+DStextColor=lightWhite
+DSstatusbarBackground=offBlack
+DSprimaryButton_hoverHighlight=highlightHover
+DSstateBackgroundColor_hover=ashGrey
+DSstateControlBackgroundColor_globalHover=ashGrey
+DSstateControlBackgroundColor_hover=raincloudGrey
+DSpanelBackground=dawnGrey
+;END NEW FOR QtDS 4.0
DSwelcomeScreenBackground=ff242424
DSsubPanelBackground=ff1c1c1c
@@ -32,21 +85,21 @@ DSgreenLight=ff5cdc68
DSamberLight=ffffbf00
DSredLight=ffff0401
-DSinteraction=ff2aafd3
+DSinteraction=highlightBlue
DSerrorColor=ffdf3a3a
DSwarningColor=warning
DSdisabledColor=ff707070
DSinteractionHover=ff74cbfc
-DScontrolBackground=ff2e2f30
+DScontrolBackground=dawnGrey
DScontrolBackgroundInteraction=ff3d3d3d
DScontrolBackgroundDisabled=ff2e2f30
DScontrolBackgroundGlobalHover=ff333333
DScontrolBackgroundHover=ff333333
-DScontrolOutline=ff1f1f1f
-DScontrolOutlineInteraction=ff2aafd3
+DScontrolOutline=nearBlack
+DScontrolOutlineInteraction=highlightBlue
DScontrolOutlineDisabled=ff707070
DStextColor=ffffffff
@@ -59,16 +112,16 @@ DSplaceholderTextColorInteraction=ffababab
DSiconColor=ffffffff
DSiconColorHover=ffffffff
-DSiconColorInteraction=ff707070
+DSiconColorInteraction=nearBlack
DSiconColorDisabled=ffC7C7C7
-DSiconColorSelected=ff2aafd3
+DSiconColorSelected=nearBlack
DSlinkIndicatorColor=ff808080
DSlinkIndicatorColorHover=ffffffff
DSlinkIndicatorColorInteraction=ff2aafd3
DSlinkIndicatorColorDisabled=ff707070
-DSpopupBackground=ff474747
+DSpopupBackground=offBlack
DSpopupOverlayColor=99191919
DSsliderActiveTrack=ff7c7b7b
@@ -82,13 +135,13 @@ DSsliderHandleHover=ff606060
DSsliderHandleFocus=ff0492c9
DSsliderHandleInteraction=ff2aafd3
-DSscrollBarTrack=ff3E3E3E
-DSscrollBarHandle=ff4C4C4C
+DSscrollBarTrack=dawnGrey
+DSscrollBarHandle=offBlack
-DSsectionHeadBackground=ff1f1f1f
+DSsectionHeadBackground=midnightGrey
DSstateDefaultHighlight=ffffe400
-DSstateSeparatorColor=ff7c7b7b
+DSstateSeparatorColor=graniteGrey
DSstateBackgroundColor=ff383838
DSstatePreviewOutline=ffaaaaaa
@@ -114,8 +167,8 @@ DSdockContainerSplitter=ff323232
DSdockAreaBackground=ff262728
DSdockWidgetBackground=ff00ff00
-DSdockWidgetSplitter=ff595959
-DSdockWidgetTitleBar=ff1f1f1f
+DSdockWidgetSplitter=fullBlack
+DSdockWidgetTitleBar=dawnGrey
DStitleBarText=ffdadada
DStitleBarIcon=ffffffff
@@ -131,24 +184,24 @@ DStabInactiveIcon=ffffffff
DStabInactiveButtonHover=ff1f1f1f
DStabInactiveButtonPress=ff1f1f1f
-DStabActiveBackground=ffdadada
-DStabActiveText=ff111111
-DStabActiveIcon=ff000000
+DStabActiveBackground=raincloudGrey
+DStabActiveText=offWhite
+DStabActiveIcon=offWhite
DStabActiveButtonHover=ffdadada
DStabActiveButtonPress=ffdadada
-DStabFocusBackground=ff2aafd3
+DStabFocusBackground=highlightBlue
DStabFocusText=ff111111
DStabFocusIcon=ff000000
-DStabFocusButtonHover=ff2aafd3
-DStabFocusButtonPress=ff2aafd3
+DStabFocusButtonHover=highlightBlue
+DStabFocusButtonPress=highlightBlue
DSnavigatorBranch=ff7c7b7b
DSnavigatorBranchIndicator=ff7c7b7b
-DSnavigatorItemBackground=ff2E2F30
-DSnavigatorItemBackgroundHover=ff333333
-DSnavigatorItemBackgroundSelected=ff3D3D3D
-DSnavigatorText=ffffffff
+DSnavigatorItemBackground=dawnGrey
+DSnavigatorItemBackgroundHover=graniteGrey
+DSnavigatorItemBackgroundSelected=midnightGrey
+DSnavigatorText=lightWhite
DSnavigatorTextHover=ffffffff
DSnavigatorTextSelected=ff2aafd3
DSnavigatorIcon=ffffffff
@@ -170,6 +223,8 @@ DSUnimportedModuleColor=ffe33c2e
DSBackgroundColorAlternate=alternateBackground
DSBackgroundColorNormal=normalBackground
+DStoolbarBackground=midnightGrey
+
;DS controls theme END
BackgroundColorAlternate=alternateBackground
@@ -349,7 +404,7 @@ QmlDesigner_BackgroundColor=qmlDesignerButtonColor
QmlDesigner_HighlightColor=ff46a2da
QmlDesigner_FormEditorSelectionColor=ff4ba2ff
QmlDesigner_FormEditorForegroundColor=ffffffff
-QmlDesigner_BackgroundColorDarkAlternate=ff323232
+QmlDesigner_BackgroundColorDarkAlternate=dawnGrey
QmlDesigner_BackgroundColorDarker=ff262728
QmlDesigner_BorderColor=splitter
QmlDesigner_ButtonColor=ff595b5c
@@ -396,3 +451,4 @@ FlatMenuBar=false
ToolBarIconShadow=true
WindowColorAsBase=false
DarkUserInterface=false
+QDSTheme=false
diff --git a/src/app/main.cpp b/src/app/main.cpp
index bda27b5e82..b0ca009b8c 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -425,13 +425,26 @@ QStringList lastSessionArgument()
return hasProjectExplorer ? QStringList({"-lastsession"}) : QStringList();
}
+// should be in sync with src/plugins/coreplugin/icore.cpp -> FilePath ICore::crashReportsPath()
+// and src\tools\qml2puppet\qml2puppet\qmlpuppet.cpp -> QString crashReportsPath()
+QString crashReportsPath()
+{
+ std::unique_ptr<QSettings> settings(createUserSettings());
+ QFileInfo(settings->fileName()).path() + "/crashpad_reports";
+ if (Utils::HostOsInfo::isMacHost())
+ return QFileInfo(createUserSettings()->fileName()).path() + "/crashpad_reports";
+ else
+ return QCoreApplication::applicationDirPath()
+ + '/' + RELATIVE_LIBEXEC_PATH + "crashpad_reports";
+}
+
#ifdef ENABLE_CRASHPAD
bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled)
{
using namespace crashpad;
// Cache directory that will store crashpad information and minidumps
- QString databasePath = QDir::cleanPath(libexecPath + "/crashpad_reports");
+ QString databasePath = QDir::cleanPath(crashReportsPath());
QString handlerPath = QDir::cleanPath(libexecPath + "/crashpad_handler");
#ifdef Q_OS_WIN
handlerPath += ".exe";
@@ -453,6 +466,9 @@ bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled)
std::map<std::string, std::string> annotations;
annotations["app-version"] = Core::Constants::IDE_VERSION_DISPLAY;
annotations["qt-version"] = QT_VERSION_STR;
+#ifdef IDE_REVISION
+ annotations["sha1"] = Core::Constants::IDE_REVISION_STR;
+#endif
// Optional arguments to pass to the handler
std::vector<std::string> arguments;
diff --git a/src/libs/3rdparty/sqlite/carray.c b/src/libs/3rdparty/sqlite/carray.c
index b6eb0453a0..709c894f27 100644
--- a/src/libs/3rdparty/sqlite/carray.c
+++ b/src/libs/3rdparty/sqlite/carray.c
@@ -28,7 +28,7 @@
**
** There is an optional third parameter to determine the datatype of
** the C-language array. Allowed values of the third parameter are
-** 'int32', 'int64', 'double', 'char*'. Example:
+** 'int32', 'int64', 'double', 'char*', 'struct iovec'. Example:
**
** SELECT * FROM carray($ptr,10,'char*');
**
@@ -56,6 +56,14 @@
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
+#ifdef _WIN32
+ struct iovec {
+ void *iov_base;
+ size_t iov_len;
+ };
+#else
+# include <sys/uio.h>
+#endif
/* Allowed values for the mFlags parameter to sqlite3_carray_bind().
** Must exactly match the definitions in carray.h.
@@ -65,6 +73,7 @@ SQLITE_EXTENSION_INIT1
# define CARRAY_INT64 1 /* Data is 64-bit signed integers */
# define CARRAY_DOUBLE 2 /* Data is doubles */
# define CARRAY_TEXT 3 /* Data is char* */
+# define CARRAY_BLOB 4 /* Data is struct iovec* */
#endif
#ifndef SQLITE_API
@@ -80,7 +89,8 @@ SQLITE_EXTENSION_INIT1
/*
** Names of allowed datatypes
*/
-static const char *azType[] = { "int32", "int64", "double", "char*" };
+static const char *azType[] = { "int32", "int64", "double", "char*",
+ "struct iovec" };
/*
** Structure used to hold the sqlite3_carray_bind() information
@@ -224,6 +234,12 @@ static int carrayColumn(
sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT);
return SQLITE_OK;
}
+ case CARRAY_BLOB: {
+ const struct iovec *p = (struct iovec*)pCur->pPtr;
+ sqlite3_result_blob(ctx, p[pCur->iRowid-1].iov_base,
+ (int)p[pCur->iRowid-1].iov_len, SQLITE_TRANSIENT);
+ return SQLITE_OK;
+ }
}
}
}
@@ -268,7 +284,7 @@ static int carrayFilter(
if( pBind==0 ) break;
pCur->pPtr = pBind->aData;
pCur->iCnt = pBind->nData;
- pCur->eType = pBind->mFlags & 0x03;
+ pCur->eType = pBind->mFlags & 0x07;
break;
}
case 2:
@@ -431,24 +447,29 @@ SQLITE_API int sqlite3_carray_bind(
pNew->mFlags = mFlags;
if( xDestroy==SQLITE_TRANSIENT ){
sqlite3_int64 sz = nData;
- switch( mFlags & 0x03 ){
- case CARRAY_INT32: sz *= 4; break;
- case CARRAY_INT64: sz *= 8; break;
- case CARRAY_DOUBLE: sz *= 8; break;
- case CARRAY_TEXT: sz *= sizeof(char*); break;
+ switch( mFlags & 0x07 ){
+ case CARRAY_INT32: sz *= 4; break;
+ case CARRAY_INT64: sz *= 8; break;
+ case CARRAY_DOUBLE: sz *= 8; break;
+ case CARRAY_TEXT: sz *= sizeof(char*); break;
+ case CARRAY_BLOB: sz *= sizeof(struct iovec); break;
}
- if( (mFlags & 0x03)==CARRAY_TEXT ){
+ if( (mFlags & 0x07)==CARRAY_TEXT ){
for(i=0; i<nData; i++){
const char *z = ((char**)aData)[i];
if( z ) sz += strlen(z) + 1;
}
+ }else if( (mFlags & 0x07)==CARRAY_BLOB ){
+ for(i=0; i<nData; i++){
+ sz += ((struct iovec*)aData)[i].iov_len;
+ }
}
pNew->aData = sqlite3_malloc64( sz );
if( pNew->aData==0 ){
sqlite3_free(pNew);
return SQLITE_NOMEM;
}
- if( (mFlags & 0x03)==CARRAY_TEXT ){
+ if( (mFlags & 0x07)==CARRAY_TEXT ){
char **az = (char**)pNew->aData;
char *z = (char*)&az[nData];
for(i=0; i<nData; i++){
@@ -463,6 +484,16 @@ SQLITE_API int sqlite3_carray_bind(
memcpy(z, zData, n+1);
z += n+1;
}
+ }else if( (mFlags & 0x07)==CARRAY_BLOB ){
+ struct iovec *p = (struct iovec*)pNew->aData;
+ unsigned char *z = (unsigned char*)&p[nData];
+ for(i=0; i<nData; i++){
+ size_t n = ((struct iovec*)aData)[i].iov_len;
+ p[i].iov_len = n;
+ p[i].iov_base = z;
+ z += n;
+ memcpy(p[i].iov_base, ((struct iovec*)aData)[i].iov_base, n);
+ }
}else{
memcpy(pNew->aData, aData, sz);
}
diff --git a/src/libs/3rdparty/sqlite/sqlite3.c b/src/libs/3rdparty/sqlite/sqlite3.c
index b8f98c7c1e..b47891c381 100644
--- a/src/libs/3rdparty/sqlite/sqlite3.c
+++ b/src/libs/3rdparty/sqlite/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.39.2. By combining all the individual C code files into this
+** version 3.41.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -452,9 +452,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.2"
-#define SQLITE_VERSION_NUMBER 3039002
-#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603"
+#define SQLITE_VERSION "3.41.0"
+#define SQLITE_VERSION_NUMBER 3041000
+#define SQLITE_SOURCE_ID "2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -869,6 +869,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
@@ -976,13 +977,17 @@ SQLITE_API int sqlite3_exec(
**
** SQLite uses one of these integer values as the second
** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlite3_io_methods] object.
+** of an [sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -1060,7 +1065,14 @@ struct sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+* If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file. It returns true
@@ -1165,9 +1177,8 @@ struct sqlite3_io_methods {
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1471,7 +1482,6 @@ struct sqlite3_io_methods {
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
-** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
@@ -1484,10 +1494,16 @@ struct sqlite3_io_methods {
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
-** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** Used by the cksmvfs VFS module only.
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** [checksum VFS shim] only.
+**
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
+** If there is currently no transaction open on the database, and the
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
+** purges the contents of the in-memory page cache. If there is an open
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1530,6 +1546,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
+#define SQLITE_FCNTL_RESET_CACHE 42
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1560,6 +1577,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlite3_filename_database()
+** <li> sqlite3_filename_journal()
+** <li> sqlite3_filename_wal()
+** <li> sqlite3_uri_parameter()
+** <li> sqlite3_uri_boolean()
+** <li> sqlite3_uri_int64()
+** <li> sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1737,7 +1774,7 @@ struct sqlite3_vfs {
sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
+ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
@@ -2453,7 +2490,7 @@ struct sqlite3_mem_methods {
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
** when the "current value" returned by
-** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
@@ -2603,8 +2640,12 @@ struct sqlite3_mem_methods {
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
-** process requires the use of this obscure API and multiple steps to help
-** ensure that it does not happen by accident.
+** process requires the use of this obscure API and multiple steps to
+** help ensure that it does not happen by accident. Because this
+** feature must be capable of resetting corrupt databases, and
+** shutting down virtual tables may require access to that corrupt
+** storage, the library must abandon any installed virtual tables
+** without calling their xDestroy() methods.
**
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
@@ -2615,6 +2656,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -2942,8 +2984,12 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
+**
+** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
+** or not an interrupt is currently in effect for [database connection] D.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API int sqlite3_is_interrupted(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -3561,8 +3607,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
** information as is provided by the [sqlite3_profile()] callback.
** ^The P argument is a pointer to the [prepared statement] and the
-** X argument points to a 64-bit integer which is the estimated of
-** the number of nanosecond that the prepared statement took to run.
+** X argument points to a 64-bit integer which is approximately
+** the number of nanoseconds that the prepared statement took to run.
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
@@ -3625,7 +3671,7 @@ SQLITE_API int sqlite3_trace_v2(
**
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
-** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
+** [sqlite3_step()] and [sqlite3_prepare()] and similar for
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
@@ -3650,6 +3696,13 @@ SQLITE_API int sqlite3_trace_v2(
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
** database connections for the meaning of "modify" in this paragraph.
**
+** The progress handler callback would originally only be invoked from the
+** bytecode engine. It still might be invoked during [sqlite3_prepare()]
+** and similar because those routines might force a reparse of the schema
+** which involves running the bytecode engine. However, beginning with
+** SQLite version 3.41.0, the progress handler callback might also be
+** invoked directly from [sqlite3_prepare()] while analyzing and generating
+** code for complex queries.
*/
SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
@@ -3686,13 +3739,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
-** <dd>The database is opened in read-only mode. If the database does not
-** already exist, an error is returned.</dd>)^
+** <dd>The database is opened in read-only mode. If the database does
+** not already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
-** <dd>The database is opened for reading and writing if possible, or reading
-** only if the file is write protected by the operating system. In either
-** case the database must already exist, otherwise an error is returned.</dd>)^
+** <dd>The database is opened for reading and writing if possible, or
+** reading only if the file is write protected by the operating
+** system. In either case the database must already exist, otherwise
+** an error is returned. For historical reasons, if opening in
+** read-write mode fails due to OS-level permissions, an attempt is
+** made to open it in read-only mode. [sqlite3_db_readonly()] can be
+** used to determine whether the database is actually
+** read-write.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
@@ -3730,6 +3788,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3745,7 +3806,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
@@ -4004,10 +4065,10 @@ SQLITE_API int sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -4036,9 +4097,9 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -4104,14 +4165,14 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API sqlite3_filename sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlite3_free_filename(char*);
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -5670,10 +5731,21 @@ SQLITE_API int sqlite3_create_window_function(
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
-** for all [application-defined SQL functions], and especially for functions
-** that have side-effects or that could potentially leak sensitive
-** information.
+** <p>
+** The SQLITE_DIRECTONLY flag is recommended for any
+** [application-defined SQL function]
+** that has side-effects or that could potentially leak sensitive information.
+** This will prevent attacks in which an application is tricked
+** into using a database file that has had its schema surreptiously
+** modified to invoke the application-defined function in ways that are
+** harmful.
+** <p>
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
+** [application-defined SQL functions], regardless of whether or not they
+** are security sensitive, as doing so prevents those functions from being used
+** inside of the database schema, and thus ensures that the database
+** can be inspected and modified using generic tools (such as the [CLI])
+** that do not have access to the application-defined functions.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
@@ -5880,6 +5952,28 @@ SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
/*
+** CAPI3REF: Report the internal text encoding state of an sqlite3_value object
+** METHOD: sqlite3_value
+**
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
+** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
+** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
+** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
+**
+** This routine is intended for used by applications that test and validate
+** the SQLite implementation. This routine is inquiring about the opaque
+** internal state of an [sqlite3_value] object. Ordinary applications should
+** not need to know what the internal state of an sqlite3_value object is and
+** hence should not need to use this interface.
+*/
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
+
+/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlite3_value
**
@@ -5931,7 +6025,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
@@ -6136,9 +6230,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlite3_result_text* interfaces.
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
+** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces
+** other than sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for the first
+** zero character.
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
** is non-negative, then as many bytes (not characters) of the text
** pointed to by the 2nd parameter are taken as the application-defined
@@ -6634,7 +6729,7 @@ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
** <li> [sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6771,7 +6866,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6892,6 +6987,11 @@ SQLITE_API void *sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -6990,7 +7090,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -7252,15 +7352,6 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** Structures used by the virtual table interface
*/
typedef struct sqlite3_vtab sqlite3_vtab;
@@ -7378,10 +7469,10 @@ struct sqlite3_module {
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
-** ^The idxNum and idxPtr values are recorded and passed into the
+** ^The idxNum and idxStr values are recorded and passed into the
** [xFilter] method.
-** ^[sqlite3_free()] is used to free idxPtr if and only if
-** needToFreeIdxPtr is true.
+** ^[sqlite3_free()] is used to free idxStr if and only if
+** needToFreeIdxStr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
@@ -7501,7 +7592,7 @@ struct sqlite3_index_info {
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
** tables, the collating sequence of constraints does not matter (for example
** because the constraints are numeric) and so the sqlite3_vtab_collation()
-** interface is no commonly needed.
+** interface is not commonly needed.
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
@@ -7661,16 +7752,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
**
@@ -9285,7 +9366,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** if the application incorrectly accesses the destination [database connection]
** and so no error code is reported, but the operations may malfunction
** nevertheless. Use of the destination database connection while a
-** backup is in progress might also also cause a mutex deadlock.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9713,7 +9794,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
@@ -9873,7 +9954,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
** <li><p> Otherwise, "BINARY" is returned.
** </ol>
*/
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
+SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
/*
** CAPI3REF: Determine if a virtual table query is DISTINCT
@@ -10030,21 +10111,20 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
** is undefined and probably harmful.
**
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
-** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
+** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
-** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
-** exhibit some other undefined or harmful behavior.
+** processing, then these routines return [SQLITE_ERROR].)^
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** &nbsp; for(rc=sqlite3_vtab_in_first(pList, &pVal);
-** &nbsp; rc==SQLITE_OK && pVal
+** &nbsp; rc==SQLITE_OK && pVal;
** &nbsp; rc=sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
@@ -10142,6 +10222,10 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
+** Not all values are available for all query elements. When a value is
+** not available, the output variable is set to -1 if the value is numeric,
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
+**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
@@ -10169,12 +10253,24 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
-** "select-id" for the X-th loop. The select-id identifies which query or
-** subquery the loop is part of. The main query has a select-id of zero.
-** The select-id is the same value as is output in the first column
-** of an [EXPLAIN QUERY PLAN] query.
+** id for the X-th query plan element. The id value is unique within the
+** statement. The select-id is the same value as is output in the first
+** column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
+** <dd>The "int" variable pointed to by the V parameter will be set to the
+** the id of the parent of the current query element, if applicable, or
+** to zero if the query element has no parent. This is the same value as
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
+** <dd>The sqlite3_int64 output value is set to the number of cycles,
+** according to the processor time-stamp counter, that elapsed while the
+** query element was being processed. This value is not available for
+** all query elements - if it is unavailable the output variable is
+** set to -1.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP 0
@@ -10183,12 +10279,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
+#define SQLITE_SCANSTAT_PARENTID 6
+#define SQLITE_SCANSTAT_NCYCLE 7
/*
** CAPI3REF: Prepared Statement Scan Status
** METHOD: sqlite3_stmt
**
-** This interface returns information about the predicted and measured
+** These interfaces return information about the predicted and measured
** performance for pStmt. Advanced applications can use this
** interface to compare the predicted and the measured performance and
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
@@ -10199,19 +10297,25 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
-** of this interface is undefined.
-** ^The requested measurement is written into a variable pointed to by
-** the "pOut" parameter.
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
-** Loops are numbered starting from zero. ^If idx is out of range - less than
-** zero or greater than or equal to the total number of loops used to implement
-** the statement - a non-zero value is returned and the variable that pOut
-** points to is unchanged.
-**
-** ^Statistics might not be available for all loops in all statements. ^In cases
-** where there exist loops with no available statistics, this function behaves
-** as if the loop did not exist - it returns non-zero and leave the variable
-** that pOut points to unchanged.
+** of this interface is undefined. ^The requested measurement is written into
+** a variable pointed to by the "pOut" parameter.
+**
+** The "flags" parameter must be passed a mask of flags. At present only
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
+** is specified, then status information is available for all elements
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
+** sqlite3_stmt_scanstatus() is equivalent to calling
+** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
+**
+** Parameter "idx" identifies the specific query element to retrieve statistics
+** for. Query elements are numbered starting from zero. A value of -1 may be
+** to query for statistics regarding the entire query. ^If idx is out of range
+** - less than -1 or greater than or equal to the total number of query
+** elements used to implement the statement - a non-zero value is returned and
+** the variable that pOut points to is unchanged.
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
@@ -10221,6 +10325,19 @@ SQLITE_API int sqlite3_stmt_scanstatus(
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
);
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ int flags, /* Mask of flags defined below */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** KEYWORDS: {scan status flags}
+*/
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -10311,6 +10428,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** function is not defined for operations on WITHOUT ROWID tables, or for
** DELETE operations on rowid tables.
**
+** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from
+** the previous call on the same [database connection] D, or NULL for
+** the first call on D.
+**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
** provide additional information about a preupdate event. These routines
@@ -10716,6 +10837,19 @@ SQLITE_API int sqlite3_deserialize(
# undef double
#endif
+#if defined(__wasi__)
+# undef SQLITE_WASI
+# define SQLITE_WASI 1
+# undef SQLITE_OMIT_WAL
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION
+# endif
+# ifndef SQLITE_THREADSAFE
+# define SQLITE_THREADSAFE 0
+# endif
+#endif
+
#if 0
} /* End of the 'extern "C"' block */
#endif
@@ -13145,11 +13279,16 @@ struct fts5_api {
/************** Continuing where we left off in sqliteInt.h ******************/
/*
+** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory.
+*/
+#define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1
+
+/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-#include "config.h"
+#include "sqlite_cfg.h"
#define SQLITECONFIG_H 1
#endif
@@ -14262,15 +14401,9 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
/*
** The datatype used to store estimates of the number of rows in a
-** table or index. This is an unsigned integer type. For 99.9% of
-** the world, a 32-bit integer is sufficient. But a 64-bit integer
-** can be used at compile-time if desired.
+** table or index.
*/
-#ifdef SQLITE_64BIT_STATS
- typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
-#else
- typedef u32 tRowcnt; /* 32-bit is the default */
-#endif
+typedef u64 tRowcnt;
/*
** Estimated quantities used for query planning are stored as 16-bit
@@ -14416,9 +14549,9 @@ typedef INT16_TYPE LogEst;
** pointers. In that case, only verify 4-byte alignment.
*/
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0)
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
#else
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
#endif
/*
@@ -14472,15 +14605,38 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace;
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \
|| defined(SQLITE_ENABLE_TREETRACE))
# define TREETRACE_ENABLED 1
-# define SELECTTRACE(K,P,S,X) \
+# define TREETRACE(K,P,S,X) \
if(sqlite3TreeTrace&(K)) \
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
sqlite3DebugPrintf X
#else
-# define SELECTTRACE(K,P,S,X)
+# define TREETRACE(K,P,S,X)
# define TREETRACE_ENABLED 0
#endif
+/* TREETRACE flag meanings:
+**
+** 0x00000001 Beginning and end of SELECT processing
+** 0x00000002 WHERE clause processing
+** 0x00000004 Query flattener
+** 0x00000008 Result-set wildcard expansion
+** 0x00000010 Query name resolution
+** 0x00000020 Aggregate analysis
+** 0x00000040 Window functions
+** 0x00000080 Generated column names
+** 0x00000100 Move HAVING terms into WHERE
+** 0x00000200 Count-of-view optimization
+** 0x00000400 Compound SELECT processing
+** 0x00000800 Drop superfluous ORDER BY
+** 0x00001000 LEFT JOIN simplifies to JOIN
+** 0x00002000 Constant propagation
+** 0x00004000 Push-down optimization
+** 0x00008000 After all FROM-clause analysis
+** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
+** 0x00020000 Transform DISTINCT into GROUP BY
+** 0x00040000 SELECT tree dump after all code has been generated
+*/
+
/*
** Macros for "wheretrace"
*/
@@ -14493,6 +14649,36 @@ SQLITE_PRIVATE u32 sqlite3WhereTrace;
# define WHERETRACE(K,X)
#endif
+/*
+** Bits for the sqlite3WhereTrace mask:
+**
+** (---any--) Top-level block structure
+** 0x-------F High-level debug messages
+** 0x----FFF- More detail
+** 0xFFFF---- Low-level debug messages
+**
+** 0x00000001 Code generation
+** 0x00000002 Solver
+** 0x00000004 Solver costs
+** 0x00000008 WhereLoop inserts
+**
+** 0x00000010 Display sqlite3_index_info xBestIndex calls
+** 0x00000020 Range an equality scan metrics
+** 0x00000040 IN operator decisions
+** 0x00000080 WhereLoop cost adjustements
+** 0x00000100
+** 0x00000200 Covering index decisions
+** 0x00000400 OR optimization
+** 0x00000800 Index scanner
+** 0x00001000 More details associated with code generation
+** 0x00002000
+** 0x00004000 Show all WHERE terms at key points
+** 0x00008000 Show the full SELECT statement at key places
+**
+** 0x00010000 Show more detail when printing WHERE terms
+** 0x00020000 Show WHERE terms returned from whereScanNext()
+*/
+
/*
** An instance of the following structure is used to store the busy-handler
@@ -14632,6 +14818,7 @@ typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
typedef struct IdList IdList;
typedef struct Index Index;
+typedef struct IndexedExpr IndexedExpr;
typedef struct IndexSample IndexSample;
typedef struct KeyClass KeyClass;
typedef struct KeyInfo KeyInfo;
@@ -14697,6 +14884,7 @@ typedef struct With With;
#define MASKBIT32(n) (((unsigned int)1)<<(n))
#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
#define ALLBITS ((Bitmask)-1)
+#define TOPBIT (((Bitmask)1)<<(BMS-1))
/* A VList object records a mapping between parameters/variables/wildcards
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
@@ -14711,6 +14899,331 @@ typedef int VList;
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
+/************** Include os.h in the middle of sqliteInt.h ********************/
+/************** Begin file os.h **********************************************/
+/*
+** 2001 September 16
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This header file (together with is companion C source-code file
+** "os.c") attempt to abstract the underlying operating system so that
+** the SQLite library will work on both POSIX and windows systems.
+**
+** This header file is #include-ed by sqliteInt.h and thus ends up
+** being included by every source file.
+*/
+#ifndef _SQLITE_OS_H_
+#define _SQLITE_OS_H_
+
+/*
+** Attempt to automatically detect the operating system and setup the
+** necessary pre-processor macros for it.
+*/
+/************** Include os_setup.h in the middle of os.h *********************/
+/************** Begin file os_setup.h ****************************************/
+/*
+** 2013 November 25
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains pre-processor directives related to operating system
+** detection and/or setup.
+*/
+#ifndef SQLITE_OS_SETUP_H
+#define SQLITE_OS_SETUP_H
+
+/*
+** Figure out if we are dealing with Unix, Windows, or some other operating
+** system.
+**
+** After the following block of preprocess macros, all of
+**
+** SQLITE_OS_KV
+** SQLITE_OS_OTHER
+** SQLITE_OS_UNIX
+** SQLITE_OS_WIN
+**
+** will defined to either 1 or 0. One of them will be 1. The others will be 0.
+** If none of the macros are initially defined, then select either
+** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
+**
+** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
+** must provide its own VFS implementation together with sqlite3_os_init()
+** and sqlite3_os_end() routines.
+*/
+#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
+ !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
+# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
+ defined(__MINGW32__) || defined(__BORLANDC__)
+# define SQLITE_OS_WIN 1
+# define SQLITE_OS_UNIX 0
+# else
+# define SQLITE_OS_WIN 0
+# define SQLITE_OS_UNIX 1
+# endif
+#endif
+#if SQLITE_OS_OTHER+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_KV+1>1
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+# define SQLITE_OMIT_LOAD_EXTENSION 1
+# define SQLITE_OMIT_WAL 1
+# define SQLITE_OMIT_DEPRECATED 1
+# undef SQLITE_TEMP_STORE
+# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
+# define SQLITE_DQS 0
+# define SQLITE_OMIT_SHARED_CACHE 1
+# define SQLITE_OMIT_AUTOINIT 1
+#endif
+#if SQLITE_OS_UNIX+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_WIN
+# define SQLITE_OS_WIN 0
+#endif
+#if SQLITE_OS_WIN+1>1
+# undef SQLITE_OS_KV
+# define SQLITE_OS_KV 0
+# undef SQLITE_OS_OTHER
+# define SQLITE_OS_OTHER 0
+# undef SQLITE_OS_UNIX
+# define SQLITE_OS_UNIX 0
+#endif
+
+
+#endif /* SQLITE_OS_SETUP_H */
+
+/************** End of os_setup.h ********************************************/
+/************** Continuing where we left off in os.h *************************/
+
+/* If the SET_FULLSYNC macro is not defined above, then make it
+** a no-op
+*/
+#ifndef SET_FULLSYNC
+# define SET_FULLSYNC(x,y)
+#endif
+
+/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
+*/
+#ifndef SQLITE_MAX_PATHLEN
+# define SQLITE_MAX_PATHLEN FILENAME_MAX
+#endif
+
+/* Maximum number of symlinks that will be resolved while trying to
+** expand a filename in xFullPathname() in the VFS.
+*/
+#ifndef SQLITE_MAX_SYMLINK
+# define SQLITE_MAX_SYMLINK 200
+#endif
+
+/*
+** The default size of a disk sector
+*/
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 4096
+#endif
+
+/*
+** Temporary files are named starting with this prefix followed by 16 random
+** alphanumeric characters, and no file extension. They are stored in the
+** OS's standard temporary file directory, and are deleted prior to exit.
+** If sqlite is being embedded in another program, you may wish to change the
+** prefix to reflect your program's name, so that if your program exits
+** prematurely, old temporary files can be easily identified. This can be done
+** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
+**
+** 2006-10-31: The default prefix used to be "sqlite_". But then
+** Mcafee started using SQLite in their anti-virus product and it
+** started putting files with the "sqlite" name in the c:/temp folder.
+** This annoyed many windows users. Those users would then do a
+** Google search for "sqlite", find the telephone numbers of the
+** developers and call to wake them up at night and complain.
+** For this reason, the default name prefix is changed to be "sqlite"
+** spelled backwards. So the temp files are still identified, but
+** anybody smart enough to figure out the code is also likely smart
+** enough to know that calling the developer will not help get rid
+** of the file.
+*/
+#ifndef SQLITE_TEMP_FILE_PREFIX
+# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
+#endif
+
+/*
+** The following values may be passed as the second argument to
+** sqlite3OsLock(). The various locks exhibit the following semantics:
+**
+** SHARED: Any number of processes may hold a SHARED lock simultaneously.
+** RESERVED: A single process may hold a RESERVED lock on a file at
+** any time. Other processes may hold and obtain new SHARED locks.
+** PENDING: A single process may hold a PENDING lock on a file at
+** any one time. Existing SHARED locks may persist, but no new
+** SHARED locks may be obtained by other processes.
+** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
+**
+** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
+** process that requests an EXCLUSIVE lock may actually obtain a PENDING
+** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
+** sqlite3OsLock().
+*/
+#define NO_LOCK 0
+#define SHARED_LOCK 1
+#define RESERVED_LOCK 2
+#define PENDING_LOCK 3
+#define EXCLUSIVE_LOCK 4
+
+/*
+** File Locking Notes: (Mostly about windows but also some info for Unix)
+**
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
+** those functions are not available. So we use only LockFile() and
+** UnlockFile().
+**
+** LockFile() prevents not just writing but also reading by other processes.
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
+** byte out of a specific range of bytes. The lock byte is obtained at
+** random so two separate readers can probably access the file at the
+** same time, unless they are unlucky and choose the same lock byte.
+** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
+** There can only be one writer. A RESERVED_LOCK is obtained by locking
+** a single byte of the file that is designated as the reserved lock byte.
+** A PENDING_LOCK is obtained by locking a designated byte different from
+** the RESERVED_LOCK byte.
+**
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
+** which means we can use reader/writer locks. When reader/writer locks
+** are used, the lock is placed on the same range of bytes that is used
+** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
+** will support two or more Win95 readers or two or more WinNT readers.
+** But a single Win95 reader will lock out all WinNT readers and a single
+** WinNT reader will lock out all other Win95 readers.
+**
+** The following #defines specify the range of bytes used for locking.
+** SHARED_SIZE is the number of bytes available in the pool from which
+** a random byte is selected for a shared lock. The pool of bytes for
+** shared locks begins at SHARED_FIRST.
+**
+** The same locking strategy and
+** byte ranges are used for Unix. This leaves open the possibility of having
+** clients on win95, winNT, and unix all talking to the same shared file
+** and all locking correctly. To do so would require that samba (or whatever
+** tool is being used for file sharing) implements locks correctly between
+** windows and unix. I'm guessing that isn't likely to happen, but by
+** using the same locking range we are at least open to the possibility.
+**
+** Locking in windows is manditory. For this reason, we cannot store
+** actual data in the bytes used for locking. The pager never allocates
+** the pages involved in locking therefore. SHARED_SIZE is selected so
+** that all locks will fit on a single page even at the minimum page size.
+** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
+** is set high so that we don't have to allocate an unused page except
+** for very large databases. But one should test the page skipping logic
+** by setting PENDING_BYTE low and running the entire regression suite.
+**
+** Changing the value of PENDING_BYTE results in a subtly incompatible
+** file format. Depending on how it is changed, you might not notice
+** the incompatibility right away, even running a full regression test.
+** The default location of PENDING_BYTE is the first byte past the
+** 1GB boundary.
+**
+*/
+#ifdef SQLITE_OMIT_WSD
+# define PENDING_BYTE (0x40000000)
+#else
+# define PENDING_BYTE sqlite3PendingByte
+#endif
+#define RESERVED_BYTE (PENDING_BYTE+1)
+#define SHARED_FIRST (PENDING_BYTE+2)
+#define SHARED_SIZE 510
+
+/*
+** Wrapper around OS specific sqlite3_os_init() function.
+*/
+SQLITE_PRIVATE int sqlite3OsInit(void);
+
+/*
+** Functions for accessing sqlite3_file methods
+*/
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
+SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
+SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
+SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
+SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
+SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
+SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
+#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
+SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
+#ifndef SQLITE_OMIT_WAL
+SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
+SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
+#endif /* SQLITE_OMIT_WAL */
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
+
+
+/*
+** Functions for accessing sqlite3_vfs methods
+*/
+SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
+SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
+SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
+SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
+SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
+SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
+SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
+
+/*
+** Convenience functions for opening and closing files using
+** sqlite3_malloc() to obtain space for the file-handle structure.
+*/
+SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
+
+#endif /* _SQLITE_OS_H_ */
+
+/************** End of os.h **************************************************/
+/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include pager.h in the middle of sqliteInt.h *****************/
/************** Begin file pager.h *******************************************/
/*
@@ -15146,7 +15659,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
** reduce network bandwidth.
**
** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
-** standard SQLite. The other hints are provided for extentions that use
+** standard SQLite. The other hints are provided for extensions that use
** the SQLite parser and code generator but substitute their own storage
** engine.
*/
@@ -15292,7 +15805,15 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,Pgno*aRoot,int nRoot,int,int*);
+SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
+ sqlite3 *db, /* Database connection that is running the check */
+ Btree *p, /* The btree to be checked */
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
+ int nRoot, /* Number of entries in aRoot[] */
+ int mxErr, /* Stop reporting errors after this many */
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
+ char **pzOut /* OUT: Write the error message string here */
+);
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
@@ -15331,6 +15852,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
+SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree*);
+
/*
** If we are not using shared cache, then there is no need to
** use mutexes to access the BtShared structures. So make the
@@ -15447,14 +15970,14 @@ struct VdbeOp {
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
char *zComment; /* Comment to improve readability */
#endif
-#ifdef VDBE_PROFILE
- u32 cnt; /* Number of times this instruction was executed */
- u64 cycles; /* Total time spent executing this instruction */
-#endif
#ifdef SQLITE_VDBE_COVERAGE
u32 iSrcLine; /* Source-code line that generated this opcode
** with flags in the upper 8 bits */
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ u64 nExec;
+ u64 nCycle;
+#endif
};
typedef struct VdbeOp VdbeOp;
@@ -15555,48 +16078,48 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Vacuum 5
#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
-#define OP_Goto 8 /* jump */
-#define OP_Gosub 9 /* jump */
-#define OP_InitCoroutine 10 /* jump */
-#define OP_Yield 11 /* jump */
-#define OP_MustBeInt 12 /* jump */
-#define OP_Jump 13 /* jump */
-#define OP_Once 14 /* jump */
-#define OP_If 15 /* jump */
-#define OP_IfNot 16 /* jump */
-#define OP_IsNullOrType 17 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */
-#define OP_IfNullRow 18 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_Init 8 /* jump, synopsis: Start at P2 */
+#define OP_Goto 9 /* jump */
+#define OP_Gosub 10 /* jump */
+#define OP_InitCoroutine 11 /* jump */
+#define OP_Yield 12 /* jump */
+#define OP_MustBeInt 13 /* jump */
+#define OP_Jump 14 /* jump */
+#define OP_Once 15 /* jump */
+#define OP_If 16 /* jump */
+#define OP_IfNot 17 /* jump */
+#define OP_IsType 18 /* jump, synopsis: if typeof(P1.P3) in P5 goto P2 */
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_SeekLT 20 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekLE 21 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGE 22 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekGT 23 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IfNotOpen 24 /* jump, synopsis: if( !csr[P1] ) goto P2 */
-#define OP_IfNoHope 25 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NoConflict 26 /* jump, synopsis: key=r[P3@P4] */
-#define OP_NotFound 27 /* jump, synopsis: key=r[P3@P4] */
-#define OP_Found 28 /* jump, synopsis: key=r[P3@P4] */
-#define OP_SeekRowid 29 /* jump, synopsis: intkey=r[P3] */
-#define OP_NotExists 30 /* jump, synopsis: intkey=r[P3] */
-#define OP_Last 31 /* jump */
-#define OP_IfSmaller 32 /* jump */
-#define OP_SorterSort 33 /* jump */
-#define OP_Sort 34 /* jump */
-#define OP_Rewind 35 /* jump */
-#define OP_SorterNext 36 /* jump */
-#define OP_Prev 37 /* jump */
-#define OP_Next 38 /* jump */
-#define OP_IdxLE 39 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGT 40 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxLT 41 /* jump, synopsis: key=r[P3@P4] */
-#define OP_IdxGE 42 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
+#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
+#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
+#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
+#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */
+#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
+#define OP_Last 32 /* jump */
+#define OP_IfSmaller 33 /* jump */
+#define OP_SorterSort 34 /* jump */
+#define OP_Sort 35 /* jump */
+#define OP_Rewind 36 /* jump */
+#define OP_SorterNext 37 /* jump */
+#define OP_Prev 38 /* jump */
+#define OP_Next 39 /* jump */
+#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */
+#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_RowSetRead 45 /* jump, synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 47 /* jump */
-#define OP_FkIfZero 48 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_IfPos 49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 48 /* jump */
+#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
@@ -15606,12 +16129,12 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
-#define OP_IfNotZero 59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
-#define OP_DecrJumpZero 60 /* jump, synopsis: if (--r[P1])==0 goto P2 */
-#define OP_IncrVacuum 61 /* jump */
-#define OP_VNext 62 /* jump */
-#define OP_Filter 63 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
-#define OP_Init 64 /* jump, synopsis: Start at P2 */
+#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 62 /* jump */
+#define OP_VNext 63 /* jump */
+#define OP_Filter 64 /* jump, synopsis: if key(P3@P4) not in filter(P1) goto P2 */
#define OP_PureFunc 65 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */
#define OP_Return 67
@@ -15745,29 +16268,30 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_IN3 0x08 /* in3: P3 is an input */
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
+#define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */
#define OPFLG_INITIALIZER {\
-/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00,\
-/* 8 */ 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, 0x03,\
-/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x09, 0x09, 0x09, 0x09,\
-/* 24 */ 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01,\
-/* 32 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\
-/* 48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\
+/* 0 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x41, 0x00,\
+/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\
+/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\
+/* 32 */ 0x41, 0x01, 0x01, 0x01, 0x41, 0x01, 0x41, 0x41,\
+/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
+/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
+/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\
/* 64 */ 0x01, 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10,\
/* 72 */ 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, 0x00,\
/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x02, 0x02,\
-/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00,\
-/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x26, 0x26,\
+/* 88 */ 0x02, 0x00, 0x00, 0x12, 0x1e, 0x20, 0x40, 0x00,\
+/* 96 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
-/* 112 */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00,\
-/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
-/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
-/* 136 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
+/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
+/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,\
+/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\
+/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x40,\
/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
/* 184 */ 0x00, 0x00, 0x00,}
@@ -15822,14 +16346,20 @@ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int);
#endif
SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#ifndef SQLITE_OMIT_EXPLAIN
-SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...);
+SQLITE_PRIVATE int sqlite3VdbeExplain(Parse*,u8,const char*,...);
SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*);
SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*);
# define ExplainQueryPlan(P) sqlite3VdbeExplain P
+# ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define ExplainQueryPlan2(V,P) (V = sqlite3VdbeExplain P)
+# else
+# define ExplainQueryPlan2(V,P) ExplainQueryPlan(P)
+# endif
# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P)
# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P)
#else
# define ExplainQueryPlan(P)
+# define ExplainQueryPlan2(V,P)
# define ExplainQueryPlanPop(P)
# define ExplainQueryPlanParent(P) 0
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
@@ -15845,6 +16375,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe*, int);
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
@@ -15859,6 +16390,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe*);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
@@ -16000,8 +16532,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
+SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(Vdbe*, int, int, int);
+SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
#else
-# define sqlite3VdbeScanStatus(a,b,c,d,e)
+# define sqlite3VdbeScanStatus(a,b,c,d,e,f)
+# define sqlite3VdbeScanStatusRange(a,b,c,d)
+# define sqlite3VdbeScanStatusCounters(a,b,c,d)
#endif
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@@ -16207,297 +16743,6 @@ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache);
/************** End of pcache.h **********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
-/************** Include os.h in the middle of sqliteInt.h ********************/
-/************** Begin file os.h **********************************************/
-/*
-** 2001 September 16
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This header file (together with is companion C source-code file
-** "os.c") attempt to abstract the underlying operating system so that
-** the SQLite library will work on both POSIX and windows systems.
-**
-** This header file is #include-ed by sqliteInt.h and thus ends up
-** being included by every source file.
-*/
-#ifndef _SQLITE_OS_H_
-#define _SQLITE_OS_H_
-
-/*
-** Attempt to automatically detect the operating system and setup the
-** necessary pre-processor macros for it.
-*/
-/************** Include os_setup.h in the middle of os.h *********************/
-/************** Begin file os_setup.h ****************************************/
-/*
-** 2013 November 25
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains pre-processor directives related to operating system
-** detection and/or setup.
-*/
-#ifndef SQLITE_OS_SETUP_H
-#define SQLITE_OS_SETUP_H
-
-/*
-** Figure out if we are dealing with Unix, Windows, or some other operating
-** system.
-**
-** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
-** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
-** the three will be 1. The other two will be 0.
-*/
-#if defined(SQLITE_OS_OTHER)
-# if SQLITE_OS_OTHER==1
-# undef SQLITE_OS_UNIX
-# define SQLITE_OS_UNIX 0
-# undef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# else
-# undef SQLITE_OS_OTHER
-# endif
-#endif
-#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
-# define SQLITE_OS_OTHER 0
-# ifndef SQLITE_OS_WIN
-# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
- defined(__MINGW32__) || defined(__BORLANDC__)
-# define SQLITE_OS_WIN 1
-# define SQLITE_OS_UNIX 0
-# else
-# define SQLITE_OS_WIN 0
-# define SQLITE_OS_UNIX 1
-# endif
-# else
-# define SQLITE_OS_UNIX 0
-# endif
-#else
-# ifndef SQLITE_OS_WIN
-# define SQLITE_OS_WIN 0
-# endif
-#endif
-
-#endif /* SQLITE_OS_SETUP_H */
-
-/************** End of os_setup.h ********************************************/
-/************** Continuing where we left off in os.h *************************/
-
-/* If the SET_FULLSYNC macro is not defined above, then make it
-** a no-op
-*/
-#ifndef SET_FULLSYNC
-# define SET_FULLSYNC(x,y)
-#endif
-
-/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
-*/
-#ifndef SQLITE_MAX_PATHLEN
-# define SQLITE_MAX_PATHLEN FILENAME_MAX
-#endif
-
-/* Maximum number of symlinks that will be resolved while trying to
-** expand a filename in xFullPathname() in the VFS.
-*/
-#ifndef SQLITE_MAX_SYMLINK
-# define SQLITE_MAX_SYMLINK 200
-#endif
-
-/*
-** The default size of a disk sector
-*/
-#ifndef SQLITE_DEFAULT_SECTOR_SIZE
-# define SQLITE_DEFAULT_SECTOR_SIZE 4096
-#endif
-
-/*
-** Temporary files are named starting with this prefix followed by 16 random
-** alphanumeric characters, and no file extension. They are stored in the
-** OS's standard temporary file directory, and are deleted prior to exit.
-** If sqlite is being embedded in another program, you may wish to change the
-** prefix to reflect your program's name, so that if your program exits
-** prematurely, old temporary files can be easily identified. This can be done
-** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
-**
-** 2006-10-31: The default prefix used to be "sqlite_". But then
-** Mcafee started using SQLite in their anti-virus product and it
-** started putting files with the "sqlite" name in the c:/temp folder.
-** This annoyed many windows users. Those users would then do a
-** Google search for "sqlite", find the telephone numbers of the
-** developers and call to wake them up at night and complain.
-** For this reason, the default name prefix is changed to be "sqlite"
-** spelled backwards. So the temp files are still identified, but
-** anybody smart enough to figure out the code is also likely smart
-** enough to know that calling the developer will not help get rid
-** of the file.
-*/
-#ifndef SQLITE_TEMP_FILE_PREFIX
-# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
-#endif
-
-/*
-** The following values may be passed as the second argument to
-** sqlite3OsLock(). The various locks exhibit the following semantics:
-**
-** SHARED: Any number of processes may hold a SHARED lock simultaneously.
-** RESERVED: A single process may hold a RESERVED lock on a file at
-** any time. Other processes may hold and obtain new SHARED locks.
-** PENDING: A single process may hold a PENDING lock on a file at
-** any one time. Existing SHARED locks may persist, but no new
-** SHARED locks may be obtained by other processes.
-** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
-**
-** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
-** process that requests an EXCLUSIVE lock may actually obtain a PENDING
-** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
-** sqlite3OsLock().
-*/
-#define NO_LOCK 0
-#define SHARED_LOCK 1
-#define RESERVED_LOCK 2
-#define PENDING_LOCK 3
-#define EXCLUSIVE_LOCK 4
-
-/*
-** File Locking Notes: (Mostly about windows but also some info for Unix)
-**
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
-** those functions are not available. So we use only LockFile() and
-** UnlockFile().
-**
-** LockFile() prevents not just writing but also reading by other processes.
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
-** byte out of a specific range of bytes. The lock byte is obtained at
-** random so two separate readers can probably access the file at the
-** same time, unless they are unlucky and choose the same lock byte.
-** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
-** There can only be one writer. A RESERVED_LOCK is obtained by locking
-** a single byte of the file that is designated as the reserved lock byte.
-** A PENDING_LOCK is obtained by locking a designated byte different from
-** the RESERVED_LOCK byte.
-**
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
-** which means we can use reader/writer locks. When reader/writer locks
-** are used, the lock is placed on the same range of bytes that is used
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
-** will support two or more Win95 readers or two or more WinNT readers.
-** But a single Win95 reader will lock out all WinNT readers and a single
-** WinNT reader will lock out all other Win95 readers.
-**
-** The following #defines specify the range of bytes used for locking.
-** SHARED_SIZE is the number of bytes available in the pool from which
-** a random byte is selected for a shared lock. The pool of bytes for
-** shared locks begins at SHARED_FIRST.
-**
-** The same locking strategy and
-** byte ranges are used for Unix. This leaves open the possibility of having
-** clients on win95, winNT, and unix all talking to the same shared file
-** and all locking correctly. To do so would require that samba (or whatever
-** tool is being used for file sharing) implements locks correctly between
-** windows and unix. I'm guessing that isn't likely to happen, but by
-** using the same locking range we are at least open to the possibility.
-**
-** Locking in windows is manditory. For this reason, we cannot store
-** actual data in the bytes used for locking. The pager never allocates
-** the pages involved in locking therefore. SHARED_SIZE is selected so
-** that all locks will fit on a single page even at the minimum page size.
-** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
-** is set high so that we don't have to allocate an unused page except
-** for very large databases. But one should test the page skipping logic
-** by setting PENDING_BYTE low and running the entire regression suite.
-**
-** Changing the value of PENDING_BYTE results in a subtly incompatible
-** file format. Depending on how it is changed, you might not notice
-** the incompatibility right away, even running a full regression test.
-** The default location of PENDING_BYTE is the first byte past the
-** 1GB boundary.
-**
-*/
-#ifdef SQLITE_OMIT_WSD
-# define PENDING_BYTE (0x40000000)
-#else
-# define PENDING_BYTE sqlite3PendingByte
-#endif
-#define RESERVED_BYTE (PENDING_BYTE+1)
-#define SHARED_FIRST (PENDING_BYTE+2)
-#define SHARED_SIZE 510
-
-/*
-** Wrapper around OS specific sqlite3_os_init() function.
-*/
-SQLITE_PRIVATE int sqlite3OsInit(void);
-
-/*
-** Functions for accessing sqlite3_file methods
-*/
-SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
-SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
-SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
-SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
-SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
-SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
-SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
-SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
-SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
-SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
-#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
-SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
-SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
-SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
-#endif /* SQLITE_OMIT_WAL */
-SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
-SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
-
-
-/*
-** Functions for accessing sqlite3_vfs methods
-*/
-SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
-SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
-SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
-SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
-SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
-SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
-SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
-SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
-SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
-SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
-
-/*
-** Convenience functions for opening and closing files using
-** sqlite3_malloc() to obtain space for the file-handle structure.
-*/
-SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
-SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
-
-#endif /* _SQLITE_OS_H_ */
-
-/************** End of os.h **************************************************/
-/************** Continuing where we left off in sqliteInt.h ******************/
/************** Include mutex.h in the middle of sqliteInt.h *****************/
/************** Begin file mutex.h *******************************************/
/*
@@ -16743,6 +16988,7 @@ struct Lookaside {
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
void *pStart; /* First byte of available memory space */
void *pEnd; /* First byte past end of available space */
+ void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */
};
struct LookasideSlot {
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
@@ -17087,6 +17333,8 @@ struct sqlite3 {
#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
+#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
+#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17171,8 +17419,14 @@ struct FuncDestructor {
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
-** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS
+** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
+**
+** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
+** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
+** used internally and if set means tha the function has side effects.
+** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
+** See multiple instances of tag-20230109-1.
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
@@ -17289,7 +17543,7 @@ struct FuncDestructor {
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
#define JFUNCTION(zName, nArg, iArg, xFunc) \
- {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|\
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\
SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
@@ -17481,6 +17735,7 @@ struct CollSeq {
#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
#define SQLITE_AFF_REAL 0x45 /* 'E' */
+#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
@@ -17659,7 +17914,7 @@ struct Table {
#ifndef SQLITE_OMIT_VIRTUALTABLE
# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB)
# define ExprIsVtab(X) \
- ((X)->op==TK_COLUMN && (X)->y.pTab!=0 && (X)->y.pTab->eTabType==TABTYP_VTAB)
+ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB)
#else
# define IsVirtual(X) 0
# define ExprIsVtab(X) 0
@@ -17876,10 +18131,22 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
-** algorithm to employ whenever an attempt is made to insert a non-unique
+** and the value of Index.onError indicates which conflict resolution
+** algorithm to employ when an attempt is made to insert a non-unique
** element.
**
+** The colNotIdxed bitmask is used in combination with SrcItem.colUsed
+** for a fast test to see if an index can serve as a covering index.
+** colNotIdxed has a 1 bit for every column of the original table that
+** is *not* available in the index. Thus the expression
+** "colUsed & colNotIdxed" will be non-zero if the index is not a
+** covering index. The most significant bit of of colNotIdxed will always
+** be true (note-20221022-a). If a column beyond the 63rd column of the
+** table is used, the "colUsed & colNotIdxed" test will always be non-zero
+** and we have to assume either that the index is not covering, or use
+** an alternative (slower) algorithm to determine whether or not
+** the index is covering.
+**
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
** generate VDBE code (as opposed to parsing one read from an sqlite_schema
** table as part of parsing an existing database schema), transient instances
@@ -17915,6 +18182,8 @@ struct Index {
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
+ unsigned bHasExpr:1; /* Index contains an expression, either a literal
+ ** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
@@ -17923,7 +18192,7 @@ struct Index {
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
#endif
- Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
+ Bitmask colNotIdxed; /* Unindexed columns in pTab */
};
/*
@@ -17998,16 +18267,15 @@ struct AggInfo {
** from source tables rather than from accumulators */
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
** than the source table */
+ u16 nSortingColumn; /* Number of columns in the sorting index */
int sortingIdx; /* Cursor number of the sorting index */
int sortingIdxPTab; /* Cursor number of pseudo-table */
- int nSortingColumn; /* Number of columns in the sorting index */
- int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
+ int iFirstReg; /* First register in range for aCol[] and aFunc[] */
ExprList *pGroupBy; /* The group by clause */
struct AggInfo_col { /* For each column used in source tables */
Table *pTab; /* Source table */
Expr *pCExpr; /* The original expression */
int iTable; /* Cursor number of the source table */
- int iMem; /* Memory location that acts as accumulator */
i16 iColumn; /* Column number within the source table */
i16 iSorterColumn; /* Column number in the sorting index */
} *aCol;
@@ -18018,15 +18286,28 @@ struct AggInfo {
struct AggInfo_func { /* For each aggregate function */
Expr *pFExpr; /* Expression encoding the function */
FuncDef *pFunc; /* The aggregate function implementation */
- int iMem; /* Memory location that acts as accumulator */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
int iDistAddr; /* Address of OP_OpenEphemeral */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
u32 selId; /* Select to which this AggInfo belongs */
+#ifdef SQLITE_DEBUG
+ Select *pSelect; /* SELECT statement that this AggInfo supports */
+#endif
};
/*
+** Macros to compute aCol[] and aFunc[] register numbers.
+**
+** These macros should not be used prior to the call to
+** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
+** The assert()s that are part of this macro verify that constraint.
+*/
+#define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I))
+#define AggInfoFuncReg(A,I) \
+ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
+
+/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit. 16-bit is preferred because
@@ -18191,7 +18472,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
-#define EP_MemToken 0x020000 /* Need to sqlite3DbFree() Expr.zToken */
+ /* 0x020000 // Available for reuse */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -18376,6 +18657,14 @@ struct IdList {
** The SrcItem object represents a single term in the FROM clause of a query.
** The SrcList object is mostly an array of SrcItems.
**
+** The jointype starts out showing the join type between the current table
+** and the next table on the list. The parser builds the list this way.
+** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
+** jointype expresses the join between the table and the previous table.
+**
+** In the colUsed field, the high-order bit (bit 63) is set if the table
+** contains more than 63 columns and the 64-th or later column is used.
+**
** Union member validity:
**
** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
@@ -18415,14 +18704,14 @@ struct SrcItem {
Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
} u3;
- Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
+ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
union {
char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
ExprList *pFuncArg; /* Arguments to table-valued-function */
} u1;
union {
Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
- CteUse *pCteUse; /* CTE Usage info info fg.isCte is true */
+ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
} u2;
};
@@ -18436,23 +18725,11 @@ struct OnOrUsing {
};
/*
-** The following structure describes the FROM clause of a SELECT statement.
-** Each table or subquery in the FROM clause is a separate element of
-** the SrcList.a[] array.
+** This object represents one or more tables that are the source of
+** content for an SQL statement. For example, a single SrcList object
+** is used to hold the FROM clause of a SELECT statement. SrcList also
+** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
-** With the addition of multiple database support, the following structure
-** can also be used to describe a particular table such as the table that
-** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
-** such a table must be a simple name: ID. But in SQLite, the table can
-** now be identified by a database name, a dot, then the table name: ID.ID.
-**
-** The jointype starts out showing the join type between the current table
-** and the next table on the list. The parser builds the list this way.
-** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
-** jointype expresses the join between the table and the previous table.
-**
-** In the colUsed field, the high-order bit (bit 63) is set if the table
-** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
int nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -18689,6 +18966,7 @@ struct Select {
#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
+#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
/* True if S exists and has SF_NestedFrom */
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
@@ -18797,7 +19075,7 @@ struct SelectDest {
int iSDParm2; /* A second parameter for the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
+ char *zAffSdst; /* Affinity used for SRT_Set */
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
};
@@ -18856,11 +19134,33 @@ struct TriggerPrg {
#else
typedef unsigned int yDbMask;
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
-# define DbMaskZero(M) (M)=0
-# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
-# define DbMaskAllZero(M) (M)==0
-# define DbMaskNonZero(M) (M)!=0
+# define DbMaskZero(M) ((M)=0)
+# define DbMaskSet(M,I) ((M)|=(((yDbMask)1)<<(I)))
+# define DbMaskAllZero(M) ((M)==0)
+# define DbMaskNonZero(M) ((M)!=0)
+#endif
+
+/*
+** For each index X that has as one of its arguments either an expression
+** or the name of a virtual generated column, and if X is in scope such that
+** the value of the expression can simply be read from the index, then
+** there is an instance of this object on the Parse.pIdxExpr list.
+**
+** During code generation, while generating code to evaluate expressions,
+** this list is consulted and if a matching expression is found, the value
+** is read from the index rather than being recomputed.
+*/
+struct IndexedExpr {
+ Expr *pExpr; /* The expression contained in the index */
+ int iDataCur; /* The data cursor associated with the index */
+ int iIdxCur; /* The index cursor */
+ int iIdxCol; /* The index column that contains value of pExpr */
+ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
+ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ const char *zIdxName; /* Name of index, used only for bytecode comments */
#endif
+};
/*
** An instance of the ParseCleanup object specifies an operation that
@@ -18903,7 +19203,7 @@ struct Parse {
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
- u8 disableVtab; /* Disable all virtual tables for this parse */
+ u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
@@ -18920,6 +19220,7 @@ struct Parse {
int nLabelAlloc; /* Number of slots in aLabel */
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
+ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
@@ -18943,6 +19244,9 @@ struct Parse {
u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
+#endif
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 bReturning; /* Coding a RETURNING trigger */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
@@ -19355,15 +19659,15 @@ struct Walker {
struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
- struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */
ExprList *pGroupBy; /* GROUP BY clause */
Select *pSelect; /* HAVING to WHERE clause ctx */
struct WindowRewrite *pRewrite; /* Window rewrite context */
struct WhereConst *pConst; /* WHERE clause constants */
struct RenameCtx *pRename; /* RENAME COLUMN context */
struct Table *pTab; /* Table of generated column */
+ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
- DbFixer *pFix;
+ DbFixer *pFix; /* See sqlite3FixSelect() */
} u;
};
@@ -19669,6 +19973,7 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(const void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
@@ -19689,12 +19994,14 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
*/
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
-# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
+# define sqlite3StackAllocRawNN(D,N) alloca(N)
# define sqlite3StackFree(D,P)
+# define sqlite3StackFreeNN(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
-# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
+# define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N)
# define sqlite3StackFree(D,P) sqlite3DbFree(D,P)
+# define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P)
#endif
/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they
@@ -19817,6 +20124,7 @@ SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*);
#endif
SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
+SQLITE_PRIVATE void sqlite3ProgressCheck(Parse*);
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int);
SQLITE_PRIVATE void sqlite3Dequote(char*);
@@ -19874,7 +20182,7 @@ SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*);
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect);
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
+SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int);
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
@@ -20193,7 +20501,8 @@ SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
-SQLITE_PRIVATE void sqlite3Int64ToText(i64,char*);
+SQLITE_PRIVATE i64 sqlite3RealToI64(double);
+SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*);
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
@@ -20238,11 +20547,13 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3*,const Table*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
+SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
@@ -20259,6 +20570,9 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int);
#ifndef SQLITE_OMIT_DESERIALIZE
SQLITE_PRIVATE int sqlite3MemdbInit(void);
+SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs*);
+#else
+# define sqlite3IsMemdb(X) 0
#endif
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
@@ -20309,7 +20623,6 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[];
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[];
-SQLITE_PRIVATE const char sqlite3StdTypeMap[];
SQLITE_PRIVATE const char *sqlite3StdType[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char *sqlite3aLTb;
@@ -20399,7 +20712,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
-SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, int);
+SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8);
SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
@@ -20753,6 +21066,16 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
#endif
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlite3KvvfsInit(void);
+#endif
+
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void);
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -20794,101 +21117,6 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
*/
#ifdef SQLITE_PERFORMANCE_TRACE
-/*
-** hwtime.h contains inline assembler code for implementing
-** high-performance timing routines.
-*/
-/************** Include hwtime.h in the middle of os_common.h ****************/
-/************** Begin file hwtime.h ******************************************/
-/*
-** 2008 May 27
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-******************************************************************************
-**
-** This file contains inline asm code for retrieving "high-performance"
-** counters for x86 and x86_64 class CPUs.
-*/
-#ifndef SQLITE_HWTIME_H
-#define SQLITE_HWTIME_H
-
-/*
-** The following routine only works on pentium-class (or newer) processors.
-** It uses the RDTSC opcode to read the cycle count value out of the
-** processor and returns that value. This can be used for high-res
-** profiling.
-*/
-#if !defined(__STRICT_ANSI__) && \
- (defined(__GNUC__) || defined(_MSC_VER)) && \
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
-
- #if defined(__GNUC__)
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned int lo, hi;
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
- return (sqlite_uint64)hi << 32 | lo;
- }
-
- #elif defined(_MSC_VER)
-
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
- __asm {
- rdtsc
- ret ; return value at EDX:EAX
- }
- }
-
- #endif
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned long val;
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
- return val;
- }
-
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
-
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
- unsigned long long retval;
- unsigned long junk;
- __asm__ __volatile__ ("\n\
- 1: mftbu %1\n\
- mftb %L0\n\
- mftbu %0\n\
- cmpw %0,%1\n\
- bne 1b"
- : "=r" (retval), "=r" (junk));
- return retval;
- }
-
-#else
-
- /*
- ** asm() is needed for hardware timing support. Without asm(),
- ** disable the sqlite3Hwtime() routine.
- **
- ** sqlite3Hwtime() is only used for some obscure debugging
- ** and analysis configurations, not in any deliverable, so this
- ** should not be a great loss.
- */
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
-
-#endif
-
-#endif /* !defined(SQLITE_HWTIME_H) */
-
-/************** End of hwtime.h **********************************************/
-/************** Continuing where we left off in os_common.h ******************/
-
static sqlite_uint64 g_start;
static sqlite_uint64 g_elapsed;
#define TIMER_START g_start=sqlite3Hwtime()
@@ -20984,7 +21212,7 @@ SQLITE_API extern int sqlite3_open_file_count;
** autoconf-based build
*/
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
-/* #include "config.h" */
+/* #include "sqlite_cfg.h" */
#define SQLITECONFIG_H 1
#endif
@@ -21149,6 +21377,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
"DISABLE_SKIPAHEAD_DISTINCT",
#endif
+#ifdef SQLITE_DQS
+ "DQS=" CTIMEOPT_VAL(SQLITE_DQS),
+#endif
#ifdef SQLITE_ENABLE_8_3_NAMES
"ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
@@ -21639,9 +21870,6 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_XFER_OPT
"OMIT_XFER_OPT",
#endif
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- "PCACHE_SEPARATE_HEADER",
-#endif
#ifdef SQLITE_PERFORMANCE_TRACE
"PERFORMANCE_TRACE",
#endif
@@ -22121,10 +22349,6 @@ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
**
** sqlite3StdTypeAffinity[] The affinity associated with each entry
** in sqlite3StdType[].
-**
-** sqlite3StdTypeMap[] The type value (as returned from
-** sqlite3_column_type() or sqlite3_value_type())
-** for each entry in sqlite3StdType[].
*/
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
@@ -22135,14 +22359,6 @@ SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
SQLITE_AFF_REAL,
SQLITE_AFF_TEXT
};
-SQLITE_PRIVATE const char sqlite3StdTypeMap[] = {
- 0,
- SQLITE_BLOB,
- SQLITE_INTEGER,
- SQLITE_INTEGER,
- SQLITE_FLOAT,
- SQLITE_TEXT
-};
SQLITE_PRIVATE const char *sqlite3StdType[] = {
"ANY",
"BLOB",
@@ -22345,7 +22561,6 @@ struct VdbeFrame {
Vdbe *v; /* VM this frame belongs to */
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
Op *aOp; /* Program instructions for parent frame */
- i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
u8 *aOnce; /* Bitmask used by OP_Once */
@@ -22561,10 +22776,19 @@ typedef unsigned bft; /* Bit Field Type */
/* The ScanStatus object holds a single value for the
** sqlite3_stmt_scanstatus() interface.
+**
+** aAddrRange[]:
+** This array is used by ScanStatus elements associated with EQP
+** notes that make an SQLITE_SCANSTAT_NCYCLE value available. It is
+** an array of up to 3 ranges of VM addresses for which the Vdbe.anCycle[]
+** values should be summed to calculate the NCYCLE value. Each pair of
+** integer addresses is a start and end address (both inclusive) for a range
+** instructions. A start value of 0 indicates an empty range.
*/
typedef struct ScanStatus ScanStatus;
struct ScanStatus {
int addrExplain; /* OP_Explain for loop */
+ int aAddrRange[6];
int addrLoop; /* Address of "loops" counter */
int addrVisit; /* Address of "rows visited" counter */
int iSelectID; /* The "Select-ID" for this loop */
@@ -22594,7 +22818,7 @@ struct DblquoteStr {
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+ Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */
Parse *pParse; /* Parsing context used to create this Vdbe */
ynVar nVar; /* Number of entries in aVar[] */
int nMem; /* Number of memory locations currently allocated */
@@ -22620,7 +22844,7 @@ struct Vdbe {
int nOp; /* Number of instructions in the program */
int nOpAlloc; /* Slots allocated for aOp[] */
Mem *aColName; /* Column names to return */
- Mem *pResultSet; /* Pointer to an array of results */
+ Mem *pResultRow; /* Current output row */
char *zErrMsg; /* Error message written here */
VList *pVList; /* Name of variables */
#ifndef SQLITE_OMIT_TRACE
@@ -22657,7 +22881,6 @@ struct Vdbe {
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- i64 *anExec; /* Number of times each op has been executed */
int nScan; /* Entries in aScan[] */
ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
#endif
@@ -22824,6 +23047,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
+SQLITE_PRIVATE void sqlite3VdbeValueListFree(void*);
+
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*);
@@ -23152,6 +23377,8 @@ SQLITE_API int sqlite3_db_status(
sqlite3BtreeEnterAll(db);
db->pnBytesFreed = &nByte;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
for(i=0; i<db->nDb; i++){
Schema *pSchema = db->aDb[i].pSchema;
if( ALWAYS(pSchema!=0) ){
@@ -23177,6 +23404,7 @@ SQLITE_API int sqlite3_db_status(
}
}
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3BtreeLeaveAll(db);
*pHighwater = 0;
@@ -23194,9 +23422,12 @@ SQLITE_API int sqlite3_db_status(
int nByte = 0; /* Used to accumulate return value */
db->pnBytesFreed = &nByte;
- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
sqlite3VdbeDelete(pVdbe);
}
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
db->pnBytesFreed = 0;
*pHighwater = 0; /* IMP: R-64479-57858 */
@@ -23532,7 +23763,7 @@ static void computeJD(DateTime *p){
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
if( p->validHMS ){
- p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
+ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
if( p->validTZ ){
p->iJD -= p->tz*60000;
p->validYMD = 0;
@@ -24005,7 +24236,7 @@ static int parseModifier(
i64 iOrigJD; /* Original localtime */
i64 iGuess; /* Guess at the corresponding utc time */
int cnt = 0; /* Safety to prevent infinite loop */
- int iErr; /* Guess is off by this much */
+ i64 iErr; /* Guess is off by this much */
computeJD(p);
iGuess = iOrigJD = p->iJD;
@@ -24041,7 +24272,7 @@ static int parseModifier(
*/
if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
- && (n=(int)r)==r && n>=0 && r<7 ){
+ && r>=0.0 && r<7.0 && (n=(int)r)==r ){
sqlite3_int64 Z;
computeYMD_HMS(p);
p->validTZ = 0;
@@ -24722,9 +24953,11 @@ SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
}
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
DO_OS_MALLOC_TEST(id);
+ assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
return id->pMethods->xLock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
+ assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
return id->pMethods->xUnlock(id, lockType);
}
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
@@ -24839,6 +25072,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
** reaching the VFS. */
+ assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
assert( rc==SQLITE_OK || pFile->pMethods==0 );
return rc;
@@ -27154,9 +27388,13 @@ static int memsys5Roundup(int n){
if( n<=mem5.szAtom ) return mem5.szAtom;
return mem5.szAtom*2;
}
- if( n>0x40000000 ) return 0;
+ if( n>0x10000000 ){
+ if( n>0x40000000 ) return 0;
+ if( n>0x20000000 ) return 0x40000000;
+ return 0x20000000;
+ }
for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
- if( (iFullSz/2)>=n ) return iFullSz/2;
+ if( (iFullSz/2)>=(i64)n ) return iFullSz/2;
return iFullSz;
}
@@ -29058,17 +29296,33 @@ static void mallocWithAlarm(int n, void **pp){
}
/*
+** Maximum size of any single memory allocation.
+**
+** This is not a limit on the total amount of memory used. This is
+** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
+**
+** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
+** This provides a 256-byte safety margin for defense against 32-bit
+** signed integer overflow bugs when computing memory allocation sizes.
+** Paranoid applications might want to reduce the maximum allocation size
+** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
+** or even smaller would be reasonable upper bounds on the size of a memory
+** allocations for most applications.
+*/
+#ifndef SQLITE_MAX_ALLOCATION_SIZE
+# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
+#endif
+#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
+# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
+#endif
+
+/*
** Allocate memory. This routine is like sqlite3_malloc() except that it
** assumes the memory subsystem has already been initialized.
*/
SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
void *p;
- if( n==0 || n>=0x7fffff00 ){
- /* A memory allocation of a number of bytes which is near the maximum
- ** signed integer value might cause an integer overflow inside of the
- ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
- ** 255 bytes of overhead. SQLite itself will never use anything near
- ** this amount. The only way to reach the limit is with sqlite3_malloc() */
+ if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
p = 0;
}else if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
@@ -29104,7 +29358,7 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, const void *p){
- return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
+ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
}
#else
#define isLookaside(A,B) 0
@@ -29128,18 +29382,16 @@ static int lookasideMallocSize(sqlite3 *db, const void *p){
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
assert( p!=0 );
#ifdef SQLITE_DEBUG
- if( db==0 || !isLookaside(db,p) ){
- if( db==0 ){
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
- assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
- }else{
- assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
- }
+ if( db==0 ){
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
+ }else if( !isLookaside(db,p) ){
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
}
#endif
if( db ){
- if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
assert( sqlite3_mutex_held(db->mutex) );
@@ -29195,14 +29447,11 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
assert( p!=0 );
if( db ){
- if( db->pnBytesFreed ){
- measureAllocationSize(db, p);
- return;
- }
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
#endif
@@ -29213,6 +29462,7 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
#ifdef SQLITE_DEBUG
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
#endif
@@ -29221,6 +29471,10 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
return;
}
}
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
}
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
@@ -29228,6 +29482,43 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3 *db, void *p){
+ assert( db!=0 );
+ assert( sqlite3_mutex_held(db->mutex) );
+ assert( p!=0 );
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pSmallFree;
+ db->lookaside.pSmallFree = pBuf;
+ return;
+ }
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
+ LookasideSlot *pBuf = (LookasideSlot*)p;
+ assert( db->pnBytesFreed==0 );
+#ifdef SQLITE_DEBUG
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
+#endif
+ pBuf->pNext = db->lookaside.pFree;
+ db->lookaside.pFree = pBuf;
+ return;
+ }
+ }
+ if( db->pnBytesFreed ){
+ measureAllocationSize(db, p);
+ return;
+ }
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
+ sqlite3_free(p);
+}
SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
assert( db==0 || sqlite3_mutex_held(db->mutex) );
if( p ) sqlite3DbFreeNN(db, p);
@@ -29527,9 +29818,14 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
*/
SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
int n;
+#ifdef SQLITE_DEBUG
+ /* Because of the way the parser works, the span is guaranteed to contain
+ ** at least one non-space character */
+ for(n=0; sqlite3Isspace(zStart[n]); n++){ assert( &zStart[n]<zEnd ); }
+#endif
while( sqlite3Isspace(zStart[0]) ) zStart++;
n = (int)(zEnd - zStart);
- while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
+ while( sqlite3Isspace(zStart[n-1]) ) n--;
return sqlite3DbStrNDup(db, zStart, n);
}
@@ -29563,8 +29859,13 @@ SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){
}
DisableLookaside;
if( db->pParse ){
+ Parse *pParse;
sqlite3ErrorMsg(db->pParse, "out of memory");
db->pParse->rc = SQLITE_NOMEM_BKPT;
+ for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
+ pParse->nErr++;
+ pParse->rc = SQLITE_NOMEM;
+ }
}
}
return 0;
@@ -30363,13 +30664,26 @@ SQLITE_API void sqlite3_str_vappendf(
}
}
if( precision>1 ){
+ i64 nPrior = 1;
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlite3_str_appendchar(pAccum, width-1, ' ');
width = 0;
}
- while( precision-- > 1 ){
- sqlite3_str_append(pAccum, buf, length);
+ sqlite3_str_append(pAccum, buf, length);
+ precision--;
+ while( precision > 1 ){
+ i64 nCopyBytes;
+ if( nPrior > precision-1 ) nPrior = precision - 1;
+ nCopyBytes = length*nPrior;
+ if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
+ sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
+ }
+ if( pAccum->accError ) break;
+ sqlite3_str_append(pAccum,
+ &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
+ precision -= nPrior;
+ nPrior *= 2;
}
}
bufpt = buf;
@@ -30597,9 +30911,9 @@ SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExp
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
-SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){
+SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
char *zNew;
- assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
+ assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==SQLITE_TOOBIG);
testcase(p->accError==SQLITE_NOMEM);
@@ -30610,8 +30924,7 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){
return p->nAlloc - p->nChar - 1;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
- i64 szNew = p->nChar;
- szNew += (sqlite3_int64)N + 1;
+ i64 szNew = p->nChar + N + 1;
if( szNew+p->nChar<=p->mxAlloc ){
/* Force exponential buffer size growth as long as it does not overflow,
** to avoid having to call this routine too often */
@@ -30641,7 +30954,8 @@ SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, int N){
return 0;
}
}
- return N;
+ assert( N>=0 && N<=0x7fffffff );
+ return (int)N;
}
/*
@@ -31237,6 +31551,13 @@ SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc)
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
sqlite3_str_appendf(&x, " ON");
}
+ if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
+ if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
+ if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
+ if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
+ if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
+ if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
+
sqlite3StrAccumFinish(&x);
sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
n = 0;
@@ -31506,7 +31827,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewPop(&pView);
return;
}
- if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){
+ if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags || pExpr->pAggInfo ){
StrAccum x;
sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
sqlite3_str_appendf(&x, " fg.af=%x.%c",
@@ -31523,6 +31844,9 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
sqlite3_str_appendf(&x, " IMMUTABLE");
}
+ if( pExpr->pAggInfo!=0 ){
+ sqlite3_str_appendf(&x, " agg-column[%d]", pExpr->iAgg);
+ }
sqlite3StrAccumFinish(&x);
}else{
zFlgs[0] = 0;
@@ -32334,16 +32658,41 @@ SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(
** This structure is the current state of the generator.
*/
static SQLITE_WSD struct sqlite3PrngType {
- unsigned char isInit; /* True if initialized */
- unsigned char i, j; /* State variables */
- unsigned char s[256]; /* State variables */
+ u32 s[16]; /* 64 bytes of chacha20 state */
+ u8 out[64]; /* Output bytes */
+ u8 n; /* Output bytes remaining */
} sqlite3Prng;
+
+/* The RFC-7539 ChaCha20 block function
+*/
+#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
+#define QR(a, b, c, d) ( \
+ a += b, d ^= a, d = ROTL(d,16), \
+ c += d, b ^= c, b = ROTL(b,12), \
+ a += b, d ^= a, d = ROTL(d, 8), \
+ c += d, b ^= c, b = ROTL(b, 7))
+static void chacha_block(u32 *out, const u32 *in){
+ int i;
+ u32 x[16];
+ memcpy(x, in, 64);
+ for(i=0; i<10; i++){
+ QR(x[0], x[4], x[ 8], x[12]);
+ QR(x[1], x[5], x[ 9], x[13]);
+ QR(x[2], x[6], x[10], x[14]);
+ QR(x[3], x[7], x[11], x[15]);
+ QR(x[0], x[5], x[10], x[15]);
+ QR(x[1], x[6], x[11], x[12]);
+ QR(x[2], x[7], x[ 8], x[13]);
+ QR(x[3], x[4], x[ 9], x[14]);
+ }
+ for(i=0; i<16; i++) out[i] = x[i]+in[i];
+}
+
/*
** Return N random bytes.
*/
SQLITE_API void sqlite3_randomness(int N, void *pBuf){
- unsigned char t;
unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
@@ -32373,53 +32722,46 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_enter(mutex);
if( N<=0 || pBuf==0 ){
- wsdPrng.isInit = 0;
+ wsdPrng.s[0] = 0;
sqlite3_mutex_leave(mutex);
return;
}
/* Initialize the state of the random number generator once,
- ** the first time this routine is called. The seed value does
- ** not need to contain a lot of randomness since we are not
- ** trying to do secure encryption or anything like that...
- **
- ** Nothing in this file or anywhere else in SQLite does any kind of
- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
- ** number generator) not as an encryption device.
+ ** the first time this routine is called.
*/
- if( !wsdPrng.isInit ){
+ if( wsdPrng.s[0]==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
- int i;
- char k[256];
- wsdPrng.j = 0;
- wsdPrng.i = 0;
+ static const u32 chacha20_init[] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+ };
+ memcpy(&wsdPrng.s[0], chacha20_init, 16);
if( NEVER(pVfs==0) ){
- memset(k, 0, sizeof(k));
+ memset(&wsdPrng.s[4], 0, 44);
}else{
- sqlite3OsRandomness(pVfs, 256, k);
+ sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
}
- for(i=0; i<256; i++){
- wsdPrng.s[i] = (u8)i;
- }
- for(i=0; i<256; i++){
- wsdPrng.j += wsdPrng.s[i] + k[i];
- t = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
- wsdPrng.s[i] = t;
- }
- wsdPrng.isInit = 1;
+ wsdPrng.s[15] = wsdPrng.s[12];
+ wsdPrng.s[12] = 0;
+ wsdPrng.n = 0;
}
assert( N>0 );
- do{
- wsdPrng.i++;
- t = wsdPrng.s[wsdPrng.i];
- wsdPrng.j += t;
- wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
- wsdPrng.s[wsdPrng.j] = t;
- t += wsdPrng.s[wsdPrng.i];
- *(zBuf++) = wsdPrng.s[t];
- }while( --N );
+ while( 1 /* exit by break */ ){
+ if( N<=wsdPrng.n ){
+ memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
+ wsdPrng.n -= N;
+ break;
+ }
+ if( wsdPrng.n>0 ){
+ memcpy(zBuf, wsdPrng.out, wsdPrng.n);
+ N -= wsdPrng.n;
+ zBuf += wsdPrng.n;
+ }
+ wsdPrng.s[12]++;
+ chacha_block((u32*)wsdPrng.out, wsdPrng.s);
+ wsdPrng.n = 64;
+ }
sqlite3_mutex_leave(mutex);
}
@@ -33445,6 +33787,26 @@ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *z
}
/*
+** Check for interrupts and invoke progress callback.
+*/
+SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){
+ sqlite3 *db = p->db;
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){
+ if( db->xProgress(db->pProgressArg) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+ p->nProgressSteps = 0;
+ }
+#endif
+}
+
+/*
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
**
** This function should be used to report any error that occurs while
@@ -33459,7 +33821,7 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
sqlite3 *db = pParse->db;
assert( db!=0 );
- assert( db->pParse==pParse );
+ assert( db->pParse==pParse || db->pParse->pToplevel==pParse );
db->errByteOffset = -2;
va_start(ap, zFormat);
zMsg = sqlite3VMPrintf(db, zFormat, ap);
@@ -33901,11 +34263,14 @@ do_atof_calc:
#endif
/*
-** Render an signed 64-bit integer as text. Store the result in zOut[].
+** Render an signed 64-bit integer as text. Store the result in zOut[] and
+** return the length of the string that was stored, in bytes. The value
+** returned does not include the zero terminator at the end of the output
+** string.
**
** The caller must ensure that zOut[] is at least 21 bytes in size.
*/
-SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){
+SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){
int i;
u64 x;
char zTemp[22];
@@ -33922,6 +34287,7 @@ SQLITE_PRIVATE void sqlite3Int64ToText(i64 v, char *zOut){
}while( x );
if( v<0 ) zTemp[i--] = '-';
memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
+ return sizeof(zTemp)-2-i;
}
/*
@@ -34983,6 +35349,104 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam
return 0;
}
+/*
+** High-resolution hardware timer used for debugging and testing only.
+*/
+#if defined(VDBE_PROFILE) \
+ || defined(SQLITE_PERFORMANCE_TRACE) \
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+/************** Include hwtime.h in the middle of util.c *********************/
+/************** Begin file hwtime.h ******************************************/
+/*
+** 2008 May 27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains inline asm code for retrieving "high-performance"
+** counters for x86 and x86_64 class CPUs.
+*/
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
+
+/*
+** The following routine only works on pentium-class (or newer) processors.
+** It uses the RDTSC opcode to read the cycle count value out of the
+** processor and returns that value. This can be used for high-res
+** profiling.
+*/
+#if !defined(__STRICT_ANSI__) && \
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
+
+ #if defined(__GNUC__)
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+ #elif defined(_MSC_VER)
+
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
+ __asm {
+ rdtsc
+ ret ; return value at EDX:EAX
+ }
+ }
+
+ #endif
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned int lo, hi;
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
+ return (sqlite_uint64)hi << 32 | lo;
+ }
+
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
+
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
+ unsigned long long retval;
+ unsigned long junk;
+ __asm__ __volatile__ ("\n\
+ 1: mftbu %1\n\
+ mftb %L0\n\
+ mftbu %0\n\
+ cmpw %0,%1\n\
+ bne 1b"
+ : "=r" (retval), "=r" (junk));
+ return retval;
+ }
+
+#else
+
+ /*
+ ** asm() is needed for hardware timing support. Without asm(),
+ ** disable the sqlite3Hwtime() routine.
+ **
+ ** sqlite3Hwtime() is only used for some obscure debugging
+ ** and analysis configurations, not in any deliverable, so this
+ ** should not be a great loss.
+ */
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
+
+#endif
+
+#endif /* !defined(SQLITE_HWTIME_H) */
+
+/************** End of hwtime.h **********************************************/
+/************** Continuing where we left off in util.c ***********************/
+#endif
+
/************** End of util.c ************************************************/
/************** Begin file hash.c ********************************************/
/*
@@ -35153,12 +35617,13 @@ static HashElem *findElementWithHash(
count = pH->count;
}
if( pHash ) *pHash = h;
- while( count-- ){
+ while( count ){
assert( elem!=0 );
if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
return elem;
}
elem = elem->next;
+ count--;
}
return &nullElement;
}
@@ -35277,48 +35742,48 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 5 */ "Vacuum" OpHelp(""),
/* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
/* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
- /* 8 */ "Goto" OpHelp(""),
- /* 9 */ "Gosub" OpHelp(""),
- /* 10 */ "InitCoroutine" OpHelp(""),
- /* 11 */ "Yield" OpHelp(""),
- /* 12 */ "MustBeInt" OpHelp(""),
- /* 13 */ "Jump" OpHelp(""),
- /* 14 */ "Once" OpHelp(""),
- /* 15 */ "If" OpHelp(""),
- /* 16 */ "IfNot" OpHelp(""),
- /* 17 */ "IsNullOrType" OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"),
- /* 18 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 8 */ "Init" OpHelp("Start at P2"),
+ /* 9 */ "Goto" OpHelp(""),
+ /* 10 */ "Gosub" OpHelp(""),
+ /* 11 */ "InitCoroutine" OpHelp(""),
+ /* 12 */ "Yield" OpHelp(""),
+ /* 13 */ "MustBeInt" OpHelp(""),
+ /* 14 */ "Jump" OpHelp(""),
+ /* 15 */ "Once" OpHelp(""),
+ /* 16 */ "If" OpHelp(""),
+ /* 17 */ "IfNot" OpHelp(""),
+ /* 18 */ "IsType" OpHelp("if typeof(P1.P3) in P5 goto P2"),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 21 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 22 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 23 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 24 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
- /* 25 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
- /* 26 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 27 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 28 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 29 */ "SeekRowid" OpHelp("intkey=r[P3]"),
- /* 30 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 31 */ "Last" OpHelp(""),
- /* 32 */ "IfSmaller" OpHelp(""),
- /* 33 */ "SorterSort" OpHelp(""),
- /* 34 */ "Sort" OpHelp(""),
- /* 35 */ "Rewind" OpHelp(""),
- /* 36 */ "SorterNext" OpHelp(""),
- /* 37 */ "Prev" OpHelp(""),
- /* 38 */ "Next" OpHelp(""),
- /* 39 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 40 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 41 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 42 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
+ /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
+ /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
+ /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 29 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 32 */ "Last" OpHelp(""),
+ /* 33 */ "IfSmaller" OpHelp(""),
+ /* 34 */ "SorterSort" OpHelp(""),
+ /* 35 */ "Sort" OpHelp(""),
+ /* 36 */ "Rewind" OpHelp(""),
+ /* 37 */ "SorterNext" OpHelp(""),
+ /* 38 */ "Prev" OpHelp(""),
+ /* 39 */ "Next" OpHelp(""),
+ /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 45 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 46 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 47 */ "Program" OpHelp(""),
- /* 48 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 49 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 48 */ "Program" OpHelp(""),
+ /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
@@ -35328,12 +35793,12 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
/* 58 */ "ElseEq" OpHelp(""),
- /* 59 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
- /* 60 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 61 */ "IncrVacuum" OpHelp(""),
- /* 62 */ "VNext" OpHelp(""),
- /* 63 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
- /* 64 */ "Init" OpHelp("Start at P2"),
+ /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 62 */ "IncrVacuum" OpHelp(""),
+ /* 63 */ "VNext" OpHelp(""),
+ /* 64 */ "Filter" OpHelp("if key(P3@P4) not in filter(P1) goto P2"),
/* 65 */ "PureFunc" OpHelp("r[P3]=func(r[P2@NP])"),
/* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
/* 67 */ "Return" OpHelp(""),
@@ -35462,6 +35927,988 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
#endif
/************** End of opcodes.c *********************************************/
+/************** Begin file os_kv.c *******************************************/
+/*
+** 2022-09-06
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+** This file contains an experimental VFS layer that operates on a
+** Key/Value storage engine where both keys and values must be pure
+** text.
+*/
+/* #include <sqliteInt.h> */
+#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
+
+/*****************************************************************************
+** Debugging logic
+*/
+
+/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
+#if 0
+#define SQLITE_KV_TRACE(X) printf X
+#else
+#define SQLITE_KV_TRACE(X)
+#endif
+
+/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
+#if 0
+#define SQLITE_KV_LOG(X) printf X
+#else
+#define SQLITE_KV_LOG(X)
+#endif
+
+
+/*
+** Forward declaration of objects used by this VFS implementation
+*/
+typedef struct KVVfsFile KVVfsFile;
+
+/* A single open file. There are only two files represented by this
+** VFS - the database and the rollback journal.
+*/
+struct KVVfsFile {
+ sqlite3_file base; /* IO methods */
+ const char *zClass; /* Storage class */
+ int isJournal; /* True if this is a journal file */
+ unsigned int nJrnl; /* Space allocated for aJrnl[] */
+ char *aJrnl; /* Journal content */
+ int szPage; /* Last known page size */
+ sqlite3_int64 szDb; /* Database file size. -1 means unknown */
+ char *aData; /* Buffer to hold page data */
+};
+#define SQLITE_KVOS_SZ 133073
+
+/*
+** Methods for KVVfsFile
+*/
+static int kvvfsClose(sqlite3_file*);
+static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
+static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
+static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
+static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
+static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
+static int kvvfsSyncDb(sqlite3_file*, int flags);
+static int kvvfsSyncJrnl(sqlite3_file*, int flags);
+static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
+static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
+static int kvvfsLock(sqlite3_file*, int);
+static int kvvfsUnlock(sqlite3_file*, int);
+static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
+static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
+static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
+static int kvvfsSectorSize(sqlite3_file*);
+static int kvvfsDeviceCharacteristics(sqlite3_file*);
+
+/*
+** Methods for sqlite3_vfs
+*/
+static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
+static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
+static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
+static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
+static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
+static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
+static int kvvfsSleep(sqlite3_vfs*, int microseconds);
+static int kvvfsCurrentTime(sqlite3_vfs*, double*);
+static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
+
+static sqlite3_vfs sqlite3OsKvvfsObject = {
+ 1, /* iVersion */
+ sizeof(KVVfsFile), /* szOsFile */
+ 1024, /* mxPathname */
+ 0, /* pNext */
+ "kvvfs", /* zName */
+ 0, /* pAppData */
+ kvvfsOpen, /* xOpen */
+ kvvfsDelete, /* xDelete */
+ kvvfsAccess, /* xAccess */
+ kvvfsFullPathname, /* xFullPathname */
+ kvvfsDlOpen, /* xDlOpen */
+ 0, /* xDlError */
+ 0, /* xDlSym */
+ 0, /* xDlClose */
+ kvvfsRandomness, /* xRandomness */
+ kvvfsSleep, /* xSleep */
+ kvvfsCurrentTime, /* xCurrentTime */
+ 0, /* xGetLastError */
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
+};
+
+/* Methods for sqlite3_file objects referencing a database file
+*/
+static sqlite3_io_methods kvvfs_db_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadDb, /* xRead */
+ kvvfsWriteDb, /* xWrite */
+ kvvfsTruncateDb, /* xTruncate */
+ kvvfsSyncDb, /* xSync */
+ kvvfsFileSizeDb, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlDb, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/* Methods for sqlite3_file objects referencing a rollback journal
+*/
+static sqlite3_io_methods kvvfs_jrnl_io_methods = {
+ 1, /* iVersion */
+ kvvfsClose, /* xClose */
+ kvvfsReadJrnl, /* xRead */
+ kvvfsWriteJrnl, /* xWrite */
+ kvvfsTruncateJrnl, /* xTruncate */
+ kvvfsSyncJrnl, /* xSync */
+ kvvfsFileSizeJrnl, /* xFileSize */
+ kvvfsLock, /* xLock */
+ kvvfsUnlock, /* xUnlock */
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
+ kvvfsFileControlJrnl, /* xFileControl */
+ kvvfsSectorSize, /* xSectorSize */
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, /* xShmMap */
+ 0, /* xShmLock */
+ 0, /* xShmBarrier */
+ 0, /* xShmUnmap */
+ 0, /* xFetch */
+ 0 /* xUnfetch */
+};
+
+/****** Storage subsystem **************************************************/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* Forward declarations for the low-level storage engine
+*/
+static int kvstorageWrite(const char*, const char *zKey, const char *zData);
+static int kvstorageDelete(const char*, const char *zKey);
+static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
+#define KVSTORAGE_KEY_SZ 32
+
+/* Expand the key name with an appropriate prefix and put the result
+** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
+** KVSTORAGE_KEY_SZ bytes.
+*/
+static void kvstorageMakeKey(
+ const char *zClass,
+ const char *zKeyIn,
+ char *zKeyOut
+){
+ sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
+}
+
+/* Write content into a key. zClass is the particular namespace of the
+** underlying key/value store to use - either "local" or "session".
+**
+** Both zKey and zData are zero-terminated pure text strings.
+**
+** Return the number of errors.
+*/
+static int kvstorageWrite(
+ const char *zClass,
+ const char *zKey,
+ const char *zData
+){
+ FILE *fd;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ fd = fopen(zXKey, "wb");
+ if( fd ){
+ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
+ (int)strlen(zData), zData,
+ strlen(zData)>50 ? "..." : ""));
+ fputs(zData, fd);
+ fclose(fd);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+
+/* Delete a key (with its corresponding data) from the key/value
+** namespace given by zClass. If the key does not previously exist,
+** this routine is a no-op.
+*/
+static int kvstorageDelete(const char *zClass, const char *zKey){
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ unlink(zXKey);
+ SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
+ return 0;
+}
+
+/* Read the value associated with a zKey from the key/value namespace given
+** by zClass and put the text data associated with that key in the first
+** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
+** enough to hold it all. The value put into zBuf must always be zero
+** terminated, even if it gets truncated because nBuf is not large enough.
+**
+** Return the total number of bytes in the data, without truncation, and
+** not counting the final zero terminator. Return -1 if the key does
+** not exist.
+**
+** If nBuf<=0 then this routine simply returns the size of the data without
+** actually reading it.
+*/
+static int kvstorageRead(
+ const char *zClass,
+ const char *zKey,
+ char *zBuf,
+ int nBuf
+){
+ FILE *fd;
+ struct stat buf;
+ char zXKey[KVSTORAGE_KEY_SZ];
+ kvstorageMakeKey(zClass, zKey, zXKey);
+ if( access(zXKey, R_OK)!=0
+ || stat(zXKey, &buf)!=0
+ || !S_ISREG(buf.st_mode)
+ ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }
+ if( nBuf<=0 ){
+ return (int)buf.st_size;
+ }else if( nBuf==1 ){
+ zBuf[0] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
+ (int)buf.st_size));
+ return (int)buf.st_size;
+ }
+ if( nBuf > buf.st_size + 1 ){
+ nBuf = buf.st_size + 1;
+ }
+ fd = fopen(zXKey, "rb");
+ if( fd==0 ){
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
+ return -1;
+ }else{
+ sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
+ fclose(fd);
+ zBuf[n] = 0;
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
+ n, zBuf, n>50 ? "..." : ""));
+ return (int)n;
+ }
+}
+
+/*
+** An internal level of indirection which enables us to replace the
+** kvvfs i/o methods with JavaScript implementations in WASM builds.
+** Maintenance reminder: if this struct changes in any way, the JSON
+** rendering of its structure must be updated in
+** sqlite3_wasm_enum_json(). There are no binary compatibility
+** concerns, so it does not need an iVersion member. This file is
+** necessarily always compiled together with sqlite3_wasm_enum_json(),
+** and JS code dynamically creates the mapping of members based on
+** that JSON description.
+*/
+typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
+struct sqlite3_kvvfs_methods {
+ int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
+ int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
+ int (*xDelete)(const char *zClass, const char *zKey);
+ const int nKeySize;
+};
+
+/*
+** This object holds the kvvfs I/O methods which may be swapped out
+** for JavaScript-side implementations in WASM builds. In such builds
+** it cannot be const, but in native builds it should be so that
+** the compiler can hopefully optimize this level of indirection out.
+** That said, kvvfs is intended primarily for use in WASM builds.
+**
+** Note that this is not explicitly flagged as static because the
+** amalgamation build will tag it with SQLITE_PRIVATE.
+*/
+#ifndef SQLITE_WASM
+const
+#endif
+SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
+kvstorageRead,
+kvstorageWrite,
+kvstorageDelete,
+KVSTORAGE_KEY_SZ
+};
+
+/****** Utility subroutines ************************************************/
+
+/*
+** Encode binary into the text encoded used to persist on disk.
+** The output text is stored in aOut[], which must be at least
+** nData+1 bytes in length.
+**
+** Return the actual length of the encoded text, not counting the
+** zero terminator at the end.
+**
+** Encoding format
+** ---------------
+**
+** * Non-zero bytes are encoded as upper-case hexadecimal
+**
+** * A sequence of one or more zero-bytes that are not at the
+** beginning of the buffer are encoded as a little-endian
+** base-26 number using a..z. "a" means 0. "b" means 1,
+** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
+**
+** * Because there is no overlap between the encoding characters
+** of hexadecimal and base-26 numbers, it is always clear where
+** one stops and the next begins.
+*/
+static int kvvfsEncode(const char *aData, int nData, char *aOut){
+ int i, j;
+ const unsigned char *a = (const unsigned char*)aData;
+ for(i=j=0; i<nData; i++){
+ unsigned char c = a[i];
+ if( c!=0 ){
+ aOut[j++] = "0123456789ABCDEF"[c>>4];
+ aOut[j++] = "0123456789ABCDEF"[c&0xf];
+ }else{
+ /* A sequence of 1 or more zeros is stored as a little-endian
+ ** base-26 number using a..z as the digits. So one zero is "b".
+ ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
+ ** and so forth.
+ */
+ int k;
+ for(k=1; i+k<nData && a[i+k]==0; k++){}
+ i += k-1;
+ while( k>0 ){
+ aOut[j++] = 'a'+(k%26);
+ k /= 26;
+ }
+ }
+ }
+ aOut[j] = 0;
+ return j;
+}
+
+static const signed char kvvfsHexValue[256] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+/*
+** Decode the text encoding back to binary. The binary content is
+** written into pOut, which must be at least nOut bytes in length.
+**
+** The return value is the number of bytes actually written into aOut[].
+*/
+static int kvvfsDecode(const char *a, char *aOut, int nOut){
+ int i, j;
+ int c;
+ const unsigned char *aIn = (const unsigned char*)a;
+ i = 0;
+ j = 0;
+ while( 1 ){
+ c = kvvfsHexValue[aIn[i]];
+ if( c<0 ){
+ int n = 0;
+ int mult = 1;
+ c = aIn[i];
+ if( c==0 ) break;
+ while( c>='a' && c<='z' ){
+ n += (c - 'a')*mult;
+ mult *= 26;
+ c = aIn[++i];
+ }
+ if( j+n>nOut ) return -1;
+ memset(&aOut[j], 0, n);
+ j += n;
+ if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */
+ }else{
+ aOut[j] = c<<4;
+ c = kvvfsHexValue[aIn[++i]];
+ if( c<0 ) break;
+ aOut[j++] += c;
+ i++;
+ }
+ }
+ return j;
+}
+
+/*
+** Decode a complete journal file. Allocate space in pFile->aJrnl
+** and store the decoding there. Or leave pFile->aJrnl set to NULL
+** if an error is encountered.
+**
+** The first few characters of the text encoding will be a little-endian
+** base-26 number (digits a..z) that is the total number of bytes
+** in the decoded journal file image. This base-26 number is followed
+** by a single space, then the encoding of the journal. The space
+** separator is required to act as a terminator for the base-26 number.
+*/
+static void kvvfsDecodeJournal(
+ KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
+ const char *zTxt, /* Text encoding. Zero-terminated */
+ int nTxt /* Bytes in zTxt, excluding zero terminator */
+){
+ unsigned int n = 0;
+ int c, i, mult;
+ i = 0;
+ mult = 1;
+ while( (c = zTxt[i++])>='a' && c<='z' ){
+ n += (zTxt[i] - 'a')*mult;
+ mult *= 26;
+ }
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = sqlite3_malloc64( n );
+ if( pFile->aJrnl==0 ){
+ pFile->nJrnl = 0;
+ return;
+ }
+ pFile->nJrnl = n;
+ n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
+ if( n<pFile->nJrnl ){
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ }
+}
+
+/*
+** Read or write the "sz" element, containing the database file size.
+*/
+static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
+ char zData[50];
+ zData[0] = 0;
+ sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
+ return strtoll(zData, 0, 0);
+}
+static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
+ char zData[50];
+ sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
+ return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
+}
+
+/****** sqlite3_io_methods methods ******************************************/
+
+/*
+** Close an kvvfs-file.
+*/
+static int kvvfsClose(sqlite3_file *pProtoFile){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+
+ SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
+ pFile->isJournal ? "journal" : "db"));
+ sqlite3_free(pFile->aJrnl);
+ sqlite3_free(pFile->aData);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the -journal file.
+*/
+static int kvvfsReadJrnl(
+ sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ assert( pFile->isJournal );
+ SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( pFile->aJrnl==0 ){
+ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
+ char *aTxt;
+ if( szTxt<=4 ){
+ return SQLITE_IOERR;
+ }
+ aTxt = sqlite3_malloc64( szTxt+1 );
+ if( aTxt==0 ) return SQLITE_NOMEM;
+ kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
+ kvvfsDecodeJournal(pFile, aTxt, szTxt);
+ sqlite3_free(aTxt);
+ if( pFile->aJrnl==0 ) return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt>pFile->nJrnl ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Read from the database file.
+*/
+static int kvvfsReadDb(
+ sqlite3_file *pProtoFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ int got, n;
+ char zKey[30];
+ char *aData = pFile->aData;
+ assert( iOfst>=0 );
+ assert( iAmt>=0 );
+ SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iOfst+iAmt>=512 ){
+ if( (iOfst % iAmt)!=0 ){
+ return SQLITE_IOERR_READ;
+ }
+ if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
+ return SQLITE_IOERR_READ;
+ }
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ }else{
+ pgno = 1;
+ }
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey,
+ aData, SQLITE_KVOS_SZ-1);
+ if( got<0 ){
+ n = 0;
+ }else{
+ aData[got] = 0;
+ if( iOfst+iAmt<512 ){
+ int k = iOfst+iAmt;
+ aData[k*2] = 0;
+ n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000);
+ if( n>=iOfst+iAmt ){
+ memcpy(zBuf, &aData[2000+iOfst], iAmt);
+ n = iAmt;
+ }else{
+ n = 0;
+ }
+ }else{
+ n = kvvfsDecode(aData, zBuf, iAmt);
+ }
+ }
+ if( n<iAmt ){
+ memset(zBuf+n, 0, iAmt-n);
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
+** Write into the -journal file.
+*/
+static int kvvfsWriteJrnl(
+ sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ sqlite3_int64 iEnd = iOfst+iAmt;
+ SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ if( iEnd>=0x10000000 ) return SQLITE_FULL;
+ if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
+ char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
+ if( aNew==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ pFile->aJrnl = aNew;
+ if( pFile->nJrnl<iOfst ){
+ memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
+ }
+ pFile->nJrnl = iEnd;
+ }
+ memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
+ return SQLITE_OK;
+}
+
+/*
+** Write into the database file.
+*/
+static int kvvfsWriteDb(
+ sqlite3_file *pProtoFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ unsigned int pgno;
+ char zKey[30];
+ char *aData = pFile->aData;
+ SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
+ assert( iAmt>=512 && iAmt<=65536 );
+ assert( (iAmt & (iAmt-1))==0 );
+ assert( pFile->szPage<0 || pFile->szPage==iAmt );
+ pFile->szPage = iAmt;
+ pgno = 1 + iOfst/iAmt;
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ kvvfsEncode(zBuf, iAmt, aData);
+ if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
+ return SQLITE_IOERR;
+ }
+ if( iOfst+iAmt > pFile->szDb ){
+ pFile->szDb = iOfst + iAmt;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Truncate an kvvfs-file.
+*/
+static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
+ assert( size==0 );
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
+ sqlite3_free(pFile->aJrnl);
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ return SQLITE_OK;
+}
+static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ if( pFile->szDb>size
+ && pFile->szPage>0
+ && (size % pFile->szPage)==0
+ ){
+ char zKey[50];
+ unsigned int pgno, pgnoMax;
+ SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
+ pgno = 1 + size/pFile->szPage;
+ pgnoMax = 2 + pFile->szDb/pFile->szPage;
+ while( pgno<=pgnoMax ){
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
+ pgno++;
+ }
+ pFile->szDb = size;
+ return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
+ }
+ return SQLITE_IOERR;
+}
+
+/*
+** Sync an kvvfs-file.
+*/
+static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
+ int i, n;
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ char *zOut;
+ SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
+ if( pFile->nJrnl<=0 ){
+ return kvvfsTruncateJrnl(pProtoFile, 0);
+ }
+ zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
+ if( zOut==0 ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ n = pFile->nJrnl;
+ i = 0;
+ do{
+ zOut[i++] = 'a' + (n%26);
+ n /= 26;
+ }while( n>0 );
+ zOut[i++] = ' ';
+ kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
+ i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
+ sqlite3_free(zOut);
+ return i ? SQLITE_IOERR : SQLITE_OK;
+}
+static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current file-size of an kvvfs-file.
+*/
+static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
+ *pSize = pFile->nJrnl;
+ return SQLITE_OK;
+}
+static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>=0 ){
+ *pSize = pFile->szDb;
+ }else{
+ *pSize = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Lock an kvvfs-file.
+*/
+static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
+
+ if( eLock!=SQLITE_LOCK_NONE ){
+ pFile->szDb = kvvfsReadFileSize(pFile);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Unlock an kvvfs-file.
+*/
+static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ assert( !pFile->isJournal );
+ SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
+ if( eLock==SQLITE_LOCK_NONE ){
+ pFile->szDb = -1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
+*/
+static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
+ SQLITE_KV_LOG(("xCheckReservedLock\n"));
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+/*
+** File control method. For custom operations on an kvvfs-file.
+*/
+static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
+ return SQLITE_NOTFOUND;
+}
+static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
+ SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
+ if( op==SQLITE_FCNTL_SYNC ){
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
+ int rc = SQLITE_OK;
+ SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
+ if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
+ rc = SQLITE_IOERR;
+ }
+ return rc;
+ }
+ return SQLITE_NOTFOUND;
+}
+
+/*
+** Return the sector-size in bytes for an kvvfs-file.
+*/
+static int kvvfsSectorSize(sqlite3_file *pFile){
+ return 512;
+}
+
+/*
+** Return the device characteristic flags supported by an kvvfs-file.
+*/
+static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
+ return 0;
+}
+
+/****** sqlite3_vfs methods *************************************************/
+
+/*
+** Open an kvvfs file handle.
+*/
+static int kvvfsOpen(
+ sqlite3_vfs *pProtoVfs,
+ const char *zName,
+ sqlite3_file *pProtoFile,
+ int flags,
+ int *pOutFlags
+){
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
+ if( zName==0 ) zName = "";
+ SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
+ if( strcmp(zName, "local")==0
+ || strcmp(zName, "session")==0
+ ){
+ pFile->isJournal = 0;
+ pFile->base.pMethods = &kvvfs_db_io_methods;
+ }else
+ if( strcmp(zName, "local-journal")==0
+ || strcmp(zName, "session-journal")==0
+ ){
+ pFile->isJournal = 1;
+ pFile->base.pMethods = &kvvfs_jrnl_io_methods;
+ }else{
+ return SQLITE_CANTOPEN;
+ }
+ if( zName[0]=='s' ){
+ pFile->zClass = "session";
+ }else{
+ pFile->zClass = "local";
+ }
+ pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ);
+ if( pFile->aData==0 ){
+ return SQLITE_NOMEM;
+ }
+ pFile->aJrnl = 0;
+ pFile->nJrnl = 0;
+ pFile->szPage = -1;
+ pFile->szDb = -1;
+ return SQLITE_OK;
+}
+
+/*
+** Delete the file located at zPath. If the dirSync argument is true,
+** ensure the file-system modifications are synced to disk before
+** returning.
+*/
+static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ if( strcmp(zPath, "local-journal")==0 ){
+ sqlite3KvvfsMethods.xDelete("local", "jrnl");
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ sqlite3KvvfsMethods.xDelete("session", "jrnl");
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int kvvfsAccess(
+ sqlite3_vfs *pProtoVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
+ if( strcmp(zPath, "local-journal")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session-journal")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "local")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
+ }else
+ if( strcmp(zPath, "session")==0 ){
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
+ }else
+ {
+ *pResOut = 0;
+ }
+ SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
+ return SQLITE_OK;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (INST_MAX_PATHNAME+1) bytes.
+*/
+static int kvvfsFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ size_t nPath;
+#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
+ zPath = "local";
+#endif
+ nPath = strlen(zPath);
+ SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
+ if( nOut<nPath+1 ) nPath = nOut - 1;
+ memcpy(zOut, zPath, nPath);
+ zOut[nPath] = 0;
+ return SQLITE_OK;
+}
+
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ return 0;
+}
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ memset(zBufOut, 0, nByte);
+ return nByte;
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
+ return SQLITE_OK;
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ sqlite3_int64 i = 0;
+ int rc;
+ rc = kvvfsCurrentTimeInt64(0, &i);
+ *pTimeOut = i/86400000.0;
+ return rc;
+}
+#include <sys/time.h>
+static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
+ struct timeval sNow;
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
+ *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
+
+#if SQLITE_OS_KV
+/*
+** This routine is called initialize the KV-vfs as the default VFS.
+*/
+SQLITE_API int sqlite3_os_init(void){
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
+}
+SQLITE_API int sqlite3_os_end(void){
+ return SQLITE_OK;
+}
+#endif /* SQLITE_OS_KV */
+
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+SQLITE_PRIVATE int sqlite3KvvfsInit(void){
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
+}
+#endif
+
+/************** End of os_kv.c ***********************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
@@ -35552,15 +36999,16 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/*
** standard include files.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <sys/types.h> /* amalgamator: keep */
+#include <sys/stat.h> /* amalgamator: keep */
#include <fcntl.h>
#include <sys/ioctl.h>
-#include <unistd.h>
+#include <unistd.h> /* amalgamator: keep */
/* #include <time.h> */
-#include <sys/time.h>
+#include <sys/time.h> /* amalgamator: keep */
#include <errno.h>
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
# include <sys/mman.h>
#endif
@@ -35648,9 +37096,46 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
*/
#define SQLITE_MAX_SYMLINKS 100
+/*
+** Remove and stub certain info for WASI (WebAssembly System
+** Interface) builds.
+*/
+#ifdef SQLITE_WASI
+# undef HAVE_FCHMOD
+# undef HAVE_FCHOWN
+# undef HAVE_MREMAP
+# define HAVE_MREMAP 0
+# ifndef SQLITE_DEFAULT_UNIX_VFS
+# define SQLITE_DEFAULT_UNIX_VFS "unix-dotfile"
+ /* ^^^ should SQLITE_DEFAULT_UNIX_VFS be "unix-none"? */
+# endif
+# ifndef F_RDLCK
+# define F_RDLCK 0
+# define F_WRLCK 1
+# define F_UNLCK 2
+# if __LONG_MAX == 0x7fffffffL
+# define F_GETLK 12
+# define F_SETLK 13
+# define F_SETLKW 14
+# else
+# define F_GETLK 5
+# define F_SETLK 6
+# define F_SETLKW 7
+# endif
+# endif
+#else /* !SQLITE_WASI */
+# ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD
+# endif
+#endif /* SQLITE_WASI */
+
+#ifdef SQLITE_WASI
+# define osGetpid(X) (pid_t)1
+#else
/* Always cast the getpid() return type for compatibility with
** kernel modules in VxWorks. */
-#define osGetpid(X) (pid_t)getpid()
+# define osGetpid(X) (pid_t)getpid()
+#endif
/*
** Only set the lastErrno if the error code is a real error and not
@@ -35922,7 +37407,11 @@ static struct unix_syscall {
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
aSyscall[13].pCurrent)
+#if defined(HAVE_FCHMOD)
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
+#else
+ { "fchmod", (sqlite3_syscall_ptr)0, 0 },
+#endif
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
@@ -35958,14 +37447,16 @@ static struct unix_syscall {
#endif
#define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
#else
{ "mmap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
+ && !defined(SQLITE_WASI)
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
#else
{ "munmap", (sqlite3_syscall_ptr)0, 0 },
@@ -36151,6 +37642,9 @@ static int robust_open(const char *z, int f, mode_t m){
break;
}
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
+ if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){
+ (void)osUnlink(z);
+ }
osClose(fd);
sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z, fd);
@@ -37113,7 +38607,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
**
** UNLOCKED -> SHARED
** SHARED -> RESERVED
-** SHARED -> (PENDING) -> EXCLUSIVE
+** SHARED -> EXCLUSIVE
** RESERVED -> (PENDING) -> EXCLUSIVE
** PENDING -> EXCLUSIVE
**
@@ -37146,19 +38640,20 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** A RESERVED lock is implemented by grabbing a write-lock on the
** 'reserved byte'.
**
- ** A process may only obtain a PENDING lock after it has obtained a
- ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
- ** on the 'pending byte'. This ensures that no new SHARED locks can be
- ** obtained, but existing SHARED locks are allowed to persist. A process
- ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
- ** This property is used by the algorithm for rolling back a journal file
- ** after a crash.
+ ** An EXCLUSIVE lock may only be requested after either a SHARED or
+ ** RESERVED lock is held. An EXCLUSIVE lock is implemented by obtaining
+ ** a write-lock on the entire 'shared byte range'. Since all other locks
+ ** require a read-lock on one of the bytes within this range, this ensures
+ ** that no other locks are held on the database.
**
- ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
- ** implemented by obtaining a write-lock on the entire 'shared byte
- ** range'. Since all other locks require a read-lock on one of the bytes
- ** within this range, this ensures that no other locks are held on the
- ** database.
+ ** If a process that holds a RESERVED lock requests an EXCLUSIVE, then
+ ** a PENDING lock is obtained first. A PENDING lock is implemented by
+ ** obtaining a write-lock on the 'pending byte'. This ensures that no new
+ ** SHARED locks can be obtained, but existing SHARED locks are allowed to
+ ** persist. If the call to this function fails to obtain the EXCLUSIVE
+ ** lock in this case, it holds the PENDING lock intead. The client may
+ ** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
+ ** locks have cleared.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -37229,7 +38724,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
lock.l_len = 1L;
lock.l_whence = SEEK_SET;
if( eFileLock==SHARED_LOCK
- || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock==RESERVED_LOCK)
){
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
@@ -37240,6 +38735,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){
storeLastErrno(pFile, tErrno);
}
goto end_lock;
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
+ pFile->eFileLock = PENDING_LOCK;
+ pInode->eFileLock = PENDING_LOCK;
}
}
@@ -37327,13 +38825,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){
}
#endif
-
if( rc==SQLITE_OK ){
pFile->eFileLock = eFileLock;
pInode->eFileLock = eFileLock;
- }else if( eFileLock==EXCLUSIVE_LOCK ){
- pFile->eFileLock = PENDING_LOCK;
- pInode->eFileLock = PENDING_LOCK;
}
end_lock:
@@ -41320,6 +42814,7 @@ static const char *unixTempFileDir(void){
static int unixGetTempname(int nBuf, char *zBuf){
const char *zDir;
int iLimit = 0;
+ int rc = SQLITE_OK;
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
@@ -41328,18 +42823,26 @@ static int unixGetTempname(int nBuf, char *zBuf){
zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
zDir = unixTempFileDir();
- if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
- do{
- u64 r;
- sqlite3_randomness(sizeof(r), &r);
- assert( nBuf>2 );
- zBuf[nBuf-2] = 0;
- sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
- zDir, r, 0);
- if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
- }while( osAccess(zBuf,0)==0 );
- return SQLITE_OK;
+ if( zDir==0 ){
+ rc = SQLITE_IOERR_GETTEMPPATH;
+ }else{
+ do{
+ u64 r;
+ sqlite3_randomness(sizeof(r), &r);
+ assert( nBuf>2 );
+ zBuf[nBuf-2] = 0;
+ sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
+ zDir, r, 0);
+ if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
+ rc = SQLITE_ERROR;
+ break;
+ }
+ }while( osAccess(zBuf,0)==0 );
+ }
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
+ return rc;
}
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
@@ -41915,12 +43418,10 @@ static void appendOnePathElement(
if( zName[0]=='.' ){
if( nName==1 ) return;
if( zName[1]=='.' && nName==2 ){
- if( pPath->nUsed<=1 ){
- pPath->rc = SQLITE_ERROR;
- return;
+ if( pPath->nUsed>1 ){
+ assert( pPath->zOut[0]=='/' );
+ while( pPath->zOut[--pPath->nUsed]!='/' ){}
}
- assert( pPath->zOut[0]=='/' );
- while( pPath->zOut[--pPath->nUsed]!='/' ){}
return;
}
}
@@ -42132,7 +43633,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** than the argument.
*/
static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS
+#if OS_VXWORKS || _POSIX_C_SOURCE >= 199309L
struct timespec sp;
sp.tv_sec = microseconds / 1000000;
@@ -43514,8 +45015,16 @@ SQLITE_API int sqlite3_os_init(void){
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
+#ifdef SQLITE_DEFAULT_UNIX_VFS
+ sqlite3_vfs_register(&aVfs[i],
+ 0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
+#else
sqlite3_vfs_register(&aVfs[i], i==0);
+#endif
}
+#ifdef SQLITE_OS_KV_OPTIONAL
+ sqlite3KvvfsInit();
+#endif
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#ifndef SQLITE_OMIT_WAL
@@ -45478,10 +46987,12 @@ SQLITE_API int sqlite3_win32_set_directory8(
const char *zValue /* New value for directory being set or reset */
){
char **ppDirectory = 0;
+ int rc;
#ifndef SQLITE_OMIT_AUTOINIT
- int rc = sqlite3_initialize();
+ rc = sqlite3_initialize();
if( rc ) return rc;
#endif
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
ppDirectory = &sqlite3_data_directory;
}else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
@@ -45496,14 +47007,19 @@ SQLITE_API int sqlite3_win32_set_directory8(
if( zValue && zValue[0] ){
zCopy = sqlite3_mprintf("%s", zValue);
if ( zCopy==0 ){
- return SQLITE_NOMEM_BKPT;
+ rc = SQLITE_NOMEM_BKPT;
+ goto set_directory8_done;
}
}
sqlite3_free(*ppDirectory);
*ppDirectory = zCopy;
- return SQLITE_OK;
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_ERROR;
}
- return SQLITE_ERROR;
+set_directory8_done:
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
+ return rc;
}
/*
@@ -48278,6 +49794,19 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
}
/*
+** If sqlite3_temp_directory is defined, take the mutex and return true.
+**
+** If sqlite3_temp_directory is NULL (undefined), omit the mutex and
+** return false.
+*/
+static int winTempDirDefined(void){
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
+ if( sqlite3_temp_directory!=0 ) return 1;
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
+ return 0;
+}
+
+/*
** Create a temporary file name and store the resulting pointer into pzBuf.
** The pointer returned in pzBuf must be freed via sqlite3_free().
*/
@@ -48313,20 +49842,23 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
*/
nDir = nMax - (nPre + 15);
assert( nDir>0 );
- if( sqlite3_temp_directory ){
+ if( winTempDirDefined() ){
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
if( nDirLen>0 ){
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
nDirLen++;
}
if( nDirLen>nDir ){
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
}
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
}
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
}
+
#if defined(__CYGWIN__)
else{
static const char *azDirs[] = {
@@ -49115,7 +50647,7 @@ static BOOL winIsVerbatimPathname(
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
** bytes in size.
*/
-static int winFullPathname(
+static int winFullPathnameNoMutex(
sqlite3_vfs *pVfs, /* Pointer to vfs object */
const char *zRelative, /* Possibly relative input path */
int nFull, /* Size of output buffer in bytes */
@@ -49294,6 +50826,20 @@ static int winFullPathname(
}
#endif
}
+static int winFullPathname(
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */
+ const char *zRelative, /* Possibly relative input path */
+ int nFull, /* Size of output buffer in bytes */
+ char *zFull /* Output buffer */
+){
+ int rc;
+ MUTEX_LOGIC( sqlite3_mutex *pMutex; )
+ MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
+ sqlite3_mutex_enter(pMutex);
+ rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
+ sqlite3_mutex_leave(pMutex);
+ return rc;
+}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
@@ -49830,6 +51376,7 @@ static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
static int memdbSync(sqlite3_file*, int flags);
static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int memdbLock(sqlite3_file*, int);
+static int memdbUnlock(sqlite3_file*, int);
/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
static int memdbFileControl(sqlite3_file*, int op, void *pArg);
/* static int memdbSectorSize(sqlite3_file*); // not used */
@@ -49888,7 +51435,7 @@ static const sqlite3_io_methods memdb_io_methods = {
memdbSync, /* xSync */
memdbFileSize, /* xFileSize */
memdbLock, /* xLock */
- memdbLock, /* xUnlock - same as xLock in this case */
+ memdbUnlock, /* xUnlock */
0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
memdbFileControl, /* xFileControl */
0, /* memdbSectorSize,*/ /* xSectorSize */
@@ -50089,39 +51636,81 @@ static int memdbLock(sqlite3_file *pFile, int eLock){
MemFile *pThis = (MemFile*)pFile;
MemStore *p = pThis->pStore;
int rc = SQLITE_OK;
- if( eLock==pThis->eLock ) return SQLITE_OK;
+ if( eLock<=pThis->eLock ) return SQLITE_OK;
memdbEnter(p);
- if( eLock>SQLITE_LOCK_SHARED ){
- if( p->mFlags & SQLITE_DESERIALIZE_READONLY ){
- rc = SQLITE_READONLY;
- }else if( pThis->eLock<=SQLITE_LOCK_SHARED ){
- if( p->nWrLock ){
- rc = SQLITE_BUSY;
- }else{
- p->nWrLock = 1;
+
+ assert( p->nWrLock==0 || p->nWrLock==1 );
+ assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 );
+ assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 );
+
+ if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
+ rc = SQLITE_READONLY;
+ }else{
+ switch( eLock ){
+ case SQLITE_LOCK_SHARED: {
+ assert( pThis->eLock==SQLITE_LOCK_NONE );
+ if( p->nWrLock>0 ){
+ rc = SQLITE_BUSY;
+ }else{
+ p->nRdLock++;
+ }
+ break;
+ };
+
+ case SQLITE_LOCK_RESERVED:
+ case SQLITE_LOCK_PENDING: {
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
+ if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){
+ if( p->nWrLock>0 ){
+ rc = SQLITE_BUSY;
+ }else{
+ p->nWrLock = 1;
+ }
+ }
+ break;
+ }
+
+ default: {
+ assert( eLock==SQLITE_LOCK_EXCLUSIVE );
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
+ if( p->nRdLock>1 ){
+ rc = SQLITE_BUSY;
+ }else if( pThis->eLock==SQLITE_LOCK_SHARED ){
+ p->nWrLock = 1;
+ }
+ break;
}
}
- }else if( eLock==SQLITE_LOCK_SHARED ){
- if( pThis->eLock > SQLITE_LOCK_SHARED ){
- assert( p->nWrLock==1 );
- p->nWrLock = 0;
- }else if( p->nWrLock ){
- rc = SQLITE_BUSY;
- }else{
- p->nRdLock++;
+ }
+ if( rc==SQLITE_OK ) pThis->eLock = eLock;
+ memdbLeave(p);
+ return rc;
+}
+
+/*
+** Unlock an memdb-file.
+*/
+static int memdbUnlock(sqlite3_file *pFile, int eLock){
+ MemFile *pThis = (MemFile*)pFile;
+ MemStore *p = pThis->pStore;
+ if( eLock>=pThis->eLock ) return SQLITE_OK;
+ memdbEnter(p);
+
+ assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE );
+ if( eLock==SQLITE_LOCK_SHARED ){
+ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){
+ p->nWrLock--;
}
}else{
- assert( eLock==SQLITE_LOCK_NONE );
if( pThis->eLock>SQLITE_LOCK_SHARED ){
- assert( p->nWrLock==1 );
- p->nWrLock = 0;
+ p->nWrLock--;
}
- assert( p->nRdLock>0 );
p->nRdLock--;
}
- if( rc==SQLITE_OK ) pThis->eLock = eLock;
+
+ pThis->eLock = eLock;
memdbLeave(p);
- return rc;
+ return SQLITE_OK;
}
#if 0
@@ -50231,7 +51820,7 @@ static int memdbOpen(
memset(pFile, 0, sizeof(*pFile));
szName = sqlite3Strlen30(zName);
- if( szName>1 && zName[0]=='/' ){
+ if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){
int i;
#ifndef SQLITE_MUTEX_OMIT
sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
@@ -50579,6 +52168,13 @@ end_deserialize:
}
/*
+** Return true if the VFS is the memvfs.
+*/
+SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){
+ return pVfs==&memdb_vfs;
+}
+
+/*
** This routine is called when the extension is loaded.
** Register the new VFS.
*/
@@ -51082,12 +52678,20 @@ struct PCache {
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
- void pcacheDump(PCache *pCache){
- int N;
- int i, j;
- sqlite3_pcache_page *pLower;
+ static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
PgHdr *pPg;
unsigned char *a;
+ int j;
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
+ static void pcacheDump(PCache *pCache){
+ int N;
+ int i;
+ sqlite3_pcache_page *pLower;
if( sqlite3PcacheTrace<2 ) return;
if( pCache->pCache==0 ) return;
@@ -51096,22 +52700,33 @@ struct PCache {
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
if( pLower==0 ) continue;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf("\n");
- if( pPg->pPage==0 ){
+ pcachePageTrace(i, pLower);
+ if( ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
}
- #else
+#else
# define pcacheTrace(X)
+# define pcachePageTrace(PGNO, X)
# define pcacheDump(X)
#endif
/*
+** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
+** This routine runs inside of assert() statements only.
+*/
+#ifdef SQLITE_DEBUG
+static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
** Check invariants on a PgHdr entry. Return true if everything is OK.
** Return false if any invariant is violated.
**
@@ -51129,8 +52744,13 @@ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
assert( pCache!=0 ); /* Every page has an associated PCache */
if( pPg->flags & PGHDR_CLEAN ){
assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
- assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
- assert( pCache->pDirtyTail!=pPg );
+ assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
+ }else{
+ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
+ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
+ assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
+ assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
+ assert( pageOnDirtyList(pCache, pPg) );
}
/* WRITEABLE pages must also be DIRTY */
if( pPg->flags & PGHDR_WRITEABLE ){
@@ -51404,8 +53024,9 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
- pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
+ pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
createFlag?" create":"",pRes));
+ pcachePageTrace(pgno, pRes);
return pRes;
}
@@ -51533,6 +53154,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
pcacheUnpin(p);
}else{
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+ assert( sqlite3PcachePageSanity(p) );
}
}
}
@@ -51576,6 +53198,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
+ assert( sqlite3PcachePageSanity(p) );
}
assert( sqlite3PcachePageSanity(p) );
}
@@ -51638,14 +53261,24 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
*/
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
+ sqlite3_pcache_page *pOther;
assert( p->nRef>0 );
assert( newPgno>0 );
assert( sqlite3PcachePageSanity(p) );
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
+ pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
+ if( pOther ){
+ PgHdr *pXPage = (PgHdr*)pOther->pExtra;
+ assert( pXPage->nRef==0 );
+ pXPage->nRef++;
+ pCache->nRefSum++;
+ sqlite3PcacheDrop(pXPage);
+ }
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
+ assert( sqlite3PcachePageSanity(p) );
}
}
@@ -51943,12 +53576,13 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** size can vary according to architecture, compile-time options, and
** SQLite library version number.
**
-** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
-** using a separate memory allocation from the database page content. This
-** seeks to overcome the "clownshoe" problem (also called "internal
-** fragmentation" in academic literature) of allocating a few bytes more
-** than a power of two with the memory allocator rounding up to the next
-** power of two, and leaving the rounded-up space unused.
+** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER
+** was defined, then the page content would be held in a separate memory
+** allocation from the PgHdr1. This was intended to avoid clownshoe memory
+** allocations. However, the btree layer needs a small (16-byte) overrun
+** area after the page content buffer. The header serves as that overrun
+** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid
+** any possibility of a memory error.
**
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
** with this module. Information is passed back and forth as PgHdr1 pointers.
@@ -51993,30 +53627,40 @@ typedef struct PGroup PGroup;
/*
** Each cache entry is represented by an instance of the following
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
-** in memory.
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
+** directly before this structure and is used to cache the page content.
+**
+** When reading a corrupt database file, it is possible that SQLite might
+** read a few bytes (no more than 16 bytes) past the end of the page buffer.
+** It will only read past the end of the page buffer, never write. This
+** object is positioned immediately after the page buffer to serve as an
+** overrun area, so that overreads are harmless.
**
-** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
+** Variables isBulkLocal and isAnchor were once type "u8". That works,
** but causes a 2-byte gap in the structure for most architectures (since
** pointers must be either 4 or 8-byte aligned). As this structure is located
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
** can cause a valgrind error if the unitialized gap is accessed. Using u16
-** ensures there is no such gap, and therefore no bytes of unitialized memory
-** in the structure.
+** ensures there is no such gap, and therefore no bytes of uninitialized
+** memory in the structure.
+**
+** The pLruNext and pLruPrev pointers form a double-linked circular list
+** of all pages that are unpinned. The PGroup.lru element (which should be
+** the only element on the list with PgHdr1.isAnchor set to 1) forms the
+** beginning and the end of the list.
*/
struct PgHdr1 {
- sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
- unsigned int iKey; /* Key value (page number) */
- u16 isBulkLocal; /* This page from bulk local storage */
- u16 isAnchor; /* This is the PGroup.lru element */
- PgHdr1 *pNext; /* Next in hash table chain */
- PCache1 *pCache; /* Cache that currently owns this page */
- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
- /* NB: pLruPrev is only valid if pLruNext!=0 */
+ sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
+ unsigned int iKey; /* Key value (page number) */
+ u16 isBulkLocal; /* This page from bulk local storage */
+ u16 isAnchor; /* This is the PGroup.lru element */
+ PgHdr1 *pNext; /* Next in hash table chain */
+ PCache1 *pCache; /* Cache that currently owns this page */
+ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
+ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
+ /* NB: pLruPrev is only valid if pLruNext!=0 */
};
/*
@@ -52342,25 +53986,13 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
pcache1LeaveMutex(pCache->pGroup);
#endif
if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- pPg = pcache1Alloc(pCache->szPage);
- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
- if( !pPg || !p ){
- pcache1Free(pPg);
- sqlite3_free(p);
- pPg = 0;
- }
-#else
pPg = pcache1Alloc(pCache->szAlloc);
-#endif
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
pcache1EnterMutex(pCache->pGroup);
#endif
if( pPg==0 ) return 0;
-#ifndef SQLITE_PCACHE_SEPARATE_HEADER
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
-#endif
p->page.pBuf = pPg;
p->page.pExtra = &p[1];
p->isBulkLocal = 0;
@@ -52384,9 +54016,6 @@ static void pcache1FreePage(PgHdr1 *p){
pCache->pFree = p;
}else{
pcache1Free(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- sqlite3_free(p);
-#endif
}
(*pCache->pnPurgeable)--;
}
@@ -53027,23 +54656,26 @@ static void pcache1Rekey(
PCache1 *pCache = (PCache1 *)p;
PgHdr1 *pPage = (PgHdr1 *)pPg;
PgHdr1 **pp;
- unsigned int h;
+ unsigned int hOld, hNew;
assert( pPage->iKey==iOld );
assert( pPage->pCache==pCache );
+ assert( iOld!=iNew ); /* The page number really is changing */
pcache1EnterMutex(pCache->pGroup);
- h = iOld%pCache->nHash;
- pp = &pCache->apHash[h];
+ assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
+ hOld = iOld%pCache->nHash;
+ pp = &pCache->apHash[hOld];
while( (*pp)!=pPage ){
pp = &(*pp)->pNext;
}
*pp = pPage->pNext;
- h = iNew%pCache->nHash;
+ assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
+ hNew = iNew%pCache->nHash;
pPage->iKey = iNew;
- pPage->pNext = pCache->apHash[h];
- pCache->apHash[h] = pPage;
+ pPage->pNext = pCache->apHash[hNew];
+ pCache->apHash[hNew] = pPage;
if( iNew>pCache->iMaxKey ){
pCache->iMaxKey = iNew;
}
@@ -53150,9 +54782,6 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
&& p->isAnchor==0
){
nFree += pcache1MemSize(p->page.pBuf);
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
- nFree += sqlite3MemSize(p);
-#endif
assert( PAGE_IS_UNPINNED(p) );
pcache1PinPage(p);
pcache1RemoveFromHash(p, 1);
@@ -56790,7 +58419,7 @@ end_playback:
** see if it is possible to delete the super-journal.
*/
assert( zSuper==&pPager->pTmpSpace[4] );
- memset(&zSuper[-4], 0, 4);
+ memset(pPager->pTmpSpace, 0, 4);
rc = pager_delsuper(pPager, zSuper);
testcase( rc!=SQLITE_OK );
}
@@ -57411,7 +59040,6 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
SQLITE_PRIVATE void sqlite3PagerSetFlags(
Pager *pPager, /* The pager to set safety level for */
unsigned pgFlags /* Various flags */
@@ -57446,7 +59074,6 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
pPager->doNotSpill |= SPILLFLAG_OFF;
}
}
-#endif
/*
** The following global variable is incremented whenever the library
@@ -58548,7 +60175,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
const char *zUri = 0; /* URI args to copy */
int nUriByte = 1; /* Number of bytes of URI args at *zUri */
- int nUri = 0; /* Number of URI parameters */
/* Figure out how much space is required for each journal file-handle
** (there are two of them, the main journal and the sub-journal). */
@@ -58596,7 +60222,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
while( *z ){
z += strlen(z)+1;
z += strlen(z)+1;
- nUri++;
}
nUriByte = (int)(&z[1] - zUri);
assert( nUriByte>=1 );
@@ -58852,18 +60477,7 @@ act_like_temp_file:
pPager->memDb = (u8)memDb;
pPager->readOnly = (u8)readOnly;
assert( useJournal || pPager->tempFile );
- pPager->noSync = pPager->tempFile;
- if( pPager->noSync ){
- assert( pPager->fullSync==0 );
- assert( pPager->extraSync==0 );
- assert( pPager->syncFlags==0 );
- assert( pPager->walSyncFlags==0 );
- }else{
- pPager->fullSync = 1;
- pPager->extraSync = 0;
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
- }
+ sqlite3PagerSetFlags(pPager, (SQLITE_DEFAULT_SYNCHRONOUS+1)|PAGER_CACHESPILL);
/* pPager->pFirst = 0; */
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
@@ -59641,6 +61255,7 @@ static int pager_open_journal(Pager *pPager){
if( pPager->tempFile ){
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+ flags |= SQLITE_OPEN_EXCLUSIVE;
nSpill = sqlite3Config.nStmtSpill;
}else{
flags |= SQLITE_OPEN_MAIN_JOURNAL;
@@ -59676,6 +61291,7 @@ static int pager_open_journal(Pager *pPager){
if( rc!=SQLITE_OK ){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
+ pPager->journalOff = 0;
}else{
assert( pPager->eState==PAGER_WRITER_LOCKED );
pPager->eState = PAGER_WRITER_CACHEMOD;
@@ -60122,7 +61738,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
# define DIRECT_MODE isDirectMode
#endif
- if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
+ if( !pPager->changeCountDone && pPager->dbSize>0 ){
PgHdr *pPgHdr; /* Reference to page 1 */
assert( !pPager->tempFile && isOpen(pPager->fd) );
@@ -60862,7 +62478,11 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
*/
SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename;
+ if( nullIfMemDb && (pPager->memDb || sqlite3IsMemdb(pPager->pVfs)) ){
+ return &zFake[4];
+ }else{
+ return pPager->zFilename;
+ }
}
/*
@@ -66445,15 +68065,15 @@ struct BtCursor {
** So, this macro is defined instead.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
-#define ISAUTOVACUUM (pBt->autoVacuum)
+#define ISAUTOVACUUM(pBt) (pBt->autoVacuum)
#else
-#define ISAUTOVACUUM 0
+#define ISAUTOVACUUM(pBt) 0
#endif
/*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
+** This structure is passed around through all the PRAGMA integrity_check
+** checking routines in order to keep track of some global state information.
**
** The aRef[] array is allocated so that there is 1 bit for each page in
** the database. As the integrity-check proceeds, for each page used in
@@ -66469,7 +68089,8 @@ struct IntegrityCk {
Pgno nPage; /* Number of pages in the database */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
- int bOomFault; /* A memory allocation error has occurred */
+ int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
+ u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
Pgno v1; /* Value for first %u substitution in zPfx */
int v2; /* Value for second %d substitution in zPfx */
@@ -66739,6 +68360,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
Btree *p;
assert( db!=0 );
+ if( db->pVfs==0 && db->nDb==0 ) return 1;
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
assert( iDb>=0 && iDb<db->nDb );
if( !sqlite3_mutex_held(db->mutex) ) return 0;
@@ -68311,8 +69933,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- temp = 0;
- src = data = pPage->aData;
+ data = pPage->aData;
hdr = pPage->hdrOffset;
cellOffset = pPage->cellOffset;
nCell = pPage->nCell;
@@ -68346,7 +69967,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
- }else if( NEVER(iFree+sz>usableSize) ){
+ }else if( iFree+sz>usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -68366,39 +69987,38 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
cbrk = usableSize;
iCellLast = usableSize - 4;
iCellStart = get2byte(&data[hdr+5]);
- for(i=0; i<nCell; i++){
- u8 *pAddr; /* The i-th cell pointer */
- pAddr = &data[cellOffset + i*2];
- pc = get2byte(pAddr);
- testcase( pc==iCellFirst );
- testcase( pc==iCellLast );
- /* These conditions have already been verified in btreeInitPage()
- ** if PRAGMA cell_size_check=ON.
- */
- if( pc<iCellStart || pc>iCellLast ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( pc>=iCellStart && pc<=iCellLast );
- size = pPage->xCellSize(pPage, &src[pc]);
- cbrk -= size;
- if( cbrk<iCellStart || pc+size>usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
- }
- assert( cbrk+size<=usableSize && cbrk>=iCellStart );
- testcase( cbrk+size==usableSize );
- testcase( pc+size==usableSize );
- put2byte(pAddr, cbrk);
- if( temp==0 ){
- if( cbrk==pc ) continue;
- temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
- src = temp;
+ if( nCell>0 ){
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
+ memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
+ src = temp;
+ for(i=0; i<nCell; i++){
+ u8 *pAddr; /* The i-th cell pointer */
+ pAddr = &data[cellOffset + i*2];
+ pc = get2byte(pAddr);
+ testcase( pc==iCellFirst );
+ testcase( pc==iCellLast );
+ /* These conditions have already been verified in btreeInitPage()
+ ** if PRAGMA cell_size_check=ON.
+ */
+ if( pc<iCellStart || pc>iCellLast ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( pc>=iCellStart && pc<=iCellLast );
+ size = pPage->xCellSize(pPage, &src[pc]);
+ cbrk -= size;
+ if( cbrk<iCellStart || pc+size>usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ assert( cbrk+size<=usableSize && cbrk>=iCellStart );
+ testcase( cbrk+size==usableSize );
+ testcase( pc+size==usableSize );
+ put2byte(pAddr, cbrk);
+ memcpy(&data[cbrk], &src[pc], size);
}
- memcpy(&data[cbrk], &src[pc], size);
}
data[hdr+7] = 0;
- defragment_out:
+defragment_out:
assert( pPage->nFree>=0 );
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
return SQLITE_CORRUPT_PAGE(pPage);
@@ -68455,7 +70075,6 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** fragmented bytes within the page. */
memcpy(&aData[iAddr], &aData[pc], 2);
aData[hdr+7] += (u8)x;
- testcase( pc+x>maxPC );
return &aData[pc];
}else if( x+pc > maxPC ){
/* This slot extends off the end of the usable part of the page */
@@ -68471,9 +70090,9 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
iAddr = pc;
pTmp = &aData[pc];
pc = get2byte(pTmp);
- if( pc<=iAddr+size ){
+ if( pc<=iAddr ){
if( pc ){
- /* The next slot in the chain is not past the end of the current slot */
+ /* The next slot in the chain comes before the current slot */
*pRc = SQLITE_CORRUPT_PAGE(pPg);
}
return 0;
@@ -68625,7 +70244,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
- if( iFreeBlk<iPtr+4 ){
+ if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -68701,62 +70320,67 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
** Only the following combinations are supported. Anything different
** indicates a corrupt database files:
**
-** PTF_ZERODATA
-** PTF_ZERODATA | PTF_LEAF
-** PTF_LEAFDATA | PTF_INTKEY
-** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
+** PTF_ZERODATA (0x02, 2)
+** PTF_LEAFDATA | PTF_INTKEY (0x05, 5)
+** PTF_ZERODATA | PTF_LEAF (0x0a, 10)
+** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13)
*/
static int decodeFlags(MemPage *pPage, int flagByte){
BtShared *pBt; /* A copy of pPage->pBt */
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
- flagByte &= ~PTF_LEAF;
- pPage->childPtrSize = 4-4*pPage->leaf;
pBt = pPage->pBt;
- if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
- /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
- ** interior table b-tree page. */
- assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
- /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
- ** leaf table b-tree page. */
- assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
- pPage->intKey = 1;
- if( pPage->leaf ){
+ pPage->max1bytePayload = pBt->max1bytePayload;
+ if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){
+ pPage->childPtrSize = 0;
+ pPage->leaf = 1;
+ if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){
pPage->intKeyLeaf = 1;
pPage->xCellSize = cellSizePtrTableLeaf;
pPage->xParseCell = btreeParseCellPtr;
+ pPage->intKey = 1;
+ pPage->maxLocal = pBt->maxLeaf;
+ pPage->minLocal = pBt->minLeaf;
+ }else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ pPage->maxLocal = pBt->maxLocal;
+ pPage->minLocal = pBt->minLocal;
}else{
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
+ }else{
+ pPage->childPtrSize = 4;
+ pPage->leaf = 0;
+ if( flagByte==(PTF_ZERODATA) ){
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ pPage->maxLocal = pBt->maxLocal;
+ pPage->minLocal = pBt->minLocal;
+ }else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
pPage->intKeyLeaf = 0;
pPage->xCellSize = cellSizePtrNoPayload;
pPage->xParseCell = btreeParseCellPtrNoPayload;
+ pPage->intKey = 1;
+ pPage->maxLocal = pBt->maxLeaf;
+ pPage->minLocal = pBt->minLeaf;
+ }else{
+ pPage->intKey = 0;
+ pPage->intKeyLeaf = 0;
+ pPage->xCellSize = cellSizePtr;
+ pPage->xParseCell = btreeParseCellPtrIndex;
+ return SQLITE_CORRUPT_PAGE(pPage);
}
- pPage->maxLocal = pBt->maxLeaf;
- pPage->minLocal = pBt->minLeaf;
- }else if( flagByte==PTF_ZERODATA ){
- /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
- ** interior index b-tree page. */
- assert( (PTF_ZERODATA)==2 );
- /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
- ** leaf index b-tree page. */
- assert( (PTF_ZERODATA|PTF_LEAF)==10 );
- pPage->intKey = 0;
- pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
- pPage->xParseCell = btreeParseCellPtrIndex;
- pPage->maxLocal = pBt->maxLocal;
- pPage->minLocal = pBt->minLocal;
- }else{
- /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
- ** an error. */
- pPage->intKey = 0;
- pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
- pPage->xParseCell = btreeParseCellPtrIndex;
- return SQLITE_CORRUPT_PAGE(pPage);
}
- pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
}
@@ -69107,9 +70731,7 @@ getAndInitPage_error1:
pCur->pPage = pCur->apPage[pCur->iPage];
}
testcase( pgno==0 );
- assert( pgno!=0 || rc==SQLITE_CORRUPT
- || rc==SQLITE_IOERR_NOMEM
- || rc==SQLITE_NOMEM );
+ assert( pgno!=0 || rc!=SQLITE_OK );
return rc;
}
@@ -70545,6 +72167,9 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}
}else{
+ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
+ }
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
break;
@@ -72051,8 +73676,6 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
- BtShared *pBt = pCur->pBt;
-
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -72066,7 +73689,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
+ return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
+ pCur->curPagerFlags);
}
#ifdef SQLITE_DEBUG
@@ -72172,7 +73796,7 @@ static int moveToRoot(BtCursor *pCur){
}
sqlite3BtreeClearCursor(pCur);
}
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
+ rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
@@ -72296,9 +73920,25 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
*/
+static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){
+ int rc = moveToRoot(pCur);
+ if( rc==SQLITE_OK ){
+ assert( pCur->eState==CURSOR_VALID );
+ *pRes = 0;
+ rc = moveToRightmost(pCur);
+ if( rc==SQLITE_OK ){
+ pCur->curFlags |= BTCF_AtLast;
+ }else{
+ pCur->curFlags &= ~BTCF_AtLast;
+ }
+ }else if( rc==SQLITE_EMPTY ){
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ *pRes = 1;
+ rc = SQLITE_OK;
+ }
+ return rc;
+}
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
- int rc;
-
assert( cursorOwnsBtShared(pCur) );
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
@@ -72319,23 +73959,7 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
*pRes = 0;
return SQLITE_OK;
}
-
- rc = moveToRoot(pCur);
- if( rc==SQLITE_OK ){
- assert( pCur->eState==CURSOR_VALID );
- *pRes = 0;
- rc = moveToRightmost(pCur);
- if( rc==SQLITE_OK ){
- pCur->curFlags |= BTCF_AtLast;
- }else{
- pCur->curFlags &= ~BTCF_AtLast;
- }
- }else if( rc==SQLITE_EMPTY ){
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
- *pRes = 1;
- rc = SQLITE_OK;
- }
- return rc;
+ return btreeLast(pCur, pRes);
}
/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
@@ -72880,14 +74504,7 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( !pPage->isInit || sqlite3FaultSim(412) ){
- /* The only known way for this to happen is for there to be a
- ** recursive SQL function that does a DELETE operation as part of a
- ** SELECT which deletes content out from under an active cursor
- ** in a corrupt database file where the table being DELETE-ed from
- ** has pages in common with the table being queried. See TH3
- ** module cov1/btree78.test testcase 220 (2018-06-08) for an
- ** example. */
+ if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -73063,8 +74680,8 @@ static int allocateBtreePage(
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
pPage1 = pBt->pPage1;
mxPage = btreePagecount(pBt);
- /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
- ** stores stores the total number of pages on the freelist. */
+ /* EVIDENCE-OF: R-21003-45125 The 4-byte big-endian integer at offset 36
+ ** stores the total number of pages on the freelist. */
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -73409,7 +75026,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the database supports auto-vacuum, write an entry in the pointer-map
** to indicate that the page is free.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
if( rc ) goto freepage_out;
}
@@ -73813,12 +75430,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
assert( pPage->pBt->usableSize > (u32)(ptr-data) );
pc = get2byte(ptr);
hdr = pPage->hdrOffset;
-#if 0 /* Not required. Omit for efficiency */
- if( pc<hdr+pPage->nCell*2 ){
- *pRC = SQLITE_CORRUPT_BKPT;
- return;
- }
-#endif
testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
@@ -73855,24 +75466,20 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
-**
-** *pRC must be SQLITE_OK when this routine is called.
*/
-static void insertCell(
+static int insertCell(
MemPage *pPage, /* Page into which we are copying */
int i, /* New cell becomes the i-th cell of the page */
u8 *pCell, /* Content of the new cell */
int sz, /* Bytes of content in pCell */
u8 *pTemp, /* Temp storage space for pCell, if needed */
- Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
- int *pRC /* Read and write return code from here */
+ Pgno iChild /* If non-zero, replace first 4 bytes with this value */
){
int idx = 0; /* Where to write new cell content in data[] */
int j; /* Loop counter */
u8 *data; /* The content of the whole page */
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
- assert( *pRC==SQLITE_OK );
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
@@ -73907,14 +75514,13 @@ static void insertCell(
}else{
int rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc!=SQLITE_OK ){
- *pRC = rc;
- return;
+ return rc;
}
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
rc = allocateSpace(pPage, sz, &idx);
- if( rc ){ *pRC = rc; return; }
+ if( rc ){ return rc; }
/* The allocateSpace() routine guarantees the following properties
** if it returns successfully */
assert( idx >= 0 );
@@ -73941,13 +75547,16 @@ static void insertCell(
assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
/* The cell may contain a pointer to an overflow page. If so, write
** the entry for the overflow page into the pointer map.
*/
- ptrmapPutOvflPtr(pPage, pPage, pCell, pRC);
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
}
#endif
}
+ return SQLITE_OK;
}
/*
@@ -74048,14 +75657,16 @@ struct CellArray {
** computed.
*/
static void populateCellCache(CellArray *p, int idx, int N){
+ MemPage *pRef = p->pRef;
+ u16 *szCell = p->szCell;
assert( idx>=0 && idx+N<=p->nCell );
while( N>0 ){
assert( p->apCell[idx]!=0 );
- if( p->szCell[idx]==0 ){
- p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
+ if( szCell[idx]==0 ){
+ szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]);
}else{
assert( CORRUPT_DB ||
- p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
+ szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) );
}
idx++;
N--;
@@ -74257,8 +75868,8 @@ static int pageFreeArray(
int nRet = 0;
int i;
int iEnd = iFirst + nCell;
- u8 *pFree = 0;
- int szFree = 0;
+ u8 *pFree = 0; /* \__ Parameters for pending call to */
+ int szFree = 0; /* / freeSpace() */
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
@@ -74279,6 +75890,9 @@ static int pageFreeArray(
return 0;
}
}else{
+ /* The current cell is adjacent to and before the pFree cell.
+ ** Combine the two regions into one to reduce the number of calls
+ ** to freeSpace(). */
pFree = pCell;
szFree += sz;
}
@@ -74486,7 +76100,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
** be marked as dirty. Returning an error code will cause a
** rollback, undoing any changes made to the parent page.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
if( szCell>pNew->minLocal ){
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
@@ -74514,8 +76128,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
/* Insert the new divider cell into pParent. */
if( rc==SQLITE_OK ){
- insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
- 0, pPage->pgno, &rc);
+ rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
+ 0, pPage->pgno);
}
/* Set the right-child pointer of pParent to point to the new page. */
@@ -74624,7 +76238,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
/* If this is an auto-vacuum database, update the pointer-map entries
** for any b-tree or overflow pages that pTo now contains the pointers to.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
*pRC = setChildPtrmaps(pTo);
}
}
@@ -74702,8 +76316,6 @@ static int balance_nonroot(
Pgno pgno; /* Temp var to store a page number in */
u8 abDone[NB+2]; /* True after i'th new page is populated */
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
- Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
- u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
CellArray b; /* Parsed information on cells being balanced */
memset(abDone, 0, sizeof(abDone));
@@ -75050,15 +76662,17 @@ static int balance_nonroot(
d = r + 1 - leafData;
(void)cachedCellSize(&b, d);
do{
+ int szR, szD;
assert( d<nMaxCells );
assert( r<nMaxCells );
- (void)cachedCellSize(&b, r);
+ szR = cachedCellSize(&b, r);
+ szD = b.szCell[d];
if( szRight!=0
- && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
+ && (bBulk || szRight+szD+2 > szLeft-(szR+(i==k-1?0:2)))){
break;
}
- szRight += b.szCell[d] + 2;
- szLeft -= b.szCell[r] + 2;
+ szRight += szD + 2;
+ szLeft -= szR + 2;
cntNew[i-1] = r;
r--;
d--;
@@ -75112,7 +76726,7 @@ static int balance_nonroot(
cntOld[i] = b.nCell;
/* Set the pointer-map entry for the new sibling page. */
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
if( rc!=SQLITE_OK ){
goto balance_cleanup;
@@ -75127,42 +76741,39 @@ static int balance_nonroot(
** of the table is closer to a linear scan through the file. That in turn
** helps the operating system to deliver pages from the disk more rapidly.
**
- ** An O(n^2) insertion sort algorithm is used, but since n is never more
- ** than (NB+2) (a small constant), that should not be a problem.
+ ** An O(N*N) sort algorithm is used, but since N is never more than NB+2
+ ** (5), that is not a performance concern.
**
** When NB==3, this one optimization makes the database about 25% faster
** for large insertions and deletions.
*/
for(i=0; i<nNew; i++){
- aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
- aPgFlags[i] = apNew[i]->pDbPage->flags;
- for(j=0; j<i; j++){
- if( NEVER(aPgno[j]==aPgno[i]) ){
- /* This branch is taken if the set of sibling pages somehow contains
- ** duplicate entries. This can happen if the database is corrupt.
- ** It would be simpler to detect this as part of the loop below, but
- ** we do the detection here in order to avoid populating the pager
- ** cache with two separate objects associated with the same
- ** page number. */
- assert( CORRUPT_DB );
- rc = SQLITE_CORRUPT_BKPT;
- goto balance_cleanup;
- }
- }
+ aPgno[i] = apNew[i]->pgno;
+ assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
+ assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
}
- for(i=0; i<nNew; i++){
- int iBest = 0; /* aPgno[] index of page number to use */
- for(j=1; j<nNew; j++){
- if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
+ for(i=0; i<nNew-1; i++){
+ int iB = i;
+ for(j=i+1; j<nNew; j++){
+ if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
}
- pgno = aPgOrder[iBest];
- aPgOrder[iBest] = 0xffffffff;
- if( iBest!=i ){
- if( iBest>i ){
- sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
- }
- sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
- apNew[i]->pgno = pgno;
+
+ /* If apNew[i] has a page number that is bigger than any of the
+ ** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
+ ** entry that has the smallest page number (which we know to be
+ ** entry apNew[iB]).
+ */
+ if( iB!=i ){
+ Pgno pgnoA = apNew[i]->pgno;
+ Pgno pgnoB = apNew[iB]->pgno;
+ Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
+ u16 fgA = apNew[i]->pDbPage->flags;
+ u16 fgB = apNew[iB]->pDbPage->flags;
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
+ sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
+ apNew[i]->pgno = pgnoB;
+ apNew[iB]->pgno = pgnoA;
}
}
@@ -75208,7 +76819,7 @@ static int balance_nonroot(
** updated. This happens below, after the sibling pages have been
** populated, not here.
*/
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
MemPage *pOld;
MemPage *pNew = pOld = apNew[0];
int cntOldNext = pNew->nCell + pNew->nOverflow;
@@ -75305,7 +76916,7 @@ static int balance_nonroot(
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
- insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
+ rc = insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno);
if( rc!=SQLITE_OK ) goto balance_cleanup;
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
}
@@ -75401,7 +77012,7 @@ static int balance_nonroot(
);
copyNodeContent(apNew[0], pParent, &rc);
freePage(apNew[0], &rc);
- }else if( ISAUTOVACUUM && !leafCorrection ){
+ }else if( ISAUTOVACUUM(pBt) && !leafCorrection ){
/* Fix the pointer map entries associated with the right-child of each
** sibling page. All other pointer map entries have already been taken
** care of. */
@@ -75422,7 +77033,7 @@ static int balance_nonroot(
}
#if 0
- if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
+ if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){
/* The ptrmapCheckPages() contains assert() statements that verify that
** all pointer map pages are set correctly. This is helpful while
** debugging. This is usually disabled because a corrupt database may
@@ -75484,7 +77095,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
if( rc==SQLITE_OK ){
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
copyNodeContent(pRoot, pChild, &rc);
- if( ISAUTOVACUUM ){
+ if( ISAUTOVACUUM(pBt) ){
ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
}
}
@@ -75588,6 +77199,11 @@ static int balance(BtCursor *pCur){
}else{
break;
}
+ }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){
+ /* The page being written is not a root page, and there is currently
+ ** more than one reference to it. This only happens if the page is one
+ ** of its own ancestor pages. Corruption. */
+ rc = SQLITE_CORRUPT_BKPT;
}else{
MemPage * const pParent = pCur->apPage[iPage-1];
int const iIdx = pCur->aiIdx[iPage-1];
@@ -75718,9 +77334,13 @@ static int btreeOverwriteContent(
/*
** Overwrite the cell that cursor pCur is pointing to with fresh content
-** contained in pX.
+** contained in pX. In this variant, pCur is pointing to an overflow
+** cell.
*/
-static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
+static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
+ BtCursor *pCur, /* Cursor pointing to cell to ovewrite */
+ const BtreePayload *pX /* Content to write into the cell */
+){
int iOffset; /* Next byte of pX->pData to write */
int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
int rc; /* Return code */
@@ -75729,16 +77349,12 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
Pgno ovflPgno; /* Next overflow page to write */
u32 ovflPageSize; /* Size to write on overflow page */
- if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
- || pCur->info.pPayload < pPage->aData + pPage->cellOffset
- ){
- return SQLITE_CORRUPT_BKPT;
- }
+ assert( pCur->info.nLocal<nTotal ); /* pCur is an overflow cell */
+
/* Overwrite the local portion first */
rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
0, pCur->info.nLocal);
if( rc ) return rc;
- if( pCur->info.nLocal==nTotal ) return SQLITE_OK;
/* Now overwrite the overflow pages */
iOffset = pCur->info.nLocal;
@@ -75768,6 +77384,29 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
return SQLITE_OK;
}
+/*
+** Overwrite the cell that cursor pCur is pointing to with fresh content
+** contained in pX.
+*/
+static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
+ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
+ MemPage *pPage = pCur->pPage; /* Page being written */
+
+ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
+ || pCur->info.pPayload < pPage->aData + pPage->cellOffset
+ ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ if( pCur->info.nLocal==nTotal ){
+ /* The entire cell is local */
+ return btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
+ 0, pCur->info.nLocal);
+ }else{
+ /* The cell contains overflow content */
+ return btreeOverwriteOverflowCell(pCur, pX);
+ }
+}
+
/*
** Insert a new record into the BTree. The content of the new record
@@ -75811,7 +77450,6 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
int idx;
MemPage *pPage;
Btree *p = pCur->pBtree;
- BtShared *pBt = p->pBt;
unsigned char *oldCell;
unsigned char *newCell = 0;
@@ -75830,7 +77468,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** not to clear the cursor here.
*/
if( pCur->curFlags & BTCF_Multiple ){
- rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
+ rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur);
if( rc ) return rc;
if( loc && pCur->iPage<0 ){
/* This can only happen if the schema is corrupt such that there is more
@@ -75854,8 +77492,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( cursorOwnsBtShared(pCur) );
assert( (pCur->curFlags & BTCF_WriteFlag)!=0
- && pBt->inTransaction==TRANS_WRITE
- && (pBt->btsFlags & BTS_READ_ONLY)==0 );
+ && p->pBt->inTransaction==TRANS_WRITE
+ && (p->pBt->btsFlags & BTS_READ_ONLY)==0 );
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
/* Assert that the caller has been consistent. If this cursor was opened
@@ -75972,26 +77610,28 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
- newCell = pBt->pTmpSpace;
+ newCell = p->pBt->pTmpSpace;
assert( newCell!=0 );
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
- szNew = pBt->nPreformatSize;
+ szNew = p->pBt->nPreformatSize;
if( szNew<4 ) szNew = 4;
- if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
+ if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
if( info.nPayload!=info.nLocal ){
Pgno ovfl = get4byte(&newCell[szNew-4]);
- ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
+ ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
+ if( NEVER(rc) ) goto end_insert;
}
}
}else{
rc = fillInCell(pPage, newCell, pX, &szNew);
+ if( rc ) goto end_insert;
}
- if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
- assert( szNew <= MX_CELL_SIZE(pBt) );
+ assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
if( loc==0 ){
CellInfo info;
@@ -76011,7 +77651,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
testcase( pCur->curFlags & BTCF_ValidOvfl );
invalidateOverflowCache(pCur);
if( info.nSize==szNew && info.nLocal==info.nPayload
- && (!ISAUTOVACUUM || szNew<pPage->minLocal)
+ && (!ISAUTOVACUUM(p->pBt) || szNew<pPage->minLocal)
){
/* Overwrite the old cell with the new if they are the same size.
** We could also try to do this if the old cell is smaller, then add
@@ -76041,7 +77681,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}else{
assert( pPage->leaf );
}
- insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
+ rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -76114,7 +77754,6 @@ end_insert:
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
- int rc = SQLITE_OK;
BtShared *pBt = pDest->pBt;
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
const u8 *aIn; /* Pointer to next input buffer */
@@ -76137,7 +77776,9 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
memcpy(aOut, aIn, nIn);
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
+ return SQLITE_OK;
}else{
+ int rc = SQLITE_OK;
Pager *pSrcPager = pSrc->pBt->pPager;
u8 *pPgnoOut = 0;
Pgno ovflIn = 0;
@@ -76189,7 +77830,7 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
MemPage *pNew = 0;
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
put4byte(pPgnoOut, pgnoNew);
- if( ISAUTOVACUUM && pPageOut ){
+ if( ISAUTOVACUUM(pBt) && pPageOut ){
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
}
releasePage(pPageOut);
@@ -76205,9 +77846,8 @@ SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64
releasePage(pPageOut);
sqlite3PagerUnref(pPageIn);
+ return rc;
}
-
- return rc;
}
/*
@@ -76362,7 +78002,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
if( rc==SQLITE_OK ){
- insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
+ rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
}
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;
@@ -76962,6 +78602,41 @@ SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
/*
+** Record an OOM error during integrity_check
+*/
+static void checkOom(IntegrityCk *pCheck){
+ pCheck->rc = SQLITE_NOMEM;
+ pCheck->mxErr = 0; /* Causes integrity_check processing to stop */
+ if( pCheck->nErr==0 ) pCheck->nErr++;
+}
+
+/*
+** Invoke the progress handler, if appropriate. Also check for an
+** interrupt.
+*/
+static void checkProgress(IntegrityCk *pCheck){
+ sqlite3 *db = pCheck->db;
+ if( AtomicLoad(&db->u1.isInterrupted) ){
+ pCheck->rc = SQLITE_INTERRUPT;
+ pCheck->nErr++;
+ pCheck->mxErr = 0;
+ }
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ if( db->xProgress ){
+ assert( db->nProgressOps>0 );
+ pCheck->nStep++;
+ if( (pCheck->nStep % db->nProgressOps)==0
+ && db->xProgress(db->pProgressArg)
+ ){
+ pCheck->rc = SQLITE_INTERRUPT;
+ pCheck->nErr++;
+ pCheck->mxErr = 0;
+ }
+ }
+#endif
+}
+
+/*
** Append a message to the error message string.
*/
static void checkAppendMsg(
@@ -76970,6 +78645,7 @@ static void checkAppendMsg(
...
){
va_list ap;
+ checkProgress(pCheck);
if( !pCheck->mxErr ) return;
pCheck->mxErr--;
pCheck->nErr++;
@@ -76983,7 +78659,7 @@ static void checkAppendMsg(
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
- pCheck->bOomFault = 1;
+ checkOom(pCheck);
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -77025,7 +78701,6 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
return 1;
}
- if( AtomicLoad(&pCheck->db->u1.isInterrupted) ) return 1;
setPageReferenced(pCheck, iPage);
return 0;
}
@@ -77048,7 +78723,7 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->bOomFault = 1;
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
return;
}
@@ -77155,7 +78830,9 @@ static void checkList(
** lower 16 bits are the index of the last byte of that range.
*/
static void btreeHeapInsert(u32 *aHeap, u32 x){
- u32 j, i = ++aHeap[0];
+ u32 j, i;
+ assert( aHeap!=0 );
+ i = ++aHeap[0];
aHeap[i] = x;
while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
x = aHeap[j];
@@ -77232,6 +78909,8 @@ static int checkTreePage(
/* Check that the page exists
*/
+ checkProgress(pCheck);
+ if( pCheck->mxErr==0 ) goto end_of_check;
pBt = pCheck->pBt;
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
@@ -77477,13 +79156,14 @@ end_of_check:
** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
** checks are still performed.
*/
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
+SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
sqlite3 *db, /* Database connection that is running the check */
Btree *p, /* The btree to be checked */
Pgno *aRoot, /* An array of root pages numbers for individual trees */
int nRoot, /* Number of entries in aRoot[] */
int mxErr, /* Stop reporting errors after this many */
- int *pnErr /* Write number of errors seen to this variable */
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
+ char **pzOut /* OUT: Write the error message string here */
){
Pgno i;
IntegrityCk sCheck;
@@ -77506,18 +79186,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
assert( nRef>=0 );
+ memset(&sCheck, 0, sizeof(sCheck));
sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
- sCheck.nErr = 0;
- sCheck.bOomFault = 0;
- sCheck.zPfx = 0;
- sCheck.v1 = 0;
- sCheck.v2 = 0;
- sCheck.aPgRef = 0;
- sCheck.heap = 0;
sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
if( sCheck.nPage==0 ){
@@ -77526,12 +79200,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
if( !sCheck.aPgRef ){
- sCheck.bOomFault = 1;
+ checkOom(&sCheck);
goto integrity_ck_cleanup;
}
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
if( sCheck.heap==0 ){
- sCheck.bOomFault = 1;
+ checkOom(&sCheck);
goto integrity_ck_cleanup;
}
@@ -77612,16 +79286,17 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
integrity_ck_cleanup:
sqlite3PageFree(sCheck.heap);
sqlite3_free(sCheck.aPgRef);
- if( sCheck.bOomFault ){
+ *pnErr = sCheck.nErr;
+ if( sCheck.nErr==0 ){
sqlite3_str_reset(&sCheck.errMsg);
- sCheck.nErr++;
+ *pzOut = 0;
+ }else{
+ *pzOut = sqlite3StrAccumFinish(&sCheck.errMsg);
}
- *pnErr = sCheck.nErr;
- if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg);
/* Make sure this analysis did not leave any unref() pages. */
assert( nRef==sqlite3PagerRefcount(pBt->pPager) );
sqlite3BtreeLeave(p);
- return sqlite3StrAccumFinish(&sCheck.errMsg);
+ return sCheck.rc;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -77886,6 +79561,17 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
*/
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
+/*
+** If no transaction is active and the database is not a temp-db, clear
+** the in-memory pager cache.
+*/
+SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree *p){
+ BtShared *pBt = p->pBt;
+ if( pBt->inTransaction==TRANS_NONE ){
+ sqlite3PagerClearCache(pBt->pPager);
+ }
+}
+
#if !defined(SQLITE_OMIT_SHARED_CACHE)
/*
** Return true if the Btree passed as the only argument is sharable.
@@ -78796,9 +80482,9 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
i64 x;
assert( (p->flags&MEM_Int)*2==sizeof(x) );
memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
- sqlite3Int64ToText(x, zBuf);
+ p->n = sqlite3Int64ToText(x, zBuf);
#else
- sqlite3Int64ToText(p->u.i, zBuf);
+ p->n = sqlite3Int64ToText(p->u.i, zBuf);
#endif
}else{
sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
@@ -78806,6 +80492,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
(p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
assert( acc.zText==zBuf && acc.mxAlloc<=0 );
zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
+ p->n = acc.nChar;
}
}
@@ -78833,6 +80520,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
** This routine is for use inside of assert() statements only.
*/
SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
+ Mem tmp;
char zBuf[100];
char *z;
int i, j, incr;
@@ -78849,7 +80537,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 );
}
if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1;
- vdbeMemRenderNum(sizeof(zBuf), zBuf, p);
+ memcpy(&tmp, p, sizeof(tmp));
+ vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp);
z = p->z;
i = j = 0;
incr = 1;
@@ -79118,7 +80807,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- pMem->n = sqlite3Strlen30NN(pMem->z);
+ assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -79358,32 +81047,35 @@ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
}
/*
-** The MEM structure is already a MEM_Real. Try to also make it a
-** MEM_Int if we can.
+** The MEM structure is already a MEM_Real or MEM_IntReal. Try to
+** make it a MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
- i64 ix;
assert( pMem!=0 );
- assert( pMem->flags & MEM_Real );
+ assert( pMem->flags & (MEM_Real|MEM_IntReal) );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
- ix = doubleToInt64(pMem->u.r);
-
- /* Only mark the value as an integer if
- **
- ** (1) the round-trip conversion real->int->real is a no-op, and
- ** (2) The integer is neither the largest nor the smallest
- ** possible integer (ticket #3922)
- **
- ** The second and third terms in the following conditional enforces
- ** the second condition under the assumption that addition overflow causes
- ** values to wrap around.
- */
- if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
- pMem->u.i = ix;
+ if( pMem->flags & MEM_IntReal ){
MemSetTypeFlag(pMem, MEM_Int);
+ }else{
+ i64 ix = doubleToInt64(pMem->u.r);
+
+ /* Only mark the value as an integer if
+ **
+ ** (1) the round-trip conversion real->int->real is a no-op, and
+ ** (2) The integer is neither the largest nor the smallest
+ ** possible integer (ticket #3922)
+ **
+ ** The second and third terms in the following conditional enforces
+ ** the second condition under the assumption that addition overflow causes
+ ** values to wrap around.
+ */
+ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
+ pMem->u.i = ix;
+ MemSetTypeFlag(pMem, MEM_Int);
+ }
}
}
@@ -79431,6 +81123,16 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
&& i >= -2251799813685248LL && i < 2251799813685248LL);
}
+/* Convert a floating point value to its closest integer. Do so in
+** a way that avoids 'outside the range of representable values' warnings
+** from UBSAN.
+*/
+SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
+ if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
+ if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
+ return (i64)r;
+}
+
/*
** Convert pMem so that it has type MEM_Real or MEM_Int.
** Invalidate any prior representations.
@@ -79452,7 +81154,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
- || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r))
+ || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
){
pMem->u.i = ix;
MemSetTypeFlag(pMem, MEM_Int);
@@ -79504,6 +81206,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
+ if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
return sqlite3VdbeChangeEncoding(pMem, encoding);
}
}
@@ -80173,8 +81876,6 @@ static int valueFromFunction(
goto value_from_function_out;
}
- testcase( pCtx->pParse->rc==SQLITE_ERROR );
- testcase( pCtx->pParse->rc==SQLITE_OK );
memset(&ctx, 0, sizeof(ctx));
ctx.pOut = pVal;
ctx.pFunc = pFunc;
@@ -80186,17 +81887,22 @@ static int valueFromFunction(
}else{
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
+ assert( enc==pVal->enc
+ || (pVal->flags & MEM_Str)==0
+ || db->mallocFailed );
+#if 0 /* Not reachable except after a prior failure */
rc = sqlite3VdbeChangeEncoding(pVal, enc);
if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
+#endif
}
- pCtx->pParse->rc = rc;
value_from_function_out:
if( rc!=SQLITE_OK ){
pVal = 0;
+ pCtx->pParse->rc = rc;
}
if( apVal ){
for(i=0; i<nVal; i++){
@@ -80639,6 +82345,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
return p->n;
}
+ if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){
+ return p->n;
+ }
if( (p->flags & MEM_Blob)!=0 ){
if( p->flags & MEM_Zero ){
return p->n + p->u.nZero;
@@ -80684,10 +82393,10 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
- db->pVdbe->pPrev = p;
+ db->pVdbe->ppVPrev = &p->pVNext;
}
- p->pNext = db->pVdbe;
- p->pPrev = 0;
+ p->pVNext = db->pVdbe;
+ p->ppVPrev = &db->pVdbe;
db->pVdbe = p;
assert( p->eVdbeState==VDBE_INIT_STATE );
p->pParse = pParse;
@@ -80769,21 +82478,28 @@ SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(
#endif
/*
-** Swap all content between two VDBE structures.
+** Swap byte-code between two VDBE structures.
+**
+** This happens after pB was previously run and returned
+** SQLITE_SCHEMA. The statement was then reprepared in pA.
+** This routine transfers the new bytecode in pA over to pB
+** so that pB can be run again. The old pB byte code is
+** moved back to pA so that it will be cleaned up when pA is
+** finalized.
*/
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
- Vdbe tmp, *pTmp;
+ Vdbe tmp, *pTmp, **ppTmp;
char *zTmp;
assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
- pTmp = pA->pNext;
- pA->pNext = pB->pNext;
- pB->pNext = pTmp;
- pTmp = pA->pPrev;
- pA->pPrev = pB->pPrev;
- pB->pPrev = pTmp;
+ pTmp = pA->pVNext;
+ pA->pVNext = pB->pVNext;
+ pB->pVNext = pTmp;
+ ppTmp = pA->ppVPrev;
+ pA->ppVPrev = pB->ppVPrev;
+ pB->ppVPrev = ppTmp;
zTmp = pA->zSql;
pA->zSql = pB->zSql;
pB->zSql = zTmp;
@@ -80859,6 +82575,8 @@ static int growOpArray(Vdbe *v, int nOp){
*/
static void test_addop_breakpoint(int pc, Op *pOp){
static int n = 0;
+ (void)pc;
+ (void)pOp;
n++;
}
#endif
@@ -80909,16 +82627,16 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
#ifdef SQLITE_DEBUG
if( p->db->flags & SQLITE_VdbeAddopTrace ){
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
test_addop_breakpoint(i, &p->aOp[i]);
}
#endif
-#ifdef VDBE_PROFILE
- pOp->cycles = 0;
- pOp->cnt = 0;
-#endif
#ifdef SQLITE_VDBE_COVERAGE
pOp->iSrcLine = 0;
#endif
@@ -81035,6 +82753,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
+ sqlite3MayAbort(pParse);
return addr;
}
@@ -81085,8 +82804,9 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
** If the bPush flag is true, then make this opcode the parent for
** subsequent Explains until sqlite3VdbeExplainPop() is called.
*/
-SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
-#ifndef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
+ int addr = 0;
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
** But omit them (for performance) during production builds */
if( pParse->explain==2 )
@@ -81101,13 +82821,15 @@ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt
va_end(ap);
v = pParse->pVdbe;
iThis = v->nOp;
- sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
+ addr = sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
zMsg, P4_DYNAMIC);
- sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z);
+ sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z);
if( bPush){
pParse->addrExplain = iThis;
}
+ sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
}
+ return addr;
}
/*
@@ -81215,6 +82937,9 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
int i;
for(i=p->nLabelAlloc; i<nNewSize; i++) p->aLabel[i] = -1;
#endif
+ if( nNewSize>=100 && (nNewSize/100)>(p->nLabelAlloc/100) ){
+ sqlite3ProgressCheck(p);
+ }
p->nLabelAlloc = nNewSize;
p->aLabel[j] = v->nOp;
}
@@ -81370,6 +83095,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|| opcode==OP_VDestroy
|| opcode==OP_VCreate
|| opcode==OP_ParseSchema
+ || opcode==OP_Function || opcode==OP_PureFunc
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
){
@@ -81460,8 +83186,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
- while(1){
-
+ assert( p->aOp[0].opcode==OP_Init );
+ while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
/* Only JUMP opcodes and the short list of special opcodes in the switch
** below need to be considered. The mkopcodeh.tcl generator script groups
** all these opcodes together near the front of the opcode list. Skip
@@ -81490,6 +83216,10 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
p->bIsReader = 1;
break;
}
+ case OP_Init: {
+ assert( pOp->p2>=0 );
+ goto resolve_p2_values_loop_exit;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
case OP_VUpdate: {
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -81522,11 +83252,12 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
}
- if( pOp==p->aOp ) break;
+ assert( pOp>p->aOp );
pOp--;
}
+resolve_p2_values_loop_exit:
if( aLabel ){
- sqlite3DbFreeNN(p->db, pParse->aLabel);
+ sqlite3DbNNFreeNN(p->db, pParse->aLabel);
pParse->aLabel = 0;
}
pParse->nLabel = 0;
@@ -81759,6 +83490,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
if( aNew ){
ScanStatus *pNew = &aNew[p->nScan++];
+ memset(pNew, 0, sizeof(ScanStatus));
pNew->addrExplain = addrExplain;
pNew->addrLoop = addrLoop;
pNew->addrVisit = addrVisit;
@@ -81767,6 +83499,62 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
p->aScan = aNew;
}
}
+
+/*
+** Add the range of instructions from addrStart to addrEnd (inclusive) to
+** the set of those corresponding to the sqlite3_stmt_scanstatus() counters
+** associated with the OP_Explain instruction at addrExplain. The
+** sum of the sqlite3Hwtime() values for each of these instructions
+** will be returned for SQLITE_SCANSTAT_NCYCLE requests.
+*/
+SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(
+ Vdbe *p,
+ int addrExplain,
+ int addrStart,
+ int addrEnd
+){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ if( pScan->aAddrRange[ii]==0 ){
+ pScan->aAddrRange[ii] = addrStart;
+ pScan->aAddrRange[ii+1] = addrEnd;
+ break;
+ }
+ }
+ }
+}
+
+/*
+** Set the addresses for the SQLITE_SCANSTAT_NLOOP and SQLITE_SCANSTAT_NROW
+** counters for the query element associated with the OP_Explain at
+** addrExplain.
+*/
+SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(
+ Vdbe *p,
+ int addrExplain,
+ int addrLoop,
+ int addrVisit
+){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ pScan->addrLoop = addrLoop;
+ pScan->addrVisit = addrVisit;
+ }
+}
#endif
@@ -81775,15 +83563,19 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
** for a specific instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p1 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
+ assert( addr>=0 || p->db->mallocFailed );
sqlite3VdbeGetOp(p,addr)->p2 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
+ assert( addr>=0 );
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
@@ -81792,6 +83584,18 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
}
/*
+** If the previous opcode is an OP_Column that delivers results
+** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
+** opcode.
+*/
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
+ if( pOp->p3==iDest && pOp->opcode==OP_Column ){
+ pOp->p5 |= OPFLAG_TYPEOFARG;
+ }
+}
+
+/*
** Change the P2 operand of instruction addr so that it points to
** the address of the next instruction to be coded.
*/
@@ -81819,7 +83623,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
|| p->aOp[addr].opcode==OP_FkIfZero );
assert( p->aOp[addr].p4type==0 );
#ifdef SQLITE_VDBE_COVERAGE
- sqlite3VdbeGetOp(p,-1)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
+ sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
#endif
p->nOp--;
}else{
@@ -81833,8 +83637,9 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
+ assert( db!=0 );
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
- sqlite3DbFreeNN(db, pDef);
+ sqlite3DbNNFreeNN(db, pDef);
}
}
@@ -81843,11 +83648,12 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
*/
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
+ assert( db!=0 );
freeEphemeralFunction(db, p->pFunc);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
static void freeP4(sqlite3 *db, int p4type, void *p4){
assert( db );
@@ -81860,7 +83666,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
case P4_INT64:
case P4_DYNAMIC:
case P4_INTARRAY: {
- sqlite3DbFree(db, p4);
+ if( p4 ) sqlite3DbNNFreeNN(db, p4);
break;
}
case P4_KEYINFO: {
@@ -81899,6 +83705,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
*/
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
assert( nOp>=0 );
+ assert( db!=0 );
if( aOp ){
Op *pOp = &aOp[nOp-1];
while(1){ /* Exit via break */
@@ -81909,7 +83716,7 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( pOp==aOp ) break;
pOp--;
}
- sqlite3DbFreeNN(db, aOp);
+ sqlite3DbNNFreeNN(db, aOp);
}
}
@@ -82078,7 +83885,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
if( p->db->mallocFailed ){
freeP4(p->db, n, pP4);
}else{
- assert( pP4!=0 );
+ assert( pP4!=0 || n==P4_DYNAMIC );
assert( p->nOp>0 );
pOp = &p->aOp[p->nOp-1];
assert( pOp->p4type==P4_NOTUSED );
@@ -82140,13 +83947,13 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
** Set the value if the iSrcLine field for the previously coded instruction.
*/
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
- sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine;
+ sqlite3VdbeGetLastOp(v)->iSrcLine = iLine;
}
#endif /* SQLITE_VDBE_COVERAGE */
/*
-** Return the opcode for a given address. If the address is -1, then
-** return the most recently inserted opcode.
+** Return the opcode for a given address. The address must be non-negative.
+** See sqlite3VdbeGetLastOp() to get the most recently added opcode.
**
** If a memory allocation error has occurred prior to the calling of this
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
@@ -82162,9 +83969,6 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
** zeros, which is correct. MSVC generates a warning, nevertheless. */
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
assert( p->eVdbeState==VDBE_INIT_STATE );
- if( addr<0 ){
- addr = p->nOp - 1;
- }
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
if( p->db->mallocFailed ){
return (VdbeOp*)&dummy;
@@ -82173,6 +83977,12 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
}
}
+/* Return the most recently added opcode
+*/
+VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
+ return sqlite3VdbeGetOp(p, p->nOp - 1);
+}
+
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
/*
** Return an integer value for one of the parameters to the opcode pOp
@@ -82660,7 +84470,7 @@ static void releaseMemArray(Mem *p, int N){
sqlite3VdbeMemRelease(p);
p->flags = MEM_Undefined;
}else if( p->szMalloc ){
- sqlite3DbFreeNN(db, p->zMalloc);
+ sqlite3DbNNFreeNN(db, p->zMalloc);
p->szMalloc = 0;
p->flags = MEM_Undefined;
}
@@ -82874,7 +84684,6 @@ SQLITE_PRIVATE int sqlite3VdbeList(
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
*/
releaseMemArray(pMem, 8);
- p->pResultSet = 0;
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
@@ -82931,7 +84740,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
p->nResColumn = 8;
}
- p->pResultSet = pMem;
+ p->pResultRow = pMem;
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM;
rc = SQLITE_ERROR;
@@ -83042,7 +84851,7 @@ static void *allocSpace(
** running it.
*/
SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+#if defined(SQLITE_DEBUG)
int i;
#endif
assert( p!=0 );
@@ -83071,8 +84880,8 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
for(i=0; i<p->nOp; i++){
- p->aOp[i].cnt = 0;
- p->aOp[i].cycles = 0;
+ p->aOp[i].nExec = 0;
+ p->aOp[i].nCycle = 0;
}
#endif
}
@@ -83181,9 +84990,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64));
-#endif
if( x.nNeeded ){
x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
x.nFree = x.nNeeded;
@@ -83192,9 +84998,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
-#endif
}
}
@@ -83209,9 +85012,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->nMem = nMem;
initMemArray(p->aMem, nMem, db, MEM_Undefined);
memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- memset(p->anExec, 0, p->nOp*sizeof(i64));
-#endif
}
sqlite3VdbeRewind(p);
}
@@ -83269,9 +85069,6 @@ static void closeCursorsInFrame(Vdbe *p){
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
Vdbe *v = pFrame->v;
closeCursorsInFrame(v);
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- v->anExec = pFrame->anExec;
-#endif
v->aOp = pFrame->aOp;
v->nOp = pFrame->nOp;
v->aMem = pFrame->aMem;
@@ -83652,7 +85449,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){
if( p->readOnly==0 ) nWrite++;
if( p->bIsReader ) nRead++;
}
- p = p->pNext;
+ p = p->pVNext;
}
assert( cnt==db->nVdbeActive );
assert( nWrite==db->nVdbeWrite );
@@ -84075,7 +85872,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}
- p->pResultSet = 0;
+ p->pResultRow = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
#endif
@@ -84103,10 +85900,12 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
}
for(i=0; i<p->nOp; i++){
char zHdr[100];
+ i64 cnt = p->aOp[i].nExec;
+ i64 cycles = p->aOp[i].nCycle;
sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ",
- p->aOp[i].cnt,
- p->aOp[i].cycles,
- p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
+ cnt,
+ cycles,
+ cnt>0 ? cycles/cnt : 0
);
fprintf(out, "%s", zHdr);
sqlite3VdbePrintOp(out, i, &p->aOp[i]);
@@ -84181,10 +85980,11 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
*/
static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
+ assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
- sqlite3DbFreeNN(db, p->aColName);
+ sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
@@ -84193,11 +85993,11 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
}
if( p->eVdbeState!=VDBE_INIT_STATE ){
releaseMemArray(p->aVar, p->nVar);
- if( p->pVList ) sqlite3DbFreeNN(db, p->pVList);
- if( p->pFree ) sqlite3DbFreeNN(db, p->pFree);
+ if( p->pVList ) sqlite3DbNNFreeNN(db, p->pVList);
+ if( p->pFree ) sqlite3DbNNFreeNN(db, p->pFree);
}
vdbeFreeOpArray(db, p->aOp, p->nOp);
- sqlite3DbFree(db, p->zSql);
+ if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql);
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
@@ -84227,20 +86027,17 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
assert( p!=0 );
db = p->db;
+ assert( db!=0 );
assert( sqlite3_mutex_held(db->mutex) );
sqlite3VdbeClearObject(db, p);
if( db->pnBytesFreed==0 ){
- if( p->pPrev ){
- p->pPrev->pNext = p->pNext;
- }else{
- assert( db->pVdbe==p );
- db->pVdbe = p->pNext;
- }
- if( p->pNext ){
- p->pNext->pPrev = p->pPrev;
+ assert( p->ppVPrev!=0 );
+ *p->ppVPrev = p->pVNext;
+ if( p->pVNext ){
+ p->pVNext->ppVPrev = p->ppVPrev;
}
}
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
/*
@@ -85195,7 +86992,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
assert( pPKey2->pKeyInfo->aSortFlags!=0 );
assert( pPKey2->pKeyInfo->nKeyField>0 );
assert( idx1<=szHdr1 || CORRUPT_DB );
- do{
+ while( 1 /*exit-by-break*/ ){
u32 serial_type;
/* RHS is an integer */
@@ -85205,7 +87002,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
serial_type = aKey1[idx1];
testcase( serial_type==12 );
if( serial_type>=10 ){
- rc = +1;
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
@@ -85230,7 +87027,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
** them to numberic values are. */
- rc = +1;
+ rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
@@ -85311,7 +87108,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
- rc = (serial_type!=0);
+ rc = (serial_type!=0 && serial_type!=10);
}
if( rc!=0 ){
@@ -85333,8 +87130,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
if( i==pPKey2->nField ) break;
pRhs++;
d1 += sqlite3VdbeSerialTypeLen(serial_type);
+ if( d1>(unsigned)nKey1 ) break;
idx1 += sqlite3VarintLen(serial_type);
- }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
+ if( idx1>=(unsigned)szHdr1 ){
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
+ return 0; /* Corrupt index */
+ }
+ }
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
@@ -85735,7 +87537,7 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){
*/
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
Vdbe *p;
- for(p = db->pVdbe; p; p=p->pNext){
+ for(p = db->pVdbe; p; p=p->pVNext){
p->expired = iCode+1;
}
}
@@ -85856,13 +87658,14 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
** the vdbeUnpackRecord() function found in vdbeapi.c.
*/
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
+ assert( db!=0 );
if( p ){
int i;
for(i=0; i<nField; i++){
Mem *pMem = &p->aMem[i];
if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem);
}
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -85933,7 +87736,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
- sqlite3DbFreeNN(db, preupdate.aNew);
+ sqlite3DbNNFreeNN(db, preupdate.aNew);
}
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -85957,6 +87760,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
*/
/* #include "sqliteInt.h" */
/* #include "vdbeInt.h" */
+/* #include "opcodes.h" */
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -86050,7 +87854,9 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db, v);
- rc = sqlite3VdbeFinalize(v);
+ assert( v->eVdbeState>=VDBE_READY_STATE );
+ rc = sqlite3VdbeReset(v);
+ sqlite3VdbeDelete(v);
rc = sqlite3ApiExit(db, rc);
sqlite3LeaveMutexAndCloseZombie(db);
}
@@ -86258,6 +88064,9 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
#endif
return aType[pVal->flags&MEM_AffMask];
}
+SQLITE_API int sqlite3_value_encoding(sqlite3_value *pVal){
+ return pVal->enc;
+}
/* Return true if a parameter to xUpdate represents an unchanged column */
SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
@@ -86442,7 +88251,10 @@ SQLITE_API void sqlite3_result_text64(
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ if( enc!=SQLITE_UTF8 ){
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ n &= ~(u64)1;
+ }
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
@@ -86457,7 +88269,7 @@ SQLITE_API void sqlite3_result_text16(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16NATIVE, xDel);
}
SQLITE_API void sqlite3_result_text16be(
sqlite3_context *pCtx,
@@ -86466,7 +88278,7 @@ SQLITE_API void sqlite3_result_text16be(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16BE, xDel);
}
SQLITE_API void sqlite3_result_text16le(
sqlite3_context *pCtx,
@@ -86475,7 +88287,7 @@ SQLITE_API void sqlite3_result_text16le(
void (*xDel)(void *)
){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
@@ -86686,7 +88498,7 @@ static int sqlite3Step(Vdbe *p){
/* If the statement completed successfully, invoke the profile callback */
checkProfileCallback(db, p);
#endif
-
+ p->pResultRow = 0;
if( rc==SQLITE_DONE && db->autoCommit ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
@@ -86816,6 +88628,17 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
}
/*
+** The destructor function for a ValueList object. This needs to be
+** a separate function, unknowable to the application, to ensure that
+** calls to sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not
+** preceeded by activation of IN processing via sqlite3_vtab_int() do not
+** try to access a fake ValueList object inserted by a hostile extension.
+*/
+SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){
+ sqlite3_free(pToDelete);
+}
+
+/*
** Implementation of sqlite3_vtab_in_first() (if bNext==0) and
** sqlite3_vtab_in_next() (if bNext!=0).
*/
@@ -86829,8 +88652,15 @@ static int valueFromValueList(
*ppOut = 0;
if( pVal==0 ) return SQLITE_MISUSE;
- pRhs = (ValueList*)sqlite3_value_pointer(pVal, "ValueList");
- if( pRhs==0 ) return SQLITE_MISUSE;
+ if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){
+ return SQLITE_ERROR;
+ }else{
+ assert( (pVal->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
+ (MEM_Null|MEM_Term|MEM_Subtype) );
+ assert( pVal->eSubtype=='p' );
+ assert( pVal->u.zPType!=0 && strcmp(pVal->u.zPType,"ValueList")==0 );
+ pRhs = (ValueList*)pVal->z;
+ }
if( bNext ){
rc = sqlite3BtreeNext(pRhs->pCsr, 0);
}else{
@@ -87050,7 +88880,7 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
*/
SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- if( pVm==0 || pVm->pResultSet==0 ) return 0;
+ if( pVm==0 || pVm->pResultRow==0 ) return 0;
return pVm->nResColumn;
}
@@ -87105,8 +88935,8 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
if( pVm==0 ) return (Mem*)columnNullValue();
assert( pVm->db );
sqlite3_mutex_enter(pVm->db->mutex);
- if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
- pOut = &pVm->pResultSet[i];
+ if( pVm->pResultRow!=0 && i<pVm->nResColumn && i>=0 ){
+ pOut = &pVm->pResultRow[i];
}else{
sqlite3Error(pVm->db, SQLITE_RANGE);
pOut = (Mem*)columnNullValue();
@@ -87372,7 +89202,7 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
** The error code stored in database p->db is overwritten with the return
** value in any case.
*/
-static int vdbeUnbind(Vdbe *p, int i){
+static int vdbeUnbind(Vdbe *p, unsigned int i){
Mem *pVar;
if( vdbeSafetyNotNull(p) ){
return SQLITE_MISUSE_BKPT;
@@ -87385,12 +89215,11 @@ static int vdbeUnbind(Vdbe *p, int i){
"bind on a busy prepared statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
}
- if( i<1 || i>p->nVar ){
+ if( i>=(unsigned int)p->nVar ){
sqlite3Error(p->db, SQLITE_RANGE);
sqlite3_mutex_leave(p->db->mutex);
return SQLITE_RANGE;
}
- i--;
pVar = &p->aVar[i];
sqlite3VdbeMemRelease(pVar);
pVar->flags = MEM_Null;
@@ -87427,7 +89256,7 @@ static int bindText(
Mem *pVar;
int rc;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
if( zData!=0 ){
pVar = &p->aVar[i-1];
@@ -87476,7 +89305,7 @@ SQLITE_API int sqlite3_bind_blob64(
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
sqlite3_mutex_leave(p->db->mutex);
@@ -87489,7 +89318,7 @@ SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
sqlite3_mutex_leave(p->db->mutex);
@@ -87499,7 +89328,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3_mutex_leave(p->db->mutex);
}
@@ -87514,7 +89343,7 @@ SQLITE_API int sqlite3_bind_pointer(
){
int rc;
Vdbe *p = (Vdbe*)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
@@ -87541,7 +89370,10 @@ SQLITE_API int sqlite3_bind_text64(
unsigned char enc
){
assert( xDel!=SQLITE_DYNAMIC );
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ if( enc!=SQLITE_UTF8 ){
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
+ nData &= ~(u16)1;
+ }
return bindText(pStmt, i, zData, nData, xDel, enc);
}
#ifndef SQLITE_OMIT_UTF16
@@ -87549,10 +89381,10 @@ SQLITE_API int sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
const void *zData,
- int nData,
+ int n,
void (*xDel)(void*)
){
- return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
+ return bindText(pStmt, i, zData, n & ~(u64)1, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
@@ -87592,7 +89424,7 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
- rc = vdbeUnbind(p, i);
+ rc = vdbeUnbind(p, (u32)(i-1));
if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_INCRBLOB
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
@@ -87752,7 +89584,7 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
if( pStmt==0 ){
pNext = (sqlite3_stmt*)pDb->pVdbe;
}else{
- pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext;
+ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pVNext;
}
sqlite3_mutex_leave(pDb->mutex);
return pNext;
@@ -87777,8 +89609,11 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
sqlite3_mutex_enter(db->mutex);
v = 0;
db->pnBytesFreed = (int*)&v;
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
+ db->lookaside.pEnd = db->lookaside.pStart;
sqlite3VdbeDelete(pVdbe);
db->pnBytesFreed = 0;
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
sqlite3_mutex_leave(db->mutex);
}else{
v = pVdbe->aCounter[op];
@@ -88040,23 +89875,60 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
/*
** Return status data for a single loop within query pStmt.
*/
-SQLITE_API int sqlite3_stmt_scanstatus(
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
sqlite3_stmt *pStmt, /* Prepared statement being queried */
- int idx, /* Index of loop to report on */
+ int iScan, /* Index of loop to report on */
int iScanStatusOp, /* Which metric to return */
+ int flags,
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
ScanStatus *pScan;
- if( idx<0 || idx>=p->nScan ) return 1;
- pScan = &p->aScan[idx];
+ int idx;
+
+ if( iScan<0 ){
+ int ii;
+ if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
+ i64 res = 0;
+ for(ii=0; ii<p->nOp; ii++){
+ res += p->aOp[ii].nCycle;
+ }
+ *(i64*)pOut = res;
+ return 0;
+ }
+ return 1;
+ }
+ if( flags & SQLITE_SCANSTAT_COMPLEX ){
+ idx = iScan;
+ pScan = &p->aScan[idx];
+ }else{
+ /* If the COMPLEX flag is clear, then this function must ignore any
+ ** ScanStatus structures with ScanStatus.addrLoop set to 0. */
+ for(idx=0; idx<p->nScan; idx++){
+ pScan = &p->aScan[idx];
+ if( pScan->zName ){
+ iScan--;
+ if( iScan<0 ) break;
+ }
+ }
+ }
+ if( idx>=p->nScan ) return 1;
+
switch( iScanStatusOp ){
case SQLITE_SCANSTAT_NLOOP: {
- *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
+ if( pScan->addrLoop>0 ){
+ *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
+ }else{
+ *(sqlite3_int64*)pOut = -1;
+ }
break;
}
case SQLITE_SCANSTAT_NVISIT: {
- *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
+ if( pScan->addrVisit>0 ){
+ *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
+ }else{
+ *(sqlite3_int64*)pOut = -1;
+ }
break;
}
case SQLITE_SCANSTAT_EST: {
@@ -88089,6 +89961,45 @@ SQLITE_API int sqlite3_stmt_scanstatus(
}
break;
}
+ case SQLITE_SCANSTAT_PARENTID: {
+ if( pScan->addrExplain ){
+ *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
+ }else{
+ *(int*)pOut = -1;
+ }
+ break;
+ }
+ case SQLITE_SCANSTAT_NCYCLE: {
+ i64 res = 0;
+ if( pScan->aAddrRange[0]==0 ){
+ res = -1;
+ }else{
+ int ii;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ int iIns = pScan->aAddrRange[ii];
+ int iEnd = pScan->aAddrRange[ii+1];
+ if( iIns==0 ) break;
+ if( iIns>0 ){
+ while( iIns<=iEnd ){
+ res += p->aOp[iIns].nCycle;
+ iIns++;
+ }
+ }else{
+ int iOp;
+ for(iOp=0; iOp<p->nOp; iOp++){
+ Op *pOp = &p->aOp[iOp];
+ if( pOp->p1!=iEnd ) continue;
+ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
+ continue;
+ }
+ res += p->aOp[iOp].nCycle;
+ }
+ }
+ }
+ }
+ *(i64*)pOut = res;
+ break;
+ }
default: {
return 1;
}
@@ -88097,11 +90008,28 @@ SQLITE_API int sqlite3_stmt_scanstatus(
}
/*
+** Return status data for a single loop within query pStmt.
+*/
+SQLITE_API int sqlite3_stmt_scanstatus(
+ sqlite3_stmt *pStmt, /* Prepared statement being queried */
+ int iScan, /* Index of loop to report on */
+ int iScanStatusOp, /* Which metric to return */
+ void *pOut /* OUT: Write the answer here */
+){
+ return sqlite3_stmt_scanstatus_v2(pStmt, iScan, iScanStatusOp, 0, pOut);
+}
+
+/*
** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
*/
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
- memset(p->anExec, 0, p->nOp * sizeof(i64));
+ int ii;
+ for(ii=0; ii<p->nOp; ii++){
+ Op *pOp = &p->aOp[ii];
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+ }
}
#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
@@ -88437,6 +90365,9 @@ SQLITE_API int sqlite3_found_count = 0;
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
static int n = 0;
+ (void)pc;
+ (void)pOp;
+ (void)v;
n++;
}
#endif
@@ -88618,7 +90549,8 @@ static VdbeCursor *allocateCursor(
** return false.
*/
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
- i64 iValue = (double)rValue;
+ i64 iValue;
+ iValue = sqlite3RealToI64(rValue);
if( sqlite3RealSameAsInt(rValue,iValue) ){
*piValue = iValue;
return 1;
@@ -88674,6 +90606,10 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
** always preferred, even if the affinity is REAL, because
** an integer representation is more space efficient on disk.
**
+** SQLITE_AFF_FLEXNUM:
+** If the value is text, then try to convert it into a number of
+** some kind (integer or real) but do not make any other changes.
+**
** SQLITE_AFF_TEXT:
** Convert pRec to a text representation.
**
@@ -88688,11 +90624,11 @@ static void applyAffinity(
){
if( affinity>=SQLITE_AFF_NUMERIC ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
- || affinity==SQLITE_AFF_NUMERIC );
+ || affinity==SQLITE_AFF_NUMERIC || affinity==SQLITE_AFF_FLEXNUM );
if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
- if( (pRec->flags & MEM_Real)==0 ){
+ if( (pRec->flags & (MEM_Real|MEM_IntReal))==0 ){
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
- }else{
+ }else if( affinity<=SQLITE_AFF_REAL ){
sqlite3VdbeIntegerAffinity(pRec);
}
}
@@ -88780,17 +90716,18 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
** But it does set pMem->u.r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
- if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
+ assert( (pMem->flags & MEM_Null)==0
+ || pMem->db==0 || pMem->db->mallocFailed );
+ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){
testcase( pMem->flags & MEM_Int );
testcase( pMem->flags & MEM_Real );
testcase( pMem->flags & MEM_IntReal );
- return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
- }
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
- testcase( pMem->flags & MEM_Str );
- testcase( pMem->flags & MEM_Blob );
- return computeNumericType(pMem);
+ return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null);
}
+ assert( pMem->flags & (MEM_Str|MEM_Blob) );
+ testcase( pMem->flags & MEM_Str );
+ testcase( pMem->flags & MEM_Blob );
+ return computeNumericType(pMem);
return 0;
}
@@ -88919,17 +90856,6 @@ SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){
# define REGISTER_TRACE(R,M)
#endif
-
-#ifdef VDBE_PROFILE
-
-/*
-** hwtime.h contains inline assembler code for implementing
-** high-performance timing routines.
-*/
-/* #include "hwtime.h" */
-
-#endif
-
#ifndef NDEBUG
/*
** This function is only called from within an assert() expression. It
@@ -89019,11 +90945,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
){
Op *aOp = p->aOp; /* Copy of p->aOp */
Op *pOp = aOp; /* Current operation */
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
- Op *pOrigOp; /* Value of pOp at the top of the loop */
-#endif
#ifdef SQLITE_DEBUG
+ Op *pOrigOp; /* Value of pOp at the top of the loop */
int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
+ u8 iCompareIsInit = 0; /* iCompare is initialized */
#endif
int rc = SQLITE_OK; /* Value to return */
sqlite3 *db = p->db; /* The database */
@@ -89039,13 +90964,15 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
-#ifdef VDBE_PROFILE
- u64 start; /* CPU clock count at start of opcode */
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ u64 *pnCycle = 0;
#endif
/*** INSERT STACK UNION HERE ***/
assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */
- sqlite3VdbeEnter(p);
+ if( DbMaskNonZero(p->lockMask) ){
+ sqlite3VdbeEnter(p);
+ }
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
@@ -89066,7 +90993,6 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( p->bIsReader || p->readOnly!=0 );
p->iCurrentTime = 0;
assert( p->explain==0 );
- p->pResultSet = 0;
db->busyHandler.nBusy = 0;
if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
sqlite3VdbeIOTraceSql(p);
@@ -89103,12 +91029,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( rc==SQLITE_OK );
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
-#ifdef VDBE_PROFILE
- start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
-#endif
nVmStep++;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- if( p->anExec ) p->anExec[(int)(pOp-aOp)]++;
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
+# ifdef VDBE_PROFILE
+ if( sqlite3NProfileCnt==0 )
+# endif
+ *pnCycle -= sqlite3Hwtime();
#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
@@ -89170,7 +91098,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
}
#endif
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+#ifdef SQLITE_DEBUG
pOrigOp = pOp;
#endif
@@ -89454,6 +91382,12 @@ case OP_Halt: {
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
+
+ /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
+ ** something is wrong with the code generator. Raise an assertion in order
+ ** to bring this to the attention of fuzzers and other testing tools. */
+ assert( pOp->p1!=SQLITE_INTERNAL );
+
if( p->pFrame && pOp->p1==SQLITE_OK ){
/* Halt the sub-program. Return control to the parent frame. */
pFrame = p->pFrame;
@@ -89895,10 +91829,10 @@ case OP_ResultRow: {
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
p->cacheCtr = (p->cacheCtr + 2)|1;
- p->pResultSet = &aMem[pOp->p1];
+ p->pResultRow = &aMem[pOp->p1];
#ifdef SQLITE_DEBUG
{
- Mem *pMem = p->pResultSet;
+ Mem *pMem = p->pResultRow;
int i;
for(i=0; i<pOp->p2; i++){
assert( memIsValid(&pMem[i]) );
@@ -90035,7 +91969,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
- u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
@@ -90044,12 +91977,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
- type1 = numericType(pIn1);
+ type1 = pIn1->flags;
pIn2 = &aMem[pOp->p2];
- type2 = numericType(pIn2);
+ type2 = pIn2->flags;
pOut = &aMem[pOp->p3];
- flags = pIn1->flags | pIn2->flags;
if( (type1 & type2 & MEM_Int)!=0 ){
+int_math:
iA = pIn1->u.i;
iB = pIn2->u.i;
switch( pOp->opcode ){
@@ -90071,9 +92004,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
}
pOut->u.i = iB;
MemSetTypeFlag(pOut, MEM_Int);
- }else if( (flags & MEM_Null)!=0 ){
+ }else if( ((type1 | type2) & MEM_Null)!=0 ){
goto arithmetic_result_is_null;
}else{
+ type1 = numericType(pIn1);
+ type2 = numericType(pIn2);
+ if( (type1 & type2 & MEM_Int)!=0 ) goto int_math;
fp_math:
rA = sqlite3VdbeRealValue(pIn1);
rB = sqlite3VdbeRealValue(pIn2);
@@ -90426,7 +92362,6 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
flags1 = pIn1->flags;
flags3 = pIn3->flags;
if( (flags1 & flags3 & MEM_Int)!=0 ){
- assert( (pOp->p5 & SQLITE_AFF_MASK)!=SQLITE_AFF_TEXT || CORRUPT_DB );
/* Common case of comparison of two integers */
if( pIn3->u.i > pIn1->u.i ){
if( sqlite3aGTb[pOp->opcode] ){
@@ -90434,18 +92369,21 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto jump_to_p2;
}
iCompare = +1;
+ VVA_ONLY( iCompareIsInit = 1; )
}else if( pIn3->u.i < pIn1->u.i ){
if( sqlite3aLTb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = -1;
+ VVA_ONLY( iCompareIsInit = 1; )
}else{
if( sqlite3aEQb[pOp->opcode] ){
VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
goto jump_to_p2;
}
iCompare = 0;
+ VVA_ONLY( iCompareIsInit = 1; )
}
VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
break;
@@ -90477,6 +92415,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
goto jump_to_p2;
}
iCompare = 1; /* Operands are not equal */
+ VVA_ONLY( iCompareIsInit = 1; )
break;
}
}else{
@@ -90487,14 +92426,14 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( (flags1 | flags3)&MEM_Str ){
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn1,0);
- testcase( flags3==pIn3->flags );
+ assert( flags3==pIn3->flags || CORRUPT_DB );
flags3 = pIn3->flags;
}
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
applyNumericAffinity(pIn3,0);
}
}
- }else if( affinity==SQLITE_AFF_TEXT ){
+ }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
@@ -90502,7 +92441,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
- if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str;
+ if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
}
if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
@@ -90533,6 +92472,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
res2 = sqlite3aGTb[pOp->opcode];
}
iCompare = res;
+ VVA_ONLY( iCompareIsInit = 1; )
/* Undo any changes made by applyAffinity() to the input registers. */
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
@@ -90571,6 +92511,7 @@ case OP_ElseEq: { /* same as TK_ESCAPE, jump */
break;
}
#endif /* SQLITE_DEBUG */
+ assert( iCompareIsInit );
VdbeBranchTaken(iCompare==0, 2);
if( iCompare==0 ) goto jump_to_p2;
break;
@@ -90665,6 +92606,7 @@ case OP_Compare: {
pColl = pKeyInfo->aColl[i];
bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
+ VVA_ONLY( iCompareIsInit = 1; )
if( iCompare ){
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
&& ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
@@ -90689,6 +92631,7 @@ case OP_Compare: {
*/
case OP_Jump: { /* jump */
assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
+ assert( iCompareIsInit );
if( iCompare<0 ){
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
@@ -90888,19 +92831,90 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
break;
}
-/* Opcode: IsNullOrType P1 P2 P3 * *
-** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2
+/* Opcode: IsType P1 P2 P3 P4 P5
+** Synopsis: if typeof(P1.P3) in P5 goto P2
+**
+** Jump to P2 if the type of a column in a btree is one of the types specified
+** by the P5 bitmask.
+**
+** P1 is normally a cursor on a btree for which the row decode cache is
+** valid through at least column P3. In other words, there should have been
+** a prior OP_Column for column P3 or greater. If the cursor is not valid,
+** then this opcode might give spurious results.
+** The the btree row has fewer than P3 columns, then use P4 as the
+** datatype.
+**
+** If P1 is -1, then P3 is a register number and the datatype is taken
+** from the value in that register.
+**
+** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant
+** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
+** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
+**
+** Take the jump to address P2 if and only if the datatype of the
+** value determined by P1 and P3 corresponds to one of the bits in the
+** P5 bitmask.
**
-** Jump to P2 if the value in register P1 is NULL or has a datatype P3.
-** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT,
-** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT.
*/
-case OP_IsNullOrType: { /* jump, in1 */
- int doTheJump;
- pIn1 = &aMem[pOp->p1];
- doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3;
- VdbeBranchTaken( doTheJump, 2);
- if( doTheJump ) goto jump_to_p2;
+case OP_IsType: { /* jump */
+ VdbeCursor *pC;
+ u16 typeMask;
+ u32 serialType;
+
+ assert( pOp->p1>=(-1) && pOp->p1<p->nCursor );
+ assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) );
+ if( pOp->p1>=0 ){
+ pC = p->apCsr[pOp->p1];
+ assert( pC!=0 );
+ assert( pOp->p3>=0 );
+ if( pOp->p3<pC->nHdrParsed ){
+ serialType = pC->aType[pOp->p3];
+ if( serialType>=12 ){
+ if( serialType&1 ){
+ typeMask = 0x04; /* SQLITE_TEXT */
+ }else{
+ typeMask = 0x08; /* SQLITE_BLOB */
+ }
+ }else{
+ static const unsigned char aMask[] = {
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2,
+ 0x01, 0x01, 0x10, 0x10
+ };
+ testcase( serialType==0 );
+ testcase( serialType==1 );
+ testcase( serialType==2 );
+ testcase( serialType==3 );
+ testcase( serialType==4 );
+ testcase( serialType==5 );
+ testcase( serialType==6 );
+ testcase( serialType==7 );
+ testcase( serialType==8 );
+ testcase( serialType==9 );
+ testcase( serialType==10 );
+ testcase( serialType==11 );
+ typeMask = aMask[serialType];
+ }
+ }else{
+ typeMask = 1 << (pOp->p4.i - 1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ }else{
+ assert( memIsValid(&aMem[pOp->p3]) );
+ typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1);
+ testcase( typeMask==0x01 );
+ testcase( typeMask==0x02 );
+ testcase( typeMask==0x04 );
+ testcase( typeMask==0x08 );
+ testcase( typeMask==0x10 );
+ }
+ VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2);
+ if( typeMask & pOp->p5 ){
+ goto jump_to_p2;
+ }
break;
}
@@ -90943,11 +92957,14 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** If it is, then set register P3 to NULL and jump immediately to P2.
** If P1 is not on a NULL row, then fall through without making any
** changes.
+**
+** If P1 is not an open cursor, then this opcode is a no-op.
*/
case OP_IfNullRow: { /* jump */
+ VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( p->apCsr[pOp->p1]!=0 );
- if( p->apCsr[pOp->p1]->nullRow ){
+ pC = p->apCsr[pOp->p1];
+ if( ALWAYS(pC) && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -90998,7 +93015,7 @@ case OP_Offset: { /* out3 */
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
** information about the format of the data.) Extract the P2-th column
-** from this record. If there are less that (P2+1)
+** from this record. If there are less than (P2+1)
** values in the record, extract a NULL.
**
** The value extracted is stored in register P3.
@@ -91007,12 +93024,14 @@ case OP_Offset: { /* out3 */
** if the P4 argument is a P4_MEM use the value of the P4 argument as
** the result.
**
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
-** the result is guaranteed to only be used as the argument of a length()
-** or typeof() function, respectively. The loading of large blobs can be
-** skipped for length() and all content loading can be skipped for typeof().
+** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed
+** to only be used by the length() function or the equivalent. The content
+** of large blobs is not loaded, thus saving CPU cycles. If the
+** OPFLAG_TYPEOFARG bit is set then the result will only be used by the
+** typeof() function or the IS NULL or IS NOT NULL operators or the
+** equivalent. In this case, all content loading can be omitted.
*/
-case OP_Column: {
+case OP_Column: { /* ncycle */
u32 p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */
@@ -91361,7 +93380,7 @@ case OP_TypeCheck: {
}
case COLTYPE_REAL: {
testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real );
- testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_IntReal );
+ assert( (pIn1->flags & MEM_IntReal)==0 );
if( pIn1->flags & MEM_Int ){
/* When applying REAL affinity, if the result is still an MEM_Int
** that will fit in 6 bytes, then change the type to MEM_IntReal
@@ -92364,7 +94383,7 @@ case OP_SetCookie: {
**
** See also: OP_OpenRead, OP_ReopenIdx
*/
-case OP_ReopenIdx: {
+case OP_ReopenIdx: { /* ncycle */
int nField;
KeyInfo *pKeyInfo;
u32 p2;
@@ -92385,7 +94404,7 @@ case OP_ReopenIdx: {
}
/* If the cursor is not currently open or is open on a different
** index, then fall through into OP_OpenRead to force a reopen */
-case OP_OpenRead:
+case OP_OpenRead: /* ncycle */
case OP_OpenWrite:
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
@@ -92479,7 +94498,7 @@ open_cursor_set_hints:
**
** Duplicate ephemeral cursors are used for self-joins of materialized views.
*/
-case OP_OpenDup: {
+case OP_OpenDup: { /* ncycle */
VdbeCursor *pOrig; /* The original cursor to be duplicated */
VdbeCursor *pCx; /* The new cursor */
@@ -92541,8 +94560,8 @@ case OP_OpenDup: {
** by this opcode will be used for automatically created transient
** indices in joins.
*/
-case OP_OpenAutoindex:
-case OP_OpenEphemeral: {
+case OP_OpenAutoindex: /* ncycle */
+case OP_OpenEphemeral: { /* ncycle */
VdbeCursor *pCx;
KeyInfo *pKeyInfo;
@@ -92700,7 +94719,7 @@ case OP_OpenPseudo: {
** Close a cursor previously opened as P1. If P1 is not
** currently open, this instruction is a no-op.
*/
-case OP_Close: {
+case OP_Close: { /* ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
p->apCsr[pOp->p1] = 0;
@@ -92817,10 +94836,10 @@ case OP_ColumnsUsed: {
**
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
*/
-case OP_SeekLT: /* jump, in3, group */
-case OP_SeekLE: /* jump, in3, group */
-case OP_SeekGE: /* jump, in3, group */
-case OP_SeekGT: { /* jump, in3, group */
+case OP_SeekLT: /* jump, in3, group, ncycle */
+case OP_SeekLE: /* jump, in3, group, ncycle */
+case OP_SeekGE: /* jump, in3, group, ncycle */
+case OP_SeekGT: { /* jump, in3, group, ncycle */
int res; /* Comparison result */
int oc; /* Opcode */
VdbeCursor *pC; /* The cursor to seek */
@@ -92949,7 +94968,13 @@ case OP_SeekGT: { /* jump, in3, group */
r.aMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+ {
+ int i;
+ for(i=0; i<r.nField; i++){
+ assert( memIsValid(&r.aMem[i]) );
+ if( i>0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
+ }
+ }
#endif
r.eqSeen = 0;
rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
@@ -93012,7 +95037,7 @@ seek_not_found:
}
-/* Opcode: SeekScan P1 P2 * * *
+/* Opcode: SeekScan P1 P2 * * P5
** Synopsis: Scan-ahead up to P1 rows
**
** This opcode is a prefix opcode to OP_SeekGE. In other words, this
@@ -93022,8 +95047,8 @@ seek_not_found:
** This opcode uses the P1 through P4 operands of the subsequent
** OP_SeekGE. In the text that follows, the operands of the subsequent
** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
-** the P1 and P2 operands of this opcode are also used, and are called
-** This.P1 and This.P2.
+** the P1, P2 and P5 operands of this opcode are also used, and are called
+** This.P1, This.P2 and This.P5.
**
** This opcode helps to optimize IN operators on a multi-column index
** where the IN operator is on the later terms of the index by avoiding
@@ -93033,32 +95058,54 @@ seek_not_found:
**
** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
** is the desired entry that we want the cursor SeekGE.P1 to be pointing
-** to. Call this SeekGE.P4/P5 row the "target".
+** to. Call this SeekGE.P3/P4 row the "target".
**
** If the SeekGE.P1 cursor is not currently pointing to a valid row,
** then this opcode is a no-op and control passes through into the OP_SeekGE.
**
** If the SeekGE.P1 cursor is pointing to a valid row, then that row
** might be the target row, or it might be near and slightly before the
-** target row. This opcode attempts to position the cursor on the target
-** row by, perhaps by invoking sqlite3BtreeStep() on the cursor
-** between 0 and This.P1 times.
-**
-** There are three possible outcomes from this opcode:<ol>
-**
-** <li> If after This.P1 steps, the cursor is still pointing to a place that
-** is earlier in the btree than the target row, then fall through
-** into the subsquence OP_SeekGE opcode.
-**
-** <li> If the cursor is successfully moved to the target row by 0 or more
-** sqlite3BtreeNext() calls, then jump to This.P2, which will land just
-** past the OP_IdxGT or OP_IdxGE opcode that follows the OP_SeekGE.
-**
-** <li> If the cursor ends up past the target row (indicating the the target
-** row does not exist in the btree) then jump to SeekOP.P2.
+** target row, or it might be after the target row. If the cursor is
+** currently before the target row, then this opcode attempts to position
+** the cursor on or after the target row by invoking sqlite3BtreeStep()
+** on the cursor between 1 and This.P1 times.
+**
+** The This.P5 parameter is a flag that indicates what to do if the
+** cursor ends up pointing at a valid row that is past the target
+** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
+** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
+** case occurs when there are no inequality constraints to the right of
+** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** occurs when there are inequality constraints to the right of the IN
+** operator. In that case, the This.P2 will point either directly to or
+** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
+** loop terminate.
+**
+** Possible outcomes from this opcode:<ol>
+**
+** <li> If the cursor is initally not pointed to any valid row, then
+** fall through into the subsequent OP_SeekGE opcode.
+**
+** <li> If the cursor is left pointing to a row that is before the target
+** row, even after making as many as This.P1 calls to
+** sqlite3BtreeNext(), then also fall through into OP_SeekGE.
+**
+** <li> If the cursor is left pointing at the target row, either because it
+** was at the target row to begin with or because one or more
+** sqlite3BtreeNext() calls moved the cursor to the target row,
+** then jump to This.P2..,
+**
+** <li> If the cursor started out before the target row and a call to
+** to sqlite3BtreeNext() moved the cursor off the end of the index
+** (indicating that the target row definitely does not exist in the
+** btree) then jump to SeekGE.P2, ending the loop.
+**
+** <li> If the cursor ends up on a valid row that is past the target row
+** (indicating that the target row does not exist in the btree) then
+** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0.
** </ol>
*/
-case OP_SeekScan: {
+case OP_SeekScan: { /* ncycle */
VdbeCursor *pC;
int res;
int nStep;
@@ -93066,14 +95113,25 @@ case OP_SeekScan: {
assert( pOp[1].opcode==OP_SeekGE );
- /* pOp->p2 points to the first instruction past the OP_IdxGT that
- ** follows the OP_SeekGE. */
+ /* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the
+ ** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first
+ ** opcode past the OP_SeekGE itself. */
assert( pOp->p2>=(int)(pOp-aOp)+2 );
- assert( aOp[pOp->p2-1].opcode==OP_IdxGT || aOp[pOp->p2-1].opcode==OP_IdxGE );
- testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
- assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
- assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
- assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+#ifdef SQLITE_DEBUG
+ if( pOp->p5==0 ){
+ /* There are no inequality constraints following the IN constraint. */
+ assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
+ assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
+ assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT
+ || aOp[pOp->p2-1].opcode==OP_IdxGE );
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
+ }else{
+ /* There are inequality constraints. */
+ assert( pOp->p2==(int)(pOp-aOp)+2 );
+ assert( aOp[pOp->p2-1].opcode==OP_SeekGE );
+ }
+#endif
assert( pOp->p1>0 );
pC = p->apCsr[pOp[1].p1];
@@ -93107,8 +95165,9 @@ case OP_SeekScan: {
while(1){
rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
if( rc ) goto abort_due_to_error;
- if( res>0 ){
+ if( res>0 && pOp->p5==0 ){
seekscan_search_fail:
+ /* Jump to SeekGE.P2, ending the loop */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then skip\n", pOp->p1 - nStep);
@@ -93118,7 +95177,8 @@ case OP_SeekScan: {
pOp++;
goto jump_to_p2;
}
- if( res==0 ){
+ if( res>=0 ){
+ /* Jump to This.P2, bypassing the OP_SeekGE opcode */
#ifdef SQLITE_DEBUG
if( db->flags&SQLITE_VdbeTrace ){
printf("... %d steps and then success\n", pOp->p1 - nStep);
@@ -93167,7 +95227,7 @@ case OP_SeekScan: {
**
** P1 must be a valid b-tree cursor.
*/
-case OP_SeekHit: {
+case OP_SeekHit: { /* ncycle */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -93194,12 +95254,16 @@ case OP_SeekHit: {
/* Opcode: IfNotOpen P1 P2 * * *
** Synopsis: if( !csr[P1] ) goto P2
**
-** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
+** If cursor P1 is not open or if P1 is set to a NULL row using the
+** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through.
*/
case OP_IfNotOpen: { /* jump */
+ VdbeCursor *pCur;
+
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
- if( !p->apCsr[pOp->p1] ){
+ pCur = p->apCsr[pOp->p1];
+ VdbeBranchTaken(pCur==0 || pCur->nullRow, 2);
+ if( pCur==0 || pCur->nullRow ){
goto jump_to_p2_and_check_for_interrupt;
}
break;
@@ -93295,7 +95359,7 @@ case OP_IfNotOpen: { /* jump */
**
** See also: NotFound, Found, NotExists
*/
-case OP_IfNoHope: { /* jump, in3 */
+case OP_IfNoHope: { /* jump, in3, ncycle */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -93309,9 +95373,9 @@ case OP_IfNoHope: { /* jump, in3 */
/* Fall through into OP_NotFound */
/* no break */ deliberate_fall_through
}
-case OP_NoConflict: /* jump, in3 */
-case OP_NotFound: /* jump, in3 */
-case OP_Found: { /* jump, in3 */
+case OP_NoConflict: /* jump, in3, ncycle */
+case OP_NotFound: /* jump, in3, ncycle */
+case OP_Found: { /* jump, in3, ncycle */
int alreadyExists;
int ii;
VdbeCursor *pC;
@@ -93441,7 +95505,7 @@ case OP_Found: { /* jump, in3 */
**
** See also: Found, NotFound, NoConflict, SeekRowid
*/
-case OP_SeekRowid: { /* jump, in3 */
+case OP_SeekRowid: { /* jump, in3, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -93466,7 +95530,7 @@ case OP_SeekRowid: { /* jump, in3 */
}
/* Fall through into OP_NotExists */
/* no break */ deliberate_fall_through
-case OP_NotExists: /* jump, in3 */
+case OP_NotExists: /* jump, in3, ncycle */
pIn3 = &aMem[pOp->p3];
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -93746,8 +95810,11 @@ case OP_Insert: {
if( pOp->p5 & OPFLAG_ISNOOP ) break;
#endif
- if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
+ assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 );
+ if( pOp->p5 & OPFLAG_NCHANGE ){
+ p->nChange++;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
+ }
assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
x.pData = pData->z;
x.nData = pData->n;
@@ -93758,6 +95825,7 @@ case OP_Insert: {
x.nZero = 0;
}
x.pKey = 0;
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
seekResult
@@ -94089,7 +96157,7 @@ case OP_RowData: {
** be a separate OP_VRowid opcode for use with virtual tables, but this
** one opcode now works for both table types.
*/
-case OP_Rowid: { /* out2 */
+case OP_Rowid: { /* out2, ncycle */
VdbeCursor *pC;
i64 v;
sqlite3_vtab *pVtab;
@@ -94188,8 +96256,8 @@ case OP_NullRow: {
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
*/
-case OP_SeekEnd:
-case OP_Last: { /* jump */
+case OP_SeekEnd: /* ncycle */
+case OP_Last: { /* jump, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
@@ -94290,17 +96358,22 @@ case OP_Sort: { /* jump */
** If the table or index is not empty, fall through to the following
** instruction.
**
+** If P2 is zero, that is an assertion that the P1 table is never
+** empty and hence the jump will never be taken.
+**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
*/
-case OP_Rewind: { /* jump */
+case OP_Rewind: { /* jump, ncycle */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5==0 );
+ assert( pOp->p2>=0 && pOp->p2<p->nOp );
+
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
@@ -94320,9 +96393,10 @@ case OP_Rewind: { /* jump */
}
if( rc ) goto abort_due_to_error;
pC->nullRow = (u8)res;
- assert( pOp->p2>0 && pOp->p2<p->nOp );
- VdbeBranchTaken(res!=0,2);
- if( res ) goto jump_to_p2;
+ if( pOp->p2>0 ){
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
+ }
break;
}
@@ -94388,9 +96462,11 @@ case OP_SorterNext: { /* jump */
rc = sqlite3VdbeSorterNext(db, pC);
goto next_tail;
-case OP_Prev: /* jump */
+case OP_Prev: /* jump, ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -94401,9 +96477,11 @@ case OP_Prev: /* jump */
rc = sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3);
goto next_tail;
-case OP_Next: /* jump */
+case OP_Next: /* jump, ncycle */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
- assert( pOp->p5<ArraySize(p->aCounter) );
+ assert( pOp->p5==0
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->deferredMoveto==0 );
@@ -94591,8 +96669,8 @@ case OP_IdxDelete: {
**
** See also: Rowid, MakeRecord.
*/
-case OP_DeferredSeek:
-case OP_IdxRowid: { /* out2 */
+case OP_DeferredSeek: /* ncycle */
+case OP_IdxRowid: { /* out2, ncycle */
VdbeCursor *pC; /* The P1 index cursor */
VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
i64 rowid; /* Rowid that P1 current points to */
@@ -94610,10 +96688,10 @@ case OP_IdxRowid: { /* out2 */
** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
rc = sqlite3VdbeCursorRestore(pC);
- /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
- ** out from under the cursor. That will never happens for an IdxRowid
- ** or Seek opcode */
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
+ /* sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed
+ ** since it was last positioned and an error (e.g. OOM or an IO error)
+ ** occurs while trying to reposition it. */
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
if( !pC->nullRow ){
rowid = 0; /* Not needed. Only used to silence a warning. */
@@ -94654,8 +96732,8 @@ case OP_IdxRowid: { /* out2 */
** seek operation now, without further delay. If the cursor seek has
** already occurred, this instruction is a no-op.
*/
-case OP_FinishSeek: {
- VdbeCursor *pC; /* The P1 index cursor */
+case OP_FinishSeek: { /* ncycle */
+ VdbeCursor *pC; /* The P1 index cursor */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -94710,10 +96788,10 @@ case OP_FinishSeek: {
** If the P1 index entry is less than or equal to the key value then jump
** to P2. Otherwise fall through to the next instruction.
*/
-case OP_IdxLE: /* jump */
-case OP_IdxGT: /* jump */
-case OP_IdxLT: /* jump */
-case OP_IdxGE: { /* jump */
+case OP_IdxLE: /* jump, ncycle */
+case OP_IdxGT: /* jump, ncycle */
+case OP_IdxLT: /* jump, ncycle */
+case OP_IdxGE: { /* jump, ncycle */
VdbeCursor *pC;
int res;
UnpackedRecord r;
@@ -95124,13 +97202,14 @@ case OP_IntegrityCk: {
pIn1 = &aMem[pOp->p1];
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
- z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
- (int)pnErr->u.i+1, &nErr);
+ rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
+ (int)pnErr->u.i+1, &nErr, &z);
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
assert( z==0 );
- }else if( z==0 ){
- goto no_mem;
+ }else if( rc ){
+ sqlite3_free(z);
+ goto abort_due_to_error;
}else{
pnErr->u.i -= nErr-1;
sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
@@ -95334,9 +97413,6 @@ case OP_Program: { /* jump */
pFrame->aOp = p->aOp;
pFrame->nOp = p->nOp;
pFrame->token = pProgram->token;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- pFrame->anExec = p->anExec;
-#endif
#ifdef SQLITE_DEBUG
pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
#endif
@@ -95373,9 +97449,6 @@ case OP_Program: { /* jump */
memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- p->anExec = 0;
-#endif
#ifdef SQLITE_DEBUG
/* Verify that second and subsequent executions of the same trigger do not
** try to reuse register values from the first use. */
@@ -95515,7 +97588,7 @@ case OP_IfPos: { /* jump, in1 */
** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
**
** This opcode performs a commonly used computation associated with
-** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
+** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3]
** holds the offset counter. The opcode computes the combined value
** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
** value computed is the total number of rows that will need to be
@@ -96132,7 +98205,7 @@ case OP_VDestroy: {
** P1 is a cursor number. This opcode opens a cursor to the virtual
** table and stores that cursor in P1.
*/
-case OP_VOpen: {
+case OP_VOpen: { /* ncycle */
VdbeCursor *pCur;
sqlite3_vtab_cursor *pVCur;
sqlite3_vtab *pVtab;
@@ -96179,7 +98252,7 @@ case OP_VOpen: {
** cursor. Register P3 is used to hold the values returned by
** sqlite3_vtab_in_first() and sqlite3_vtab_in_next().
*/
-case OP_VInitIn: { /* out2 */
+case OP_VInitIn: { /* out2, ncycle */
VdbeCursor *pC; /* The cursor containing the RHS values */
ValueList *pRhs; /* New ValueList object to put in reg[P2] */
@@ -96190,7 +98263,7 @@ case OP_VInitIn: { /* out2 */
pRhs->pOut = &aMem[pOp->p3];
pOut = out2Prerelease(p, pOp);
pOut->flags = MEM_Null;
- sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3_free);
+ sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3VdbeValueListFree);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -96216,7 +98289,7 @@ case OP_VInitIn: { /* out2 */
**
** A jump is made to P2 if the result set after filtering would be empty.
*/
-case OP_VFilter: { /* jump */
+case OP_VFilter: { /* jump, ncycle */
int nArg;
int iQuery;
const sqlite3_module *pModule;
@@ -96276,7 +98349,7 @@ case OP_VFilter: { /* jump */
** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
** unused by OP_VColumn.
*/
-case OP_VColumn: {
+case OP_VColumn: { /* ncycle */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
Mem *pDest;
@@ -96328,7 +98401,7 @@ case OP_VColumn: {
** jump to instruction P2. Or, if the virtual table has reached
** the end of its result set, then fall through to the next instruction.
*/
-case OP_VNext: { /* jump */
+case OP_VNext: { /* jump, ncycle */
sqlite3_vtab *pVtab;
const sqlite3_module *pModule;
int res;
@@ -96911,12 +98984,12 @@ default: { /* This is really OP_Noop, OP_Explain */
*****************************************************************************/
}
-#ifdef VDBE_PROFILE
- {
- u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
- if( endTime>start ) pOrigOp->cycles += endTime - start;
- pOrigOp->cnt++;
- }
+#if defined(VDBE_PROFILE)
+ *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
+ pnCycle = 0;
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ *pnCycle += sqlite3Hwtime();
+ pnCycle = 0;
#endif
/* The following code adds nothing to the actual functionality
@@ -96992,6 +99065,18 @@ abort_due_to_error:
** release the mutexes on btrees that were acquired at the
** top. */
vdbe_return:
+#if defined(VDBE_PROFILE)
+ if( pnCycle ){
+ *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
+ pnCycle = 0;
+ }
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( pnCycle ){
+ *pnCycle += sqlite3Hwtime();
+ pnCycle = 0;
+ }
+#endif
+
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
nProgressLimit += db->nProgressOps;
@@ -97003,7 +99088,9 @@ vdbe_return:
}
#endif
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
- sqlite3VdbeLeave(p);
+ if( DbMaskNonZero(p->lockMask) ){
+ sqlite3VdbeLeave(p);
+ }
assert( rc!=SQLITE_OK || nExtraDelete==0
|| sqlite3_strlike("DELETE%",p->zSql,0)!=0
);
@@ -100410,6 +102497,9 @@ static int bytecodevtabConnect(
");"
};
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
if( rc==SQLITE_OK ){
pNew = sqlite3_malloc( sizeof(*pNew) );
@@ -100645,6 +102735,7 @@ static int bytecodevtabFilter(
bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
int rc = SQLITE_OK;
+ (void)idxStr;
bytecodevtabCursorClear(pCur);
pCur->iRowid = 0;
@@ -101113,6 +103204,8 @@ SQLITE_PRIVATE int sqlite3JournalOpen(
){
MemJournal *p = (MemJournal*)pJfd;
+ assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
+
/* Zero the file-handle object. If nSpill was passed zero, initialize
** it using the sqlite3OsOpen() function of the underlying VFS. In this
** case none of the code in this module is executed as a result of calls
@@ -101554,9 +103647,7 @@ static void resolveAlias(
pExpr->y.pWin->pOwner = pExpr;
}
}
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3ExprDelete,
- pDup);
+ sqlite3ExprDeferredDelete(pParse, pDup);
}
}
@@ -101660,6 +103751,32 @@ static void extendFJMatch(
}
/*
+** Return TRUE (non-zero) if zTab is a valid name for the schema table pTab.
+*/
+static SQLITE_NOINLINE int isValidSchemaTableName(
+ const char *zTab, /* Name as it appears in the SQL */
+ Table *pTab, /* The schema table we are trying to match */
+ Schema *pSchema /* non-NULL if a database qualifier is present */
+){
+ const char *zLegacy;
+ assert( pTab!=0 );
+ assert( pTab->tnum==1 );
+ if( sqlite3StrNICmp(zTab, "sqlite_", 7)!=0 ) return 0;
+ zLegacy = pTab->zName;
+ if( strcmp(zLegacy+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
+ return 1;
+ }
+ if( pSchema==0 ) return 0;
+ if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
+ }else{
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
+ }
+ return 0;
+}
+
+/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr
** expression node refer back to that source column. The following changes
@@ -101812,15 +103929,17 @@ static int lookupName(
}
assert( zDb==0 || zTab!=0 );
if( zTab ){
- const char *zTabName;
if( zDb ){
if( pTab->pSchema!=pSchema ) continue;
if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
}
- zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
- assert( zTabName!=0 );
- if( sqlite3StrICmp(zTabName, zTab)!=0 ){
- continue;
+ if( pItem->zAlias!=0 ){
+ if( sqlite3StrICmp(zTab, pItem->zAlias)!=0 ){
+ continue;
+ }
+ }else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){
+ if( pTab->tnum!=1 ) continue;
+ if( !isValidSchemaTableName(zTab, pTab, pSchema) ) continue;
}
assert( ExprUseYTab(pExpr) );
if( IN_RENAME_OBJECT && pItem->zAlias ){
@@ -101963,6 +104082,7 @@ static int lookupName(
if( pParse->bReturning ){
eNewExprOp = TK_REGISTER;
pExpr->op2 = TK_COLUMN;
+ pExpr->iColumn = iCol;
pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable +
sqlite3TableColumnToStorage(pTab, iCol) + 1;
}else{
@@ -103639,50 +105759,122 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){
*/
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
int op;
- while( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
- assert( pExpr->op==TK_COLLATE
- || pExpr->op==TK_IF_NULL_ROW
- || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
- pExpr = pExpr->pLeft;
- assert( pExpr!=0 );
- }
op = pExpr->op;
- if( op==TK_REGISTER ) op = pExpr->op2;
- if( op==TK_COLUMN || op==TK_AGG_COLUMN ){
- assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
+ while( 1 /* exit-by-break */ ){
+ if( op==TK_COLUMN || (op==TK_AGG_COLUMN && pExpr->y.pTab!=0) ){
+ assert( ExprUseYTab(pExpr) );
+ assert( pExpr->y.pTab!=0 );
return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
}
- }
- if( op==TK_SELECT ){
- assert( ExprUseXSelect(pExpr) );
- assert( pExpr->x.pSelect!=0 );
- assert( pExpr->x.pSelect->pEList!=0 );
- assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
- return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
- }
+ if( op==TK_SELECT ){
+ assert( ExprUseXSelect(pExpr) );
+ assert( pExpr->x.pSelect!=0 );
+ assert( pExpr->x.pSelect->pEList!=0 );
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
+ return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
+ }
#ifndef SQLITE_OMIT_CAST
- if( op==TK_CAST ){
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- return sqlite3AffinityType(pExpr->u.zToken, 0);
- }
+ if( op==TK_CAST ){
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+ return sqlite3AffinityType(pExpr->u.zToken, 0);
+ }
#endif
- if( op==TK_SELECT_COLUMN ){
- assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
- assert( pExpr->iColumn < pExpr->iTable );
- assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
- return sqlite3ExprAffinity(
- pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
- );
- }
- if( op==TK_VECTOR ){
- assert( ExprUseXList(pExpr) );
- return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ if( op==TK_SELECT_COLUMN ){
+ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
+ assert( pExpr->iColumn < pExpr->iTable );
+ assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
+ return sqlite3ExprAffinity(
+ pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
+ );
+ }
+ if( op==TK_VECTOR ){
+ assert( ExprUseXList(pExpr) );
+ return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
+ }
+ if( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
+ assert( pExpr->op==TK_COLLATE
+ || pExpr->op==TK_IF_NULL_ROW
+ || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
+ pExpr = pExpr->pLeft;
+ op = pExpr->op;
+ continue;
+ }
+ if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break;
}
return pExpr->affExpr;
}
/*
+** Make a guess at all the possible datatypes of the result that could
+** be returned by an expression. Return a bitmask indicating the answer:
+**
+** 0x01 Numeric
+** 0x02 Text
+** 0x04 Blob
+**
+** If the expression must return NULL, then 0x00 is returned.
+*/
+SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr){
+ while( pExpr ){
+ switch( pExpr->op ){
+ case TK_COLLATE:
+ case TK_IF_NULL_ROW:
+ case TK_UPLUS: {
+ pExpr = pExpr->pLeft;
+ break;
+ }
+ case TK_NULL: {
+ pExpr = 0;
+ break;
+ }
+ case TK_STRING: {
+ return 0x02;
+ }
+ case TK_BLOB: {
+ return 0x04;
+ }
+ case TK_CONCAT: {
+ return 0x06;
+ }
+ case TK_VARIABLE:
+ case TK_AGG_FUNCTION:
+ case TK_FUNCTION: {
+ return 0x07;
+ }
+ case TK_COLUMN:
+ case TK_AGG_COLUMN:
+ case TK_SELECT:
+ case TK_CAST:
+ case TK_SELECT_COLUMN:
+ case TK_VECTOR: {
+ int aff = sqlite3ExprAffinity(pExpr);
+ if( aff>=SQLITE_AFF_NUMERIC ) return 0x05;
+ if( aff==SQLITE_AFF_TEXT ) return 0x06;
+ return 0x07;
+ }
+ case TK_CASE: {
+ int res = 0;
+ int ii;
+ ExprList *pList = pExpr->x.pList;
+ assert( ExprUseXList(pExpr) && pList!=0 );
+ assert( pList->nExpr > 0);
+ for(ii=1; ii<pList->nExpr; ii+=2){
+ res |= sqlite3ExprDataType(pList->a[ii].pExpr);
+ }
+ if( pList->nExpr % 2 ){
+ res |= sqlite3ExprDataType(pList->a[pList->nExpr-1].pExpr);
+ }
+ return res;
+ }
+ default: {
+ return 0x01;
+ }
+ } /* End of switch(op) */
+ } /* End of while(pExpr) */
+ return 0x00;
+}
+
+/*
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken. Return a pointer to a new Expr node that
** implements the COLLATE operator.
@@ -103769,18 +105961,17 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
while( p ){
int op = p->op;
if( op==TK_REGISTER ) op = p->op2;
- if( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER ){
+ if( (op==TK_AGG_COLUMN && p->y.pTab!=0)
+ || op==TK_COLUMN || op==TK_TRIGGER
+ ){
+ int j;
assert( ExprUseYTab(p) );
- if( p->y.pTab!=0 ){
- /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
- ** a TK_COLUMN but was previously evaluated and cached in a register */
- int j = p->iColumn;
- if( j>=0 ){
- const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
- pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
- }
- break;
+ assert( p->y.pTab!=0 );
+ if( (j = p->iColumn)>=0 ){
+ const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
+ pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
}
+ break;
}
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
@@ -104365,7 +106556,9 @@ static void heightOfSelect(const Select *pSelect, int *pnHeight){
*/
static void exprSetHeight(Expr *p){
int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
- if( p->pRight && p->pRight->nHeight>nHeight ) nHeight = p->pRight->nHeight;
+ if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){
+ nHeight = p->pRight->nHeight;
+ }
if( ExprUseXSelect(p) ){
heightOfSelect(p->x.pSelect, &nHeight);
}else if( p->x.pList ){
@@ -104508,15 +106701,26 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
sqlite3ExprDelete(db, pLeft);
sqlite3ExprDelete(db, pRight);
}else{
+ assert( ExprUseXList(pRoot) );
+ assert( pRoot->x.pSelect==0 );
if( pRight ){
pRoot->pRight = pRight;
pRoot->flags |= EP_Propagate & pRight->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ pRoot->nHeight = pRight->nHeight+1;
+ }else{
+ pRoot->nHeight = 1;
+#endif
}
if( pLeft ){
pRoot->pLeft = pLeft;
pRoot->flags |= EP_Propagate & pLeft->flags;
+#if SQLITE_MAX_EXPR_DEPTH>0
+ if( pLeft->nHeight>=pRoot->nHeight ){
+ pRoot->nHeight = pLeft->nHeight+1;
+ }
+#endif
}
- exprSetHeight(pRoot);
}
}
@@ -104802,6 +107006,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
*/
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
assert( p!=0 );
+ assert( db!=0 );
assert( !ExprUseUValue(p) || p->u.iValue>=0 );
assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
@@ -104833,12 +107038,8 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
#endif
}
}
- if( ExprHasProperty(p, EP_MemToken) ){
- assert( !ExprHasProperty(p, EP_IntValue) );
- sqlite3DbFree(db, p->u.zToken);
- }
if( !ExprHasProperty(p, EP_Static) ){
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
}
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
@@ -104869,8 +107070,9 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
** pExpr to the pParse->pConstExpr list with a register number of 0.
*/
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- pParse->pConstExpr =
- sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr);
+ sqlite3ParserAddCleanup(pParse,
+ (void(*)(sqlite3*,void*))sqlite3ExprDelete,
+ pExpr);
}
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
@@ -104944,7 +107146,6 @@ static int dupedExprStructSize(const Expr *p, int flags){
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_OuterON) );
- assert( !ExprHasProperty(p, EP_MemToken) );
assert( !ExprHasVVAProperty(p, EP_NoReduce) );
if( p->pLeft || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
@@ -105048,7 +107249,7 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
ExprClearVVAProperties(pNew);
@@ -105624,12 +107825,13 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
int i = pList->nExpr;
struct ExprList_item *pItem = pList->a;
assert( pList->nExpr>0 );
+ assert( db!=0 );
do{
sqlite3ExprDelete(db, pItem->pExpr);
- sqlite3DbFree(db, pItem->zEName);
+ if( pItem->zEName ) sqlite3DbNNFreeNN(db, pItem->zEName);
pItem++;
}while( --i>0 );
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
@@ -106807,6 +109009,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
}
if( addrOnce ){
+ sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
sqlite3VdbeJumpHere(v, addrOnce);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
@@ -106842,6 +109045,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
SelectDest dest; /* How to deal with SELECT result */
int nReg; /* Registers to allocate */
Expr *pLimit; /* New limit expression */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain; /* Address of OP_Explain instruction */
+#endif
Vdbe *v = pParse->pVdbe;
assert( v!=0 );
@@ -106894,8 +109100,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
** In both cases, the query is augmented with "LIMIT 1". Any
** preexisting limit is discarded in place of the new LIMIT 1.
*/
- ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d",
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "%sSCALAR SUBQUERY %d",
addrOnce?"":"CORRELATED ", pSel->selId));
+ sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, -1);
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
pParse->nMem += nReg;
@@ -106920,7 +109127,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
pLimit = sqlite3PExpr(pParse, TK_NE,
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
}
- sqlite3ExprDelete(db, pSel->pLimit->pLeft);
+ sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft);
pSel->pLimit->pLeft = pLimit;
}else{
/* If there is no pre-existing limit add a limit of 1 */
@@ -106938,6 +109145,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
if( addrOnce ){
sqlite3VdbeJumpHere(v, addrOnce);
}
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
/* Subroutine return */
assert( ExprUseYSub(pExpr) );
@@ -107373,10 +109581,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
){
Column *pCol;
assert( v!=0 );
- if( pTab==0 ){
- sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
- return;
- }
+ assert( pTab!=0 );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -107434,7 +109639,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
assert( pParse->pVdbe!=0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
- VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
}
return iReg;
@@ -107503,7 +109708,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
** so that a subsequent copy will not be merged into this one.
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
- if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
+ if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
}
}
@@ -107613,10 +109818,13 @@ static int exprCodeInlineFunction(
** the type affinity of the argument. This is used for testing of
** the SQLite type logic.
*/
- const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
+ const char *azAff[] = { "blob", "text", "numeric", "integer",
+ "real", "flexnum" };
char aff;
assert( nFarg==1 );
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
+ assert( aff<=SQLITE_AFF_NONE
+ || (aff>=SQLITE_AFF_BLOB && aff<=SQLITE_AFF_FLEXNUM) );
sqlite3VdbeLoadString(v, target,
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
break;
@@ -107626,6 +109834,53 @@ static int exprCodeInlineFunction(
return target;
}
+/*
+** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
+** If it is, then resolve the expression by reading from the index and
+** return the register into which the value has been read. If pExpr is
+** not an indexed expression, then return negative.
+*/
+static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
+ Parse *pParse, /* The parsing context */
+ Expr *pExpr, /* The expression to potentially bypass */
+ int target /* Where to store the result of the expression */
+){
+ IndexedExpr *p;
+ Vdbe *v;
+ for(p=pParse->pIdxEpr; p; p=p->pIENext){
+ int iDataCur = p->iDataCur;
+ if( iDataCur<0 ) continue;
+ if( pParse->iSelfTab ){
+ if( p->iDataCur!=pParse->iSelfTab-1 ) continue;
+ iDataCur = -1;
+ }
+ if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
+ v = pParse->pVdbe;
+ assert( v!=0 );
+ if( p->bMaybeNullRow ){
+ /* If the index is on a NULL row due to an outer join, then we
+ ** cannot extract the value from the index. The value must be
+ ** computed using the original expression. */
+ int addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ sqlite3VdbeGoto(v, 0);
+ p = pParse->pIdxEpr;
+ pParse->pIdxEpr = 0;
+ sqlite3ExprCode(pParse, pExpr, target);
+ pParse->pIdxEpr = p;
+ sqlite3VdbeJumpHere(v, addr+2);
+ }else{
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
+ }
+ return target;
+ }
+ return -1; /* Not found */
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
@@ -107654,6 +109909,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
expr_code_doover:
if( pExpr==0 ){
op = TK_NULL;
+ }else if( pParse->pIdxEpr!=0
+ && !ExprHasProperty(pExpr, EP_Leaf)
+ && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0
+ ){
+ return r1;
}else{
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
@@ -107666,13 +109926,14 @@ expr_code_doover:
assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
- assert( pCol->iMem>0 );
- return pCol->iMem;
+ return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
}else if( pAggInfo->useSortingIdx ){
Table *pTab = pCol->pTab;
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
- if( pCol->iColumn<0 ){
+ if( pTab==0 ){
+ /* No comment added */
+ }else if( pCol->iColumn<0 ){
VdbeComment((v,"%s.rowid",pTab->zName));
}else{
VdbeComment((v,"%s.%s",
@@ -107682,6 +109943,11 @@ expr_code_doover:
}
}
return target;
+ }else if( pExpr->y.pTab==0 ){
+ /* This case happens when the argument to an aggregate function
+ ** is rewritten by aggregateConvertIndexedExprRefToColumn() */
+ sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, pExpr->iColumn, target);
+ return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
/* no break */ deliberate_fall_through
@@ -107699,13 +109965,10 @@ expr_code_doover:
int aff;
iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
assert( ExprUseYTab(pExpr) );
- if( pExpr->y.pTab ){
- aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
- }else{
- aff = pExpr->affExpr;
- }
+ assert( pExpr->y.pTab!=0 );
+ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
if( aff>SQLITE_AFF_BLOB ){
- static const char zAff[] = "B\000C\000D\000E";
+ static const char zAff[] = "B\000C\000D\000E\000F";
assert( SQLITE_AFF_BLOB=='A' );
assert( SQLITE_AFF_TEXT=='B' );
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
@@ -107765,12 +110028,10 @@ expr_code_doover:
}
}
assert( ExprUseYTab(pExpr) );
+ assert( pExpr->y.pTab!=0 );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
- if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
- sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
- }
return iReg;
}
case TK_INTEGER: {
@@ -107984,7 +110245,7 @@ expr_code_doover:
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr);
}else{
- return pInfo->aFunc[pExpr->iAgg].iMem;
+ return AggInfoFuncReg(pInfo, pExpr->iAgg);
}
break;
}
@@ -108269,6 +110530,21 @@ expr_code_doover:
case TK_IF_NULL_ROW: {
int addrINR;
u8 okConstFactor = pParse->okConstFactor;
+ AggInfo *pAggInfo = pExpr->pAggInfo;
+ if( pAggInfo ){
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( !pAggInfo->directMode ){
+ inReg = AggInfoColumnReg(pAggInfo, pExpr->iAgg);
+ break;
+ }
+ if( pExpr->pAggInfo->useSortingIdx ){
+ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
+ pAggInfo->aCol[pExpr->iAgg].iSorterColumn,
+ target);
+ inReg = target;
+ break;
+ }
+ }
addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
/* Temporarily disable factoring of constant expressions, since
** even though expressions may appear to be constant, they are not
@@ -108610,7 +110886,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
if( inReg!=target+i ){
VdbeOp *pOp;
if( copyOp==OP_Copy
- && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
+ && (pOp=sqlite3VdbeGetLastOp(v))->opcode==OP_Copy
&& pOp->p1+pOp->p3+1==inReg
&& pOp->p2+pOp->p3+1==target+i
&& pOp->p5==0 /* The do-not-merge flag must be clear */
@@ -108809,6 +111085,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -108983,6 +111260,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
case TK_ISNULL:
case TK_NOTNULL: {
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
+ sqlite3VdbeTypeofColumn(v, r1);
sqlite3VdbeAddOp2(v, op, r1, dest);
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
@@ -109136,7 +111414,13 @@ SQLITE_PRIVATE int sqlite3ExprCompare(
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
return 1;
}
- return 2;
+ if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN
+ && pB->iTable<0 && pA->iTable==iTab
+ ){
+ /* fall through */
+ }else{
+ return 2;
+ }
}
assert( !ExprHasProperty(pA, EP_IntValue) );
assert( !ExprHasProperty(pB, EP_IntValue) );
@@ -109438,10 +111722,10 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
if( (pLeft->op==TK_COLUMN
- && pLeft->y.pTab!=0
+ && ALWAYS(pLeft->y.pTab!=0)
&& IsVirtual(pLeft->y.pTab))
|| (pRight->op==TK_COLUMN
- && pRight->y.pTab!=0
+ && ALWAYS(pRight->y.pTab!=0)
&& IsVirtual(pRight->y.pTab))
){
return WRC_Prune;
@@ -109646,6 +111930,7 @@ static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){
SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
Walker w;
struct RefSrcList x;
+ assert( pParse->db!=0 );
memset(&w, 0, sizeof(w));
memset(&x, 0, sizeof(x));
w.xExprCallback = exprRefToSrcList;
@@ -109662,7 +111947,7 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
}
#endif
- sqlite3DbFree(pParse->db, x.aiExclude);
+ if( x.aiExclude ) sqlite3DbNNFreeNN(pParse->db, x.aiExclude);
if( w.eCode & 0x01 ){
return 1;
}else if( w.eCode ){
@@ -109680,10 +111965,8 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList
** it does, make a copy. This is done because the pExpr argument is
** subject to change.
**
-** The copy is stored on pParse->pConstExpr with a register number of 0.
-** This will cause the expression to be deleted automatically when the
-** Parse object is destroyed, but the zero register number means that it
-** will not generate any code in the preamble.
+** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete()
+** which builds on the sqlite3ParserAddCleanup() mechanism.
*/
static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
@@ -109693,8 +111976,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
- assert( pExpr->op==TK_AGG_COLUMN || pExpr->op==TK_AGG_FUNCTION );
- if( pExpr->op==TK_AGG_COLUMN ){
+ if( pExpr->op!=TK_AGG_FUNCTION ){
assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
@@ -109704,6 +111986,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
}
}
}else{
+ assert( pExpr->op==TK_AGG_FUNCTION );
assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
@@ -109761,6 +112044,73 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
}
/*
+** Search the AggInfo object for an aCol[] entry that has iTable and iColumn.
+** Return the index in aCol[] of the entry that describes that column.
+**
+** If no prior entry is found, create a new one and return -1. The
+** new column will have an idex of pAggInfo->nColumn-1.
+*/
+static void findOrCreateAggInfoColumn(
+ Parse *pParse, /* Parsing context */
+ AggInfo *pAggInfo, /* The AggInfo object to search and/or modify */
+ Expr *pExpr /* Expr describing the column to find or insert */
+){
+ struct AggInfo_col *pCol;
+ int k;
+
+ assert( pAggInfo->iFirstReg==0 );
+ pCol = pAggInfo->aCol;
+ for(k=0; k<pAggInfo->nColumn; k++, pCol++){
+ if( pCol->iTable==pExpr->iTable
+ && pCol->iColumn==pExpr->iColumn
+ && pExpr->op!=TK_IF_NULL_ROW
+ ){
+ goto fix_up_expr;
+ }
+ }
+ k = addAggInfoColumn(pParse->db, pAggInfo);
+ if( k<0 ){
+ /* OOM on resize */
+ assert( pParse->db->mallocFailed );
+ return;
+ }
+ pCol = &pAggInfo->aCol[k];
+ assert( ExprUseYTab(pExpr) );
+ pCol->pTab = pExpr->y.pTab;
+ pCol->iTable = pExpr->iTable;
+ pCol->iColumn = pExpr->iColumn;
+ pCol->iSorterColumn = -1;
+ pCol->pCExpr = pExpr;
+ if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){
+ int j, n;
+ ExprList *pGB = pAggInfo->pGroupBy;
+ struct ExprList_item *pTerm = pGB->a;
+ n = pGB->nExpr;
+ for(j=0; j<n; j++, pTerm++){
+ Expr *pE = pTerm->pExpr;
+ if( pE->op==TK_COLUMN
+ && pE->iTable==pExpr->iTable
+ && pE->iColumn==pExpr->iColumn
+ ){
+ pCol->iSorterColumn = j;
+ break;
+ }
+ }
+ }
+ if( pCol->iSorterColumn<0 ){
+ pCol->iSorterColumn = pAggInfo->nSortingColumn++;
+ }
+fix_up_expr:
+ ExprSetVVAProperty(pExpr, EP_NoReduce);
+ assert( pExpr->pAggInfo==0 || pExpr->pAggInfo==pAggInfo );
+ pExpr->pAggInfo = pAggInfo;
+ if( pExpr->op==TK_COLUMN ){
+ pExpr->op = TK_AGG_COLUMN;
+ }
+ pExpr->iAgg = (i16)k;
+}
+
+/*
** This is the xExprCallback for a tree walker. It is used to
** implement sqlite3ExprAnalyzeAggregates(). See sqlite3ExprAnalyzeAggregates
** for additional information.
@@ -109773,71 +112123,51 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
AggInfo *pAggInfo = pNC->uNC.pAggInfo;
assert( pNC->ncFlags & NC_UAggInfo );
+ assert( pAggInfo->iFirstReg==0 );
switch( pExpr->op ){
+ default: {
+ IndexedExpr *pIEpr;
+ Expr tmp;
+ assert( pParse->iSelfTab==0 );
+ if( (pNC->ncFlags & NC_InAggFunc)==0 ) break;
+ if( pParse->pIdxEpr==0 ) break;
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
+ int iDataCur = pIEpr->iDataCur;
+ if( iDataCur<0 ) continue;
+ if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break;
+ }
+ if( pIEpr==0 ) break;
+ if( NEVER(!ExprUseYTab(pExpr)) ) break;
+ if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
+
+ /* If we reach this point, it means that expression pExpr can be
+ ** translated into a reference to an index column as described by
+ ** pIEpr.
+ */
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.op = TK_AGG_COLUMN;
+ tmp.iTable = pIEpr->iIdxCur;
+ tmp.iColumn = pIEpr->iIdxCol;
+ findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
+ pExpr->pAggInfo = pAggInfo;
+ pExpr->iAgg = tmp.iAgg;
+ return WRC_Prune;
+ }
+ case TK_IF_NULL_ROW:
case TK_AGG_COLUMN:
case TK_COLUMN: {
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_COLUMN );
+ testcase( pExpr->op==TK_IF_NULL_ROW );
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
if( ALWAYS(pSrcList!=0) ){
SrcItem *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
- struct AggInfo_col *pCol;
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
- /* If we reach this point, it means that pExpr refers to a table
- ** that is in the FROM clause of the aggregate query.
- **
- ** Make an entry for the column in pAggInfo->aCol[] if there
- ** is not an entry there already.
- */
- int k;
- pCol = pAggInfo->aCol;
- for(k=0; k<pAggInfo->nColumn; k++, pCol++){
- if( pCol->iTable==pExpr->iTable &&
- pCol->iColumn==pExpr->iColumn ){
- break;
- }
- }
- if( (k>=pAggInfo->nColumn)
- && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
- ){
- pCol = &pAggInfo->aCol[k];
- assert( ExprUseYTab(pExpr) );
- pCol->pTab = pExpr->y.pTab;
- pCol->iTable = pExpr->iTable;
- pCol->iColumn = pExpr->iColumn;
- pCol->iMem = ++pParse->nMem;
- pCol->iSorterColumn = -1;
- pCol->pCExpr = pExpr;
- if( pAggInfo->pGroupBy ){
- int j, n;
- ExprList *pGB = pAggInfo->pGroupBy;
- struct ExprList_item *pTerm = pGB->a;
- n = pGB->nExpr;
- for(j=0; j<n; j++, pTerm++){
- Expr *pE = pTerm->pExpr;
- if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
- pE->iColumn==pExpr->iColumn ){
- pCol->iSorterColumn = j;
- break;
- }
- }
- }
- if( pCol->iSorterColumn<0 ){
- pCol->iSorterColumn = pAggInfo->nSortingColumn++;
- }
- }
- /* There is now an entry for pExpr in pAggInfo->aCol[] (either
- ** because it was there before or because we just created it).
- ** Convert the pExpr to be a TK_AGG_COLUMN referring to that
- ** pAggInfo->aCol[] entry.
- */
- ExprSetVVAProperty(pExpr, EP_NoReduce);
- pExpr->pAggInfo = pAggInfo;
- pExpr->op = TK_AGG_COLUMN;
- pExpr->iAgg = (i16)k;
+ findOrCreateAggInfoColumn(pParse, pAggInfo, pExpr);
break;
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
@@ -109867,7 +112197,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pFExpr = pExpr;
- pItem->iMem = ++pParse->nMem;
assert( ExprUseUToken(pExpr) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
pExpr->u.zToken,
@@ -110764,13 +113093,14 @@ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
if( pParse->nErr==0 ){
const RenameToken *p;
- u8 i = 0;
+ u32 i = 1;
for(p=pParse->pRename; p; p=p->pNext){
if( p->p ){
assert( p->p!=pPtr );
- i += *(u8*)(p->p);
+ i += *(u8*)(p->p) | 1;
}
}
+ assert( i>0 );
}
}
#else
@@ -113256,6 +115586,7 @@ static void analyzeVdbeCommentIndexWithColumnName(
if( NEVER(i==XN_ROWID) ){
VdbeComment((v,"%s.rowid",pIdx->zName));
}else if( i==XN_EXPR ){
+ assert( pIdx->bHasExpr );
VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
}else{
VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
@@ -113899,6 +116230,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
** and its contents.
*/
SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
+ assert( db!=0 );
+ assert( pIdx!=0 );
#ifdef SQLITE_ENABLE_STAT4
if( pIdx->aSample ){
int j;
@@ -113908,7 +116241,7 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
}
sqlite3DbFree(db, pIdx->aSample);
}
- if( db && db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
pIdx->nSample = 0;
pIdx->aSample = 0;
}
@@ -114327,7 +116660,7 @@ static void attachFunc(
char *zErr = 0;
unsigned int flags;
Db *aNew; /* New array of Db pointers */
- Db *pNew; /* Db object for the newly attached database */
+ Db *pNew = 0; /* Db object for the newly attached database */
char *zErrDyn = 0;
sqlite3_vfs *pVfs;
@@ -114347,13 +116680,26 @@ static void attachFunc(
/* This is not a real ATTACH. Instead, this routine is being called
** from sqlite3_deserialize() to close database db->init.iDb and
** reopen it as a MemDB */
+ Btree *pNewBt = 0;
pVfs = sqlite3_vfs_find("memdb");
if( pVfs==0 ) return;
- pNew = &db->aDb[db->init.iDb];
- if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
- pNew->pBt = 0;
- pNew->pSchema = 0;
- rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
+ rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
+ if( rc==SQLITE_OK ){
+ Schema *pNewSchema = sqlite3SchemaGet(db, pNewBt);
+ if( pNewSchema ){
+ /* Both the Btree and the new Schema were allocated successfully.
+ ** Close the old db and update the aDb[] slot with the new memdb
+ ** values. */
+ pNew = &db->aDb[db->init.iDb];
+ if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt);
+ pNew->pBt = pNewBt;
+ pNew->pSchema = pNewSchema;
+ }else{
+ sqlite3BtreeClose(pNewBt);
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc ) goto attach_error;
}else{
/* This is a real ATTACH
**
@@ -114466,7 +116812,7 @@ static void attachFunc(
}
#endif
if( rc ){
- if( !REOPEN_AS_MEMDB(db) ){
+ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
int iDb = db->nDb - 1;
assert( iDb>=2 );
if( db->aDb[iDb].pBt ){
@@ -114583,6 +116929,8 @@ static void codeAttach(
sqlite3* db = pParse->db;
int regArgs;
+ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end;
+
if( pParse->nErr ) goto attach_end;
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
@@ -115258,6 +117606,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
sqlite3 *db;
Vdbe *v;
+ int iDb, i;
assert( pParse->pToplevel==0 );
db = pParse->db;
@@ -115287,7 +117636,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
if( pParse->bReturning ){
Returning *pReturning = pParse->u1.pReturning;
int addrRewind;
- int i;
int reg;
if( pReturning->nRetCol ){
@@ -115324,76 +117672,69 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
** transaction on each used database and to verify the schema cookie
** on each used database.
*/
- if( db->mallocFailed==0
- && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
- ){
- int iDb, i;
- assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
- sqlite3VdbeJumpHere(v, 0);
- assert( db->nDb>0 );
- iDb = 0;
- do{
- Schema *pSchema;
- if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
- sqlite3VdbeUsesBtree(v, iDb);
- pSchema = db->aDb[iDb].pSchema;
- sqlite3VdbeAddOp4Int(v,
- OP_Transaction, /* Opcode */
- iDb, /* P1 */
- DbMaskTest(pParse->writeMask,iDb), /* P2 */
- pSchema->schema_cookie, /* P3 */
- pSchema->iGeneration /* P4 */
- );
- if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
- VdbeComment((v,
- "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
- }while( ++iDb<db->nDb );
+ assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
+ sqlite3VdbeJumpHere(v, 0);
+ assert( db->nDb>0 );
+ iDb = 0;
+ do{
+ Schema *pSchema;
+ if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
+ sqlite3VdbeUsesBtree(v, iDb);
+ pSchema = db->aDb[iDb].pSchema;
+ sqlite3VdbeAddOp4Int(v,
+ OP_Transaction, /* Opcode */
+ iDb, /* P1 */
+ DbMaskTest(pParse->writeMask,iDb), /* P2 */
+ pSchema->schema_cookie, /* P3 */
+ pSchema->iGeneration /* P4 */
+ );
+ if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
+ VdbeComment((v,
+ "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
+ }while( ++iDb<db->nDb );
#ifndef SQLITE_OMIT_VIRTUALTABLE
- for(i=0; i<pParse->nVtabLock; i++){
- char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
- sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
- }
- pParse->nVtabLock = 0;
+ for(i=0; i<pParse->nVtabLock; i++){
+ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
+ sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
+ }
+ pParse->nVtabLock = 0;
#endif
- /* Once all the cookies have been verified and transactions opened,
- ** obtain the required table-locks. This is a no-op unless the
- ** shared-cache feature is enabled.
- */
- codeTableLocks(pParse);
+ /* Once all the cookies have been verified and transactions opened,
+ ** obtain the required table-locks. This is a no-op unless the
+ ** shared-cache feature is enabled.
+ */
+ codeTableLocks(pParse);
- /* Initialize any AUTOINCREMENT data structures required.
- */
- sqlite3AutoincrementBegin(pParse);
+ /* Initialize any AUTOINCREMENT data structures required.
+ */
+ sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
- */
- if( pParse->pConstExpr ){
- ExprList *pEL = pParse->pConstExpr;
- pParse->okConstFactor = 0;
- for(i=0; i<pEL->nExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- if( iReg>0 ){
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
- }
- }
+ /* Code constant expressions that where factored out of inner loops.
+ **
+ ** The pConstExpr list might also contain expressions that we simply
+ ** want to keep around until the Parse object is deleted. Such
+ ** expressions have iConstExprReg==0. Do not generate code for
+ ** those expressions, of course.
+ */
+ if( pParse->pConstExpr ){
+ ExprList *pEL = pParse->pConstExpr;
+ pParse->okConstFactor = 0;
+ for(i=0; i<pEL->nExpr; i++){
+ int iReg = pEL->a[i].u.iConstExprReg;
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
}
+ }
- if( pParse->bReturning ){
- Returning *pRet = pParse->u1.pReturning;
- if( pRet->nRetCol ){
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
- }
+ if( pParse->bReturning ){
+ Returning *pRet = pParse->u1.pReturning;
+ if( pRet->nRetCol ){
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
}
-
- /* Finally, jump back to the beginning of the executable code. */
- sqlite3VdbeGoto(v, 1);
}
+
+ /* Finally, jump back to the beginning of the executable code. */
+ sqlite3VdbeGoto(v, 1);
}
/* Get the VDBE program ready for execution
@@ -115432,6 +117773,7 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
char saveBuf[PARSE_TAIL_SZ];
if( pParse->nErr ) return;
+ if( pParse->eParseMode ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
va_start(ap, zFormat);
zSql = sqlite3VMPrintf(db, zFormat, ap);
@@ -115578,7 +117920,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
- if( pParse->disableVtab==0 && db->init.busy==0 ){
+ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
pMod = sqlite3PragmaVtabRegister(db, zName);
@@ -115591,7 +117933,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
#endif
if( flags & LOCATE_NOERR ) return 0;
pParse->checkSchema = 1;
- }else if( IsVirtual(p) && pParse->disableVtab ){
+ }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){
p = 0;
}
@@ -115900,16 +118242,17 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
int i;
Column *pCol;
assert( pTable!=0 );
+ assert( db!=0 );
if( (pCol = pTable->aCol)!=0 ){
for(i=0; i<pTable->nCol; i++, pCol++){
assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
sqlite3DbFree(db, pCol->zCnName);
}
- sqlite3DbFree(db, pTable->aCol);
+ sqlite3DbNNFreeNN(db, pTable->aCol);
if( IsOrdinaryTable(pTable) ){
sqlite3ExprListDelete(db, pTable->u.tab.pDfltList);
}
- if( db==0 || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
pTable->aCol = 0;
pTable->nCol = 0;
if( IsOrdinaryTable(pTable) ){
@@ -115946,7 +118289,8 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
** a Table object that was going to be marked ephemeral. So do not check
** that no lookaside memory is used in this case either. */
int nLookaside = 0;
- if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
+ assert( db!=0 );
+ if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
nLookaside = sqlite3LookasideUsed(db, 0);
}
#endif
@@ -115956,7 +118300,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
pNext = pIndex->pNext;
assert( pIndex->pSchema==pTable->pSchema
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
- if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
+ if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
@@ -115993,8 +118337,9 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
}
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Do not delete the table until the reference count reaches zero. */
+ assert( db!=0 );
if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
+ if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
@@ -117126,6 +119471,13 @@ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType
if( pCol->colFlags & COLFLAG_PRIMKEY ){
makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
}
+ if( ALWAYS(pExpr) && pExpr->op==TK_ID ){
+ /* The value of a generated column needs to be a real expression, not
+ ** just a reference to another column, in order for covering index
+ ** optimizations to work correctly. So if the value is not an expression,
+ ** turn it into one by adding a unary "+" operator. */
+ pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0);
+ }
sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr);
pExpr = 0;
goto generated_done;
@@ -117262,7 +119614,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){
/* SQLITE_AFF_TEXT */ " TEXT",
/* SQLITE_AFF_NUMERIC */ " NUM",
/* SQLITE_AFF_INTEGER */ " INT",
- /* SQLITE_AFF_REAL */ " REAL"
+ /* SQLITE_AFF_REAL */ " REAL",
+ /* SQLITE_AFF_FLEXNUM */ " NUM",
};
int len;
const char *zType;
@@ -117278,10 +119631,12 @@ static char *createTableStmt(sqlite3 *db, Table *p){
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
testcase( pCol->affinity==SQLITE_AFF_REAL );
+ testcase( pCol->affinity==SQLITE_AFF_FLEXNUM );
zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
len = sqlite3Strlen30(zType);
assert( pCol->affinity==SQLITE_AFF_BLOB
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
memcpy(&zStmt[k], zType, len);
k += len;
@@ -117398,7 +119753,8 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
/* Recompute the colNotIdxed field of the Index.
**
** colNotIdxed is a bitmask that has a 0 bit representing each indexed
-** columns that are within the first 63 columns of the table. The
+** columns that are within the first 63 columns of the table and a 1 for
+** all other bits (all columns that are not in the index). The
** high-order bit of colNotIdxed is always 1. All unindexed columns
** of the table have a 1.
**
@@ -117426,7 +119782,7 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
}
}
pIdx->colNotIdxed = ~m;
- assert( (pIdx->colNotIdxed>>63)==1 );
+ assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */
}
/*
@@ -117695,6 +120051,7 @@ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
** not pass them into code generator routines by mistake.
*/
static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
+ (void)pWalker;
ExprSetVVAProperty(pExpr, EP_Immutable);
return WRC_Continue;
}
@@ -118167,7 +120524,7 @@ create_view_fail:
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
-SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
Table *pSelTab; /* A fake table from which we get the result set */
Select *pSel; /* Copy of the SELECT that implements the view */
int nErr = 0; /* Number of errors encountered */
@@ -118192,9 +120549,10 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#ifndef SQLITE_OMIT_VIEW
/* A positive nCol means the columns names for this view are
- ** already known.
+ ** already known. This routine is not called unless either the
+ ** table is virtual or nCol is zero.
*/
- if( pTable->nCol>0 ) return 0;
+ assert( pTable->nCol<=0 );
/* A negative nCol is a special marker meaning that we are currently
** trying to compute the column names. If we enter this routine with
@@ -118260,8 +120618,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
&& pTable->nCol==pSel->pEList->nExpr
){
assert( db->mallocFailed==0 );
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
- SQLITE_AFF_NONE);
+ sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE);
}
}else{
/* CREATE VIEW name AS... without an argument list. Construct
@@ -118290,6 +120647,11 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
+SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
+ assert( pTable!=0 );
+ if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0;
+ return viewGetColumnNames(pParse, pTable);
+}
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifndef SQLITE_OMIT_VIEW
@@ -119155,7 +121517,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
if( !IN_RENAME_OBJECT ){
if( !db->init.busy ){
- if( sqlite3FindTable(db, zName, 0)!=0 ){
+ if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
@@ -119308,6 +121670,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
j = XN_EXPR;
pIndex->aiColumn[i] = XN_EXPR;
pIndex->uniqNotNull = 0;
+ pIndex->bHasExpr = 1;
}else{
j = pCExpr->iColumn;
assert( j<=0x7fff );
@@ -119319,6 +121682,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
}
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
pIndex->bHasVCol = 1;
+ pIndex->bHasExpr = 1;
}
}
pIndex->aiColumn[i] = (i16)j;
@@ -119808,12 +122172,13 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *
*/
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
int i;
+ assert( db!=0 );
if( pList==0 ) return;
assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
for(i=0; i<pList->nId; i++){
sqlite3DbFree(db, pList->a[i].zName);
}
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -120016,11 +122381,12 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
int i;
SrcItem *pItem;
+ assert( db!=0 );
if( pList==0 ) return;
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
- if( pItem->zDatabase ) sqlite3DbFreeNN(db, pItem->zDatabase);
- sqlite3DbFree(db, pItem->zName);
- if( pItem->zAlias ) sqlite3DbFreeNN(db, pItem->zAlias);
+ if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
+ if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
+ if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
sqlite3DeleteTable(db, pItem->pTab);
@@ -120031,7 +122397,7 @@ SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
sqlite3ExprDelete(db, pItem->u3.pOn);
}
}
- sqlite3DbFreeNN(db, pList);
+ sqlite3DbNNFreeNN(db, pList);
}
/*
@@ -121283,19 +123649,21 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
+ sqlite3 xdb;
+ memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
- sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
+ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(0, pTab);
+ sqlite3DeleteTable(&xdb, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
@@ -121394,18 +123762,42 @@ SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *
** 1) It is a virtual table and no implementation of the xUpdate method
** has been provided
**
-** 2) It is a system table (i.e. sqlite_schema), this call is not
+** 2) A trigger is currently being coded and the table is a virtual table
+** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
+** the table is not SQLITE_VTAB_INNOCUOUS.
+**
+** 3) It is a system table (i.e. sqlite_schema), this call is not
** part of a nested parse and writable_schema pragma has not
** been specified
**
-** 3) The table is a shadow table, the database connection is in
+** 4) The table is a shadow table, the database connection is in
** defensive mode, and the current sqlite3_prepare()
** is for a top-level SQL statement.
*/
+static int vtabIsReadOnly(Parse *pParse, Table *pTab){
+ if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
+ return 1;
+ }
+
+ /* Within triggers:
+ ** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
+ ** virtual tables
+ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
+ ** virtual tables if PRAGMA trusted_schema=ON.
+ */
+ if( pParse->pToplevel!=0
+ && pTab->u.vtab.p->eVtabRisk >
+ ((pParse->db->flags & SQLITE_TrustedSchema)!=0)
+ ){
+ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
+ pTab->zName);
+ }
+ return 0;
+}
static int tabIsReadOnly(Parse *pParse, Table *pTab){
sqlite3 *db;
if( IsVirtual(pTab) ){
- return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
+ return vtabIsReadOnly(pParse, pTab);
}
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
db = pParse->db;
@@ -121417,9 +123809,11 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
}
/*
-** Check to make sure the given table is writable. If it is not
-** writable, generate an error message and return 1. If it is
-** writable return 0;
+** Check to make sure the given table is writable.
+**
+** If pTab is not writable -> generate an error message and return 1.
+** If pTab is writable but other errors have occurred -> return 1.
+** If pTab is writable and no prior errors -> return 0;
*/
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
if( tabIsReadOnly(pParse, pTab) ){
@@ -121780,9 +124174,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->pSchema==pTab->pSchema );
- sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- sqlite3VdbeChangeP3(v, -1, memCnt ? memCnt : -1);
+ sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
}
}
}else
@@ -121982,7 +124377,7 @@ delete_from_cleanup:
sqlite3ExprListDelete(db, pOrderBy);
sqlite3ExprDelete(db, pLimit);
#endif
- sqlite3DbFree(db, aToOpen);
+ if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen);
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -123065,7 +125460,7 @@ static int patternCompare(
** c but in the other case and search the input string for either
** c or cx.
*/
- if( c<=0x80 ){
+ if( c<0x80 ){
char zStop[3];
int bMatch;
if( noCase ){
@@ -123148,7 +125543,13 @@ static int patternCompare(
** non-zero if there is no match.
*/
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ if( zString==0 ){
+ return zGlobPattern!=0;
+ }else if( zGlobPattern==0 ){
+ return 1;
+ }else {
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
+ }
}
/*
@@ -123156,7 +125557,13 @@ SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
** a miss - like strcmp().
*/
SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ if( zStr==0 ){
+ return zPattern!=0;
+ }else if( zPattern==0 ){
+ return 1;
+ }else{
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
+ }
}
/*
@@ -123395,7 +125802,7 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
}
case SQLITE_BLOB: {
char const *zBlob = sqlite3_value_blob(pValue);
- int nBlob = sqlite3_value_bytes(pValue);
+ i64 nBlob = sqlite3_value_bytes(pValue);
assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */
sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4);
if( pStr->accError==0 ){
@@ -123537,6 +125944,96 @@ static void hexFunc(
}
/*
+** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr
+** contains character ch, or 0 if it does not.
+*/
+static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
+ const u8 *zEnd = &zStr[nStr];
+ const u8 *z = zStr;
+ while( z<zEnd ){
+ u32 tst = Utf8Read(z);
+ if( tst==ch ) return 1;
+ }
+ return 0;
+}
+
+/*
+** The unhex() function. This function may be invoked with either one or
+** two arguments. In both cases the first argument is interpreted as text
+** a text value containing a set of pairs of hexadecimal digits which are
+** decoded and returned as a blob.
+**
+** If there is only a single argument, then it must consist only of an
+** even number of hexadeximal digits. Otherwise, return NULL.
+**
+** Or, if there is a second argument, then any character that appears in
+** the second argument is also allowed to appear between pairs of hexadecimal
+** digits in the first argument. If any other character appears in the
+** first argument, or if one of the allowed characters appears between
+** two hexadecimal digits that make up a single byte, NULL is returned.
+**
+** The following expressions are all true:
+**
+** unhex('ABCD') IS x'ABCD'
+** unhex('AB CD') IS NULL
+** unhex('AB CD', ' ') IS x'ABCD'
+** unhex('A BCD', ' ') IS NULL
+*/
+static void unhexFunc(
+ sqlite3_context *pCtx,
+ int argc,
+ sqlite3_value **argv
+){
+ const u8 *zPass = (const u8*)"";
+ int nPass = 0;
+ const u8 *zHex = sqlite3_value_text(argv[0]);
+ int nHex = sqlite3_value_bytes(argv[0]);
+#ifdef SQLITE_DEBUG
+ const u8 *zEnd = zHex ? &zHex[nHex] : 0;
+#endif
+ u8 *pBlob = 0;
+ u8 *p = 0;
+
+ assert( argc==1 || argc==2 );
+ if( argc==2 ){
+ zPass = sqlite3_value_text(argv[1]);
+ nPass = sqlite3_value_bytes(argv[1]);
+ }
+ if( !zHex || !zPass ) return;
+
+ p = pBlob = contextMalloc(pCtx, (nHex/2)+1);
+ if( pBlob ){
+ u8 c; /* Most significant digit of next byte */
+ u8 d; /* Least significant digit of next byte */
+
+ while( (c = *zHex)!=0x00 ){
+ while( !sqlite3Isxdigit(c) ){
+ u32 ch = Utf8Read(zHex);
+ assert( zHex<=zEnd );
+ if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null;
+ c = *zHex;
+ if( c==0x00 ) goto unhex_done;
+ }
+ zHex++;
+ assert( *zEnd==0x00 );
+ assert( zHex<=zEnd );
+ d = *(zHex++);
+ if( !sqlite3Isxdigit(d) ) goto unhex_null;
+ *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d);
+ }
+ }
+
+ unhex_done:
+ sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free);
+ return;
+
+ unhex_null:
+ sqlite3_free(pBlob);
+ return;
+}
+
+
+/*
** The zeroblob(N) function returns a zero-filled blob of size N bytes.
*/
static void zeroblobFunc(
@@ -123753,6 +126250,9 @@ static void unknownFunc(
sqlite3_value **argv
){
/* no-op */
+ (void)context;
+ (void)argc;
+ (void)argv;
}
#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
@@ -124419,17 +126919,15 @@ static void logFunc(
}
ans = log(x)/b;
}else{
- ans = log(x);
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
case 1:
- /* Convert from natural logarithm to log base 10 */
- ans /= M_LN10;
+ ans = log10(x);
break;
case 2:
- /* Convert from natural logarithm to log base 2 */
- ans /= M_LN2;
+ ans = log2(x);
break;
default:
+ ans = log(x);
break;
}
}
@@ -124498,6 +126996,7 @@ static void piFunc(
sqlite3_value **argv
){
assert( argc==0 );
+ (void)argv;
sqlite3_result_double(context, M_PI);
}
@@ -124598,6 +127097,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
FUNCTION(hex, 1, 0, 0, hexFunc ),
+ FUNCTION(unhex, 1, 0, 0, unhexFunc ),
+ FUNCTION(unhex, 2, 0, 0, unhexFunc ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -126150,11 +128651,12 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pNext; /* Copy of pFKey->pNextFrom */
assert( IsOrdinaryTable(pTab) );
+ assert( db!=0 );
for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
/* Remove the FK from the fkeyHash hash table. */
- if( !db || db->pnBytesFreed==0 ){
+ if( db->pnBytesFreed==0 ){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
@@ -126284,6 +128786,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
aff = SQLITE_AFF_INTEGER;
}else{
assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
assert( pIdx->aColExpr!=0 );
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
@@ -126298,6 +128801,28 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
}
/*
+** Compute an affinity string for a table. Space is obtained
+** from sqlite3DbMalloc(). The caller is responsible for freeing
+** the space when done.
+*/
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
+ char *zColAff;
+ zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
+ if( zColAff ){
+ int i, j;
+ for(i=j=0; i<pTab->nCol; i++){
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
+ zColAff[j++] = pTab->aCol[i].affinity;
+ }
+ }
+ do{
+ zColAff[j--] = 0;
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
+ }
+ return zColAff;
+}
+
+/*
** Make changes to the evolving bytecode to do affinity transformations
** of values that are about to be gathered into a row for table pTab.
**
@@ -126338,7 +128863,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
** Apply the type checking to that array of registers.
*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
- int i, j;
+ int i;
char *zColAff;
if( pTab->tabFlags & TF_Strict ){
if( iReg==0 ){
@@ -126347,7 +128872,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
** OP_MakeRecord is found */
VdbeOp *pPrev;
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
- pPrev = sqlite3VdbeGetOp(v, -1);
+ pPrev = sqlite3VdbeGetLastOp(v);
assert( pPrev!=0 );
assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
pPrev->opcode = OP_TypeCheck;
@@ -126361,22 +128886,11 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
}
zColAff = pTab->zColAff;
if( zColAff==0 ){
- sqlite3 *db = sqlite3VdbeDb(v);
- zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
+ zColAff = sqlite3TableAffinityStr(0, pTab);
if( !zColAff ){
- sqlite3OomFault(db);
+ sqlite3OomFault(sqlite3VdbeDb(v));
return;
}
-
- for(i=j=0; i<pTab->nCol; i++){
- assert( pTab->aCol[i].affinity!=0 || sqlite3VdbeParser(v)->nErr>0 );
- if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
- zColAff[j++] = pTab->aCol[i].affinity;
- }
- }
- do{
- zColAff[j--] = 0;
- }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
pTab->zColAff = zColAff;
}
assert( zColAff!=0 );
@@ -126385,7 +128899,7 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
if( iReg ){
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
}else{
- assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord
+ assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|| sqlite3VdbeDb(v)->mallocFailed );
sqlite3VdbeChangeP4(v, -1, zColAff, i);
}
@@ -126471,7 +128985,7 @@ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
*/
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
if( (pTab->tabFlags & TF_HasStored)!=0 ){
- pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
+ pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Affinity ){
/* Change the OP_Affinity argument to '@' (NONE) for all stored
** columns. '@' is the no-op affinity and those columns have not
@@ -127377,7 +129891,12 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
}
}else{
- sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
+ Expr *pX = pList->a[k].pExpr;
+ int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
+ if( y!=iRegStore ){
+ sqlite3VdbeAddOp2(v,
+ ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
+ }
}
}
@@ -127514,7 +130033,9 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
);
- sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ if( db->flags & SQLITE_ForeignKeys ){
+ sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+ }
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
** constraints or (b) there are no triggers and this table is not a
@@ -127598,7 +130119,7 @@ insert_cleanup:
sqlite3UpsertDelete(db, pUpsert);
sqlite3SelectDelete(db, pSelect);
sqlite3IdListDelete(db, pColumn);
- sqlite3DbFree(db, aRegIdx);
+ if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -127962,6 +130483,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
pCol->zCnName);
+ testcase( zMsg==0 && db->mallocFailed==0 );
sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
onError, iReg);
sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
@@ -129825,9 +132347,9 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
- char *(*create_filename)(const char*,const char*,const char*,
+ const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
- void (*free_filename)(char*);
+ void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
@@ -129851,6 +132373,10 @@ struct sqlite3_api_routines {
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
+ /* Version 3.40.0 and later */
+ int (*value_encoding)(sqlite3_value*);
+ /* Version 3.41.0 and later */
+ int (*is_interrupted)(sqlite3*);
};
/*
@@ -130175,6 +132701,10 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
+/* Version 3.40.0 and later */
+#define sqlite3_value_encoding sqlite3_api->value_encoding
+/* Version 3.41.0 and later */
+#define sqlite3_is_interrupted sqlite3_api->is_interrupted
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -130687,7 +133217,11 @@ static const sqlite3_api_routines sqlite3Apis = {
0,
0,
#endif
- sqlite3_db_name
+ sqlite3_db_name,
+ /* Version 3.40.0 and later */
+ sqlite3_value_encoding,
+ /* Version 3.41.0 and later */
+ sqlite3_is_interrupted
};
/* True if x is the directory separator character
@@ -132704,6 +135238,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_temp_directory);
}else{
@@ -132713,6 +135248,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
@@ -132730,6 +135266,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
#endif /* SQLITE_OMIT_WSD */
}
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
@@ -132748,6 +135285,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
*/
case PragTyp_DATA_STORE_DIRECTORY: {
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
if( !zRight ){
returnSingleText(v, sqlite3_data_directory);
}else{
@@ -132757,6 +135295,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
if( rc!=SQLITE_OK || res==0 ){
sqlite3ErrorMsg(pParse, "not a writable directory");
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
goto pragma_out;
}
}
@@ -132768,6 +135307,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
#endif /* SQLITE_OMIT_WSD */
}
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
break;
}
#endif
@@ -133481,15 +136021,24 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx, *pPk;
- Index *pPrior = 0;
+ Index *pPrior = 0; /* Previous index */
int loopTop;
int iDataCur, iIdxCur;
int r1 = -1;
- int bStrict;
+ int bStrict; /* True for a STRICT table */
+ int r2; /* Previous key for WITHOUT ROWID tables */
+ int mxCol; /* Maximum non-virtual column number */
if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
- pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
+ if( isQuick || HasRowid(pTab) ){
+ pPk = 0;
+ r2 = 0;
+ }else{
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
+ sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
+ }
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
1, 0, &iDataCur, &iIdxCur);
/* reg[7] counts the number of entries in the table.
@@ -133503,52 +136052,166 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
+
+ /* Fetch the right-most column from the table. This will cause
+ ** the entire record header to be parsed and sanity checked. It
+ ** will also prepopulate the cursor column cache that is used
+ ** by the OP_IsType code, so it is a required step.
+ */
+ assert( !IsVirtual(pTab) );
+ if( HasRowid(pTab) ){
+ mxCol = -1;
+ for(j=0; j<pTab->nCol; j++){
+ if( (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)==0 ) mxCol++;
+ }
+ if( mxCol==pTab->iPKey ) mxCol--;
+ }else{
+ /* COLFLAG_VIRTUAL columns are not included in the WITHOUT ROWID
+ ** PK index column-count, so there is no need to account for them
+ ** in this case. */
+ mxCol = sqlite3PrimaryKeyIndex(pTab)->nColumn-1;
+ }
+ if( mxCol>=0 ){
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, mxCol, 3);
+ sqlite3VdbeTypeofColumn(v, 3);
+ }
+
if( !isQuick ){
- /* Sanity check on record header decoding */
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
- VdbeComment((v, "(right-most column)"));
+ if( pPk ){
+ /* Verify WITHOUT ROWID keys are in ascending order */
+ int a1;
+ char *zErr;
+ a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db,
+ "row not in PRIMARY KEY order for %s",
+ pTab->zName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, a1);
+ sqlite3VdbeJumpHere(v, a1+1);
+ for(j=0; j<pPk->nKeyCol; j++){
+ sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
+ }
+ }
}
- /* Verify that all NOT NULL columns really are NOT NULL. At the
- ** same time verify the type of the content of STRICT tables */
+ /* Verify datatypes for all columns:
+ **
+ ** (1) NOT NULL columns may not contain a NULL
+ ** (2) Datatype must be exact for non-ANY columns in STRICT tables
+ ** (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB.
+ ** (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be losslessly converted to numeric.
+ */
bStrict = (pTab->tabFlags & TF_Strict)!=0;
for(j=0; j<pTab->nCol; j++){
char *zErr;
- Column *pCol = pTab->aCol + j;
- int doError, jmp2;
+ Column *pCol = pTab->aCol + j; /* The column to be checked */
+ int labelError; /* Jump here to report an error */
+ int labelOk; /* Jump here if all looks ok */
+ int p1, p3, p4; /* Operands to the OP_IsType opcode */
+ int doTypeCheck; /* Check datatypes (besides NOT NULL) */
+
if( j==pTab->iPKey ) continue;
- if( pCol->notNull==0 && !bStrict ) continue;
- doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0;
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
- if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
+ if( bStrict ){
+ doTypeCheck = pCol->eCType>COLTYPE_ANY;
+ }else{
+ doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
+ }
+ if( pCol->notNull==0 && !doTypeCheck ) continue;
+
+ /* Compute the operands that will be needed for OP_IsType */
+ p4 = SQLITE_NULL;
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ p1 = -1;
+ p3 = 3;
+ }else{
+ if( pCol->iDflt ){
+ sqlite3_value *pDfltValue = 0;
+ sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db),
+ pCol->affinity, &pDfltValue);
+ if( pDfltValue ){
+ p4 = sqlite3_value_type(pDfltValue);
+ sqlite3ValueFree(pDfltValue);
+ }
+ }
+ p1 = iDataCur;
+ if( !HasRowid(pTab) ){
+ testcase( j!=sqlite3TableColumnToStorage(pTab, j) );
+ p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j);
+ }else{
+ p3 = sqlite3TableColumnToStorage(pTab,j);
+ testcase( p3!=j);
+ }
}
+
+ labelError = sqlite3VdbeMakeLabel(pParse);
+ labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
- jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
+ /* (1) NOT NULL columns may not contain a NULL */
+ int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x0f);
+ VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- if( bStrict && pCol->eCType!=COLTYPE_ANY ){
- sqlite3VdbeGoto(v, doError);
+ if( doTypeCheck ){
+ sqlite3VdbeGoto(v, labelError);
+ sqlite3VdbeJumpHere(v, jmp2);
}else{
- integrityCheckResultRow(v);
+ /* VDBE byte code will fall thru */
}
- sqlite3VdbeJumpHere(v, jmp2);
}
- if( (pTab->tabFlags & TF_Strict)!=0
- && pCol->eCType!=COLTYPE_ANY
- ){
- jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0,
- sqlite3StdTypeMap[pCol->eCType-1]);
+ if( bStrict && doTypeCheck ){
+ /* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
+ static unsigned char aStdTypeMask[] = {
+ 0x1f, /* ANY */
+ 0x18, /* BLOB */
+ 0x11, /* INT */
+ 0x11, /* INTEGER */
+ 0x13, /* REAL */
+ 0x14 /* TEXT */
+ };
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
+ sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
VdbeCoverage(v);
zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
sqlite3StdType[pCol->eCType-1],
pTab->zName, pTab->aCol[j].zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
- sqlite3VdbeResolveLabel(v, doError);
- integrityCheckResultRow(v);
- sqlite3VdbeJumpHere(v, jmp2);
+ }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
+ /* (3) Datatype for TEXT columns in non-STRICT tables must be
+ ** NULL, TEXT, or BLOB. */
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
+ }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
+ /* (4) Datatype for numeric columns in non-STRICT tables must not
+ ** be a TEXT value that can be converted to numeric. */
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
+ sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
+ VdbeCoverage(v);
+ if( p1>=0 ){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
+ }
+ sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
+ sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
+ VdbeCoverage(v);
+ zErr = sqlite3MPrintf(db, "TEXT value in %s.%s",
+ pTab->zName, pTab->aCol[j].zCnName);
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
}
+ sqlite3VdbeResolveLabel(v, labelError);
+ integrityCheckResultRow(v);
+ sqlite3VdbeResolveLabel(v, labelOk);
}
/* Verify CHECK constraints */
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
@@ -133577,7 +136240,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( !isQuick ){ /* Omit the remaining tests for quick_check */
/* Validate index entries for the current row */
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
- int jmp2, jmp3, jmp4, jmp5;
+ int jmp2, jmp3, jmp4, jmp5, label6;
+ int kk;
int ckUniq = sqlite3VdbeMakeLabel(pParse);
if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
@@ -133595,13 +136259,32 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
jmp4 = integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
+
+ /* Any indexed columns with non-BINARY collations must still hold
+ ** the exact same text value as the table. */
+ label6 = 0;
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
+ if( pIdx->azColl[kk]==sqlite3StrBINARY ) continue;
+ if( label6==0 ) label6 = sqlite3VdbeMakeLabel(pParse);
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+j, kk, 3);
+ sqlite3VdbeAddOp3(v, OP_Ne, 3, label6, r1+kk); VdbeCoverage(v);
+ }
+ if( label6 ){
+ int jmp6 = sqlite3VdbeAddOp0(v, OP_Goto);
+ sqlite3VdbeResolveLabel(v, label6);
+ sqlite3VdbeLoadString(v, 3, "row ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlite3VdbeLoadString(v, 4, " values differ from index ");
+ sqlite3VdbeGoto(v, jmp5-1);
+ sqlite3VdbeJumpHere(v, jmp6);
+ }
+
/* For UNIQUE indexes, verify that only one entry exists with the
** current key. The entry is unique if (1) any column is NULL
** or (2) the next entry has a different key */
if( IsUniqueIndex(pIdx) ){
int uniqOk = sqlite3VdbeMakeLabel(pParse);
int jmp6;
- int kk;
for(kk=0; kk<pIdx->nKeyCol; kk++){
int iCol = pIdx->aiColumn[kk];
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
@@ -133636,6 +136319,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, addr);
}
+ if( pPk ){
+ sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
+ }
}
}
}
@@ -133786,6 +136472,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[1].p2 = iCookie;
aOp[1].p3 = sqlite3Atoi(zRight);
aOp[1].p5 = 1;
+ if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){
+ /* Do not allow the use of PRAGMA schema_version=VALUE in defensive
+ ** mode. Change the OP_SetCookie opcode into a no-op. */
+ aOp[1].opcode = OP_Noop;
+ }
}else{
/* Read the specified cookie value */
static const VdbeOpList readCookie[] = {
@@ -134766,7 +137457,12 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
#else
encoding = SQLITE_UTF8;
#endif
- sqlite3SetTextEncoding(db, encoding);
+ if( db->nVdbeActive>0 && encoding!=ENC(db) ){
+ rc = SQLITE_LOCKED;
+ goto initone_error_out;
+ }else{
+ sqlite3SetTextEncoding(db, encoding);
+ }
}else{
/* If opening an attached database, the encoding much match ENC(db) */
if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
@@ -134980,8 +137676,8 @@ static void schemaIsValid(Parse *pParse){
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
+ if( DbHasProperty(db, iDb, DB_SchemaLoaded) ) pParse->rc = SQLITE_SCHEMA;
sqlite3ResetOneSchema(db, iDb);
- pParse->rc = SQLITE_SCHEMA;
}
/* Close the transaction, if one was opened. */
@@ -135034,15 +137730,15 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
assert( db->pParse==pParse );
assert( pParse->nested==0 );
#ifndef SQLITE_OMIT_SHARED_CACHE
- sqlite3DbFree(db, pParse->aTableLock);
+ if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock);
#endif
while( pParse->pCleanup ){
ParseCleanup *pCleanup = pParse->pCleanup;
pParse->pCleanup = pCleanup->pNext;
pCleanup->xCleanup(db, pCleanup->pPtr);
- sqlite3DbFreeNN(db, pCleanup);
+ sqlite3DbNNFreeNN(db, pCleanup);
}
- sqlite3DbFree(db, pParse->aLabel);
+ if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel);
if( pParse->pConstExpr ){
sqlite3ExprListDelete(db, pParse->pConstExpr);
}
@@ -135165,7 +137861,7 @@ static int sqlite3Prepare(
sParse.disableLookaside++;
DisableLookaside;
}
- sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
+ sParse.prepFlags = prepFlags & 0xff;
/* Check to verify that it is possible to get a read lock on all
** database schemas. The inability to get a read lock indicates that
@@ -135206,7 +137902,9 @@ static int sqlite3Prepare(
}
}
- sqlite3VtabUnlockList(db);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( db->pDisconnect ) sqlite3VtabUnlockList(db);
+#endif
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
@@ -135590,6 +138288,10 @@ struct SortCtx {
} aDefer[4];
#endif
struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrPush; /* First instruction to push data into sorter */
+ int addrPushEnd; /* Last instruction that pushes data into sorter */
+#endif
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
@@ -135601,6 +138303,7 @@ struct SortCtx {
** If bFree==0, Leave the first Select object unfreed
*/
static void clearSelect(sqlite3 *db, Select *p, int bFree){
+ assert( db!=0 );
while( p ){
Select *pPrior = p->pPrior;
sqlite3ExprListDelete(db, p->pEList);
@@ -135620,7 +138323,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3WindowUnlinkFromSelect(p->pWin);
}
#endif
- if( bFree ) sqlite3DbFreeNN(db, p);
+ if( bFree ) sqlite3DbNNFreeNN(db, p);
p = pPrior;
bFree = 1;
}
@@ -136245,6 +138948,10 @@ static void pushOntoSorter(
*/
assert( nData==1 || regData==regOrigData || regOrigData==0 );
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pSort->addrPush = sqlite3VdbeCurrentAddr(v);
+#endif
+
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nPrefixReg;
@@ -136345,6 +139052,9 @@ static void pushOntoSorter(
sqlite3VdbeChangeP2(v, iSkip,
pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v));
}
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ pSort->addrPushEnd = sqlite3VdbeCurrentAddr(v)-1;
+#endif
}
/*
@@ -137026,9 +139736,10 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
*/
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
+ assert( p->db!=0 );
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
+ if( p->nRef==0 ) sqlite3DbNNFreeNN(p->db, p);
}
}
@@ -137167,6 +139878,16 @@ static void generateSortTail(
int bSeq; /* True if sorter record includes seq. no. */
int nRefKey = 0;
struct ExprList_item *aOutEx = p->pEList->a;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain; /* Address of OP_Explain instruction */
+#endif
+
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
+ "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat>0?"RIGHT PART OF ":"")
+ );
+ sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd);
+ sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush);
+
assert( addrBreak<0 );
if( pSort->labelBkOut ){
@@ -137213,7 +139934,7 @@ static void generateSortTail(
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
- codeOffset(v, p->iOffset, addrContinue);
+ assert( p->iLimit==0 && p->iOffset==0 );
sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
bSeq = 0;
}else{
@@ -137221,6 +139942,9 @@ static void generateSortTail(
codeOffset(v, p->iOffset, addrContinue);
iSortTab = iTab;
bSeq = 1;
+ if( p->iOffset>0 ){
+ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
+ }
}
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
@@ -137276,6 +140000,7 @@ static void generateSortTail(
VdbeComment((v, "%s", aOutEx[i].zEName));
}
}
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
switch( eDest ){
case SRT_Table:
case SRT_EphemTab: {
@@ -137337,6 +140062,7 @@ static void generateSortTail(
}else{
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
}
+ sqlite3VdbeScanStatusRange(v, addrExplain, sqlite3VdbeCurrentAddr(v)-1, -1);
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
sqlite3VdbeResolveLabel(v, addrBreak);
}
@@ -137345,9 +140071,6 @@ static void generateSortTail(
** Return a pointer to a string containing the 'declaration type' of the
** expression pExpr. The string may be treated as static by the caller.
**
-** Also try to estimate the size of the returned value and return that
-** result in *pEstWidth.
-**
** The declaration type is the exact datatype definition extracted from the
** original CREATE TABLE statement if the expression is a column. The
** declaration type for a ROWID field is INTEGER. Exactly when an expression
@@ -137611,7 +140334,7 @@ SQLITE_PRIVATE void sqlite3GenerateColumnNames(
if( pParse->colNamesSet ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
- SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
+ TREETRACE(0x80,pParse,pSelect,("generating column names\n"));
pTabList = pSelect->pSrc;
pEList = pSelect->pEList;
assert( v!=0 );
@@ -137711,7 +140434,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
*pnCol = nCol;
*paCol = aCol;
- for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
+ for(i=0, pCol=aCol; i<nCol && !pParse->nErr; i++, pCol++){
struct ExprList_item *pX = &pEList->a[i];
struct ExprList_item *pCollide;
/* Get an appropriate name for the column
@@ -137761,7 +140484,10 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
if( zName[j]==':' ) nName = j;
}
zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
- if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
+ sqlite3ProgressCheck(pParse);
+ if( cnt>3 ){
+ sqlite3_randomness(sizeof(cnt), &cnt);
+ }
}
pCol->zCnName = zName;
pCol->hName = sqlite3StrIHash(zName);
@@ -137774,71 +140500,105 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
}
}
sqlite3HashClear(&ht);
- if( db->mallocFailed ){
+ if( pParse->nErr ){
for(j=0; j<i; j++){
sqlite3DbFree(db, aCol[j].zCnName);
}
sqlite3DbFree(db, aCol);
*paCol = 0;
*pnCol = 0;
- return SQLITE_NOMEM_BKPT;
+ return pParse->rc;
}
return SQLITE_OK;
}
/*
-** Add type and collation information to a column list based on
-** a SELECT statement.
-**
-** The column list presumably came from selectColumnNamesFromExprList().
-** The column list has only names, not types or collations. This
-** routine goes through and adds the types and collations.
+** pTab is a transient Table object that represents a subquery of some
+** kind (maybe a parenthesized subquery in the FROM clause of a larger
+** query, or a VIEW, or a CTE). This routine computes type information
+** for that Table object based on the Select object that implements the
+** subquery. For the purposes of this routine, "type infomation" means:
**
-** This routine requires that all identifiers in the SELECT
-** statement be resolved.
+** * The datatype name, as it might appear in a CREATE TABLE statement
+** * Which collating sequence to use for the column
+** * The affinity of the column
*/
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
- Parse *pParse, /* Parsing contexts */
- Table *pTab, /* Add column type information to this table */
- Select *pSelect, /* SELECT used to determine types and collations */
- char aff /* Default affinity for columns */
+SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
+ Parse *pParse, /* Parsing contexts */
+ Table *pTab, /* Add column type information to this table */
+ Select *pSelect, /* SELECT used to determine types and collations */
+ char aff /* Default affinity. */
){
sqlite3 *db = pParse->db;
- NameContext sNC;
Column *pCol;
CollSeq *pColl;
- int i;
+ int i,j;
Expr *p;
struct ExprList_item *a;
+ NameContext sNC;
assert( pSelect!=0 );
assert( (pSelect->selFlags & SF_Resolved)!=0 );
- assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
+ assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
+ assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
if( db->mallocFailed ) return;
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
+ a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
sNC.pSrcList = pSelect->pSrc;
- a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
const char *zType;
- i64 n, m;
+ i64 n;
pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
p = a[i].pExpr;
- zType = columnType(&sNC, p, 0, 0, 0);
/* pCol->szEst = ... // Column size est for SELECT tables never used */
pCol->affinity = sqlite3ExprAffinity(p);
- if( zType ){
- m = sqlite3Strlen30(zType);
- n = sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
- if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
+ if( pCol->affinity<=SQLITE_AFF_NONE ){
+ pCol->affinity = aff;
+ }else if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
+ pCol->affinity = SQLITE_AFF_FLEXNUM;
+ }
+ if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){
+ int m = 0;
+ Select *pS2;
+ for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){
+ m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
+ }
+ if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }else
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){
+ pCol->affinity = SQLITE_AFF_BLOB;
+ }
+ }
+ zType = columnType(&sNC, p, 0, 0, 0);
+ if( zType==0 || pCol->affinity!=sqlite3AffinityType(zType, 0) ){
+ if( pCol->affinity==SQLITE_AFF_NUMERIC
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
+ ){
+ zType = "NUM";
}else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
+ zType = 0;
+ for(j=1; j<SQLITE_N_STDTYPE; j++){
+ if( sqlite3StdTypeAffinity[j]==pCol->affinity ){
+ zType = sqlite3StdType[j];
+ break;
+ }
+ }
+ }
+ }
+ if( zType ){
+ i64 m = sqlite3Strlen30(zType);
+ n = sqlite3Strlen30(pCol->zCnName);
+ pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
+ if( pCol->zCnName ){
+ memcpy(&pCol->zCnName[n+1], zType, m+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
+ }else{
+ testcase( pCol->colFlags & COLFLAG_HASTYPE );
pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
}
}
- if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl ){
assert( pTab->pIndex==0 );
@@ -137872,7 +140632,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -138397,7 +141157,7 @@ static int multiSelect(
pPrior->iLimit = p->iLimit;
pPrior->iOffset = p->iOffset;
pPrior->pLimit = p->pLimit;
- SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL left...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n"));
rc = sqlite3Select(pParse, pPrior, &dest);
pPrior->pLimit = 0;
if( rc ){
@@ -138415,7 +141175,7 @@ static int multiSelect(
}
}
ExplainQueryPlan((pParse, 1, "UNION ALL"));
- SELECTTRACE(1, pParse, p, ("multiSelect UNION ALL right...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n"));
rc = sqlite3Select(pParse, p, &dest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
@@ -138468,7 +141228,7 @@ static int multiSelect(
*/
assert( !pPrior->pOrderBy );
sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
- SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
rc = sqlite3Select(pParse, pPrior, &uniondest);
if( rc ){
goto multi_select_end;
@@ -138488,7 +141248,7 @@ static int multiSelect(
uniondest.eDest = op;
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
sqlite3SelectOpName(p->op)));
- SELECTTRACE(1, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
rc = sqlite3Select(pParse, p, &uniondest);
testcase( rc!=SQLITE_OK );
assert( p->pOrderBy==0 );
@@ -138549,7 +141309,7 @@ static int multiSelect(
/* Code the SELECTs to our left into temporary table "tab1".
*/
sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
- SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT left...\n"));
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n"));
rc = sqlite3Select(pParse, pPrior, &intersectdest);
if( rc ){
goto multi_select_end;
@@ -138566,7 +141326,7 @@ static int multiSelect(
intersectdest.iSDParm = tab2;
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
sqlite3SelectOpName(p->op)));
- SELECTTRACE(1, pParse, p, ("multiSelect INTERSECT right...\n"));
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n"));
rc = sqlite3Select(pParse, p, &intersectdest);
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
@@ -139213,10 +141973,11 @@ static int multiSelectOrderBy(
*/
sqlite3VdbeResolveLabel(v, labelEnd);
- /* Reassembly the compound query so that it will be freed correctly
- ** by the calling function */
+ /* Make arrangements to free the 2nd and subsequent arms of the compound
+ ** after the parse has finished */
if( pSplit->pPrior ){
- sqlite3SelectDelete(db, pSplit->pPrior);
+ sqlite3ParserAddCleanup(pParse,
+ (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
@@ -139246,7 +142007,7 @@ static int multiSelectOrderBy(
** the left operands of a RIGHT JOIN. In either case, we need to potentially
** bypass the substituted expression with OP_IfNullRow.
**
-** Suppose the original expression integer constant. Even though the table
+** Suppose the original expression is an integer constant. Even though the table
** has the nullRow flag set, because the expression is an integer constant,
** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode
** that checks to see if the nullRow flag is set on the table. If the nullRow
@@ -139272,6 +142033,7 @@ typedef struct SubstContext {
int iNewTable; /* New table number */
int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
ExprList *pEList; /* Replacement expressions */
+ ExprList *pCList; /* Collation sequences for replacement expr */
} SubstContext;
/* Forward Declarations */
@@ -139313,9 +142075,10 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
+ int iColumn = pExpr->iColumn;
+ Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
Expr ifNullRow;
- assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
+ assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
if( sqlite3ExprIsVector(pCopy) ){
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
@@ -139326,6 +142089,7 @@ static Expr *substExpr(
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
ifNullRow.iTable = pSubst->iNewTable;
+ ifNullRow.iColumn = -99;
ifNullRow.flags = EP_IfNullRow;
pCopy = &ifNullRow;
}
@@ -139352,11 +142116,16 @@ static Expr *substExpr(
/* Ensure that the expression now has an implicit collation sequence,
** just as it did when it was a column of a view or sub-query. */
- if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
- CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
- pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
- (pColl ? pColl->zName : "BINARY")
+ {
+ CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
+ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
+ pSubst->pCList->a[iColumn].pExpr
);
+ if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
+ pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
+ (pColl ? pColl->zName : "BINARY")
+ );
+ }
}
ExprClearProperty(pExpr, EP_Collate);
}
@@ -139549,6 +142318,46 @@ static void renumberCursors(
}
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+/*
+** If pSel is not part of a compound SELECT, return a pointer to its
+** expression list. Otherwise, return a pointer to the expression list
+** of the leftmost SELECT in the compound.
+*/
+static ExprList *findLeftmostExprlist(Select *pSel){
+ while( pSel->pPrior ){
+ pSel = pSel->pPrior;
+ }
+ return pSel->pEList;
+}
+
+/*
+** Return true if any of the result-set columns in the compound query
+** have incompatible affinities on one or more arms of the compound.
+*/
+static int compoundHasDifferentAffinities(Select *p){
+ int ii;
+ ExprList *pList;
+ assert( p!=0 );
+ assert( p->pEList!=0 );
+ assert( p->pPrior!=0 );
+ pList = p->pEList;
+ for(ii=0; ii<pList->nExpr; ii++){
+ char aff;
+ Select *pSub1;
+ assert( pList->a[ii].pExpr!=0 );
+ aff = sqlite3ExprAffinity(pList->a[ii].pExpr);
+ for(pSub1=p->pPrior; pSub1; pSub1=pSub1->pPrior){
+ assert( pSub1->pEList!=0 );
+ assert( pSub1->pEList->nExpr>ii );
+ assert( pSub1->pEList->a[ii].pExpr!=0 );
+ if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/*
** This routine attempts to flatten subqueries as a performance optimization.
@@ -139593,7 +142402,8 @@ static void renumberCursors(
** (3a) the subquery may not be a join and
** (3b) the FROM clause of the subquery may not contain a virtual
** table and
-** (3c) the outer query may not be an aggregate.
+** (**) Was: "The outer query may not have a GROUP BY." This case
+** is now managed correctly
** (3d) the outer query may not be DISTINCT.
** See also (26) for restrictions on RIGHT JOIN.
**
@@ -139650,6 +142460,9 @@ static void renumberCursors(
** (17g) either the subquery is the first element of the outer
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
+** (17h) The corresponding result set expressions in all arms of the
+** compound must have the same affinity. (See restriction (9)
+** on the push-down optimization.)
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -139701,19 +142514,13 @@ static void renumberCursors(
** See also (3) for restrictions on LEFT JOIN.
**
** (27) The subquery may not contain a FULL or RIGHT JOIN unless it
-** is the first element of the parent query. This must be the
-** the case if:
-** (27a) the subquery is not compound query, and
+** is the first element of the parent query. Two subcases:
+** (27a) the subquery is not a compound query.
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
** (28) The subquery is not a MATERIALIZED CTE.
**
-** (29) Either the subquery is not the right-hand operand of a join with an
-** ON or USING clause nor the right-hand operand of a NATURAL JOIN, or
-** the right-most table within the FROM clause of the subquery
-** is not part of an outer join.
-**
**
** In this routine, the "p" parameter is a pointer to the outer query.
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
@@ -139805,16 +142612,10 @@ static int flattenSubquery(
**
** which is not at all the same thing.
**
- ** If the subquery is the right operand of a LEFT JOIN, then the outer
- ** query cannot be an aggregate. (3c) This is an artifact of the way
- ** aggregates are processed - there is no mechanism to determine if
- ** the LEFT JOIN table should be all-NULL.
- **
** See also tickets #306, #350, and #3300.
*/
if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
if( pSubSrc->nSrc>1 /* (3a) */
- || isAgg /* (3c) */
|| IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|| (p->selFlags & SF_Distinct)!=0 /* (3d) */
|| (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
@@ -139823,15 +142624,6 @@ static int flattenSubquery(
}
isOuterJoin = 1;
}
-#ifdef SQLITE_EXTRA_IFNULLROW
- else if( iFrom>0 && !isAgg ){
- /* Setting isOuterJoin to -1 causes OP_IfNullRow opcodes to be generated for
- ** every reference to any result column from subquery in a join, even
- ** though they are not necessary. This will stress-test the OP_IfNullRow
- ** opcode. */
- isOuterJoin = -1;
- }
-#endif
assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
@@ -139841,41 +142633,13 @@ static int flattenSubquery(
return 0; /* (28) */
}
- /* Restriction (29):
- **
- ** We do not want two constraints on the same term of the flattened
- ** query where one constraint has EP_InnerON and the other is EP_OuterON.
- ** To prevent this, one or the other of the following conditions must be
- ** false:
- **
- ** (29a) The right-most entry in the FROM clause of the subquery
- ** must not be part of an outer join.
- **
- ** (29b) The subquery itself must not be the right operand of a
- ** NATURAL join or a join that as an ON or USING clause.
- **
- ** These conditions are sufficient to keep an EP_OuterON from being
- ** flattened into an EP_InnerON. Restrictions (3a) and (27a) prevent
- ** an EP_InnerON from being flattened into an EP_OuterON.
- */
- if( pSubSrc->nSrc>=2
- && (pSubSrc->a[pSubSrc->nSrc-1].fg.jointype & JT_OUTER)!=0
- ){
- if( (pSubitem->fg.jointype & JT_NATURAL)!=0
- || pSubitem->fg.isUsing
- || NEVER(pSubitem->u3.pOn!=0) /* ON clause already shifted into WHERE */
- || pSubitem->fg.isOn
- ){
- return 0;
- }
- }
-
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
** that make up the compound SELECT are allowed to be aggregate or distinct
** queries.
*/
if( pSub->pPrior ){
+ int ii;
if( pSub->pOrderBy ){
return 0; /* Restriction (20) */
}
@@ -139908,7 +142672,6 @@ static int flattenSubquery(
/* Restriction (18). */
if( p->pOrderBy ){
- int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
}
@@ -139917,6 +142680,9 @@ static int flattenSubquery(
/* Restriction (23) */
if( (p->selFlags & SF_Recursive) ) return 0;
+ /* Restriction (17h) */
+ if( compoundHasDifferentAffinities(pSub) ) return 0;
+
if( pSrc->nSrc>1 ){
if( pParse->nSelect>500 ) return 0;
if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
@@ -139926,7 +142692,7 @@ static int flattenSubquery(
}
/***** If we reach this point, flattening is permitted. *****/
- SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
+ TREETRACE(0x4,pParse,p,("flatten %u.%p from term %d\n",
pSub->selId, pSub, iFrom));
/* Authorize the subquery */
@@ -140005,7 +142771,7 @@ static int flattenSubquery(
if( pPrior ) pPrior->pNext = pNew;
pNew->pNext = p;
p->pPrior = pNew;
- SELECTTRACE(2,pParse,p,("compound-subquery flattener"
+ TREETRACE(0x4,pParse,p,("compound-subquery flattener"
" creates %u as peer\n",pNew->selId));
}
assert( pSubitem->pSelect==0 );
@@ -140150,6 +142916,7 @@ static int flattenSubquery(
x.iNewTable = iNewParent;
x.isOuterJoin = isOuterJoin;
x.pEList = pSub->pEList;
+ x.pCList = findLeftmostExprlist(pSub);
substSelect(&x, pParent, 0);
}
@@ -140169,7 +142936,7 @@ static int flattenSubquery(
pSub->pLimit = 0;
}
- /* Recompute the SrcList_item.colUsed masks for the flattened
+ /* Recompute the SrcItem.colUsed masks for the flattened
** tables. */
for(i=0; i<nSubSrc; i++){
recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
@@ -140184,8 +142951,8 @@ static int flattenSubquery(
sqlite3SelectDelete(db, pSub1);
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
+ if( sqlite3TreeTrace & 0x4 ){
+ TREETRACE(0x4,pParse,p,("After flattening:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -140559,6 +143326,15 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** be materialized. (This restriction is implemented in the calling
** routine.)
**
+** (8) If the subquery is a compound that uses UNION, INTERSECT,
+** or EXCEPT, then all of the result set columns for all arms of
+** the compound must use the BINARY collating sequence.
+**
+** (9) If the subquery is a compound, then all arms of the compound must
+** have the same affinity. (This is the same as restriction (17h)
+** for query flattening.)
+**
+**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
@@ -140574,16 +143350,44 @@ static int pushDownWhereTerms(
if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
-#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pPrior ){
Select *pSel;
+ int notUnionAll = 0;
for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ u8 op = pSel->op;
+ assert( op==TK_ALL || op==TK_SELECT
+ || op==TK_UNION || op==TK_INTERSECT || op==TK_EXCEPT );
+ if( op!=TK_ALL && op!=TK_SELECT ){
+ notUnionAll = 1;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSel->pWin ) return 0; /* restriction (6b) */
+#endif
+ }
+ if( compoundHasDifferentAffinities(pSubq) ){
+ return 0; /* restriction (9) */
+ }
+ if( notUnionAll ){
+ /* If any of the compound arms are connected using UNION, INTERSECT,
+ ** or EXCEPT, then we must ensure that none of the columns use a
+ ** non-BINARY collating sequence. */
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
+ int ii;
+ const ExprList *pList = pSel->pEList;
+ assert( pList!=0 );
+ for(ii=0; ii<pList->nExpr; ii++){
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[ii].pExpr);
+ if( !sqlite3IsBinary(pColl) ){
+ return 0; /* Restriction (8) */
+ }
+ }
+ }
}
}else{
+#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0;
- }
#endif
+ }
#ifdef SQLITE_DEBUG
/* Only the first term of a compound can have a WITH clause. But make
@@ -140632,6 +143436,7 @@ static int pushDownWhereTerms(
x.iNewTable = pSrc->iCursor;
x.isOuterJoin = 0;
x.pEList = pSubq->pEList;
+ x.pCList = findLeftmostExprlist(pSubq);
pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
@@ -140735,6 +143540,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|| p->pSrc->nSrc!=1
|| p->pSrc->a[0].pSelect
|| pAggInfo->nFunc!=1
+ || p->pHaving
){
return 0;
}
@@ -141043,9 +143849,6 @@ static int resolveFromTermToCte(
pFrom->fg.isCte = 1;
pFrom->u2.pCteUse = pCteUse;
pCteUse->nUse++;
- if( pCteUse->nUse>=2 && pCteUse->eM10d==M10d_Any ){
- pCteUse->eM10d = M10d_Yes;
- }
/* Check if this is a recursive CTE. */
pRecTerm = pSel = pFrom->pSelect;
@@ -141155,9 +143958,9 @@ SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){
#endif
/*
-** The SrcList_item structure passed as the second argument represents a
+** The SrcItem structure passed as the second argument represents a
** sub-query in the FROM clause of a SELECT statement. This function
-** allocates and populates the SrcList_item.pTab object. If successful,
+** allocates and populates the SrcItem.pTab object. If successful,
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
** SQLITE_NOMEM.
*/
@@ -141585,8 +144388,8 @@ static int selectExpander(Walker *pWalker, Select *p){
}
}
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After result-set wildcard expansion:\n"));
+ if( sqlite3TreeTrace & 0x8 ){
+ TREETRACE(0x8,pParse,p,("After result-set wildcard expansion:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -141637,14 +144440,14 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo()
** interface.
**
-** For each FROM-clause subquery, add Column.zType and Column.zColl
-** information to the Table structure that represents the result set
-** of that subquery.
+** For each FROM-clause subquery, add Column.zType, Column.zColl, and
+** Column.affinity information to the Table structure that represents
+** the result set of that subquery.
**
** The Table structure that represents the result set was constructed
-** by selectExpander() but the type and collation information was omitted
-** at that point because identifiers had not yet been resolved. This
-** routine is called after identifier resolution.
+** by selectExpander() but the type and collation and affinity information
+** was omitted at that point because identifiers had not yet been resolved.
+** This routine is called after identifier resolution.
*/
static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Parse *pParse;
@@ -141664,9 +144467,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
/* A sub-query in the FROM clause of a SELECT */
Select *pSel = pFrom->pSelect;
if( pSel ){
- while( pSel->pPrior ) pSel = pSel->pPrior;
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
- SQLITE_AFF_NONE);
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
}
}
}
@@ -141721,6 +144522,173 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
sqlite3SelectAddTypeInfo(pParse, p);
}
+#if TREETRACE_ENABLED
+/*
+** Display all information about an AggInfo object
+*/
+static void printAggInfo(AggInfo *pAggInfo){
+ int ii;
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
+ struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
+ sqlite3DebugPrintf(
+ "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
+ " iSorterColumn=%d %s\n",
+ ii, pCol->pTab ? pCol->pTab->zName : "NULL",
+ pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii,
+ pCol->iSorterColumn,
+ ii>=pAggInfo->nAccumulator ? "" : " Accumulator");
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
+ }
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
+ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
+ ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii);
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
+ }
+}
+#endif /* TREETRACE_ENABLED */
+
+/*
+** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[]
+** entries for columns that are arguments to aggregate functions but which
+** are not otherwise used.
+**
+** The aCol[] entries in AggInfo prior to nAccumulator are columns that
+** are referenced outside of aggregate functions. These might be columns
+** that are part of the GROUP by clause, for example. Other database engines
+** would throw an error if there is a column reference that is not in the
+** GROUP BY clause and that is not part of an aggregate function argument.
+** But SQLite allows this.
+**
+** The aCol[] entries beginning with the aCol[nAccumulator] and following
+** are column references that are used exclusively as arguments to
+** aggregate functions. This routine is responsible for computing
+** (or recomputing) those aCol[] entries.
+*/
+static void analyzeAggFuncArgs(
+ AggInfo *pAggInfo,
+ NameContext *pNC
+){
+ int i;
+ assert( pAggInfo!=0 );
+ assert( pAggInfo->iFirstReg==0 );
+ pNC->ncFlags |= NC_InAggFunc;
+ for(i=0; i<pAggInfo->nFunc; i++){
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( ExprUseXList(pExpr) );
+ sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ assert( !IsWindowFunc(pExpr) );
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
+ sqlite3ExprAnalyzeAggregates(pNC, pExpr->y.pWin->pFilter);
+ }
+#endif
+ }
+ pNC->ncFlags &= ~NC_InAggFunc;
+}
+
+/*
+** An index on expressions is being used in the inner loop of an
+** aggregate query with a GROUP BY clause. This routine attempts
+** to adjust the AggInfo object to take advantage of index and to
+** perhaps use the index as a covering index.
+**
+*/
+static void optimizeAggregateUseOfIndexedExpr(
+ Parse *pParse, /* Parsing context */
+ Select *pSelect, /* The SELECT statement being processed */
+ AggInfo *pAggInfo, /* The aggregate info */
+ NameContext *pNC /* Name context used to resolve agg-func args */
+){
+ assert( pAggInfo->iFirstReg==0 );
+ pAggInfo->nColumn = pAggInfo->nAccumulator;
+ if( ALWAYS(pAggInfo->nSortingColumn>0) ){
+ if( pAggInfo->nColumn==0 ){
+ pAggInfo->nSortingColumn = 0;
+ }else{
+ pAggInfo->nSortingColumn =
+ pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
+ }
+ }
+ analyzeAggFuncArgs(pAggInfo, pNC);
+#if TREETRACE_ENABLED
+ if( sqlite3TreeTrace & 0x20 ){
+ IndexedExpr *pIEpr;
+ TREETRACE(0x20, pParse, pSelect,
+ ("AggInfo (possibly) adjusted for Indexed Exprs\n"));
+ sqlite3TreeViewSelect(0, pSelect, 0);
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
+ printf("data-cursor=%d index={%d,%d}\n",
+ pIEpr->iDataCur, pIEpr->iIdxCur, pIEpr->iIdxCol);
+ sqlite3TreeViewExpr(0, pIEpr->pExpr, 0);
+ }
+ printAggInfo(pAggInfo);
+ }
+#else
+ UNUSED_PARAMETER(pSelect);
+ UNUSED_PARAMETER(pParse);
+#endif
+}
+
+/*
+** Walker callback for aggregateConvertIndexedExprRefToColumn().
+*/
+static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
+ AggInfo *pAggInfo;
+ struct AggInfo_col *pCol;
+ UNUSED_PARAMETER(pWalker);
+ if( pExpr->pAggInfo==0 ) return WRC_Continue;
+ if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue;
+ if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
+ if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
+ pAggInfo = pExpr->pAggInfo;
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
+ pExpr->op = TK_AGG_COLUMN;
+ pExpr->iTable = pCol->iTable;
+ pExpr->iColumn = pCol->iColumn;
+ return WRC_Prune;
+}
+
+/*
+** Convert every pAggInfo->aFunc[].pExpr such that any node within
+** those expressions that has pAppInfo set is changed into a TK_AGG_COLUMN
+** opcode.
+*/
+static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
+ int i;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = aggregateIdxEprRefToColCallback;
+ for(i=0; i<pAggInfo->nFunc; i++){
+ sqlite3WalkExpr(&w, pAggInfo->aFunc[i].pFExpr);
+ }
+}
+
+
+/*
+** Allocate a block of registers so that there is one register for each
+** pAggInfo->aCol[] and pAggInfo->aFunc[] entry in pAggInfo. The first
+** register in this block is stored in pAggInfo->iFirstReg.
+**
+** This routine may only be called once for each AggInfo object. Prior
+** to calling this routine:
+**
+** * The aCol[] and aFunc[] arrays may be modified
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
+**
+** After clling this routine:
+**
+** * The aCol[] and aFunc[] arrays are fixed
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
+**
+*/
+static void assignAggregateRegisters(Parse *pParse, AggInfo *pAggInfo){
+ assert( pAggInfo!=0 );
+ assert( pAggInfo->iFirstReg==0 );
+ pAggInfo->iFirstReg = pParse->nMem + 1;
+ pParse->nMem += pAggInfo->nColumn + pAggInfo->nFunc;
+}
+
/*
** Reset the aggregate accumulator.
**
@@ -141734,24 +144702,13 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
int i;
struct AggInfo_func *pFunc;
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
+ assert( pAggInfo->iFirstReg>0 );
assert( pParse->db->pParse==pParse );
assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
if( nReg==0 ) return;
if( pParse->nErr ) return;
-#ifdef SQLITE_DEBUG
- /* Verify that all AggInfo registers are within the range specified by
- ** AggInfo.mnReg..AggInfo.mxReg */
- assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
- for(i=0; i<pAggInfo->nColumn; i++){
- assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
- && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
- }
- for(i=0; i<pAggInfo->nFunc; i++){
- assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
- && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
- }
-#endif
- sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
+ sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->iFirstReg,
+ pAggInfo->iFirstReg+nReg-1);
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
if( pFunc->iDistinct>=0 ){
Expr *pE = pFunc->pFExpr;
@@ -141783,15 +144740,16 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
pList = pF->pFExpr->x.pList;
- sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
+ sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
+ pList ? pList->nExpr : 0);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
/*
-** Update the accumulator memory cells for an aggregate based on
-** the current cursor position.
+** Generate code that will update the accumulator memory cells for an
+** aggregate based on the current cursor position.
**
** If regAcc is non-zero and there are no min() or max() aggregates
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
@@ -141811,6 +144769,8 @@ static void updateAccumulator(
struct AggInfo_func *pF;
struct AggInfo_col *pC;
+ assert( pAggInfo->iFirstReg>0 );
+ if( pParse->nErr ) return;
pAggInfo->directMode = 1;
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
int nArg;
@@ -141871,7 +144831,7 @@ static void updateAccumulator(
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
@@ -141886,7 +144846,7 @@ static void updateAccumulator(
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
}
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
- sqlite3ExprCode(pParse, pC->pCExpr, pC->iMem);
+ sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
}
pAggInfo->directMode = 0;
@@ -141982,26 +144942,31 @@ static void havingToWhere(Parse *pParse, Select *p){
sqlite3WalkExpr(&sWalker, p->pHaving);
#if TREETRACE_ENABLED
if( sWalker.eCode && (sqlite3TreeTrace & 0x100)!=0 ){
- SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
+ TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
}
/*
-** Check to see if the pThis entry of pTabList is a self-join of a prior view.
-** If it is, then return the SrcList_item for the prior view. If it is not,
-** then return 0.
+** Check to see if the pThis entry of pTabList is a self-join of another view.
+** Search FROM-clause entries in the range of iFirst..iEnd, including iFirst
+** but stopping before iEnd.
+**
+** If pThis is a self-join, then return the SrcItem for the first other
+** instance of that view found. If pThis is not a self-join then return 0.
*/
static SrcItem *isSelfJoinView(
SrcList *pTabList, /* Search for self-joins in this FROM clause */
- SrcItem *pThis /* Search for prior reference to this subquery */
+ SrcItem *pThis, /* Search for prior reference to this subquery */
+ int iFirst, int iEnd /* Range of FROM-clause entries to search. */
){
SrcItem *pItem;
assert( pThis->pSelect!=0 );
if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
- for(pItem = pTabList->a; pItem<pThis; pItem++){
+ while( iFirst<iEnd ){
Select *pS1;
+ pItem = &pTabList->a[iFirst++];
if( pItem->pSelect==0 ) continue;
if( pItem->fg.viaCoroutine ) continue;
if( pItem->zName==0 ) continue;
@@ -142070,6 +145035,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
assert( ExprUseXList(pExpr) );
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
+ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
pSub = p->pSrc->a[0].pSelect;
if( pSub==0 ) return 0; /* The FROM is a subquery */
if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
@@ -142114,8 +145080,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
p->selFlags &= ~SF_Aggregate;
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
+ if( sqlite3TreeTrace & 0x200 ){
+ TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142147,6 +145113,68 @@ static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
}
/*
+** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can
+** be implemented as a co-routine. The i-th entry is guaranteed to be
+** a subquery.
+**
+** The subquery is implemented as a co-routine if all of the following are
+** true:
+**
+** (1) The subquery will likely be implemented in the outer loop of
+** the query. This will be the case if any one of the following
+** conditions hold:
+** (a) The subquery is the only term in the FROM clause
+** (b) The subquery is the left-most term and a CROSS JOIN or similar
+** requires it to be the outer loop
+** (c) All of the following are true:
+** (i) The subquery is the left-most subquery in the FROM clause
+** (ii) There is nothing that would prevent the subquery from
+** being used as the outer loop if the sqlite3WhereBegin()
+** routine nominates it to that position.
+** (iii) The query is not a UPDATE ... FROM
+** (2) The subquery is not a CTE that should be materialized because
+** (a) the AS MATERIALIZED keyword is used, or
+** (b) the CTE is used multiple times and does not have the
+** NOT MATERIALIZED keyword
+** (3) The subquery is not part of a left operand for a RIGHT JOIN
+** (4) The SQLITE_Coroutine optimization disable flag is not set
+** (5) The subquery is not self-joined
+*/
+static int fromClauseTermCanBeCoroutine(
+ Parse *pParse, /* Parsing context */
+ SrcList *pTabList, /* FROM clause */
+ int i, /* Which term of the FROM clause holds the subquery */
+ int selFlags /* Flags on the SELECT statement */
+){
+ SrcItem *pItem = &pTabList->a[i];
+ if( pItem->fg.isCte ){
+ const CteUse *pCteUse = pItem->u2.pCteUse;
+ if( pCteUse->eM10d==M10d_Yes ) return 0; /* (2a) */
+ if( pCteUse->nUse>=2 && pCteUse->eM10d!=M10d_No ) return 0; /* (2b) */
+ }
+ if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */
+ if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */
+ if( isSelfJoinView(pTabList, pItem, i+1, pTabList->nSrc)!=0 ){
+ return 0; /* (5) */
+ }
+ if( i==0 ){
+ if( pTabList->nSrc==1 ) return 1; /* (1a) */
+ if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1b) */
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
+ return 1;
+ }
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
+ while( 1 /*exit-by-break*/ ){
+ if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
+ if( i==0 ) break;
+ i--;
+ pItem--;
+ if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
+ }
+ return 1;
+}
+
+/*
** Generate code for the SELECT statement given in the p argument.
**
** The results are returned according to the SelectDest structure.
@@ -142191,8 +145219,8 @@ SQLITE_PRIVATE int sqlite3Select(
assert( db->mallocFailed==0 );
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
#if TREETRACE_ENABLED
- SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
- if( sqlite3TreeTrace & 0x10100 ){
+ TREETRACE(0x1,pParse,p, ("begin processing:\n", pParse->addrExplain));
+ if( sqlite3TreeTrace & 0x10000 ){
if( (sqlite3TreeTrace & 0x10001)==0x10000 ){
sqlite3TreeViewLine(0, "In sqlite3Select() at %s:%d",
__FILE__, __LINE__);
@@ -142212,8 +145240,8 @@ SQLITE_PRIVATE int sqlite3Select(
/* All of these destinations are also able to ignore the ORDER BY clause */
if( p->pOrderBy ){
#if TREETRACE_ENABLED
- SELECTTRACE(1,pParse,p, ("dropping superfluous ORDER BY:\n"));
- if( sqlite3TreeTrace & 0x100 ){
+ TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n"));
+ if( sqlite3TreeTrace & 0x800 ){
sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
}
#endif
@@ -142233,8 +145261,8 @@ SQLITE_PRIVATE int sqlite3Select(
assert( db->mallocFailed==0 );
assert( p->pEList!=0 );
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x104 ){
- SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
+ if( sqlite3TreeTrace & 0x10 ){
+ TREETRACE(0x10,pParse,p, ("after name resolution:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142275,8 +145303,8 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
#if TREETRACE_ENABLED
- if( p->pWin && (sqlite3TreeTrace & 0x108)!=0 ){
- SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
+ if( p->pWin && (sqlite3TreeTrace & 0x40)!=0 ){
+ TREETRACE(0x40,pParse,p, ("after window rewrite:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142307,7 +145335,7 @@ SQLITE_PRIVATE int sqlite3Select(
&& sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
){
- SELECTTRACE(0x100,pParse,p,
+ TREETRACE(0x1000,pParse,p,
("LEFT-JOIN simplifies to JOIN on term %d\n",i));
pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
assert( pItem->iCursor>=0 );
@@ -142363,7 +145391,7 @@ SQLITE_PRIVATE int sqlite3Select(
&& (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */
&& OptimizationEnabled(db, SQLITE_OmitOrderBy)
){
- SELECTTRACE(0x100,pParse,p,
+ TREETRACE(0x800,pParse,p,
("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
sqlite3ParserAddCleanup(pParse,
(void(*)(sqlite3*,void*))sqlite3ExprListDelete,
@@ -142418,8 +145446,8 @@ SQLITE_PRIVATE int sqlite3Select(
if( p->pPrior ){
rc = multiSelect(pParse, p, pDest);
#if TREETRACE_ENABLED
- SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
- if( (sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
+ if( (sqlite3TreeTrace & 0x400)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142439,13 +145467,13 @@ SQLITE_PRIVATE int sqlite3Select(
&& propagateConstants(pParse, p)
){
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
+ if( sqlite3TreeTrace & 0x2000 ){
+ TREETRACE(0x2000,pParse,p,("After constant propagation:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
}else{
- SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
+ TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
@@ -142518,36 +145546,23 @@ SQLITE_PRIVATE int sqlite3Select(
&& pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
){
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x100 ){
- SELECTTRACE(0x100,pParse,p,
+ if( sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
}else{
- SELECTTRACE(0x100,pParse,p,("Push-down not possible\n"));
+ TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
}
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
/* Generate code to implement the subquery
- **
- ** The subquery is implemented as a co-routine if all of the following are
- ** true:
- **
- ** (1) the subquery is guaranteed to be the outer loop (so that
- ** it does not need to be computed more than once), and
- ** (2) the subquery is not a CTE that should be materialized
- ** (3) the subquery is not part of a left operand for a RIGHT JOIN
*/
- if( i==0
- && (pTabList->nSrc==1
- || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) /* (1) */
- && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes) /* (2) */
- && (pTabList->a[0].fg.jointype & JT_LTORJ)==0 /* (3) */
- ){
+ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
*/
@@ -142578,7 +145593,7 @@ SQLITE_PRIVATE int sqlite3Select(
VdbeComment((v, "%!S", pItem));
}
pSub->nSelectRow = pCteUse->nRowEst;
- }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){
+ }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
/* This view has already been materialized by a prior entry in
** this same FROM clause. Reuse it. */
if( pPrior->addrFillSub ){
@@ -142592,6 +145607,9 @@ SQLITE_PRIVATE int sqlite3Select(
** the same view can reuse the materialization. */
int topAddr;
int onceAddr = 0;
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExplain;
+#endif
pItem->regReturn = ++pParse->nMem;
topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
@@ -142607,12 +145625,14 @@ SQLITE_PRIVATE int sqlite3Select(
VdbeNoopComment((v, "materialize %!S", pItem));
}
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
- ExplainQueryPlan((pParse, 1, "MATERIALIZE %!S", pItem));
+
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
VdbeComment((v, "end %!S", pItem));
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
sqlite3VdbeJumpHere(v, topAddr);
sqlite3ClearTempRegCache(pParse);
if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
@@ -142638,8 +145658,8 @@ SQLITE_PRIVATE int sqlite3Select(
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
+ if( sqlite3TreeTrace & 0x8000 ){
+ TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142675,8 +145695,8 @@ SQLITE_PRIVATE int sqlite3Select(
sDistinct.isTnct = 2;
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x400 ){
- SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
+ if( sqlite3TreeTrace & 0x20000 ){
+ TREETRACE(0x20000,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -142728,7 +145748,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( (p->selFlags & SF_FixedLimit)==0 ){
p->nSelectRow = 320; /* 4 billion rows */
}
- computeLimitRegisters(pParse, p, iEnd);
+ if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
sSort.sortFlags |= SORTFLAG_UseSorter;
@@ -142762,7 +145782,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* Begin the database scan. */
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, p, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end;
@@ -142779,7 +145799,7 @@ SQLITE_PRIVATE int sqlite3Select(
sSort.pOrderBy = 0;
}
}
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
@@ -142818,7 +145838,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* End the database scan loop.
*/
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
}
}else{
@@ -142899,12 +145919,14 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
pAggInfo->selId = p->selId;
+#ifdef SQLITE_DEBUG
+ pAggInfo->pSelect = p;
+#endif
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
sNC.pSrcList = pTabList;
sNC.uNC.pAggInfo = pAggInfo;
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
- pAggInfo->mnReg = pParse->nMem+1;
pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
pAggInfo->pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
@@ -142925,40 +145947,17 @@ SQLITE_PRIVATE int sqlite3Select(
}else{
minMaxFlag = WHERE_ORDERBY_NORMAL;
}
- for(i=0; i<pAggInfo->nFunc; i++){
- Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
- assert( ExprUseXList(pExpr) );
- sNC.ncFlags |= NC_InAggFunc;
- sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
-#ifndef SQLITE_OMIT_WINDOWFUNC
- assert( !IsWindowFunc(pExpr) );
- if( ExprHasProperty(pExpr, EP_WinFunc) ){
- sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
- }
-#endif
- sNC.ncFlags &= ~NC_InAggFunc;
- }
- pAggInfo->mxReg = pParse->nMem;
+ analyzeAggFuncArgs(pAggInfo, &sNC);
if( db->mallocFailed ) goto select_end;
#if TREETRACE_ENABLED
- if( sqlite3TreeTrace & 0x400 ){
- int ii;
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
+ if( sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
sqlite3TreeViewSelect(0, p, 0);
if( minMaxFlag ){
sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
}
- for(ii=0; ii<pAggInfo->nColumn; ii++){
- sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
- ii, pAggInfo->aCol[ii].iMem);
- sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
- }
- for(ii=0; ii<pAggInfo->nFunc; ii++){
- sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
- ii, pAggInfo->aFunc[ii].iMem);
- sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
- }
+ printAggInfo(pAggInfo);
}
#endif
@@ -143027,17 +146026,21 @@ SQLITE_PRIVATE int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
- 0, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
+ p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
| (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
);
if( pWInfo==0 ){
sqlite3ExprListDelete(db, pDistinct);
goto select_end;
}
+ if( pParse->pIdxEpr ){
+ optimizeAggregateUseOfIndexedExpr(pParse, p, pAggInfo, &sNC);
+ }
+ assignAggregateRegisters(pParse, pAggInfo);
eDist = sqlite3WhereIsDistinct(pWInfo);
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
@@ -143072,21 +146075,21 @@ SQLITE_PRIVATE int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
j = nGroupBy;
+ pAggInfo->directMode = 1;
for(i=0; i<pAggInfo->nColumn; i++){
struct AggInfo_col *pCol = &pAggInfo->aCol[i];
if( pCol->iSorterColumn>=j ){
- int r1 = j + regBase;
- sqlite3ExprCodeGetColumnOfTable(v,
- pCol->pTab, pCol->iTable, pCol->iColumn, r1);
+ sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase);
j++;
}
}
+ pAggInfo->directMode = 0;
regRecord = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
@@ -143096,6 +146099,23 @@ SQLITE_PRIVATE int sqlite3Select(
pAggInfo->useSortingIdx = 1;
}
+ /* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
+ ** that are indexed (and that were previously identified and tagged
+ ** in optimizeAggregateUseOfIndexedExpr()) then those subexpressions
+ ** must now be converted into a TK_AGG_COLUMN node so that the value
+ ** is correctly pulled from the index rather than being recomputed. */
+ if( pParse->pIdxEpr ){
+ aggregateConvertIndexedExprRefToColumn(pAggInfo);
+#if TREETRACE_ENABLED
+ if( sqlite3TreeTrace & 0x20 ){
+ TREETRACE(0x20, pParse, p,
+ ("AggInfo function expressions converted to reference index\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ printAggInfo(pAggInfo);
+ }
+#endif
+ }
+
/* If the index or temporary table used by the GROUP BY sort
** will naturally deliver rows in the order required by the ORDER BY
** clause, cancel the ephemeral table open coded earlier.
@@ -143164,7 +146184,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop);
VdbeCoverage(v);
}else{
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
sqlite3VdbeChangeToNoop(v, addrSortingIdx);
}
@@ -143274,7 +146294,8 @@ SQLITE_PRIVATE int sqlite3Select(
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
}
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, pAggInfo->aFunc[0].iMem);
+ assignAggregateRegisters(pParse, pAggInfo);
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
explainSimpleCount(pParse, pTab, pBest);
}else{
@@ -143310,6 +146331,7 @@ SQLITE_PRIVATE int sqlite3Select(
pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList;
distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0;
}
+ assignAggregateRegisters(pParse, pAggInfo);
/* This case runs if the aggregate has no GROUP BY clause. The
** processing is much simpler since there is only a single row
@@ -143326,13 +146348,13 @@ SQLITE_PRIVATE int sqlite3Select(
assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
- pDistinct, 0, minMaxFlag|distFlag, 0);
+ pDistinct, p, minMaxFlag|distFlag, 0);
if( pWInfo==0 ){
goto select_end;
}
- SELECTTRACE(1,pParse,p,("WhereBegin returns\n"));
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
eDist = sqlite3WhereIsDistinct(pWInfo);
updateAccumulator(pParse, regAcc, pAggInfo, eDist);
if( eDist!=WHERE_DISTINCT_NOOP ){
@@ -143346,7 +146368,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( minMaxFlag ){
sqlite3WhereMinMaxOptEarlyOut(v, pWInfo);
}
- SELECTTRACE(1,pParse,p,("WhereEnd\n"));
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
finalizeAggFunctions(pParse, pAggInfo);
}
@@ -143368,8 +146390,6 @@ SQLITE_PRIVATE int sqlite3Select(
** and send them to the callback one by one.
*/
if( sSort.pOrderBy ){
- explainTempTable(pParse,
- sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
assert( p->pEList==pEList );
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
@@ -143393,7 +146413,7 @@ select_end:
if( pAggInfo && !db->mallocFailed ){
for(i=0; i<pAggInfo->nColumn; i++){
Expr *pExpr = pAggInfo->aCol[i].pCExpr;
- assert( pExpr!=0 );
+ if( pExpr==0 ) continue;
assert( pExpr->pAggInfo==pAggInfo );
assert( pExpr->iAgg==i );
}
@@ -143407,8 +146427,8 @@ select_end:
#endif
#if TREETRACE_ENABLED
- SELECTTRACE(0x1,pParse,p,("end processing\n"));
- if( (sqlite3TreeTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
+ TREETRACE(0x1,pParse,p,("end processing\n"));
+ if( (sqlite3TreeTrace & 0x40000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
sqlite3TreeViewSelect(0, p, 0);
}
#endif
@@ -143682,7 +146702,7 @@ SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
if( pTrig->pTabSchema==pTab->pSchema
&& pTrig->table
&& 0==sqlite3StrICmp(pTrig->table, pTab->zName)
- && pTrig->pTabSchema!=pTmpSchema
+ && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning)
){
pTrig->pNext = pList;
pList = pTrig;
@@ -143972,6 +146992,23 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
Vdbe *v;
char *z;
+ /* If this is a new CREATE TABLE statement, and if shadow tables
+ ** are read-only, and the trigger makes a change to a shadow table,
+ ** then raise an error - do not allow the trigger to be created. */
+ if( sqlite3ReadOnlyShadowTables(db) ){
+ TriggerStep *pStep;
+ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
+ if( pStep->zTarget!=0
+ && sqlite3ShadowTableName(db, pStep->zTarget)
+ ){
+ sqlite3ErrorMsg(pParse,
+ "trigger \"%s\" may not write to shadow table \"%s\"",
+ pTrig->zName, pStep->zTarget);
+ goto triggerfinish_cleanup;
+ }
+ }
+ }
+
/* Make an entry in the sqlite_schema table */
v = sqlite3GetVdbe(pParse);
if( v==0 ) goto triggerfinish_cleanup;
@@ -144795,7 +147832,7 @@ static TriggerPrg *codeRowTrigger(
sSubParse.zAuthContext = pTrigger->zName;
sSubParse.eTriggerOp = pTrigger->op;
sSubParse.nQueryLoop = pParse->nQueryLoop;
- sSubParse.disableVtab = pParse->disableVtab;
+ sSubParse.prepFlags = pParse->prepFlags;
v = sqlite3GetVdbe(&sSubParse);
if( v ){
@@ -145141,11 +148178,14 @@ static void updateVirtualTable(
** it has been converted into REAL.
*/
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
+ Column *pCol;
assert( pTab!=0 );
- if( !IsView(pTab) ){
+ assert( pTab->nCol>i );
+ pCol = &pTab->aCol[i];
+ if( pCol->iDflt ){
sqlite3_value *pValue = 0;
u8 enc = ENC(sqlite3VdbeDb(v));
- Column *pCol = &pTab->aCol[i];
+ assert( !IsView(pTab) );
VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName));
assert( i<pTab->nCol );
sqlite3ValueFromExpr(sqlite3VdbeDb(v),
@@ -145156,7 +148196,7 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
}
}
#ifndef SQLITE_OMIT_FLOATING_POINT
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
+ if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
}
#endif
@@ -145342,7 +148382,8 @@ static void updateFromSelect(
}
}
pSelect = sqlite3SelectNew(pParse, pList,
- pSrc, pWhere2, pGrp, 0, pOrderBy2, SF_UFSrcCheck|SF_IncludeHidden, pLimit2
+ pSrc, pWhere2, pGrp, 0, pOrderBy2,
+ SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2
);
if( pSelect ) pSelect->selFlags |= SF_OrderByReqd;
sqlite3SelectDestInit(&dest, eDest, iEph);
@@ -146596,6 +149637,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
if( pIdx->aiColumn[ii]==XN_EXPR ){
assert( pIdx->aColExpr!=0 );
assert( pIdx->aColExpr->nExpr>ii );
+ assert( pIdx->bHasExpr );
pExpr = pIdx->aColExpr->a[ii].pExpr;
if( pExpr->op!=TK_COLLATE ){
sCol[0].pLeft = pExpr;
@@ -146909,6 +149951,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
int nDb; /* Number of attached databases */
const char *zDbMain; /* Schema name of database to vacuum */
const char *zOut; /* Name of output file */
+ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -146980,12 +150023,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
+
+ /* For a VACUUM INTO, the pager-flags are set to the same values as
+ ** they are for the database being vacuumed, except that PAGER_CACHESPILL
+ ** is always set. */
+ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
}
nRes = sqlite3BtreeGetRequestedReserve(pMain);
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
- sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
+ sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
@@ -147369,10 +150417,10 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
pVTab->nRef--;
if( pVTab->nRef==0 ){
sqlite3_vtab *p = pVTab->pVtab;
- sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
if( p ){
p->pModule->xDisconnect(p);
}
+ sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
sqlite3DbFree(db, pVTab);
}
}
@@ -147498,7 +150546,8 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
assert( IsVirtual(p) );
- if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
+ assert( db!=0 );
+ if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
if( p->u.vtab.azArg ){
int i;
for(i=0; i<p->u.vtab.nArg; i++){
@@ -148298,7 +151347,7 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
if( pExpr->op!=TK_COLUMN ) return pDef;
assert( ExprUseYTab(pExpr) );
pTab = pExpr->y.pTab;
- if( pTab==0 ) return pDef;
+ if( NEVER(pTab==0) ) return pDef;
if( !IsVirtual(pTab) ) return pDef;
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
assert( pVtab!=0 );
@@ -148905,7 +151954,7 @@ struct WhereAndInfo {
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
**
** The VDBE cursor numbers are small integers contained in
-** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
+** SrcItem.iCursor and Expr.iTable fields. For any given WHERE
** clause, the cursor numbers might not begin with 0 and they might
** contain gaps in the numbering sequence. But we want to make maximum
** use of the bits in our bitmasks. This structure provides a mapping
@@ -148977,20 +152026,6 @@ struct WhereLoopBuilder {
#endif
/*
-** Each instance of this object records a change to a single node
-** in an expression tree to cause that node to point to a column
-** of an index rather than an expression or a virtual column. All
-** such transformations need to be undone at the end of WHERE clause
-** processing.
-*/
-typedef struct WhereExprMod WhereExprMod;
-struct WhereExprMod {
- WhereExprMod *pNext; /* Next translation on a list of them all */
- Expr *pExpr; /* The Expr node that was transformed */
- Expr orig; /* Original value of the Expr node */
-};
-
-/*
** The WHERE clause processing routine has two halves. The
** first part does the start of the WHERE loop and the second
** half does the tail of the WHERE loop. An instance of
@@ -149005,10 +152040,10 @@ struct WhereInfo {
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
+#if WHERETRACE_ENABLED
Expr *pWhere; /* The complete WHERE clause */
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- Select *pLimit; /* Used to access LIMIT expr/registers for vtabs */
#endif
+ Select *pSelect; /* The entire SELECT statement containing WHERE */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */
int iBreak; /* Jump here to break out of the loop */
@@ -149027,7 +152062,6 @@ struct WhereInfo {
int iTop; /* The very beginning of the WHERE loop */
int iEndWhere; /* End of the WHERE clause itself */
WhereLoop *pLoops; /* List of all WhereLoop objects */
- WhereExprMod *pExprMods; /* Expression modifications */
WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
WhereClause sWC; /* Decomposition of the WHERE clause */
@@ -149175,6 +152209,8 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
+#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */
+#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -149431,6 +152467,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
zMsg = sqlite3StrAccumFinish(&str);
ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
+
+ sqlite3VdbeScanStatus(v, sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0);
return ret;
}
#endif /* SQLITE_OMIT_EXPLAIN */
@@ -149453,14 +152491,27 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
){
const char *zObj = 0;
WhereLoop *pLoop = pLvl->pWLoop;
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ int wsFlags = pLoop->wsFlags;
+ int viaCoroutine = 0;
+
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
zObj = pLoop->u.btree.pIndex->zName;
}else{
zObj = pSrclist->a[pLvl->iFrom].zName;
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
}
sqlite3VdbeScanStatus(
v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
);
+
+ if( viaCoroutine==0 ){
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ }
+ if( wsFlags & WHERE_INDEXED ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ }
+ }
}
#endif
@@ -149520,7 +152571,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
pTerm->wtFlags |= TERM_CODED;
}
#ifdef WHERETRACE_ENABLED
- if( sqlite3WhereTrace & 0x20000 ){
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlite3DebugPrintf("DISABLE-");
sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a)));
}
@@ -149635,68 +152686,75 @@ static Expr *removeUnindexableInClauseTerms(
Expr *pX /* The IN expression to be reduced */
){
sqlite3 *db = pParse->db;
+ Select *pSelect; /* Pointer to the SELECT on the RHS */
Expr *pNew;
pNew = sqlite3ExprDup(db, pX, 0);
if( db->mallocFailed==0 ){
- ExprList *pOrigRhs; /* Original unmodified RHS */
- ExprList *pOrigLhs; /* Original unmodified LHS */
- ExprList *pRhs = 0; /* New RHS after modifications */
- ExprList *pLhs = 0; /* New LHS after mods */
- int i; /* Loop counter */
- Select *pSelect; /* Pointer to the SELECT on the RHS */
-
- assert( ExprUseXSelect(pNew) );
- pOrigRhs = pNew->x.pSelect->pEList;
- assert( pNew->pLeft!=0 );
- assert( ExprUseXList(pNew->pLeft) );
- pOrigLhs = pNew->pLeft->x.pList;
- for(i=iEq; i<pLoop->nLTerm; i++){
- if( pLoop->aLTerm[i]->pExpr==pX ){
- int iField;
- assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
- iField = pLoop->aLTerm[i]->u.x.iField - 1;
- if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
- pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
- pOrigRhs->a[iField].pExpr = 0;
- assert( pOrigLhs->a[iField].pExpr!=0 );
- pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
- pOrigLhs->a[iField].pExpr = 0;
- }
- }
- sqlite3ExprListDelete(db, pOrigRhs);
- sqlite3ExprListDelete(db, pOrigLhs);
- pNew->pLeft->x.pList = pLhs;
- pNew->x.pSelect->pEList = pRhs;
- if( pLhs && pLhs->nExpr==1 ){
- /* Take care here not to generate a TK_VECTOR containing only a
- ** single value. Since the parser never creates such a vector, some
- ** of the subroutines do not handle this case. */
- Expr *p = pLhs->a[0].pExpr;
- pLhs->a[0].pExpr = 0;
- sqlite3ExprDelete(db, pNew->pLeft);
- pNew->pLeft = p;
- }
- pSelect = pNew->x.pSelect;
- if( pSelect->pOrderBy ){
- /* If the SELECT statement has an ORDER BY clause, zero the
- ** iOrderByCol variables. These are set to non-zero when an
- ** ORDER BY term exactly matches one of the terms of the
- ** result-set. Since the result-set of the SELECT statement may
- ** have been modified or reordered, these variables are no longer
- ** set correctly. Since setting them is just an optimization,
- ** it's easiest just to zero them here. */
- ExprList *pOrderBy = pSelect->pOrderBy;
- for(i=0; i<pOrderBy->nExpr; i++){
- pOrderBy->a[i].u.x.iOrderByCol = 0;
+ for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){
+ ExprList *pOrigRhs; /* Original unmodified RHS */
+ ExprList *pOrigLhs = 0; /* Original unmodified LHS */
+ ExprList *pRhs = 0; /* New RHS after modifications */
+ ExprList *pLhs = 0; /* New LHS after mods */
+ int i; /* Loop counter */
+
+ assert( ExprUseXSelect(pNew) );
+ pOrigRhs = pSelect->pEList;
+ assert( pNew->pLeft!=0 );
+ assert( ExprUseXList(pNew->pLeft) );
+ if( pSelect==pNew->x.pSelect ){
+ pOrigLhs = pNew->pLeft->x.pList;
+ }
+ for(i=iEq; i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iField;
+ assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
+ iField = pLoop->aLTerm[i]->u.x.iField - 1;
+ if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
+ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
+ pOrigRhs->a[iField].pExpr = 0;
+ if( pOrigLhs ){
+ assert( pOrigLhs->a[iField].pExpr!=0 );
+ pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
+ pOrigLhs->a[iField].pExpr = 0;
+ }
+ }
+ }
+ sqlite3ExprListDelete(db, pOrigRhs);
+ if( pOrigLhs ){
+ sqlite3ExprListDelete(db, pOrigLhs);
+ pNew->pLeft->x.pList = pLhs;
+ }
+ pSelect->pEList = pRhs;
+ if( pLhs && pLhs->nExpr==1 ){
+ /* Take care here not to generate a TK_VECTOR containing only a
+ ** single value. Since the parser never creates such a vector, some
+ ** of the subroutines do not handle this case. */
+ Expr *p = pLhs->a[0].pExpr;
+ pLhs->a[0].pExpr = 0;
+ sqlite3ExprDelete(db, pNew->pLeft);
+ pNew->pLeft = p;
+ }
+ if( pSelect->pOrderBy ){
+ /* If the SELECT statement has an ORDER BY clause, zero the
+ ** iOrderByCol variables. These are set to non-zero when an
+ ** ORDER BY term exactly matches one of the terms of the
+ ** result-set. Since the result-set of the SELECT statement may
+ ** have been modified or reordered, these variables are no longer
+ ** set correctly. Since setting them is just an optimization,
+ ** it's easiest just to zero them here. */
+ ExprList *pOrderBy = pSelect->pOrderBy;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
}
- }
#if 0
- printf("For indexing, change the IN expr:\n");
- sqlite3TreeViewExpr(0, pX, 0);
- printf("Into:\n");
- sqlite3TreeViewExpr(0, pNew, 0);
+ printf("For indexing, change the IN expr:\n");
+ sqlite3TreeViewExpr(0, pX, 0);
+ printf("Into:\n");
+ sqlite3TreeViewExpr(0, pNew, 0);
#endif
+ }
}
return pNew;
}
@@ -149783,7 +152841,8 @@ static int codeEqualityTerm(
}
sqlite3ExprDelete(db, pX);
}else{
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
+ int n = sqlite3ExprVectorSize(pX->pLeft);
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
}
pX = pExpr;
@@ -150053,7 +153112,7 @@ static void whereLikeOptimizationStringFixup(
if( pTerm->wtFlags & TERM_LIKEOPT ){
VdbeOp *pOp;
assert( pLevel->iLikeRepCntr>0 );
- pOp = sqlite3VdbeGetOp(v, -1);
+ pOp = sqlite3VdbeGetLastOp(v);
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
@@ -150377,143 +153436,6 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
}
}
-/* An instance of the IdxExprTrans object carries information about a
-** mapping from an expression on table columns into a column in an index
-** down through the Walker.
-*/
-typedef struct IdxExprTrans {
- Expr *pIdxExpr; /* The index expression */
- int iTabCur; /* The cursor of the corresponding table */
- int iIdxCur; /* The cursor for the index */
- int iIdxCol; /* The column for the index */
- int iTabCol; /* The column for the table */
- WhereInfo *pWInfo; /* Complete WHERE clause information */
- sqlite3 *db; /* Database connection (for malloc()) */
-} IdxExprTrans;
-
-/*
-** Preserve pExpr on the WhereETrans list of the WhereInfo.
-*/
-static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
- WhereExprMod *pNew;
- pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
- if( pNew==0 ) return;
- pNew->pNext = pTrans->pWInfo->pExprMods;
- pTrans->pWInfo->pExprMods = pNew;
- pNew->pExpr = pExpr;
- memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
-}
-
-/* The walker node callback used to transform matching expressions into
-** a reference to an index column for an index on an expression.
-**
-** If pExpr matches, then transform it into a reference to the index column
-** that contains the value of pExpr.
-*/
-static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
- pExpr = sqlite3ExprSkipCollate(pExpr);
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlite3ExprAffinity(pExpr);
- pExpr->op = TK_COLUMN;
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- testcase( ExprHasProperty(pExpr, EP_Unlikely) );
- ExprClearProperty(pExpr, EP_Skip|EP_Unlikely|EP_WinFunc|EP_Subrtn);
- pExpr->y.pTab = 0;
- return WRC_Prune;
- }else{
- return WRC_Continue;
- }
-}
-
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
-/* A walker node callback that translates a column reference to a table
-** into a corresponding column reference of an index.
-*/
-static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
- if( pExpr->op==TK_COLUMN ){
- IdxExprTrans *pX = p->u.pIdxTrans;
- if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
- assert( ExprUseYTab(pExpr) && pExpr->y.pTab!=0 );
- preserveExpr(pX, pExpr);
- pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
- pExpr->iTable = pX->iIdxCur;
- pExpr->iColumn = pX->iIdxCol;
- pExpr->y.pTab = 0;
- }
- }
- return WRC_Continue;
-}
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
-
-/*
-** For an indexes on expression X, locate every instance of expression X
-** in pExpr and change that subexpression into a reference to the appropriate
-** column of the index.
-**
-** 2019-10-24: Updated to also translate references to a VIRTUAL column in
-** the table into references to the corresponding (stored) column of the
-** index.
-*/
-static void whereIndexExprTrans(
- Index *pIdx, /* The Index */
- int iTabCur, /* Cursor of the table that is being indexed */
- int iIdxCur, /* Cursor of the index itself */
- WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
-){
- int iIdxCol; /* Column number of the index */
- ExprList *aColExpr; /* Expressions that are indexed */
- Table *pTab;
- Walker w;
- IdxExprTrans x;
- aColExpr = pIdx->aColExpr;
- if( aColExpr==0 && !pIdx->bHasVCol ){
- /* The index does not reference any expressions or virtual columns
- ** so no translations are needed. */
- return;
- }
- pTab = pIdx->pTable;
- memset(&w, 0, sizeof(w));
- w.u.pIdxTrans = &x;
- x.iTabCur = iTabCur;
- x.iIdxCur = iIdxCur;
- x.pWInfo = pWInfo;
- x.db = pWInfo->pParse->db;
- for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
- i16 iRef = pIdx->aiColumn[iIdxCol];
- if( iRef==XN_EXPR ){
- assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 );
- x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
- if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
- w.xExprCallback = whereIndexExprTransNode;
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
- }else if( iRef>=0
- && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
- && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0
- || sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]),
- sqlite3StrBINARY)==0)
- ){
- /* Check to see if there are direct references to generated columns
- ** that are contained in the index. Pulling the generated column
- ** out of the index is an optimization only - the main table is always
- ** available if the index cannot be used. To avoid unnecessary
- ** complication, omit this optimization if the collating sequence for
- ** the column is non-standard */
- x.iTabCol = iRef;
- w.xExprCallback = whereIndexExprTransColumn;
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
- }else{
- continue;
- }
- x.iIdxCol = iIdxCol;
- sqlite3WalkExpr(&w, pWInfo->pWhere);
- sqlite3WalkExprList(&w, pWInfo->pOrderBy);
- sqlite3WalkExprList(&w, pWInfo->pResultSet);
- }
-}
-
/*
** The pTruth expression is always true because it is the WHERE clause
** a partial index that is driving a query loop. Look through all of the
@@ -150582,6 +153504,8 @@ static SQLITE_NOINLINE void filterPullDown(
testcase( pTerm->wtFlags & TERM_VIRTUAL );
regRowid = sqlite3GetTempReg(pParse);
regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
+ VdbeCoverage(pParse->pVdbe);
sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
addrNxt, regRowid, 1);
VdbeCoverage(pParse->pVdbe);
@@ -150641,13 +153565,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
-#if WHERETRACE_ENABLED /* 0x20800 */
- if( sqlite3WhereTrace & 0x800 ){
+#if WHERETRACE_ENABLED /* 0x4001 */
+ if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
- sqlite3WhereLoopPrint(pLoop, pWC);
+ if( sqlite3WhereTrace & 0x1000 ){
+ sqlite3WhereLoopPrint(pLoop, pWC);
+ }
}
- if( sqlite3WhereTrace & 0x20000 ){
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
if( iLevel==0 ){
sqlite3DebugPrintf("WHERE clause being coded:\n");
sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
@@ -150733,9 +153659,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
&& pLoop->u.vtab.bOmitOffset
){
assert( pTerm->eOperator==WO_AUX );
- assert( pWInfo->pLimit!=0 );
- assert( pWInfo->pLimit->iOffset>0 );
- sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pLimit->iOffset);
+ assert( pWInfo->pSelect!=0 );
+ assert( pWInfo->pSelect->iOffset>0 );
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
VdbeComment((v,"Zero OFFSET counter"));
}
}
@@ -150843,6 +153769,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
if( pLevel->regFilter ){
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
+ VdbeCoverage(v);
sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
iRowidReg, 1);
VdbeCoverage(v);
@@ -151194,6 +154122,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
+ if( pRangeStart ){
+ sqlite3VdbeChangeP5(v, 1);
+ sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
+ addrSeekScan = 0;
+ }
VdbeCoverage(v);
}
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
@@ -151269,8 +154202,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
nConstraint++;
}
- sqlite3DbFree(db, zStartAff);
- sqlite3DbFree(db, zEndAff);
+ if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff);
+ if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -151332,27 +154265,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
if( pLevel->iLeftJoin==0 ){
- /* If pIdx is an index on one or more expressions, then look through
- ** all the expressions in pWInfo and try to transform matching expressions
- ** into reference to index columns. Also attempt to translate references
- ** to virtual columns in the table into references to (stored) columns
- ** of the index.
- **
- ** Do not do this for the RHS of a LEFT JOIN. This is because the
- ** expression may be evaluated after OP_NullRow has been executed on
- ** the cursor. In this case it is important to do the full evaluation,
- ** as the result of the expression may not be NULL, even if all table
- ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
- **
- ** Also, do not do this when processing one index an a multi-index
- ** OR clause, since the transformation will become invalid once we
- ** move forward to the next index.
- ** https://sqlite.org/src/info/4e8e4857d32d401f
- */
- if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 ){
- whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
- }
-
/* If a partial index is driving the loop, try to eliminate WHERE clause
** terms from the query that must be true due to the WHERE clause of
** the partial index.
@@ -151465,7 +154377,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
- pOrTab = sqlite3StackAllocRaw(db,
+ pOrTab = sqlite3DbMallocRawNN(db,
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
@@ -151585,7 +154497,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
/* Loop through table entries that match term pOrTerm. */
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
- WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
+ WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n"));
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
WHERE_OR_SUBCLAUSE, iCovCur);
assert( pSubWInfo || pParse->nErr );
@@ -151718,7 +154630,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->op==OP_Return );
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
+ if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
if( !untestedTerms ) disableTerm(pLevel, pTerm);
}else
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -151822,12 +154734,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
#endif
}
-#ifdef WHERETRACE_ENABLED /* 0xffff */
+#ifdef WHERETRACE_ENABLED /* 0xffffffff */
if( sqlite3WhereTrace ){
VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
pWC->nTerm-j, pTerm, iLoop));
}
- if( sqlite3WhereTrace & 0x800 ){
+ if( sqlite3WhereTrace & 0x4000 ){
sqlite3DebugPrintf("Coding auxiliary constraint:\n");
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
@@ -151856,8 +154768,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( pTerm->leftCursor!=iCur ) continue;
if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue;
pE = pTerm->pExpr;
-#ifdef WHERETRACE_ENABLED /* 0x800 */
- if( sqlite3WhereTrace & 0x800 ){
+#ifdef WHERETRACE_ENABLED /* 0x4001 */
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
sqlite3DebugPrintf("Coding transitive constraint:\n");
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
}
@@ -151972,13 +154884,13 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
}
-#if WHERETRACE_ENABLED /* 0x20800 */
- if( sqlite3WhereTrace & 0x20000 ){
+#if WHERETRACE_ENABLED /* 0x4001 */
+ if( sqlite3WhereTrace & 0x4000 ){
sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
iLevel);
sqlite3WhereClausePrint(pWC);
}
- if( sqlite3WhereTrace & 0x800 ){
+ if( sqlite3WhereTrace & 0x1 ){
sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
iLevel, (u64)pLevel->notReady);
}
@@ -152346,7 +155258,7 @@ static int isLikeOrGlob(
if( pLeft->op!=TK_COLUMN
|| sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|| (ALWAYS( ExprUseYTab(pLeft) )
- && pLeft->y.pTab
+ && ALWAYS(pLeft->y.pTab)
&& IsVirtual(pLeft->y.pTab)) /* Might be numeric */
){
int isNum;
@@ -152463,8 +155375,7 @@ static int isAuxiliaryVtabOperator(
** MATCH(expression,vtab_column)
*/
pCol = pList->a[1].pExpr;
- assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
for(i=0; i<ArraySize(aOp); i++){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
@@ -152489,7 +155400,7 @@ static int isAuxiliaryVtabOperator(
*/
pCol = pList->a[0].pExpr;
assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
- testcase( pCol->op==TK_COLUMN && pCol->y.pTab==0 );
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
if( ExprIsVtab(pCol) ){
sqlite3_vtab *pVtab;
sqlite3_module *pMod;
@@ -152514,13 +155425,12 @@ static int isAuxiliaryVtabOperator(
int res = 0;
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
- assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
- testcase( pLeft->op==TK_COLUMN && pLeft->y.pTab==0 );
+ assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) );
if( ExprIsVtab(pLeft) ){
res++;
}
- assert( pRight==0 || pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
- testcase( pRight && pRight->op==TK_COLUMN && pRight->y.pTab==0 );
+ assert( pRight==0 || pRight->op!=TK_COLUMN
+ || (ExprUseYTab(pRight) && pRight->y.pTab!=0) );
if( pRight && ExprIsVtab(pRight) ){
res++;
SWAP(Expr*, pLeft, pRight);
@@ -153056,35 +155966,40 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
*/
static SQLITE_NOINLINE int exprMightBeIndexed2(
SrcList *pFrom, /* The FROM clause */
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
int *aiCurCol, /* Write the referenced table cursor and column here */
- Expr *pExpr /* An operand of a comparison operator */
+ Expr *pExpr, /* An operand of a comparison operator */
+ int j /* Start looking with the j-th pFrom entry */
){
Index *pIdx;
int i;
int iCur;
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
- iCur = pFrom->a[i].iCursor;
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->aColExpr==0 ) continue;
- for(i=0; i<pIdx->nKeyCol; i++){
- if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
- if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
- aiCurCol[0] = iCur;
- aiCurCol[1] = XN_EXPR;
- return 1;
+ do{
+ iCur = pFrom->a[j].iCursor;
+ for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr==0 ) continue;
+ for(i=0; i<pIdx->nKeyCol; i++){
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
+ assert( pIdx->bHasExpr );
+ if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
+ && pExpr->op!=TK_STRING
+ ){
+ aiCurCol[0] = iCur;
+ aiCurCol[1] = XN_EXPR;
+ return 1;
+ }
}
}
- }
+ }while( ++j < pFrom->nSrc );
return 0;
}
static int exprMightBeIndexed(
SrcList *pFrom, /* The FROM clause */
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
int *aiCurCol, /* Write the referenced table cursor & column here */
Expr *pExpr, /* An operand of a comparison operator */
int op /* The specific comparison operator */
){
+ int i;
+
/* If this expression is a vector to the left or right of a
** inequality constraint (>, <, >= or <=), perform the processing
** on the first element of the vector. */
@@ -153094,7 +156009,6 @@ static int exprMightBeIndexed(
if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
assert( ExprUseXList(pExpr) );
pExpr = pExpr->x.pList->a[0].pExpr;
-
}
if( pExpr->op==TK_COLUMN ){
@@ -153102,9 +156016,16 @@ static int exprMightBeIndexed(
aiCurCol[1] = pExpr->iColumn;
return 1;
}
- if( mPrereq==0 ) return 0; /* No table references */
- if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
- return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
+
+ for(i=0; i<pFrom->nSrc; i++){
+ Index *pIdx;
+ for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( pIdx->aColExpr ){
+ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
+ }
+ }
+ }
+ return 0;
}
@@ -153230,7 +156151,7 @@ static void exprAnalyze(
pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr;
}
- if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
+ if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){
pTerm->leftCursor = aiCurCol[0];
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
pTerm->u.x.leftColumn = aiCurCol[1];
@@ -153238,7 +156159,7 @@ static void exprAnalyze(
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
if( pRight
- && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
+ && exprMightBeIndexed(pSrc, aiCurCol, pRight, op)
&& !ExprHasProperty(pRight, EP_FixedCol)
){
WhereTerm *pNew;
@@ -153449,7 +156370,6 @@ static void exprAnalyze(
transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
- exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
@@ -153457,6 +156377,7 @@ static void exprAnalyze(
transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
+ exprAnalyze(pSrc, pWC, idxNew1);
exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
@@ -153513,7 +156434,7 @@ static void exprAnalyze(
&& pTerm->u.x.iField==0
&& pExpr->pLeft->op==TK_VECTOR
&& ALWAYS( ExprUseXSelect(pExpr) )
- && pExpr->x.pSelect->pPrior==0
+ && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values))
#ifndef SQLITE_OMIT_WINDOWFUNC
&& pExpr->x.pSelect->pWin==0
#endif
@@ -153682,9 +156603,9 @@ static void whereAddLimitExpr(
** exist only so that they may be passed to the xBestIndex method of the
** single virtual table in the FROM clause of the SELECT.
*/
-SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
- assert( p==0 || (p->pGroupBy==0 && (p->selFlags & SF_Aggregate)==0) );
- if( (p && p->pLimit) /* 1 */
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
+ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
+ if( p->pGroupBy==0
&& (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
&& (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
){
@@ -153701,6 +156622,13 @@ SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
assert( pWC->a[ii].eOperator==WO_ROWVAL );
continue;
}
+ if( pWC->a[ii].nChild ){
+ /* If this term has child terms, then they are also part of the
+ ** pWC->a[] array. So this term can be ignored, as a LIMIT clause
+ ** will only be added if each of the child terms passes the
+ ** (leftCursor==iCsr) test below. */
+ continue;
+ }
if( pWC->a[ii].leftCursor!=iCsr ) return;
}
@@ -154001,7 +156929,7 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
** block sorting is required.
*/
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
- return pWInfo->nOBSat;
+ return pWInfo->nOBSat<0 ? 0 : pWInfo->nOBSat;
}
/*
@@ -154639,7 +157567,7 @@ static void translateColumnToCopy(
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
int i;
- if( !sqlite3WhereTrace ) return;
+ if( (sqlite3WhereTrace & 0x10)==0 ) return;
for(i=0; i<p->nConstraint; i++){
sqlite3DebugPrintf(
" constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
@@ -154659,7 +157587,7 @@ static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
}
static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
int i;
- if( !sqlite3WhereTrace ) return;
+ if( (sqlite3WhereTrace & 0x10)==0 ) return;
for(i=0; i<p->nConstraint; i++){
sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
i,
@@ -154677,6 +157605,43 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
#define whereTraceIndexInfoOutputs(A)
#endif
+/*
+** We know that pSrc is an operand of an outer join. Return true if
+** pTerm is a constraint that is compatible with that join.
+**
+** pTerm must be EP_OuterON if pSrc is the right operand of an
+** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
+** is the left operand of a RIGHT join.
+**
+** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
+** for an example of a WHERE clause constraints that may not be used on
+** the right table of a RIGHT JOIN because the constraint implies a
+** not-NULL condition on the left table of the RIGHT JOIN.
+*/
+static int constraintCompatibleWithOuterJoin(
+ const WhereTerm *pTerm, /* WHERE clause term to check */
+ const SrcItem *pSrc /* Table we are trying to access */
+){
+ assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
+ testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
+ testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
+ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
+ || pTerm->pExpr->w.iJoin != pSrc->iCursor
+ ){
+ return 0;
+ }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ ){
+ return 0;
+ }
+ return 1;
+}
+
+
+
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
@@ -154692,16 +157657,10 @@ static int termCanDriveIndex(
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- return 0; /* See tag-20191211-001 */
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */
}
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
@@ -154715,6 +157674,57 @@ static int termCanDriveIndex(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+/*
+** Argument pIdx represents an automatic index that the current statement
+** will create and populate. Add an OP_Explain with text of the form:
+**
+** CREATE AUTOMATIC INDEX ON <table>(<cols>) [WHERE <expr>]
+**
+** This is only required if sqlite3_stmt_scanstatus() is enabled, to
+** associate an SQLITE_SCANSTAT_NCYCLE and SQLITE_SCANSTAT_NLOOP
+** values with. In order to avoid breaking legacy code and test cases,
+** the OP_Explain is not added if this is an EXPLAIN QUERY PLAN command.
+*/
+static void explainAutomaticIndex(
+ Parse *pParse,
+ Index *pIdx, /* Automatic index to explain */
+ int bPartial, /* True if pIdx is a partial index */
+ int *pAddrExplain /* OUT: Address of OP_Explain */
+){
+ if( pParse->explain!=2 ){
+ Table *pTab = pIdx->pTable;
+ const char *zSep = "";
+ char *zText = 0;
+ int ii = 0;
+ sqlite3_str *pStr = sqlite3_str_new(pParse->db);
+ sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName);
+ assert( pIdx->nColumn>1 );
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID );
+ for(ii=0; ii<(pIdx->nColumn-1); ii++){
+ const char *zName = 0;
+ int iCol = pIdx->aiColumn[ii];
+
+ zName = pTab->aCol[iCol].zCnName;
+ sqlite3_str_appendf(pStr, "%s%s", zSep, zName);
+ zSep = ", ";
+ }
+ zText = sqlite3_str_finish(pStr);
+ if( zText==0 ){
+ sqlite3OomFault(pParse->db);
+ }else{
+ *pAddrExplain = sqlite3VdbeExplain(
+ pParse, 0, "%s)%s", zText, (bPartial ? " WHERE <expr>" : "")
+ );
+ sqlite3_free(zText);
+ }
+ }
+}
+#else
+# define explainAutomaticIndex(a,b,c,d)
+#endif
+
/*
** Generate code to construct the Index object for an automatic index
** and to set up the WhereLevel object pLevel so that the code generator
@@ -154750,6 +157760,9 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
SrcItem *pTabItem; /* FROM clause term being indexed */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp = 0; /* Address of OP_Explain */
+#endif
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
@@ -154873,6 +157886,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
pIdx->azColl[n] = sqlite3StrBINARY;
/* Create the automatic index */
+ explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp);
assert( pLevel->iIdxCur>=0 );
pLevel->iIdxCur = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
@@ -154908,6 +157922,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0,
regBase, pLoop->u.btree.nEq);
}
+ sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
@@ -154928,6 +157943,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
+ sqlite3VdbeScanStatusRange(v, addrExp, addrExp, -1);
end_auto_index_create:
sqlite3ExprDelete(pParse->db, pPartial);
@@ -155113,22 +158129,10 @@ static sqlite3_index_info *allocateIndexInfo(
assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
assert( pTerm->u.x.leftColumn>=XN_ROWID );
assert( pTerm->u.x.leftColumn<pTab->nCol );
-
- /* tag-20191211-002: WHERE-clause constraints are not useful to the
- ** right-hand table of a LEFT JOIN nor to the either table of a
- ** RIGHT JOIN. See tag-20191211-001 for the
- ** equivalent restriction for ordinary tables. */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) );
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
nTerm++;
pTerm->wtFlags |= TERM_OK;
@@ -155479,12 +158483,12 @@ static int whereKeyStats(
if( iCol>0 ){
pRec->nField = iCol;
assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
- || pParse->db->mallocFailed );
+ || pParse->db->mallocFailed || CORRUPT_DB );
}
if( i>0 ){
pRec->nField = nField;
assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
- || pParse->db->mallocFailed );
+ || pParse->db->mallocFailed || CORRUPT_DB );
}
}
}
@@ -155501,7 +158505,7 @@ static int whereKeyStats(
** is larger than all samples in the array. */
tRowcnt iUpper, iGap;
if( i>=pIdx->nSample ){
- iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
+ iUpper = pIdx->nRowEst0;
}else{
iUpper = aSample[i].anLt[iCol];
}
@@ -155657,7 +158661,7 @@ static int whereRangeSkipScanEst(
int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff));
pLoop->nOut -= nAdjust;
*pbDone = 1;
- WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
+ WHERETRACE(0x20, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
nLower, nUpper, nAdjust*-1, pLoop->nOut));
}
@@ -155835,7 +158839,7 @@ static int whereRangeScanEst(
if( nNew<nOut ){
nOut = nNew;
}
- WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n",
+ WHERETRACE(0x20, ("STAT4 range scan: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
}
}else{
@@ -155868,7 +158872,7 @@ static int whereRangeScanEst(
if( nNew<nOut ) nOut = nNew;
#if defined(WHERETRACE_ENABLED)
if( pLoop->nOut>nOut ){
- WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n",
+ WHERETRACE(0x20,("Range scan lowers nOut from %d to %d\n",
pLoop->nOut, nOut));
}
#endif
@@ -155933,7 +158937,7 @@ static int whereEqualScanEst(
pBuilder->nRecValid = nEq;
whereKeyStats(pParse, p, pRec, 0, a);
- WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
+ WHERETRACE(0x20,("equality scan regions %s(%d): %d\n",
p->zName, nEq-1, (int)a[1]));
*pnRow = a[1];
@@ -155981,9 +158985,9 @@ static int whereInScanEst(
}
if( rc==SQLITE_OK ){
- if( nRowEst > nRow0 ) nRowEst = nRow0;
+ if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0;
*pnRow = nRowEst;
- WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst));
+ WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst));
}
assert( pBuilder->nRecValid==nRecValid );
return rc;
@@ -156092,7 +159096,7 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
}
sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
- if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
+ if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){
int i;
for(i=0; i<p->nLTerm; i++){
sqlite3WhereTermPrint(p->aLTerm[i], i);
@@ -156130,12 +159134,18 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
}
/*
-** Deallocate internal memory used by a WhereLoop object
+** Deallocate internal memory used by a WhereLoop object. Leave the
+** object in an initialized state, as if it had been newly allocated.
*/
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
+ if( p->aLTerm!=p->aLTermSpace ){
+ sqlite3DbFreeNN(db, p->aLTerm);
+ p->aLTerm = p->aLTermSpace;
+ p->nLSlot = ArraySize(p->aLTermSpace);
+ }
whereLoopClearUnion(db, p);
- whereLoopInit(p);
+ p->nLTerm = 0;
+ p->wsFlags = 0;
}
/*
@@ -156159,7 +159169,9 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
*/
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
- if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
+ if( pFrom->nLTerm > pTo->nLSlot
+ && whereLoopResize(db, pTo, pFrom->nLTerm)
+ ){
memset(pTo, 0, WHERE_LOOP_XFER_SZ);
return SQLITE_NOMEM_BKPT;
}
@@ -156177,8 +159189,9 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
** Delete a WhereLoop object
*/
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
+ assert( db!=0 );
whereLoopClear(db, p);
- sqlite3DbFreeNN(db, p);
+ sqlite3DbNNFreeNN(db, p);
}
/*
@@ -156186,30 +159199,19 @@ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
assert( pWInfo!=0 );
+ assert( db!=0 );
sqlite3WhereClauseClear(&pWInfo->sWC);
while( pWInfo->pLoops ){
WhereLoop *p = pWInfo->pLoops;
pWInfo->pLoops = p->pNextLoop;
whereLoopDelete(db, p);
}
- assert( pWInfo->pExprMods==0 );
while( pWInfo->pMemToFree ){
WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
- sqlite3DbFreeNN(db, pWInfo->pMemToFree);
+ sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
pWInfo->pMemToFree = pNext;
}
- sqlite3DbFreeNN(db, pWInfo);
-}
-
-/* Undo all Expr node modifications
-*/
-static void whereUndoExprMods(WhereInfo *pWInfo){
- while( pWInfo->pExprMods ){
- WhereExprMod *p = pWInfo->pExprMods;
- pWInfo->pExprMods = p->pNext;
- memcpy(p->pExpr, &p->orig, sizeof(p->orig));
- sqlite3DbFree(pWInfo->pParse->db, p);
- }
+ sqlite3DbNNFreeNN(db, pWInfo);
}
/*
@@ -156558,6 +159560,7 @@ static void whereLoopOutputAdjust(
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
}
if( j<0 ){
+ sqlite3ProgressCheck(pWC->pWInfo->pParse);
if( pLoop->maskSelf==pTerm->prereqAll ){
/* If there are extra terms in the WHERE clause not used by an index
** that depend only on the table being scanned, and that will tend to
@@ -156725,7 +159728,10 @@ static int whereLoopAddBtreeIndex(
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
pNew = pBuilder->pNew;
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
+ assert( db->mallocFailed==0 || pParse->nErr>0 );
+ if( pParse->nErr ){
+ return pParse->rc;
+ }
WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n",
pProbe->pTable->zName,pProbe->zName,
pNew->u.btree.nEq, pNew->nSkip, pNew->rRun));
@@ -156776,32 +159782,11 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
- /* tag-20191211-001: Do not allow constraints from the WHERE clause to
- ** be used by the right table of a LEFT JOIN nor by the left table of a
- ** RIGHT JOIN. Only constraints in the ON clause are allowed.
- ** See tag-20191211-002 for the vtab equivalent.
- **
- ** 2022-06-06: See https://sqlite.org/forum/forumpost/206d99a16dd9212f
- ** for an example of a WHERE clause constraints that may not be used on
- ** the right table of a RIGHT JOIN because the constraint implies a
- ** not-NULL condition on the left table of the RIGHT JOIN.
- **
- ** 2022-06-10: The same condition applies to termCanDriveIndex() above.
- ** https://sqlite.org/forum/forumpost/51e6959f61
- */
- if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ){
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_RIGHT );
- testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
- testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
- testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
- if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
- || pTerm->pExpr->w.iJoin != pSrc->iCursor
- ){
- continue;
- }
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
+ ){
+ continue;
}
-
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
}else{
@@ -156812,7 +159797,11 @@ static int whereLoopAddBtreeIndex(
pNew->u.btree.nBtm = saved_nBtm;
pNew->u.btree.nTop = saved_nTop;
pNew->nLTerm = saved_nLTerm;
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ if( pNew->nLTerm>=pNew->nLSlot
+ && whereLoopResize(db, pNew, pNew->nLTerm+1)
+ ){
+ break; /* OOM while trying to enlarge the pNew->aLTerm array */
+ }
pNew->aLTerm[pNew->nLTerm++] = pTerm;
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
@@ -156905,38 +159894,39 @@ static int whereLoopAddBtreeIndex(
if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
- }else if( eOp & (WO_GT|WO_GE) ){
- testcase( eOp & WO_GT );
- testcase( eOp & WO_GE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
- pNew->u.btree.nBtm = whereRangeVectorLen(
- pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
- );
- pBtm = pTerm;
- pTop = 0;
- if( pTerm->wtFlags & TERM_LIKEOPT ){
- /* Range constraints that come from the LIKE optimization are
- ** always used in pairs. */
- pTop = &pTerm[1];
- assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
- assert( pTop->wtFlags & TERM_LIKEOPT );
- assert( pTop->eOperator==WO_LT );
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
- pNew->aLTerm[pNew->nLTerm++] = pTop;
- pNew->wsFlags |= WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = 1;
- }
- }else{
- assert( eOp & (WO_LT|WO_LE) );
- testcase( eOp & WO_LT );
- testcase( eOp & WO_LE );
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
- pNew->u.btree.nTop = whereRangeVectorLen(
+ }else{
+ int nVecLen = whereRangeVectorLen(
pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
);
- pTop = pTerm;
- pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
- pNew->aLTerm[pNew->nLTerm-2] : 0;
+ if( eOp & (WO_GT|WO_GE) ){
+ testcase( eOp & WO_GT );
+ testcase( eOp & WO_GE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
+ pNew->u.btree.nBtm = nVecLen;
+ pBtm = pTerm;
+ pTop = 0;
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
+ /* Range constraints that come from the LIKE optimization are
+ ** always used in pairs. */
+ pTop = &pTerm[1];
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
+ assert( pTop->wtFlags & TERM_LIKEOPT );
+ assert( pTop->eOperator==WO_LT );
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = 1;
+ }
+ }else{
+ assert( eOp & (WO_LT|WO_LE) );
+ testcase( eOp & WO_LT );
+ testcase( eOp & WO_LE );
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = nVecLen;
+ pTop = pTerm;
+ pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
+ pNew->aLTerm[pNew->nLTerm-2] : 0;
+ }
}
/* At this point pNew->nOut is set to the number of rows expected to
@@ -156988,7 +159978,7 @@ static int whereLoopAddBtreeIndex(
&& pNew->nOut+10 > pProbe->aiRowLogEst[0]
){
#if WHERETRACE_ENABLED /* 0x01 */
- if( sqlite3WhereTrace & 0x01 ){
+ if( sqlite3WhereTrace & 0x20 ){
sqlite3DebugPrintf(
"STAT4 determines term has low selectivity:\n");
sqlite3WhereTermPrint(pTerm, 999);
@@ -157025,9 +160015,17 @@ static int whereLoopAddBtreeIndex(
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
assert( pSrc->pTab->szTabRow>0 );
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
+ if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
+ /* The pProbe->szIdxRow is low for an IPK table since the interior
+ ** pages are small. Thuse szIdxRow gives a good estimate of seek cost.
+ ** But the leaf pages are full-size, so pProbe->szIdxRow would badly
+ ** under-estimate the scanning cost. */
+ rCostIdx = pNew->nOut + 16;
+ }else{
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
+ }
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
- if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
+ if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
@@ -157049,6 +160047,9 @@ static int whereLoopAddBtreeIndex(
&& (pNew->u.btree.nEq<pProbe->nKeyCol ||
pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
){
+ if( pNew->u.btree.nEq>3 ){
+ sqlite3ProgressCheck(pParse);
+ }
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
}
pNew->nOut = saved_nOut;
@@ -157181,6 +160182,149 @@ static int whereUsablePartialIndex(
}
/*
+** pIdx is an index containing expressions. Check it see if any of the
+** expressions in the index match the pExpr expression.
+*/
+static int exprIsCoveredByIndex(
+ const Expr *pExpr,
+ const Index *pIdx,
+ int iTabCur
+){
+ int i;
+ for(i=0; i<pIdx->nColumn; i++){
+ if( pIdx->aiColumn[i]==XN_EXPR
+ && sqlite3ExprCompare(0, pExpr, pIdx->aColExpr->a[i].pExpr, iTabCur)==0
+ ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+** Structure passed to the whereIsCoveringIndex Walker callback.
+*/
+typedef struct CoveringIndexCheck CoveringIndexCheck;
+struct CoveringIndexCheck {
+ Index *pIdx; /* The index */
+ int iTabCur; /* Cursor number for the corresponding table */
+ u8 bExpr; /* Uses an indexed expression */
+ u8 bUnidx; /* Uses an unindexed column not within an indexed expr */
+};
+
+/*
+** Information passed in is pWalk->u.pCovIdxCk. Call it pCk.
+**
+** If the Expr node references the table with cursor pCk->iTabCur, then
+** make sure that column is covered by the index pCk->pIdx. We know that
+** all columns less than 63 (really BMS-1) are covered, so we don't need
+** to check them. But we do need to check any column at 63 or greater.
+**
+** If the index does not cover the column, then set pWalk->eCode to
+** non-zero and return WRC_Abort to stop the search.
+**
+** If this node does not disprove that the index can be a covering index,
+** then just return WRC_Continue, to continue the search.
+**
+** If pCk->pIdx contains indexed expressions and one of those expressions
+** matches pExpr, then prune the search.
+*/
+static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){
+ int i; /* Loop counter */
+ const Index *pIdx; /* The index of interest */
+ const i16 *aiColumn; /* Columns contained in the index */
+ u16 nColumn; /* Number of columns in the index */
+ CoveringIndexCheck *pCk; /* Info about this search */
+
+ pCk = pWalk->u.pCovIdxCk;
+ pIdx = pCk->pIdx;
+ if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) ){
+ /* if( pExpr->iColumn<(BMS-1) && pIdx->bHasExpr==0 ) return WRC_Continue;*/
+ if( pExpr->iTable!=pCk->iTabCur ) return WRC_Continue;
+ pIdx = pWalk->u.pCovIdxCk->pIdx;
+ aiColumn = pIdx->aiColumn;
+ nColumn = pIdx->nColumn;
+ for(i=0; i<nColumn; i++){
+ if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
+ }
+ pCk->bUnidx = 1;
+ return WRC_Abort;
+ }else if( pIdx->bHasExpr
+ && exprIsCoveredByIndex(pExpr, pIdx, pWalk->u.pCovIdxCk->iTabCur) ){
+ pCk->bExpr = 1;
+ return WRC_Prune;
+ }
+ return WRC_Continue;
+}
+
+
+/*
+** pIdx is an index that covers all of the low-number columns used by
+** pWInfo->pSelect (columns from 0 through 62) or an index that has
+** expressions terms. Hence, we cannot determine whether or not it is
+** a covering index by using the colUsed bitmasks. We have to do a search
+** to see if the index is covering. This routine does that search.
+**
+** The return value is one of these:
+**
+** 0 The index is definitely not a covering index
+**
+** WHERE_IDX_ONLY The index is definitely a covering index
+**
+** WHERE_EXPRIDX The index is likely a covering index, but it is
+** difficult to determine precisely because of the
+** expressions that are indexed. Score it as a
+** covering index, but still keep the main table open
+** just in case we need it.
+**
+** This routine is an optimization. It is always safe to return zero.
+** But returning one of the other two values when zero should have been
+** returned can lead to incorrect bytecode and assertion faults.
+*/
+static SQLITE_NOINLINE u32 whereIsCoveringIndex(
+ WhereInfo *pWInfo, /* The WHERE clause context */
+ Index *pIdx, /* Index that is being tested */
+ int iTabCur /* Cursor for the table being indexed */
+){
+ int i, rc;
+ struct CoveringIndexCheck ck;
+ Walker w;
+ if( pWInfo->pSelect==0 ){
+ /* We don't have access to the full query, so we cannot check to see
+ ** if pIdx is covering. Assume it is not. */
+ return 0;
+ }
+ if( pIdx->bHasExpr==0 ){
+ for(i=0; i<pIdx->nColumn; i++){
+ if( pIdx->aiColumn[i]>=BMS-1 ) break;
+ }
+ if( i>=pIdx->nColumn ){
+ /* pIdx does not index any columns greater than 62, but we know from
+ ** colMask that columns greater than 62 are used, so this is not a
+ ** covering index */
+ return 0;
+ }
+ }
+ ck.pIdx = pIdx;
+ ck.iTabCur = iTabCur;
+ ck.bExpr = 0;
+ ck.bUnidx = 0;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = whereIsCoveringIndexWalkCallback;
+ w.xSelectCallback = sqlite3SelectWalkNoop;
+ w.u.pCovIdxCk = &ck;
+ sqlite3WalkSelect(&w, pWInfo->pSelect);
+ if( ck.bUnidx ){
+ rc = 0;
+ }else if( ck.bExpr ){
+ rc = WHERE_EXPRIDX;
+ }else{
+ rc = WHERE_IDX_ONLY;
+ }
+ return rc;
+}
+
+/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
@@ -157262,7 +160406,7 @@ static int whereLoopAddBtree(
sPk.aiRowLogEst = aiRowEstPk;
sPk.onError = OE_Replace;
sPk.pTable = pTab;
- sPk.szIdxRow = pTab->szTabRow;
+ sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
sPk.idxType = SQLITE_IDXTYPE_IPK;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
@@ -157313,7 +160457,8 @@ static int whereLoopAddBtree(
if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){
pNew->rSetup += 28;
}else{
- pNew->rSetup -= 10;
+ pNew->rSetup -= 25; /* Greatly reduced setup cost for auto indexes
+ ** on ephemeral materializations of views */
}
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
if( pNew->rSetup<0 ) pNew->rSetup = 0;
@@ -157382,6 +160527,9 @@ static int whereLoopAddBtree(
#else
pNew->rRun = rSize + 16;
#endif
+ if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
+ pNew->wsFlags |= WHERE_VIEWSCAN;
+ }
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
@@ -157390,11 +160538,38 @@ static int whereLoopAddBtree(
}else{
Bitmask m;
if( pProbe->isCovering ){
- pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
m = 0;
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
- pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
+ pNew->wsFlags = WHERE_INDEXED;
+ if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
+ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
+ if( isCov==0 ){
+ WHERETRACE(0x200,
+ ("-> %s is not a covering index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ assert( m!=0 );
+ }else{
+ m = 0;
+ pNew->wsFlags |= isCov;
+ if( isCov & WHERE_IDX_ONLY ){
+ WHERETRACE(0x200,
+ ("-> %s is a covering expression index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ }else{
+ assert( isCov==WHERE_EXPRIDX );
+ WHERETRACE(0x200,
+ ("-> %s might be a covering expression index"
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
+ }
+ }
+ }else if( m==0 ){
+ WHERETRACE(0x200,
+ ("-> %s a covering index according to bitmasks\n",
+ pProbe->zName, m==0 ? "is" : "is not"));
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
+ }
}
/* Full scan via index */
@@ -157567,7 +160742,7 @@ static int whereLoopAddVirtualOne(
** that the particular combination of parameters provided is unusable.
** Make no entries in the loop table.
*/
- WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n"));
+ WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n"));
return SQLITE_OK;
}
return rc;
@@ -157678,7 +160853,7 @@ static int whereLoopAddVirtualOne(
sqlite3_free(pNew->u.vtab.idxStr);
pNew->u.vtab.needFree = 0;
}
- WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
+ WHERETRACE(0xffffffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
*pbIn, (sqlite3_uint64)mPrereq,
(sqlite3_uint64)(pNew->prereq & ~mPrereq)));
@@ -157783,7 +160958,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
-** xBestIndex to potentiall use all schemas. If the statement being
+** xBestIndex to potentially use all schemas. If the statement being
** prepared is read-only, then just start read transactions on all
** schemas. But if this is a write operation, start writes on all
** schemas.
@@ -157798,7 +160973,7 @@ SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
for(i=0; i<nDb; i++){
sqlite3CodeVerifySchema(pParse, i);
}
- if( pParse->writeMask ){
+ if( DbMaskNonZero(pParse->writeMask) ){
for(i=0; i<nDb; i++){
sqlite3BeginWriteOperation(pParse, 0, i);
}
@@ -157870,7 +161045,7 @@ static int whereLoopAddVirtual(
/* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
- WHERETRACE(0x40, (" VirtualOne: all usable\n"));
+ WHERETRACE(0x800, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
);
@@ -157895,7 +161070,7 @@ static int whereLoopAddVirtual(
/* If the plan produced by the earlier call uses an IN(...) term, call
** xBestIndex again, this time with IN(...) terms disabled. */
if( bIn ){
- WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
+ WHERETRACE(0x800, (" VirtualOne: all usable w/o IN\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0);
assert( bIn==0 );
@@ -157921,7 +161096,7 @@ static int whereLoopAddVirtual(
mPrev = mNext;
if( mNext==ALLBITS ) break;
if( mNext==mBest || mNext==mBestNoIn ) continue;
- WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
+ WHERETRACE(0x800, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
(sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0);
@@ -157935,7 +161110,7 @@ static int whereLoopAddVirtual(
** that requires no source tables at all (i.e. one guaranteed to be
** usable), make a call here with all source tables disabled */
if( rc==SQLITE_OK && seenZero==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
+ WHERETRACE(0x800, (" VirtualOne: all disabled\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0);
if( bIn==0 ) seenZeroNoIN = 1;
@@ -157945,7 +161120,7 @@ static int whereLoopAddVirtual(
** that requires no source tables at all and does not use an IN(...)
** operator, make a final call to obtain one here. */
if( rc==SQLITE_OK && seenZeroNoIN==0 ){
- WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
+ WHERETRACE(0x800, (" VirtualOne: all disabled and w/o IN\n"));
rc = whereLoopAddVirtualOne(
pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
}
@@ -158001,7 +161176,7 @@ static int whereLoopAddOr(
sSubBuild = *pBuilder;
sSubBuild.pOrSet = &sCur;
- WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm));
+ WHERETRACE(0x400, ("Begin processing OR-clause %p\n", pTerm));
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
if( (pOrTerm->eOperator & WO_AND)!=0 ){
sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
@@ -158018,9 +161193,9 @@ static int whereLoopAddOr(
}
sCur.n = 0;
#ifdef WHERETRACE_ENABLED
- WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
+ WHERETRACE(0x400, ("OR-term %d of %p has %d subterms:\n",
(int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
- if( sqlite3WhereTrace & 0x400 ){
+ if( sqlite3WhereTrace & 0x20000 ){
sqlite3WhereClausePrint(sSubBuild.pWC);
}
#endif
@@ -158035,8 +161210,6 @@ static int whereLoopAddOr(
if( rc==SQLITE_OK ){
rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
}
- assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0
- || rc==SQLITE_NOMEM );
testcase( rc==SQLITE_NOMEM && sCur.n>0 );
testcase( rc==SQLITE_DONE );
if( sCur.n==0 ){
@@ -158082,7 +161255,7 @@ static int whereLoopAddOr(
pNew->prereq = sSum.a[i].prereq;
rc = whereLoopInsert(pBuilder, pNew);
}
- WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm));
+ WHERETRACE(0x400, ("End processing OR-clause %p\n", pTerm));
}
}
return rc;
@@ -158108,7 +161281,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/* Loop over the tables in the join, from left to right */
pNew = pBuilder->pNew;
- whereLoopInit(pNew);
+
+ /* Verify that pNew has already been initialized */
+ assert( pNew->nLTerm==0 );
+ assert( pNew->wsFlags==0 );
+ assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) );
+ assert( pNew->aLTerm!=0 );
+
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
Bitmask mUnusable = 0;
@@ -158424,8 +161603,8 @@ static i8 wherePathSatisfiesOrderBy(
if( pOBExpr->iTable!=iCur ) continue;
if( pOBExpr->iColumn!=iColumn ) continue;
}else{
- Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
- if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
+ Expr *pIxExpr = pIndex->aColExpr->a[j].pExpr;
+ if( sqlite3ExprCompareSkip(pOBExpr, pIxExpr, iCur) ){
continue;
}
}
@@ -158557,37 +161736,56 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
** order.
*/
static LogEst whereSortingCost(
- WhereInfo *pWInfo,
- LogEst nRow,
- int nOrderBy,
- int nSorted
+ WhereInfo *pWInfo, /* Query planning context */
+ LogEst nRow, /* Estimated number of rows to sort */
+ int nOrderBy, /* Number of ORDER BY clause terms */
+ int nSorted /* Number of initial ORDER BY terms naturally in order */
){
- /* TUNING: Estimated cost of a full external sort, where N is
+ /* Estimated cost of a full external sort, where N is
** the number of rows to sort is:
**
- ** cost = (3.0 * N * log(N)).
+ ** cost = (K * N * log(N)).
**
** Or, if the order-by clause has X terms but only the last Y
** terms are out of order, then block-sorting will reduce the
** sorting cost to:
**
- ** cost = (3.0 * N * log(N)) * (Y/X)
+ ** cost = (K * N * log(N)) * (Y/X)
+ **
+ ** The constant K is at least 2.0 but will be larger if there are a
+ ** large number of columns to be sorted, as the sorting time is
+ ** proportional to the amount of content to be sorted. The algorithm
+ ** does not currently distinguish between fat columns (BLOBs and TEXTs)
+ ** and skinny columns (INTs). It just uses the number of columns as
+ ** an approximation for the row width.
**
- ** The (Y/X) term is implemented using stack variable rScale
- ** below.
+ ** And extra factor of 2.0 or 3.0 is added to the sorting cost if the sort
+ ** is built using OP_IdxInsert and OP_Sort rather than with OP_SorterInsert.
*/
- LogEst rScale, rSortCost;
- assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
- rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
- rSortCost = nRow + rScale + 16;
+ LogEst rSortCost, nCol;
+ assert( pWInfo->pSelect!=0 );
+ assert( pWInfo->pSelect->pEList!=0 );
+ /* TUNING: sorting cost proportional to the number of output columns: */
+ nCol = sqlite3LogEst((pWInfo->pSelect->pEList->nExpr+59)/30);
+ rSortCost = nRow + nCol;
+ if( nSorted>0 ){
+ /* Scale the result by (Y/X) */
+ rSortCost += sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
+ }
/* Multiple by log(M) where M is the number of output rows.
** Use the LIMIT for M if it is smaller. Or if this sort is for
** a DISTINCT operator, M will be the number of distinct output
** rows, so fudge it downwards a bit.
*/
- if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
- nRow = pWInfo->iLimit;
+ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 ){
+ rSortCost += 10; /* TUNING: Extra 2.0x if using LIMIT */
+ if( nSorted!=0 ){
+ rSortCost += 6; /* TUNING: Extra 1.5x if also using partial sort */
+ }
+ if( pWInfo->iLimit<nRow ){
+ nRow = pWInfo->iLimit;
+ }
}else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
/* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT
** reduces the number of output rows by a factor of 2 */
@@ -158613,7 +161811,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int mxChoice; /* Maximum number of simultaneous paths tracked */
int nLoop; /* Number of terms in the join */
Parse *pParse; /* Parsing context */
- sqlite3 *db; /* The database connection */
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
@@ -158632,7 +161829,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int nSpace; /* Bytes of space allocated at pSpace */
pParse = pWInfo->pParse;
- db = pParse->db;
nLoop = pWInfo->nLevel;
/* TUNING: For simple queries, only the best path is tracked.
** For 2-way joins, the 5 best paths are followed.
@@ -158655,7 +161851,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
- pSpace = sqlite3DbMallocRawNN(db, nSpace);
+ pSpace = sqlite3StackAllocRawNN(pParse->db, nSpace);
if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
@@ -158705,9 +161901,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
- i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
+ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
Bitmask maskNew; /* Mask of src visited by (..) */
- Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
+ Bitmask revMask; /* Mask of rev-order loops for (..) */
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
@@ -158726,7 +161922,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
+ isOrdered = pFrom->isOrdered;
if( isOrdered<0 ){
+ revMask = 0;
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
@@ -158739,11 +161937,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo, nRowEst, nOrderBy, isOrdered
);
}
- /* TUNING: Add a small extra penalty (5) to sorting as an
+ /* TUNING: Add a small extra penalty (3) to sorting as an
** extra encouragment to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
- rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5;
+ rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
@@ -158754,6 +161952,13 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
+ /* TUNING: A full-scan of a VIEW or subquery in the outer loop
+ ** is not so bad. */
+ if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
+ rCost += -10;
+ nOut += -30;
+ }
+
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
@@ -158904,7 +162109,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( nFrom==0 ){
sqlite3ErrorMsg(pParse, "no query solution");
- sqlite3DbFreeNN(db, pSpace);
+ sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_ERROR;
}
@@ -158986,7 +162191,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->nRowOut = pFrom->nRow;
/* Free temporary memory and return success */
- sqlite3DbFreeNN(db, pSpace);
+ sqlite3StackFreeNN(pParse->db, pSpace);
return SQLITE_OK;
}
@@ -159084,7 +162289,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->cId = '0';
#endif
#ifdef WHERETRACE_ENABLED
- if( sqlite3WhereTrace ){
+ if( sqlite3WhereTrace & 0x02 ){
sqlite3DebugPrintf("whereShortCut() used to compute solution\n");
}
#endif
@@ -159214,7 +162419,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
}
}
if( pTerm<pEnd ) continue;
- WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
+ WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
notReady &= ~pLoop->maskSelf;
for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
@@ -159253,28 +162458,27 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
const WhereInfo *pWInfo
){
int i;
- LogEst nSearch;
+ LogEst nSearch = 0;
assert( pWInfo->nLevel>=2 );
assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
- nSearch = pWInfo->a[0].pWLoop->nOut;
- for(i=1; i<pWInfo->nLevel; i++){
+ for(i=0; i<pWInfo->nLevel; i++){
WhereLoop *pLoop = pWInfo->a[i].pWLoop;
const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
- if( (pLoop->wsFlags & reqFlags)==reqFlags
+ SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
+ Table *pTab = pItem->pTab;
+ if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
+ pTab->tabFlags |= TF_StatsUsed;
+ if( i>=1
+ && (pLoop->wsFlags & reqFlags)==reqFlags
/* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
&& ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0)
){
- SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
- Table *pTab = pItem->pTab;
- pTab->tabFlags |= TF_StatsUsed;
- if( nSearch > pTab->nRowLogEst
- && (pTab->tabFlags & TF_HasStat1)!=0
- ){
+ if( nSearch > pTab->nRowLogEst ){
testcase( pItem->fg.jointype & JT_LEFT );
pLoop->wsFlags |= WHERE_BLOOMFILTER;
pLoop->wsFlags &= ~WHERE_IDX_ONLY;
- WHERETRACE(0xffff, (
+ WHERETRACE(0xffffffff, (
"-> use Bloom-filter on loop %c because there are ~%.1e "
"lookups into %s which has only ~%.1e rows\n",
pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName,
@@ -159286,6 +162490,83 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
/*
+** This is an sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
+ Parse *pParse = (Parse*)pObject;
+ while( pParse->pIdxEpr!=0 ){
+ IndexedExpr *p = pParse->pIdxEpr;
+ pParse->pIdxEpr = p->pIENext;
+ sqlite3ExprDelete(db, p->pExpr);
+ sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** The index pIdx is used by a query and contains one or more expressions.
+** In other words pIdx is an index on an expression. iIdxCur is the cursor
+** number for the index and iDataCur is the cursor number for the corresponding
+** table.
+**
+** This routine adds IndexedExpr entries to the Parse->pIdxEpr field for
+** each of the expressions in the index so that the expression code generator
+** will know to replace occurrences of the indexed expression with
+** references to the corresponding column of the index.
+*/
+static SQLITE_NOINLINE void whereAddIndexedExpr(
+ Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxEpr */
+ Index *pIdx, /* The index-on-expression that contains the expressions */
+ int iIdxCur, /* Cursor number for pIdx */
+ SrcItem *pTabItem /* The FROM clause entry for the table */
+){
+ int i;
+ IndexedExpr *p;
+ Table *pTab;
+ assert( pIdx->bHasExpr );
+ pTab = pIdx->pTable;
+ for(i=0; i<pIdx->nColumn; i++){
+ Expr *pExpr;
+ int j = pIdx->aiColumn[i];
+ int bMaybeNullRow;
+ if( j==XN_EXPR ){
+ pExpr = pIdx->aColExpr->a[i].pExpr;
+ testcase( pTabItem->fg.jointype & JT_LEFT );
+ testcase( pTabItem->fg.jointype & JT_RIGHT );
+ testcase( pTabItem->fg.jointype & JT_LTORJ );
+ bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
+ }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
+ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
+ bMaybeNullRow = 0;
+ }else{
+ continue;
+ }
+ if( sqlite3ExprIsConstant(pExpr) ) continue;
+ p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
+ if( p==0 ) break;
+ p->pIENext = pParse->pIdxEpr;
+#ifdef WHERETRACE_ENABLED
+ if( sqlite3WhereTrace & 0x200 ){
+ sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i);
+ if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(pExpr);
+ }
+#endif
+ p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
+ p->iDataCur = pTabItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = i;
+ p->bMaybeNullRow = bMaybeNullRow;
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ p->zIdxName = pIdx->zName;
+#endif
+ pParse->pIdxEpr = p;
+ if( p->pIENext==0 ){
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
+ }
+ }
+}
+
+/*
** Generate the beginning of the loop used for WHERE clause processing.
** The return value is a pointer to an opaque structure that contains
** information needed to terminate the loop. Later, the calling routine
@@ -159379,7 +162660,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
- Select *pLimit, /* Use this LIMIT/OFFSET clause, if any */
+ Select *pSelect, /* The entire SELECT statement */
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
** If WHERE_USE_LIMIT, then the limit amount */
@@ -159448,7 +162729,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
+#if WHERETRACE_ENABLED
pWInfo->pWhere = pWhere;
+#endif
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;
@@ -159456,9 +162739,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
-#ifndef SQLITE_OMIT_VIRTUALTABLE
- pWInfo->pLimit = pLimit;
-#endif
+ pWInfo->pSelect = pSelect;
memset(&pWInfo->nOBSat, 0,
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
@@ -159527,7 +162808,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Analyze all of the subexpressions. */
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
- sqlite3WhereAddLimit(&pWInfo->sWC, pLimit);
+ if( pSelect && pSelect->pLimit ){
+ sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
+ }
if( pParse->nErr ) goto whereBeginError;
/* Special case: WHERE terms that do not refer to any tables in the join
@@ -159568,13 +162851,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Construct the WhereLoop objects */
#if defined(WHERETRACE_ENABLED)
- if( sqlite3WhereTrace & 0xffff ){
+ if( sqlite3WhereTrace & 0xffffffff ){
sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
if( wctrlFlags & WHERE_USE_LIMIT ){
sqlite3DebugPrintf(", limit: %d", iAuxArg);
}
sqlite3DebugPrintf(")\n");
- if( sqlite3WhereTrace & 0x100 ){
+ if( sqlite3WhereTrace & 0x8000 ){
Select sSelect;
memset(&sSelect, 0, sizeof(sSelect));
sSelect.selFlags = SF_WhereBegin;
@@ -159584,10 +162867,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sSelect.pEList = pResultSet;
sqlite3TreeViewSelect(0, &sSelect, 0);
}
- }
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
- sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
- sqlite3WhereClausePrint(sWLB.pWC);
+ if( sqlite3WhereTrace & 0x4000 ){ /* Display all WHERE clause terms */
+ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
+ sqlite3WhereClausePrint(sWLB.pWC);
+ }
}
#endif
@@ -159603,7 +162886,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** loops will be built using the revised truthProb values. */
if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){
WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
- WHERETRACE(0xffff,
+ WHERETRACE(0xffffffff,
("**** Redo all loop computations due to"
" TERM_HIGHTRUTH changes ****\n"));
while( pWInfo->pLoops ){
@@ -159689,11 +162972,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
#if defined(WHERETRACE_ENABLED)
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ if( sqlite3WhereTrace & 0x4000 ){ /* Display all terms of the WHERE clause */
sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
sqlite3WhereClausePrint(sWLB.pWC);
}
- WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
+ WHERETRACE(0xffffffff,("*** Optimizer Finished ***\n"));
#endif
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
@@ -159830,6 +163113,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
+ if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
+ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -159952,8 +163238,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginError:
if( pWInfo ){
- testcase( pWInfo->pExprMods!=0 );
- whereUndoExprMods(pWInfo);
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
@@ -160172,7 +163456,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
assert( pWInfo->nLevel<=pTabList->nSrc );
- if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo);
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
int k, last;
VdbeOp *pOp, *pLastOp;
@@ -160226,6 +163509,23 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}else{
last = pWInfo->iEndWhere;
}
+ if( pIdx->bHasExpr ){
+ IndexedExpr *p = pParse->pIdxEpr;
+ while( p ){
+ if( p->iIdxCur==pLevel->iIdxCur ){
+#ifdef WHERETRACE_ENABLED
+ if( sqlite3WhereTrace & 0x200 ){
+ sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n",
+ p->iIdxCur, p->iIdxCol);
+ if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(p->pExpr);
+ }
+#endif
+ p->iDataCur = -1;
+ p->iIdxCur = -1;
+ }
+ p = p->pIENext;
+ }
+ }
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
@@ -161219,7 +164519,6 @@ static ExprList *exprListAppendList(
for(i=0; i<pAppend->nExpr; i++){
sqlite3 *db = pParse->db;
Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
- assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
if( db->mallocFailed ){
sqlite3ExprDelete(db, pDup);
break;
@@ -161389,7 +164688,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
pSub = sqlite3SelectNew(
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
);
- SELECTTRACE(1,pParse,pSub,
+ TREETRACE(0x40,pParse,pSub,
("New window-function subquery in FROM clause of (%u/%p)\n",
p->selId, p));
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
@@ -161399,6 +164698,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
if( p->pSrc ){
Table *pTab2;
p->pSrc->a[0].pSelect = pSub;
+ p->pSrc->a[0].fg.isCorrelated = 1;
sqlite3SrcListAssignCursors(pParse, p->pSrc);
pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
@@ -162490,10 +165790,9 @@ static void windowCodeRangeTest(
/* This block runs if reg1 is not NULL, but reg2 is. */
sqlite3VdbeJumpHere(v, addr);
- sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
- if( op==OP_Gt || op==OP_Ge ){
- sqlite3VdbeChangeP2(v, -1, addrDone);
- }
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2,
+ (op==OP_Gt || op==OP_Ge) ? addrDone : lbl);
+ VdbeCoverage(v);
}
/* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
@@ -163265,8 +166564,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */
windowAggFinal(&s, 0);
- sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
windowReturnOneRow(&s);
sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
@@ -163278,13 +166576,10 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
}
if( pMWin->eStart!=TK_UNBOUNDED ){
- sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.start.csr);
}
- sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
- VdbeCoverageNeverTaken(v);
- sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1);
- VdbeCoverageNeverTaken(v);
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.end.csr);
if( regPeer && pOrderBy ){
sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1);
sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1);
@@ -167966,6 +171261,11 @@ static YYACTIONTYPE yy_reduce(
sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS);
+ }else if( yymsp[-1].minor.yy322->nExpr==1 && pRHS->op==TK_SELECT ){
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pRHS->x.pSelect);
+ pRHS->x.pSelect = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
}else{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
if( yymsp[-4].minor.yy528==0 ){
@@ -170070,7 +173370,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
}
- if( pParse->pVList ) sqlite3DbFreeNN(db, pParse->pVList);
+ if( pParse->pVList ) sqlite3DbNNFreeNN(db, pParse->pVList);
db->pParse = pParentParse;
assert( nErr==0 || pParse->rc!=SQLITE_OK );
return nErr;
@@ -171426,18 +174726,19 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
db->lookaside.bMalloced = pBuf==0 ?1:0;
db->lookaside.nSlot = nBig+nSm;
}else{
- db->lookaside.pStart = db;
+ db->lookaside.pStart = 0;
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
db->lookaside.pSmallInit = 0;
db->lookaside.pSmallFree = 0;
- db->lookaside.pMiddle = db;
+ db->lookaside.pMiddle = 0;
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
- db->lookaside.pEnd = db;
+ db->lookaside.pEnd = 0;
db->lookaside.bDisable = 1;
db->lookaside.sz = 0;
db->lookaside.bMalloced = 0;
db->lookaside.nSlot = 0;
}
+ db->lookaside.pTrueEnd = db->lookaside.pEnd;
assert( sqlite3LookasideUsed(db,0)==0 );
#endif /* SQLITE_OMIT_LOOKASIDE */
return SQLITE_OK;
@@ -171516,6 +174817,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
+ sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
case SQLITE_DBCONFIG_MAINDBNAME: {
@@ -171581,6 +174883,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
}
}
va_end(ap);
+ sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -172165,6 +175468,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break;
case SQLITE_NOTICE_RECOVER_ROLLBACK:
zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break;
+ case SQLITE_NOTICE_RBU: zName = "SQLITE_NOTICE_RBU"; break;
case SQLITE_WARNING: zName = "SQLITE_WARNING"; break;
case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break;
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
@@ -172394,7 +175698,9 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){
+ if( !sqlite3SafetyCheckOk(db)
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
+ ){
(void)SQLITE_MISUSE_BKPT;
return;
}
@@ -172402,6 +175708,21 @@ SQLITE_API void sqlite3_interrupt(sqlite3 *db){
AtomicStore(&db->u1.isInterrupted, 1);
}
+/*
+** Return true or false depending on whether or not an interrupt is
+** pending on connection db.
+*/
+SQLITE_API int sqlite3_is_interrupted(sqlite3 *db){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db)
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
+ ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+ return AtomicLoad(&db->u1.isInterrupted)!=0;
+}
/*
** This function is exactly the same as sqlite3_create_function(), except
@@ -172446,7 +175767,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
** the meaning is inverted. So flip the bit. */
assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
- extraFlags ^= SQLITE_FUNC_UNSAFE;
+ extraFlags ^= SQLITE_FUNC_UNSAFE; /* tag-20230109-1 */
#ifndef SQLITE_OMIT_UTF16
@@ -172464,11 +175785,11 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
case SQLITE_ANY: {
int rc;
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
- (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
+ (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1 */
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
if( rc==SQLITE_OK ){
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
- (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
+ (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1*/
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
}
if( rc!=SQLITE_OK ){
@@ -172717,7 +176038,7 @@ SQLITE_API int sqlite3_overload_function(
rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
sqlite3_mutex_leave(db->mutex);
if( rc ) return SQLITE_OK;
- zCopy = sqlite3_mprintf(zName);
+ zCopy = sqlite3_mprintf("%s", zName);
if( zCopy==0 ) return SQLITE_NOMEM;
return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
@@ -173951,6 +177272,19 @@ static int openDatabase(
goto opendb_out;
}
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
+ /* Process magic filenames ":localStorage:" and ":sessionStorage:" */
+ if( zFilename && zFilename[0]==':' ){
+ if( strcmp(zFilename, ":localStorage:")==0 ){
+ zFilename = "file:local?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }else if( strcmp(zFilename, ":sessionStorage:")==0 ){
+ zFilename = "file:session?vfs=kvvfs";
+ flags |= SQLITE_OPEN_URI;
+ }
+ }
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
+
/* Parse the filename/URI argument
**
** Only allow sensible combinations of bits in the flags argument.
@@ -173981,6 +177315,12 @@ static int openDatabase(
sqlite3_free(zErrMsg);
goto opendb_out;
}
+ assert( db->pVfs!=0 );
+#if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL)
+ if( sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){
+ db->temp_store = 2;
+ }
+#endif
/* Open the backend database driver */
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
@@ -174530,6 +177870,9 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
}
rc = SQLITE_OK;
+ }else if( op==SQLITE_FCNTL_RESET_CACHE ){
+ sqlite3BtreeClearCache(pBtree);
+ rc = SQLITE_OK;
}else{
int nSave = db->busyHandler.nBusy;
rc = sqlite3OsFileControl(fd, op, pArg);
@@ -175090,7 +178433,7 @@ static char *appendText(char *p, const char *z){
** Memory layout must be compatible with that generated by the pager
** and expected by sqlite3_uri_parameter() and databaseName().
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API const char *sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
@@ -175126,10 +178469,10 @@ SQLITE_API char *sqlite3_create_filename(
** error to call this routine with any parameter other than a pointer
** previously obtained from sqlite3_create_filename() or a NULL pointer.
*/
-SQLITE_API void sqlite3_free_filename(char *p){
+SQLITE_API void sqlite3_free_filename(const char *p){
if( p==0 ) return;
- p = (char*)databaseName(p);
- sqlite3_free(p - 4);
+ p = databaseName(p);
+ sqlite3_free((char*)p - 4);
}
@@ -175380,8 +178723,8 @@ SQLITE_API int sqlite3_snapshot_open(
*/
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
int rc = SQLITE_ERROR;
- int iDb;
#ifndef SQLITE_OMIT_WAL
+ int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -176936,7 +180279,7 @@ struct Fts3MultiSegReader {
int nAdvance; /* How many seg-readers to advance */
Fts3SegFilter *pFilter; /* Pointer to filter object */
char *aBuffer; /* Buffer to merge doclists in */
- int nBuffer; /* Allocated size of aBuffer[] in bytes */
+ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
int iColFilter; /* If >=0, filter for this column */
int bRestart;
@@ -177028,6 +180371,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int);
SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
#endif
+SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
+
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
@@ -179632,7 +182977,7 @@ static int fts3TermSelectMerge(
**
** Similar padding is added in the fts3DoclistOrMerge() function.
*/
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
+ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
pTS->anOutput[0] = nDoclist;
if( pTS->aaOutput[0] ){
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
@@ -181120,7 +184465,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
nDistance = iPrev - nMaxUndeferred;
}
- aOut = (char *)sqlite3_malloc(nPoslist+8);
+ aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
if( !aOut ){
sqlite3_free(aPoslist);
return SQLITE_NOMEM;
@@ -181489,7 +184834,7 @@ static int fts3EvalIncrPhraseNext(
if( bEof==0 ){
int nList = 0;
int nByte = a[p->nToken-1].nList;
- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
+ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
if( !aDoclist ) return SQLITE_NOMEM;
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
@@ -182031,9 +185376,8 @@ static void fts3EvalNextRow(
Fts3Expr *pExpr, /* Expr. to advance to next matching row */
int *pRc /* IN/OUT: Error code */
){
- if( *pRc==SQLITE_OK ){
+ if( *pRc==SQLITE_OK && pExpr->bEof==0 ){
int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */
- assert( pExpr->bEof==0 );
pExpr->bStart = 1;
switch( pExpr->eType ){
@@ -182510,6 +185854,22 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
}
/*
+** This is an sqlite3Fts3ExprIterate() callback. If the Fts3Expr.aMI[] array
+** has not yet been allocated, allocate and zero it. Otherwise, just zero
+** it.
+*/
+static int fts3AllocateMSI(Fts3Expr *pExpr, int iPhrase, void *pCtx){
+ Fts3Table *pTab = (Fts3Table*)pCtx;
+ UNUSED_PARAMETER(iPhrase);
+ if( pExpr->aMI==0 ){
+ pExpr->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
+ if( pExpr->aMI==0 ) return SQLITE_NOMEM;
+ }
+ memset(pExpr->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
+ return SQLITE_OK;
+}
+
+/*
** Expression pExpr must be of type FTSQUERY_PHRASE.
**
** If it is not already allocated and populated, this function allocates and
@@ -182530,7 +185890,6 @@ static int fts3EvalGatherStats(
if( pExpr->aMI==0 ){
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
Fts3Expr *pRoot; /* Root of NEAR expression */
- Fts3Expr *p; /* Iterator used for several purposes */
sqlite3_int64 iPrevId = pCsr->iPrevId;
sqlite3_int64 iDocid;
@@ -182538,7 +185897,9 @@ static int fts3EvalGatherStats(
/* Find the root of the NEAR expression */
pRoot = pExpr;
- while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){
+ while( pRoot->pParent
+ && (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred)
+ ){
pRoot = pRoot->pParent;
}
iDocid = pRoot->iDocid;
@@ -182546,14 +185907,8 @@ static int fts3EvalGatherStats(
assert( pRoot->bStart );
/* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */
- for(p=pRoot; p; p=p->pLeft){
- Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
- assert( pE->aMI==0 );
- pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
- if( !pE->aMI ) return SQLITE_NOMEM;
- memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
- }
-
+ rc = sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab);
+ if( rc!=SQLITE_OK ) return rc;
fts3EvalRestart(pCsr, pRoot, &rc);
while( pCsr->isEof==0 && rc==SQLITE_OK ){
@@ -182709,6 +186064,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
u8 bTreeEof = 0;
Fts3Expr *p; /* Used to iterate from pExpr to root */
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
+ Fts3Expr *pRun; /* Closest non-deferred ancestor of pNear */
int bMatch;
/* Check if this phrase descends from an OR expression node. If not,
@@ -182723,25 +186079,30 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
if( p->bEof ) bTreeEof = 1;
}
if( bOr==0 ) return SQLITE_OK;
+ pRun = pNear;
+ while( pRun->bDeferred ){
+ assert( pRun->pParent );
+ pRun = pRun->pParent;
+ }
/* This is the descendent of an OR node. In this case we cannot use
** an incremental phrase. Load the entire doclist for the phrase
** into memory in this case. */
if( pPhrase->bIncr ){
- int bEofSave = pNear->bEof;
- fts3EvalRestart(pCsr, pNear, &rc);
- while( rc==SQLITE_OK && !pNear->bEof ){
- fts3EvalNextRow(pCsr, pNear, &rc);
- if( bEofSave==0 && pNear->iDocid==iDocid ) break;
+ int bEofSave = pRun->bEof;
+ fts3EvalRestart(pCsr, pRun, &rc);
+ while( rc==SQLITE_OK && !pRun->bEof ){
+ fts3EvalNextRow(pCsr, pRun, &rc);
+ if( bEofSave==0 && pRun->iDocid==iDocid ) break;
}
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
- if( rc==SQLITE_OK && pNear->bEof!=bEofSave ){
+ if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){
rc = FTS_CORRUPT_VTAB;
}
}
if( bTreeEof ){
- while( rc==SQLITE_OK && !pNear->bEof ){
- fts3EvalNextRow(pCsr, pNear, &rc);
+ while( rc==SQLITE_OK && !pRun->bEof ){
+ fts3EvalNextRow(pCsr, pRun, &rc);
}
}
if( rc!=SQLITE_OK ) return rc;
@@ -185725,7 +189086,7 @@ static int porterNext(
if( n>c->nAllocated ){
char *pNew;
c->nAllocated = n+20;
- pNew = sqlite3_realloc(c->zToken, c->nAllocated);
+ pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->zToken = pNew;
}
@@ -186477,7 +189838,7 @@ static int simpleNext(
if( n>c->nTokenAllocated ){
char *pNew;
c->nTokenAllocated = n+20;
- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
+ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
if( !pNew ) return SQLITE_NOMEM;
c->pToken = pNew;
}
@@ -187639,7 +191000,7 @@ static int fts3PendingListAppendVarint(
/* Allocate or grow the PendingList as required. */
if( !p ){
- p = sqlite3_malloc(sizeof(*p) + 100);
+ p = sqlite3_malloc64(sizeof(*p) + 100);
if( !p ){
return SQLITE_NOMEM;
}
@@ -187648,14 +191009,14 @@ static int fts3PendingListAppendVarint(
p->nData = 0;
}
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
- int nNew = p->nSpace * 2;
- p = sqlite3_realloc(p, sizeof(*p) + nNew);
+ i64 nNew = p->nSpace * 2;
+ p = sqlite3_realloc64(p, sizeof(*p) + nNew);
if( !p ){
sqlite3_free(*pp);
*pp = 0;
return SQLITE_NOMEM;
}
- p->nSpace = nNew;
+ p->nSpace = (int)nNew;
p->aData = (char *)&p[1];
}
@@ -188212,7 +191573,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
int nByte = sqlite3_blob_bytes(p->pSegments);
*pnBlob = nByte;
if( paBlob ){
- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
+ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
if( !aByte ){
rc = SQLITE_NOMEM;
}else{
@@ -188329,7 +191690,7 @@ static int fts3SegReaderNext(
int nTerm = fts3HashKeysize(pElem);
if( (nTerm+1)>pReader->nTermAlloc ){
sqlite3_free(pReader->zTerm);
- pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2);
+ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
if( !pReader->zTerm ) return SQLITE_NOMEM;
pReader->nTermAlloc = (nTerm+1)*2;
}
@@ -188337,7 +191698,7 @@ static int fts3SegReaderNext(
pReader->zTerm[nTerm] = '\0';
pReader->nTerm = nTerm;
- aCopy = (char*)sqlite3_malloc(nCopy);
+ aCopy = (char*)sqlite3_malloc64(nCopy);
if( !aCopy ) return SQLITE_NOMEM;
memcpy(aCopy, pList->aData, nCopy);
pReader->nNode = pReader->nDoclist = nCopy;
@@ -188624,7 +191985,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
nExtra = nRoot + FTS3_NODE_PADDING;
}
- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
+ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
if( !pReader ){
return SQLITE_NOMEM;
}
@@ -188716,7 +192077,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
if( nElem==nAlloc ){
Fts3HashElem **aElem2;
nAlloc += 16;
- aElem2 = (Fts3HashElem **)sqlite3_realloc(
+ aElem2 = (Fts3HashElem **)sqlite3_realloc64(
aElem, nAlloc*sizeof(Fts3HashElem *)
);
if( !aElem2 ){
@@ -189050,7 +192411,7 @@ static int fts3NodeAddTerm(
** this is not expected to be a serious problem.
*/
assert( pTree->aData==(char *)&pTree[1] );
- pTree->aData = (char *)sqlite3_malloc(nReq);
+ pTree->aData = (char *)sqlite3_malloc64(nReq);
if( !pTree->aData ){
return SQLITE_NOMEM;
}
@@ -189068,7 +192429,7 @@ static int fts3NodeAddTerm(
if( isCopyTerm ){
if( pTree->nMalloc<nTerm ){
- char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2);
+ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189094,7 +192455,7 @@ static int fts3NodeAddTerm(
** now. Instead, the term is inserted into the parent of pTree. If pTree
** has no parent, one is created here.
*/
- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
+ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
if( !pNew ){
return SQLITE_NOMEM;
}
@@ -189232,7 +192593,7 @@ static int fts3SegWriterAdd(
){
int nPrefix; /* Size of term prefix in bytes */
int nSuffix; /* Size of term suffix in bytes */
- int nReq; /* Number of bytes required on leaf page */
+ i64 nReq; /* Number of bytes required on leaf page */
int nData;
SegmentWriter *pWriter = *ppWriter;
@@ -189241,13 +192602,13 @@ static int fts3SegWriterAdd(
sqlite3_stmt *pStmt;
/* Allocate the SegmentWriter structure */
- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter));
+ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
if( !pWriter ) return SQLITE_NOMEM;
memset(pWriter, 0, sizeof(SegmentWriter));
*ppWriter = pWriter;
/* Allocate a buffer in which to accumulate data */
- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
+ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
if( !pWriter->aData ) return SQLITE_NOMEM;
pWriter->nSize = p->nNodeSize;
@@ -189322,7 +192683,7 @@ static int fts3SegWriterAdd(
** the buffer to make it large enough.
*/
if( nReq>pWriter->nSize ){
- char *aNew = sqlite3_realloc(pWriter->aData, nReq);
+ char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
if( !aNew ) return SQLITE_NOMEM;
pWriter->aData = aNew;
pWriter->nSize = nReq;
@@ -189347,7 +192708,7 @@ static int fts3SegWriterAdd(
*/
if( isCopyTerm ){
if( nTerm>pWriter->nMalloc ){
- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2);
+ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
if( !zNew ){
return SQLITE_NOMEM;
}
@@ -189655,12 +193016,12 @@ static void fts3ColumnFilter(
static int fts3MsrBufferData(
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
char *pList,
- int nList
+ i64 nList
){
if( nList>pMsr->nBuffer ){
char *pNew;
pMsr->nBuffer = nList*2;
- pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer);
+ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
}
@@ -189716,7 +193077,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
- rc = fts3MsrBufferData(pMsr, pList, nList+1);
+ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
if( rc!=SQLITE_OK ) return rc;
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
pList = pMsr->aBuffer;
@@ -189853,11 +193214,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
return SQLITE_OK;
}
-static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
if( nReq>pCsr->nBuffer ){
char *aNew;
pCsr->nBuffer = nReq*2;
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
+ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
if( !aNew ){
return SQLITE_NOMEM;
}
@@ -189948,7 +193309,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
){
pCsr->nDoclist = apSegment[0]->nDoclist;
if( fts3SegReaderIsPending(apSegment[0]) ){
- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
+ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
+ (i64)pCsr->nDoclist);
pCsr->aDoclist = pCsr->aBuffer;
}else{
pCsr->aDoclist = apSegment[0]->aDoclist;
@@ -190001,7 +193363,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING);
+ rc = fts3GrowSegReaderBuffer(pCsr,
+ (i64)nByte+nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
if( isFirst ){
@@ -190027,7 +193390,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
}
if( nDoclist>0 ){
- rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING);
+ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
if( rc ) return rc;
memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
pCsr->aDoclist = pCsr->aBuffer;
@@ -190740,7 +194103,7 @@ struct NodeReader {
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
int nAlloc = nMin;
- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
+ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
if( a ){
pBlob->nAlloc = nAlloc;
pBlob->a = a;
@@ -191537,7 +194900,7 @@ static int fts3RepackSegdirLevel(
if( nIdx>=nAlloc ){
int *aNew;
nAlloc += 16;
- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
+ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
if( !aNew ){
rc = SQLITE_NOMEM;
break;
@@ -191911,7 +195274,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
/* Allocate space for the cursor, filter and writer objects */
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
+ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
if( !pWriter ) return SQLITE_NOMEM;
pFilter = (Fts3SegFilter *)&pWriter[1];
pCsr = (Fts3MultiSegReader *)&pFilter[1];
@@ -192547,7 +195910,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
return SQLITE_OK;
}
- pRet = (char *)sqlite3_malloc(p->pList->nData);
+ pRet = (char *)sqlite3_malloc64(p->pList->nData);
if( !pRet ) return SQLITE_NOMEM;
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
@@ -192567,7 +195930,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
int iCol /* Column that token must appear in (or -1) */
){
Fts3DeferredToken *pDeferred;
- pDeferred = sqlite3_malloc(sizeof(*pDeferred));
+ pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
if( !pDeferred ){
return SQLITE_NOMEM;
}
@@ -192846,7 +196209,7 @@ typedef sqlite3_int64 i64;
/*
-** Used as an fts3ExprIterate() context when loading phrase doclists to
+** Used as an sqlite3Fts3ExprIterate() context when loading phrase doclists to
** Fts3Expr.aDoclist[]/nDoclist.
*/
typedef struct LoadDoclistCtx LoadDoclistCtx;
@@ -192890,7 +196253,7 @@ struct SnippetFragment {
};
/*
-** This type is used as an fts3ExprIterate() context object while
+** This type is used as an sqlite3Fts3ExprIterate() context object while
** accumulating the data returned by the matchinfo() function.
*/
typedef struct MatchInfo MatchInfo;
@@ -193049,7 +196412,7 @@ static void fts3GetDeltaPosition(char **pp, i64 *piPos){
}
/*
-** Helper function for fts3ExprIterate() (see below).
+** Helper function for sqlite3Fts3ExprIterate() (see below).
*/
static int fts3ExprIterate2(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
@@ -193083,7 +196446,7 @@ static int fts3ExprIterate2(
** Otherwise, SQLITE_OK is returned after a callback has been made for
** all eligible phrase nodes.
*/
-static int fts3ExprIterate(
+SQLITE_PRIVATE int sqlite3Fts3ExprIterate(
Fts3Expr *pExpr, /* Expression to iterate phrases of */
int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
void *pCtx /* Second argument to pass to callback */
@@ -193092,10 +196455,9 @@ static int fts3ExprIterate(
return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
}
-
/*
-** This is an fts3ExprIterate() callback used while loading the doclists
-** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
+** This is an sqlite3Fts3ExprIterate() callback used while loading the
+** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
** fts3ExprLoadDoclists().
*/
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
@@ -193127,9 +196489,9 @@ static int fts3ExprLoadDoclists(
int *pnToken /* OUT: Number of tokens in query */
){
int rc; /* Return Code */
- LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
+ LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlite3Fts3ExprIterate() */
sCtx.pCsr = pCsr;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx);
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
if( pnToken ) *pnToken = sCtx.nToken;
return rc;
@@ -193142,7 +196504,7 @@ static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
}
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
int nPhrase = 0;
- (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
+ (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
return nPhrase;
}
@@ -193270,8 +196632,9 @@ static void fts3SnippetDetails(
}
/*
-** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
-** Each invocation populates an element of the SnippetIter.aPhrase[] array.
+** This function is an sqlite3Fts3ExprIterate() callback used by
+** fts3BestSnippet(). Each invocation populates an element of the
+** SnippetIter.aPhrase[] array.
*/
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
SnippetIter *p = (SnippetIter *)ctx;
@@ -193361,7 +196724,9 @@ static int fts3BestSnippet(
sIter.nSnippet = nSnippet;
sIter.nPhrase = nList;
sIter.iCurrent = -1;
- rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
+ rc = sqlite3Fts3ExprIterate(
+ pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter
+ );
if( rc==SQLITE_OK ){
/* Set the *pmSeen output variable. */
@@ -193722,10 +197087,10 @@ static int fts3ExprLHitGather(
}
/*
-** fts3ExprIterate() callback used to collect the "global" matchinfo stats
-** for a single query.
+** sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo
+** stats for a single query.
**
-** fts3ExprIterate() callback to load the 'global' elements of a
+** sqlite3Fts3ExprIterate() callback to load the 'global' elements of a
** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
** of the matchinfo array that are constant for all rows returned by the
** current query.
@@ -193760,7 +197125,7 @@ static int fts3ExprGlobalHitsCb(
}
/*
-** fts3ExprIterate() callback used to collect the "local" part of the
+** sqlite3Fts3ExprIterate() callback used to collect the "local" part of the
** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
** array that are different for each row returned by the query.
*/
@@ -193956,7 +197321,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
**/
aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase);
if( !aIter ) return SQLITE_NOMEM;
- (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
+ (void)sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
for(i=0; i<pInfo->nPhrase; i++){
LcsIterator *pIter = &aIter[i];
@@ -194133,11 +197498,11 @@ static int fts3MatchinfoValues(
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
if( rc!=SQLITE_OK ) break;
}
- rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
+ rc = sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
sqlite3Fts3EvalTestDeferred(pCsr, &rc);
if( rc!=SQLITE_OK ) break;
}
- (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
+ (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
break;
}
}
@@ -194360,7 +197725,7 @@ struct TermOffsetCtx {
};
/*
-** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets().
+** This function is an sqlite3Fts3ExprIterate() callback used by sqlite3Fts3Offsets().
*/
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
TermOffsetCtx *p = (TermOffsetCtx *)ctx;
@@ -194442,7 +197807,9 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
*/
sCtx.iCol = iCol;
sCtx.iTerm = 0;
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
+ rc = sqlite3Fts3ExprIterate(
+ pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx
+ );
if( rc!=SQLITE_OK ) goto offsets_out;
/* Retreive the text stored in column iCol. If an SQL NULL is stored
@@ -197818,6 +201185,13 @@ static int jsonEachBestIndex(
idxMask |= iMask;
}
}
+ if( pIdxInfo->nOrderBy>0
+ && pIdxInfo->aOrderBy[0].iColumn<0
+ && pIdxInfo->aOrderBy[0].desc==0
+ ){
+ pIdxInfo->orderByConsumed = 1;
+ }
+
if( (unusableMask & ~idxMask)!=0 ){
/* If there are any unusable constraints on JSON or ROOT, then reject
** this entire plan */
@@ -198013,10 +201387,10 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){
#endif
WAGGREGATE(json_group_array, 1, 0, 0,
jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS),
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
WAGGREGATE(json_group_object, 2, 0, 0,
jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC)
};
sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
@@ -198548,7 +201922,7 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
+ assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
pCoord->u = _byteswap_ulong(*(u32*)p);
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -198602,7 +201976,7 @@ static void writeInt16(u8 *p, int i){
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
+ assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -199330,7 +202704,7 @@ static void rtreeNonleafConstraint(
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
- assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
+ assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */
@@ -199383,7 +202757,7 @@ static void rtreeLeafConstraint(
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
- assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
+ assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
@@ -201282,7 +204656,7 @@ static int rtreeUpdate(
rtreeReference(pRtree);
assert(nData>=1);
- cell.iRowid = 0; /* Used only to suppress a compiler warning */
+ memset(&cell, 0, sizeof(cell));
/* Constraint handling. A write operation on an r-tree table may return
** SQLITE_CONSTRAINT for two reasons:
@@ -202755,7 +206129,7 @@ static GeoPoly *geopolyFuncParam(
int nByte;
testcase( pCtx==0 );
if( sqlite3_value_type(pVal)==SQLITE_BLOB
- && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
+ && (nByte = sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord))
){
const unsigned char *a = sqlite3_value_blob(pVal);
int nVertex;
@@ -202813,6 +206187,7 @@ static void geopolyBlobFunc(
sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlite3_result_blob(context, p->hdr,
4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -202832,6 +206207,7 @@ static void geopolyJsonFunc(
sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlite3 *db = sqlite3_context_db_handle(context);
sqlite3_str *x = sqlite3_str_new(db);
@@ -202913,6 +206289,7 @@ static void geopolyXformFunc(
double F = sqlite3_value_double(argv[6]);
GeoCoord x1, y1, x0, y0;
int ii;
+ (void)argc;
if( p ){
for(ii=0; ii<p->nVertex; ii++){
x0 = GeoX(p,ii);
@@ -202963,6 +206340,7 @@ static void geopolyAreaFunc(
sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
sqlite3_result_double(context, geopolyArea(p));
sqlite3_free(p);
@@ -202988,6 +206366,7 @@ static void geopolyCcwFunc(
sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
+ (void)argc;
if( p ){
if( geopolyArea(p)<0.0 ){
int ii, jj;
@@ -203042,6 +206421,7 @@ static void geopolyRegularFunc(
int n = sqlite3_value_int(argv[3]);
int i;
GeoPoly *p;
+ (void)argc;
if( n<3 || r<=0.0 ) return;
if( n>1000 ) n = 1000;
@@ -203151,6 +206531,7 @@ static void geopolyBBoxFunc(
sqlite3_value **argv
){
GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
+ (void)argc;
if( p ){
sqlite3_result_blob(context, p->hdr,
4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -203178,6 +206559,7 @@ static void geopolyBBoxStep(
){
RtreeCoord a[4];
int rc = SQLITE_OK;
+ (void)argc;
(void)geopolyBBox(context, argv[0], a, &rc);
if( rc==SQLITE_OK ){
GeoBBox *pBBox;
@@ -203266,6 +206648,8 @@ static void geopolyContainsPointFunc(
int v = 0;
int cnt = 0;
int ii;
+ (void)argc;
+
if( p1==0 ) return;
for(ii=0; ii<p1->nVertex-1; ii++){
v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
@@ -203305,6 +206689,7 @@ static void geopolyWithinFunc(
){
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ (void)argc;
if( p1 && p2 ){
int x = geopolyOverlap(p1, p2);
if( x<0 ){
@@ -203635,6 +207020,7 @@ static void geopolyOverlapFunc(
){
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+ (void)argc;
if( p1 && p2 ){
int x = geopolyOverlap(p1, p2);
if( x<0 ){
@@ -203655,8 +207041,12 @@ static void geopolyDebugFunc(
int argc,
sqlite3_value **argv
){
+ (void)context;
+ (void)argc;
#ifdef GEOPOLY_ENABLE_DEBUG
geo_debug = sqlite3_value_int(argv[0]);
+#else
+ (void)argv;
#endif
}
@@ -203684,6 +207074,7 @@ static int geopolyInit(
sqlite3_str *pSql;
char *zSql;
int ii;
+ (void)pAux;
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
@@ -203800,6 +207191,7 @@ static int geopolyFilter(
RtreeNode *pRoot = 0;
int rc = SQLITE_OK;
int iCell = 0;
+ (void)idxStr;
rtreeReference(pRtree);
@@ -203926,6 +207318,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int iRowidTerm = -1;
int iFuncTerm = -1;
int idxNum = 0;
+ (void)tab;
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
@@ -204146,7 +207539,7 @@ static int geopolyUpdate(
sqlite3_free(p);
nChange = 1;
}
- for(jj=1; jj<pRtree->nAux; jj++){
+ for(jj=1; jj<nData-2; jj++){
nChange++;
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
}
@@ -204172,6 +207565,8 @@ static int geopolyFindFunction(
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
void **ppArg
){
+ (void)pVtab;
+ (void)nArg;
if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
*pxFunc = geopolyOverlapFunc;
*ppArg = 0;
@@ -204241,7 +207636,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){
} aAgg[] = {
{ geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" },
};
- int i;
+ unsigned int i;
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
int enc;
if( aFunc[i].bPure ){
@@ -204749,8 +208144,9 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( U_SUCCESS(status) ){
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
- }else{
- assert(!pExpr);
+ pExpr = sqlite3_get_auxdata(p, 0);
+ }
+ if( !pExpr ){
icuFunctionError(p, "uregex_open", status);
return;
}
@@ -205461,7 +208857,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** The order of the columns in the data_% table does not matter.
**
** Instead of a regular table, the RBU database may also contain virtual
-** tables or view named using the data_<target> naming scheme.
+** tables or views named using the data_<target> naming scheme.
**
** Instead of the plain data_<target> naming scheme, RBU database tables
** may also be named data<integer>_<target>, where <integer> is any sequence
@@ -205474,7 +208870,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
**
** If the target database table is a virtual table or a table that has no
** PRIMARY KEY declaration, the data_% table must also contain a column
-** named "rbu_rowid". This column is mapped to the tables implicit primary
+** named "rbu_rowid". This column is mapped to the table's implicit primary
** key column - "rowid". Virtual tables for which the "rowid" column does
** not function like a primary key value cannot be updated using RBU. For
** example, if the target db contains either of the following:
@@ -205908,6 +209304,34 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
+** As part of applying an RBU update or performing an RBU vacuum operation,
+** the system must at one point move the *-oal file to the equivalent *-wal
+** path. Normally, it does this by invoking POSIX function rename(2) directly.
+** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
+** function may be used to register a callback that the RBU module will invoke
+** instead of one of these APIs.
+**
+** If a callback is registered with an RBU handle, it invokes it instead
+** of rename(2) when it needs to move a file within the file-system. The
+** first argument passed to the xRename() callback is a copy of the second
+** argument (pArg) passed to this function. The second is the full path
+** to the file to move and the third the full path to which it should be
+** moved. The callback function should return SQLITE_OK to indicate
+** success. If an error occurs, it should return an SQLite error code.
+** In this case the RBU operation will be abandoned and the error returned
+** to the RBU user.
+**
+** Passing a NULL pointer in place of the xRename argument to this function
+** restores the default behaviour.
+*/
+SQLITE_API void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+);
+
+
+/*
** Create an RBU VFS named zName that accesses the underlying file-system
** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
** then the new RBU VFS uses the default system VFS to access the file-system.
@@ -206274,6 +209698,8 @@ struct sqlite3rbu {
int nPagePerSector; /* Pages per sector for pTargetFd */
i64 iOalSz;
i64 nPhaseOneStep;
+ void *pRenameArg;
+ int (*xRename)(void*, const char*, const char*);
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@@ -208662,7 +212088,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){
sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
if( p->zState==0 ){
const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
- p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
+ p->zState = rbuMPrintf(p, "file:///%s-vacuum?modeof=%s", zFile, zFile);
}
}
@@ -208910,11 +212336,11 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
** no-ops. These locks will not be released until the connection
** is closed.
**
- ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
+ ** * Attempting to xSync() the database file causes an SQLITE_NOTICE
** error.
**
** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
- ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
+ ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[]
** array populated with a set of (frame -> page) mappings. Because the
** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
** data from the wal file into the database file according to the
@@ -208924,7 +212350,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
int rc2;
p->eStage = RBU_STAGE_CAPTURE;
rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0);
- if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
+ if( rc2!=SQLITE_NOTICE ) p->rc = rc2;
}
if( p->rc==SQLITE_OK && p->nFrame>0 ){
@@ -208970,7 +212396,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
if( pRbu->mLock!=mReq ){
pRbu->rc = SQLITE_BUSY;
- return SQLITE_INTERNAL;
+ return SQLITE_NOTICE_RBU;
}
pRbu->pgsz = iAmt;
@@ -209122,32 +212548,7 @@ static void rbuMoveOalFile(sqlite3rbu *p){
}
if( p->rc==SQLITE_OK ){
-#if defined(_WIN32_WCE)
- {
- LPWSTR zWideOal;
- LPWSTR zWideWal;
-
- zWideOal = rbuWinUtf8ToUnicode(zOal);
- if( zWideOal ){
- zWideWal = rbuWinUtf8ToUnicode(zWal);
- if( zWideWal ){
- if( MoveFileW(zWideOal, zWideWal) ){
- p->rc = SQLITE_OK;
- }else{
- p->rc = SQLITE_IOERR;
- }
- sqlite3_free(zWideWal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- sqlite3_free(zWideOal);
- }else{
- p->rc = SQLITE_IOERR_NOMEM;
- }
- }
-#else
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
-#endif
+ p->rc = p->xRename(p->pRenameArg, zOal, zWal);
}
if( p->rc!=SQLITE_OK
@@ -209734,7 +213135,8 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
static void rbuDeleteOalFile(sqlite3rbu *p){
char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
if( zOal ){
- sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
+ sqlite3_vfs *pVfs = 0;
+ sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_VFS_POINTER, &pVfs);
assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
pVfs->xDelete(pVfs, zOal, 0);
sqlite3_free(zOal);
@@ -209886,6 +213288,7 @@ static sqlite3rbu *openRbuHandle(
/* Create the custom VFS. */
memset(p, 0, sizeof(sqlite3rbu));
+ sqlite3rbu_rename_handler(p, 0, 0);
rbuCreateVfs(p);
/* Open the target, RBU and state databases */
@@ -210277,6 +213680,54 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
return rc;
}
+/*
+** Default xRename callback for RBU.
+*/
+static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
+ int rc = SQLITE_OK;
+#if defined(_WIN32_WCE)
+ {
+ LPWSTR zWideOld;
+ LPWSTR zWideNew;
+
+ zWideOld = rbuWinUtf8ToUnicode(zOld);
+ if( zWideOld ){
+ zWideNew = rbuWinUtf8ToUnicode(zNew);
+ if( zWideNew ){
+ if( MoveFileW(zWideOld, zWideNew) ){
+ rc = SQLITE_OK;
+ }else{
+ rc = SQLITE_IOERR;
+ }
+ sqlite3_free(zWideNew);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_free(zWideOld);
+ }else{
+ rc = SQLITE_IOERR_NOMEM;
+ }
+ }
+#else
+ rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
+#endif
+ return rc;
+}
+
+SQLITE_API void sqlite3rbu_rename_handler(
+ sqlite3rbu *pRbu,
+ void *pArg,
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
+){
+ if( xRename ){
+ pRbu->xRename = xRename;
+ pRbu->pRenameArg = pArg;
+ }else{
+ pRbu->xRename = xDefaultRename;
+ pRbu->pRenameArg = 0;
+ }
+}
+
/**************************************************************************
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
** of a standard VFS in the following ways:
@@ -210333,7 +213784,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
** database file are recorded. xShmLock() calls to unlock the same
** locks are no-ops (so that once obtained, these locks are never
** relinquished). Finally, calls to xSync() on the target database
-** file fail with SQLITE_INTERNAL errors.
+** file fail with SQLITE_NOTICE errors.
*/
static void rbuUnlockShm(rbu_file *p){
@@ -210442,9 +213893,12 @@ static int rbuVfsClose(sqlite3_file *pFile){
sqlite3_free(p->zDel);
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
+ const sqlite3_io_methods *pMeth = p->pReal->pMethods;
rbuMainlistRemove(p);
rbuUnlockShm(p);
- p->pReal->pMethods->xShmUnmap(p->pReal, 0);
+ if( pMeth->iVersion>1 && pMeth->xShmUnmap ){
+ pMeth->xShmUnmap(p->pReal, 0);
+ }
}
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
rbuUpdateTempSize(p, 0);
@@ -210612,7 +214066,7 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){
rbu_file *p = (rbu_file *)pFile;
if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
- return SQLITE_INTERNAL;
+ return SQLITE_NOTICE_RBU;
}
return SQLITE_OK;
}
@@ -210903,6 +214357,25 @@ static int rbuVfsOpen(
rbuVfsShmUnmap, /* xShmUnmap */
0, 0 /* xFetch, xUnfetch */
};
+ static sqlite3_io_methods rbuvfs_io_methods1 = {
+ 1, /* iVersion */
+ rbuVfsClose, /* xClose */
+ rbuVfsRead, /* xRead */
+ rbuVfsWrite, /* xWrite */
+ rbuVfsTruncate, /* xTruncate */
+ rbuVfsSync, /* xSync */
+ rbuVfsFileSize, /* xFileSize */
+ rbuVfsLock, /* xLock */
+ rbuVfsUnlock, /* xUnlock */
+ rbuVfsCheckReservedLock, /* xCheckReservedLock */
+ rbuVfsFileControl, /* xFileControl */
+ rbuVfsSectorSize, /* xSectorSize */
+ rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ 0, 0, 0, 0, 0, 0
+ };
+
+
+
rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
rbu_file *pFd = (rbu_file *)pFile;
@@ -210957,10 +214430,15 @@ static int rbuVfsOpen(
rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
}
if( pFd->pReal->pMethods ){
+ const sqlite3_io_methods *pMeth = pFd->pReal->pMethods;
/* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
** pointer and, if the file is a main database file, link it into the
** mutex protected linked list of all such files. */
- pFile->pMethods = &rbuvfs_io_methods;
+ if( pMeth->iVersion<2 || pMeth->xShmLock==0 ){
+ pFile->pMethods = &rbuvfs_io_methods1;
+ }else{
+ pFile->pMethods = &rbuvfs_io_methods;
+ }
if( flags & SQLITE_OPEN_MAIN_DB ){
rbuMainlistAdd(pFd);
}
@@ -211393,6 +214871,7 @@ static int statConnect(
StatTable *pTab = 0;
int rc = SQLITE_OK;
int iDb;
+ (void)pAux;
if( argc>=4 ){
Token nm;
@@ -211446,6 +214925,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int iSchema = -1;
int iName = -1;
int iAgg = -1;
+ (void)tab;
/* Look for a valid schema=? constraint. If found, change the idxNum to
** 1 and request the value of that constraint be sent to xFilter. And
@@ -211971,6 +215451,8 @@ static int statFilter(
int iArg = 0; /* Count of argv[] parameters used so far */
int rc = SQLITE_OK; /* Result of this operation */
const char *zName = 0; /* Only provide analysis of this table */
+ (void)argc;
+ (void)idxStr;
statResetCsr(pCsr);
sqlite3_finalize(pCsr->pStmt);
@@ -212054,16 +215536,16 @@ static int statColumn(
}
break;
case 4: /* ncell */
- sqlite3_result_int(ctx, pCsr->nCell);
+ sqlite3_result_int64(ctx, pCsr->nCell);
break;
case 5: /* payload */
- sqlite3_result_int(ctx, pCsr->nPayload);
+ sqlite3_result_int64(ctx, pCsr->nPayload);
break;
case 6: /* unused */
- sqlite3_result_int(ctx, pCsr->nUnused);
+ sqlite3_result_int64(ctx, pCsr->nUnused);
break;
case 7: /* mx_payload */
- sqlite3_result_int(ctx, pCsr->nMxPayload);
+ sqlite3_result_int64(ctx, pCsr->nMxPayload);
break;
case 8: /* pgoffset */
if( !pCsr->isAgg ){
@@ -212071,7 +215553,7 @@ static int statColumn(
}
break;
case 9: /* pgsize */
- sqlite3_result_int(ctx, pCsr->szPage);
+ sqlite3_result_int64(ctx, pCsr->szPage);
break;
case 10: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
@@ -212205,6 +215687,10 @@ static int dbpageConnect(
){
DbpageTable *pTab = 0;
int rc = SQLITE_OK;
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
rc = sqlite3_declare_vtab(db,
@@ -212243,6 +215729,7 @@ static int dbpageDisconnect(sqlite3_vtab *pVtab){
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int i;
int iPlan = 0;
+ (void)tab;
/* If there is a schema= constraint, it must be honored. Report a
** ridiculously large estimated cost if the schema= constraint is
@@ -212358,6 +215845,8 @@ static int dbpageFilter(
sqlite3 *db = pTab->db;
Btree *pBt;
+ (void)idxStr;
+
/* Default setting is no rows of result */
pCsr->pgno = 1;
pCsr->mxPgno = 0;
@@ -212372,7 +215861,7 @@ static int dbpageFilter(
pCsr->iDb = 0;
}
pBt = db->aDb[pCsr->iDb].pBt;
- if( pBt==0 ) return SQLITE_OK;
+ if( NEVER(pBt==0) ) return SQLITE_OK;
pCsr->pPager = sqlite3BtreePager(pBt);
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
@@ -212407,12 +215896,18 @@ static int dbpageColumn(
}
case 1: { /* data */
DbPage *pDbPage = 0;
- rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
- if( rc==SQLITE_OK ){
- sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
- SQLITE_TRANSIENT);
+ if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
+ /* The pending byte page. Assume it is zeroed out. Attempting to
+ ** request this page from the page is an SQLITE_CORRUPT error. */
+ sqlite3_result_zeroblob(ctx, pCsr->szPage);
+ }else{
+ rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
+ SQLITE_TRANSIENT);
+ }
+ sqlite3PagerUnref(pDbPage);
}
- sqlite3PagerUnref(pDbPage);
break;
}
default: { /* schema */
@@ -212421,7 +215916,7 @@ static int dbpageColumn(
break;
}
}
- return SQLITE_OK;
+ return rc;
}
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
@@ -212447,6 +215942,7 @@ static int dbpageUpdate(
Pager *pPager;
int szPage;
+ (void)pRowid;
if( pTab->db->flags & SQLITE_Defensive ){
zErr = "read-only";
goto update_fail;
@@ -212456,18 +215952,20 @@ static int dbpageUpdate(
goto update_fail;
}
pgno = sqlite3_value_int(argv[0]);
- if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL
+ || (Pgno)sqlite3_value_int(argv[1])!=pgno
+ ){
zErr = "cannot insert";
goto update_fail;
}
zSchema = (const char*)sqlite3_value_text(argv[4]);
- iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
- if( iDb<0 ){
+ iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1;
+ if( NEVER(iDb<0) ){
zErr = "no such schema";
goto update_fail;
}
pBt = pTab->db->aDb[iDb].pBt;
- if( pgno<1 || pBt==0 || pgno>sqlite3BtreeLastPage(pBt) ){
+ if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){
zErr = "bad page number";
goto update_fail;
}
@@ -212481,11 +215979,12 @@ static int dbpageUpdate(
pPager = sqlite3BtreePager(pBt);
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
if( rc==SQLITE_OK ){
- rc = sqlite3PagerWrite(pDbPage);
- if( rc==SQLITE_OK ){
- memcpy(sqlite3PagerGetData(pDbPage),
- sqlite3_value_blob(argv[3]),
- szPage);
+ const void *pData = sqlite3_value_blob(argv[3]);
+ assert( pData!=0 || pTab->db->mallocFailed );
+ if( pData
+ && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
+ ){
+ memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
}
}
sqlite3PagerUnref(pDbPage);
@@ -212507,7 +216006,7 @@ static int dbpageBegin(sqlite3_vtab *pVtab){
int i;
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
- if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
+ if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
}
return SQLITE_OK;
}
@@ -214052,6 +217551,8 @@ static void xPreUpdate(
int nDb = sqlite3Strlen30(zDb);
assert( sqlite3_mutex_held(db->mutex) );
+ (void)iKey1;
+ (void)iKey2;
for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
SessionTable *pTab;
@@ -214128,6 +217629,7 @@ static int sessionDiffCount(void *pCtx){
return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
}
static int sessionDiffDepth(void *pCtx){
+ (void)pCtx;
return 0;
}
@@ -214201,7 +217703,6 @@ static char *sessionExprCompareOther(
}
static char *sessionSelectFindNew(
- int nCol,
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
const char *zTbl, /* Table name */
@@ -214225,7 +217726,7 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -215880,6 +219381,22 @@ static int sessionChangesetNextOne(
if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
}
+
+ /* If this is an UPDATE that is part of a changeset, then check that
+ ** there are no fields in the old.* record that are not (a) PK fields,
+ ** or (b) also present in the new.* record.
+ **
+ ** Such records are technically corrupt, but the rebaser was at one
+ ** point generating them. Under most circumstances this is benign, but
+ ** can cause spurious SQLITE_RANGE errors when applying the changeset. */
+ if( p->bPatchset==0 && p->op==SQLITE_UPDATE){
+ for(i=0; i<p->nCol; i++){
+ if( p->abPK[i]==0 && p->apValue[i+p->nCol]==0 ){
+ sqlite3ValueFree(p->apValue[i]);
+ p->apValue[i] = 0;
+ }
+ }
+ }
}
return SQLITE_ROW;
@@ -216726,7 +220243,6 @@ static int sessionBindRow(
** UPDATE, bind values from the old.* record.
*/
static int sessionSeekToRow(
- sqlite3 *db, /* Database handle */
sqlite3_changeset_iter *pIter, /* Changeset iterator */
u8 *abPK, /* Primary key flags array */
sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
@@ -216856,7 +220372,7 @@ static int sessionConflictHandler(
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
if( pbReplace ){
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
}else{
rc = SQLITE_OK;
}
@@ -217030,7 +220546,7 @@ static int sessionApplyOneOp(
/* Check if there is a conflicting row. For sqlite_stat1, this needs
** to be done using a SELECT, as there is no PRIMARY KEY in the
** database schema to throw an exception if a duplicate is inserted. */
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
if( rc==SQLITE_ROW ){
rc = SQLITE_CONSTRAINT;
sqlite3_reset(p->pSelect);
@@ -218076,7 +221592,7 @@ static void sessionAppendPartialUpdate(
if( !pIter->abPK[i] && a1[0] ) bData = 1;
memcpy(pOut, a1, n1);
pOut += n1;
- }else if( a2[0]!=0xFF ){
+ }else if( a2[0]!=0xFF && a1[0] ){
bData = 1;
memcpy(pOut, a2, n2);
pOut += n2;
@@ -219233,7 +222749,7 @@ static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
-#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
+#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,(i64)c)
#define fts5BufferFree(a) sqlite3Fts5BufferFree(a)
#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d)
@@ -223680,6 +227196,19 @@ static int sqlite3Fts5ExprNew(
}
/*
+** Assuming that buffer z is at least nByte bytes in size and contains a
+** valid utf-8 string, return the number of characters in the string.
+*/
+static int fts5ExprCountChar(const char *z, int nByte){
+ int nRet = 0;
+ int ii;
+ for(ii=0; ii<nByte; ii++){
+ if( (z[ii] & 0xC0)!=0x80 ) nRet++;
+ }
+ return nRet;
+}
+
+/*
** This function is only called when using the special 'trigram' tokenizer.
** Argument zText contains the text of a LIKE or GLOB pattern matched
** against column iCol. This function creates and compiles an FTS5 MATCH
@@ -223716,7 +227245,8 @@ static int sqlite3Fts5ExprPattern(
if( i==nText
|| zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2]
){
- if( i-iFirst>=3 ){
+
+ if( fts5ExprCountChar(&zText[iFirst], i-iFirst)>=3 ){
int jj;
zExpr[iOut++] = '"';
for(jj=iFirst; jj<i; jj++){
@@ -227077,6 +230607,8 @@ static void sqlite3Fts5HashScanEntry(
# error "FTS5_MAX_PREFIX_INDEXES is too large"
#endif
+#define FTS5_MAX_LEVEL 64
+
/*
** Details:
**
@@ -231110,7 +234642,9 @@ static void fts5WriteAppendRowid(
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
+ fts5BufferAppendVarint(&p->rc, &pPage->buf,
+ (u64)iRowid - (u64)pWriter->iPrevRowid
+ );
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
@@ -231789,10 +235323,10 @@ static Fts5Structure *fts5IndexOptimizeStruct(
if( pNew ){
Fts5StructureLevel *pLvl;
nByte = nSeg * sizeof(Fts5StructureSegment);
- pNew->nLevel = pStruct->nLevel+1;
+ pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
- pLvl = &pNew->aLevel[pStruct->nLevel];
+ pLvl = &pNew->aLevel[pNew->nLevel-1];
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pLvl->aSeg ){
int iLvl, iSeg;
@@ -231874,7 +235408,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
static void fts5AppendRowid(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pUnused,
Fts5Buffer *pBuf
){
@@ -231884,7 +235418,7 @@ static void fts5AppendRowid(
static void fts5AppendPoslist(
Fts5Index *p,
- i64 iDelta,
+ u64 iDelta,
Fts5Iter *pMulti,
Fts5Buffer *pBuf
){
@@ -231959,10 +235493,10 @@ static void fts5MergeAppendDocid(
}
#endif
-#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
- assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
- fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
- (iLastRowid) = (iRowid); \
+#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
+ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
+ fts5BufferSafeAppendVarint((pBuf), (u64)(iRowid) - (u64)(iLastRowid)); \
+ (iLastRowid) = (iRowid); \
}
/*
@@ -232094,7 +235628,7 @@ static void fts5MergePrefixLists(
/* Initialize a doclist-iterator for each input buffer. Arrange them in
** a linked-list starting at pHead in ascending order of rowid. Avoid
** linking any iterators already at EOF into the linked list at all. */
- assert( nBuf+1<=sizeof(aMerger)/sizeof(aMerger[0]) );
+ assert( nBuf+1<=(int)(sizeof(aMerger)/sizeof(aMerger[0])) );
memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1));
pHead = &aMerger[nBuf];
fts5DoclistIterInit(p1, &pHead->iter);
@@ -232233,7 +235767,7 @@ static void fts5SetupPrefixIter(
int nMerge = 1;
void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
xMerge = fts5MergeRowidLists;
xAppend = fts5AppendRowid;
@@ -232272,7 +235806,7 @@ static void fts5SetupPrefixIter(
Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
p1->xSetOutputs(p1, pSeg);
if( p1->base.nData ){
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
}
@@ -232320,7 +235854,7 @@ static void fts5SetupPrefixIter(
iLastRowid = 0;
}
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
iLastRowid = p1->base.iRowid;
}
@@ -233299,6 +236833,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum
/* If this is a new term, query for it. Update cksum3 with the results. */
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
+ if( p->rc ) break;
if( eDetail==FTS5_DETAIL_NONE ){
if( 0==fts5MultiIterIsEmpty(p, pIter) ){
@@ -234103,7 +237638,7 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
break;
case FTS5_SYNC:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState==1 || p->ts.eState==2 );
p->ts.eState = 2;
break;
@@ -234118,21 +237653,21 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
break;
case FTS5_SAVEPOINT:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=0 );
assert( iSavepoint>=p->ts.iSavepoint );
p->ts.iSavepoint = iSavepoint;
break;
case FTS5_RELEASE:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=0 );
assert( iSavepoint<=p->ts.iSavepoint );
p->ts.iSavepoint = iSavepoint-1;
break;
case FTS5_ROLLBACKTO:
- assert( p->ts.eState==1 );
+ assert( p->ts.eState>=1 );
assert( iSavepoint>=-1 );
/* The following assert() can fail if another vtab strikes an error
** within an xSavepoint() call then SQLite calls xRollbackTo() - without
@@ -235468,7 +239003,7 @@ static int fts5UpdateMethod(
int rc = SQLITE_OK; /* Return code */
/* A transaction must be open when this is called. */
- assert( pTab->ts.eState==1 );
+ assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
assert( pVtab->zErrMsg==0 );
assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
@@ -236636,7 +240171,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d", -1, SQLITE_TRANSIENT);
}
/*
@@ -236709,7 +240244,9 @@ static int fts5Init(sqlite3 *db){
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(
- db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
+ db, "fts5_source_id", 0,
+ SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
+ p, fts5SourceIdFunc, 0, 0
);
}
}
@@ -241374,6 +244911,10 @@ static int stmtConnect(
#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
+ (void)pAux;
+ (void)argc;
+ (void)argv;
+ (void)pzErr;
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
"reprep,run,mem)");
@@ -241493,6 +245034,10 @@ static int stmtFilter(
sqlite3_int64 iRowid = 1;
StmtRow **ppRow = 0;
+ (void)idxNum;
+ (void)idxStr;
+ (void)argc;
+ (void)argv;
stmtCsrReset(pCur);
ppRow = &pCur->pRow;
for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){
@@ -241548,6 +245093,7 @@ static int stmtBestIndex(
sqlite3_vtab *tab,
sqlite3_index_info *pIdxInfo
){
+ (void)tab;
pIdxInfo->estimatedCost = (double)500;
pIdxInfo->estimatedRows = 500;
return SQLITE_OK;
diff --git a/src/libs/3rdparty/sqlite/sqlite3.h b/src/libs/3rdparty/sqlite/sqlite3.h
index f0df724d7b..4c6addac26 100644
--- a/src/libs/3rdparty/sqlite/sqlite3.h
+++ b/src/libs/3rdparty/sqlite/sqlite3.h
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.39.2"
-#define SQLITE_VERSION_NUMBER 3039002
-#define SQLITE_SOURCE_ID "2022-07-21 15:24:47 698edb77537b67c41adc68f9b892db56bcf9a55e00371a61420f3ddd668e6603"
+#define SQLITE_VERSION "3.41.0"
+#define SQLITE_VERSION_NUMBER 3041000
+#define SQLITE_SOURCE_ID "2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -563,6 +563,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
@@ -670,13 +671,17 @@ SQLITE_API int sqlite3_exec(
**
** SQLite uses one of these integer values as the second
** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlite3_io_methods] object.
+** of an [sqlite3_io_methods] object. These values are ordered from
+** lest restrictive to most restrictive.
+**
+** The argument to xLock() is always SHARED or higher. The argument to
+** xUnlock is either SHARED or NONE.
*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
/*
** CAPI3REF: Synchronization Type Flags
@@ -754,7 +759,14 @@ struct sqlite3_file {
** <li> [SQLITE_LOCK_PENDING], or
** <li> [SQLITE_LOCK_EXCLUSIVE].
** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
+** xLock() upgrades the database file lock. In other words, xLock() moves the
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
+** requested lock, then the call to xLock() is a no-op.
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
+* If the lock is already at or below the requested lock state, then the call
+** to xUnlock() is a no-op.
** The xCheckReservedLock() method checks whether any database connection,
** either in this process or in some other process, is holding a RESERVED,
** PENDING, or EXCLUSIVE lock on the file. It returns true
@@ -859,9 +871,8 @@ struct sqlite3_io_methods {
** opcode causes the xFileControl method to write the current state of
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and is only available when the SQLITE_TEST
-** compile-time option is used.
+** into an integer that the pArg argument points to.
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
**
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
@@ -1165,7 +1176,6 @@ struct sqlite3_io_methods {
** in wal mode after the client has finished copying pages from the wal
** file to the database file, but before the *-shm file is updated to
** record the fact that the pages have been checkpointed.
-** </ul>
**
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
@@ -1178,10 +1188,16 @@ struct sqlite3_io_methods {
** the database is not a wal-mode db, or if there is no such connection in any
** other process. This opcode cannot be used to detect transactions opened
** by clients within the current process, only within other processes.
-** </ul>
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** Used by the cksmvfs VFS module only.
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** [checksum VFS shim] only.
+**
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
+** If there is currently no transaction open on the database, and the
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
+** purges the contents of the in-memory page cache. If there is an open
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1224,6 +1240,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_CKPT_START 39
#define SQLITE_FCNTL_EXTERNAL_READER 40
#define SQLITE_FCNTL_CKSM_FILE 41
+#define SQLITE_FCNTL_RESET_CACHE 42
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1254,6 +1271,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
+** CAPI3REF: File Name
+**
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
+** may also be passed to special APIs such as:
+**
+** <ul>
+** <li> sqlite3_filename_database()
+** <li> sqlite3_filename_journal()
+** <li> sqlite3_filename_wal()
+** <li> sqlite3_uri_parameter()
+** <li> sqlite3_uri_boolean()
+** <li> sqlite3_uri_int64()
+** <li> sqlite3_uri_key()
+** </ul>
+*/
+typedef const char *sqlite3_filename;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1431,7 +1468,7 @@ struct sqlite3_vfs {
sqlite3_vfs *pNext; /* Next registered VFS */
const char *zName; /* Name of this virtual file system */
void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
+ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*,
int flags, int *pOutFlags);
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
@@ -2147,7 +2184,7 @@ struct sqlite3_mem_methods {
** configuration for a database connection can only be changed when that
** connection is not currently using lookaside memory, or in other words
** when the "current value" returned by
-** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
+** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
** Any attempt to change the lookaside memory configuration when lookaside
** memory is in use leaves the configuration unchanged and returns
** [SQLITE_BUSY].)^</dd>
@@ -2297,8 +2334,12 @@ struct sqlite3_mem_methods {
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
** </ol>
** Because resetting a database is destructive and irreversible, the
-** process requires the use of this obscure API and multiple steps to help
-** ensure that it does not happen by accident.
+** process requires the use of this obscure API and multiple steps to
+** help ensure that it does not happen by accident. Because this
+** feature must be capable of resetting corrupt databases, and
+** shutting down virtual tables may require access to that corrupt
+** storage, the library must abandon any installed virtual tables
+** without calling their xDestroy() methods.
**
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
@@ -2309,6 +2350,7 @@ struct sqlite3_mem_methods {
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
+** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** </ul>
@@ -2636,8 +2678,12 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
** SQL statements is a no-op and has no effect on SQL statements
** that are started after the sqlite3_interrupt() call returns.
+**
+** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
+** or not an interrupt is currently in effect for [database connection] D.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
+SQLITE_API int sqlite3_is_interrupted(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -3255,8 +3301,8 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
** information as is provided by the [sqlite3_profile()] callback.
** ^The P argument is a pointer to the [prepared statement] and the
-** X argument points to a 64-bit integer which is the estimated of
-** the number of nanosecond that the prepared statement took to run.
+** X argument points to a 64-bit integer which is approximately
+** the number of nanoseconds that the prepared statement took to run.
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
**
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
@@ -3319,7 +3365,7 @@ SQLITE_API int sqlite3_trace_v2(
**
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
** function X to be invoked periodically during long running calls to
-** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
+** [sqlite3_step()] and [sqlite3_prepare()] and similar for
** database connection D. An example use for this
** interface is to keep a GUI updated during a large query.
**
@@ -3344,6 +3390,13 @@ SQLITE_API int sqlite3_trace_v2(
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
** database connections for the meaning of "modify" in this paragraph.
**
+** The progress handler callback would originally only be invoked from the
+** bytecode engine. It still might be invoked during [sqlite3_prepare()]
+** and similar because those routines might force a reparse of the schema
+** which involves running the bytecode engine. However, beginning with
+** SQLite version 3.41.0, the progress handler callback might also be
+** invoked directly from [sqlite3_prepare()] while analyzing and generating
+** code for complex queries.
*/
SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
@@ -3380,13 +3433,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
**
** <dl>
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
-** <dd>The database is opened in read-only mode. If the database does not
-** already exist, an error is returned.</dd>)^
+** <dd>The database is opened in read-only mode. If the database does
+** not already exist, an error is returned.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
-** <dd>The database is opened for reading and writing if possible, or reading
-** only if the file is write protected by the operating system. In either
-** case the database must already exist, otherwise an error is returned.</dd>)^
+** <dd>The database is opened for reading and writing if possible, or
+** reading only if the file is write protected by the operating
+** system. In either case the database must already exist, otherwise
+** an error is returned. For historical reasons, if opening in
+** read-write mode fails due to OS-level permissions, an attempt is
+** made to open it in read-only mode. [sqlite3_db_readonly()] can be
+** used to determine whether the database is actually
+** read-write.</dd>)^
**
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
** <dd>The database is opened for reading and writing, and is created if
@@ -3424,6 +3482,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** <dd>The database is opened [shared cache] enabled, overriding
** the default shared cache setting provided by
** [sqlite3_enable_shared_cache()].)^
+** The [use of shared cache mode is discouraged] and hence shared cache
+** capabilities may be omitted from many builds of SQLite. In such cases,
+** this option is a no-op.
**
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
** <dd>The database is opened [shared cache] disabled, overriding
@@ -3439,7 +3500,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** to return an extended result code.</dd>
**
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
-** <dd>The database filename is not allowed to be a symbolic link</dd>
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
** </dl>)^
**
** If the 3rd parameter to sqlite3_open_v2() is not one of the
@@ -3698,10 +3759,10 @@ SQLITE_API int sqlite3_open_v2(
**
** See the [URI filename] documentation for additional information.
*/
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
/*
** CAPI3REF: Translate filenames
@@ -3730,9 +3791,9 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
** return value from [sqlite3_db_filename()], then the result is
** undefined and is likely a memory access violation.
*/
-SQLITE_API const char *sqlite3_filename_database(const char*);
-SQLITE_API const char *sqlite3_filename_journal(const char*);
-SQLITE_API const char *sqlite3_filename_wal(const char*);
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
/*
** CAPI3REF: Database File Corresponding To A Journal
@@ -3798,14 +3859,14 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
** then the corresponding [sqlite3_module.xClose() method should also be
** invoked prior to calling sqlite3_free_filename(Y).
*/
-SQLITE_API char *sqlite3_create_filename(
+SQLITE_API sqlite3_filename sqlite3_create_filename(
const char *zDatabase,
const char *zJournal,
const char *zWal,
int nParam,
const char **azParam
);
-SQLITE_API void sqlite3_free_filename(char*);
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
/*
** CAPI3REF: Error Codes And Messages
@@ -5364,10 +5425,21 @@ SQLITE_API int sqlite3_create_window_function(
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
** schema structures such as [CHECK constraints], [DEFAULT clauses],
** [expression indexes], [partial indexes], or [generated columns].
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
-** for all [application-defined SQL functions], and especially for functions
-** that have side-effects or that could potentially leak sensitive
-** information.
+** <p>
+** The SQLITE_DIRECTONLY flag is recommended for any
+** [application-defined SQL function]
+** that has side-effects or that could potentially leak sensitive information.
+** This will prevent attacks in which an application is tricked
+** into using a database file that has had its schema surreptiously
+** modified to invoke the application-defined function in ways that are
+** harmful.
+** <p>
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
+** [application-defined SQL functions], regardless of whether or not they
+** are security sensitive, as doing so prevents those functions from being used
+** inside of the database schema, and thus ensures that the database
+** can be inspected and modified using generic tools (such as the [CLI])
+** that do not have access to the application-defined functions.
** </dd>
**
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
@@ -5574,6 +5646,28 @@ SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
/*
+** CAPI3REF: Report the internal text encoding state of an sqlite3_value object
+** METHOD: sqlite3_value
+**
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
+** returns something other than SQLITE_TEXT, then the return value from
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
+** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
+** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
+** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
+**
+** This routine is intended for used by applications that test and validate
+** the SQLite implementation. This routine is inquiring about the opaque
+** internal state of an [sqlite3_value] object. Ordinary applications should
+** not need to know what the internal state of an sqlite3_value object is and
+** hence should not need to use this interface.
+*/
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
+
+/*
** CAPI3REF: Finding The Subtype Of SQL Values
** METHOD: sqlite3_value
**
@@ -5625,7 +5719,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
**
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** when first called if N is less than or equal to zero or if a memory
-** allocate error occurs.
+** allocation error occurs.
**
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the
@@ -5830,9 +5924,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlite3_result_text* interfaces.
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
+** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces
+** other than sqlite3_result_text64() is negative, then SQLite computes
+** the string length itself by searching the 2nd parameter for the first
+** zero character.
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
** is non-negative, then as many bytes (not characters) of the text
** pointed to by the 2nd parameter are taken as the application-defined
@@ -6328,7 +6423,7 @@ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
** <li> [sqlite3_filename_wal()]
** </ul>
*/
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -6465,7 +6560,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** function C that is invoked prior to each autovacuum of the database
** file. ^The callback is passed a copy of the generic data pointer (P),
** the schema-name of the attached database that is being autovacuumed,
-** the the size of the database file in pages, the number of free pages,
+** the size of the database file in pages, the number of free pages,
** and the number of bytes per page, respectively. The callback should
** return the number of free pages that should be removed by the
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
@@ -6586,6 +6681,11 @@ SQLITE_API void *sqlite3_update_hook(
** to the same database. Sharing is enabled if the argument is true
** and disabled if the argument is false.)^
**
+** This interface is omitted if SQLite is compiled with
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
+** compile-time option is recommended because the
+** [use of shared cache mode is discouraged].
+**
** ^Cache sharing is enabled and disabled for an entire process.
** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
** In prior versions of SQLite,
@@ -6684,7 +6784,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
** ^The soft heap limit may not be greater than the hard heap limit.
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
** is invoked with a value of N that is greater than the hard heap limit,
-** the the soft heap limit is set to the value of the hard heap limit.
+** the soft heap limit is set to the value of the hard heap limit.
** ^The soft heap limit is automatically enabled whenever the hard heap
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
** the soft heap limit is outside the range of 1..N, then the soft heap
@@ -6946,15 +7046,6 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
SQLITE_API void sqlite3_reset_auto_extension(void);
/*
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** Structures used by the virtual table interface
*/
typedef struct sqlite3_vtab sqlite3_vtab;
@@ -7072,10 +7163,10 @@ struct sqlite3_module {
** when the omit flag is true there is no guarantee that the constraint will
** not be checked again using byte code.)^
**
-** ^The idxNum and idxPtr values are recorded and passed into the
+** ^The idxNum and idxStr values are recorded and passed into the
** [xFilter] method.
-** ^[sqlite3_free()] is used to free idxPtr if and only if
-** needToFreeIdxPtr is true.
+** ^[sqlite3_free()] is used to free idxStr if and only if
+** needToFreeIdxStr is true.
**
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
** the correct order to satisfy the ORDER BY clause so that no separate
@@ -7195,7 +7286,7 @@ struct sqlite3_index_info {
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
** tables, the collating sequence of constraints does not matter (for example
** because the constraints are numeric) and so the sqlite3_vtab_collation()
-** interface is no commonly needed.
+** interface is not commonly needed.
*/
#define SQLITE_INDEX_CONSTRAINT_EQ 2
#define SQLITE_INDEX_CONSTRAINT_GT 4
@@ -7355,16 +7446,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
**
@@ -8979,7 +9060,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** if the application incorrectly accesses the destination [database connection]
** and so no error code is reported, but the operations may malfunction
** nevertheless. Use of the destination database connection while a
-** backup is in progress might also also cause a mutex deadlock.
+** backup is in progress might also cause a mutex deadlock.
**
** If running in [shared cache mode], the application must
** guarantee that the shared cache used by the destination database
@@ -9407,7 +9488,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
*/
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
/*
@@ -9567,7 +9648,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
** <li><p> Otherwise, "BINARY" is returned.
** </ol>
*/
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
+SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
/*
** CAPI3REF: Determine if a virtual table query is DISTINCT
@@ -9724,21 +9805,20 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
** is undefined and probably harmful.
**
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
-** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
+** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
** xFilter method which invokes these routines, and specifically
** a parameter that was previously selected for all-at-once IN constraint
** processing use the [sqlite3_vtab_in()] interface in the
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
** an xFilter argument that was selected for all-at-once IN constraint
-** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
-** exhibit some other undefined or harmful behavior.
+** processing, then these routines return [SQLITE_ERROR].)^
**
** ^(Use these routines to access all values on the right-hand side
** of the IN constraint using code like the following:
**
** <blockquote><pre>
** &nbsp; for(rc=sqlite3_vtab_in_first(pList, &pVal);
-** &nbsp; rc==SQLITE_OK && pVal
+** &nbsp; rc==SQLITE_OK && pVal;
** &nbsp; rc=sqlite3_vtab_in_next(pList, &pVal)
** &nbsp; ){
** &nbsp; // do something with pVal
@@ -9836,6 +9916,10 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
** managed by the prepared statement S and will be automatically freed when
** S is finalized.
**
+** Not all values are available for all query elements. When a value is
+** not available, the output variable is set to -1 if the value is numeric,
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
+**
** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
@@ -9863,12 +9947,24 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
** description for the X-th loop.
**
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
** <dd>^The "int" variable pointed to by the V parameter will be set to the
-** "select-id" for the X-th loop. The select-id identifies which query or
-** subquery the loop is part of. The main query has a select-id of zero.
-** The select-id is the same value as is output in the first column
-** of an [EXPLAIN QUERY PLAN] query.
+** id for the X-th query plan element. The id value is unique within the
+** statement. The select-id is the same value as is output in the first
+** column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
+** <dd>The "int" variable pointed to by the V parameter will be set to the
+** the id of the parent of the current query element, if applicable, or
+** to zero if the query element has no parent. This is the same value as
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
+**
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
+** <dd>The sqlite3_int64 output value is set to the number of cycles,
+** according to the processor time-stamp counter, that elapsed while the
+** query element was being processed. This value is not available for
+** all query elements - if it is unavailable the output variable is
+** set to -1.
** </dl>
*/
#define SQLITE_SCANSTAT_NLOOP 0
@@ -9877,12 +9973,14 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
#define SQLITE_SCANSTAT_NAME 3
#define SQLITE_SCANSTAT_EXPLAIN 4
#define SQLITE_SCANSTAT_SELECTID 5
+#define SQLITE_SCANSTAT_PARENTID 6
+#define SQLITE_SCANSTAT_NCYCLE 7
/*
** CAPI3REF: Prepared Statement Scan Status
** METHOD: sqlite3_stmt
**
-** This interface returns information about the predicted and measured
+** These interfaces return information about the predicted and measured
** performance for pStmt. Advanced applications can use this
** interface to compare the predicted and the measured performance and
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
@@ -9893,19 +9991,25 @@ SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **
**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
-** of this interface is undefined.
-** ^The requested measurement is written into a variable pointed to by
-** the "pOut" parameter.
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
-** Loops are numbered starting from zero. ^If idx is out of range - less than
-** zero or greater than or equal to the total number of loops used to implement
-** the statement - a non-zero value is returned and the variable that pOut
-** points to is unchanged.
-**
-** ^Statistics might not be available for all loops in all statements. ^In cases
-** where there exist loops with no available statistics, this function behaves
-** as if the loop did not exist - it returns non-zero and leave the variable
-** that pOut points to unchanged.
+** of this interface is undefined. ^The requested measurement is written into
+** a variable pointed to by the "pOut" parameter.
+**
+** The "flags" parameter must be passed a mask of flags. At present only
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
+** is specified, then status information is available for all elements
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
+** sqlite3_stmt_scanstatus() is equivalent to calling
+** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
+**
+** Parameter "idx" identifies the specific query element to retrieve statistics
+** for. Query elements are numbered starting from zero. A value of -1 may be
+** to query for statistics regarding the entire query. ^If idx is out of range
+** - less than -1 or greater than or equal to the total number of query
+** elements used to implement the statement - a non-zero value is returned and
+** the variable that pOut points to is unchanged.
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
@@ -9915,6 +10019,19 @@ SQLITE_API int sqlite3_stmt_scanstatus(
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
void *pOut /* Result written here */
);
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
+ int idx, /* Index of loop to report on */
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
+ int flags, /* Mask of flags defined below */
+ void *pOut /* Result written here */
+);
+
+/*
+** CAPI3REF: Prepared Statement Scan Status
+** KEYWORDS: {scan status flags}
+*/
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
/*
** CAPI3REF: Zero Scan-Status Counters
@@ -10005,6 +10122,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** function is not defined for operations on WITHOUT ROWID tables, or for
** DELETE operations on rowid tables.
**
+** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from
+** the previous call on the same [database connection] D, or NULL for
+** the first call on D.
+**
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
** provide additional information about a preupdate event. These routines
@@ -10410,6 +10531,19 @@ SQLITE_API int sqlite3_deserialize(
# undef double
#endif
+#if defined(__wasi__)
+# undef SQLITE_WASI
+# define SQLITE_WASI 1
+# undef SQLITE_OMIT_WAL
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
+# define SQLITE_OMIT_LOAD_EXTENSION
+# endif
+# ifndef SQLITE_THREADSAFE
+# define SQLITE_THREADSAFE 0
+# endif
+#endif
+
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
diff --git a/src/libs/3rdparty/sqlite/sqlite3ext.h b/src/libs/3rdparty/sqlite/sqlite3ext.h
index 2cdd0e429b..19e030028a 100644
--- a/src/libs/3rdparty/sqlite/sqlite3ext.h
+++ b/src/libs/3rdparty/sqlite/sqlite3ext.h
@@ -331,9 +331,9 @@ struct sqlite3_api_routines {
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
- char *(*create_filename)(const char*,const char*,const char*,
+ const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
- void (*free_filename)(char*);
+ void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
@@ -357,6 +357,10 @@ struct sqlite3_api_routines {
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
+ /* Version 3.40.0 and later */
+ int (*value_encoding)(sqlite3_value*);
+ /* Version 3.41.0 and later */
+ int (*is_interrupted)(sqlite3*);
};
/*
@@ -681,6 +685,10 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
+/* Version 3.40.0 and later */
+#define sqlite3_value_encoding sqlite3_api->value_encoding
+/* Version 3.41.0 and later */
+#define sqlite3_is_interrupted sqlite3_api->is_interrupted
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/libs/advanceddockingsystem/dockareatitlebar.cpp b/src/libs/advanceddockingsystem/dockareatitlebar.cpp
index 178170777d..02c83489fa 100644
--- a/src/libs/advanceddockingsystem/dockareatitlebar.cpp
+++ b/src/libs/advanceddockingsystem/dockareatitlebar.cpp
@@ -17,6 +17,8 @@
#include "floatingdragpreview.h"
#include "iconprovider.h"
+#include <utils/qtcassert.h>
+
#include <QBoxLayout>
#include <QLoggingCategory>
#include <QMenu>
@@ -379,6 +381,8 @@ namespace ADS
void DockAreaTitleBar::updateDockWidgetActionsButtons()
{
+ QTC_ASSERT(d->m_tabBar->currentTab(), return );
+ QTC_ASSERT(d->m_tabBar->currentTab()->dockWidget(), return );
DockWidget* dockWidget = d->m_tabBar->currentTab()->dockWidget();
if (!d->m_dockWidgetActionsButtons.isEmpty()) {
for (auto button : std::as_const(d->m_dockWidgetActionsButtons)) {
diff --git a/src/libs/advanceddockingsystem/dockfocuscontroller.cpp b/src/libs/advanceddockingsystem/dockfocuscontroller.cpp
index 79b6c6cad2..a5878ba856 100644
--- a/src/libs/advanceddockingsystem/dockfocuscontroller.cpp
+++ b/src/libs/advanceddockingsystem/dockfocuscontroller.cpp
@@ -105,11 +105,16 @@ namespace ADS
q, &DockFocusController::onFocusedDockAreaViewToggled);
}
- auto newFloatingWidget = m_focusedDockWidget->dockContainer()->floatingWidget();
+ auto dockContainer = m_focusedDockWidget->dockContainer();
+ FloatingDockContainer *newFloatingWidget = nullptr;
+
+ if (dockContainer)
+ newFloatingWidget = dockContainer->floatingWidget();
+
if (newFloatingWidget)
newFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(dockWidget));
- #ifdef Q_OS_LINUX
+#ifdef Q_OS_LINUX
// This code is required for styling the floating widget titlebar for linux
// depending on the current focus state
if (m_floatingWidget == newFloatingWidget)
@@ -122,7 +127,7 @@ namespace ADS
if (m_floatingWidget)
updateFloatingWidgetFocusStyle(m_floatingWidget, true);
- #endif
+#endif
if (old != dockWidget)
emit m_dockManager->focusedDockWidgetChanged(old, dockWidget);
@@ -162,6 +167,8 @@ namespace ADS
if (!dockWidget)
dockWidget = qobject_cast<DockWidget *>(focusedNow);
+ bool focusActual = dockWidget && dockWidget->widget();
+
if (!dockWidget)
dockWidget = internal::findParent<DockWidget *>(focusedNow);
@@ -174,6 +181,12 @@ namespace ADS
#endif
d->updateDockWidgetFocus(dockWidget);
+
+ if (focusActual) {
+ // Do this async to avoid issues when changing focus in middle of another focus handling
+ QMetaObject::invokeMethod(dockWidget->widget(), QOverload<>::of(&QWidget::setFocus),
+ Qt::QueuedConnection);
+ }
}
void DockFocusController::setDockWidgetFocused(DockWidget *focusedNow)
diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp
index 2694f2986e..46e7b5e5af 100644
--- a/src/libs/advanceddockingsystem/dockmanager.cpp
+++ b/src/libs/advanceddockingsystem/dockmanager.cpp
@@ -599,10 +599,13 @@ namespace ADS
return d->m_settings->value(Constants::AUTO_RESTORE_WORKSPACE_SETTINGS_KEY).toBool();
}
- const QString m_dirName = QLatin1String("workspaces");
- const QString m_fileExt = QLatin1String(".wrk"); // TODO
+ constexpr QStringView m_dirName{u"workspaces"};
+ constexpr QStringView m_fileExt{u".wrk"}; // TODO
- QString DockManager::workspaceFileExtension() const { return m_fileExt; }
+ QStringView DockManager::workspaceFileExtension() const
+ {
+ return m_fileExt;
+ }
QStringList DockManager::workspaces()
{
diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h
index 9dbfc30cda..9ef2a6f3f1 100644
--- a/src/libs/advanceddockingsystem/dockmanager.h
+++ b/src/libs/advanceddockingsystem/dockmanager.h
@@ -484,7 +484,7 @@ public:
QString activeWorkspace() const;
QString lastWorkspace() const;
bool autoRestorLastWorkspace() const;
- QString workspaceFileExtension() const;
+ QStringView workspaceFileExtension() const;
QStringList workspaces();
QSet<QString> workspacePresets() const;
QDateTime workspaceDateTime(const QString &workspace) const;
diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp
index 8b6bd8e7dc..8d5bcadad5 100644
--- a/src/libs/qmljs/qmljscheck.cpp
+++ b/src/libs/qmljs/qmljscheck.cpp
@@ -1838,16 +1838,32 @@ bool Check::visit(CallExpression *ast)
static const QStringList translationFunctions = {"qsTr", "qsTrId", "qsTranslate",
"qsTrNoOp", "qsTrIdNoOp", "qsTranslateNoOp"};
- static const QStringList whiteListedFunctions = {"toString", "toFixed", "toExponential", "toPrecision", "isFinite", "isNaN", "valueOf",
- "toLowerCase", "toLocaleString", "toLocaleLowerCase", "toUpperCase", "toLocaleUpperCase",
- "substring" , "charAt", "charCodeAt", "concat", "endsWith", "includes", "indexOf", "lastIndexOf"};
+ static const QStringList whiteListedFunctions = {
+ "toString", "toFixed", "toExponential", "toPrecision", "isFinite",
+ "isNaN", "valueOf", "toLowerCase", "toLocaleString", "toLocaleLowerCase",
+ "toUpperCase", "toLocaleUpperCase", "substring", "charAt", "charCodeAt",
+ "concat", "endsWith", "includes", "indexOf", "lastIndexOf",
+ "arg"};
static const QStringList colorFunctions = {"lighter", "darker", "rgba", "tint", "hsla", "hsva"};
- static const QStringList qtFunction = {"point", "rect", "size", "vector2d", "vector3d", "vector4d", "quaternion" "matrix4x4", "formatDate",
- "formatDateTime", "formatTime", "resolvedUrl"};
+ static const QStringList qtFunction = {"point",
+ "rect",
+ "size",
+ "vector2d",
+ "vector3d",
+ "vector4d",
+ "quaternion",
+ "matrix4x4",
+ "formatDate",
+ "formatDateTime",
+ "formatTime",
+ "resolvedUrl"};
+
+ const bool whiteListedFunction = translationFunctions.contains(name)
+ || whiteListedFunctions.contains(name)
+ || colorFunctions.contains(name) || qtFunction.contains(name);
- const bool whiteListedFunction = translationFunctions.contains(name) || whiteListedFunctions.contains(name) || colorFunctions.contains(name) || qtFunction.contains(name);
// We allow the Math. functions
const bool isMathFunction = namespaceName == "Math";
diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp
index 5054ce5703..ed1c506df7 100644
--- a/src/libs/qmljs/qmljslink.cpp
+++ b/src/libs/qmljs/qmljslink.cpp
@@ -523,8 +523,8 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath, true);
if (!subImportFound && errorLoc.isValid()) {
- import->valid = false;
if (!(optional || (toImport.flags & QmlDirParser::Import::Optional))) {
+ import->valid = false;
error(doc,
errorLoc,
Tr::tr("Implicit import '%1' of QML module '%2' not found.\n\n"
diff --git a/src/libs/qmljs/qmljsscopebuilder.cpp b/src/libs/qmljs/qmljsscopebuilder.cpp
index e1f38f3013..9e277e6328 100644
--- a/src/libs/qmljs/qmljsscopebuilder.cpp
+++ b/src/libs/qmljs/qmljsscopebuilder.cpp
@@ -157,6 +157,7 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
if ((qmlMetaObject->className() == "ListElement"
|| qmlMetaObject->className() == "Connections")
&& (qmlMetaObject->moduleName() == "Qt" || qmlMetaObject->moduleName() == "QtQml"
+ || qmlMetaObject->moduleName() == "QtQml.Base"
|| qmlMetaObject->moduleName() == "QtQuick")) {
qmlScopeObjects.clear();
break;
diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp
index 73ab49f4d1..1465aab5aa 100644
--- a/src/libs/qmljs/qmljsscopechain.cpp
+++ b/src/libs/qmljs/qmljsscopechain.cpp
@@ -11,6 +11,8 @@
using namespace QmlJS;
+bool ScopeChain::s_setSkipmakeComponentChain = false;
+
/*!
\class QmlJS::ScopeChain
\brief The ScopeChain class describes the scopes used for global lookup in
@@ -210,6 +212,11 @@ QList<const ObjectValue *> ScopeChain::all() const
return m_all;
}
+void ScopeChain::setSkipmakeComponentChain(bool b)
+{
+ s_setSkipmakeComponentChain = b;
+}
+
static void collectScopes(const QmlComponentChain *chain, QList<const ObjectValue *> *target)
{
for (const QmlComponentChain *parent : chain->instantiatingComponents())
@@ -351,6 +358,9 @@ void ScopeChain::makeComponentChain(
const Snapshot &snapshot,
QHash<const Document *, QmlComponentChain *> *components)
{
+ if (s_setSkipmakeComponentChain)
+ return;
+
Document::Ptr doc = target->document();
if (!doc->qmlProgram())
return;
diff --git a/src/libs/qmljs/qmljsscopechain.h b/src/libs/qmljs/qmljsscopechain.h
index f798821388..52e7c95131 100644
--- a/src/libs/qmljs/qmljsscopechain.h
+++ b/src/libs/qmljs/qmljsscopechain.h
@@ -77,6 +77,8 @@ public:
QList<const ObjectValue *> all() const;
+ static void setSkipmakeComponentChain(bool b);
+
private:
void update() const;
void initializeRootScope();
@@ -97,6 +99,8 @@ private:
mutable bool m_modified;
mutable QList<const ObjectValue *> m_all;
+
+ static bool s_setSkipmakeComponentChain;
};
} // namespace QmlJS
diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt
index 6f5b165af1..7f33b18921 100644
--- a/src/libs/sqlite/CMakeLists.txt
+++ b/src/libs/sqlite/CMakeLists.txt
@@ -32,7 +32,9 @@ add_qtc_library(Sqlite
sqlitedatabaseinterface.h
sqliteexception.cpp sqliteexception.h
sqliteglobal.cpp sqliteglobal.h
+ sqlitefunctionregistry.cpp sqlitefunctionregistry.h
sqliteindex.h
+ sqliteprogresshandler.h
sqlitereadstatement.h
sqlitereadwritestatement.h
sqlitesessionchangeset.cpp sqlitesessionchangeset.h
diff --git a/src/libs/sqlite/constraints.h b/src/libs/sqlite/constraints.h
index 575c1e6c82..c934c1f830 100644
--- a/src/libs/sqlite/constraints.h
+++ b/src/libs/sqlite/constraints.h
@@ -4,8 +4,8 @@
#pragma once
#include "sqliteglobal.h"
+#include "sqlitevalue.h"
-#include <sqlitevalue.h>
#include <utils/smallstring.h>
#include <variant>
diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp
index 9bdc9ceec6..91b417bea1 100644
--- a/src/libs/sqlite/sqlitebasestatement.cpp
+++ b/src/libs/sqlite/sqlitebasestatement.cpp
@@ -7,7 +7,7 @@
#include "sqlitedatabasebackend.h"
#include "sqliteexception.h"
-#include "sqlite.h"
+#include <sqlite.h>
#include <condition_variable>
#include <mutex>
@@ -27,17 +27,11 @@ extern "C" int sqlite3_carray_bind(
namespace Sqlite {
BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database)
- : m_compiledStatement(nullptr, deleteCompiledStatement)
- , m_database(database)
+ : m_database(database)
{
prepare(sqlStatement);
}
-void BaseStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement)
-{
- sqlite3_finalize(compiledStatement);
-}
-
class UnlockNotification
{
public:
@@ -79,7 +73,7 @@ void BaseStatement::waitForUnlockNotify() const
&unlockNotification);
if (resultCode == SQLITE_LOCKED)
- throw DeadLock("SqliteStatement::waitForUnlockNotify: database is in a dead lock!");
+ throw DeadLock();
unlockNotification.wait();
}
@@ -107,7 +101,7 @@ bool BaseStatement::next() const
else if (resultCode == SQLITE_DONE)
return false;
- checkForStepError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::step() const
@@ -119,7 +113,7 @@ void BaseStatement::bindNull(int index)
{
int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, NullValue)
@@ -131,21 +125,21 @@ void BaseStatement::bind(int index, int value)
{
int resultCode = sqlite3_bind_int(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, long long value)
{
int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, double value)
{
int resultCode = sqlite3_bind_double(m_compiledStatement.get(), index, value);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, void *pointer)
@@ -156,7 +150,7 @@ void BaseStatement::bind(int index, void *pointer)
"carray",
nullptr);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, Utils::span<const int> values)
@@ -168,7 +162,7 @@ void BaseStatement::bind(int index, Utils::span<const int> values)
CARRAY_INT32,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, Utils::span<const long long> values)
@@ -180,7 +174,7 @@ void BaseStatement::bind(int index, Utils::span<const long long> values)
CARRAY_INT64,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, Utils::span<const double> values)
@@ -192,7 +186,7 @@ void BaseStatement::bind(int index, Utils::span<const double> values)
CARRAY_DOUBLE,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, Utils::span<const char *> values)
@@ -204,7 +198,7 @@ void BaseStatement::bind(int index, Utils::span<const char *> values)
CARRAY_TEXT,
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, Utils::SmallStringView text)
@@ -215,7 +209,7 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
int(text.size()),
SQLITE_STATIC);
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, BlobView blobView)
@@ -233,7 +227,7 @@ void BaseStatement::bind(int index, BlobView blobView)
}
if (resultCode != SQLITE_OK)
- checkForBindingError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void BaseStatement::bind(int index, const Value &value)
@@ -298,7 +292,7 @@ void BaseStatement::prepare(Utils::SmallStringView sqlStatement)
if (resultCode != SQLITE_OK)
- checkForPrepareError(resultCode);
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
sqlite3 *BaseStatement::sqliteDatabaseHandle() const
@@ -306,197 +300,16 @@ sqlite3 *BaseStatement::sqliteDatabaseHandle() const
return m_database.backend().sqliteDatabaseHandle();
}
-void BaseStatement::checkForStepError(int resultCode) const
-{
- switch (resultCode) {
- case SQLITE_BUSY_RECOVERY:
- case SQLITE_BUSY_SNAPSHOT:
- case SQLITE_BUSY_TIMEOUT:
- case SQLITE_BUSY:
- throwStatementIsBusy("SqliteStatement::stepStatement: database engine was unable to "
- "acquire the database locks!");
- case SQLITE_ERROR_MISSING_COLLSEQ:
- case SQLITE_ERROR_RETRY:
- case SQLITE_ERROR_SNAPSHOT:
- case SQLITE_ERROR:
- throwStatementHasError("SqliteStatement::stepStatement: run-time error (such as a "
- "constraint violation) has occurred!");
- case SQLITE_MISUSE:
- throwStatementIsMisused("SqliteStatement::stepStatement: was called inappropriately!");
- case SQLITE_CONSTRAINT_CHECK:
- case SQLITE_CONSTRAINT_COMMITHOOK:
- case SQLITE_CONSTRAINT_DATATYPE:
- case SQLITE_CONSTRAINT_FOREIGNKEY:
- case SQLITE_CONSTRAINT_FUNCTION:
- case SQLITE_CONSTRAINT_NOTNULL:
- case SQLITE_CONSTRAINT_PINNED:
- case SQLITE_CONSTRAINT_PRIMARYKEY:
- case SQLITE_CONSTRAINT_ROWID:
- case SQLITE_CONSTRAINT_TRIGGER:
- case SQLITE_CONSTRAINT_UNIQUE:
- case SQLITE_CONSTRAINT_VTAB:
- case SQLITE_CONSTRAINT:
- throwConstraintPreventsModification(
- "SqliteStatement::stepStatement: contraint prevent insert or update!");
- case SQLITE_TOOBIG:
- throwTooBig("SqliteStatement::stepStatement: Some is to bigger than SQLITE_MAX_LENGTH.");
- case SQLITE_SCHEMA:
- throwSchemaChangeError("SqliteStatement::stepStatement: Schema changed but the statement "
- "cannot be recompiled.");
- case SQLITE_READONLY_CANTINIT:
- case SQLITE_READONLY_CANTLOCK:
- case SQLITE_READONLY_DBMOVED:
- case SQLITE_READONLY_DIRECTORY:
- case SQLITE_READONLY_RECOVERY:
- case SQLITE_READONLY_ROLLBACK:
- case SQLITE_READONLY:
- throwCannotWriteToReadOnlyConnection(
- "SqliteStatement::stepStatement: Cannot write to read only connection");
- case SQLITE_PROTOCOL:
- throwProtocolError(
- "SqliteStatement::stepStatement: Something strang with the file locking happened.");
- case SQLITE_NOMEM:
- throw std::bad_alloc();
- case SQLITE_NOLFS:
- throwDatabaseExceedsMaximumFileSize(
- "SqliteStatement::stepStatement: Database exceeds maximum file size.");
- case SQLITE_MISMATCH:
- throwDataTypeMismatch(
- "SqliteStatement::stepStatement: Most probably you used not an integer for a rowid.");
- case SQLITE_LOCKED_SHAREDCACHE:
- case SQLITE_LOCKED_VTAB:
- case SQLITE_LOCKED:
- throwConnectionIsLocked("SqliteStatement::stepStatement: Database connection is locked.");
- case SQLITE_IOERR_AUTH:
- case SQLITE_IOERR_BEGIN_ATOMIC:
- case SQLITE_IOERR_BLOCKED:
- case SQLITE_IOERR_CHECKRESERVEDLOCK:
- case SQLITE_IOERR_CLOSE:
- case SQLITE_IOERR_COMMIT_ATOMIC:
- case SQLITE_IOERR_CONVPATH:
- case SQLITE_IOERR_DATA:
- case SQLITE_IOERR_DELETE:
- case SQLITE_IOERR_DELETE_NOENT:
- case SQLITE_IOERR_DIR_CLOSE:
- case SQLITE_IOERR_DIR_FSYNC:
- case SQLITE_IOERR_FSTAT:
- case SQLITE_IOERR_FSYNC:
- case SQLITE_IOERR_GETTEMPPATH:
- case SQLITE_IOERR_LOCK:
- case SQLITE_IOERR_MMAP:
- case SQLITE_IOERR_NOMEM:
- case SQLITE_IOERR_RDLOCK:
- case SQLITE_IOERR_READ:
- case SQLITE_IOERR_ROLLBACK_ATOMIC:
- case SQLITE_IOERR_SEEK:
- case SQLITE_IOERR_SHMLOCK:
- case SQLITE_IOERR_SHMMAP:
- case SQLITE_IOERR_SHMOPEN:
- case SQLITE_IOERR_SHMSIZE:
- case SQLITE_IOERR_SHORT_READ:
- case SQLITE_IOERR_TRUNCATE:
- case SQLITE_IOERR_UNLOCK:
- case SQLITE_IOERR_VNODE:
- case SQLITE_IOERR_WRITE:
- case SQLITE_IOERR:
- throwInputOutputError("SqliteStatement::stepStatement: An IO error happened.");
- case SQLITE_INTERRUPT:
- throwExecutionInterrupted("SqliteStatement::stepStatement: Execution was interrupted.");
- case SQLITE_CORRUPT_INDEX:
- case SQLITE_CORRUPT_SEQUENCE:
- case SQLITE_CORRUPT_VTAB:
- case SQLITE_CORRUPT:
- throwDatabaseIsCorrupt("SqliteStatement::stepStatement: Database is corrupt.");
- case SQLITE_CANTOPEN_CONVPATH:
- case SQLITE_CANTOPEN_DIRTYWAL:
- case SQLITE_CANTOPEN_FULLPATH:
- case SQLITE_CANTOPEN_ISDIR:
- case SQLITE_CANTOPEN_NOTEMPDIR:
- case SQLITE_CANTOPEN_SYMLINK:
- case SQLITE_CANTOPEN:
- throwCannotOpen("SqliteStatement::stepStatement: Cannot open database or temporary file.");
- }
-
- throwUnknowError("SqliteStatement::stepStatement: unknown error has happened");
-}
-
-void BaseStatement::checkForPrepareError(int resultCode) const
-{
- switch (resultCode) {
- case SQLITE_BUSY_RECOVERY:
- case SQLITE_BUSY_SNAPSHOT:
- case SQLITE_BUSY_TIMEOUT:
- case SQLITE_BUSY:
- throwStatementIsBusy("SqliteStatement::prepareStatement: database engine was unable to "
- "acquire the database locks!");
- case SQLITE_ERROR_MISSING_COLLSEQ:
- case SQLITE_ERROR_RETRY:
- case SQLITE_ERROR_SNAPSHOT:
- case SQLITE_ERROR:
- throwStatementHasError("SqliteStatement::prepareStatement: run-time error (such as a "
- "constraint violation) has occurred!");
- case SQLITE_MISUSE:
- throwStatementIsMisused("SqliteStatement::prepareStatement: was called inappropriately!");
- case SQLITE_IOERR_AUTH:
- case SQLITE_IOERR_BEGIN_ATOMIC:
- case SQLITE_IOERR_BLOCKED:
- case SQLITE_IOERR_CHECKRESERVEDLOCK:
- case SQLITE_IOERR_CLOSE:
- case SQLITE_IOERR_COMMIT_ATOMIC:
- case SQLITE_IOERR_CONVPATH:
- case SQLITE_IOERR_DATA:
- case SQLITE_IOERR_DELETE:
- case SQLITE_IOERR_DELETE_NOENT:
- case SQLITE_IOERR_DIR_CLOSE:
- case SQLITE_IOERR_DIR_FSYNC:
- case SQLITE_IOERR_FSTAT:
- case SQLITE_IOERR_FSYNC:
- case SQLITE_IOERR_GETTEMPPATH:
- case SQLITE_IOERR_LOCK:
- case SQLITE_IOERR_MMAP:
- case SQLITE_IOERR_NOMEM:
- case SQLITE_IOERR_RDLOCK:
- case SQLITE_IOERR_READ:
- case SQLITE_IOERR_ROLLBACK_ATOMIC:
- case SQLITE_IOERR_SEEK:
- case SQLITE_IOERR_SHMLOCK:
- case SQLITE_IOERR_SHMMAP:
- case SQLITE_IOERR_SHMOPEN:
- case SQLITE_IOERR_SHMSIZE:
- case SQLITE_IOERR_SHORT_READ:
- case SQLITE_IOERR_TRUNCATE:
- case SQLITE_IOERR_UNLOCK:
- case SQLITE_IOERR_VNODE:
- case SQLITE_IOERR_WRITE:
- case SQLITE_IOERR:
- throwInputOutputError("SqliteStatement::prepareStatement: IO error happened!");
- }
-
- throwUnknowError("SqliteStatement::prepareStatement: unknown error has happened");
-}
-
-void BaseStatement::checkForBindingError(int resultCode) const
-{
- switch (resultCode) {
- case SQLITE_TOOBIG: throwBingingTooBig("SqliteStatement::bind: string or blob are over size limits(SQLITE_LIMIT_LENGTH)!");
- case SQLITE_RANGE : throwBindingIndexIsOutOfRange("SqliteStatement::bind: binding index is out of range!");
- case SQLITE_NOMEM: throw std::bad_alloc();
- case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::bind: was called inappropriately!");
- }
-
- throwUnknowError("SqliteStatement::bind: unknown error has happened");
-}
-
void BaseStatement::checkBindingParameterCount(int bindingParameterCount) const
{
if (bindingParameterCount != sqlite3_bind_parameter_count(m_compiledStatement.get()))
- throw WrongBindingParameterCount{"Sqlite: wrong binding parameter count!"};
+ throw WrongBindingParameterCount{};
}
void BaseStatement::checkColumnCount(int columnCount) const
{
if (columnCount != sqlite3_column_count(m_compiledStatement.get()))
- throw WrongColumnCount{"Sqlite: wrong column count!"};
+ throw WrongColumnCount{};
}
bool BaseStatement::isReadOnlyStatement() const
@@ -504,104 +317,6 @@ bool BaseStatement::isReadOnlyStatement() const
return sqlite3_stmt_readonly(m_compiledStatement.get());
}
-void BaseStatement::throwStatementIsBusy(const char *whatHasHappened) const
-{
- throw StatementIsBusy(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwStatementHasError(const char *whatHasHappened) const
-{
- throw StatementHasError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwStatementIsMisused(const char *whatHasHappened) const
-{
- throw StatementIsMisused(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwInputOutputError(const char *whatHasHappened) const
-{
- throw InputOutputError(whatHasHappened);
-}
-
-void BaseStatement::throwConstraintPreventsModification(const char *whatHasHappened) const
-{
- throw ConstraintPreventsModification(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwNoValuesToFetch(const char *whatHasHappened) const
-{
- throw NoValuesToFetch(whatHasHappened);
-}
-
-void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const
-{
- throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwUnknowError(const char *whatHasHappened) const
-{
- if (sqliteDatabaseHandle())
- throw UnknowError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
- else
- throw UnknowError(whatHasHappened);
-}
-
-void BaseStatement::throwBingingTooBig(const char *whatHasHappened) const
-{
- throw BindingTooBig(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle()));
-}
-
-void BaseStatement::throwTooBig(const char *whatHasHappened) const
-{
- throw TooBig{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwSchemaChangeError(const char *whatHasHappened) const
-{
- throw SchemeChangeError{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwCannotWriteToReadOnlyConnection(const char *whatHasHappened) const
-{
- throw CannotWriteToReadOnlyConnection{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwProtocolError(const char *whatHasHappened) const
-{
- throw ProtocolError{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwDatabaseExceedsMaximumFileSize(const char *whatHasHappened) const
-{
- throw DatabaseExceedsMaximumFileSize{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwDataTypeMismatch(const char *whatHasHappened) const
-{
- throw DataTypeMismatch{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwConnectionIsLocked(const char *whatHasHappened) const
-{
- throw ConnectionIsLocked{whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())};
-}
-
-void BaseStatement::throwExecutionInterrupted(const char *whatHasHappened) const
-{
- throw ExecutionInterrupted{whatHasHappened};
-}
-
-void BaseStatement::throwDatabaseIsCorrupt(const char *whatHasHappened) const
-{
- throw DatabaseIsCorrupt{whatHasHappened};
-}
-
-void BaseStatement::throwCannotOpen(const char *whatHasHappened) const
-{
- throw CannotOpen{whatHasHappened};
-}
-
QString BaseStatement::columnName(int column) const
{
return QString::fromUtf8(sqlite3_column_name(m_compiledStatement.get(), column));
@@ -764,4 +479,9 @@ ValueView BaseStatement::fetchValueView(int column) const
return ValueView::create(NullValue{});
}
+void BaseStatement::Deleter::operator()(sqlite3_stmt *statement)
+{
+ sqlite3_finalize(statement);
+}
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h
index 4f6eba16c6..1178b97f3a 100644
--- a/src/libs/sqlite/sqlitebasestatement.h
+++ b/src/libs/sqlite/sqlitebasestatement.h
@@ -50,8 +50,6 @@ public:
BaseStatement(const BaseStatement &) = delete;
BaseStatement &operator=(const BaseStatement &) = delete;
- static void deleteCompiledStatement(sqlite3_stmt *m_compiledStatement);
-
bool next() const;
void step() const;
void reset() const noexcept;
@@ -109,35 +107,11 @@ public:
sqlite3 *sqliteDatabaseHandle() const;
- [[noreturn]] void checkForStepError(int resultCode) const;
- [[noreturn]] void checkForPrepareError(int resultCode) const;
- [[noreturn]] void checkForBindingError(int resultCode) const;
void setIfIsReadyToFetchValues(int resultCode) const;
void checkBindingName(int index) const;
void checkBindingParameterCount(int bindingParameterCount) const;
void checkColumnCount(int columnCount) const;
bool isReadOnlyStatement() const;
- [[noreturn]] void throwStatementIsBusy(const char *whatHasHappened) const;
- [[noreturn]] void throwStatementHasError(const char *whatHasHappened) const;
- [[noreturn]] void throwStatementIsMisused(const char *whatHasHappened) const;
- [[noreturn]] void throwInputOutputError(const char *whatHasHappened) const;
- [[noreturn]] void throwConstraintPreventsModification(const char *whatHasHappened) const;
- [[noreturn]] void throwNoValuesToFetch(const char *whatHasHappened) const;
- [[noreturn]] void throwInvalidColumnFetched(const char *whatHasHappened) const;
- [[noreturn]] void throwBindingIndexIsOutOfRange(const char *whatHasHappened) const;
- [[noreturn]] void throwWrongBingingName(const char *whatHasHappened) const;
- [[noreturn]] void throwUnknowError(const char *whatHasHappened) const;
- [[noreturn]] void throwBingingTooBig(const char *whatHasHappened) const;
- [[noreturn]] void throwTooBig(const char *whatHasHappened) const;
- [[noreturn]] void throwSchemaChangeError(const char *whatHasHappened) const;
- [[noreturn]] void throwCannotWriteToReadOnlyConnection(const char *whatHasHappened) const;
- [[noreturn]] void throwProtocolError(const char *whatHasHappened) const;
- [[noreturn]] void throwDatabaseExceedsMaximumFileSize(const char *whatHasHappened) const;
- [[noreturn]] void throwDataTypeMismatch(const char *whatHasHappened) const;
- [[noreturn]] void throwConnectionIsLocked(const char *whatHasHappened) const;
- [[noreturn]] void throwExecutionInterrupted(const char *whatHasHappened) const;
- [[noreturn]] void throwDatabaseIsCorrupt(const char *whatHasHappened) const;
- [[noreturn]] void throwCannotOpen(const char *whatHasHappened) const;
QString columnName(int column) const;
@@ -147,7 +121,13 @@ protected:
~BaseStatement() = default;
private:
- std::unique_ptr<sqlite3_stmt, void (*)(sqlite3_stmt *)> m_compiledStatement;
+ struct Deleter
+ {
+ SQLITE_EXPORT void operator()(sqlite3_stmt *statement);
+ };
+
+private:
+ std::unique_ptr<sqlite3_stmt, Deleter> m_compiledStatement;
Database &m_database;
};
@@ -417,7 +397,7 @@ private:
: statement(statement)
{
if (statement && !statement->database().isLocked())
- throw DatabaseIsNotLocked{"Database connection is not locked!"};
+ throw DatabaseIsNotLocked{};
}
Resetter(Resetter &) = delete;
diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp
index 940ee7f42a..bb92943776 100644
--- a/src/libs/sqlite/sqlitedatabase.cpp
+++ b/src/libs/sqlite/sqlitedatabase.cpp
@@ -69,7 +69,7 @@ void Database::activateLogging()
void Database::open(LockingMode lockingMode)
{
- m_databaseBackend.open(m_databaseFilePath, m_openMode);
+ m_databaseBackend.open(m_databaseFilePath, m_openMode, m_journalMode);
if (m_busyTimeout > 0ms)
m_databaseBackend.setBusyTimeout(m_busyTimeout);
else
diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h
index c181390ea8..70be8f4305 100644
--- a/src/libs/sqlite/sqlitedatabase.h
+++ b/src/libs/sqlite/sqlitedatabase.h
@@ -90,15 +90,12 @@ public:
return m_databaseBackend.lastInsertedRowId();
}
- void setLastInsertedRowId(int64_t rowId)
- {
- m_databaseBackend.setLastInsertedRowId(rowId);
- }
+ void setLastInsertedRowId(int64_t rowId) { m_databaseBackend.setLastInsertedRowId(rowId); }
- int changesCount()
- {
- return m_databaseBackend.changesCount();
- }
+ int version() const { return m_databaseBackend.version(); }
+ void setVersion(int version) { m_databaseBackend.setVersion(version); }
+
+ int changesCount() { return m_databaseBackend.changesCount(); }
int totalChangesCount() { return m_databaseBackend.totalChangesCount(); }
diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp
index 07c2da46fe..0fd18dfaa1 100644
--- a/src/libs/sqlite/sqlitedatabasebackend.cpp
+++ b/src/libs/sqlite/sqlitedatabasebackend.cpp
@@ -84,19 +84,22 @@ void DatabaseBackend::checkpointFullWalLog()
checkIfLogCouldBeCheckpointed(resultCode);
}
-void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mode)
+void DatabaseBackend::open(Utils::SmallStringView databaseFilePath,
+ OpenMode openMode,
+ JournalMode journalMode)
{
checkCanOpenDatabase(databaseFilePath);
+ sqlite3 *handle = m_databaseHandle.get();
int resultCode = sqlite3_open_v2(std::string(databaseFilePath).c_str(),
- &m_databaseHandle,
- openMode(mode),
+ &handle,
+ createOpenFlags(openMode, journalMode),
nullptr);
+ m_databaseHandle.reset(handle);
checkDatabaseCouldBeOpened(resultCode);
- sqlite3_extended_result_codes(m_databaseHandle, true);
- resultCode = sqlite3_carray_init(m_databaseHandle, nullptr, nullptr);
+ resultCode = sqlite3_carray_init(m_databaseHandle.get(), nullptr, nullptr);
checkCarrayCannotBeIntialized(resultCode);
}
@@ -104,7 +107,7 @@ void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mod
sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const
{
checkDatabaseHandleIsNotNull();
- return m_databaseHandle;
+ return m_databaseHandle.get();
}
void DatabaseBackend::setPragmaValue(Utils::SmallStringView pragmaKey, Utils::SmallStringView newPragmaValue)
@@ -168,6 +171,19 @@ LockingMode DatabaseBackend::lockingMode() const
return pragmaToLockingMode(pragmaValue("main.locking_mode"));
}
+int DatabaseBackend::version() const
+{
+ return toValue<int>("PRAGMA main.user_version");
+}
+
+void DatabaseBackend::setVersion(int version)
+{
+ ReadWriteStatement<>{Utils::SmallString{"PRAGMA main.user_version = "}
+ + Utils::SmallString::number(version),
+ m_database}
+ .execute();
+}
+
int DatabaseBackend::changesCount() const
{
return sqlite3_changes(sqliteDatabaseHandle());
@@ -202,12 +218,11 @@ void DatabaseBackend::close()
{
checkForOpenDatabaseWhichCanBeClosed();
- int resultCode = sqlite3_close(m_databaseHandle);
+ int resultCode = sqlite3_close(m_databaseHandle.get());
checkDatabaseClosing(resultCode);
- m_databaseHandle = nullptr;
-
+ m_databaseHandle.release();
}
bool DatabaseBackend::databaseIsOpen() const
@@ -217,12 +232,7 @@ bool DatabaseBackend::databaseIsOpen() const
void DatabaseBackend::closeWithoutException()
{
- if (m_databaseHandle) {
- int resultCode = sqlite3_close_v2(m_databaseHandle);
- m_databaseHandle = nullptr;
- if (resultCode != SQLITE_OK)
- qWarning() << "SqliteDatabaseBackend::closeWithoutException: Unexpected error at closing the database!";
- }
+ m_databaseHandle.reset();
}
namespace {
@@ -246,15 +256,17 @@ void DatabaseBackend::registerBusyHandler()
void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed()
{
if (m_databaseHandle == nullptr)
- throw DatabaseIsAlreadyClosed("SqliteDatabaseBackend::close: database is not open so it cannot be closed.");
+ throw DatabaseIsAlreadyClosed();
}
void DatabaseBackend::checkDatabaseClosing(int resultCode)
{
switch (resultCode) {
case SQLITE_OK: return;
- case SQLITE_BUSY: throw DatabaseIsBusy("SqliteDatabaseBackend::close: database is busy because of e.g. unfinalized statements and will stay open!");
- default: throwUnknowError("SqliteDatabaseBackend::close: unknown error happens at closing!");
+ case SQLITE_BUSY:
+ throw DatabaseIsBusy();
+ default:
+ throw UnknowError("SqliteDatabaseBackend::close: unknown error happens at closing!");
}
}
@@ -264,8 +276,7 @@ void DatabaseBackend::checkCanOpenDatabase(Utils::SmallStringView databaseFilePa
throw DatabaseFilePathIsEmpty("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because the file path is empty!");
if (!QFileInfo::exists(QFileInfo(QString(databaseFilePath)).path()))
- throw WrongFilePath("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because of wrong file path!",
- Utils::SmallString(databaseFilePath));
+ throw WrongFilePath(Utils::SmallString(databaseFilePath));
if (databaseIsOpen())
throw DatabaseIsAlreadyOpen("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because it is already open!");
@@ -273,81 +284,75 @@ void DatabaseBackend::checkCanOpenDatabase(Utils::SmallStringView databaseFilePa
void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode)
{
- switch (resultCode) {
- case SQLITE_OK:
- return;
- default:
+ if (resultCode != SQLITE_OK) {
+ try {
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
+ } catch (...) {
closeWithoutException();
- throw UnknowError(
- "SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:",
- sqlite3_errmsg(sqliteDatabaseHandle()));
+ throw;
}
+ }
}
void DatabaseBackend::checkCarrayCannotBeIntialized(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwDatabaseIsNotOpen(
- "SqliteDatabaseBackend: database cannot be opened because carray failed!");
+ throw DatabaseIsNotOpen();
}
void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue,
Utils::SmallStringView expectedValue)
{
if (databaseValue != expectedValue)
- throw PragmaValueNotSet("SqliteDatabaseBackend::setPragmaValue: pragma value is not set!");
+ throw PragmaValueNotSet();
}
void DatabaseBackend::checkDatabaseHandleIsNotNull() const
{
if (m_databaseHandle == nullptr)
- throwDatabaseIsNotOpen("SqliteDatabaseBackend: database is not open!");
+ throw DatabaseIsNotOpen();
}
void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwExceptionStatic(
- "SqliteDatabaseBackend::activateMultiThreading: multithreading can't be activated!");
+ throw MultiTheadingCannotBeActivated{};
}
void DatabaseBackend::checkIfLoogingIsActivated(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwExceptionStatic("SqliteDatabaseBackend::activateLogging: logging can't be activated!");
+ throw LoggingCannotBeActivated{};
}
void DatabaseBackend::checkMmapSizeIsSet(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwExceptionStatic(
- "SqliteDatabaseBackend::checkMmapSizeIsSet: mmap size can't be changed!");
+ throw MemoryMappingCannotBeChanged{};
}
void DatabaseBackend::checkInitializeSqliteLibraryWasSuccesful(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwExceptionStatic(
- "SqliteDatabaseBackend::initializeSqliteLibrary: SqliteLibrary cannot initialized!");
+ throw LibraryCannotBeInitialized{};
}
void DatabaseBackend::checkShutdownSqliteLibraryWasSuccesful(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwExceptionStatic(
- "SqliteDatabaseBackend::shutdownSqliteLibrary: SqliteLibrary cannot be shutdowned!");
+ throw LibraryCannotBeShutdown{};
}
void DatabaseBackend::checkIfLogCouldBeCheckpointed(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwException("SqliteDatabaseBackend::checkpointFullWalLog: WAL log could not be checkpointed!");
+ throw LogCannotBeCheckpointed{};
}
void DatabaseBackend::checkIfBusyTimeoutWasSet(int resultCode)
{
if (resultCode != SQLITE_OK)
- throwException("SqliteDatabaseBackend::setBusyTimeout: Busy timeout cannot be set!");
+ throw BusyTimerCannotBeSet{};
}
namespace {
@@ -379,65 +384,57 @@ JournalMode DatabaseBackend::pragmaToJournalMode(Utils::SmallStringView pragma)
int index = indexOfPragma(pragma, journalModeStrings);
if (index < 0)
- throwExceptionStatic("SqliteDatabaseBackend::pragmaToJournalMode: pragma can't be transformed in a journal mode enumeration!");
+ throw PragmaValueCannotBeTransformed{};
return static_cast<JournalMode>(index);
}
-int DatabaseBackend::openMode(OpenMode mode)
+int DatabaseBackend::createOpenFlags(OpenMode openMode, JournalMode journalMode)
{
- int sqliteMode = SQLITE_OPEN_CREATE;
+ int sqliteOpenFlags = SQLITE_OPEN_CREATE | SQLITE_OPEN_EXRESCODE;
+
+ if (journalMode == JournalMode::Memory)
+ sqliteOpenFlags |= SQLITE_OPEN_MEMORY;
- switch (mode) {
- case OpenMode::ReadOnly: sqliteMode |= SQLITE_OPEN_READONLY; break;
- case OpenMode::ReadWrite: sqliteMode |= SQLITE_OPEN_READWRITE; break;
+ switch (openMode) {
+ case OpenMode::ReadOnly:
+ sqliteOpenFlags |= SQLITE_OPEN_READONLY;
+ break;
+ case OpenMode::ReadWrite:
+ sqliteOpenFlags |= SQLITE_OPEN_READWRITE;
+ break;
}
- return sqliteMode;
+ return sqliteOpenFlags;
}
void DatabaseBackend::setBusyTimeout(std::chrono::milliseconds timeout)
{
- sqlite3_busy_timeout(m_databaseHandle, int(timeout.count()));
+ sqlite3_busy_timeout(m_databaseHandle.get(), int(timeout.count()));
}
void DatabaseBackend::walCheckpointFull()
{
- int resultCode = sqlite3_wal_checkpoint_v2(m_databaseHandle,
+ int resultCode = sqlite3_wal_checkpoint_v2(m_databaseHandle.get(),
nullptr,
SQLITE_CHECKPOINT_TRUNCATE,
nullptr,
nullptr);
- switch (resultCode) {
- case SQLITE_OK:
- break;
- case SQLITE_BUSY_RECOVERY:
- case SQLITE_BUSY_SNAPSHOT:
- case SQLITE_BUSY_TIMEOUT:
- case SQLITE_BUSY:
- throw DatabaseIsBusy("DatabaseBackend::walCheckpointFull: Operation could not concluded "
- "because database is busy!");
- case SQLITE_ERROR_MISSING_COLLSEQ:
- case SQLITE_ERROR_RETRY:
- case SQLITE_ERROR_SNAPSHOT:
- case SQLITE_ERROR:
- throwException("DatabaseBackend::walCheckpointFull: Error occurred!");
- case SQLITE_MISUSE:
- throwExceptionStatic("DatabaseBackend::walCheckpointFull: Misuse of database!");
- }
+ if (resultCode != SQLITE_OK)
+ Sqlite::throwError(resultCode, sqliteDatabaseHandle());
}
void DatabaseBackend::setUpdateHook(
void *object,
void (*callback)(void *object, int, char const *database, char const *, long long rowId))
{
- sqlite3_update_hook(m_databaseHandle, callback, object);
+ sqlite3_update_hook(m_databaseHandle.get(), callback, object);
}
void DatabaseBackend::resetUpdateHook()
{
- sqlite3_update_hook(m_databaseHandle, nullptr, nullptr);
+ sqlite3_update_hook(m_databaseHandle.get(), nullptr, nullptr);
}
void DatabaseBackend::setBusyHandler(DatabaseBackend::BusyHandler &&busyHandler)
@@ -446,27 +443,34 @@ void DatabaseBackend::setBusyHandler(DatabaseBackend::BusyHandler &&busyHandler)
registerBusyHandler();
}
-void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens)
-{
- throw Exception(whatHasHappens);
-}
+namespace {
-void DatabaseBackend::throwException(const char *whatHasHappens) const
+int progressHandlerCallback(void *userData)
{
- if (m_databaseHandle)
- throw ExceptionWithMessage(whatHasHappens, sqlite3_errmsg(m_databaseHandle));
- else
- throw Exception(whatHasHappens);
+ auto &&progressHandler = *static_cast<DatabaseBackend::ProgressHandler *>(userData);
+
+ return progressHandler() == Progress::Interrupt;
}
-void DatabaseBackend::throwUnknowError(const char *whatHasHappens) const
+} // namespace
+
+void DatabaseBackend::setProgressHandler(int operationCount, ProgressHandler &&progressHandler)
{
- throw UnknowError(whatHasHappens);
+ m_progressHandler = std::move(progressHandler);
+
+ if (m_progressHandler)
+ sqlite3_progress_handler(sqliteDatabaseHandle(),
+ operationCount,
+ &progressHandlerCallback,
+ &m_progressHandler);
+ else {
+ sqlite3_progress_handler(sqliteDatabaseHandle(), 0, nullptr, nullptr);
+ }
}
-void DatabaseBackend::throwDatabaseIsNotOpen(const char *whatHasHappens) const
+void DatabaseBackend::resetProgressHandler()
{
- throw DatabaseIsNotOpen(whatHasHappens);
+ sqlite3_progress_handler(sqliteDatabaseHandle(), 0, nullptr, nullptr);
}
template<typename Type>
@@ -483,4 +487,14 @@ Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) const
}
}
+void DatabaseBackend::Deleter::operator()(sqlite3 *database)
+{
+ if (database) {
+ int resultCode = sqlite3_close_v2(database);
+ if (resultCode != SQLITE_OK)
+ qWarning() << "SqliteDatabaseBackend::closeWithoutException: Unexpected error at "
+ "closing the database!";
+ }
+}
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitedatabasebackend.h b/src/libs/sqlite/sqlitedatabasebackend.h
index 1f602a4ff8..9a1caa92d6 100644
--- a/src/libs/sqlite/sqlitedatabasebackend.h
+++ b/src/libs/sqlite/sqlitedatabasebackend.h
@@ -15,10 +15,13 @@ namespace Sqlite {
class Database;
+enum class Progress { Interrupt, Continue };
+
class SQLITE_EXPORT DatabaseBackend
{
public:
using BusyHandler = std::function<bool(int count)>;
+ using ProgressHandler = std::function<Progress()>;
DatabaseBackend(Database &database);
~DatabaseBackend();
@@ -36,7 +39,7 @@ public:
static void shutdownSqliteLibrary();
void checkpointFullWalLog();
- void open(Utils::SmallStringView databaseFilePath, OpenMode openMode);
+ void open(Utils::SmallStringView databaseFilePath, OpenMode openMode, JournalMode journalMode);
void close();
void closeWithoutException();
@@ -50,6 +53,9 @@ public:
Utils::SmallStringVector columnNames(Utils::SmallStringView tableName);
+ int version() const;
+ void setVersion(int version);
+
int changesCount() const;
int totalChangesCount() const;
@@ -61,7 +67,7 @@ public:
template<typename Type>
Type toValue(Utils::SmallStringView sqlStatement) const;
- static int openMode(OpenMode);
+ static int createOpenFlags(OpenMode openMode, JournalMode journalMode);
void setBusyTimeout(std::chrono::milliseconds timeout);
@@ -73,6 +79,8 @@ public:
void resetUpdateHook();
void setBusyHandler(BusyHandler &&busyHandler);
+ void setProgressHandler(int operationCount, ProgressHandler &&progressHandler);
+ void resetProgressHandler();
void registerBusyHandler();
@@ -100,15 +108,17 @@ protected:
static Utils::SmallStringView journalModeToPragma(JournalMode journalMode);
static JournalMode pragmaToJournalMode(Utils::SmallStringView pragma);
- Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens);
- [[noreturn]] void throwException(const char *whatHasHappens) const;
- [[noreturn]] void throwUnknowError(const char *whatHasHappens) const;
- [[noreturn]] void throwDatabaseIsNotOpen(const char *whatHasHappens) const;
+private:
+ struct Deleter
+ {
+ SQLITE_EXPORT void operator()(sqlite3 *database);
+ };
private:
Database &m_database;
- sqlite3 *m_databaseHandle;
+ std::unique_ptr<sqlite3, Deleter> m_databaseHandle;
BusyHandler m_busyHandler;
+ ProgressHandler m_progressHandler;
};
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqliteexception.cpp b/src/libs/sqlite/sqliteexception.cpp
index 45276dfed5..b5f581ad68 100644
--- a/src/libs/sqlite/sqliteexception.cpp
+++ b/src/libs/sqlite/sqliteexception.cpp
@@ -5,13 +5,836 @@
#include <utils/smallstringio.h>
+#include <sqlite.h>
+
#include <QDebug>
namespace Sqlite {
+const char *Exception::what() const noexcept
+{
+ return "Sqlite::Exception";
+}
+
+const char *ExceptionWithMessage::what() const noexcept
+{
+ return "Sqlite::ExceptionWithMessage";
+}
+
void ExceptionWithMessage::printWarning() const
{
qWarning() << what() << m_sqliteErrorMessage;
}
+const char *StatementIsBusy::what() const noexcept
+{
+ return "Sqlite::StatementIsBusy";
+}
+
+const char *DatabaseIsBusy::what() const noexcept
+{
+ return "Sqlite::DatabaseIsBusy";
+}
+
+const char *StatementHasError::what() const noexcept
+{
+ return "Sqlite::StatementHasError";
+}
+
+const char *StatementIsMisused::what() const noexcept
+{
+ return "Sqlite::StatementIsMisused";
+}
+
+const char *InputOutputError::what() const noexcept
+{
+ return "Sqlite::InputOutputError";
+}
+
+const char *ConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::ConstraintPreventsModification";
+}
+
+const char *NoValuesToFetch::what() const noexcept
+{
+ return "Sqlite::NoValuesToFetch";
+}
+
+const char *BindingIndexIsOutOfRange::what() const noexcept
+{
+ return "Sqlite::BindingIndexIsOutOfRange";
+}
+
+const char *WrongBindingName::what() const noexcept
+{
+ return "Sqlite::WrongBindingName";
+}
+
+const char *DatabaseIsNotOpen::what() const noexcept
+{
+ return "Sqlite::DatabaseIsNotOpen";
+}
+
+const char *DatabaseCannotBeOpened::what() const noexcept
+{
+ return "Sqlite::DatabaseCannotBeOpened";
+}
+
+const char *DatabaseFilePathIsEmpty::what() const noexcept
+{
+ return "Sqlite::DatabaseFilePathIsEmpty";
+}
+
+const char *DatabaseIsAlreadyOpen::what() const noexcept
+{
+ return "Sqlite::DatabaseIsAlreadyOpen";
+}
+
+const char *DatabaseCannotBeClosed::what() const noexcept
+{
+ return "Sqlite::DatabaseCannotBeClosed";
+}
+
+const char *DatabaseIsAlreadyClosed::what() const noexcept
+{
+ return "Sqlite::DatabaseIsAlreadyClosed";
+}
+
+const char *WrongFilePath::what() const noexcept
+{
+ return "Sqlite::WrongFilePath";
+}
+
+const char *PragmaValueNotSet::what() const noexcept
+{
+ return "Sqlite::PragmaValueNotSet";
+}
+
+const char *NotReadOnlySqlStatement::what() const noexcept
+{
+ return "Sqlite::NotReadOnlySqlStatement";
+}
+
+const char *NotWriteSqlStatement::what() const noexcept
+{
+ return "Sqlite::NotWriteSqlStatement";
+}
+
+const char *DeadLock::what() const noexcept
+{
+ return "Sqlite::DeadLock";
+}
+
+const char *UnknowError::what() const noexcept
+{
+ return "Sqlite::UnknowError";
+}
+
+const char *BindingTooBig::what() const noexcept
+{
+ return "Sqlite::BindingTooBig";
+}
+
+const char *TooBig::what() const noexcept
+{
+ return "Sqlite::TooBig";
+}
+
+const char *CannotConvert::what() const noexcept
+{
+ return "Sqlite::CannotConvert";
+}
+
+const char *ForeignKeyColumnIsNotUnique::what() const noexcept
+{
+ return "Sqlite::ForeignKeyColumnIsNotUnique";
+}
+
+const char *CannotApplyChangeSet::what() const noexcept
+{
+ return "Sqlite::CannotApplyChangeSet";
+}
+
+const char *ChangeSetIsMisused::what() const noexcept
+{
+ return "Sqlite::ChangeSetIsMisused";
+}
+
+const char *SchemeChangeError::what() const noexcept
+{
+ return "Sqlite::SchemeChangeError";
+}
+
+const char *CannotWriteToReadOnlyConnection::what() const noexcept
+{
+ return "Sqlite::CannotWriteToReadOnlyConnection";
+}
+
+const char *ProtocolError::what() const noexcept
+{
+ return "Sqlite::ProtocolError";
+}
+
+const char *DatabaseExceedsMaximumFileSize::what() const noexcept
+{
+ return "Sqlite::DatabaseExceedsMaximumFileSize";
+}
+
+const char *DataTypeMismatch::what() const noexcept
+{
+ return "Sqlite::DataTypeMismatch";
+}
+
+const char *ConnectionIsLocked::what() const noexcept
+{
+ return "Sqlite::ConnectionIsLocked";
+}
+
+const char *ExecutionInterrupted::what() const noexcept
+{
+ return "Sqlite::ExecutionInterrupted";
+}
+
+const char *DatabaseIsCorrupt::what() const noexcept
+{
+ return "Sqlite::DatabaseIsCorrupt";
+}
+
+const char *CannotOpen::what() const noexcept
+{
+ return "Sqlite::CannotOpen";
+}
+
+const char *CannotCreateChangeSetIterator::what() const noexcept
+{
+ return "Sqlite::CannotCreateChangeSetIterator";
+}
+
+const char *CannotGetChangeSetOperation::what() const noexcept
+{
+ return "Sqlite::CannotGetChangeSetOperation";
+}
+
+const char *ChangeSetTupleIsOutOfRange::what() const noexcept
+{
+ return "Sqlite::ChangeSetTupleIsOutOfRange";
+}
+
+const char *ChangeSetTupleIsMisused::what() const noexcept
+{
+ return "Sqlite::ChangeSetTupleIsMisused";
+}
+
+const char *UnknownError::what() const noexcept
+{
+ return "Sqlite::UnknownError";
+}
+
+const char *DatabaseIsNotLocked::what() const noexcept
+{
+ return "Sqlite::DatabaseIsNotLocked";
+}
+
+const char *WrongBindingParameterCount::what() const noexcept
+{
+ return "Sqlite::WrongBindingParameterCount";
+}
+
+const char *WrongColumnCount::what() const noexcept
+{
+ return "Sqlite::WrongColumnCount";
+}
+
+const char *IndexHasNoTableName::what() const noexcept
+{
+ return "Sqlite::IndexHasNoTableName";
+}
+
+const char *IndexHasNoColumns::what() const noexcept
+{
+ return "Sqlite::IndexHasNoColumns";
+}
+
+const char *MultiTheadingCannotBeActivated::what() const noexcept
+{
+ return "Sqlite::MultiTheadingCannotBeActivated";
+}
+
+const char *LoggingCannotBeActivated::what() const noexcept
+{
+ return "Sqlite::LoggingCannotBeActivated";
+}
+
+const char *MemoryMappingCannotBeChanged::what() const noexcept
+{
+ return "Sqlite::MemoryMappingCannotBeChanged";
+}
+
+const char *LibraryCannotBeInitialized::what() const noexcept
+{
+ return "Sqlite::LibraryCannotBeInitialized";
+}
+
+const char *LibraryCannotBeShutdown::what() const noexcept
+{
+ return "Sqlite::LibraryCannotBeShutdown";
+}
+
+const char *LogCannotBeCheckpointed::what() const noexcept
+{
+ return "Sqlite::LogCannotBeCheckPointed";
+}
+
+const char *BusyTimerCannotBeSet::what() const noexcept
+{
+ return "Sqlite::BusyTimerCannotBeSet";
+}
+
+const char *PragmaValueCannotBeTransformed::what() const noexcept
+{
+ return "Sqlite::PragmaValueCannotBeTransformed";
+}
+
+const char *CheckpointIsMisused::what() const noexcept
+{
+ return "Sqlite::CheckpointIsMisused";
+}
+
+const char *InputOutputCannotAuthenticate::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotAuthenticate";
+}
+
+const char *InputOutputCannotBeginAtomic::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotBeginAtomic";
+}
+
+const char *InputOutputBlocked::what() const noexcept
+{
+ return "Sqlite::InputOutputBlocked";
+}
+
+const char *InputOutputCannotCommitAtomic::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotCommitAtomic";
+}
+
+const char *InputOutputCannotRollbackAtomic::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotRollbackAtomic";
+}
+
+const char *InputOutputDataError::what() const noexcept
+{
+ return "Sqlite::InputOutputDataError";
+}
+
+const char *InputOutputFileSystemIsCorrupt::what() const noexcept
+{
+ return "Sqlite::InputOutputFileSystemIsCorrupt";
+}
+
+const char *InputOutputVNodeError::what() const noexcept
+{
+ return "Sqlite::InputOutputVNodeError";
+}
+
+const char *InputOutputConvPathFailed::what() const noexcept
+{
+ return "Sqlite::InputOutputConvPathFailed";
+}
+
+const char *InputOutputCannotGetTemporaryPath::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotGetTemporaryPath";
+}
+
+const char *InputOutputCannotMemoryMap::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotMemoryMap";
+}
+
+const char *InputOutputCannotDeleteNonExistingFile::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotDeleteNonExistingFile";
+}
+
+const char *InputOutputCannotSeek::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotSeek";
+}
+
+const char *InputOutputCannotMapSharedMemory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotMapSharedMemory";
+}
+
+const char *InputOutputCannotLockSharedMemory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotLockSharedMemory";
+}
+
+const char *InputOutputCannotEnlargeSharedMemory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotEnlargeSharedMemory";
+}
+
+const char *InputOutputCannotOpenSharedMemory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotOpenSharedMemory";
+}
+
+const char *InputOutputCannotCloseDirectory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotCloseDirectory";
+}
+
+const char *InputOutputCannotClose::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotClose";
+}
+
+const char *InputOutputCannotLock::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotLock";
+}
+
+const char *InputOutputCannotCheckReservedLock::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotCheckReservedLock";
+}
+
+const char *InputOutputCannotAccess::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotAccess";
+}
+
+const char *InputOutputNoMemory::what() const noexcept
+{
+ return "Sqlite::InputOutputNoMemory";
+}
+
+const char *InputOutputCannotDelete::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotDelete";
+}
+
+const char *InputOutputCannotReadLock::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotReadLock";
+}
+
+const char *InputOutputCannotUnlock::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotUnlock";
+}
+
+const char *InputOutputCannotFsStat::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotFsStat";
+}
+
+const char *InputOutputCannotTruncate::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotTruncate";
+}
+
+const char *InputOutputCannotSynchronizeDirectory::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotFsyncDirectory";
+}
+
+const char *InputOutputCannotSynchronizeFile::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotSynchronizeFile";
+}
+
+const char *InputOutputCannotWrite::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotWrite";
+}
+
+const char *InputOutputCannotShortRead::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotShortRead";
+}
+
+const char *InputOutputCannotRead::what() const noexcept
+{
+ return "Sqlite::InputOutputCannotRead";
+}
+
+const char *StatementIsBusyRecovering::what() const noexcept
+{
+ return "Sqlite::StatementIsBusyRecovering";
+}
+
+const char *StatementIsBusySnapshot::what() const noexcept
+{
+ return "Sqlite::StatementIsBusySnapshot";
+}
+
+const char *StatementIsBusyTimeout::what() const noexcept
+{
+ return "Sqlite::StatementIsBusyTimeout";
+}
+
+const char *DatabaseIsBusyRecovering::what() const noexcept
+{
+ return "Sqlite::DatabaseIsBusyRecovering";
+}
+
+const char *DatabaseIsBusySnapshot::what() const noexcept
+{
+ return "Sqlite::DatabaseIsBusySnapshot";
+}
+
+const char *DatabaseIsBusyTimeout::what() const noexcept
+{
+ return "Sqlite::DatabaseIsBusyTimeout";
+}
+
+const char *StatementHasErrorMissingCollatingSequence::what() const noexcept
+{
+ return "Sqlite::StatementHasErrorMissingCollatingSequence";
+}
+
+const char *StatementHasErrorRetry::what() const noexcept
+{
+ return "Sqlite::StatementHasErrorRetry";
+}
+
+const char *StatementHasErrorSnapshot::what() const noexcept
+{
+ return "Sqlite::StatementHasErrorSnapshot";
+}
+
+const char *CheckConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::CheckConstraintPreventsModification";
+}
+
+const char *CommitHookConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::CommitHookConstraintPreventsModification";
+}
+
+const char *DataTypeConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::DataTypeConstraintPreventsModification";
+}
+
+const char *ForeignKeyConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::ForeignKeyConstraintPreventsModification";
+}
+
+const char *FunctionConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::FunctionConstraintPreventsModification";
+}
+
+const char *NotNullConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::NotNullConstraintPreventsModification";
+}
+
+const char *PinnedConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::PinnedConstraintPreventsModification";
+}
+
+const char *PrimaryKeyConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::PrimaryKeyConstraintPreventsModification";
+}
+
+const char *RowIdConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::RowIdConstraintPreventsModification";
+}
+
+const char *TriggerConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::TriggerConstraintPreventsModification";
+}
+
+const char *UniqueConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::UniqueConstraintPreventsModification";
+}
+
+const char *VirtualTableConstraintPreventsModification::what() const noexcept
+{
+ return "Sqlite::VirtualTableConstraintPreventsModification";
+}
+
+const char *DatabaseHasCorruptIndex::what() const noexcept
+{
+ return "Sqlite::DatabaseHasCorruptIndex";
+}
+
+const char *DatabaseHasCorruptSequence::what() const noexcept
+{
+ return "Sqlite::DatabaseHasCorruptSequence";
+}
+
+const char *DatabaseHasCorruptVirtualTable::what() const noexcept
+{
+ return "Sqlite::DatabaseHasCorruptVirtualTable";
+}
+
+const char *CannotInitializeReadOnlyConnection::what() const noexcept
+{
+ return "Sqlite::CannotInitializeReadOnlyConnection";
+}
+
+const char *CannotLockReadOnlyConnection::what() const noexcept
+{
+ return "Sqlite::CannotLockReadOnlyConnection";
+}
+
+const char *CannotWriteToMovedDatabase::what() const noexcept
+{
+ return "Sqlite::CannotWriteToMovedDatabase";
+}
+
+const char *CannotCreateLogInReadonlyDirectory::what() const noexcept
+{
+ return "Sqlite::CannotCreateLogInReadonlyDirectory";
+}
+
+const char *DatabaseNeedsToBeRecovered::what() const noexcept
+{
+ return "Sqlite::DatabaseNeedsToBeRecovered";
+}
+
+const char *CannotRollbackToReadOnlyConnection::what() const noexcept
+{
+ return "Sqlite::CannotRollbackToReadOnlyConnection";
+}
+
+const char *ConnectionsSharedCacheIsLocked::what() const noexcept
+{
+ return "Sqlite::ConnectionsSharedCacheIsLocked";
+}
+
+const char *ConnectionsVirtualTableIsLocked::what() const noexcept
+{
+ return "Sqlite::ConnectionsVirtualTableIsLocked";
+}
+
+const char *CannotOpenConvPath::what() const noexcept
+{
+ return "Sqlite::CannotOpenConvPath";
+}
+
+const char *CannotOpenDirtyWal::what() const noexcept
+{
+ return "Sqlite::CannotOpenDirtyWal";
+}
+
+const char *CannotCovertToFullPath::what() const noexcept
+{
+ return "Sqlite::CannotCovertToFullPath";
+}
+
+const char *CannotOpenDirectoryPath::what() const noexcept
+{
+ return "Sqlite::CannotOpenDirectoryPath";
+}
+
+const char *CannotOpenNoTempDir::what() const noexcept
+{
+ return "Sqlite::CannotOpenNoTempDir";
+}
+
+const char *CannotOpenSynbolicLink::what() const noexcept
+{
+ return "Sqlite::CannotOpenSynbolicLink";
+}
+
+void throwError(int resultCode, sqlite3 *sqliteHandle)
+{
+ switch (resultCode) {
+ case SQLITE_BUSY_RECOVERY:
+ throw StatementIsBusyRecovering(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_BUSY_SNAPSHOT:
+ throw StatementIsBusySnapshot(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_BUSY_TIMEOUT:
+ throw StatementIsBusyTimeout(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_BUSY:
+ throw StatementIsBusy(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_ERROR_MISSING_COLLSEQ:
+ throw StatementHasErrorMissingCollatingSequence(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_ERROR_RETRY:
+ throw StatementHasErrorRetry(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_ERROR_SNAPSHOT:
+ throw StatementHasErrorSnapshot(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_ERROR:
+ throw StatementHasError(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_MISUSE:
+ throw StatementIsMisused(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_CHECK:
+ throw CheckConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_COMMITHOOK:
+ throw CommitHookConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_DATATYPE:
+ throw DataTypeConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_FOREIGNKEY:
+ throw ForeignKeyConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_FUNCTION:
+ throw FunctionConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_NOTNULL:
+ throw NotNullConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_PINNED:
+ throw PinnedConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_PRIMARYKEY:
+ throw PrimaryKeyConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_ROWID:
+ throw RowIdConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_TRIGGER:
+ throw TriggerConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_UNIQUE:
+ throw UniqueConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT_VTAB:
+ throw VirtualTableConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_CONSTRAINT:
+ throw ConstraintPreventsModification(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_TOOBIG:
+ throw TooBig(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_SCHEMA:
+ throw SchemeChangeError(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_CANTINIT:
+ throw CannotInitializeReadOnlyConnection(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_CANTLOCK:
+ throw CannotLockReadOnlyConnection(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_DBMOVED:
+ throw CannotWriteToMovedDatabase(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_DIRECTORY:
+ throw CannotCreateLogInReadonlyDirectory(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_RECOVERY:
+ throw DatabaseNeedsToBeRecovered(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY_ROLLBACK:
+ throw CannotRollbackToReadOnlyConnection(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_READONLY:
+ throw CannotWriteToReadOnlyConnection(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_PROTOCOL:
+ throw ProtocolError(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_NOMEM:
+ throw std::bad_alloc();
+ case SQLITE_NOLFS:
+ throw DatabaseExceedsMaximumFileSize(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_MISMATCH:
+ throw DataTypeMismatch(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_LOCKED_SHAREDCACHE:
+ throw ConnectionsSharedCacheIsLocked(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_LOCKED_VTAB:
+ throw ConnectionsVirtualTableIsLocked(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_LOCKED:
+ throw ConnectionIsLocked(sqlite3_errmsg(sqliteHandle));
+ case SQLITE_IOERR_READ:
+ throw InputOutputCannotRead();
+ case SQLITE_IOERR_SHORT_READ:
+ throw InputOutputCannotShortRead();
+ case SQLITE_IOERR_WRITE:
+ throw InputOutputCannotWrite();
+ case SQLITE_IOERR_FSYNC:
+ throw InputOutputCannotSynchronizeFile();
+ case SQLITE_IOERR_DIR_FSYNC:
+ throw InputOutputCannotSynchronizeDirectory();
+ case SQLITE_IOERR_TRUNCATE:
+ throw InputOutputCannotTruncate();
+ case SQLITE_IOERR_FSTAT:
+ throw InputOutputCannotFsStat();
+ case SQLITE_IOERR_UNLOCK:
+ throw InputOutputCannotUnlock();
+ case SQLITE_IOERR_RDLOCK:
+ throw InputOutputCannotReadLock();
+ case SQLITE_IOERR_DELETE:
+ throw InputOutputCannotDelete();
+ case SQLITE_IOERR_BLOCKED:
+ throw InputOutputBlocked();
+ case SQLITE_IOERR_NOMEM:
+ throw InputOutputNoMemory();
+ case SQLITE_IOERR_ACCESS:
+ throw InputOutputCannotAccess();
+ case SQLITE_IOERR_CHECKRESERVEDLOCK:
+ throw InputOutputCannotCheckReservedLock();
+ case SQLITE_IOERR_LOCK:
+ throw InputOutputCannotLock();
+ case SQLITE_IOERR_CLOSE:
+ throw InputOutputCannotClose();
+ case SQLITE_IOERR_DIR_CLOSE:
+ throw InputOutputCannotCloseDirectory();
+ case SQLITE_IOERR_SHMOPEN:
+ throw InputOutputCannotOpenSharedMemory();
+ case SQLITE_IOERR_SHMSIZE:
+ throw InputOutputCannotEnlargeSharedMemory();
+ case SQLITE_IOERR_SHMLOCK:
+ throw InputOutputCannotLockSharedMemory();
+ case SQLITE_IOERR_SHMMAP:
+ throw InputOutputCannotMapSharedMemory();
+ case SQLITE_IOERR_SEEK:
+ throw InputOutputCannotSeek();
+ case SQLITE_IOERR_DELETE_NOENT:
+ throw InputOutputCannotDeleteNonExistingFile();
+ case SQLITE_IOERR_MMAP:
+ throw InputOutputCannotMemoryMap();
+ case SQLITE_IOERR_GETTEMPPATH:
+ throw InputOutputCannotGetTemporaryPath();
+ case SQLITE_IOERR_CONVPATH:
+ throw InputOutputConvPathFailed();
+ case SQLITE_IOERR_VNODE:
+ throw InputOutputVNodeError();
+ case SQLITE_IOERR_AUTH:
+ throw InputOutputCannotAuthenticate();
+ case SQLITE_IOERR_BEGIN_ATOMIC:
+ throw InputOutputCannotBeginAtomic();
+ case SQLITE_IOERR_COMMIT_ATOMIC:
+ throw InputOutputCannotCommitAtomic();
+ case SQLITE_IOERR_ROLLBACK_ATOMIC:
+ throw InputOutputCannotRollbackAtomic();
+ case SQLITE_IOERR_DATA:
+ throw InputOutputDataError();
+ case SQLITE_IOERR_CORRUPTFS:
+ throw InputOutputFileSystemIsCorrupt();
+ case SQLITE_IOERR:
+ throw InputOutputError();
+ case SQLITE_INTERRUPT:
+ throw ExecutionInterrupted();
+ case SQLITE_CORRUPT_INDEX:
+ throw DatabaseHasCorruptIndex();
+ case SQLITE_CORRUPT_SEQUENCE:
+ throw DatabaseHasCorruptSequence();
+ case SQLITE_CORRUPT_VTAB:
+ throw DatabaseHasCorruptVirtualTable();
+ case SQLITE_CORRUPT:
+ throw DatabaseIsCorrupt();
+ case SQLITE_CANTOPEN_CONVPATH:
+ throw CannotOpenConvPath();
+ case SQLITE_CANTOPEN_DIRTYWAL:
+ throw CannotOpenDirtyWal();
+ case SQLITE_CANTOPEN_FULLPATH:
+ throw CannotCovertToFullPath();
+ case SQLITE_CANTOPEN_ISDIR:
+ throw CannotOpenDirectoryPath();
+ case SQLITE_CANTOPEN_NOTEMPDIR:
+ throw CannotOpenNoTempDir();
+ case SQLITE_CANTOPEN_SYMLINK:
+ throw CannotOpenSynbolicLink();
+ case SQLITE_CANTOPEN:
+ throw CannotOpen();
+ case SQLITE_RANGE:
+ throw BindingIndexIsOutOfRange(sqlite3_errmsg(sqliteHandle));
+ }
+
+ if (sqliteHandle)
+ throw UnknowError(sqlite3_errmsg(sqliteHandle));
+ else
+ throw UnknowError();
+}
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h
index 319b22f3ff..d030f65280 100644
--- a/src/libs/sqlite/sqliteexception.h
+++ b/src/libs/sqlite/sqliteexception.h
@@ -10,298 +10,880 @@
#include <exception>
#include <iostream>
+extern "C" {
+struct sqlite3;
+}
+
namespace Sqlite {
class SQLITE_EXPORT Exception : public std::exception
{
public:
- Exception(const char *whatErrorHasHappen)
- : m_whatErrorHasHappen(whatErrorHasHappen)
- {}
-
- const char *what() const noexcept override { return m_whatErrorHasHappen; }
-
-private:
- const char *m_whatErrorHasHappen;
+ Exception() = default;
+ const char *what() const noexcept override;
};
class SQLITE_EXPORT ExceptionWithMessage : public Exception
{
public:
- ExceptionWithMessage(const char *whatErrorHasHappen,
- Utils::SmallString &&sqliteErrorMessage = Utils::SmallString{})
- : Exception{whatErrorHasHappen}
- , m_sqliteErrorMessage(std::move(sqliteErrorMessage))
+ ExceptionWithMessage(Utils::SmallString &&sqliteErrorMessage = Utils::SmallString{})
+ : m_sqliteErrorMessage(std::move(sqliteErrorMessage))
{}
+ const char *what() const noexcept override;
void printWarning() const;
private:
Utils::SmallString m_sqliteErrorMessage;
};
-class StatementIsBusy : public ExceptionWithMessage
+class SQLITE_EXPORT StatementIsBusy : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementIsBusyRecovering : public StatementIsBusy
+{
+public:
+ using StatementIsBusy::StatementIsBusy;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementIsBusySnapshot : public StatementIsBusy
+{
+public:
+ using StatementIsBusy::StatementIsBusy;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementIsBusyTimeout : public StatementIsBusy
+{
+public:
+ using StatementIsBusy::StatementIsBusy;
+ const char *what() const noexcept override;
};
-class DatabaseIsBusy : public Exception
+class SQLITE_EXPORT DatabaseIsBusy : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DatabaseIsBusyRecovering : public DatabaseIsBusy
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DatabaseIsBusySnapshot : public DatabaseIsBusy
+{
+public:
+ const char *what() const noexcept override;
};
-class StatementHasError : public ExceptionWithMessage
+class SQLITE_EXPORT DatabaseIsBusyTimeout : public DatabaseIsBusy
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementHasError : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementHasErrorMissingCollatingSequence : public StatementHasError
+{
+public:
+ using StatementHasError::StatementHasError;
+ const char *what() const noexcept override;
};
-class StatementIsMisused : public ExceptionWithMessage
+class SQLITE_EXPORT StatementHasErrorRetry : public StatementHasError
+{
+public:
+ using StatementHasError::StatementHasError;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementHasErrorSnapshot : public StatementHasError
+{
+public:
+ using StatementHasError::StatementHasError;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT StatementIsMisused : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class InputOutputError : public Exception
+class SQLITE_EXPORT InputOutputError : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotAuthenticate : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotBeginAtomic : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotCommitAtomic : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotRollbackAtomic : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputDataError : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputBlocked : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputFileSystemIsCorrupt : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputVNodeError : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputConvPathFailed : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotGetTemporaryPath : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotMemoryMap : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotDeleteNonExistingFile : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotSeek : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotMapSharedMemory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotLockSharedMemory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotEnlargeSharedMemory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotOpenSharedMemory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotCloseDirectory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotClose : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotLock : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotCheckReservedLock : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotAccess : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputNoMemory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotDelete : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotReadLock : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotUnlock : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotFsStat : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotTruncate : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotSynchronizeDirectory : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotSynchronizeFile : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotWrite : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
};
-class ConstraintPreventsModification : public ExceptionWithMessage
+class SQLITE_EXPORT InputOutputCannotShortRead : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT InputOutputCannotRead : public InputOutputError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ConstraintPreventsModification : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class NoValuesToFetch : public Exception
+class SQLITE_EXPORT CheckConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CommitHookConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DataTypeConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ForeignKeyConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT FunctionConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT NotNullConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT PinnedConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT PrimaryKeyConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT RowIdConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT TriggerConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT UniqueConstraintPreventsModification : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT VirtualTableConstraintPreventsModification
+ : public ConstraintPreventsModification
+{
+public:
+ using ConstraintPreventsModification::ConstraintPreventsModification;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT NoValuesToFetch : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class BindingIndexIsOutOfRange : public ExceptionWithMessage
+class SQLITE_EXPORT BindingIndexIsOutOfRange : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class WrongBindingName : public Exception
+class SQLITE_EXPORT WrongBindingName : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class DatabaseIsNotOpen : public Exception
+class SQLITE_EXPORT DatabaseIsNotOpen : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class DatabaseCannotBeOpened : public ExceptionWithMessage
+class SQLITE_EXPORT DatabaseCannotBeOpened : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
+class SQLITE_EXPORT DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened
{
public:
using DatabaseCannotBeOpened::DatabaseCannotBeOpened;
+ const char *what() const noexcept override;
};
-class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
+class SQLITE_EXPORT DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened
{
public:
using DatabaseCannotBeOpened::DatabaseCannotBeOpened;
+ const char *what() const noexcept override;
};
-class DatabaseCannotBeClosed : public Exception
+class SQLITE_EXPORT DatabaseCannotBeClosed : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
+class SQLITE_EXPORT DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed
{
public:
using DatabaseCannotBeClosed::DatabaseCannotBeClosed;
+ const char *what() const noexcept override;
};
-class WrongFilePath : public ExceptionWithMessage
+class SQLITE_EXPORT WrongFilePath : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT PragmaValueNotSet : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
};
-class PragmaValueNotSet : public Exception
+class SQLITE_EXPORT PragmaValueCannotBeTransformed : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class NotReadOnlySqlStatement : public Exception
+class SQLITE_EXPORT NotReadOnlySqlStatement : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class NotWriteSqlStatement : public Exception
+class SQLITE_EXPORT NotWriteSqlStatement : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class DeadLock : public Exception
+class SQLITE_EXPORT DeadLock : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class UnknowError : public ExceptionWithMessage
+class SQLITE_EXPORT UnknowError : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class BindingTooBig : public ExceptionWithMessage
+class SQLITE_EXPORT BindingTooBig : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class TooBig : public ExceptionWithMessage
+class SQLITE_EXPORT TooBig : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class CannotConvert : public Exception
+class SQLITE_EXPORT CannotConvert : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class ForeignKeyColumnIsNotUnique : public Exception
+class SQLITE_EXPORT ForeignKeyColumnIsNotUnique : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class CannotApplyChangeSet : public Exception
+class SQLITE_EXPORT CannotApplyChangeSet : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class ChangeSetIsMisused : public Exception
+class SQLITE_EXPORT ChangeSetIsMisused : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class SchemeChangeError : public ExceptionWithMessage
+class SQLITE_EXPORT SchemeChangeError : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class CannotWriteToReadOnlyConnection : public ExceptionWithMessage
+class SQLITE_EXPORT CannotWriteToReadOnlyConnection : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class ProtocolError : public ExceptionWithMessage
+class SQLITE_EXPORT CannotInitializeReadOnlyConnection : public CannotWriteToReadOnlyConnection
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
};
-class DatabaseExceedsMaximumFileSize : public ExceptionWithMessage
+class SQLITE_EXPORT CannotLockReadOnlyConnection : public CannotWriteToReadOnlyConnection
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
};
-class DataTypeMismatch : public ExceptionWithMessage
+class SQLITE_EXPORT CannotWriteToMovedDatabase : public CannotWriteToReadOnlyConnection
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotCreateLogInReadonlyDirectory : public CannotWriteToReadOnlyConnection
+{
+public:
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DatabaseNeedsToBeRecovered : public CannotWriteToReadOnlyConnection
+{
+public:
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
};
-class ConnectionIsLocked : public ExceptionWithMessage
+class SQLITE_EXPORT CannotRollbackToReadOnlyConnection : public CannotWriteToReadOnlyConnection
+{
+public:
+ using CannotWriteToReadOnlyConnection::CannotWriteToReadOnlyConnection;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ProtocolError : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class ExecutionInterrupted : public ExceptionWithMessage
+class SQLITE_EXPORT DatabaseExceedsMaximumFileSize : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class DatabaseIsCorrupt : public ExceptionWithMessage
+class SQLITE_EXPORT DataTypeMismatch : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
};
-class CannotOpen : public ExceptionWithMessage
+class SQLITE_EXPORT ConnectionIsLocked : public ExceptionWithMessage
{
public:
using ExceptionWithMessage::ExceptionWithMessage;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ConnectionsSharedCacheIsLocked : public ConnectionIsLocked
+{
+public:
+ using ConnectionIsLocked::ConnectionIsLocked;
+ const char *what() const noexcept override;
};
-class CannotCreateChangeSetIterator : public Exception
+class SQLITE_EXPORT ConnectionsVirtualTableIsLocked : public ConnectionIsLocked
+{
+public:
+ using ConnectionIsLocked::ConnectionIsLocked;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ExecutionInterrupted : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class CannotGetChangeSetOperation : public Exception
+class SQLITE_EXPORT DatabaseIsCorrupt : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DatabaseHasCorruptIndex : public DatabaseIsCorrupt
+{
+public:
+ using DatabaseIsCorrupt::DatabaseIsCorrupt;
+ const char *what() const noexcept override;
};
-class ChangeSetTupleIsOutOfRange : public Exception
+class SQLITE_EXPORT DatabaseHasCorruptSequence : public DatabaseIsCorrupt
+{
+public:
+ using DatabaseIsCorrupt::DatabaseIsCorrupt;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT DatabaseHasCorruptVirtualTable : public DatabaseIsCorrupt
+{
+public:
+ using DatabaseIsCorrupt::DatabaseIsCorrupt;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotOpen : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class ChangeSetTupleIsMisused : public Exception
+class SQLITE_EXPORT CannotOpenConvPath : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotOpenDirtyWal : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotCovertToFullPath : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotOpenDirectoryPath : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotOpenNoTempDir : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotOpenSynbolicLink : public CannotOpen
+{
+public:
+ using CannotOpen::CannotOpen;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotCreateChangeSetIterator : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CannotGetChangeSetOperation : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ChangeSetTupleIsOutOfRange : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT ChangeSetTupleIsMisused : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class UnknownError : public Exception
+class SQLITE_EXPORT UnknownError : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class DatabaseIsNotLocked : public Exception
+class SQLITE_EXPORT DatabaseIsNotLocked : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class WrongBindingParameterCount : public Exception
+class SQLITE_EXPORT WrongBindingParameterCount : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
-class WrongColumnCount : public Exception
+class SQLITE_EXPORT WrongColumnCount : public Exception
{
public:
using Exception::Exception;
+ const char *what() const noexcept override;
};
+class SQLITE_EXPORT IndexHasNoTableName : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT IndexHasNoColumns : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT MultiTheadingCannotBeActivated : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT LoggingCannotBeActivated : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT MemoryMappingCannotBeChanged : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT LibraryCannotBeInitialized : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT LibraryCannotBeShutdown : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT LogCannotBeCheckpointed : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT BusyTimerCannotBeSet : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+class SQLITE_EXPORT CheckpointIsMisused : public Exception
+{
+public:
+ using Exception::Exception;
+ const char *what() const noexcept override;
+};
+
+[[noreturn]] SQLITE_EXPORT void throwError(int resultCode, sqlite3 *sqliteHandle);
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitefunctionregistry.cpp b/src/libs/sqlite/sqlitefunctionregistry.cpp
new file mode 100644
index 0000000000..c2cb6a696a
--- /dev/null
+++ b/src/libs/sqlite/sqlitefunctionregistry.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "sqlitefunctionregistry.h"
+
+#include "sqlite.h"
+
+#include <QFileInfo>
+
+namespace {
+extern "C" {
+void pathExists(sqlite3_context *context, int, sqlite3_value **arguments)
+{
+ auto argument = arguments[0];
+
+ auto errorText = "pathExists only accepts text";
+
+ if (sqlite3_value_type(argument) != SQLITE_TEXT) {
+ sqlite3_result_error(context, errorText, int(std::char_traits<char>::length(errorText)));
+ return;
+ }
+
+ auto size = sqlite3_value_bytes(argument);
+
+ auto content = QByteArrayView{sqlite3_value_text(argument), size};
+
+ QString path = QString::fromUtf8(content);
+
+ bool exists = QFileInfo::exists(path);
+
+ sqlite3_result_int(context, exists);
+}
+}
+} // namespace
+
+namespace Sqlite::FunctionRegistry {
+
+void registerPathExists(Sqlite::Database &database)
+{
+ sqlite3_create_function(database.backend().sqliteDatabaseHandle(),
+ "pathExists",
+ 1,
+ SQLITE_UTF8 | SQLITE_INNOCUOUS,
+ nullptr,
+ pathExists,
+ nullptr,
+ nullptr);
+}
+
+} // namespace Sqlite::FunctionRegistry
diff --git a/src/libs/sqlite/sqlitefunctionregistry.h b/src/libs/sqlite/sqlitefunctionregistry.h
new file mode 100644
index 0000000000..6c66070122
--- /dev/null
+++ b/src/libs/sqlite/sqlitefunctionregistry.h
@@ -0,0 +1,12 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "sqlitedatabase.h"
+
+namespace Sqlite::FunctionRegistry {
+
+SQLITE_EXPORT void registerPathExists(Sqlite::Database &database);
+
+} // namespace Sqlite::FunctionRegistry
diff --git a/src/libs/sqlite/sqliteindex.h b/src/libs/sqlite/sqliteindex.h
index 488aa8770a..f320fcd599 100644
--- a/src/libs/sqlite/sqliteindex.h
+++ b/src/libs/sqlite/sqliteindex.h
@@ -55,13 +55,13 @@ public:
void checkTableName() const
{
if (m_tableName.isEmpty())
- throw Exception("SqliteIndex has not table name!");
+ throw IndexHasNoTableName();
}
void checkColumns() const
{
if (m_columnNames.empty())
- throw Exception("SqliteIndex has no columns!");
+ throw IndexHasNoColumns();
}
private:
diff --git a/src/libs/sqlite/sqliteprogresshandler.h b/src/libs/sqlite/sqliteprogresshandler.h
new file mode 100644
index 0000000000..c4c670c71a
--- /dev/null
+++ b/src/libs/sqlite/sqliteprogresshandler.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "sqlitedatabase.h"
+
+namespace Sqlite {
+
+class ProgressHandler
+{
+public:
+ template<typename Callable>
+ ProgressHandler(Callable &&callable, int operationCount, Database &database)
+ : m_database{database}
+ {
+ std::unique_lock<TransactionInterface> locker{m_database};
+ m_database.backend().setProgressHandler(operationCount, std::forward<Callable>(callable));
+ }
+
+ ~ProgressHandler()
+ {
+ std::unique_lock<TransactionInterface> locker{m_database};
+ m_database.backend().resetProgressHandler();
+ }
+
+private:
+ Database &m_database;
+};
+
+} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h
index 5db0cead8d..ac764166ce 100644
--- a/src/libs/sqlite/sqlitereadstatement.h
+++ b/src/libs/sqlite/sqlitereadstatement.h
@@ -91,8 +91,7 @@ protected:
void checkIsReadOnlyStatement()
{
if (!Base::isReadOnlyStatement())
- throw NotReadOnlySqlStatement(
- "SqliteStatement::SqliteReadStatement: is not read only statement!");
+ throw NotReadOnlySqlStatement();
}
};
diff --git a/src/libs/sqlite/sqlitesessionchangeset.cpp b/src/libs/sqlite/sqlitesessionchangeset.cpp
index 6a568bd48f..a7b4b0b1c4 100644
--- a/src/libs/sqlite/sqlitesessionchangeset.cpp
+++ b/src/libs/sqlite/sqlitesessionchangeset.cpp
@@ -26,15 +26,13 @@ void checkSessionChangeSetCreation(int resultCode)
void checkIteratorCreation(int resultCode)
{
if (resultCode != SQLITE_OK)
- throw Sqlite::CannotCreateChangeSetIterator{
- "SessionChangeSet: Cannot create iterator from blob."};
+ throw Sqlite::CannotCreateChangeSetIterator{};
}
void checkIteratorOperation(int resultCode)
{
if (resultCode != SQLITE_OK)
- throw Sqlite::CannotGetChangeSetOperation{
- "SessionChangeSet: Cannot create iterator from blob."};
+ throw Sqlite::CannotGetChangeSetOperation{};
}
void checkChangeSetValue(int resultCode)
@@ -43,14 +41,12 @@ void checkChangeSetValue(int resultCode)
case SQLITE_OK:
return;
case SQLITE_RANGE:
- throw Sqlite::ChangeSetTupleIsOutOfRange{
- "SessionChangeSet: You tried to access a non existing column."};
+ throw Sqlite::ChangeSetTupleIsOutOfRange{};
case SQLITE_MISUSE:
- throw Sqlite::ChangeSetIsMisused{
- "SessionChangeSet: Some misuse happened as you tried to access."};
+ throw Sqlite::ChangeSetIsMisused{};
}
- throw Sqlite::UnknownError{"SessionChangeSet: Some unknown error happened."};
+ throw Sqlite::UnknownError{};
}
ValueView convertSqliteValue(sqlite3_value *value)
diff --git a/src/libs/sqlite/sqlitesessions.cpp b/src/libs/sqlite/sqlitesessions.cpp
index c4aa4c868b..0dea908e5f 100644
--- a/src/libs/sqlite/sqlitesessions.cpp
+++ b/src/libs/sqlite/sqlitesessions.cpp
@@ -20,13 +20,13 @@ void checkResultCode(int resultCode)
case SQLITE_NOMEM:
throw std::bad_alloc();
case SQLITE_SCHEMA:
- throw CannotApplyChangeSet("Cannot apply change set!");
+ throw CannotApplyChangeSet();
case SQLITE_MISUSE:
- throw ChangeSetIsMisused("Change set is misused!");
+ throw ChangeSetIsMisused();
}
if (resultCode != SQLITE_OK)
- throw UnknowError("Unknow exception");
+ throw UnknowError();
}
int xConflict(void *, int conflict, sqlite3_changeset_iter *)
@@ -173,4 +173,9 @@ SessionChangeSets Sessions::changeSets() const
return selectChangeSets.values<SessionChangeSet>(1024);
}
+void Sessions::Deleter::operator()(sqlite3_session *session)
+{
+ sqlite3session_delete(session);
+}
+
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitesessions.h b/src/libs/sqlite/sqlitesessions.h
index 33ce267a97..151155d417 100644
--- a/src/libs/sqlite/sqlitesessions.h
+++ b/src/libs/sqlite/sqlitesessions.h
@@ -8,10 +8,6 @@
#include "sqlitesessionchangeset.h"
#include "sqlitewritestatement.h"
-extern "C" {
-void sqlite3session_delete(sqlite3_session *pSession);
-};
-
namespace Sqlite {
namespace Internal {
@@ -44,7 +40,6 @@ public:
{"INSERT INTO ", sessionsTableName, "(changeset) VALUES(?)"}),
database}
, databaseName(databaseName)
- , session{nullptr, sqlite3session_delete}
{}
~Sessions();
@@ -64,12 +59,17 @@ public:
private:
void attachTables(const Utils::SmallStringVector &tables);
+ struct Deleter
+ {
+ SQLITE_EXPORT void operator()(sqlite3_session *statement);
+ };
+
public:
Database &database;
WriteStatement<1> insertSession;
Utils::SmallString databaseName;
Utils::SmallStringVector tableNames;
- std::unique_ptr<sqlite3_session, decltype(&sqlite3session_delete)> session;
+ std::unique_ptr<sqlite3_session, Deleter> session;
};
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitetable.h b/src/libs/sqlite/sqlitetable.h
index e0c829420d..38355c7f67 100644
--- a/src/libs/sqlite/sqlitetable.h
+++ b/src/libs/sqlite/sqlitetable.h
@@ -88,7 +88,7 @@ public:
Constraints &&constraints = {})
{
if (!constainsUniqueIndex(referencedColumn.constraints))
- throw ForeignKeyColumnIsNotUnique("Foreign column key must be unique!");
+ throw ForeignKeyColumnIsNotUnique();
constraints.emplace_back(ForeignKey{referencedColumn.tableName,
referencedColumn.name,
diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h
index 2bbaa55985..49ab76d89f 100644
--- a/src/libs/sqlite/sqlitevalue.h
+++ b/src/libs/sqlite/sqlitevalue.h
@@ -347,7 +347,7 @@ private:
case QVariant::ByteArray:
return VariantType{Blob{value.toByteArray()}};
default:
- throw CannotConvert("Cannot convert this QVariant to a ValueBase");
+ throw CannotConvert();
}
}
@@ -365,7 +365,7 @@ private:
case ValueType::Blob:
return VariantType{view.toBlobView()};
default:
- throw CannotConvert("Cannot convert this QVariant to a ValueBase");
+ throw CannotConvert();
}
}
};
diff --git a/src/libs/sqlite/sqlitewritestatement.h b/src/libs/sqlite/sqlitewritestatement.h
index d1b2e2f74e..1abf76bd42 100644
--- a/src/libs/sqlite/sqlitewritestatement.h
+++ b/src/libs/sqlite/sqlitewritestatement.h
@@ -28,8 +28,7 @@ protected:
void checkIsWritableStatement()
{
if (Base::isReadOnlyStatement())
- throw NotWriteSqlStatement(
- "SqliteStatement::SqliteWriteStatement: is not a writable statement!");
+ throw NotWriteSqlStatement();
}
};
diff --git a/src/libs/sqlite/sqlstatementbuilder.cpp b/src/libs/sqlite/sqlstatementbuilder.cpp
index a5b6ba766e..e756b460c7 100644
--- a/src/libs/sqlite/sqlstatementbuilder.cpp
+++ b/src/libs/sqlite/sqlstatementbuilder.cpp
@@ -197,30 +197,37 @@ void SqlStatementBuilder::checkIfPlaceHolderExists(Utils::SmallStringView name)
void SqlStatementBuilder::checkIfNoPlaceHoldersAynmoreExists() const
{
if (m_sqlStatement.contains('$'))
- throwException("SqlStatementBuilder::bind: there are still placeholder in the sql statement!", m_sqlTemplate.constData());
+ throwException(
+ "SqlStatementBuilder::bind: there are still placeholder in the sql statement!",
+ m_sqlTemplate);
}
void SqlStatementBuilder::checkBindingTextIsNotEmpty(Utils::SmallStringView text) const
{
if (text.isEmpty())
- throwException("SqlStatementBuilder::bind: binding text it empty!", m_sqlTemplate.constData());
+ throwException("SqlStatementBuilder::bind: binding text it empty!", m_sqlTemplate);
}
void SqlStatementBuilder::checkBindingTextVectorIsNotEmpty(const Utils::SmallStringVector &textVector) const
{
if (textVector.empty())
- throwException("SqlStatementBuilder::bind: binding text vector it empty!", m_sqlTemplate.constData());
+ throwException("SqlStatementBuilder::bind: binding text vector it empty!", m_sqlTemplate);
}
void SqlStatementBuilder::checkBindingIntegerVectorIsNotEmpty(const std::vector<int> &integerVector) const
{
if (integerVector.empty())
- throwException("SqlStatementBuilder::bind: binding integer vector it empty!", m_sqlTemplate.constData());
+ throwException("SqlStatementBuilder::bind: binding integer vector it empty!", m_sqlTemplate);
}
-void SqlStatementBuilder::throwException(const char *whatHasHappened, const char *errorMessage)
+void SqlStatementBuilder::throwException(const char *whatHasHappened, Utils::SmallString sqlTemplate)
{
- throw SqlStatementBuilderException(whatHasHappened, errorMessage);
+ throw SqlStatementBuilderException(whatHasHappened, std::move(sqlTemplate));
+}
+
+const char *SqlStatementBuilderException::what() const noexcept
+{
+ return m_whatHasHappened;
}
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlstatementbuilder.h b/src/libs/sqlite/sqlstatementbuilder.h
index 743f743b6b..3e202572c9 100644
--- a/src/libs/sqlite/sqlstatementbuilder.h
+++ b/src/libs/sqlite/sqlstatementbuilder.h
@@ -52,7 +52,8 @@ protected:
void checkBindingTextVectorIsNotEmpty(const Utils::SmallStringVector &textVector) const;
void checkBindingIntegerVectorIsNotEmpty(const std::vector<int> &integerVector) const;
- Q_NORETURN static void throwException(const char *whatHasHappened, const char *errorMessage);
+ Q_NORETURN static void throwException(const char *whatHasHappened,
+ Utils::SmallString sqlTemplate);
private:
Utils::BasicSmallString<510> m_sqlTemplate;
diff --git a/src/libs/sqlite/sqlstatementbuilderexception.h b/src/libs/sqlite/sqlstatementbuilderexception.h
index 380b683e8d..e5ad187f4b 100644
--- a/src/libs/sqlite/sqlstatementbuilderexception.h
+++ b/src/libs/sqlite/sqlstatementbuilderexception.h
@@ -10,7 +10,16 @@ namespace Sqlite {
class SQLITE_EXPORT SqlStatementBuilderException : public ExceptionWithMessage
{
public:
- using ExceptionWithMessage::ExceptionWithMessage;
+ SqlStatementBuilderException(const char *whatHasHappened,
+ Utils::SmallString &&sqliteErrorMessage)
+ : ExceptionWithMessage(std::move(sqliteErrorMessage))
+ , m_whatHasHappened{whatHasHappened}
+ {}
+
+ const char *what() const noexcept override;
+
+private:
+ const char *m_whatHasHappened;
};
} // namespace Sqlite
diff --git a/src/libs/sqlite/tableconstraints.h b/src/libs/sqlite/tableconstraints.h
index 6522a5ea28..f02ca9282f 100644
--- a/src/libs/sqlite/tableconstraints.h
+++ b/src/libs/sqlite/tableconstraints.h
@@ -4,8 +4,8 @@
#pragma once
#include "sqliteglobal.h"
+#include "sqlitevalue.h"
-#include <sqlitevalue.h>
#include <utils/smallstringvector.h>
#include <variant>
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index 6b2e835d19..69fa8769a9 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -140,6 +140,7 @@ add_qtc_library(Utils
qtcolorbutton.cpp qtcolorbutton.h
qtcprocess.cpp qtcprocess.h
qtcsettings.cpp qtcsettings.h
+ ranges.h
reloadpromptutils.cpp reloadpromptutils.h
removefiledialog.cpp removefiledialog.h
runextensions.cpp runextensions.h
@@ -165,6 +166,7 @@ add_qtc_library(Utils
statuslabel.cpp statuslabel.h
stringtable.cpp stringtable.h
stringutils.cpp stringutils.h
+ styleanimator.cpp styleanimator.h
styledbar.cpp styledbar.h
stylehelper.cpp stylehelper.h
tasktree.cpp tasktree.h
diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp
index 9b97fb6b02..3af026d9ba 100644
--- a/src/libs/utils/filepath.cpp
+++ b/src/libs/utils/filepath.cpp
@@ -1320,13 +1320,13 @@ FilePath FilePath::relativeChildPath(const FilePath &parent) const
}
/*!
- Returns the relativePath of FilePath from a given \a anchor.
+ Returns the relative path of FilePath from a given \a anchor.
Both, FilePath and anchor may be files or directories.
Example usage:
\code
FilePath filePath("/foo/b/ar/file.txt");
- FilePath relativePath = filePath.relativePath("/foo/c");
+ FilePath relativePath = filePath.relativePathFrom("/foo/c");
qDebug() << relativePath
\endcode
diff --git a/src/libs/utils/filesystemwatcher.cpp b/src/libs/utils/filesystemwatcher.cpp
index 3f427cce2e..e0cef5aed9 100644
--- a/src/libs/utils/filesystemwatcher.cpp
+++ b/src/libs/utils/filesystemwatcher.cpp
@@ -5,13 +5,12 @@
#include "algorithm.h"
#include "globalfilechangeblocker.h"
+#include "filepath.h"
-#include <QDebug>
#include <QDir>
#include <QFileSystemWatcher>
#include <QDateTime>
-
-enum { debug = 0 };
+#include <QLoggingCategory>
// Returns upper limit of file handles that can be opened by this process at
// once. (which is limited on MacOS, exceeding it will probably result in
@@ -63,6 +62,8 @@ static inline quint64 getFileLimit()
namespace Utils {
+static Q_LOGGING_CATEGORY(fileSystemWatcherLog, "qtc.utils.filesystemwatcher", QtInfoMsg)
+
// Centralized file watcher static data per integer id.
class FileSystemWatcherStaticData
{
@@ -216,8 +217,8 @@ void FileSystemWatcher::init()
if (!d->m_staticData->m_watcher) {
d->m_staticData->m_watcher = new QFileSystemWatcher();
- if (debug)
- qDebug() << this << "Created watcher for id " << d->m_id;
+ qCDebug(fileSystemWatcherLog)
+ << this << "Created watcher for id" << d->m_id;
}
++(d->m_staticData->m_objectCount);
connect(d->m_staticData->m_watcher, &QFileSystemWatcher::fileChanged,
@@ -235,8 +236,8 @@ FileSystemWatcher::~FileSystemWatcher()
d->m_staticData->m_watcher = nullptr;
d->m_staticData->m_fileCount.clear();
d->m_staticData->m_directoryCount.clear();
- if (debug)
- qDebug() << this << "Deleted watcher" << d->m_id;
+ qCDebug(fileSystemWatcherLog)
+ << this << "Deleted watcher" << d->m_id;
}
delete d;
}
@@ -253,10 +254,10 @@ void FileSystemWatcher::addFile(const QString &file, WatchMode wm)
void FileSystemWatcher::addFiles(const QStringList &files, WatchMode wm)
{
- if (debug)
- qDebug() << this << d->m_id << "addFiles mode=" << wm << files
- << " limit currently: " << (d->m_files.size() + d->m_directories.size())
- << " of " << d->m_staticData->maxFileOpen;
+ qCDebug(fileSystemWatcherLog)
+ << this << d->m_id << "addFiles mode" << wm << files
+ << "limit currently:" << (d->m_files.size() + d->m_directories.size())
+ << "of" << d->m_staticData->maxFileOpen;
QStringList toAdd;
for (const QString &file : files) {
if (watchesFile(file)) {
@@ -297,8 +298,8 @@ void FileSystemWatcher::removeFile(const QString &file)
void FileSystemWatcher::removeFiles(const QStringList &files)
{
- if (debug)
- qDebug() << this << d->m_id << "removeFiles " << files;
+ qCDebug(fileSystemWatcherLog)
+ << this << d->m_id << "removeFiles" << files;
QStringList toRemove;
for (const QString &file : files) {
const auto it = d->m_files.constFind(file);
@@ -351,10 +352,10 @@ void FileSystemWatcher::addDirectory(const QString &directory, WatchMode wm)
void FileSystemWatcher::addDirectories(const QStringList &directories, WatchMode wm)
{
- if (debug)
- qDebug() << this << d->m_id << "addDirectories mode " << wm << directories
- << " limit currently: " << (d->m_files.size() + d->m_directories.size())
- << " of " << d->m_staticData->maxFileOpen;
+ qCDebug(fileSystemWatcherLog)
+ << this << d->m_id << "addDirectories mode" << wm << directories
+ << "limit currently:" << (d->m_files.size() + d->m_directories.size())
+ << "of" << d->m_staticData->maxFileOpen;
QStringList toAdd;
for (const QString &directory : directories) {
if (watchesDirectory(directory)) {
@@ -388,8 +389,8 @@ void FileSystemWatcher::removeDirectory(const FilePath &file)
void FileSystemWatcher::removeDirectories(const QStringList &directories)
{
- if (debug)
- qDebug() << this << d->m_id << "removeDirectories" << directories;
+ qCDebug(fileSystemWatcherLog)
+ << this << d->m_id << "removeDirectories" << directories;
QStringList toRemove;
for (const QString &directory : directories) {
@@ -419,10 +420,10 @@ void FileSystemWatcher::slotFileChanged(const QString &path)
{
const auto it = d->m_files.find(path);
if (it != d->m_files.end() && it.value().trigger(path)) {
- if (debug)
- qDebug() << this << "triggers on file " << path
- << it.value().watchMode
- << it.value().modifiedTime.toString(Qt::ISODate);
+ qCDebug(fileSystemWatcherLog)
+ << this << "triggers on file" << it.key()
+ << it.value().watchMode
+ << it.value().modifiedTime.toString(Qt::ISODate);
d->fileChanged(path);
}
}
@@ -431,17 +432,17 @@ void FileSystemWatcher::slotDirectoryChanged(const QString &path)
{
const auto it = d->m_directories.find(path);
if (it != d->m_directories.end() && it.value().trigger(path)) {
- if (debug)
- qDebug() << this << "triggers on dir " << path
- << it.value().watchMode
- << it.value().modifiedTime.toString(Qt::ISODate);
+ qCDebug(fileSystemWatcherLog)
+ << this << "triggers on dir" << it.key()
+ << it.value().watchMode
+ << it.value().modifiedTime.toString(Qt::ISODate);
d->directoryChanged(path);
}
QStringList toReadd;
- const QDir dir(path);
- for (const QFileInfo &entry : dir.entryInfoList(QDir::Files)) {
- const QString file = entry.filePath();
+ const auto dir = FilePath::fromString(path);
+ for (const FilePath &entry : dir.dirEntries(QDir::Files)) {
+ const QString file = entry.toString();
if (d->m_files.contains(file))
toReadd.append(file);
}
diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp
index 17a7b1ba29..4ce143b56c 100644
--- a/src/libs/utils/icon.cpp
+++ b/src/libs/utils/icon.cpp
@@ -134,8 +134,8 @@ static QPixmap masksToIcon(const MasksAndColors &masks, const QPixmap &combinedM
Icon::Icon() = default;
-Icon::Icon(std::initializer_list<IconMaskAndColor> args, Icon::IconStyleOptions style)
- : m_iconSourceList(args)
+Icon::Icon(QVector<IconMaskAndColor> args, Icon::IconStyleOptions style)
+ : m_iconSourceList(std::move(args))
, m_style(style)
{
}
diff --git a/src/libs/utils/icon.h b/src/libs/utils/icon.h
index 4121e1e921..c2c5e7a3de 100644
--- a/src/libs/utils/icon.h
+++ b/src/libs/utils/icon.h
@@ -40,7 +40,7 @@ public:
Q_DECLARE_FLAGS(IconStyleOptions, IconStyleOption)
Icon();
- Icon(std::initializer_list<IconMaskAndColor> args, IconStyleOptions style = ToolBarStyle);
+ Icon(QVector<IconMaskAndColor> args, IconStyleOptions style = ToolBarStyle);
Icon(const FilePath &imageFileName);
QIcon icon() const;
diff --git a/src/libs/utils/persistentsettings.cpp b/src/libs/utils/persistentsettings.cpp
index 5d7a35db3a..1db834bff7 100644
--- a/src/libs/utils/persistentsettings.cpp
+++ b/src/libs/utils/persistentsettings.cpp
@@ -336,11 +336,17 @@ bool PersistentSettingsReader::load(const FilePath &fileName)
if (fileName.fileSize() == 0) // skip empty files
return false;
+ m_filePath = fileName.parentDir();
ParseContext ctx;
m_valueMap = ctx.parse(fileName);
return true;
}
+FilePath PersistentSettingsReader::filePath()
+{
+ return m_filePath;
+}
+
/*!
\class Utils::PersistentSettingsWriter
diff --git a/src/libs/utils/persistentsettings.h b/src/libs/utils/persistentsettings.h
index 66a006ab22..7e07f0237c 100644
--- a/src/libs/utils/persistentsettings.h
+++ b/src/libs/utils/persistentsettings.h
@@ -22,9 +22,11 @@ public:
QVariant restoreValue(const QString &variable, const QVariant &defaultValue = QVariant()) const;
QVariantMap restoreValues() const;
bool load(const FilePath &fileName);
+ FilePath filePath();
private:
QMap<QString, QVariant> m_valueMap;
+ FilePath m_filePath;
};
class QTCREATOR_UTILS_EXPORT PersistentSettingsWriter
diff --git a/src/libs/utils/ranges.h b/src/libs/utils/ranges.h
new file mode 100644
index 0000000000..8b574e08d6
--- /dev/null
+++ b/src/libs/utils/ranges.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#if __cplusplus >= 202002L
+#include <ranges>
+
+namespace Utils {
+
+namespace ranges {
+using std::ranges::reverse_view;
+}
+
+namespace views {
+using std::views::reverse;
+}
+
+} // namespace Utils
+#else
+#include <stdexcept>
+
+namespace Utils {
+
+namespace ranges {
+
+template <typename Container>
+class reverse_view
+{
+public:
+ using value_type = typename Container::value_type;
+ using size_type = typename Container::size_type;
+ using Type = value_type;
+ using pointer = Type *;
+ using const_pointer = const Type *;
+ using reference = Type &;
+ using const_reference = const Type &;
+
+ using reverse_iterator = typename Container::iterator;
+ using iterator = std::reverse_iterator<reverse_iterator>;
+
+ using const_reverse_iterator = typename Container::const_iterator;
+ using const_iterator = std::reverse_iterator<const_reverse_iterator>;
+
+ using Iterator = iterator;
+ using ConstIterator = const_iterator;
+
+ reverse_view(const Container &k) : d(&k) {}
+
+ const_reverse_iterator rbegin() const noexcept { return d->begin(); }
+ const_reverse_iterator rend() const noexcept { return d->end(); }
+ const_reverse_iterator crbegin() const noexcept { return d->begin(); }
+ const_reverse_iterator crend() const noexcept { return d->end(); }
+
+ const_iterator begin() const noexcept { return const_iterator(rend()); }
+ const_iterator end() const noexcept { return const_iterator(rbegin()); }
+ const_iterator cbegin() const noexcept { return const_iterator(rend()); }
+ const_iterator cend() const noexcept { return const_iterator(rbegin()); }
+ const_iterator constBegin() const noexcept { return const_iterator(rend()); }
+ const_iterator constEnd() const noexcept { return const_iterator(rbegin()); }
+
+ const_reference front() const noexcept { return *cbegin(); }
+ const_reference back() const noexcept { return *crbegin(); }
+
+ [[nodiscard]] size_type size() const noexcept { return d->size(); }
+ [[nodiscard]] bool empty() const noexcept { return d->size() == 0; }
+ explicit operator bool() const { return d->size(); }
+
+ const_reference operator[](size_type idx) const
+ {
+ if (idx < size())
+ return *(begin() + idx);
+
+ throw std::out_of_range("bad index in reverse side");
+ }
+
+private:
+ const Container *d;
+};
+} // namespace ranges
+
+namespace views {
+
+constexpr struct {} reverse;
+
+template <typename T>
+inline ranges::reverse_view<T> operator|(const T &container, const decltype(reverse)&)
+{
+ return ranges::reverse_view(container);
+}
+
+} // namsepace views
+} // namespace Utils
+
+#endif
diff --git a/src/libs/utils/smallstringlayout.h b/src/libs/utils/smallstringlayout.h
index ae32314edd..6235995d94 100644
--- a/src/libs/utils/smallstringlayout.h
+++ b/src/libs/utils/smallstringlayout.h
@@ -111,7 +111,7 @@ struct alignas(16) StringDataLayout
shortString[i] = string[i];
} else {
control = {0, true, true};
- reference = {string, Size - 1, 0};
+ reference = {{string}, Size - 1, 0};
}
}
@@ -163,7 +163,7 @@ struct alignas(16) StringDataLayout<MaximumShortStringDataAreaSize,
shortString[i] = string[i];
} else {
control = {0, true, true};
- reference = {string, Size - 1, 0};
+ reference = {{string}, Size - 1, 0};
}
}
diff --git a/src/plugins/coreplugin/styleanimator.cpp b/src/libs/utils/styleanimator.cpp
index f9d57a0d39..0597367732 100644
--- a/src/plugins/coreplugin/styleanimator.cpp
+++ b/src/libs/utils/styleanimator.cpp
@@ -3,9 +3,13 @@
#include "styleanimator.h"
-#include <utils/algorithm.h>
+#include "algorithm.h"
+#include <QPainter>
#include <QStyleOption>
+#include <QWidget>
+
+using namespace Utils;
Animation * StyleAnimator::widgetAnimation(const QWidget *widget) const
{
diff --git a/src/plugins/coreplugin/styleanimator.h b/src/libs/utils/styleanimator.h
index f12690aa71..08c4755cd1 100644
--- a/src/plugins/coreplugin/styleanimator.h
+++ b/src/libs/utils/styleanimator.h
@@ -3,13 +3,17 @@
#pragma once
+#include "utils_global.h"
+
+#include <QBasicTimer>
#include <QPointer>
#include <QTime>
-#include <QBasicTimer>
-#include <QStyle>
-#include <QPainter>
#include <QWidget>
+class QPainter;
+class QStyleOption;
+
+namespace Utils {
/*
* This is a set of helper classes to allow for widget animations in
* the style. Its mostly taken from Vista style so it should be fully documented
@@ -17,7 +21,7 @@
*
*/
-class Animation
+class QTCREATOR_UTILS_EXPORT Animation
{
public :
Animation() = default;
@@ -41,7 +45,7 @@ protected:
};
// Handles state transition animations
-class Transition : public Animation
+class QTCREATOR_UTILS_EXPORT Transition : public Animation
{
public :
Transition() = default;
@@ -54,7 +58,7 @@ public :
int m_duration = 100; //set time in ms to complete a state transition
};
-class StyleAnimator : public QObject
+class QTCREATOR_UTILS_EXPORT StyleAnimator : public QObject
{
Q_OBJECT
@@ -70,3 +74,4 @@ private:
QBasicTimer animationTimer;
QList <Animation*> animations;
};
+}
diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp
index 1f57baf580..9f849b9a61 100644
--- a/src/libs/utils/stylehelper.cpp
+++ b/src/libs/utils/stylehelper.cpp
@@ -101,6 +101,14 @@ QColor StyleHelper::baseColor(bool lightColored)
return (lightColored || windowColorAsBase) ? windowColor : m_baseColor;
}
+QColor StyleHelper::toolbarBaseColor(bool lightColored)
+{
+ if (creatorTheme()->flag(Theme::QDSTheme))
+ return creatorTheme()->color(Utils::Theme::DStoolbarBackground);
+ else
+ return StyleHelper::baseColor(lightColored);
+}
+
QColor StyleHelper::highlightColor(bool lightColored)
{
QColor result = baseColor(lightColored);
@@ -336,6 +344,101 @@ void StyleHelper::drawArrow(QStyle::PrimitiveElement element, QPainter *painter,
painter->drawPixmap(xOffset, yOffset, pixmap);
}
+void StyleHelper::drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option)
+{
+ if (option->rect.width() <= 1 || option->rect.height() <= 1)
+ return;
+
+ const qreal devicePixelRatio = painter->device()->devicePixelRatio();
+ const bool enabled = option->state & QStyle::State_Enabled;
+ QRect r = option->rect;
+ int size = qMin(r.height(), r.width());
+ QPixmap pixmap;
+ const QString pixmapName = QString::asprintf("StyleHelper::drawMinimalArrow-%d-%d-%d-%f",
+ element, size, enabled, devicePixelRatio);
+ if (!QPixmapCache::find(pixmapName, &pixmap)) {
+ QImage image(size * devicePixelRatio, size * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+ QPainter painter(&image);
+ QStyleOption tweakedOption(*option);
+
+ double rotation = 0;
+ switch (element) {
+ case QStyle::PE_IndicatorArrowLeft:
+ rotation = 45;
+ break;
+ case QStyle::PE_IndicatorArrowUp:
+ rotation = 135;
+ break;
+ case QStyle::PE_IndicatorArrowRight:
+ rotation = 225;
+ break;
+ case QStyle::PE_IndicatorArrowDown:
+ rotation = 315;
+ break;
+ default:
+ break;
+ }
+
+ auto drawArrow = [&tweakedOption, rotation, &painter](const QRect &rect, const QColor &color) -> void
+ {
+ static const QCommonStyle* const style = qobject_cast<QCommonStyle*>(QApplication::style());
+ if (!style)
+ return;
+
+ // Workaround for QTCREATORBUG-28470
+ QPalette pal = tweakedOption.palette;
+ pal.setBrush(QPalette::Base, pal.text()); // Base and Text differ, causing a detachment.
+ // Inspired by tst_QPalette::cacheKey()
+ pal.setColor(QPalette::ButtonText, color.rgb());
+
+ tweakedOption.palette = pal;
+ tweakedOption.rect = rect;
+
+ painter.save();
+ painter.setOpacity(color.alphaF());
+
+ double minDim = std::min(rect.width(), rect.height());
+ double innerWidth = minDim/M_SQRT2;
+ int penWidth = std::max(innerWidth/4, 1.0);
+ innerWidth -= penWidth;
+
+ QPen pPen(pal.color(QPalette::ButtonText), penWidth);
+ pPen.setJoinStyle(Qt::MiterJoin);
+ painter.setBrush(pal.text());
+ painter.setPen(pPen);
+
+ painter.translate(rect.center());
+ painter.rotate(rotation);
+ painter.translate(-innerWidth/2, -innerWidth/2);
+
+ const QPointF points[3] = {
+ {0, 0},
+ {0, innerWidth},
+ {innerWidth, innerWidth}
+ };
+
+ painter.drawPolyline(points, 3);
+ painter.restore();
+ };
+
+ if (enabled) {
+ if (creatorTheme()->flag(Theme::ToolBarIconShadow))
+ drawArrow(image.rect().translated(0, devicePixelRatio), toolBarDropShadowColor());
+ drawArrow(image.rect(), creatorTheme()->color(Theme::IconsBaseColor));
+ } else {
+ drawArrow(image.rect(), creatorTheme()->color(Theme::IconsDisabledColor));
+ }
+ painter.end();
+ pixmap = QPixmap::fromImage(image);
+ pixmap.setDevicePixelRatio(devicePixelRatio);
+ QPixmapCache::insert(pixmapName, pixmap);
+ }
+ int xOffset = r.x() + (r.width() - size)/2;
+ int yOffset = r.y() + (r.height() - size)/2;
+ painter->drawPixmap(xOffset, yOffset, pixmap);
+}
+
void StyleHelper::menuGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect)
{
if (StyleHelper::usePixmapCache()) {
@@ -531,6 +634,11 @@ QLinearGradient StyleHelper::statusBarGradient(const QRect &statusBarRect)
return grad;
}
+bool StyleHelper::isQDSTheme()
+{
+ return creatorTheme() ? creatorTheme()->flag(Theme::QDSTheme) : false;
+}
+
QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QList<IconFontHelper> &parameters)
{
QFontDatabase a;
@@ -590,7 +698,7 @@ QIcon StyleHelper::getIconFromIconFont(const QString &fontName, const QString &i
painter.save();
painter.setPen(color);
painter.setFont(font);
- painter.drawText(QRectF(QPoint(0, 0), size), iconSymbol);
+ painter.drawText(QRectF(QPoint(0, 0), size), Qt::AlignCenter, iconSymbol);
painter.restore();
icon.addPixmap(pixmap);
diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h
index 75b82f38a2..da93bb3c3a 100644
--- a/src/libs/utils/stylehelper.h
+++ b/src/libs/utils/stylehelper.h
@@ -33,6 +33,7 @@ public:
// This is our color table, all colors derive from baseColor
static QColor requestedBaseColor() { return m_requestedBaseColor; }
static QColor baseColor(bool lightColored = false);
+ static QColor toolbarBaseColor(bool lightColored = false);
static QColor panelTextColor(bool lightColored = false);
static QColor highlightColor(bool lightColored = false);
static QColor shadowColor(bool lightColored = false);
@@ -54,6 +55,7 @@ public:
// Draws a shaded anti-aliased arrow
static void drawArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option);
+ static void drawMinimalArrow(QStyle::PrimitiveElement element, QPainter *painter, const QStyleOption *option);
// Gradients used for panels
static void horizontalGradient(QPainter *painter, const QRect &spanRect, const QRect &clipRect, bool lightColored = false);
@@ -71,6 +73,8 @@ public:
static void tintImage(QImage &img, const QColor &tintColor);
static QLinearGradient statusBarGradient(const QRect &statusBarRect);
+ static bool isQDSTheme();
+
class IconFontHelper
{
public:
diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp
index 3cb2cef89c..9b7afa71eb 100644
--- a/src/libs/utils/theme/theme.cpp
+++ b/src/libs/utils/theme/theme.cpp
@@ -91,6 +91,9 @@ Theme::Theme(Theme *originTheme, QObject *parent)
Theme::~Theme()
{
+ if (this == m_creatorTheme)
+ m_creatorTheme = nullptr;
+
delete d;
}
diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h
index 762f4490f9..2604780a2d 100644
--- a/src/libs/utils/theme/theme.h
+++ b/src/libs/utils/theme/theme.h
@@ -284,7 +284,6 @@ public:
QmlDesigner_ScrollBarHandleColor,
/* Palette for DS Controls */
-
DSpanelBackground,
DSinteraction,
DSerrorColor,
@@ -304,9 +303,28 @@ public:
DStextSelectionColor,
DStextSelectedTextColor,
+ /*NEW for QtDS 4.0*/
+ DScontrolBackground_toolbarIdle,
+ DScontrolBackground_toolbarHover,
+ DStoolbarBackground,
+ DStoolbarIcon_blocked,
+ DSthumbnailBackground_baseState,
+ DSidleGreen,
+ DSrunningGreen,
+ DSstatusbarBackground,
+ DScontrolBackground_statusbarIdle,
+ DScontrolBackground_topToolbarHover,
+ DSControlBackground_statusbarHover,
+ DScontrolOutline_topToolbarIdle,
+ DScontrolOutline_topToolbarHover,
+ DSprimaryButton_hoverHighlight,
+ DSstateBackgroundColor_hover,
+ DSstateControlBackgroundColor_hover,
+ DSstateControlBackgroundColor_globalHover,
DSplaceholderTextColor,
DSplaceholderTextColorInteraction,
+ /*Legacy QtDS*/
DSiconColor,
DSiconColorHover,
DSiconColorInteraction,
@@ -469,7 +487,8 @@ public:
FlatMenuBar,
ToolBarIconShadow,
WindowColorAsBase,
- DarkUserInterface
+ DarkUserInterface,
+ QDSTheme
};
Q_ENUM(Color)
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 35fe753d1c..210a623031 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -298,6 +298,8 @@ Project {
"stringtable.h",
"stringutils.cpp",
"stringutils.h",
+ "styleanimator.cpp",
+ "styleanimator.h",
"styledbar.cpp",
"styledbar.h",
"stylehelper.cpp",
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 02f1319914..33aa3db6a0 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -54,17 +54,19 @@ add_subdirectory(mesonprojectmanager)
add_subdirectory(perforce)
add_subdirectory(qmakeprojectmanager)
add_subdirectory(qmljstools)
-add_subdirectory(qmlprojectmanager)
add_subdirectory(scxmleditor)
add_subdirectory(subversion)
add_subdirectory(compilationdatabaseprojectmanager)
add_subdirectory(languageclient)
+add_subdirectory(qmldesignerbase)
+
# Level 6:
add_subdirectory(cmakeprojectmanager)
add_subdirectory(debugger)
add_subdirectory(coco)
add_subdirectory(gitlab)
+add_subdirectory(qmlprojectmanager)
# Level 7:
add_subdirectory(android)
diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt
index 8a680a0f7b..17d1af01e3 100644
--- a/src/plugins/coreplugin/CMakeLists.txt
+++ b/src/plugins/coreplugin/CMakeLists.txt
@@ -150,7 +150,6 @@ add_qtc_plugin(Core
sidebar.cpp sidebar.h
sidebarwidget.cpp sidebarwidget.h
statusbarmanager.cpp statusbarmanager.h
- styleanimator.cpp styleanimator.h
systemsettings.cpp systemsettings.h
textdocument.cpp textdocument.h
themechooser.cpp themechooser.h
diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
index e61e3345be..0b4831e51b 100644
--- a/src/plugins/coreplugin/coreconstants.h
+++ b/src/plugins/coreplugin/coreconstants.h
@@ -215,5 +215,7 @@ const int MODEBAR_ICON_SIZE = 34;
const int MODEBAR_ICONSONLY_BUTTON_SIZE = MODEBAR_ICON_SIZE + 4;
const int DEFAULT_MAX_CHAR_COUNT = 10000000;
+const char SETTINGS_MENU_HIDE_TOOLS[] = "Menu/HideTools";
+
} // namespace Constants
} // namespace Core
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index b99b8be2df..459183224c 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -157,8 +157,6 @@ Project {
"sidebarwidget.h",
"statusbarmanager.cpp",
"statusbarmanager.h",
- "styleanimator.cpp",
- "styleanimator.h",
"systemsettings.cpp",
"systemsettings.h",
"textdocument.cpp",
diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
index 5b760f8ff1..017b8dc884 100644
--- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp
+++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp
@@ -237,15 +237,33 @@ protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
};
+const char SETTING_HIDE_OPTION_CATEGORIES[] = "HideOptionCategories";
+
+static bool categoryVisible(const Id &id)
+{
+ static QStringList list
+ = Core::ICore::settings()->value(SETTING_HIDE_OPTION_CATEGORIES).toStringList();
+
+ if (anyOf(list, [id](const QString &str) { return id.toString().contains(str); }))
+ return false;
+
+ return true;
+}
+
bool CategoryFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
+ const CategoryModel *cm = static_cast<CategoryModel *>(sourceModel());
+ const Category *category = cm->categories().at(sourceRow);
+
+ if (!categoryVisible(category->id))
+ return false;
+
// Regular contents check, then check page-filter.
if (QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent))
return true;
const QRegularExpression regex = filterRegularExpression();
- const CategoryModel *cm = static_cast<CategoryModel*>(sourceModel());
- const Category *category = cm->categories().at(sourceRow);
+
for (const IOptionsPage *page : category->pages) {
if (page->displayCategory().contains(regex) || page->displayName().contains(regex)
|| page->matches(regex))
diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp
index a7cf3debe3..fc6ec2bf92 100644
--- a/src/plugins/coreplugin/icore.cpp
+++ b/src/plugins/coreplugin/icore.cpp
@@ -513,7 +513,7 @@ FilePath ICore::libexecPath(const QString &rel)
FilePath ICore::crashReportsPath()
{
if (Utils::HostOsInfo::isMacHost())
- return libexecPath("crashpad_reports/completed");
+ return Core::ICore::userResourcePath("crashpad_reports/completed");
else
return libexecPath("crashpad_reports/reports");
}
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 3688b6c0ce..168fff9220 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -112,6 +112,10 @@ static const char modeSelectorLayoutKey[] = "ModeSelectorLayout";
static const bool askBeforeExitDefault = false;
+static bool hideToolsMenu()
+{
+ return Core::ICore::settings()->value(Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
+}
enum { debugMainWindow = 0 };
@@ -498,7 +502,10 @@ void MainWindow::registerDefaultContainers()
// Tools Menu
ActionContainer *ac = ActionManager::createMenu(Constants::M_TOOLS);
- menubar->addMenu(ac, Constants::G_TOOLS);
+ ac->setParent(this);
+ if (!hideToolsMenu())
+ menubar->addMenu(ac, Constants::G_TOOLS);
+
ac->menu()->setTitle(Tr::tr("&Tools"));
// Window Menu
diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp
index 7cf4746f95..016185b1c3 100644
--- a/src/plugins/coreplugin/manhattanstyle.cpp
+++ b/src/plugins/coreplugin/manhattanstyle.cpp
@@ -3,16 +3,14 @@
#include "manhattanstyle.h"
-#include "styleanimator.h"
-
#include <utils/algorithm.h>
+#include <utils/fancymainwindow.h>
#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
+#include <utils/styleanimator.h>
#include <utils/stylehelper.h>
-
-#include <utils/fancymainwindow.h>
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
-#include <utils/qtcassert.h>
#include <QApplication>
#include <QCheckBox>
@@ -26,6 +24,7 @@
#include <QPainter>
#include <QPainterPath>
#include <QPixmap>
+#include <QPixmapCache>
#include <QSpinBox>
#include <QStatusBar>
#include <QStyleFactory>
@@ -89,6 +88,23 @@ bool panelWidget(const QWidget *widget)
}
// Consider making this a QStyle state
+static bool isQmlEditorMenu(const QWidget *widget)
+{
+ const QMenu *menu = qobject_cast<const QMenu *> (widget);
+ if (!menu)
+ return false;
+
+ const QWidget *p = widget;
+ while (p) {
+ if (p->property("qmlEditorMenu").toBool())
+ return styleEnabled(widget);
+ p = p->parentWidget();
+ }
+
+ return false;
+}
+
+// Consider making this a QStyle state
bool lightColored(const QWidget *widget)
{
if (!widget)
@@ -112,6 +128,246 @@ static bool isDarkFusionStyle(const QStyle *style)
&& strcmp(style->metaObject()->className(), "QFusionStyle") == 0;
}
+QColor qmlEditorTextColor(bool enabled,
+ bool active,
+ bool checked)
+{
+ Theme::Color themePenColorId = enabled ? (active
+ ? (checked ? Theme::DSsubPanelBackground
+ : Theme::DSpanelBackground)
+ : Theme::DStextColor)
+ : Theme::DStextColorDisabled;
+
+ return creatorTheme()->color(themePenColorId);
+}
+
+QPixmap getDeletePixmap(bool enabled,
+ bool active,
+ const QSize &sizeLimit)
+{
+ using Utils::Theme;
+ using Utils::creatorTheme;
+ using Utils::StyleHelper;
+
+ const double xRatio = 19;
+ const double yRatio = 9;
+ double sizeConst = std::min(xRatio * sizeLimit.height(), yRatio * sizeLimit.width());
+ sizeConst = std::max(xRatio, sizeConst);
+
+ const int height = sizeConst/xRatio;
+ const int width = sizeConst/yRatio;
+ QPixmap retval(width, height);
+ QPainter p(&retval);
+ const qreal devicePixelRatio = p.device()->devicePixelRatio();
+
+ QPixmap pixmap;
+ QString pixmapName = QLatin1String("StyleHelper::drawDelete")
+ + "-" + QString::number(sizeConst)
+ + "-" + QString::number(enabled)
+ + "-" + QString::number(active)
+ + "-" + QString::number(devicePixelRatio);
+
+ if (!QPixmapCache::find(pixmapName, &pixmap)) {
+ QImage image(width * devicePixelRatio, height * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+ QPainter painter(&image);
+
+ auto drawDelete = [&painter, yRatio](const QRect &rect, const QColor &color) -> void
+ {
+ static const QStyle* const style = QApplication::style();
+ if (!style)
+ return;
+
+ const int height = rect.height();
+ const int width = rect.width();
+ const int insideW = height / 2;
+ const int penWidth = std::ceil(height / yRatio);
+ const int pixelGuard = penWidth / 2;
+ const QRect xRect = {insideW + (4 * penWidth),
+ 2 * penWidth,
+ 4 * penWidth,
+ 5 * penWidth};
+
+ // Workaround for QTCREATORBUG-28470
+ painter.save();
+ painter.setOpacity(color.alphaF());
+
+ QPen pen(color, penWidth);
+ pen.setJoinStyle(Qt::MiterJoin);
+ painter.setPen(pen);
+
+ QPainterPath pp(QPointF(pixelGuard, insideW));
+ pp.lineTo(insideW, pixelGuard);
+ pp.lineTo(width - pixelGuard, pixelGuard);
+ pp.lineTo(width - pixelGuard, height - pixelGuard);
+ pp.lineTo(insideW, height - pixelGuard);
+ pp.lineTo(pixelGuard, insideW);
+
+ painter.drawPath(pp);
+
+ // drawing X
+ painter.setPen(QPen(color, 1));
+ QPoint stepOver(penWidth, 0);
+
+ pp.clear();
+ pp.moveTo(xRect.topLeft());
+ pp.lineTo(xRect.topLeft() + stepOver);
+ pp.lineTo(xRect.bottomRight());
+ pp.lineTo(xRect.bottomRight() - stepOver);
+ pp.lineTo(xRect.topLeft());
+ painter.fillPath(pp, QBrush(color));
+
+ pp.clear();
+ pp.moveTo(xRect.topRight());
+ pp.lineTo(xRect.topRight() - stepOver);
+ pp.lineTo(xRect.bottomLeft());
+ pp.lineTo(xRect.bottomLeft() + stepOver);
+ pp.lineTo(xRect.topRight());
+ painter.fillPath(pp, QBrush(color));
+
+ painter.restore();
+ };
+
+ if (enabled && creatorTheme()->flag(Theme::ToolBarIconShadow))
+ drawDelete(image.rect().translated(0, devicePixelRatio), StyleHelper::toolBarDropShadowColor());
+
+ drawDelete(image.rect(), qmlEditorTextColor(enabled, active, false));
+
+ painter.end();
+ pixmap = QPixmap::fromImage(image);
+ pixmap.setDevicePixelRatio(devicePixelRatio);
+ QPixmapCache::insert(pixmapName, pixmap);
+ }
+ return pixmap;
+}
+
+struct ManhattanShortcut {
+ ManhattanShortcut(const QStyleOptionMenuItem *option,
+ const QString &shortcutText)
+ : shortcutText(shortcutText)
+ , enabled(option->state & QStyle::State_Enabled)
+ , active(option->state & QStyle::State_Selected)
+ , font(option->font)
+ , fm(font)
+ , defaultHeight(fm.height())
+ , palette(option->palette)
+ , spaceConst(fm.boundingRect(".").width())
+ {
+ reset();
+ }
+
+ QSize getSize()
+ {
+ if (isFirstParticle)
+ calcResult();
+ return _size;
+ }
+
+ QPixmap getPixmap()
+ {
+ if (!isFirstParticle && !_pixmap.isNull())
+ return _pixmap;
+
+ _pixmap = QPixmap(getSize());
+ _pixmap.fill(Qt::transparent);
+ QPainter painter(&_pixmap);
+ painter.setFont(font);
+ QPen pPen = painter.pen();
+ pPen.setColor(qmlEditorTextColor(enabled, active, false));
+ painter.setPen(pPen);
+ calcResult(&painter);
+ painter.end();
+
+ return _pixmap;
+ }
+
+private:
+ void applySize(const QSize &itemSize) {
+ width += itemSize.width();
+ height = std::max(height, itemSize.height());
+ if (isFirstParticle)
+ isFirstParticle = false;
+ else
+ width += spaceConst;
+ };
+
+ void addText(const QString &txt, QPainter *painter = nullptr)
+ {
+ if (txt.size()) {
+ int textWidth = fm.boundingRect(txt).width();
+ QSize itemSize = {textWidth, defaultHeight};
+ if (painter) {
+ QRect placeRect({width, 0}, itemSize);
+ painter->drawText(placeRect, txt, textOption);
+ }
+ applySize(itemSize);
+ }
+ };
+
+ void addPixmap(const QPixmap &pixmap, QPainter *painter = nullptr)
+ {
+ if (painter)
+ painter->drawPixmap(QRect({width, 0}, pixmap.size()), pixmap);
+
+ applySize(pixmap.size());
+ };
+
+ void calcResult(QPainter *painter = nullptr)
+ {
+ reset();
+#ifndef QT_NO_SHORTCUT
+ if (!shortcutText.isEmpty()) {
+ int fwdIndex = 0;
+ QRegularExpressionMatch mMatch = backspaceDetect.match(shortcutText);
+ int matchCount = mMatch.lastCapturedIndex();
+
+ for (int i = 0; i <= matchCount; ++i) {
+ QString mStr = mMatch.captured(i);
+ QPixmap pixmap = getDeletePixmap(enabled,
+ active,
+ {defaultHeight * 3, defaultHeight});
+
+ int lIndex = shortcutText.indexOf(mStr, fwdIndex);
+ int diffChars = lIndex - fwdIndex;
+ addText(shortcutText.mid(fwdIndex, diffChars), painter);
+ addPixmap(pixmap, painter);
+ fwdIndex = lIndex + mStr.size();
+ }
+ addText(shortcutText.mid(fwdIndex), painter);
+ }
+#endif
+ _size = {width, height};
+ }
+
+ void reset()
+ {
+ isFirstParticle = true;
+ width = 0;
+ height = 0;
+ }
+
+ const QString shortcutText;
+ const bool enabled;
+ const bool active;
+ const QFont font;
+ const QFontMetrics fm;
+ const int defaultHeight;
+ const QPalette palette;
+ const int spaceConst;
+ static const QTextOption textOption;
+ static const QRegularExpression backspaceDetect;
+ bool isFirstParticle = true;
+
+ int width = 0;
+ int height = 0;
+ QSize _size;
+ QPixmap _pixmap;
+};
+const QRegularExpression ManhattanShortcut::backspaceDetect("\\+*backspace\\+*",
+ QRegularExpression::CaseInsensitiveOption);
+const QTextOption ManhattanShortcut::textOption(Qt::AlignLeft | Qt::AlignVCenter);
+
+
class ManhattanStylePrivate
{
public:
@@ -152,10 +408,66 @@ QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *op
{
QSize newSize = QProxyStyle::sizeFromContents(type, option, size, widget);
- if (type == CT_Splitter && widget && widget->property("minisplitter").toBool())
- return QSize(1, 1);
- else if (type == CT_ComboBox && panelWidget(widget))
- newSize += QSize(14, 0);
+ switch (type) {
+ case CT_Splitter:
+ if (widget && widget->property("minisplitter").toBool())
+ newSize = QSize(1, 1);
+ break;
+ case CT_ComboBox:
+ if (panelWidget(widget))
+ newSize += QSize(14, 0);
+ break;
+ case CT_MenuItem:
+ if (isQmlEditorMenu(widget)) {
+ if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ const int leftMargin = pixelMetric(QStyle::PM_LayoutLeftMargin, option, widget);
+ const int rightMargin = pixelMetric(QStyle::PM_LayoutRightMargin, option, widget);
+ const int horizontalSpacing = pixelMetric(QStyle::PM_LayoutHorizontalSpacing, option, widget);
+ const int iconHeight = pixelMetric(QStyle::PM_SmallIconSize, option, widget) + horizontalSpacing;
+ int width = leftMargin + rightMargin;
+ if (mbi->menuHasCheckableItems || mbi->maxIconWidth)
+ width += iconHeight + horizontalSpacing;
+
+ if (!mbi->text.isEmpty()) {
+ QString itemText = mbi->text;
+ QString shortcutText;
+ int tabIndex = itemText.indexOf("\t");
+ if (tabIndex > -1) {
+ shortcutText = itemText.mid(tabIndex + 1);
+ itemText = itemText.left(tabIndex);
+ }
+
+ if (itemText.size())
+ width += option->fontMetrics.boundingRect(itemText).width() + horizontalSpacing;
+
+ if (shortcutText.size()) {
+ QSize shortcutSize = ManhattanShortcut(mbi, shortcutText).getSize();
+ width += shortcutSize.width() + 2 * horizontalSpacing;
+ }
+ }
+
+ if (mbi->menuItemType == QStyleOptionMenuItem::SubMenu)
+ width += iconHeight + horizontalSpacing;
+
+ newSize.setWidth(width);
+
+ switch (mbi->menuItemType) {
+ case QStyleOptionMenuItem::Normal:
+ case QStyleOptionMenuItem::DefaultItem:
+ case QStyleOptionMenuItem::SubMenu:
+ newSize.setHeight(19);
+ break;
+ default:
+ newSize += QSize(0, 7);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
return newSize;
}
@@ -175,7 +487,30 @@ QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionC
return QRect(); // breaks the scrollbar, but avoids the crash
}
#endif
- return QProxyStyle::subControlRect(control, option, subControl, widget);
+
+ QRect retval = QProxyStyle::subControlRect(control, option, subControl, widget);;
+ if (panelWidget(widget)) {
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ switch (subControl) {
+ case SubControl::SC_SliderGroove:
+ return option->rect;
+ case SubControl::SC_SliderHandle:
+ {
+ int thickness = 2;
+ QPoint center = retval.center();
+ const QRect &rect = slider->rect;
+ if (slider->orientation == Qt::Horizontal)
+ return QRect(center.x() - thickness, rect.top(), (thickness * 2) + 1, rect.height());
+ else
+ return QRect(rect.left(), center.y() - thickness, rect.width(), (thickness * 2) + 1);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return retval;
}
QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
@@ -186,8 +521,8 @@ QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control,
int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
- int retval = 0;
- retval = QProxyStyle::pixelMetric(metric, option, widget);
+ int retval = QProxyStyle::pixelMetric(metric, option, widget);
+
switch (metric) {
#ifdef Q_OS_MACOS
case PM_MenuButtonIndicator:
@@ -205,30 +540,61 @@ int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option,
retval = 16;
break;
case PM_SmallIconSize:
- retval = 16;
+ if (isQmlEditorMenu(widget))
+ retval = 10;
+ else
+ retval = 16;
break;
case PM_DockWidgetHandleExtent:
case PM_DockWidgetSeparatorExtent:
return 1;
+ case PM_LayoutLeftMargin:
+ case PM_LayoutRightMargin:
+ if (isQmlEditorMenu(widget))
+ retval = 7;
+ break;
+ case PM_LayoutHorizontalSpacing:
+ if (isQmlEditorMenu(widget))
+ retval = 12;
+ break;
+ case PM_MenuHMargin:
+ if (isQmlEditorMenu(widget))
+ retval = 5;
+ break;
+ case PM_SubMenuOverlap:
+ if (isQmlEditorMenu(widget))
+ retval = 10;
+ break;
case PM_MenuPanelWidth:
case PM_MenuBarHMargin:
case PM_MenuBarVMargin:
case PM_ToolBarFrameWidth:
- if (panelWidget(widget))
+ if (panelWidget(widget) || isQmlEditorMenu(widget))
retval = 1;
break;
case PM_ButtonShiftVertical:
case PM_ButtonShiftHorizontal:
case PM_MenuBarPanelWidth:
case PM_ToolBarItemMargin:
+ if (StyleHelper::isQDSTheme()) {
+ retval = 0;
+ break;
+ }
+ [[fallthrough]];
case PM_ToolBarItemSpacing:
if (panelWidget(widget))
retval = 0;
+ if (StyleHelper::isQDSTheme())
+ retval = 4;
break;
case PM_DefaultFrameWidth:
if (qobject_cast<const QLineEdit*>(widget) && panelWidget(widget))
return 1;
break;
+ case PM_ToolBarExtensionExtent:
+ if (StyleHelper::isQDSTheme())
+ retval = 29;
+ break;
default:
break;
}
@@ -540,8 +906,11 @@ static void drawPrimitiveTweakedForDarkTheme(QStyle::PrimitiveElement element,
void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
- const bool isPanelWidget = panelWidget(widget);
- if (!isPanelWidget) {
+ if (panelWidget(widget)) {
+ drawPrimitiveForPanelWidget(element, option, painter, widget);
+ } else if (isQmlEditorMenu(widget)) {
+ drawPrimitiveForQmlEditor(element, option, painter, widget);
+ } else {
const bool tweakDarkTheme =
(element == PE_Frame
|| element == PE_FrameLineEdit
@@ -556,7 +925,13 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
QProxyStyle::drawPrimitive(element, option, painter, widget);
return;
}
+}
+void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
bool animating = (option->state & State_Animating);
int state = option->state;
QRect rect = option->rect;
@@ -630,7 +1005,10 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
painter->save();
if (!enabled)
painter->setOpacity(0.75);
- painter->fillRect(backgroundRect, option->palette.base());
+ QBrush baseBrush = option->palette.base();
+ if (widget && qobject_cast<const QSpinBox *>(widget->parentWidget()))
+ baseBrush = creatorTheme()->color(Theme::DScontrolBackgroundDisabled);
+ painter->fillRect(backgroundRect, baseBrush);
painter->restore();
} else {
backgroundRect.adjust(1, 1, -1, -1);
@@ -720,7 +1098,7 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
break;
case PE_IndicatorToolBarSeparator:
- {
+ if (!StyleHelper::isQDSTheme()) {
QRect separatorRect = rect;
separatorRect.setLeft(rect.width() / 2);
separatorRect.setWidth(1);
@@ -785,6 +1163,225 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
}
}
+void ManhattanStyle::drawPrimitiveForQmlEditor(PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
+ if (!mbi) {
+ QProxyStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+
+ switch (element) {
+ case PE_IndicatorArrowUp:
+ case PE_IndicatorArrowDown:
+ {
+ QStyleOptionMenuItem item = *mbi;
+ item.palette = QPalette(Qt::white);
+ StyleHelper::drawMinimalArrow(element, painter, &item);
+ }
+ break;
+ case PE_IndicatorArrowRight:
+ drawQmlEditorIcon(element, option, "cascadeIconRight", painter, widget);
+ break;
+ case PE_IndicatorArrowLeft:
+ drawQmlEditorIcon(element, option, "cascadeIconLeft", painter, widget);
+ break;
+ case PE_PanelButtonCommand:
+ break;
+ case PE_IndicatorMenuCheckMark:
+ drawQmlEditorIcon(element, option, "tickIcon", painter, widget);
+ break;
+ case PE_FrameMenu:
+ case PE_PanelMenu:
+ {
+ painter->save();
+ painter->setBrush(creatorTheme()->color(Theme::DSsubPanelBackground));
+ painter->setPen(Qt::NoPen);
+ painter->drawRect(option->rect);
+ painter->restore();
+ }
+ break;
+ default:
+ QProxyStyle::drawPrimitive(element, option, painter, widget);
+ break;
+ }
+}
+
+void ManhattanStyle::drawControlForQmlEditor(ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ Q_UNUSED(element)
+ if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ painter->save();
+ const int iconHeight = pixelMetric(QStyle::PM_SmallIconSize, option, widget);
+ const int horizontalSpacing = pixelMetric(QStyle::PM_LayoutHorizontalSpacing, option, widget);
+ const int iconWidth = iconHeight;
+ const bool isActive = mbi->state & State_Selected;
+ const bool isDisabled = !(mbi->state & State_Enabled);
+ const bool isCheckable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
+ const bool isChecked = isCheckable ? mbi->checked : false;
+ int startMargin = pixelMetric(QStyle::PM_LayoutLeftMargin, option, widget);
+ int endMargin = pixelMetric(QStyle::PM_LayoutRightMargin, option, widget);
+ int forwardX = 0;
+
+ if (option->direction == Qt::RightToLeft)
+ std::swap(startMargin, endMargin);
+
+ QStyleOptionMenuItem item = *mbi;
+
+ if (isActive) {
+ painter->fillRect(item.rect, creatorTheme()->color(Theme::DSinteraction));
+ }
+ forwardX += startMargin;
+
+ if (item.menuItemType == QStyleOptionMenuItem::Separator) {
+ int commonHeight = item.rect.center().y();
+ int additionalMargin = forwardX /*hmargin*/;
+ QLineF separatorLine (item.rect.left() + additionalMargin,
+ commonHeight,
+ item.rect.right() - additionalMargin,
+ commonHeight);
+
+ painter->setPen(creatorTheme()->color(Theme::DSstateSeparatorColor));
+ painter->drawLine(separatorLine);
+ item.text.clear();
+ painter->restore();
+ return;
+ }
+
+ QPixmap iconPixmap;
+ QIcon::Mode mode = isDisabled ? QIcon::Disabled : ((isActive) ? QIcon::Active : QIcon::Normal);
+ QIcon::State state = isChecked ? QIcon::On : QIcon::Off;
+ QColor themePenColor = qmlEditorTextColor(!isDisabled, isActive, isChecked);
+
+ if (!item.icon.isNull()) {
+ iconPixmap = item.icon.pixmap(QSize(iconHeight, iconHeight), mode, state);
+ } else if (isCheckable) {
+ iconPixmap = QPixmap(iconHeight, iconHeight);
+ iconPixmap.fill(Qt::transparent);
+
+ if (item.checked) {
+ QStyleOptionMenuItem so = item;
+ so.rect = iconPixmap.rect();
+ QPainter dPainter(&iconPixmap);
+ dPainter.setPen(themePenColor);
+ drawPrimitive(PE_IndicatorMenuCheckMark, &so, &dPainter, widget);
+ }
+ }
+
+ if (!iconPixmap.isNull()) {
+ QRect vCheckRect = visualRect(item.direction,
+ item.rect,
+ QRect(item.rect.x() + forwardX,
+ item.rect.y(),
+ iconWidth,
+ item.rect.height()));
+
+ QRect pmr(QPoint(0, 0), iconPixmap.deviceIndependentSize().toSize());
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(themePenColor);
+ painter->drawPixmap(pmr.topLeft(), iconPixmap);
+
+ item.checkType = QStyleOptionMenuItem::NotCheckable;
+ item.checked = false;
+ item.icon = {};
+ }
+ if (item.menuHasCheckableItems || item.maxIconWidth > 0) {
+ forwardX += iconWidth + horizontalSpacing;
+ }
+
+ QString shortcutText;
+ int tabIndex = item.text.indexOf("\t");
+ if (tabIndex > -1) {
+ shortcutText = item.text.mid(tabIndex + 1);
+ item.text = item.text.left(tabIndex);
+ }
+
+ if (item.text.size()) {
+ painter->save();
+
+ QRect vTextRect = visualRect(item.direction,
+ item.rect,
+ item.rect.adjusted(forwardX, 0 , 0 , 0));
+
+ Qt::Alignment alignmentFlags = item.direction == Qt::LeftToRight ? Qt::AlignLeft
+ : Qt::AlignRight;
+ alignmentFlags |= Qt::AlignVCenter;
+
+ int textFlags = Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, &item, widget))
+ textFlags |= Qt::TextHideMnemonic;
+ textFlags |= alignmentFlags;
+
+ painter->setPen(themePenColor);
+ painter->drawText(vTextRect, textFlags, item.text);
+ painter->restore();
+ }
+
+ if (item.menuItemType == QStyleOptionMenuItem::SubMenu) {
+ PrimitiveElement dropDirElement = item.direction == Qt::LeftToRight ? PE_IndicatorArrowRight
+ : PE_IndicatorArrowLeft;
+
+ QSize elSize(iconHeight, iconHeight);
+ int xOffset = iconHeight + endMargin;
+ int yOffset = (item.rect.height() - iconHeight) / 2;
+ QRect dropRect(item.rect.topRight(), elSize);
+ dropRect.adjust(-xOffset, yOffset, -xOffset, yOffset);
+
+ QStyleOptionMenuItem so = item;
+ so.rect = visualRect(item.direction,
+ item.rect,
+ dropRect);
+
+ drawPrimitive(dropDirElement, &so, painter, widget);
+ } else if (!shortcutText.isEmpty()) {
+ QPixmap pix = ManhattanShortcut(&item, shortcutText).getPixmap();
+
+ if (pix.width()) {
+ int xOffset = pix.width() + (iconHeight / 2) + endMargin;
+ QRect shortcutRect = item.rect.translated({item.rect.width() - xOffset, 0});
+ shortcutRect.setSize({pix.width(), item.rect.height()});
+ shortcutRect = visualRect(item.direction,
+ item.rect,
+ shortcutRect);
+ drawItemPixmap(painter,
+ shortcutRect,
+ Qt::AlignRight | Qt::AlignVCenter,
+ pix);
+ }
+ }
+ painter->restore();
+ }
+}
+
+void ManhattanStyle::drawQmlEditorIcon(PrimitiveElement element,
+ const QStyleOption *option,
+ const char *propertyName,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ if (option->styleObject && option->styleObject->property(propertyName).isValid()) {
+ const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
+ if (mbi) {
+ const bool checkable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
+ const bool isDisabled = !(mbi->state & State_Enabled);
+ const bool isActive = mbi->state & State_Selected;
+ QIcon icon = mbi->styleObject->property(propertyName).value<QIcon>();
+ QIcon::Mode mode = isDisabled ? QIcon::Disabled : ((isActive) ? QIcon::Active : QIcon::Normal);
+ QIcon::State state = (checkable && mbi->checked) ? QIcon::On : QIcon::Off;
+ QPixmap pix = icon.pixmap(option->rect.size(), mode, state);
+ drawItemPixmap(painter, option->rect, Qt::AlignCenter, pix);
+ return;
+ }
+ }
+ QProxyStyle::drawPrimitive(element, option, painter, widget);
+}
+
void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
QPainter *painter, const QWidget *widget) const
{
@@ -808,7 +1405,11 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt
pal.setBrush(QPalette::Text, color);
item.palette = pal;
}
- QProxyStyle::drawControl(element, &item, painter, widget);
+
+ if (isQmlEditorMenu(widget))
+ drawControlForQmlEditor(element, &item, painter, widget);
+ else
+ QProxyStyle::drawControl(element, &item, painter, widget);
}
painter->restore();
break;
@@ -967,6 +1568,13 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt
}
break;
+ case CE_MenuEmptyArea:
+ if (isQmlEditorMenu(widget))
+ drawPrimitive(PE_PanelMenu, option, painter, widget);
+ else
+ QProxyStyle::drawControl(element, option, painter, widget);
+
+ break;
case CE_ToolBar:
{
QRect rect = option->rect;
@@ -984,7 +1592,7 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt
bool drawLightColored = lightColored(widget);
// draws the background of the 'Type hierarchy', 'Projects' headers
if (creatorTheme()->flag(Theme::FlatToolBars))
- painter->fillRect(rect, StyleHelper::baseColor(drawLightColored));
+ painter->fillRect(rect, StyleHelper::toolbarBaseColor(drawLightColored));
else if (horizontal)
StyleHelper::horizontalGradient(painter, gradientSpan, rect, drawLightColored);
else
@@ -1043,7 +1651,7 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti
QPainter *painter, const QWidget *widget) const
{
if (!panelWidget(widget))
- return QProxyStyle::drawComplexControl(control, option, painter, widget);
+ return QProxyStyle::drawComplexControl(control, option, painter, widget);
QRect rect = option->rect;
switch (control) {
@@ -1184,7 +1792,170 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti
painter->restore();
}
break;
+ case CC_Slider:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+
+ bool horizontal = slider->orientation == Qt::Horizontal;
+ bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
+ bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
+ bool enabled = option->state & QStyle::State_Enabled;
+ bool grooveHover = slider->activeSubControls & SC_SliderGroove;
+ bool handleHover = slider->activeSubControls & SC_SliderHandle;
+ bool interaction = option->state & State_Sunken;
+ bool activeFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
+
+ int sliderPaintingOffset = horizontal
+ ? handle.center().x()
+ : handle.center().y();
+
+ int borderRadius = 4;
+ painter->save();
+ painter->setRenderHint(QPainter::RenderHint::Antialiasing);
+
+ int lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth, option, widget);
+ Theme::Color themeframeColor = enabled
+ ? interaction
+ ? Theme::DSstateControlBackgroundColor_hover // Pressed
+ : grooveHover
+ ? Theme::DSstateSeparatorColor // GrooveHover
+ : Theme::DSpopupBackground // Idle
+ : Theme::DSpopupBackground; // Disabled
+
+ QColor frameColor = creatorTheme()->color(themeframeColor);
+
+ if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
+ Theme::Color bgPlusColor = enabled
+ ? interaction
+ ? Theme::DSstateControlBackgroundColor_hover // Pressed
+ : grooveHover
+ ? Theme::DSstateSeparatorColor // GrooveHover
+ : Theme::DStoolbarBackground // Idle
+ : Theme::DStoolbarBackground; // Disabled
+ Theme::Color bgMinusColor = Theme::DSpopupBackground;
+
+ QRect minusRect(groove);
+ QRect plusRect(groove);
+
+ if (horizontal) {
+ if (slider->upsideDown) {
+ minusRect.setLeft(sliderPaintingOffset);
+ plusRect.setRight(sliderPaintingOffset);
+ } else {
+ minusRect.setRight(sliderPaintingOffset);
+ plusRect.setLeft(sliderPaintingOffset);
+ }
+ } else {
+ if (slider->upsideDown) {
+ minusRect.setBottom(sliderPaintingOffset);
+ plusRect.setTop(sliderPaintingOffset);
+ } else {
+ minusRect.setTop(sliderPaintingOffset);
+ plusRect.setBottom(sliderPaintingOffset);
+ }
+ }
+
+ painter->save();
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(creatorTheme()->color(bgPlusColor));
+ painter->drawRoundedRect(plusRect, borderRadius, borderRadius);
+ painter->setBrush(creatorTheme()->color(bgMinusColor));
+ painter->drawRoundedRect(minusRect, borderRadius, borderRadius);
+ painter->restore();
+ }
+
+ if (option->subControls & SC_SliderTickmarks) {
+ Theme::Color tickPen = enabled
+ ? activeFocus
+ ? Theme::DSstateBackgroundColor_hover
+ : Theme::DSBackgroundColorAlternate
+ : Theme::DScontrolBackgroundDisabled;
+
+ painter->setPen(tickPen);
+ int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (interval <= 0)
+ interval = 1;
+
+ int v = slider->minimum;
+ int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, (horizontal
+ ? slider->rect.width()
+ : slider->rect.height()) - len,
+ slider->upsideDown) + len / 2;
+ int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
+
+ if (horizontal) {
+ if (ticksAbove) {
+ painter->drawLine(pos, slider->rect.top() + extra,
+ pos, slider->rect.top() + tickSize);
+ }
+ if (ticksBelow) {
+ painter->drawLine(pos, slider->rect.bottom() - extra,
+ pos, slider->rect.bottom() - tickSize);
+ }
+ } else {
+ if (ticksAbove) {
+ painter->drawLine(slider->rect.left() + extra, pos,
+ slider->rect.left() + tickSize, pos);
+ }
+ if (ticksBelow) {
+ painter->drawLine(slider->rect.right() - extra, pos,
+ slider->rect.right() - tickSize, pos);
+ }
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ }
+
+ // draw handle
+ if ((option->subControls & SC_SliderHandle) ) {
+ Theme::Color handleColor = enabled
+ ? interaction
+ ? Theme::DSinteraction // Interaction
+ : grooveHover || handleHover
+ ? Theme::DStabActiveText // Hover
+ : Theme::PalettePlaceholderText // Idle
+ : Theme::DStoolbarIcon_blocked; // Disabled
+
+ int halfSliderThickness = horizontal
+ ? handle.width() / 2
+ : handle.height() / 2;
+ painter->setBrush(creatorTheme()->color(handleColor));
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(handle,
+ halfSliderThickness,
+ halfSliderThickness);
+ }
+
+ if (groove.isValid()) {
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(frameColor, lineWidth));
+ painter->drawRoundedRect(groove, borderRadius, borderRadius);
+ }
+ painter->restore();
+ }
+ break;
default:
QProxyStyle::drawComplexControl(control, option, painter, widget);
break;
diff --git a/src/plugins/coreplugin/manhattanstyle.h b/src/plugins/coreplugin/manhattanstyle.h
index 40b293cf71..07079c7d2d 100644
--- a/src/plugins/coreplugin/manhattanstyle.h
+++ b/src/plugins/coreplugin/manhattanstyle.h
@@ -30,7 +30,6 @@ public:
QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = nullptr) const override;
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override;
int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
- QRect itemRect(QPainter *p, const QRect &r, int flags, bool enabled, const QPixmap *pixmap, const QString &text, int len = -1) const;
QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const override;
int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override;
@@ -45,6 +44,27 @@ public:
void unpolish(QApplication *app) override;
private:
+ void drawPrimitiveForPanelWidget(PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const;
+
+ void drawPrimitiveForQmlEditor(PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const;
+
+ void drawControlForQmlEditor(ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const;
+
+ void drawQmlEditorIcon(PrimitiveElement element,
+ const QStyleOption *option,
+ const char *propertyName,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const;
+
static void drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse);
ManhattanStylePrivate *d;
diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp
index e91dbf94fe..7baedc4df2 100644
--- a/src/plugins/projectexplorer/projectwindow.cpp
+++ b/src/plugins/projectexplorer/projectwindow.cpp
@@ -35,6 +35,7 @@
#include <utils/hostosinfo.h>
#include <utils/navigationtreeview.h>
#include <utils/qtcassert.h>
+#include <utils/qtcsettings.h>
#include <utils/styledbar.h>
#include <utils/treemodel.h>
#include <utils/utilsicons.h>
@@ -585,8 +586,13 @@ public:
innerLayout->setSpacing(10);
innerLayout->setContentsMargins(PanelsWidget::PanelVMargin, innerLayout->spacing(),
PanelsWidget::PanelVMargin, 0);
- innerLayout->addWidget(m_manageKits);
- innerLayout->addSpacerItem(new QSpacerItem(10, 30, QSizePolicy::Maximum, QSizePolicy::Maximum));
+
+ QStringList list = Core::ICore::settings()->value("HideOptionCategories").toStringList();
+ if (!list.contains("Kit")) {
+ innerLayout->addWidget(m_manageKits);
+ innerLayout->addSpacerItem(new QSpacerItem(10, 30, QSizePolicy::Maximum, QSizePolicy::Maximum));
+ }
+
innerLayout->addWidget(activeLabel);
innerLayout->addWidget(m_projectSelection);
innerLayout->addWidget(m_importBuild);
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index d8c4ff8a71..d436d10e0e 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -1,18 +1,19 @@
+#only if the plugin is requested by qtc_plugin_enabled continue if not stop as early as possible
add_qtc_plugin(QmlDesigner
- CONDITION TARGET Qt::QuickWidgets AND TARGET Qt::Svg
- DEPENDS
- QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
- Qt::QuickWidgets Qt::CorePrivate Sqlite Qt::Xml Qt::Svg
- PLUGIN_DEPENDS
- Core ProjectExplorer QmlJSEditor QmlProjectManager
- QtSupport QmakeProjectManager
PLUGIN_RECOMMENDS QmlPreview
+ CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.2.0 AND TARGET Qt::QuickWidgets AND TARGET Qt::Svg
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+ PLUGIN_DEPENDS
+ Core ProjectExplorer QmlDesignerBase QmlJSEditor QmakeProjectManager QmlProjectManager
+ QtSupport
)
qtc_plugin_enabled(_qmlDesignerEnabled QmlDesigner)
if (NOT _qmlDesignerEnabled)
return()
endif()
+find_package(Qt6 COMPONENTS QmlDomPrivate QmlCompilerPrivate)
+
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/qmldesigner")
if (APPLE)
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
@@ -23,21 +24,22 @@ env_with_default("QDS_USE_PROJECTSTORAGE" ENV_QDS_USE_PROJECTSTORAGE OFF)
option(USE_PROJECTSTORAGE "Use ProjectStorage" ${ENV_QDS_USE_PROJECTSTORAGE})
add_feature_info("ProjectStorage" ${USE_PROJECTSTORAGE} "")
-env_with_default("QDS_WITH_QMLDOM" ENV_QDS_WITH_QMLDOM OFF)
-option(WITH_QMLDOM "Build with QmlDom" ${ENV_QDS_WITH_QMLDOM})
-add_feature_info("Build with QmlDom" ${WITH_QMLDOM} "")
-
add_qtc_library(QmlDesignerUtils STATIC
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
DEPENDS
- Qt::Gui
+ Qt::Gui Utils Qt::QmlPrivate
DEFINES QMLDESIGNERUTILS_LIBRARY
PUBLIC_DEFINES $<$<BOOL:${QTC_STATIC_BUILD}>:QMLDESIGNER_STATIC_LIBRARY>
+
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES
asset.cpp asset.h
- designersettings.cpp designersettings.h
+ filedownloader.cpp filedownloader.h
+ multifiledownloader.cpp multifiledownloader.h
+ fileextractor.cpp fileextractor.h
hdrimage.cpp hdrimage.h
+ ktximage.cpp ktximage.h
imageutils.cpp imageutils.h
qmldesignerutils_global.h
)
@@ -60,6 +62,7 @@ add_qtc_library(QmlDesignerCore STATIC
QmlProjectManager
QtSupport
PUBLIC_DEPENDS
+ QmlDesignerBase
QmlPuppetCommunication
QmlDesignerUtils
TextEditor
@@ -77,6 +80,13 @@ add_qtc_library(QmlDesignerCore STATIC
)
extend_qtc_library(QmlDesignerCore
+ CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
+
+ DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
+ DEFINES QDS_HAS_QMLDOM
+)
+
+extend_qtc_library(QmlDesignerCore
CONDITION UNIX AND NOT APPLE
PUBLIC_DEPENDS rt
)
@@ -173,6 +183,8 @@ extend_qtc_library(QmlDesignerCore
meshimagecachecollector.cpp
meshimagecachecollector.h
synchronousimagecache.cpp
+ textureimagecachecollector.cpp
+ textureimagecachecollector.h
timestampprovider.cpp
timestampprovider.h
timestampproviderinterface.h
@@ -377,6 +389,7 @@ extend_qtc_library(QmlDesignerCore
filestatus.h
filestatuscache.cpp filestatuscache.h
nonlockingmutex.h
+ projectstorageexceptions.cpp projectstorageexceptions.h
projectstorageinterface.h
projectstoragefwd.h
projectstorageinfotypes.h
@@ -407,6 +420,14 @@ file(GLOB PROJECTSTORAGE_EXCLUDED_SOURCES designercore/projectstorage/*.cpp)
set_property(SOURCE ${PROJECTSTORAGE_EXCLUDED_SOURCES} PROPERTY SKIP_AUTOMOC ON)
extend_qtc_plugin(QmlDesigner
+ PUBLIC_DEPENDS
+ QmlDesignerUtils
+ QmlDesignerBase
+ QmlPuppetCommunication
+ DEPENDS
+ QmlDesignerCore
+ QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Sqlite
+ Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg
DEFINES
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
@@ -429,13 +450,8 @@ extend_qtc_plugin(QmlDesigner
${CMAKE_CURRENT_LIST_DIR}/components/texteditor
PUBLIC_INCLUDES
${CMAKE_CURRENT_LIST_DIR}
- ${CMAKE_CURRENT_LIST_DIR}/designercore
- ${CMAKE_CURRENT_LIST_DIR}/designercore/include
- PUBLIC_DEPENDS
- QmlDesignerUtils
- QmlPuppetCommunication
- DEPENDS
- QmlDesignerCore
+ ${CMAKE_CURRENT_LIST_DIR}/designercore #can not be a public dependency -> EXCLUDE_FROM_INSTALL in QmlDesignerCore
+ ${CMAKE_CURRENT_LIST_DIR}/designercore/include #iwidgetplugin.h is used by other plugins
SOURCES
designmodecontext.cpp designmodecontext.h
designmodewidget.cpp designmodewidget.h
@@ -500,33 +516,15 @@ function(get_and_add_as_subdirectory name repository git_tag build_dir source_di
add_subdirectory(${source_dir}/${name}/${source_subdir} ${name})
endfunction()
-if (WITH_QMLDOM)
- if (Qt6_VERSION VERSION_LESS 6.3.2)
- message(FATAL_ERROR "You need Qt 6.3.2 or newer to enable WITH_QMLDOM feature.")
- endif()
-
-
- get_and_add_as_subdirectory("qmldom_standalone"
- "https://codereview.qt-project.org/qt/qtdeclarative"
- "origin/dev"
- "${CMAKE_BINARY_DIR}"
- "${CMAKE_CURRENT_SOURCE_DIR}/../.."
- "src/qmldom/standalone"
- )
-
- set_target_properties(qmldomlib PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>"
- LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>")
-
- extend_qtc_target(QmlDesigner
- CONDITION TARGET qmldomlib
- DEFINES QDS_HAS_QMLDOM
- DEPENDS qmldomlib
- )
-endif()
-
-
if (QTC_STATIC_BUILD AND TARGET QmlDesigner)
+ get_target_property(_designerType Qt5::Designer TYPE)
+ if (${_designerType} STREQUAL "STATIC_LIBRARY")
+ extend_qtc_target(QmlDesigner PUBLIC_DEFINES QT_DESIGNER_STATIC)
+ endif()
+ get_target_property(_designerType Qt::Designer TYPE)
+ if (${_designerType} STREQUAL "STATIC_LIBRARY")
+ extend_qtc_target(QmlDesigner PUBLIC_DEFINES QT_DESIGNER_STATIC)
+ endif()
extend_qtc_target(QmlDesigner PUBLIC_DEPENDS TextEditor)
endif()
@@ -618,6 +616,7 @@ extend_qtc_plugin(QmlDesigner
designeractionmanagerview.cpp designeractionmanagerview.h
designericons.cpp designericons.h
findimplementation.cpp findimplementation.h
+ groupitemaction.cpp groupitemaction.h
layoutingridlayout.cpp layoutingridlayout.h
modelnodecontextmenu.cpp modelnodecontextmenu.h
modelnodecontextmenu_helper.cpp modelnodecontextmenu_helper.h
@@ -625,6 +624,7 @@ extend_qtc_plugin(QmlDesigner
formatoperation.cpp formatoperation.h
navigation2d.cpp navigation2d.h
qmldesignericonprovider.cpp qmldesignericonprovider.h
+ qmleditormenu.cpp qmleditormenu.h
selectioncontext.cpp selectioncontext.h
theme.cpp theme.h
zoomaction.cpp zoomaction.h
@@ -776,6 +776,7 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/propertyeditor
SOURCES
aligndistribute.cpp aligndistribute.h
+ assetimageprovider.cpp assetimageprovider.h
colorpalettebackend.cpp colorpalettebackend.h
designerpropertymap.cpp designerpropertymap.h
fileresourcesmodel.cpp fileresourcesmodel.h
@@ -787,7 +788,6 @@ extend_qtc_plugin(QmlDesigner
gradientpresetitem.cpp gradientpresetitem.h
gradientpresetlistmodel.cpp gradientpresetlistmodel.h
propertyeditorcontextobject.cpp propertyeditorcontextobject.h
- propertyeditorimageprovider.cpp propertyeditorimageprovider.h
propertyeditorqmlbackend.cpp propertyeditorqmlbackend.h
propertyeditortransaction.cpp propertyeditortransaction.h
propertyeditorvalue.cpp propertyeditorvalue.h
@@ -842,6 +842,7 @@ extend_qtc_plugin(QmlDesigner
materialbrowserwidget.cpp materialbrowserwidget.h
materialbrowsermodel.cpp materialbrowsermodel.h
materialbrowsertexturesmodel.cpp materialbrowsertexturesmodel.h
+ materialutils.cpp materialutils.h
)
extend_qtc_plugin(QmlDesigner
@@ -914,6 +915,10 @@ extend_qtc_plugin(QmlDesigner
SOURCES
explicitimagecacheimageprovider.cpp
explicitimagecacheimageprovider.h
+ imagecacheimageresponse.cpp
+ imagecacheimageresponse.h
+ midsizeimagecacheprovider.cpp
+ midsizeimagecacheprovider.h
smallimagecacheprovider.cpp
smallimagecacheprovider.h
)
@@ -1072,6 +1077,7 @@ extend_qtc_plugin(QmlDesigner
curveeditorview.cpp curveeditorview.h
animationcurve.cpp animationcurve.h
curveeditor.cpp curveeditor.h
+ curveeditorconstants.h
curveeditortoolbar.cpp curveeditortoolbar.h
curveeditormodel.cpp curveeditormodel.h
curveeditorstyle.h
@@ -1118,6 +1124,15 @@ extend_qtc_plugin(QmlDesigner
)
extend_qtc_plugin(QmlDesigner
+ SOURCES_PREFIX components/toolbar
+ SOURCES
+ toolbar.cpp
+ toolbar.h
+ toolbarbackend.cpp
+ toolbarbackend.h
+)
+
+extend_qtc_plugin(QmlDesigner
CONDITION TARGET Nanotrace
DEPENDS Nanotrace
)
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc
index 26b4250d0a..fb4255cdf6 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc
@@ -19,5 +19,8 @@
<file>images/assets_default_128.png</file>
<file>images/asset_effectClass_128.png</file>
<file>images/asset_effectExported_128.png</file>
+ <file>images/asset_ktx.png</file>
+ <file>images/asset_ktx@2x.png</file>
+ <file>images/asset_ktx_128.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
index 6fc9bd4a26..838af4d63d 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp
@@ -7,6 +7,7 @@
#include <theme.h>
#include <utils/hdrimage.h>
+#include <utils/ktximage.h>
#include <utils/stylehelper.h>
namespace QmlDesigner {
@@ -43,13 +44,16 @@ Thumbnail AssetsLibraryIconProvider::createThumbnail(const QString &id, const QS
{
auto [pixmap, fileSize] = fetchPixmap(id, requestedSize);
QSize originalSize = pixmap.size();
- Asset::Type assetType = Asset(id).type();
+ Asset asset(id);
+ Asset::Type assetType = asset.type();
if (pixmap.isNull()) {
pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png");
if (assetType == Asset::Image)
assetType = Asset::MissingImage;
+ else if (asset.isKtxFile())
+ originalSize = KtxImage(id).dimensions();
}
if (requestedSize.isValid())
@@ -86,6 +90,10 @@ QPair<QPixmap, qint64> AssetsLibraryIconProvider::fetchPixmap(const QString &id,
qint64 size = QFileInfo(id).size();
QPixmap pixmap = HdrImage{id}.toPixmap();
return {pixmap, size};
+ } else if (asset.isKtxFile()) {
+ qint64 size = QFileInfo(id).size();
+ QString filePath = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/asset_ktx.png");
+ return {QPixmap{filePath}, size};
} else {
QString type;
if (asset.isShader())
@@ -129,12 +137,5 @@ qint64 AssetsLibraryIconProvider::fileSize(const QString &id)
return m_thumbnails.contains(id) ? m_thumbnails[id].fileSize : 0;
}
-bool AssetsLibraryIconProvider::assetIsImage(const QString &id)
-{
- return m_thumbnails.contains(id)
- ? (m_thumbnails[id].assetType == Asset::Type::Image || Asset(id).isHdrFile())
- : false;
-}
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
index b1a611d641..fb38605ea6 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h
@@ -29,7 +29,6 @@ public:
void invalidateThumbnail(const QString &id);
QSize imageSize(const QString &id);
qint64 fileSize(const QString &id);
- bool assetIsImage(const QString &id);
private:
QPixmap generateFontIcons(const QString &filePath, const QSize &requestedSize) const;
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
index 8a4a25c18d..faf4f1eb54 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
@@ -150,6 +150,12 @@ bool AssetsLibraryModel::addNewFolder(const QString &folderPath)
return dir.mkpath(iterPath);
}
+bool AssetsLibraryModel::urlPathExistsInModel(const QUrl &url) const
+{
+ QModelIndex index = indexForPath(url.toLocalFile());
+ return index.isValid();
+}
+
bool AssetsLibraryModel::deleteFolderRecursively(const QModelIndex &folderIndex)
{
auto idx = mapToSource(folderIndex);
@@ -160,52 +166,13 @@ bool AssetsLibraryModel::deleteFolderRecursively(const QModelIndex &folderIndex)
return ok;
}
-bool AssetsLibraryModel::allFilePathsAreImages(const QStringList &filePaths) const
+bool AssetsLibraryModel::allFilePathsAreTextures(const QStringList &filePaths) const
{
return Utils::allOf(filePaths, [](const QString &path) {
- return Asset(path).isImage();
+ return Asset(path).isValidTextureSource();
});
}
-QString AssetsLibraryModel::getUniqueEffectPath(const QString &parentFolder, const QString &effectName)
-{
- auto genEffectPath = [=](const QString &name) {
- return QString(parentFolder + "/" + name + ".qep");
- };
-
- QString uniqueName = effectName;
- QString path = genEffectPath(uniqueName);
- QFileInfo file{path};
-
- while (file.exists()) {
- uniqueName = getUniqueName(uniqueName);
-
- path = genEffectPath(uniqueName);
- file.setFile(path);
- }
-
- return path;
-}
-
-bool AssetsLibraryModel::createNewEffect(const QString &effectPath, bool openEffectMaker)
-{
- bool created = QFile(effectPath).open(QIODevice::WriteOnly);
-
- if (created && openEffectMaker)
- ModelNodeOperations::openEffectMaker(effectPath);
-
- return created;
-}
-
-bool AssetsLibraryModel::canCreateEffects() const
-{
-#ifdef LICENSECHECKER
- return checkLicense() == FoundLicense::enterprise;
-#else
- return true;
-#endif
-}
-
bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QString path = m_sourceFsModel->filePath(sourceParent);
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
index ff9832ee3c..f003ef2c54 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
@@ -39,6 +39,7 @@ public:
Q_INVOKABLE QList<QModelIndex> parentIndices(const QModelIndex &index) const;
Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const;
+ Q_INVOKABLE bool urlPathExistsInModel(const QUrl &url) const;
Q_INVOKABLE QString currentProjectDirPath() const;
Q_INVOKABLE QString contentDirPath() const;
Q_INVOKABLE bool requestDeleteFiles(const QStringList &filePaths);
@@ -46,12 +47,7 @@ public:
Q_INVOKABLE bool renameFolder(const QString &folderPath, const QString &newName);
Q_INVOKABLE bool addNewFolder(const QString &folderPath);
Q_INVOKABLE bool deleteFolderRecursively(const QModelIndex &folderIndex);
- Q_INVOKABLE bool allFilePathsAreImages(const QStringList &filePaths) const;
-
- Q_INVOKABLE QString getUniqueEffectPath(const QString &parentFolder, const QString &effectName);
- Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openEffectMaker = true);
-
- Q_INVOKABLE bool canCreateEffects() const;
+ Q_INVOKABLE bool allFilePathsAreTextures(const QStringList &filePaths) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
@@ -61,6 +57,8 @@ public:
bool haveFiles() const { return m_haveFiles; }
+ QString getUniqueName(const QString &oldName);
+
signals:
void directoryLoaded(const QString &path);
void rootPathChanged();
@@ -75,7 +73,6 @@ private:
void destroyBackendModel();
bool checkHaveFiles(const QModelIndex &parentIdx) const;
bool checkHaveFiles() const;
- QString getUniqueName(const QString &oldName);
QString m_searchText;
QString m_rootPath;
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp
index f9c4422989..6d6efbb5d2 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp
@@ -4,7 +4,7 @@
#include "assetslibraryview.h"
#include "assetslibrarywidget.h"
-#include "createtexture.h"
+#include "designmodecontext.h"
#include "qmldesignerplugin.h"
#include <asynchronousimagecache.h>
@@ -46,7 +46,6 @@ public:
AssetsLibraryView::AssetsLibraryView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
- , m_createTextures{this, false}
{}
AssetsLibraryView::~AssetsLibraryView()
@@ -61,36 +60,37 @@ WidgetInfo AssetsLibraryView::widgetInfo()
{
if (m_widget.isNull()) {
m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
- imageCacheData()->synchronousFontImageCache};
-
- connect(m_widget, &AssetsLibraryWidget::addTexturesRequested, this,
- [&] (const QStringList &filePaths, AddTextureMode mode) {
- executeInTransaction("AssetsLibraryView::widgetInfo", [&]() {
- m_createTextures.execute(filePaths, mode, m_sceneId);
- });
- });
+ imageCacheData()->synchronousFontImageCache,
+ this};
+
+ auto context = new Internal::AssetsLibraryContext(m_widget.data());
+ Core::ICore::addContextObject(context);
}
return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets"));
}
+void AssetsLibraryView::customNotification(const AbstractView * /*view*/,
+ const QString &identifier,
+ const QList<ModelNode> & /*nodeList*/,
+ const QList<QVariant> & /*data*/)
+{
+ if (identifier == "delete_selected_assets")
+ m_widget->deleteSelectedAssets();
+}
+
void AssetsLibraryView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
m_widget->clearSearchFilter();
- m_widget->setModel(model);
setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath());
-
- m_sceneId = model->active3DSceneId();
}
void AssetsLibraryView::modelAboutToBeDetached(Model *model)
{
AbstractView::modelAboutToBeDetached(model);
-
- m_widget->setModel(nullptr);
}
void AssetsLibraryView::setResourcePath(const QString &resourcePath)
@@ -103,7 +103,8 @@ void AssetsLibraryView::setResourcePath(const QString &resourcePath)
if (m_widget.isNull()) {
m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
- imageCacheData()->synchronousFontImageCache};
+ imageCacheData()->synchronousFontImageCache,
+ this};
}
m_widget->setResourcePath(resourcePath);
@@ -116,9 +117,4 @@ AssetsLibraryView::ImageCacheData *AssetsLibraryView::imageCacheData()
return m_imageCacheData.get();
}
-void AssetsLibraryView::active3DSceneChanged(qint32 sceneId)
-{
- m_sceneId = sceneId;
-}
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h
index d872439011..f1a408c303 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h
@@ -4,7 +4,6 @@
#pragma once
#include "abstractview.h"
-#include "createtexture.h"
#include <QPointer>
@@ -31,18 +30,18 @@ public:
void modelAboutToBeDetached(Model *model) override;
void setResourcePath(const QString &resourcePath);
- void active3DSceneChanged(qint32 sceneId) override;
private:
class ImageCacheData;
ImageCacheData *imageCacheData();
+ void customNotification(const AbstractView *view, const QString &identifier,
+ const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
+
std::once_flag imageCacheFlag;
std::unique_ptr<ImageCacheData> m_imageCacheData;
QPointer<AssetsLibraryWidget> m_widget;
QString m_lastResourcePath;
- CreateTextures m_createTextures;
- qint32 m_sceneId = -1;
};
}
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
index d2c208929c..14110cc699 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
@@ -6,26 +6,16 @@
#include "asset.h"
#include "assetslibraryiconprovider.h"
#include "assetslibrarymodel.h"
-
-#include <theme.h>
-
-#include <designeractionmanager.h>
+#include "assetslibraryview.h"
+#include "designeractionmanager.h"
#include "modelnodeoperations.h"
-#include <model.h>
-#include <navigatorwidget.h>
-#include <qmldesignerconstants.h>
-#include <qmldesignerplugin.h>
+#include "qmldesignerconstants.h"
+#include "qmldesignerplugin.h"
+#include "theme.h"
-#include <utils/algorithm.h>
-#include <utils/environment.h>
-#include <utils/fileutils.h>
-#include <utils/qtcassert.h>
-#include <utils/stylehelper.h>
-#include <utils/utilsicons.h>
-#include "utils/environment.h"
-#include "utils/filepath.h"
+#include <studioquickwidget.h>
-#include <coreplugin/coreconstants.h>
+#include <coreplugin/fileutils.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
@@ -33,21 +23,22 @@
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
-#include <QApplication>
-#include <QDrag>
+#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/filepath.h>
+#include <utils/qtcassert.h>
+
#include <QFileDialog>
#include <QFileInfo>
-#include <QFileSystemModel>
-#include <QVBoxLayout>
#include <QImageReader>
-#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
-#include <QShortcut>
-#include <QTimer>
-#include <QToolButton>
+#include <QPointF>
#include <QQmlContext>
#include <QQuickItem>
+#include <QShortcut>
+#include <QToolButton>
+#include <QVBoxLayout>
namespace QmlDesigner {
@@ -63,38 +54,50 @@ static QString propertyEditorResourcesPath()
bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FocusOut) {
- if (obj == m_assetsWidget.data())
+ if (obj == m_assetsWidget->quickWidget())
QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut");
} else if (event->type() == QMouseEvent::MouseMove) {
- if (!m_assetsToDrag.isEmpty() && !m_model.isNull()) {
+ if (!m_assetsToDrag.isEmpty() && m_assetsView->model()) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) {
QMimeData *mimeData = new QMimeData;
mimeData->setData(Constants::MIME_TYPE_ASSETS, m_assetsToDrag.join(',').toUtf8());
- m_model->startDrag(mimeData,
- m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128}));
+
+ QList<QUrl> urlsToDrag = Utils::transform(m_assetsToDrag, [](const QString &path) {
+ return QUrl::fromLocalFile(path);
+ });
+
+ mimeData->setUrls(urlsToDrag);
+
+ m_assetsView->model()->startDrag(mimeData, m_assetsIconProvider->requestPixmap(
+ m_assetsToDrag[0], nullptr, {128, 128}));
+
m_assetsToDrag.clear();
}
}
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_assetsToDrag.clear();
+ setIsDragging(false);
}
return QObject::eventFilter(obj, event);
}
AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
- SynchronousImageCache &synchronousFontImageCache)
+ SynchronousImageCache &synchronousFontImageCache,
+ AssetsLibraryView *view)
: m_itemIconSize{24, 24}
, m_fontImageCache{synchronousFontImageCache}
, m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)}
, m_assetsModel{new AssetsLibraryModel(this)}
- , m_assetsWidget{new QQuickWidget(this)}
+ , m_assetsView{view}
+ , m_createTextures{view}
+ , m_assetsWidget{new StudioQuickWidget(this)}
{
setWindowTitle(tr("Assets Library", "Title of assets library widget"));
setMinimumWidth(250);
- m_assetsWidget->installEventFilter(this);
+ m_assetsWidget->quickWidget()->installEventFilter(this);
m_fontPreviewTooltipBackend = std::make_unique<PreviewTooltipBackend>(asynchronousFontImageCache);
// We want font images to have custom size, so don't scale them in the tooltip
@@ -109,16 +112,12 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
"over the lazy dog\n"
"1234567890")});
// create assets widget
+ m_assetsWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_ASSET_LIBRARY);
m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
Theme::setupTheme(m_assetsWidget->engine());
m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider);
- m_assetsWidget->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
- {{"assetsModel"}, QVariant::fromValue(m_assetsModel)},
- {{"rootView"}, QVariant::fromValue(this)},
- {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())}
- });
connect(m_assetsModel, &AssetsLibraryModel::fileChanged, [](const QString &changeFilePath) {
QmlDesignerPlugin::instance()->emitAssetChanged(changeFilePath);
@@ -136,28 +135,135 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F6), this);
connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &AssetsLibraryWidget::reloadQmlSource);
- connect(this, &AssetsLibraryWidget::extFilesDrop, this, &AssetsLibraryWidget::handleExtFilesDrop, Qt::QueuedConnection);
+ connect(this,
+ &AssetsLibraryWidget::extFilesDrop,
+ this,
+ &AssetsLibraryWidget::handleExtFilesDrop,
+ Qt::QueuedConnection);
+
+ QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_ASSETSLIBRARY_TIME);
+
+ auto map = m_assetsWidget->registerPropertyMap("AssetsLibraryBackend");
- QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_ASSETSLIBRARY_TIME);
+ map->setProperties({{"assetsModel", QVariant::fromValue(m_assetsModel)},
+ {"rootView", QVariant::fromValue(this)},
+ {"tooltipBackend", QVariant::fromValue(m_fontPreviewTooltipBackend.get())}});
// init the first load of the QML UI elements
reloadQmlSource();
}
-bool AssetsLibraryWidget::qtVersionIsAtLeast6_4() const
+void AssetsLibraryWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
+{
+ if (m_assetsView)
+ QmlDesignerPlugin::contextHelp(callback, m_assetsView->contextHelpId());
+ else
+ callback({});
+}
+
+void AssetsLibraryWidget::deleteSelectedAssets()
{
- return (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0));
+ emit deleteSelectedAssetsRequested();
}
+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};
+
+ while (file.exists()) {
+ uniqueName = m_assetsModel->getUniqueName(uniqueName);
+
+ path = genEffectPath(uniqueName);
+ file.setFile(path);
+ }
+
+ return path;
+}
+
+bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openEffectMaker)
+{
+ bool created = QFile(effectPath).open(QIODevice::WriteOnly);
+
+ if (created && openEffectMaker) {
+ ModelNodeOperations::openEffectMaker(effectPath);
+ emit directoryCreated(QFileInfo(effectPath).absolutePath());
+ }
+
+ return created;
+}
+
+bool AssetsLibraryWidget::canCreateEffects() const
+{
+#ifdef LICENSECHECKER
+ return checkLicense() == FoundLicense::enterprise;
+#else
+ return true;
+#endif
+}
+
+void AssetsLibraryWidget::showInGraphicalShell(const QString &path)
+{
+ Core::FileUtils::showInGraphicalShell(Core::ICore::dialogParent(), Utils::FilePath::fromString(path));
+}
+
+QString AssetsLibraryWidget::showInGraphicalShellMsg() const
+{
+ return Core::FileUtils::msgGraphicalShellAction();
+}
+
+int AssetsLibraryWidget::qtVersion() const
+{
+ return QT_VERSION;
+}
void AssetsLibraryWidget::addTextures(const QStringList &filePaths)
{
- emit addTexturesRequested(filePaths, AddTextureMode::Texture);
+ m_assetsView->executeInTransaction(__FUNCTION__, [&] {
+ m_createTextures.execute(filePaths, AddTextureMode::Texture,
+ m_assetsView->model()->active3DSceneId());
+ });
}
void AssetsLibraryWidget::addLightProbe(const QString &filePath)
{
- emit addTexturesRequested({filePath}, AddTextureMode::LightProbe);
+ m_assetsView->executeInTransaction(__FUNCTION__, [&] {
+ m_createTextures.execute({filePath}, AddTextureMode::LightProbe,
+ m_assetsView->model()->active3DSceneId());
+ });
+}
+
+void AssetsLibraryWidget::updateContextMenuActionsEnableState()
+{
+ setHasMaterialLibrary(m_assetsView->materialLibraryNode().isValid()
+ && m_assetsView->model()->hasImport("QtQuick3D"));
+
+ ModelNode activeSceneEnv = m_createTextures.resolveSceneEnv(m_assetsView->model()->active3DSceneId());
+ setHasSceneEnv(activeSceneEnv.isValid());
+}
+
+void AssetsLibraryWidget::setHasMaterialLibrary(bool enable)
+{
+ if (m_hasMaterialLibrary == enable)
+ return;
+
+ m_hasMaterialLibrary = enable;
+ emit hasMaterialLibraryChanged();
+}
+
+void AssetsLibraryWidget::setHasSceneEnv(bool b)
+{
+ if (b == m_hasSceneEnv)
+ return;
+
+ m_hasSceneEnv = b;
+ emit hasSceneEnvChanged();
}
void AssetsLibraryWidget::invalidateThumbnail(const QString &id)
@@ -176,9 +282,9 @@ QString AssetsLibraryWidget::assetFileSize(const QString &id)
return QLocale::system().formattedDataSize(fileSize, 2, QLocale::DataSizeTraditionalFormat);
}
-bool AssetsLibraryWidget::assetIsImage(const QString &id)
+bool AssetsLibraryWidget::assetIsImageOrTexture(const QString &id)
{
- return m_assetsIconProvider->assetIsImage(id);
+ return Asset(id).isValidTextureSource();
}
QList<QToolButton *> AssetsLibraryWidget::createToolBarWidgets()
@@ -218,15 +324,16 @@ void AssetsLibraryWidget::handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
auto toLocalFile = [](const QUrl &url) { return url.toLocalFile(); };
QStringList simpleFilePathStrings = Utils::transform<QStringList>(simpleFilePaths, toLocalFile);
- QStringList complexFilePathStrings = Utils::transform<QStringList>(complexFilePaths,
- toLocalFile);
+ QStringList complexFilePathStrings = Utils::transform<QStringList>(complexFilePaths, toLocalFile);
if (!simpleFilePathStrings.isEmpty()) {
if (targetDirPath.isEmpty()) {
addResources(simpleFilePathStrings);
} else {
+ bool isDropOnRoot = m_assetsModel->rootPath() == targetDirPath;
AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilePathStrings,
- targetDirPath);
+ targetDirPath,
+ isDropOnRoot);
if (result.status() == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.")
@@ -237,6 +344,8 @@ void AssetsLibraryWidget::handleExtFilesDrop(const QList<QUrl> &simpleFilePaths,
if (!complexFilePathStrings.empty())
addResources(complexFilePathStrings);
+
+ m_assetsView->model()->endDrag();
}
QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
@@ -246,7 +355,7 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
QSet<QString> suffixes;
for (const AddResourceHandler &handler : handlers) {
- if (Asset(handler.filter).isSupported() != complex)
+ if (Asset::isSupported(handler.filter) != complex)
suffixes.insert(handler.filter);
}
@@ -258,18 +367,13 @@ void AssetsLibraryWidget::openEffectMaker(const QString &filePath)
ModelNodeOperations::openEffectMaker(filePath);
}
-void AssetsLibraryWidget::setModel(Model *model)
-{
- m_model = model;
-}
-
QString AssetsLibraryWidget::qmlSourcesPath()
{
#ifdef SHARE_QML_PATH
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
- return QLatin1String(SHARE_QML_PATH) + "/itemLibraryQmlSources";
+ return QLatin1String(SHARE_QML_PATH) + "/assetsLibraryQmlSources";
#endif
- return Core::ICore::resourcePath("qmldesigner/itemLibraryQmlSources").toString();
+ return Core::ICore::resourcePath("qmldesigner/assetsLibraryQmlSources").toString();
}
void AssetsLibraryWidget::clearSearchFilter()
@@ -281,7 +385,6 @@ void AssetsLibraryWidget::reloadQmlSource()
{
const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml";
QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return);
- m_assetsWidget->engine()->clearComponentCache();
m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath));
}
@@ -290,6 +393,14 @@ void AssetsLibraryWidget::updateSearch()
m_assetsModel->setSearchText(m_filterText);
}
+void AssetsLibraryWidget::setIsDragging(bool val)
+{
+ if (m_isDragging != val) {
+ m_isDragging = val;
+ emit isDraggingChanged();
+ }
+}
+
void AssetsLibraryWidget::setResourcePath(const QString &resourcePath)
{
m_assetsModel->setRootPath(resourcePath);
@@ -303,6 +414,7 @@ void AssetsLibraryWidget::startDragAsset(const QStringList &assetPaths, const QP
// active (and blocks mouse release) if mouse is released at the same spot of the drag start.
m_assetsToDrag = assetPaths;
m_dragStartPoint = mousePos.toPoint();
+ setIsDragging(true);
}
QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QString &assetPath)
@@ -351,7 +463,7 @@ static QHash<QByteArray, QStringList> allImageFormats()
return imageFormats;
}
-void AssetsLibraryWidget::addResources(const QStringList &files)
+void AssetsLibraryWidget::addResources(const QStringList &files, bool showDialog)
{
clearSearchFilter();
@@ -425,7 +537,7 @@ void AssetsLibraryWidget::addResources(const QStringList &files)
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
if (operation) {
AddFilesResult result = operation(fileNames,
- document->fileName().parentDir().toString(), true);
+ document->fileName().parentDir().toString(), showDialog);
if (result.status() == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.")
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
index 980cae69dc..90ae46010a 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
@@ -3,25 +3,25 @@
#pragma once
-#include <previewtooltip/previewtooltipbackend.h>
-
-#include "assetslibrarymodel.h"
#include "createtexture.h"
+#include "previewtooltipbackend.h"
+
+#include <coreplugin/icontext.h>
-#include <QFileIconProvider>
#include <QFrame>
-#include <QPointF>
#include <QQmlPropertyMap>
#include <QQuickWidget>
-#include <QTimer>
-#include <QToolButton>
#include <memory>
QT_BEGIN_NAMESPACE
+class QPointF;
class QShortcut;
+class QToolButton;
QT_END_NAMESPACE
+class StudioQuickWidget;
+
namespace Utils {
class QtcProcess;
}
@@ -33,6 +33,7 @@ class Model;
class AssetsLibraryIconProvider;
class AssetsLibraryModel;
+class AssetsLibraryView;
class SynchronousImageCache;
class AsynchronousImageCache;
class ImageCacheCollector;
@@ -41,12 +42,19 @@ class AssetsLibraryWidget : public QFrame
{
Q_OBJECT
+ Q_PROPERTY(bool hasMaterialLibrary MEMBER m_hasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
+ Q_PROPERTY(bool hasSceneEnv MEMBER m_hasSceneEnv NOTIFY hasSceneEnvChanged)
+
+ // 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)
+
public:
AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
- SynchronousImageCache &synchronousFontImageCache);
+ SynchronousImageCache &synchronousFontImageCache, AssetsLibraryView *view);
~AssetsLibraryWidget() = default;
QList<QToolButton *> createToolBarWidgets();
+ void contextHelp(const Core::IContext::HelpCallback &callback) const;
static QString qmlSourcesPath();
void clearSearchFilter();
@@ -55,9 +63,10 @@ public:
void updateModel();
void setResourcePath(const QString &resourcePath);
- void setModel(Model *model);
static QPair<QString, QByteArray> getAssetTypeAndData(const QString &assetPath);
+ void deleteSelectedAssets();
+
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchFilterChanged(const QString &filterText);
@@ -72,14 +81,23 @@ public:
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);
Q_INVOKABLE void openEffectMaker(const QString &filePath);
- Q_INVOKABLE bool qtVersionIsAtLeast6_4() const;
+ Q_INVOKABLE int qtVersion() const;
Q_INVOKABLE void invalidateThumbnail(const QString &id);
Q_INVOKABLE QSize imageSize(const QString &id);
Q_INVOKABLE QString assetFileSize(const QString &id);
- Q_INVOKABLE bool assetIsImage(const QString &id);
+ Q_INVOKABLE bool assetIsImageOrTexture(const QString &id);
Q_INVOKABLE void addTextures(const QStringList &filePaths);
Q_INVOKABLE void addLightProbe(const QString &filePaths);
+ Q_INVOKABLE void updateContextMenuActionsEnableState();
+
+ Q_INVOKABLE QString getUniqueEffectPath(const QString &parentFolder, const QString &effectName);
+ Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openEffectMaker = true);
+
+ Q_INVOKABLE bool canCreateEffects() const;
+
+ Q_INVOKABLE void showInGraphicalShell(const QString &path);
+ Q_INVOKABLE QString showInGraphicalShellMsg() const;
signals:
void itemActivated(const QString &itemName);
@@ -87,7 +105,11 @@ signals:
const QList<QUrl> &complexFilePaths,
const QString &targetDirPath);
void directoryCreated(const QString &path);
- void addTexturesRequested(const QStringList &filePaths, QmlDesigner::AddTextureMode mode);
+ void hasMaterialLibraryChanged();
+ void hasSceneEnvChanged();
+ void isDraggingChanged();
+ void endDrag();
+ void deleteSelectedAssetsRequested();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -95,8 +117,12 @@ protected:
private:
void reloadQmlSource();
- void addResources(const QStringList &files);
+ void addResources(const QStringList &files, bool showDialog = true);
void updateSearch();
+ void setIsDragging(bool val);
+
+ void setHasMaterialLibrary(bool enable);
+ void setHasSceneEnv(bool b);
QSize m_itemIconSize;
@@ -104,16 +130,20 @@ private:
AssetsLibraryIconProvider *m_assetsIconProvider = nullptr;
AssetsLibraryModel *m_assetsModel = nullptr;
+ AssetsLibraryView *m_assetsView = nullptr;
+ CreateTextures m_createTextures = nullptr;
- QScopedPointer<QQuickWidget> m_assetsWidget;
+ QScopedPointer<StudioQuickWidget> m_assetsWidget;
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
- QPointer<Model> m_model;
QStringList m_assetsToDrag;
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
+ bool m_hasMaterialLibrary = false;
+ bool m_hasSceneEnv = false;
+ bool m_isDragging = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx.png
new file mode 100644
index 0000000000..077b2f3d8d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx@2x.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx@2x.png
new file mode 100644
index 0000000000..3dca205a4f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx_128.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx_128.png
new file mode 100644
index 0000000000..ed897ae414
--- /dev/null
+++ b/src/plugins/qmldesigner/components/assetslibrary/images/asset_ktx_128.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp b/src/plugins/qmldesigner/components/componentcore/abstractaction.cpp
index ff3a27e9f0..559e8ea69c 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_defaultAction(new DefaultAction(description))
+ : m_pureAction(new DefaultAction(description))
{
const Utils::Icon defaultIcon({
{":/utils/images/select.png", Utils::Theme::QmlDesigner_FormEditorForegroundColor}}, Utils::Icon::MenuTintedStyle);
@@ -16,14 +16,14 @@ AbstractAction::AbstractAction(const QString &description)
action()->setIcon(defaultIcon.icon());
}
-AbstractAction::AbstractAction(DefaultAction *action)
- : m_defaultAction(action)
+AbstractAction::AbstractAction(PureActionInterface *action)
+ : m_pureAction(action)
{
}
QAction *AbstractAction::action() const
{
- return m_defaultAction.data();
+ return m_pureAction->action();
}
void AbstractAction::currentContextChanged(const SelectionContext &selectionContext)
@@ -34,12 +34,13 @@ void AbstractAction::currentContextChanged(const SelectionContext &selectionCont
void AbstractAction::updateContext()
{
- m_defaultAction->setSelectionContext(m_selectionContext);
+ m_pureAction->setSelectionContext(m_selectionContext);
if (m_selectionContext.isValid()) {
- m_defaultAction->setEnabled(isEnabled(m_selectionContext));
- m_defaultAction->setVisible(isVisible(m_selectionContext));
- if (m_defaultAction->isCheckable())
- m_defaultAction->setChecked(isChecked(m_selectionContext));
+ QAction *action = m_pureAction->action();
+ action->setEnabled(isEnabled(m_selectionContext));
+ action->setVisible(isVisible(m_selectionContext));
+ if (action->isCheckable())
+ action->setChecked(isChecked(m_selectionContext));
}
}
@@ -50,12 +51,12 @@ bool AbstractAction::isChecked(const SelectionContext &) const
void AbstractAction::setCheckable(bool checkable)
{
- m_defaultAction->setCheckable(checkable);
+ action()->setCheckable(checkable);
}
-DefaultAction *AbstractAction::defaultAction() const
+PureActionInterface *AbstractAction::pureAction() const
{
- return m_defaultAction.data();
+ return m_pureAction.data();
}
SelectionContext AbstractAction::selectionContext() const
@@ -65,6 +66,7 @@ SelectionContext AbstractAction::selectionContext() const
DefaultAction::DefaultAction(const QString &description)
: QAction(description, nullptr)
+ , PureActionInterface(this)
{
connect(this, &QAction::triggered, this, &DefaultAction::actionTriggered);
}
@@ -74,4 +76,15 @@ void DefaultAction::setSelectionContext(const SelectionContext &selectionContext
m_selectionContext = selectionContext;
}
+PureActionInterface::PureActionInterface(QAction *action)
+ : m_action(action)
+{
+
+}
+
+QAction *PureActionInterface::action()
+{
+ return m_action;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractaction.h b/src/plugins/qmldesigner/components/componentcore/abstractaction.h
index 320879e7ed..ca4cc582ce 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractaction.h
+++ b/src/plugins/qmldesigner/components/componentcore/abstractaction.h
@@ -10,7 +10,19 @@
namespace QmlDesigner {
-class QMLDESIGNERCOMPONENTS_EXPORT DefaultAction : public QAction
+class QMLDESIGNERCOMPONENTS_EXPORT PureActionInterface
+{
+public:
+ explicit PureActionInterface(QAction *action);
+ virtual ~PureActionInterface() = default;
+ virtual void setSelectionContext(const SelectionContext &selectionContext) = 0;
+ QAction *action();
+
+private:
+ QAction *m_action = nullptr;
+};
+
+class QMLDESIGNERCOMPONENTS_EXPORT DefaultAction : public QAction, public PureActionInterface
{
Q_OBJECT
@@ -19,7 +31,7 @@ public:
// virtual function instead of slot
virtual void actionTriggered([[maybe_unused]] bool enable) {}
- void setSelectionContext(const SelectionContext &selectionContext);
+ virtual void setSelectionContext(const SelectionContext &selectionContext) override;
protected:
SelectionContext m_selectionContext;
@@ -29,10 +41,10 @@ class QMLDESIGNERCOMPONENTS_EXPORT AbstractAction : public ActionInterface
{
public:
AbstractAction(const QString &description = QString());
- AbstractAction(DefaultAction *action);
+ AbstractAction(PureActionInterface *action);
QAction *action() const override final;
- DefaultAction *defaultAction() const;
+ PureActionInterface *pureAction() const;
void currentContextChanged(const SelectionContext &selectionContext) override;
@@ -46,7 +58,7 @@ protected:
SelectionContext selectionContext() const;
private:
- QScopedPointer<DefaultAction> m_defaultAction;
+ QScopedPointer<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 46067a6efe..288b8e409d 100644
--- a/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/abstractactiongroup.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "abstractactiongroup.h"
+#include "qmleditormenu.h"
#include <QMenu>
@@ -9,10 +10,14 @@ namespace QmlDesigner {
AbstractActionGroup::AbstractActionGroup(const QString &displayName) :
m_displayName(displayName),
- m_menu(new QMenu)
+ m_menu(new QmlEditorMenu)
{
m_menu->setTitle(displayName);
m_action = m_menu->menuAction();
+
+ QmlEditorMenu *qmlEditorMenu = qobject_cast<QmlEditorMenu *>(m_menu.data());
+ if (qmlEditorMenu)
+ qmlEditorMenu->setIconsVisible(false);
}
ActionInterface::Type AbstractActionGroup::type() const
diff --git a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
index 1c68fdf073..6ef8bbb6c9 100644
--- a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp
@@ -31,22 +31,8 @@ ChangeStyleWidgetAction::ChangeStyleWidgetAction(QObject *parent) : QWidgetActio
{
// The Default style was renamed to Basic in Qt 6. In Qt 6, "Default"
// will result in a platform-specific style being chosen.
- items = {
- {"Basic", "Basic", {}},
- {"Default", "Default", {}},
- {"Fusion", "Fusion", {}},
- {"Imagine", "Imagine", {}},
- {"Material Light", "Material", "Light"},
- {"Material Dark", "Material", "Dark"},
- {"Universal Light", "Universal", "Light"},
- {"Universal Dark", "Universal", "Dark"},
- {"Universal System", "Universal", "System"}
- };
- if (Utils::HostOsInfo::isMacHost())
- items.append({"macOS", "macOS", {}});
- if (Utils::HostOsInfo::isWindowsHost())
- items.append({"Windows", "Windows", {}});
+ items = getAllStyleItems();
}
void ChangeStyleWidgetAction::handleModelUpdate(const QString &style)
@@ -59,12 +45,35 @@ const QList<StyleWidgetEntry> ChangeStyleWidgetAction::styleItems() const
return items;
}
-void ChangeStyleWidgetAction::changeStyle(const QString &style)
+QList<StyleWidgetEntry> ChangeStyleWidgetAction::getAllStyleItems()
+{
+ QList<StyleWidgetEntry> items = {{"Basic", "Basic", {}},
+ {"Default", "Default", {}},
+ {"Fusion", "Fusion", {}},
+ {"Imagine", "Imagine", {}},
+ {"Material Light", "Material", "Light"},
+ {"Material Dark", "Material", "Dark"},
+ {"Universal Light", "Universal", "Light"},
+ {"Universal Dark", "Universal", "Dark"},
+ {"Universal System", "Universal", "System"}};
+
+ if (Utils::HostOsInfo::isMacHost())
+ items.append({"macOS", "macOS", {}});
+ if (Utils::HostOsInfo::isWindowsHost())
+ items.append({"Windows", "Windows", {}});
+
+ return items;
+}
+
+void ChangeStyleWidgetAction::changeCurrentStyle(const QString &style, const QString &qmlFileName)
{
if (style.isEmpty())
return;
- const Utils::FilePath configFileName = Utils::FilePath::fromString(styleConfigFileName(qmlFileName));
+ auto items = getAllStyleItems();
+
+ const Utils::FilePath configFileName = Utils::FilePath::fromString(
+ styleConfigFileName(qmlFileName));
if (configFileName.exists()) {
QSettings infiFile(configFileName.toString(), QSettings::IniFormat);
@@ -86,14 +95,39 @@ void ChangeStyleWidgetAction::changeStyle(const QString &style)
if (!styleTheme.isEmpty())
infiFile.setValue((styleName + "/Theme"), styleTheme);
- }
- else {
+ } else {
infiFile.setValue("Controls/Style", style);
}
+ }
+}
- if (view)
- view->resetPuppet();
+int ChangeStyleWidgetAction::getCurrentStyle(const QString &fileName)
+{
+ const QString confFileName = styleConfigFileName(fileName);
+
+ if (Utils::FilePath::fromString(confFileName).exists()) {
+ QSettings infiFile(confFileName, QSettings::IniFormat);
+ const QString styleName = infiFile.value("Controls/Style", "Basic").toString();
+ const QString styleTheme = infiFile.value(styleName + "/Theme", "").toString();
+ const auto items = getAllStyleItems();
+
+ int i = 0;
+ for (const auto &item : items) {
+ if (item.styleName == styleName && item.styleTheme == styleTheme)
+ return i;
+ ++i;
+ }
}
+
+ return 0;
+}
+
+void ChangeStyleWidgetAction::handleStyleChanged(const QString &style)
+{
+ changeCurrentStyle(style, qmlFileName);
+
+ if (view)
+ view->resetPuppet();
}
const char enabledTooltip[] = QT_TRANSLATE_NOOP("ChangeStyleWidgetAction",
@@ -134,8 +168,7 @@ QWidget *ChangeStyleWidgetAction::createWidget(QWidget *parent)
}
});
- connect(comboBox, &QComboBox::textActivated,
- this, &ChangeStyleWidgetAction::changeStyle);
+ connect(comboBox, &QComboBox::textActivated, this, &ChangeStyleWidgetAction::handleStyleChanged);
return comboBox;
}
diff --git a/src/plugins/qmldesigner/components/componentcore/changestyleaction.h b/src/plugins/qmldesigner/components/componentcore/changestyleaction.h
index 3d8d1c7eaa..673c591c20 100644
--- a/src/plugins/qmldesigner/components/componentcore/changestyleaction.h
+++ b/src/plugins/qmldesigner/components/componentcore/changestyleaction.h
@@ -44,8 +44,14 @@ public:
const QList<StyleWidgetEntry> styleItems() const;
+ static QList<StyleWidgetEntry> getAllStyleItems();
+
+ static void changeCurrentStyle(const QString &style, const QString &qmlFileName);
+
+ static int getCurrentStyle(const QString &fileName);
+
public slots:
- void changeStyle(const QString &style);
+ void handleStyleChanged(const QString &style);
protected:
QWidget *createWidget(QWidget *parent) override;
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
index e7df0ab9b4..5644648336 100644
--- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
+++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h
@@ -66,7 +66,6 @@ const char layoutFillHeightCommandId[] = "LayoutFillHeight";
const char goIntoComponentCommandId[] = "GoIntoComponent";
const char mergeTemplateCommandId[] = "MergeTemplate";
const char goToImplementationCommandId[] = "GoToImplementation";
-const char addSignalHandlerCommandId[] = "AddSignalHandler";
const char makeComponentCommandId[] = "MakeComponent";
const char editMaterialCommandId[] = "EditMaterial";
const char addItemToStackedContainerCommandId[] = "AddItemToStackedContainer";
@@ -76,7 +75,6 @@ const char decreaseIndexOfStackedContainerCommandId[] = "DecreaseIndexOfStackedC
const char flowAssignEffectCommandId[] = "AssignFlowEffect";
const char flowAssignCustomEffectCommandId[] = "AssignFlowCustomEffect";
const char addToGroupItemCommandId[] = "AddToGroupItem";
-const char removeGroupItemCommandId[] = "RemoveToGroupItem";
const char fitRootToScreenCommandId[] = "FitRootToScreen";
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
const char editAnnotationsCommandId[] = "EditAnnotation";
@@ -121,11 +119,10 @@ const char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMen
const char copyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy Formatting");
const char applyFormatDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Apply Formatting");
-const char enterComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Enter Component");
+const char enterComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Component");
const char mergeTemplateDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Merge with Template");
const char goToImplementationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go to Implementation");
-const char addSignalHandlerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add New Signal Handler");
-const char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Make Component");
+const char makeComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Create Component");
const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material");
const char editAnnotationsDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotations");
const char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Mouse Area");
diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
index b752729555..f4b6697c86 100644
--- a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
@@ -6,6 +6,7 @@
#include "qmldesignerplugin.h"
#include <nodeabstractproperty.h>
+#include <toolbar.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/idocument.h>
@@ -60,6 +61,7 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName)
{
if (!m_isInternalCalled) {
crumblePath()->clear();
+ m_pathes.clear();
} else {
// If the path already exists in crumblePath, pop up to first instance of that to avoid
// cyclical crumblePath
@@ -71,8 +73,10 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName)
}
if (match != -1) {
- for (int i = crumblePath()->length() - 1 - match; i > 0; --i)
+ for (int i = crumblePath()->length() - 1 - match; i > 0; --i) {
crumblePath()->popElement();
+ m_pathes.removeLast();
+ }
}
}
@@ -81,10 +85,13 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName)
CrumbleBarInfo crumbleBarInfo;
crumbleBarInfo.fileName = fileName;
crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo));
+ m_pathes.append({fileName, fileName.fileName(), {}});
}
m_isInternalCalled = false;
updateVisibility();
+
+ emit pathChanged();
}
void CrumbleBar::pushInFileComponent(const ModelNode &modelNode)
@@ -97,10 +104,13 @@ void CrumbleBar::pushInFileComponent(const ModelNode &modelNode)
crumblePath()->popElement();
crumblePath()->pushElement(crumbleBarInfo.displayName, QVariant::fromValue(crumbleBarInfo));
+ m_pathes.append({{}, crumbleBarInfo.displayName, modelNode});
m_isInternalCalled = false;
updateVisibility();
+
+ emit pathChanged();
}
void CrumbleBar::nextFileIsCalledInternally()
@@ -120,6 +130,21 @@ Utils::CrumblePath *CrumbleBar::crumblePath()
return m_crumblePath;
}
+QStringList CrumbleBar::path() const
+{
+ QStringList list;
+ for (auto &path : m_pathes) {
+ list.append(path.displayName);
+ }
+
+ return list;
+}
+
+QList<CrumbleBarInfo> CrumbleBar::infos() const
+{
+ return m_pathes;
+}
+
bool CrumbleBar::showSaveDialog()
{
bool canceled = false;
@@ -151,11 +176,15 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
if (!inlineComp && !showSaveDialog())
return;
- while (clickedCrumbleBarInfo != crumblePath()->dataForLastIndex().value<CrumbleBarInfo>())
+ while (clickedCrumbleBarInfo != crumblePath()->dataForLastIndex().value<CrumbleBarInfo>()) {
crumblePath()->popElement();
+ m_pathes.removeLast();
+ }
- if (crumblePath()->dataForLastIndex().value<CrumbleBarInfo>().modelNode.isValid())
+ if (crumblePath()->dataForLastIndex().value<CrumbleBarInfo>().modelNode.isValid()) {
crumblePath()->popElement();
+ m_pathes.removeLast();
+ }
m_isInternalCalled = true;
if (inlineComp) {
@@ -164,6 +193,7 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster();
} else {
crumblePath()->popElement();
+ m_pathes.removeLast();
nextFileIsCalledInternally();
Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName,
Utils::Id(),
@@ -175,12 +205,14 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data)
QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster();
}
}
+ emit pathChanged();
updateVisibility();
}
void CrumbleBar::updateVisibility()
{
- crumblePath()->setVisible(crumblePath()->length() > 1);
+ if (!ToolBar::isVisible())
+ crumblePath()->setVisible(crumblePath()->length() > 1);
}
bool operator ==(const CrumbleBarInfo &first, const CrumbleBarInfo &second)
diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.h b/src/plugins/qmldesigner/components/componentcore/crumblebar.h
index 232d8237d7..b9da4488f6 100644
--- a/src/plugins/qmldesigner/components/componentcore/crumblebar.h
+++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.h
@@ -10,6 +10,24 @@
namespace QmlDesigner {
+class CrumbleBarInfo {
+public:
+
+ CrumbleBarInfo() = default;
+
+ CrumbleBarInfo(Utils::FilePath f,
+ QString d,
+ ModelNode m) :
+ fileName(f),
+ displayName(d),
+ modelNode(m)
+ {}
+
+ Utils::FilePath fileName;
+ QString displayName;
+ ModelNode modelNode;
+};
+
class CrumbleBar : public QObject
{
Q_OBJECT
@@ -24,21 +42,23 @@ public:
Utils::CrumblePath *crumblePath();
-private:
+ QStringList path() const;
+
+ QList<CrumbleBarInfo> infos() const;
+
void onCrumblePathElementClicked(const QVariant &data);
+
+signals:
+ void pathChanged();
+
+private:
void updateVisibility();
bool showSaveDialog();
private:
bool m_isInternalCalled = false;
Utils::CrumblePath *m_crumblePath = nullptr;
-};
-
-class CrumbleBarInfo {
-public:
- Utils::FilePath fileName;
- QString displayName;
- ModelNode modelNode;
+ QList<CrumbleBarInfo> m_pathes;
};
bool operator ==(const CrumbleBarInfo &first, const CrumbleBarInfo &second);
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
index 535703ac5f..77976993e4 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp
@@ -9,8 +9,10 @@
#include "designericons.h"
#include "designermcumanager.h"
#include "formatoperation.h"
+#include "groupitemaction.h"
#include "modelnodecontextmenu_helper.h"
#include "qmldesignerconstants.h"
+#include "qmleditormenu.h"
#include "rewritingexception.h"
#include <bindingproperty.h>
#include <nodehints.h>
@@ -112,12 +114,14 @@ void DesignerActionManager::polishActions() const
Core::Context qmlDesignerEditor3DContext(Constants::C_QMLEDITOR3D);
Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR);
Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER);
+ Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY);
Core::Context qmlDesignerUIContext;
qmlDesignerUIContext.add(qmlDesignerFormEditorContext);
qmlDesignerUIContext.add(qmlDesignerEditor3DContext);
qmlDesignerUIContext.add(qmlDesignerNavigatorContext);
qmlDesignerUIContext.add(qmlDesignerMaterialBrowserContext);
+ qmlDesignerUIContext.add(qmlDesignerAssetsLibraryContext);
for (auto *action : actions) {
if (!action->menuId().isEmpty()) {
@@ -233,7 +237,7 @@ ModelNodePreviewImageOperation DesignerActionManager::modelNodePreviewOperation(
bool DesignerActionManager::externalDragHasSupportedAssets(const QMimeData *mimeData) const
{
- if (!mimeData->hasUrls())
+ if (!mimeData->hasUrls() || mimeData->hasFormat(Constants::MIME_TYPE_ASSETS))
return false;
QSet<QString> filtersSet;
@@ -292,6 +296,11 @@ QIcon DesignerActionManager::contextIcon(int contextId) const
return m_designerIcons->icon(DesignerIcons::IconId(contextId), DesignerIcons::ContextMenuArea);
}
+void DesignerActionManager::addAddActionCallback(ActionAddedInterface callback)
+{
+ m_callBacks.append(callback);
+}
+
class VisiblityModelNodeAction : public ModelNodeContextMenuAction
{
public:
@@ -304,17 +313,17 @@ public:
void updateContext() override
{
- defaultAction()->setSelectionContext(selectionContext());
+ pureAction()->setSelectionContext(selectionContext());
if (selectionContext().isValid()) {
- defaultAction()->setEnabled(isEnabled(selectionContext()));
- defaultAction()->setVisible(isVisible(selectionContext()));
+ action()->setEnabled(isEnabled(selectionContext()));
+ action()->setVisible(isVisible(selectionContext()));
- defaultAction()->setCheckable(true);
+ action()->setCheckable(true);
QmlItemNode itemNode = QmlItemNode(selectionContext().currentSingleSelectedNode());
if (itemNode.isValid())
- defaultAction()->setChecked(itemNode.instanceValue("visible").toBool());
+ action()->setChecked(itemNode.instanceValue("visible").toBool());
else
- defaultAction()->setEnabled(false);
+ action()->setEnabled(false);
}
}
};
@@ -330,12 +339,12 @@ public:
{}
void updateContext() override
{
- defaultAction()->setSelectionContext(selectionContext());
+ pureAction()->setSelectionContext(selectionContext());
if (selectionContext().isValid()) {
- defaultAction()->setEnabled(isEnabled(selectionContext()));
- defaultAction()->setVisible(isVisible(selectionContext()));
+ action()->setEnabled(isEnabled(selectionContext()));
+ action()->setVisible(isVisible(selectionContext()));
- defaultAction()->setCheckable(true);
+ action()->setCheckable(true);
QmlItemNode itemNode = QmlItemNode(selectionContext().currentSingleSelectedNode());
if (itemNode.isValid()) {
bool flag = false;
@@ -343,9 +352,9 @@ public:
|| itemNode.propertyAffectedByCurrentState(m_propertyName)) {
flag = itemNode.modelValue(m_propertyName).toBool();
}
- defaultAction()->setChecked(flag);
+ action()->setChecked(flag);
} else {
- defaultAction()->setEnabled(false);
+ action()->setEnabled(false);
}
}
}
@@ -578,10 +587,15 @@ QList<SlotList> getSlotsLists(const ModelNode &node)
ModelNode createNewConnection(ModelNode targetNode)
{
NodeMetaInfo connectionsMetaInfo = targetNode.view()->model()->qtQuickConnectionsMetaInfo();
- ModelNode newConnectionNode = targetNode.view()->createModelNode(
- "QtQuick.Connections", connectionsMetaInfo.majorVersion(), connectionsMetaInfo.minorVersion());
- if (QmlItemNode::isValidQmlItemNode(targetNode))
+ ModelNode newConnectionNode = targetNode.view()->createModelNode(connectionsMetaInfo.typeName(),
+ connectionsMetaInfo.majorVersion(),
+ connectionsMetaInfo.minorVersion());
+ if (QmlItemNode::isValidQmlItemNode(targetNode)) {
targetNode.nodeAbstractProperty("data").reparentHere(newConnectionNode);
+ } else {
+ targetNode.view()->rootModelNode().defaultNodeAbstractProperty().reparentHere(
+ newConnectionNode);
+ }
newConnectionNode.bindingProperty("target").setExpression(targetNode.id());
@@ -648,11 +662,11 @@ public:
const QString propertyName = QString::fromUtf8(signalHandler.name());
- QMenu *activeSignalHandlerGroup = new QMenu(propertyName, menu());
+ QMenu *activeSignalHandlerGroup = new QmlEditorMenu(propertyName, menu());
- QMenu *editSignalGroup = new QMenu(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
- "Change Signal"),
- menu());
+ QMenu *editSignalGroup = new QmlEditorMenu(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
+ "Change Signal"),
+ menu());
for (const auto &signalStr : signalsList) {
if (prependSignal(signalStr).toUtf8() == signalHandler.name())
@@ -679,9 +693,9 @@ public:
activeSignalHandlerGroup->addMenu(editSignalGroup);
if (!slotsLists.isEmpty()) {
- QMenu *editSlotGroup = new QMenu(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
- "Change Slot"),
- menu());
+ QMenu *editSlotGroup = new QmlEditorMenu(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
+ "Change Slot"),
+ menu());
if (slotsLists.size() == 1) {
for (const auto &slot : slotsLists.at(0).slotEntries) {
@@ -701,7 +715,7 @@ public:
}
} else {
for (const auto &slotCategory : slotsLists) {
- QMenu *slotCategoryMenu = new QMenu(slotCategory.categoryName, menu());
+ QMenu *slotCategoryMenu = new QmlEditorMenu(slotCategory.categoryName, menu());
for (const auto &slot : slotCategory.slotEntries) {
ActionTemplate *newSlotAction = new ActionTemplate(
(slot.name + "Id").toLatin1(),
@@ -754,12 +768,12 @@ public:
}
//singular add connection:
- QMenu *addConnection = new QMenu(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
- "Add Signal Handler")),
- menu());
+ QMenu *addConnection = new QmlEditorMenu(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu",
+ "Add Signal Handler")),
+ menu());
for (const auto &signalStr : signalsList) {
- QMenu *newSignal = new QMenu(signalStr, addConnection);
+ QMenu *newSignal = new QmlEditorMenu(signalStr, addConnection);
if (!slotsLists.isEmpty()) {
if (slotsLists.size() == 1) {
@@ -782,7 +796,7 @@ public:
}
} else {
for (const auto &slotCategory : slotsLists) {
- QMenu *slotCategoryMenu = new QMenu(slotCategory.categoryName, menu());
+ QMenu *slotCategoryMenu = new QmlEditorMenu(slotCategory.categoryName, menu());
for (const auto &slot : slotCategory.slotEntries) {
ActionTemplate *newSlot = new ActionTemplate(
QString(signalStr + slot.name + "Id").toLatin1(),
@@ -1328,6 +1342,26 @@ bool anchorsMenuEnabled(const SelectionContext &context)
|| singleSelectionItemIsAnchored(context);
}
+static QIcon createResetIcon(const QStringList &basicIconAddresses)
+{
+ using namespace Utils;
+ static const IconMaskAndColor resetMask({":/utils/images/iconoverlay_reset.png",
+ Theme::IconsStopToolBarColor});
+ QList<IconMaskAndColor> iconMaskList = transform(basicIconAddresses, [=] (const QString &refAddr) {
+ return IconMaskAndColor(
+ FilePath::fromString(refAddr),
+ Theme::IconsBaseColor);
+ });
+
+ QIcon finalIcon = Icon(iconMaskList).icon();
+ iconMaskList.append(resetMask);
+ QIcon finalOn = Icon(iconMaskList).icon();
+ for (const QSize &iSize : finalIcon.availableSizes()) {
+ for (const QIcon::Mode &mode : {QIcon::Normal, QIcon::Disabled, QIcon::Active, QIcon::Selected})
+ finalIcon.addPixmap(finalOn.pixmap(iSize, mode, QIcon::On), mode, QIcon::On);
+ }
+ return finalIcon;
+}
void DesignerActionManager::createDefaultDesignerActions()
{
@@ -1364,7 +1398,7 @@ void DesignerActionManager::createDefaultDesignerActions()
Priorities::ArrangeCategory,
&selectionNotEmpty));
- addDesignerAction(new SeperatorDesignerAction(arrangeCategory, 10));
+ addDesignerAction(new SeparatorDesignerAction(arrangeCategory, 10));
addDesignerAction(new ModelNodeContextMenuAction(
toFrontCommandId,
@@ -1379,7 +1413,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ModelNodeContextMenuAction(
raiseCommandId,
raiseDisplayName,
- Utils::Icon({{":/qmldesigner/icon/designeractions/images/raise.png", Utils::Theme::IconsBaseColor}}).icon(),
+ {},
arrangeCategory,
QKeySequence(),
11,
@@ -1389,7 +1423,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ModelNodeContextMenuAction(
lowerCommandId,
lowerDisplayName,
- Utils::Icon({{":/qmldesigner/icon/designeractions/images/lower.png", Utils::Theme::IconsBaseColor}}).icon(),
+ {},
arrangeCategory,
QKeySequence(),
12,
@@ -1406,7 +1440,7 @@ void DesignerActionManager::createDefaultDesignerActions()
&toBack,
&lowerAvailable));
- addDesignerAction(new SeperatorDesignerAction(arrangeCategory, 20));
+ addDesignerAction(new SeparatorDesignerAction(arrangeCategory, 20));
addDesignerAction(new ModelNodeContextMenuAction(
reverseCommandId,
@@ -1424,75 +1458,45 @@ void DesignerActionManager::createDefaultDesignerActions()
Priorities::EditCategory,
&selectionNotEmpty));
- addDesignerAction(new SeperatorDesignerAction(editCategory, 30));
-
- addDesignerAction(
- new ModelNodeAction(resetPositionCommandId,
- resetPositionDisplayName,
- Utils::Icon({{":/utils/images/pan.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png",
- Utils::Theme::IconsStopToolBarColor}})
- .icon(),
- resetPositionTooltip,
- editCategory,
- QKeySequence("Ctrl+d"),
- 32,
- &resetPosition,
- &selectionNotEmptyAndHasXorYProperty));
-
- const QString fontName = "qtds_propertyIconFont.ttf";
- const QColor iconColorDefault(Theme::getColor(Theme::IconsBaseColor));
- const QColor iconColorDisabled(Theme::getColor(Theme::IconsDisabledColor));
- const QString copyUnicode = Theme::getIconUnicode(Theme::Icon::copyStyle);
- const QString pasteUnicode = Theme::getIconUnicode(Theme::Icon::pasteStyle);
-
- const auto copyDefault = Utils::StyleHelper::IconFontHelper(copyUnicode,
- iconColorDefault,
- QSize(28, 28),
- QIcon::Normal);
- const auto copyDisabled = Utils::StyleHelper::IconFontHelper(copyUnicode,
- iconColorDisabled,
- QSize(28, 28),
- QIcon::Disabled);
- const QIcon copyIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
- {copyDefault, copyDisabled});
-
- const auto pasteDefault = Utils::StyleHelper::IconFontHelper(pasteUnicode,
- iconColorDefault,
- QSize(28, 28),
- QIcon::Normal);
- const auto pasteDisabled = Utils::StyleHelper::IconFontHelper(pasteUnicode,
- iconColorDisabled,
- QSize(28, 28),
- QIcon::Disabled);
- const QIcon pasteIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
- {pasteDefault, pasteDisabled});
-
- addDesignerAction(new ModelNodeAction(copyFormatCommandId,
- copyFormatDisplayName,
- copyIcon,
- copyFormatTooltip,
- editCategory,
- QKeySequence(),
- 41,
- &copyFormat,
- &propertiesCopyable));
-
- addDesignerAction(new ModelNodeAction(applyFormatCommandId,
- applyFormatDisplayName,
- pasteIcon,
- applyFormatTooltip,
- editCategory,
- QKeySequence(),
- 42,
- &applyFormat,
- &propertiesApplyable));
+ addDesignerAction(new SeparatorDesignerAction(editCategory, 30));
+
+ addDesignerAction(new ModelNodeAction(
+ resetPositionCommandId,
+ resetPositionDisplayName,
+ createResetIcon({":/utils/images/pan.png"}),
+ resetPositionTooltip,
+ editCategory,
+ QKeySequence("Ctrl+d"),
+ 32,
+ &resetPosition,
+ &selectionNotEmptyAndHasXorYProperty));
+
+ addDesignerAction(new ModelNodeAction(
+ copyFormatCommandId,
+ copyFormatDisplayName,
+ contextIcon(DesignerIcons::CopyIcon),
+ copyFormatTooltip,
+ editCategory,
+ QKeySequence(),
+ 41,
+ &copyFormat,
+ &propertiesCopyable));
+
+ addDesignerAction(new ModelNodeAction(
+ applyFormatCommandId,
+ applyFormatDisplayName,
+ contextIcon(DesignerIcons::PasteIcon),
+ applyFormatTooltip,
+ editCategory,
+ QKeySequence(),
+ 42,
+ &applyFormat,
+ &propertiesApplyable));
addDesignerAction(new ModelNodeAction(
resetSizeCommandId,
resetSizeDisplayName,
- Utils::Icon({{":/utils/images/fittoview.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png", Utils::Theme::IconsStopToolBarColor}}).icon(),
+ createResetIcon({":/utils/images/fittoview.png"}),
resetSizeToolTip,
editCategory,
QKeySequence("shift+s"),
@@ -1500,7 +1504,7 @@ void DesignerActionManager::createDefaultDesignerActions()
&resetSize,
&selectionNotEmptyAndHasWidthOrHeightProperty));
- addDesignerAction(new SeperatorDesignerAction(editCategory, 40));
+ addDesignerAction(new SeparatorDesignerAction(editCategory, 40));
addDesignerAction(new VisiblityModelNodeAction(
visiblityCommandId,
@@ -1541,12 +1545,13 @@ void DesignerActionManager::createDefaultDesignerActions()
&anchorsReset,
&singleSelectionItemIsAnchored));
- addDesignerAction(new SeperatorDesignerAction(anchorsCategory, 10));
+ addDesignerAction(new SeparatorDesignerAction(anchorsCategory, 10));
addDesignerAction(new ParentAnchorAction(
anchorParentTopAndBottomCommandId,
anchorParentTopAndBottomDisplayName,
- {},
+ createResetIcon({":/qmldesigner/images/anchor_top.png",
+ ":/qmldesigner/images/anchor_bottom.png"}),
{},
anchorsCategory,
QKeySequence(),
@@ -1556,20 +1561,20 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ParentAnchorAction(
anchorParentLeftAndRightCommandId,
anchorParentLeftAndRightDisplayName,
- {},
+ createResetIcon({":/qmldesigner/images/anchor_left.png",
+ ":/qmldesigner/images/anchor_right.png"}),
{},
anchorsCategory,
QKeySequence(),
12,
AnchorLineType(AnchorLineLeft | AnchorLineRight)));
- addDesignerAction(new SeperatorDesignerAction(anchorsCategory, 20));
+ addDesignerAction(new SeparatorDesignerAction(anchorsCategory, 20));
addDesignerAction(new ParentAnchorAction(
anchorParentTopCommandId,
anchorParentTopDisplayName,
- Utils::Icon({{":/qmldesigner/images/anchor_top.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png", Utils::Theme::IconsStopToolBarColor}}).icon(),
+ createResetIcon({":/qmldesigner/images/anchor_top.png"}),
{},
anchorsCategory,
QKeySequence(),
@@ -1579,8 +1584,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ParentAnchorAction(
anchorParentBottomCommandId,
anchorParentBottomDisplayName,
- Utils::Icon({{":/qmldesigner/images/anchor_bottom.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png", Utils::Theme::IconsStopToolBarColor}}).icon(),
+ createResetIcon({":/qmldesigner/images/anchor_bottom.png"}),
{},
anchorsCategory,
QKeySequence(),
@@ -1590,8 +1594,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ParentAnchorAction(
anchorParentLeftCommandId,
anchorParentLeftDisplayName,
- Utils::Icon({{":/qmldesigner/images/anchor_left.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png", Utils::Theme::IconsStopToolBarColor}}).icon(),
+ createResetIcon({":/qmldesigner/images/anchor_left.png"}),
{},
anchorsCategory,
QKeySequence(),
@@ -1601,8 +1604,7 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ParentAnchorAction(
anchorParentRightCommandId,
anchorParentRightDisplayName,
- Utils::Icon({{":/qmldesigner/images/anchor_right.png", Utils::Theme::IconsBaseColor},
- {":/utils/images/iconoverlay_reset.png", Utils::Theme::IconsStopToolBarColor}}).icon(),
+ createResetIcon({":/qmldesigner/images/anchor_right.png"}),
{},
anchorsCategory,
QKeySequence(),
@@ -1631,12 +1633,10 @@ void DesignerActionManager::createDefaultDesignerActions()
&selectionEnabled,
&selectionEnabled));
- addDesignerAction(new ActionGroup(
- groupCategoryDisplayName,
- groupCategory,
+ addDesignerAction(new GroupItemAction(
contextIcon(DesignerIcons::GroupSelectionIcon),
- Priorities::Group,
- &studioComponentsAvailableAndSelectionCanBeLayouted));
+ {},
+ Priorities::Group));
addDesignerAction(new ActionGroup(
flowCategoryDisplayName,
@@ -1659,16 +1659,16 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(effectMenu);
addDesignerAction(new ModelNodeFormEditorAction(
- createFlowActionAreaCommandId,
- createFlowActionAreaDisplayName,
- addIcon.icon(),
- addFlowActionToolTip,
- flowCategory,
- {},
- 1,
- &createFlowActionArea,
- &isFlowItem,
- &flowOptionVisible));
+ createFlowActionAreaCommandId,
+ createFlowActionAreaDisplayName,
+ addIcon.icon(),
+ addFlowActionToolTip,
+ flowCategory,
+ {},
+ 1,
+ &createFlowActionArea,
+ &isFlowItem,
+ &flowOptionVisible));
addDesignerAction(new ModelNodeContextMenuAction(
setFlowStartCommandId,
@@ -1699,20 +1699,21 @@ void DesignerActionManager::createDefaultDesignerActions()
addCustomTransitionEffectAction();
addDesignerAction(new ModelNodeContextMenuAction(
- selectFlowEffectCommandId,
- selectEffectDisplayName,
- {},
- flowCategory,
- {},
- 2,
- &selectFlowEffect,
- &isFlowTransitionItemWithEffect));
+ selectFlowEffectCommandId,
+ selectEffectDisplayName,
+ {},
+ flowCategory,
+ {},
+ 2,
+ &selectFlowEffect,
+ &isFlowTransitionItemWithEffect));
addDesignerAction(new ActionGroup(
stackedContainerCategoryDisplayName,
stackedContainerCategory,
- {},
+ addIcon.icon(),
Priorities::StackedContainerCategory,
+ &isStackedContainer,
&isStackedContainer));
addDesignerAction(new ModelNodeContextMenuAction(
@@ -1770,7 +1771,7 @@ void DesignerActionManager::createDefaultDesignerActions()
&selectionCanBeLayouted,
&selectionCanBeLayouted));
- addDesignerAction(new SeperatorDesignerAction(layoutCategory, 0));
+ addDesignerAction(new SeparatorDesignerAction(layoutCategory, 0));
addDesignerAction(new ModelNodeContextMenuAction(
removeLayoutCommandId,
@@ -1783,34 +1784,17 @@ void DesignerActionManager::createDefaultDesignerActions()
&isLayout,
&isLayout));
- addDesignerAction(new ModelNodeContextMenuAction(addToGroupItemCommandId,
- addToGroupItemDisplayName,
- {},
- groupCategory,
- QKeySequence("Ctrl+Shift+g"),
- 1,
- &addToGroupItem,
- &selectionCanBeLayouted));
-
- addDesignerAction(new ModelNodeContextMenuAction(removeGroupItemCommandId,
- removeGroupItemDisplayName,
- {},
- groupCategory,
- QKeySequence(),
- 2,
- &removeGroup,
- &isGroup));
-
- addDesignerAction(new ModelNodeFormEditorAction(addItemToStackedContainerCommandId,
- addItemToStackedContainerDisplayName,
- addIcon.icon(),
- addItemToStackedContainerToolTip,
- stackedContainerCategory,
- QKeySequence("Ctrl+Shift+a"),
- 1,
- &addItemToStackedContainer,
- &isStackedContainer,
- &isStackedContainer));
+ addDesignerAction(new ModelNodeFormEditorAction(
+ addItemToStackedContainerCommandId,
+ addItemToStackedContainerDisplayName,
+ addIcon.icon(),
+ addItemToStackedContainerToolTip,
+ stackedContainerCategory,
+ QKeySequence("Ctrl+Shift+a"),
+ 1,
+ &addItemToStackedContainer,
+ &isStackedContainer,
+ &isStackedContainer));
addDesignerAction(new ModelNodeContextMenuAction(
addTabBarToStackedContainerCommandId,
@@ -1850,7 +1834,8 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ModelNodeAction(
layoutRowLayoutCommandId,
layoutRowLayoutDisplayName,
- Utils::Icon({{":/qmldesigner/icon/designeractions/images/row.png", Utils::Theme::IconsBaseColor}}).icon(),
+ Utils::Icon({{":/qmldesigner/icon/designeractions/images/row.png",
+ Utils::Theme::IconsBaseColor}}).icon(),
layoutRowLayoutToolTip,
layoutCategory,
QKeySequence("Ctrl+u"),
@@ -1861,7 +1846,8 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ModelNodeAction(
layoutColumnLayoutCommandId,
layoutColumnLayoutDisplayName,
- Utils::Icon({{":/qmldesigner/icon/designeractions/images/column.png", Utils::Theme::IconsBaseColor}}).icon(),
+ Utils::Icon({{":/qmldesigner/icon/designeractions/images/column.png",
+ Utils::Theme::IconsBaseColor}}).icon(),
layoutColumnLayoutToolTip,
layoutCategory,
QKeySequence("Ctrl+l"),
@@ -1872,7 +1858,8 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new ModelNodeAction(
layoutGridLayoutCommandId,
layoutGridLayoutDisplayName,
- Utils::Icon({{":/qmldesigner/icon/designeractions/images/grid.png", Utils::Theme::IconsBaseColor}}).icon(),
+ Utils::Icon({{":/qmldesigner/icon/designeractions/images/grid.png",
+ Utils::Theme::IconsBaseColor}}).icon(),
layoutGridLayoutToolTip,
layoutCategory,
QKeySequence("shift+g"),
@@ -1880,7 +1867,7 @@ void DesignerActionManager::createDefaultDesignerActions()
&layoutGridLayout,
&selectionCanBeLayoutedAndQtQuickLayoutPossibleAndNotMCU));
- addDesignerAction(new SeperatorDesignerAction(layoutCategory, 10));
+ addDesignerAction(new SeparatorDesignerAction(layoutCategory, 10));
addDesignerAction(new FillWidthModelNodeAction(
layoutFillWidthCommandId,
@@ -1902,12 +1889,12 @@ void DesignerActionManager::createDefaultDesignerActions()
&singleSelectionAndInQtQuickLayout,
&singleSelectionAndInQtQuickLayout));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::ModifySection));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::PositionSection));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::EventSection));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::AdditionsSection));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::ViewOprionsSection));
- addDesignerAction(new SeperatorDesignerAction(rootCategory, Priorities::CustomActionsSection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::ModifySection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::PositionSection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::EventSection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::AdditionsSection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::ViewOprionsSection));
+ addDesignerAction(new SeparatorDesignerAction(rootCategory, Priorities::CustomActionsSection));
addDesignerAction(new ModelNodeContextMenuAction(
goIntoComponentCommandId,
@@ -1956,15 +1943,6 @@ void DesignerActionManager::createDefaultDesignerActions()
}
addDesignerAction(new ModelNodeContextMenuAction(
- addSignalHandlerCommandId,
- addSignalHandlerDisplayName,
- {},
- rootCategory, QKeySequence(),
- 42, &addNewSignalHandler,
- &singleSelectedAndUiFile,
- &singleSelectedAndUiFile));
-
- addDesignerAction(new ModelNodeContextMenuAction(
makeComponentCommandId,
makeComponentDisplayName,
contextIcon(DesignerIcons::MakeComponentIcon),
@@ -1986,14 +1964,15 @@ void DesignerActionManager::createDefaultDesignerActions()
&modelHasMaterial,
&isModel));
- addDesignerAction(new ModelNodeContextMenuAction(mergeTemplateCommandId,
- mergeTemplateDisplayName,
- {},
- rootCategory,
- {},
- Priorities::MergeWithTemplate,
- [&] (const SelectionContext& context) { mergeWithTemplate(context, m_externalDependencies); },
- &SelectionContextFunctors::always));
+ addDesignerAction(new ModelNodeContextMenuAction(
+ mergeTemplateCommandId,
+ mergeTemplateDisplayName,
+ contextIcon(DesignerIcons::MergeWithTemplateIcon),
+ rootCategory,
+ {},
+ Priorities::MergeWithTemplate,
+ [&] (const SelectionContext& context) { mergeWithTemplate(context, m_externalDependencies); },
+ &SelectionContextFunctors::always));
addDesignerAction(new ActionGroup(
"",
@@ -2005,15 +1984,15 @@ void DesignerActionManager::createDefaultDesignerActions()
addDesignerAction(new EditListModelAction);
- addDesignerAction(new ModelNodeContextMenuAction(
- openSignalDialogCommandId,
- openSignalDialogDisplayName,
- {},
- rootCategory,
- QKeySequence(),
- Priorities::SignalsDialog,
- &openSignalDialog,
- &singleSelectionAndHasSlotTrigger));
+ addDesignerAction(new ModelNodeContextMenuAction(openSignalDialogCommandId,
+ openSignalDialogDisplayName,
+ {},
+ rootCategory,
+ QKeySequence(),
+ Priorities::SignalsDialog,
+ &openSignalDialog,
+ &singleSelectionAndHasSlotTrigger,
+ &singleSelectionAndHasSlotTrigger));
addDesignerAction(new ModelNodeContextMenuAction(
update3DAssetCommandId,
@@ -2102,6 +2081,10 @@ void DesignerActionManager::createDefaultModelNodePreviewImageHandlers()
void DesignerActionManager::addDesignerAction(ActionInterface *newAction)
{
m_designerActions.append(QSharedPointer<ActionInterface>(newAction));
+
+ for (auto callback : m_callBacks) {
+ callback(newAction);
+ }
}
void DesignerActionManager::addCreatorCommand(Core::Command *command, const QByteArray &category, int priority,
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
index 569c495f88..e1544de114 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h
@@ -14,6 +14,8 @@
#include <QToolBar>
#include <QImage>
+#include <functional>
+
QT_BEGIN_NAMESPACE
class QGraphicsItem;
class QGraphicsWidget;
@@ -27,6 +29,7 @@ class DesignerIcons;
using AddResourceOperation = std::function<AddFilesResult(const QStringList &, const QString &, bool)>;
using ModelNodePreviewImageOperation = std::function<QVariant(const ModelNode &)>;
+using ActionAddedInterface = std::function<void(ActionInterface*)>;
struct AddResourceHandler
{
@@ -121,6 +124,8 @@ public:
QHash<QString, QStringList> handleExternalAssetsDrop(const QMimeData *data) const;
QIcon contextIcon(int contextId) const;
+ void addAddActionCallback(ActionAddedInterface callback);
+
private:
void addTransitionEffectAction(const TypeName &typeName);
void addCustomTransitionEffectAction();
@@ -133,6 +138,7 @@ private:
QList<ModelNodePreviewImageHandler> m_modelNodePreviewImageHandlers;
ExternalDependenciesInterface &m_externalDependencies;
QScopedPointer<DesignerIcons> m_designerIcons;
+ QList<ActionAddedInterface> m_callBacks;
};
} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.cpp b/src/plugins/qmldesigner/components/componentcore/designericons.cpp
index 2af0709c3a..053a188328 100644
--- a/src/plugins/qmldesigner/components/componentcore/designericons.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designericons.cpp
@@ -222,8 +222,17 @@ struct JsonMap<QMap<Key, Value>>
static QJsonObject json(const QMap<Key, Value> &map)
{
QJsonObject output;
- for (auto it = map.cbegin(), end = map.cend(); it != end; ++it)
- output[DesignerIconEnums<Key>::toString(it.key())] = JsonMap<Value>::json(it.value());
+
+ #if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
+ for (const auto &[key, val] : map.asKeyValueRange())
+ output[DesignerIconEnums<Key>::toString(key)] = JsonMap<Value>::json(val);
+ #else
+ const auto mapKeys = map.keys();
+ for (const Key &key : mapKeys) {
+ const Value &val = map.value(key);
+ output[DesignerIconEnums<Key>::toString(key)] = JsonMap<Value>::json(val);
+ }
+ #endif
return output;
}
@@ -390,6 +399,33 @@ void DesignerIcons::addIcon(IconId iconId, Area area, Theme::Icon themeIcon, The
addIcon(iconId, area, {themeIcon, color, size});
}
+QIcon DesignerIcons::rotateIcon(const QIcon &icon, const double &degrees)
+{
+ QIcon result;
+ const QMetaEnum &modeMetaEnum = DesignerIconEnums<QIcon::Mode>().metaEnum;
+ const QMetaEnum &stateMetaEnum = DesignerIconEnums<QIcon::State>().metaEnum;
+
+ const int maxModeIdx = modeMetaEnum.keyCount();
+ const int maxStateIdx = stateMetaEnum.keyCount();
+ for (int modeI = 0; modeI < maxModeIdx; ++modeI) {
+ const QIcon::Mode mode = static_cast<QIcon::Mode>(modeMetaEnum.value(modeI));
+ for (int stateI = 0; stateI < maxStateIdx; ++stateI) {
+ const QIcon::State state = static_cast<QIcon::State>(stateMetaEnum.value(stateI));
+ const QList<QSize> iconSizes = icon.availableSizes();
+ for (const QSize &size : iconSizes) {
+ QTransform tr;
+ tr.translate(size.width()/2, size.height()/2);
+ tr.rotate(degrees);
+
+ QPixmap pix = icon.pixmap(size, mode, state).transformed(tr);
+ result.addPixmap(pix, mode, state);
+ }
+ }
+ }
+
+ return result;
+}
+
QList<Utils::StyleHelper::IconFontHelper> DesignerIcons::helperList(const IconId &iconId,
const Area &area) const
{
diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.h b/src/plugins/qmldesigner/components/componentcore/designericons.h
index 342016b77c..f460707b91 100644
--- a/src/plugins/qmldesigner/components/componentcore/designericons.h
+++ b/src/plugins/qmldesigner/components/componentcore/designericons.h
@@ -24,14 +24,14 @@ public:
QIcon::Mode mode = QIcon::Normal,
QIcon::State state = QIcon::Off);
+ IconFontHelper();
+
static IconFontHelper fromJson(const QJsonObject &jsonObject);
QJsonObject toJson() const;
Theme::Icon themeIcon() const;
Theme::Color themeColor() const;
private:
- IconFontHelper();
-
Theme::Icon mThemeIcon;
Theme::Color mThemeColor;
};
@@ -45,25 +45,54 @@ public:
enum IconId {
AddMouseAreaIcon,
AlignBottomIcon,
+ AlignCameraToViewIcon,
AlignLeftIcon,
AlignRightIcon,
AlignTopIcon,
+ AlignViewToCameraIcon,
AnchorsIcon,
AnnotationIcon,
ArrangeIcon,
+ CameraIcon,
+ CameraOrthographicIcon,
+ CameraPerspectiveIcon,
ConnectionsIcon,
+ CopyIcon,
+ CreateIcon,
+ DeleteIcon,
+ DuplicateIcon,
+ EditComponentIcon,
EditIcon,
EnterComponentIcon,
EventListIcon,
+ FitSelectedIcon,
GroupSelectionIcon,
+ ImportedModelsIcon,
LayoutsIcon,
+ LightIcon,
+ LightDirectionalIcon,
+ LightPointIcon,
+ LightSpotIcon,
MakeComponentIcon,
+ MaterialIcon,
MergeWithTemplateIcon,
+ MinimalDownArrowIcon,
+ ModelConeIcon,
+ ModelCubeIcon,
+ ModelCylinderIcon,
+ ModelPlaneIcon,
+ ModelSphereIcon,
+ ParentIcon,
+ PasteIcon,
PositionsersIcon,
+ PrimitivesIcon,
+ ResetViewIcon,
SelecionIcon,
+ ShowBoundsIcon,
+ SimpleCheckIcon,
SnappingIcon,
TimelineIcon,
- ShowBoundsIcon,
+ ToggleGroupIcon,
VisibilityIcon
};
Q_ENUM(IconId)
@@ -80,7 +109,6 @@ public:
Hovered = QIcon::Active,
Selected = QIcon::Selected
};
-
Q_ENUM(Mode)
enum State {
@@ -123,6 +151,8 @@ public:
Theme::Color color,
const QSize &size);
+ static QIcon rotateIcon(const QIcon &icon, const double &degrees);
+
private:
QList<Utils::StyleHelper::IconFontHelper> helperList(const IconId &iconId,
const Area &area) const;
diff --git a/src/plugins/qmldesigner/components/componentcore/groupitemaction.cpp b/src/plugins/qmldesigner/components/componentcore/groupitemaction.cpp
new file mode 100644
index 0000000000..f60e0ee5e3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/groupitemaction.cpp
@@ -0,0 +1,155 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "groupitemaction.h"
+
+#include "nodeabstractproperty.h"
+#include "nodelistproperty.h"
+
+#include <utils/algorithm.h>
+
+using namespace QmlDesigner;
+
+namespace {
+
+bool selectionsAreSiblings(const QList<ModelNode> &selectedItems)
+{
+ const QList<ModelNode> prunedSelectedItems = ModelNode::pruneChildren(selectedItems);
+ if (prunedSelectedItems.size() < 2)
+ return false;
+
+ ModelNode modelItemNode(prunedSelectedItems.first());
+ if (!modelItemNode.isValid())
+ return false;
+
+ ModelNode parentNode = modelItemNode.parentProperty().parentModelNode();
+ if (!parentNode.isValid())
+ return false;
+
+ for (const ModelNode &node : Utils::span(prunedSelectedItems).subspan(1)) {
+ if (!node.isValid())
+ return false;
+
+ if (node.parentProperty().parentModelNode() != parentNode)
+ return false;
+ }
+
+ return true;
+}
+
+ModelNode availableGroupNode(const SelectionContext &selection)
+{
+ if (!selection.isValid())
+ return {};
+
+ if (selection.singleNodeIsSelected()) {
+ const ModelNode node = selection.currentSingleSelectedNode();
+ if (node.metaInfo().isQtQuickStudioComponentsGroupItem())
+ return node;
+ }
+
+ const ModelNode parentNode = selection
+ .firstSelectedModelNode()
+ .parentProperty().parentModelNode();
+
+ if (!parentNode.isValid())
+ return {};
+
+ QList<ModelNode> allSiblingNodes = parentNode.directSubModelNodes();
+
+ QList<ModelNode> selectedNodes = ModelNode::pruneChildren(selection.selectedModelNodes());
+ if (selectedNodes.size() != allSiblingNodes.size())
+ return {};
+
+ Utils::sort(allSiblingNodes);
+ Utils::sort(selectedNodes);
+
+ if (allSiblingNodes != selectedNodes)
+ return {};
+
+ if (parentNode.metaInfo().isQtQuickStudioComponentsGroupItem())
+ return parentNode;
+
+ return {};
+}
+
+inline bool itemsAreGrouped(const SelectionContext &selection)
+{
+ return availableGroupNode(selection).isValid();
+}
+
+bool groupingEnabled(const SelectionContext &selection)
+{
+ if (selection.singleNodeIsSelected())
+ return itemsAreGrouped(selection);
+ else
+ return selectionsAreSiblings(selection.selectedModelNodes());
+}
+
+void removeGroup(const ModelNode &group)
+{
+ QmlItemNode groupItem(group);
+ QmlItemNode parent = groupItem.instanceParentItem();
+
+ if (!groupItem || !parent)
+ return;
+
+ group.view()->executeInTransaction(
+ "removeGroup", [group, &groupItem, parent]() {
+ for (const ModelNode &modelNode : group.directSubModelNodes()) {
+ if (QmlVisualNode qmlItem = modelNode) {
+ QPointF pos = qmlItem.position().toPointF();
+ pos = groupItem.instanceTransform().map(pos);
+ qmlItem.setPosition(pos);
+
+ parent.modelNode().defaultNodeListProperty().reparentHere(modelNode);
+ }
+ }
+ groupItem.destroy();
+ });
+}
+
+void toggleGrouping(const SelectionContext &selection)
+{
+ if (!selection.isValid())
+ return;
+
+ ModelNode groupNode = availableGroupNode(selection);
+
+ if (groupNode.isValid())
+ removeGroup(groupNode);
+ else
+ ModelNodeOperations::addToGroupItem(selection);
+}
+
+} // blank namespace
+
+GroupItemAction::GroupItemAction(const QIcon &icon,
+ const QKeySequence &key,
+ int priority)
+ : ModelNodeAction(ComponentCoreConstants::addToGroupItemCommandId,
+ {},
+ icon,
+ {},
+ {},
+ key,
+ priority,
+ &toggleGrouping,
+ &groupingEnabled)
+{
+ setCheckable(true);
+}
+
+void GroupItemAction::updateContext()
+{
+ using namespace ComponentCoreConstants;
+ ModelNodeAction::updateContext();
+ action()->setText(QString::fromLatin1(action()->isChecked()
+ ? removeGroupItemDisplayName
+ : addToGroupItemDisplayName));
+}
+
+bool GroupItemAction::isChecked(const SelectionContext &selectionContext) const
+{
+ return itemsAreGrouped(selectionContext);
+}
diff --git a/src/plugins/qmldesigner/components/componentcore/groupitemaction.h b/src/plugins/qmldesigner/components/componentcore/groupitemaction.h
new file mode 100644
index 0000000000..8d217a8719
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/groupitemaction.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <modelnodecontextmenu_helper.h>
+
+namespace QmlDesigner {
+
+class GroupItemAction: public ModelNodeAction
+{
+public:
+ GroupItemAction(const QIcon &icon,
+ const QKeySequence &key,
+ int priority);
+
+
+protected:
+ virtual void updateContext() override;
+ virtual bool isChecked(const SelectionContext &selectionContext) const override;
+};
+
+}
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp
index eac545b2ef..0102b4126c 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp
@@ -5,6 +5,7 @@
#include "modelnodecontextmenu_helper.h"
#include "designeractionmanager.h"
#include <qmldesignerplugin.h>
+#include "qmleditormenu.h"
#include <modelnode.h>
@@ -68,7 +69,7 @@ void populateMenu(QSet<ActionInterface* > &actionInterfaces,
void ModelNodeContextMenu::execute(const QPoint &position, bool selectionMenuBool)
{
- auto mainMenu = new QMenu();
+ auto mainMenu = new QmlEditorMenu();
m_selectionContext.setShowSelectionTools(selectionMenuBool);
m_selectionContext.setScenePosition(m_scenePos);
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
index 50f5e83bd8..6bc9c703bc 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h
@@ -173,14 +173,18 @@ private:
QByteArray m_category;
};
-class SeperatorDesignerAction : public AbstractAction
+class SeparatorDesignerAction : public AbstractAction
{
public:
- SeperatorDesignerAction(const QByteArray &category, int priority) :
- m_category(category),
- m_priority(priority),
- m_visibility(&SelectionContextFunctors::always)
- { defaultAction()->setSeparator(true); }
+ SeparatorDesignerAction(const QByteArray &category, int priority)
+ : AbstractAction()
+ , m_category(category)
+ , m_priority(priority)
+ , m_visibility(&SelectionContextFunctors::always)
+ {
+ action()->setSeparator(true);
+ action()->setIcon({});
+ }
bool isVisible(const SelectionContext &m_selectionState) const override { return m_visibility(m_selectionState); }
bool isEnabled(const SelectionContext &) const override { return true; }
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 95ea8575c2..b8b1fa94e8 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -32,6 +32,7 @@
#include <designermcumanager.h>
#include <qmldesignerplugin.h>
+#include <qmldesignerconstants.h>
#include <coreplugin/messagebox.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -834,8 +835,8 @@ void editMaterial(const SelectionContext &selectionContext)
if (material.isValid()) {
QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor");
- // to MaterialEditor and MaterialBrowser...
- view->emitCustomNotification("selected_material_changed", {material});
+ // to MaterialBrowser...
+ view->emitCustomNotification("select_material", {material});
}
}
@@ -1209,7 +1210,7 @@ void addFlowEffect(const SelectionContext &selectionContext, const TypeName &typ
if (container.hasProperty("effect"))
container.removeProperty("effect");
- if (effectMetaInfo.isValid()) {
+ if (effectMetaInfo.isQtObject()) {
ModelNode effectNode =
view->createModelNode(effectMetaInfo.typeName(),
effectMetaInfo.majorVersion(),
@@ -1384,15 +1385,15 @@ void addCustomFlowEffect(const SelectionContext &selectionContext)
if (typeName.isEmpty())
return;
- qDebug() << Q_FUNC_INFO << typeName << importString;
-
- const Import import = Import::createFileImport("FlowEffects");
+ AbstractView *view = selectionContext.view();
- if (!importString.isEmpty() && !selectionContext.view()->model()->hasImport(import, true, true)) {
- selectionContext.view()-> model()->changeImports({import}, {});
- }
+ view->executeInTransaction("DesignerActionManager:addFlowEffect", [view, importString]() {
+ const Import import = Import::createFileImport("FlowEffects");
- AbstractView *view = selectionContext.view();
+ if (!importString.isEmpty() && !view->model()->hasImport(import, true, true)) {
+ view->model()->changeImports({import}, {});
+ }
+ });
QTC_ASSERT(view && selectionContext.hasSingleSelectedModelNode(), return);
ModelNode container = selectionContext.currentSingleSelectedNode();
@@ -1642,10 +1643,10 @@ void openEffectMaker(const QString &filePath)
Utils::FilePath projectPath = target->project()->projectDirectory();
QString effectName = QFileInfo(filePath).baseName();
- QString effectResDir = "asset_imports/Effects/" + effectName;
- Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir);
+ QString effectResDir = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER) + "/Effects/" + effectName;
+ Utils::FilePath effectResPath = projectPath.pathAppended(effectResDir);
if (!effectResPath.exists())
- QDir(projectPath.toString()).mkpath(effectResDir);
+ QDir().mkpath(effectResPath.toString());
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
@@ -1669,17 +1670,16 @@ void openEffectMaker(const QString &filePath)
Utils::QtcProcess *qqemProcess = new Utils::QtcProcess();
qqemProcess->setEnvironment(env);
qqemProcess->setCommand({ effectMakerPath, arguments });
- qqemProcess->start();
-
QObject::connect(qqemProcess, &Utils::QtcProcess::done, [qqemProcess]() {
qqemProcess->deleteLater();
});
+ qqemProcess->start();
}
}
Utils::FilePath getEffectsImportDirectory()
{
- QString defaultDir = "asset_imports/Effects";
+ QString defaultDir = QLatin1String(Constants::DEFAULT_ASSET_IMPORT_FOLDER) + "/Effects";
Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
Utils::FilePath effectsPath = projectPath.pathAppended(defaultDir);
@@ -1698,13 +1698,7 @@ QString getEffectsDefaultDirectory(const QString &defaultDir)
QString getEffectIcon(const QString &effectPath)
{
- const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
- if (!target) {
- qWarning() << __FUNCTION__ << "No project open";
- return QString();
- }
-
- Utils::FilePath projectPath = target->project()->projectDirectory();
+ 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");
@@ -1727,8 +1721,9 @@ bool validateEffect(const QString &effectPath)
Utils::FilePath qmlPath = effectsResDir.resolvePath(effectName + "/" + effectName + ".qml");
if (!qmlPath.exists()) {
QMessageBox msgBox;
- msgBox.setText(QObject::tr("Effect %1 not complete").arg(effectName));
- msgBox.setInformativeText(QObject::tr("Do you want to edit %1?").arg(effectName));
+ msgBox.setText(QObject::tr("Effect %1 is not complete.").arg(effectName));
+ msgBox.setInformativeText(QObject::tr("Ensure that you have saved it in Qt Quick Effect Maker."
+ "\nDo you want to edit this effect?"));
msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
msgBox.setDefaultButton(QMessageBox::Yes);
msgBox.setIcon(QMessageBox::Question);
diff --git a/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp
new file mode 100644
index 0000000000..173838f170
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp
@@ -0,0 +1,152 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0#include "qmleditormenu.h"
+
+#include "qmleditormenu.h"
+
+#include "designeractionmanager.h"
+#include "designericons.h"
+
+#include <utils/hostosinfo.h>
+
+#include <QApplication>
+#include <QStyleOption>
+
+using namespace QmlDesigner;
+
+class QmlDesigner::QmlEditorMenuPrivate
+{
+private:
+ friend class QmlDesigner::QmlEditorMenu;
+ friend class QmlDesigner::QmlEditorStyleObject;
+
+ bool iconVisibility = true;
+ int maxIconWidth = 0;
+
+ static QIcon cascadeLeft;
+ static QIcon cascadeRight;
+ static QIcon tick;
+ static QIcon backspaceIcon;
+};
+
+QIcon QmlEditorMenuPrivate::cascadeLeft;
+QIcon QmlEditorMenuPrivate::cascadeRight;
+QIcon QmlEditorMenuPrivate::tick;
+QIcon QmlEditorMenuPrivate::backspaceIcon;
+
+QmlEditorMenu::QmlEditorMenu(QWidget *parent)
+ : QMenu(parent)
+ , d(new QmlEditorMenuPrivate)
+{
+}
+
+QmlEditorMenu::QmlEditorMenu(const QString &title, QWidget *parent)
+ : QMenu(title, parent)
+ , d(new QmlEditorMenuPrivate)
+{
+}
+
+QmlEditorMenu::~QmlEditorMenu()
+{
+ delete d;
+}
+
+bool QmlEditorMenu::isValid(const QMenu *menu)
+{
+ return qobject_cast<const QmlEditorMenu *>(menu);
+}
+
+bool QmlEditorMenu::iconsVisible() const
+{
+ return d->iconVisibility;
+}
+
+void QmlEditorMenu::setIconsVisible(bool visible)
+{
+ if (d->iconVisibility == visible)
+ return;
+
+ d->iconVisibility = visible;
+ emit iconVisibilityChanged(visible);
+
+ if (isVisible()) {
+ style()->unpolish(this);
+ style()->polish(this);
+ }
+}
+
+void QmlEditorMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const
+{
+ if (option->maxIconWidth == 0)
+ d->maxIconWidth = 0;
+
+ QMenu::initStyleOption(option, action);
+
+#ifndef QT_NO_SHORTCUT
+ if (!action->isShortcutVisibleInContextMenu() && !action->shortcut().isEmpty()) {
+ int tabIndex = option->text.indexOf("\t");
+ if (tabIndex < 0)
+ option->text += QLatin1String("\t") + action->shortcut().toString(QKeySequence::NativeText);
+ }
+#endif
+ if (d->iconVisibility) {
+ if (Utils::HostOsInfo::isMacHost()) {
+ if (qApp->testAttribute(Qt::AA_DontShowIconsInMenus))
+ option->icon = action->icon();
+ } else {
+ option->icon = action->isIconVisibleInMenu() ? action->icon() : QIcon();
+ }
+ } else {
+ option->icon = {};
+ }
+
+ if (!option->icon.isNull() && (d->maxIconWidth == 0))
+ d->maxIconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, option, this);
+
+ option->maxIconWidth = d->maxIconWidth;
+ option->styleObject = QmlEditorStyleObject::instance();
+}
+
+bool QmlEditorMenu::qmlEditorMenu() const
+{
+ return true;
+}
+
+QmlEditorStyleObject *QmlEditorStyleObject::instance()
+{
+ static QmlEditorStyleObject *s_instance = nullptr;
+ if (!s_instance)
+ s_instance = new QmlEditorStyleObject;
+ return s_instance;
+}
+
+QIcon QmlEditorStyleObject::cascadeIconLeft() const
+{
+ return QmlEditorMenuPrivate::cascadeLeft;
+}
+
+QIcon QmlEditorStyleObject::cascadeIconRight() const
+{
+ return QmlEditorMenuPrivate::cascadeRight;
+}
+
+QIcon QmlEditorStyleObject::tickIcon() const
+{
+ return QmlEditorMenuPrivate::tick;
+}
+
+QIcon QmlEditorStyleObject::backspaceIcon() const
+{
+ return QmlEditorMenuPrivate::backspaceIcon;
+}
+
+QmlEditorStyleObject::QmlEditorStyleObject()
+ : QObject(qApp)
+{
+ QIcon downIcon = DesignerActionManager::instance()
+ .contextIcon(DesignerIcons::MinimalDownArrowIcon);
+
+ QmlEditorMenuPrivate::cascadeLeft = DesignerIcons::rotateIcon(downIcon, 90);
+ QmlEditorMenuPrivate::cascadeRight = DesignerIcons::rotateIcon(downIcon, -90);
+ QmlEditorMenuPrivate::tick = DesignerActionManager::instance()
+ .contextIcon(DesignerIcons::SimpleCheckIcon);
+}
diff --git a/src/plugins/qmldesigner/components/componentcore/qmleditormenu.h b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.h
new file mode 100644
index 0000000000..4163fccbea
--- /dev/null
+++ b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QMenu>
+
+class QStyleOptionMenuItem;
+
+namespace QmlDesigner {
+
+class QmlEditorMenuPrivate;
+class DesignerIcons;
+
+class QmlEditorMenu : public QMenu
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool qmlEditorMenu READ qmlEditorMenu CONSTANT)
+ Q_PROPERTY(bool iconsVisible READ iconsVisible WRITE setIconsVisible NOTIFY iconVisibilityChanged)
+
+public:
+ explicit QmlEditorMenu(QWidget *parent = nullptr);
+ explicit QmlEditorMenu(const QString &title, QWidget *parent = nullptr);
+ virtual ~QmlEditorMenu();
+
+ static bool isValid(const QMenu *menu);
+
+ bool iconsVisible() const;
+ void setIconsVisible(bool visible);
+
+signals:
+ void iconVisibilityChanged(bool);
+
+protected:
+ virtual void initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const override;
+
+private:
+ bool qmlEditorMenu() const;
+
+ QmlEditorMenuPrivate *d = nullptr;
+};
+
+class QmlEditorStyleObject : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QIcon cascadeIconLeft READ cascadeIconLeft CONSTANT)
+ Q_PROPERTY(QIcon cascadeIconRight READ cascadeIconRight CONSTANT)
+ Q_PROPERTY(QIcon backspaceIcon READ backspaceIcon CONSTANT)
+ Q_PROPERTY(QIcon tickIcon READ tickIcon CONSTANT)
+
+public:
+ static QmlEditorStyleObject *instance();
+
+ QIcon cascadeIconLeft() const;
+ QIcon cascadeIconRight() const;
+ QIcon tickIcon() const;
+ QIcon backspaceIcon() const;
+
+private:
+ QmlEditorStyleObject();
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.cpp b/src/plugins/qmldesigner/components/componentcore/theme.cpp
index 2771aff7d6..af495fd3b5 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/theme.cpp
@@ -11,12 +11,13 @@
#include <utils/stylehelper.h>
#include <QApplication>
-#include <QRegularExpression>
-#include <QScreen>
+#include <QMainWindow>
#include <QPointer>
-#include <QQmlEngine>
#include <QQmlComponent>
+#include <QQmlEngine>
#include <QQmlProperty>
+#include <QRegularExpression>
+#include <QScreen>
#include <qqml.h>
static Q_LOGGING_CATEGORY(themeLog, "qtc.qmldesigner.theme", QtWarningMsg)
@@ -137,6 +138,11 @@ bool Theme::highPixelDensity() const
return qApp->primaryScreen()->logicalDotsPerInch() > 100;
}
+QWindow *Theme::mainWindowHandle() const
+{
+ return Core::ICore::mainWindow()->windowHandle();
+}
+
QPixmap Theme::getPixmap(const QString &id)
{
return QmlDesignerIconProvider::getPixmap(id);
@@ -166,6 +172,21 @@ QString Theme::getIconUnicode(const QString &name)
return instance()->m_constants->property(name.toStdString().data()).toString();
}
+QIcon Theme::iconFromName(Icon i, QColor c)
+{
+ QColor color = c;
+ if (!color.isValid())
+ color = getColor(Theme::Color::DSiconColor);
+
+ const QString fontName = "qtds_propertyIconFont.ttf";
+ return Utils::StyleHelper::getIconFromIconFont(fontName, Theme::getIconUnicode(i), 32, 32, color);
+}
+
+int Theme::toolbarSize()
+{
+ return 41;
+}
+
QColor Theme::qmlDesignerBackgroundColorDarker() const
{
return getColor(QmlDesigner_BackgroundColorDarker);
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index f6bc8cc0bf..8e5f10d361 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -29,6 +29,8 @@ public:
addRowAfter,
addRowBefore,
addTable,
+ add_medium,
+ add_small,
adsClose,
adsDetach,
adsDropDown,
@@ -40,6 +42,10 @@ public:
alignLeft,
alignRight,
alignTo,
+ alignToCam_medium,
+ alignToCamera_small,
+ alignToObject_small,
+ alignToView_medium,
alignTop,
anchorBaseline,
anchorBottom,
@@ -47,33 +53,70 @@ public:
anchorLeft,
anchorRight,
anchorTop,
+ anchors_small,
animatedProperty,
annotationBubble,
annotationDecal,
+ annotations_large,
+ annotations_small,
applyMaterialToSelected,
+ apply_medium,
+ apply_small,
+ arrange_small,
+ arrow_small,
assign,
+ attach_medium,
+ back_medium,
+ backspace_small,
bevelAll,
bevelCorner,
+ bezier_medium,
+ binding_medium,
+ bounds_small,
+ branch_medium,
+ camera_small,
centerHorizontal,
centerVertical,
+ cleanLogs_medium,
closeCross,
+ closeFile_large,
closeLink,
+ close_small,
colorPopupClose,
+ colorSelection_medium,
columnsAndRows,
+ cone_medium,
+ cone_small,
+ connection_small,
+ connections_medium,
copyLink,
copyStyle,
+ copy_small,
cornerA,
cornerB,
cornersAll,
+ createComponent_large,
+ createComponent_small,
+ create_medium,
+ create_small,
+ cube_medium,
+ cube_small,
curveDesigner,
+ curveDesigner_medium,
curveEditor,
customMaterialEditor,
+ cylinder_medium,
+ cylinder_small,
decisionNode,
deleteColumn,
deleteMaterial,
deleteRow,
deleteTable,
+ delete_medium,
+ delete_small,
+ designMode_large,
detach,
+ directionalLight_small,
distributeBottom,
distributeCenterHorizontal,
distributeCenterVertical,
@@ -90,48 +133,115 @@ public:
downloadUnavailable,
downloadUpdate,
downloaded,
+ duplicate_small,
edit,
+ editComponent_large,
+ editComponent_small,
+ editLightOff_medium,
+ editLightOn_medium,
+ edit_medium,
+ edit_small,
+ events_small,
+ export_medium,
eyeDropper,
favorite,
+ fitAll_medium,
+ fitSelected_small,
+ fitSelection_medium,
+ fitToView_medium,
flowAction,
flowTransition,
fontStyleBold,
fontStyleItalic,
fontStyleStrikethrough,
fontStyleUnderline,
+ forward_medium,
+ globalOrient_medium,
gradient,
gridView,
+ grid_medium,
+ group_small,
+ home_large,
idAliasOff,
idAliasOn,
+ import_medium,
imported,
+ importedModels_small,
infinity,
+ invisible_medium,
keyframe,
+ languageList_medium,
+ layouts_small,
+ lights_small,
+ linear_medium,
linkTriangle,
linked,
listView,
+ list_medium,
+ localOrient_medium,
lockOff,
lockOn,
+ loopPlayback_medium,
+ materialBrowser_medium,
materialPreviewEnvironment,
materialPreviewModel,
+ material_medium,
mergeCells,
+ merge_small,
minus,
mirror,
+ more_medium,
+ mouseArea_small,
+ moveDown_medium,
+ moveInwards_medium,
+ moveUp_medium,
+ moveUpwards_medium,
+ move_medium,
newMaterial,
+ nextFile_large,
openLink,
openMaterialBrowser,
orientation,
+ orthCam_medium,
+ orthCam_small,
paddingEdge,
paddingFrame,
+ particleAnimation_medium,
pasteStyle,
+ paste_small,
pause,
+ perspectiveCam_medium,
+ perspectiveCam_small,
pin,
+ plane_medium,
+ plane_small,
play,
+ playFill_medium,
+ playOutline_medium,
plus,
+ pointLight_small,
+ positioners_small,
+ previewEnv_medium,
+ previousFile_large,
promote,
+ properties_medium,
readOnly,
+ recordFill_medium,
+ recordOutline_medium,
redo,
+ reload_medium,
+ remove_medium,
+ remove_small,
+ rename_small,
+ replace_small,
+ resetView_small,
+ restartParticles_medium,
+ reverseOrder_medium,
+ roatate_medium,
rotationFill,
rotationOutline,
+ runProjFill_large,
+ runProjOutline_large,
s_anchors,
s_annotations,
s_arrange,
@@ -150,11 +260,27 @@ public:
s_snapping,
s_timeline,
s_visibility,
+ saveLogs_medium,
+ scale_medium,
search,
+ search_small,
sectionToggle,
+ selectFill_medium,
+ selectOutline_medium,
+ selectParent_small,
+ selection_small,
+ settings_medium,
+ signal_small,
+ snapping_small,
+ sphere_medium,
+ sphere_small,
splitColumns,
splitRows,
+ spotLight_small,
+ stackedContainer_small,
startNode,
+ step_medium,
+ stop_medium,
testIcon,
textAlignBottom,
textAlignCenter,
@@ -166,7 +292,14 @@ public:
textBulletList,
textFullJustification,
textNumberedList,
+ textures_medium,
tickIcon,
+ tickMark_small,
+ timeline_small,
+ toEndFrame_medium,
+ toNextFrame_medium,
+ toPrevFrame_medium,
+ toStartFrame_medium,
topToolbar_annotations,
topToolbar_closeFile,
topToolbar_designMode,
@@ -189,11 +322,14 @@ public:
triangleCornerB,
unLinked,
undo,
+ unify_medium,
unpin,
upDownIcon,
upDownSquare2,
visibilityOff,
visibilityOn,
+ visible_medium,
+ visible_small,
wildcard,
wizardsAutomotive,
wizardsDesktop,
@@ -204,7 +340,9 @@ public:
wizardsUnknown,
zoomAll,
zoomIn,
+ zoomIn_medium,
zoomOut,
+ zoomOut_medium,
zoomSelection
};
Q_ENUM(Icon)
@@ -217,6 +355,10 @@ public:
static QString getIconUnicode(Theme::Icon i);
static QString getIconUnicode(const QString &name);
+ static QIcon iconFromName(Theme::Icon i, QColor c = {});
+
+ static int toolbarSize();
+
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const;
Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const;
Q_INVOKABLE QColor qmlDesignerTabLight() const;
@@ -228,6 +370,8 @@ public:
Q_INVOKABLE int captionFontPixelSize() const;
Q_INVOKABLE bool highPixelDensity() const;
+ Q_INVOKABLE QWindow *mainWindowHandle() const;
+
private:
Theme(Utils::Theme *originTheme, QObject *parent);
QColor evaluateColorAtThemeInstance(const QString &themeColorName);
diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
index 2eecd3d1cc..ee7ae3f678 100644
--- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp
@@ -261,7 +261,7 @@ void ViewManager::registerNanotraceActions()
22,
handleShutdownNanotraceAction);
- QObject::connect(startNanotraceAction->defaultAction(), &QAction::triggered, [&]() {
+ QObject::connect(startNanotraceAction->action(), &QAction::triggered, [&]() {
d->nodeInstanceView.startNanotrace();
});
@@ -276,7 +276,7 @@ void ViewManager::registerNanotraceActions()
23,
handleShutdownNanotraceAction);
- QObject::connect(shutDownNanotraceAction->defaultAction(), &QAction::triggered, [&]() {
+ QObject::connect(shutDownNanotraceAction->action(), &QAction::triggered, [&]() {
d->nodeInstanceView.endNanotrace();
});
diff --git a/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp b/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp
index d6289a0fc2..3d0464778d 100644
--- a/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/zoomaction.cpp
@@ -32,7 +32,9 @@ bool isValidIndex(int index)
ZoomAction::ZoomAction(QObject *parent)
: QWidgetAction(parent)
, m_combo(nullptr)
-{}
+{
+ m_index = indexOf(1.0);
+}
std::array<double, 27> ZoomAction::zoomLevels()
{
@@ -51,14 +53,20 @@ int ZoomAction::indexOf(double zoom)
void ZoomAction::setZoomFactor(double zoom)
{
if (int index = indexOf(zoom); index >= 0) {
- m_combo->setCurrentIndex(index);
- m_combo->setToolTip(m_combo->currentText());
+ emitZoomLevelChanged(index);
+ if (m_combo) {
+ m_combo->setCurrentIndex(index);
+ m_combo->setToolTip(m_combo->currentText());
+ }
+ m_index = index;
return;
}
- int rounded = static_cast<int>(std::round(zoom * 100));
- m_combo->setEditable(true);
- m_combo->setEditText(QString::number(rounded) + " %");
- m_combo->setToolTip(m_combo->currentText());
+ if (m_combo) {
+ int rounded = static_cast<int>(std::round(zoom * 100));
+ m_combo->setEditable(true);
+ m_combo->setEditText(QString::number(rounded) + " %");
+ m_combo->setToolTip(m_combo->currentText());
+ }
}
double ZoomAction::setNextZoomFactor(double zoom)
@@ -91,6 +99,11 @@ double ZoomAction::setPreviousZoomFactor(double zoom)
return zoom;
}
+int ZoomAction::currentIndex() const
+{
+ return m_index;
+}
+
bool parentIsToolBar(QWidget *parent)
{
return qobject_cast<QToolBar *>(parent) != nullptr;
@@ -111,7 +124,7 @@ QWidget *ZoomAction::createWidget(QWidget *parent)
if (!m_combo && parentIsToolBar(parent)) {
m_combo = createZoomComboBox(parent);
m_combo->setProperty("hideborder", true);
- m_combo->setCurrentIndex(indexOf(1.0));
+ m_combo->setCurrentIndex(m_index);
m_combo->setToolTip(m_combo->currentText());
connect(m_combo, &QComboBox::currentIndexChanged, this, &ZoomAction::emitZoomLevelChanged);
diff --git a/src/plugins/qmldesigner/components/componentcore/zoomaction.h b/src/plugins/qmldesigner/components/componentcore/zoomaction.h
index 7be82e92b7..d211a19e7c 100644
--- a/src/plugins/qmldesigner/components/componentcore/zoomaction.h
+++ b/src/plugins/qmldesigner/components/componentcore/zoomaction.h
@@ -32,6 +32,8 @@ public:
double setNextZoomFactor(double zoom);
double setPreviousZoomFactor(double zoom);
+ int currentIndex() const;
+
protected:
QWidget *createWidget(QWidget *parent) override;
@@ -40,6 +42,7 @@ private:
static std::array<double, 27> m_zooms;
QPointer<QComboBox> m_combo;
+ int m_index = -1;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp
index 6f5a9021be..6c970f2646 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.cpp
@@ -11,7 +11,6 @@
#include "nodemetainfo.h"
#include "nodeproperty.h"
#include "rewriterview.h"
-#include "rewritertransaction.h"
#include "addnewbackenddialog.h"
@@ -20,8 +19,6 @@
namespace QmlDesigner {
-namespace Internal {
-
BackendModel::BackendModel(ConnectionView *parent) :
QStandardItemModel(parent)
,m_connectionView(parent)
@@ -29,7 +26,7 @@ BackendModel::BackendModel(ConnectionView *parent) :
connect(this, &QStandardItemModel::dataChanged, this, &BackendModel::handleDataChanged);
}
-ConnectionView *QmlDesigner::Internal::BackendModel::connectionView() const
+ConnectionView *BackendModel::connectionView() const
{
return m_connectionView;
}
@@ -311,6 +308,4 @@ void BackendModel::handleDataChanged(const QModelIndex &topLeft, const QModelInd
m_lock = false;
}
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.h b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.h
index fc9542ca18..c4f148aa2e 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/backendmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/backendmodel.h
@@ -8,8 +8,6 @@
namespace QmlDesigner {
-namespace Internal {
-
class ConnectionView;
class BackendModel : public QStandardItemModel
@@ -47,6 +45,4 @@ private:
bool m_lock = false;
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
index 2b9e20219b..e0a8f03e99 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.cpp
@@ -18,8 +18,6 @@
namespace QmlDesigner {
-namespace Internal {
-
BindingModel::BindingModel(ConnectionView *parent)
: QStandardItemModel(parent)
, m_connectionView(parent)
@@ -440,6 +438,4 @@ void BindingModel::handleException()
resetModel();
}
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
index 400209918d..12685679e9 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/bindingmodel.h
@@ -11,8 +11,6 @@
namespace QmlDesigner {
-namespace Internal {
-
class ConnectionView;
class BindingModel : public QStandardItemModel
@@ -65,6 +63,4 @@ private:
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
index 52a6f5aabd..b3eb7542f8 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
@@ -48,8 +48,6 @@ bool isConnection(const QmlDesigner::ModelNode &modelNode)
namespace QmlDesigner {
-namespace Internal {
-
ConnectionModel::ConnectionModel(ConnectionView *parent)
: QStandardItemModel(parent)
, m_connectionView(parent)
@@ -351,7 +349,7 @@ void ConnectionModel::deleteConnectionByRow(int currentRow)
{
SignalHandlerProperty targetSignal = signalHandlerPropertyForRow(currentRow);
QTC_ASSERT(targetSignal.isValid(), return );
- QmlDesigner::ModelNode node = targetSignal.parentModelNode();
+ ModelNode node = targetSignal.parentModelNode();
QTC_ASSERT(node.isValid(), return );
QList<SignalHandlerProperty> allSignals = node.signalProperties();
@@ -527,6 +525,4 @@ QStringList ConnectionModel::getPossibleSignalsForConnection(const ModelNode &co
return stringList;
}
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
index 56971a3732..42cbe33fc7 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.h
@@ -13,8 +13,6 @@ class BindingProperty;
class SignalHandlerProperty;
class VariantProperty;
-namespace Internal {
-
class ConnectionView;
class ConnectionModel : public QStandardItemModel
@@ -73,6 +71,4 @@ private:
QString m_exceptionError;
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
index 0c34eefd45..39e05a898c 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
@@ -22,8 +22,6 @@
namespace QmlDesigner {
-namespace Internal {
-
ConnectionView::ConnectionView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
, m_connectionViewWidget(new ConnectionViewWidget())
@@ -278,6 +276,4 @@ ConnectionView *ConnectionView::instance()
return s_instance;
}
-} // namesapce Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
index ef70922a12..dcf61ad79d 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
@@ -15,8 +15,6 @@ QT_END_NAMESPACE
namespace QmlDesigner {
-namespace Internal {
-
class ConnectionViewWidget;
class BindingModel;
class ConnectionModel;
@@ -82,6 +80,4 @@ private: //variables
BackendModel *m_backendModel;
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
index 4b658aa9c6..f1b0c3f4cb 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp
@@ -34,8 +34,6 @@
namespace QmlDesigner {
-namespace Internal {
-
ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
QFrame(parent),
ui(new Ui::ConnectionViewWidget)
@@ -72,6 +70,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) :
const QList<QToolButton*> buttons = createToolBarWidgets();
+ ui->toolBar->setFixedHeight(41);
for (auto toolButton : buttons)
ui->toolBar->addWidget(toolButton);
@@ -611,6 +610,4 @@ void ConnectionViewWidget::backendTableViewSelectionChanged(const QModelIndex &c
}
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
index eff9937511..f71641bd8b 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.h
@@ -20,8 +20,6 @@ namespace Ui { class ConnectionViewWidget; }
class ActionEditor;
class BindingEditor;
-namespace Internal {
-
class BindingModel;
class ConnectionModel;
class DynamicPropertiesModel;
@@ -93,6 +91,4 @@ private:
QModelIndex m_dynamicIndex;
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/delegates.cpp b/src/plugins/qmldesigner/components/connectioneditor/delegates.cpp
index 3c482997cd..e2c30b0a03 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/delegates.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/delegates.cpp
@@ -20,8 +20,6 @@
namespace QmlDesigner {
-namespace Internal {
-
QStringList prependOnForSignalHandler(const QStringList &signalNames)
{
QStringList signalHandlerNames;
@@ -408,6 +406,4 @@ QWidget *BackendDelegate::createEditor(QWidget *parent, const QStyleOptionViewIt
return widget;
}
-} // namesapce Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/delegates.h b/src/plugins/qmldesigner/components/connectioneditor/delegates.h
index f66cbb0ba0..55f886b98a 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/delegates.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/delegates.h
@@ -9,8 +9,6 @@
namespace QmlDesigner {
-namespace Internal {
-
class PropertiesComboBox : public QComboBox
{
Q_OBJECT
@@ -77,6 +75,4 @@ public:
const QModelIndex &index) const override;
};
-} // namespace Internal
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
index 1eca539f5b..89e08c5441 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.cpp
@@ -3,32 +3,32 @@
#include "dynamicpropertiesmodel.h"
-#include "connectionview.h"
-
-#include <bindingproperty.h>
-#include <nodemetainfo.h>
-#include <nodeproperty.h>
-#include <rewritertransaction.h>
-#include <rewritingexception.h>
-#include <variantproperty.h>
-#include <qmldesignerconstants.h>
-#include <qmldesignerplugin.h>
+#include "bindingproperty.h"
+#include "nodeabstractproperty.h"
+#include "nodemetainfo.h"
+#include "qmlchangeset.h"
+#include "qmldesignerconstants.h"
+#include "qmldesignerplugin.h"
+#include "qmlobjectnode.h"
+#include "qmltimeline.h"
+#include "rewritertransaction.h"
+#include "rewritingexception.h"
+#include "variantproperty.h"
#include <utils/algorithm.h>
-#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QMessageBox>
#include <QTimer>
-#include <QUrl>
namespace {
-bool compareVariantProperties(const QmlDesigner::VariantProperty &variantProperty01, const QmlDesigner::VariantProperty &variantProperty02)
+bool compareVariantProperties(const QmlDesigner::VariantProperty &variantProp1,
+ const QmlDesigner::VariantProperty &variantProp2)
{
- if (variantProperty01.parentModelNode() != variantProperty02.parentModelNode())
+ if (variantProp1.parentModelNode() != variantProp2.parentModelNode())
return false;
- if (variantProperty01.name() != variantProperty02.name())
+ if (variantProp1.name() != variantProp2.name())
return false;
return true;
}
@@ -87,22 +87,19 @@ QVariant convertVariantForTypeName(const QVariant &variant, const QmlDesigner::T
return returnValue;
}
-} //internal namespace
+} // namespace
namespace QmlDesigner {
-namespace Internal {
-
-QmlDesigner::PropertyName DynamicPropertiesModel::unusedProperty(const QmlDesigner::ModelNode &modelNode)
+PropertyName DynamicPropertiesModel::unusedProperty(const ModelNode &modelNode)
{
- QmlDesigner::PropertyName propertyName = "property";
+ PropertyName propertyName = "property";
int i = 0;
if (modelNode.isValid() && modelNode.metaInfo().isValid()) {
while (true) {
- const QmlDesigner::PropertyName currentPropertyName = propertyName + QString::number(i).toLatin1();
+ const PropertyName currentPropertyName = propertyName + QString::number(i++).toLatin1();
if (!modelNode.hasProperty(currentPropertyName) && !modelNode.metaInfo().hasProperty(currentPropertyName))
return currentPropertyName;
- i++;
}
}
@@ -167,8 +164,7 @@ void DynamicPropertiesModel::resetModel()
{
beginResetModel();
clear();
- setHorizontalHeaderLabels(
- QStringList({tr("Item"), tr("Property"), tr("Property Type"), tr("Property Value")}));
+ setHorizontalHeaderLabels({tr("Item"), tr("Property"), tr("Property Type"), tr("Property Value")});
if (m_view->isAttached()) {
const auto nodes = selectedNodes();
@@ -180,8 +176,8 @@ void DynamicPropertiesModel::resetModel()
}
-//Method creates dynamic BindingProperty with the same name and type as old VariantProperty
-//Value copying is optional
+// Method creates dynamic BindingProperty with the same name and type as old VariantProperty
+// Value copying is optional
BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const PropertyName &name, bool copyValue)
{
if (selectedNodes().count() == 1) {
@@ -211,12 +207,11 @@ BindingProperty DynamicPropertiesModel::replaceVariantWithBinding(const Property
qWarning() << "DynamicPropertiesModel::replaceVariantWithBinding: no selected nodes";
}
- return BindingProperty();
+ return {};
}
-
-//Finds selected property, and changes it to empty value (QVariant())
-//If it's a BindingProperty, then replaces it with empty VariantProperty
+// Finds selected property, and changes it to empty value (QVariant())
+// If it's a BindingProperty, then replaces it with empty VariantProperty
void DynamicPropertiesModel::resetProperty(const PropertyName &name)
{
if (selectedNodes().count() == 1) {
@@ -235,7 +230,7 @@ void DynamicPropertiesModel::resetProperty(const PropertyName &name)
BindingProperty property = abProp.toBindingProperty();
TypeName oldType = property.dynamicTypeName();
- //removing old property, to create the new one with the same name:
+ // removing old property, to create the new one with the same name
modelNode.removeProperty(name);
VariantProperty newProperty = modelNode.variantProperty(name);
@@ -249,8 +244,7 @@ void DynamicPropertiesModel::resetProperty(const PropertyName &name)
}
}
}
- }
- else {
+ } else {
qWarning() << "DynamicPropertiesModel::resetProperty: no selected nodes";
}
}
@@ -279,14 +273,14 @@ void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindi
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(bindingProperty.parentModelNode()))
return;
+
if (!m_lock) {
int rowNumber = findRowForBindingProperty(bindingProperty);
- if (rowNumber == -1) {
+ if (rowNumber == -1)
addBindingProperty(bindingProperty);
- } else {
+ else
updateBindingProperty(rowNumber);
- }
}
m_handleDataChanged = true;
@@ -302,6 +296,7 @@ void DynamicPropertiesModel::abstractPropertyChanged(const AbstractProperty &pro
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(property.parentModelNode()))
return;
+
int rowNumber = findRowForProperty(property);
if (rowNumber > -1) {
if (property.isVariantProperty())
@@ -323,6 +318,7 @@ void DynamicPropertiesModel::variantPropertyChanged(const VariantProperty &varia
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(variantProperty.parentModelNode()))
return;
+
if (!m_lock) {
int rowNumber = findRowForVariantProperty(variantProperty);
@@ -342,6 +338,7 @@ void DynamicPropertiesModel::bindingRemoved(const BindingProperty &bindingProper
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(bindingProperty.parentModelNode()))
return;
+
if (!m_lock) {
int rowNumber = findRowForBindingProperty(bindingProperty);
removeRow(rowNumber);
@@ -357,6 +354,7 @@ void DynamicPropertiesModel::variantRemoved(const VariantProperty &variantProper
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(variantProperty.parentModelNode()))
return;
+
if (!m_lock) {
int rowNumber = findRowForVariantProperty(variantProperty);
removeRow(rowNumber);
@@ -375,7 +373,9 @@ void DynamicPropertiesModel::reset()
void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
{
QTC_ASSERT(m_explicitSelection, return);
- QTC_ASSERT(node.isValid(), return);
+
+ if (!node.isValid())
+ return;
m_selectedNodes.clear();
m_selectedNodes.append(node);
@@ -396,7 +396,7 @@ AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) c
if (modelNode.isValid())
return modelNode.property(targetPropertyName.toUtf8());
- return AbstractProperty();
+ return {};
}
BindingProperty DynamicPropertiesModel::bindingPropertyForRow(int rowNumber) const
@@ -409,7 +409,7 @@ BindingProperty DynamicPropertiesModel::bindingPropertyForRow(int rowNumber) con
if (modelNode.isValid())
return modelNode.bindingProperty(targetPropertyName.toUtf8());
- return BindingProperty();
+ return {};
}
VariantProperty DynamicPropertiesModel::variantPropertyForRow(int rowNumber) const
@@ -422,7 +422,7 @@ VariantProperty DynamicPropertiesModel::variantPropertyForRow(int rowNumber) con
if (modelNode.isValid())
return modelNode.variantProperty(targetPropertyName.toUtf8());
- return VariantProperty();
+ return {};
}
QStringList DynamicPropertiesModel::possibleTargetProperties(const BindingProperty &bindingProperty) const
@@ -438,7 +438,8 @@ QStringList DynamicPropertiesModel::possibleTargetProperties(const BindingProper
if (metaInfo.isValid()) {
QStringList possibleProperties;
- for (const auto &property : metaInfo.properties()) {
+ const PropertyMetaInfos props = metaInfo.properties();
+ for (const auto &property : props) {
if (property.isWritable())
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
@@ -446,7 +447,7 @@ QStringList DynamicPropertiesModel::possibleTargetProperties(const BindingProper
return possibleProperties;
}
- return QStringList();
+ return {};
}
void DynamicPropertiesModel::addDynamicPropertyForCurrentNode()
@@ -475,11 +476,10 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
NodeMetaInfo type;
- if (auto metaInfo = bindingProperty.parentModelNode().metaInfo(); metaInfo.isValid()) {
+ if (auto metaInfo = bindingProperty.parentModelNode().metaInfo(); metaInfo.isValid())
type = metaInfo.property(bindingProperty.name()).propertyType();
- } else {
+ else
qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for target node";
- }
const QString &id = stringlist.constFirst();
@@ -494,8 +494,9 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
if (metaInfo.isValid()) {
QStringList possibleProperties;
- for (const auto &property : metaInfo.properties()) {
- if (property.propertyType() == type) //### todo proper check
+ const PropertyMetaInfos props = metaInfo.properties();
+ for (const auto &property : props) {
+ if (property.propertyType() == type) // TODO: proper check
possibleProperties.push_back(QString::fromUtf8(property.name()));
}
return possibleProperties;
@@ -503,40 +504,39 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
qWarning() << " BindingModel::possibleSourcePropertiesForRow no meta info for source node";
}
- return QStringList();
+ return {};
}
void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
{
- m_view->executeInTransaction(
- "DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() {
- const AbstractProperty property = abstractPropertyForRow(rowNumber);
- const PropertyName propertyName = property.name();
- BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
- if (bindingProperty.isValid()) {
- bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
- } else {
- VariantProperty variantProperty = variantPropertyForRow(rowNumber);
- if (variantProperty.isValid())
- variantProperty.parentModelNode().removeProperty(variantProperty.name());
- }
+ m_view->executeInTransaction(__FUNCTION__, [this, rowNumber]() {
+ const AbstractProperty property = abstractPropertyForRow(rowNumber);
+ const PropertyName propertyName = property.name();
+ BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
+ if (bindingProperty.isValid()) {
+ bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
+ } else {
+ VariantProperty variantProperty = variantPropertyForRow(rowNumber);
+ if (variantProperty.isValid())
+ variantProperty.parentModelNode().removeProperty(variantProperty.name());
+ }
- if (property.isValid()) {
- QmlObjectNode objectNode = QmlObjectNode(property.parentModelNode());
- const auto stateOperations = objectNode.allAffectingStatesOperations();
- for (const QmlModelStateOperation &stateOperation : stateOperations) {
- if (stateOperation.modelNode().hasProperty(propertyName))
- stateOperation.modelNode().removeProperty(propertyName);
- }
+ if (property.isValid()) {
+ QmlObjectNode objectNode = QmlObjectNode(property.parentModelNode());
+ const auto stateOperations = objectNode.allAffectingStatesOperations();
+ for (const QmlModelStateOperation &stateOperation : stateOperations) {
+ if (stateOperation.modelNode().hasProperty(propertyName))
+ stateOperation.modelNode().removeProperty(propertyName);
+ }
- const auto timelineNodes = objectNode.allTimelines();
- for (auto &timelineNode : timelineNodes) {
- QmlTimeline timeline(timelineNode);
- timeline.removeKeyframesForTargetAndProperty(objectNode.modelNode(),
- propertyName);
- }
+ const QList<ModelNode> timelineNodes = objectNode.allTimelines();
+ for (auto &timelineNode : timelineNodes) {
+ QmlTimeline timeline(timelineNode);
+ timeline.removeKeyframesForTargetAndProperty(objectNode.modelNode(),
+ propertyName);
}
- });
+ }
+ });
resetModel();
}
@@ -555,7 +555,8 @@ void DynamicPropertiesModel::addProperty(const QVariant &propertyValue,
idItem = new QStandardItem(idOrTypeNameForNode(abstractProperty.parentModelNode()));
updateCustomData(idItem, abstractProperty);
- propertyNameItem = new QStandardItem(QString::fromUtf8(abstractProperty.name()));
+ const QString propName = QString::fromUtf8(abstractProperty.name());
+ propertyNameItem = new QStandardItem(propName);
items.append(idItem);
items.append(propertyNameItem);
@@ -567,6 +568,13 @@ void DynamicPropertiesModel::addProperty(const QVariant &propertyValue,
propertyValueItem->setData(propertyValue, Qt::DisplayRole);
items.append(propertyValueItem);
+ for (int i = 0; i < rowCount(); ++i) {
+ if (data(index(i, PropertyNameRow)).toString() > propName) {
+ insertRow(i, items);
+ return;
+ }
+ }
+
appendRow(items);
}
@@ -618,7 +626,6 @@ void DynamicPropertiesModel::updateVariantProperty(int rowNumber)
if (objectNode.isValid() && !objectNode.view()->currentState().isBaseState())
value = objectNode.modelValue(variantProperty.name());
-
updateDisplayRoleFromVariant(rowNumber, PropertyValueRow, value);
}
}
@@ -628,9 +635,8 @@ void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
if (!modelNode.isValid())
return;
- auto properties = modelNode.properties();
-
- auto dynamicProperties = Utils::filtered(properties, [](const AbstractProperty &p) {
+ const QList<AbstractProperty> properties = modelNode.properties();
+ QList<AbstractProperty> dynamicProperties = Utils::filtered(properties, [](const AbstractProperty &p) {
return p.isDynamic();
});
@@ -653,10 +659,10 @@ void DynamicPropertiesModel::updateValue(int row)
if (bindingProperty.isBindingProperty()) {
const QString expression = data(index(row, PropertyValueRow)).toString();
- RewriterTransaction transaction = m_view->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
+ RewriterTransaction transaction = m_view->beginRewriterTransaction(__FUNCTION__);
try {
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(), expression);
- transaction.commit(); //committing in the try block
+ transaction.commit(); // committing in the try block
} catch (Exception &e) {
m_exceptionError = e.description();
QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
@@ -669,10 +675,10 @@ void DynamicPropertiesModel::updateValue(int row)
if (variantProperty.isVariantProperty()) {
const QVariant value = data(index(row, PropertyValueRow));
- RewriterTransaction transaction = m_view->beginRewriterTransaction(QByteArrayLiteral("DynamicPropertiesModel::updateValue"));
+ RewriterTransaction transaction = m_view->beginRewriterTransaction(__FUNCTION__);
try {
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
- transaction.commit(); //committing in the try block
+ transaction.commit(); // committing in the try block
} catch (Exception &e) {
m_exceptionError = e.description();
QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
@@ -683,17 +689,14 @@ void DynamicPropertiesModel::updateValue(int row)
void DynamicPropertiesModel::updatePropertyName(int rowNumber)
{
const PropertyName newName = data(index(rowNumber, PropertyNameRow)).toString().toUtf8();
- if (newName.isEmpty()) {
- qWarning() << "DynamicPropertiesModel::updatePropertyName invalid property name";
- return;
- }
+ QTC_ASSERT(!newName.isEmpty(), return);
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
ModelNode targetNode = bindingProperty.parentModelNode();
if (bindingProperty.isBindingProperty()) {
- m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [bindingProperty, newName, &targetNode](){
+ m_view->executeInTransaction(__FUNCTION__, [bindingProperty, newName, &targetNode]() {
const QString expression = bindingProperty.expression();
const PropertyName dynamicPropertyType = bindingProperty.dynamicTypeName();
@@ -712,7 +715,7 @@ void DynamicPropertiesModel::updatePropertyName(int rowNumber)
const PropertyName dynamicPropertyType = variantProperty.dynamicTypeName();
ModelNode targetNode = variantProperty.parentModelNode();
- m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyName", [=](){
+ m_view->executeInTransaction(__FUNCTION__, [=]() {
targetNode.variantProperty(newName).setDynamicTypeNameAndValue(dynamicPropertyType, value);
targetNode.removeProperty(variantProperty.name());
});
@@ -723,13 +726,8 @@ void DynamicPropertiesModel::updatePropertyName(int rowNumber)
void DynamicPropertiesModel::updatePropertyType(int rowNumber)
{
-
const TypeName newType = data(index(rowNumber, PropertyTypeRow)).toString().toLatin1();
-
- if (newType.isEmpty()) {
- qWarning() << "DynamicPropertiesModel::updatePropertyName invalid property type";
- return;
- }
+ QTC_ASSERT(!newType.isEmpty(), return);
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
@@ -738,7 +736,7 @@ void DynamicPropertiesModel::updatePropertyType(int rowNumber)
const PropertyName propertyName = bindingProperty.name();
ModelNode targetNode = bindingProperty.parentModelNode();
- m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
+ m_view->executeInTransaction(__FUNCTION__, [=]() {
targetNode.removeProperty(bindingProperty.name());
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(newType, expression);
});
@@ -754,7 +752,7 @@ void DynamicPropertiesModel::updatePropertyType(int rowNumber)
ModelNode targetNode = variantProperty.parentModelNode();
const PropertyName propertyName = variantProperty.name();
- m_view->executeInTransaction("DynamicPropertiesModel::updatePropertyType", [=](){
+ m_view->executeInTransaction(__FUNCTION__, [=]() {
targetNode.removeProperty(variantProperty.name());
if (!isValueType(newType)) {
targetNode.bindingProperty(propertyName).setDynamicTypeNameAndExpression(
@@ -767,26 +765,22 @@ void DynamicPropertiesModel::updatePropertyType(int rowNumber)
updateCustomData(rowNumber, targetNode.variantProperty(propertyName));
- if (variantProperty.isVariantProperty()) {
+ if (variantProperty.isVariantProperty())
updateVariantProperty(rowNumber);
- } else if (bindingProperty.isBindingProperty()) {
+ else if (bindingProperty.isBindingProperty())
updateBindingProperty(rowNumber);
- }
}
}
ModelNode DynamicPropertiesModel::getNodeByIdOrParent(const QString &id, const ModelNode &targetNode) const
{
- ModelNode modelNode;
+ if (id != QLatin1String("parent"))
+ return m_view->modelNodeForId(id);
- if (id != QLatin1String("parent")) {
- modelNode = m_view->modelNodeForId(id);
- } else {
- if (targetNode.hasParentProperty()) {
- modelNode = targetNode.parentProperty().parentModelNode();
- }
- }
- return modelNode;
+ if (targetNode.hasParentProperty())
+ return targetNode.parentProperty().parentModelNode();
+
+ return {};
}
void DynamicPropertiesModel::updateCustomData(QStandardItem *item, const AbstractProperty &property)
@@ -803,54 +797,56 @@ void DynamicPropertiesModel::updateCustomData(int row, const AbstractProperty &p
int DynamicPropertiesModel::findRowForBindingProperty(const BindingProperty &bindingProperty) const
{
- for (int i=0; i < rowCount(); i++) {
+ for (int i = 0; i < rowCount(); ++i) {
if (compareBindingProperties(bindingPropertyForRow(i), bindingProperty))
return i;
}
- //not found
- return -1;
+
+ return -1; // not found
}
int DynamicPropertiesModel::findRowForVariantProperty(const VariantProperty &variantProperty) const
{
- for (int i=0; i < rowCount(); i++) {
+ for (int i = 0; i < rowCount(); ++i) {
if (compareVariantProperties(variantPropertyForRow(i), variantProperty))
return i;
}
- //not found
- return -1;
+
+ return -1; // not found
}
int DynamicPropertiesModel::findRowForProperty(const AbstractProperty &abstractProperty) const
{
- for (int i = 0; i < rowCount(); i++) {
+ for (int i = 0; i < rowCount(); ++i) {
if ((abstractPropertyForRow(i).name() == abstractProperty.name()))
return i;
}
- //not found
- return -1;
+
+ return -1; // not found
}
-bool DynamicPropertiesModel::getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty)
+bool DynamicPropertiesModel::getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode,
+ QString *sourceProperty)
{
- //### todo we assume no expressions yet
+ // TODO: we assume no expressions yet
const QString expression = bindingProperty.expression();
if (true) {
- const QStringList stringList = expression.split(QLatin1String("."));
+ const QStringList expressionParts = expression.split('.');
- *sourceNode = stringList.constFirst();
+ *sourceNode = expressionParts.constFirst();
QString propertyName;
- for (int i=1; i < stringList.count(); i++) {
- propertyName += stringList.at(i);
- if (i != stringList.count() - 1)
+ for (int i = 1; i < expressionParts.count(); ++i) {
+ propertyName += expressionParts.at(i);
+ if (i != expressionParts.count() - 1)
propertyName += QLatin1String(".");
}
*sourceProperty = propertyName;
}
+
return true;
}
@@ -875,7 +871,7 @@ void DynamicPropertiesModel::handleDataChanged(const QModelIndex &topLeft, const
return;
if (topLeft != bottomRight) {
- qWarning() << "BindingModel::handleDataChanged multi edit?";
+ qWarning() << __FUNCTION__ << ": multi edit?";
return;
}
@@ -886,7 +882,7 @@ void DynamicPropertiesModel::handleDataChanged(const QModelIndex &topLeft, const
switch (currentColumn) {
case TargetModelNodeRow: {
- //updating user data
+ // updating user data
} break;
case PropertyNameRow: {
updatePropertyName(currentRow);
@@ -898,7 +894,7 @@ void DynamicPropertiesModel::handleDataChanged(const QModelIndex &topLeft, const
updateValue(currentRow);
} break;
- default: qWarning() << "BindingModel::handleDataChanged column" << currentColumn;
+ default: qWarning() << __FUNCTION__ << " column" << currentColumn;
}
m_lock = false;
@@ -916,18 +912,16 @@ const QList<ModelNode> DynamicPropertiesModel::selectedNodes() const
// Otherwise return actual selected nodes of the model.
if (m_explicitSelection)
return m_selectedNodes;
- else
- return m_view->selectedModelNodes();
+
+ return m_view->selectedModelNodes();
}
const ModelNode DynamicPropertiesModel::singleSelectedNode() const
{
if (m_explicitSelection)
return m_selectedNodes.first();
- else
- return m_view->singleSelectedModelNode();
-}
-} // namespace Internal
+ return m_view->singleSelectedModelNode();
+}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
index fb8b5fb855..f094516e63 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/dynamicpropertiesmodel.h
@@ -3,17 +3,17 @@
#pragma once
-#include <modelnode.h>
-#include <bindingproperty.h>
-#include <variantproperty.h>
+#include <nodeinstanceglobal.h>
#include <QStandardItemModel>
namespace QmlDesigner {
+class AbstractProperty;
class AbstractView;
-
-namespace Internal {
+class BindingProperty;
+class ModelNode;
+class VariantProperty;
class DynamicPropertiesModel : public QStandardItemModel
{
@@ -22,11 +22,13 @@ class DynamicPropertiesModel : public QStandardItemModel
public:
enum ColumnRoles {
TargetModelNodeRow = 0,
- PropertyNameRow = 1,
- PropertyTypeRow = 2,
- PropertyValueRow = 3
+ PropertyNameRow = 1,
+ PropertyTypeRow = 2,
+ PropertyValueRow = 3
};
+
DynamicPropertiesModel(bool explicitSelection, AbstractView *parent);
+
void bindingPropertyChanged(const BindingProperty &bindingProperty);
void abstractPropertyChanged(const AbstractProperty &bindingProperty);
void variantPropertyChanged(const VariantProperty &variantProperty);
@@ -54,7 +56,7 @@ public:
void dispatchPropertyChanges(const AbstractProperty &abstractProperty);
- QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode);
+ PropertyName unusedProperty(const ModelNode &modelNode);
static bool isValueType(const TypeName &type);
static QVariant defaultValueForType(const TypeName &type);
@@ -84,7 +86,7 @@ protected:
void updateDisplayRole(int row, int columns, const QString &string);
private:
- void handleDataChanged(const QModelIndex &topLeft, const QModelIndex& bottomRight);
+ void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
void handleException();
AbstractView *m_view = nullptr;
@@ -95,5 +97,4 @@ private:
bool m_explicitSelection = false;
};
-} // namespace Internal
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.cpp
index 7232e83413..80cd732a9b 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.cpp
@@ -28,7 +28,7 @@
#include <dynamicpropertiesmodel.h>
#include <connectionview.h>
-using namespace QmlDesigner::Internal;
+namespace QmlDesigner {
SelectionDynamicPropertiesProxyModel::SelectionDynamicPropertiesProxyModel(QObject *parent)
: DynamicPropertiesProxyModel(parent)
@@ -42,3 +42,5 @@ void SelectionDynamicPropertiesProxyModel::registerDeclarativeType()
DynamicPropertiesProxyModel::registerDeclarativeType();
qmlRegisterType<SelectionDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "SelectionDynamicPropertiesModel");
}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.h b/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.h
index 124846dc86..8957abe5af 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/selectiondynamicpropertiesproxymodel.h
@@ -27,6 +27,8 @@
#include <dynamicpropertiesproxymodel.h>
+namespace QmlDesigner {
+
class SelectionDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
{
Q_OBJECT
@@ -35,3 +37,5 @@ public:
static void registerDeclarativeType();
};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
index d2811592cd..834bc8aa30 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.cpp
@@ -3,6 +3,8 @@
#include "contentlibrarymaterial.h"
+#include <QFileInfo>
+
namespace QmlDesigner {
ContentLibraryMaterial::ContentLibraryMaterial(QObject *parent,
@@ -10,8 +12,15 @@ ContentLibraryMaterial::ContentLibraryMaterial(QObject *parent,
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) {}
+ const QStringList &files,
+ const QString &downloadPath,
+ const QString &baseWebUrl)
+ : QObject(parent), m_name(name), m_qml(qml), m_type(type), m_icon(icon), m_files(files)
+ , m_downloadPath(downloadPath), m_baseWebUrl(baseWebUrl)
+{
+ m_allFiles = m_files;
+ m_allFiles.push_back(m_qml);
+}
bool ContentLibraryMaterial::filter(const QString &searchText)
{
@@ -64,4 +73,25 @@ bool ContentLibraryMaterial::imported() const
return m_imported;
}
+bool ContentLibraryMaterial::isDownloaded() const
+{
+ QString fullPath = qmlFilePath();
+ return QFileInfo(fullPath).isFile();
+}
+
+QString ContentLibraryMaterial::qmlFilePath() const
+{
+ return m_downloadPath + "/" + m_qml;
+}
+
+QString ContentLibraryMaterial::parentDirPath() const
+{
+ return m_downloadPath;
+}
+
+QStringList ContentLibraryMaterial::allFiles() const
+{
+ return m_allFiles;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
index cbcf5077dc..f546ea98cd 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterial.h
@@ -19,6 +19,9 @@ class ContentLibraryMaterial : public QObject
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(QString bundleMaterialBaseWebUrl MEMBER m_baseWebUrl CONSTANT)
+ Q_PROPERTY(QString bundleMaterialParentPath READ parentDirPath CONSTANT)
+ Q_PROPERTY(QStringList bundleMaterialFiles READ allFiles CONSTANT)
public:
ContentLibraryMaterial(QObject *parent,
@@ -26,18 +29,25 @@ public:
const QString &qml,
const TypeName &type,
const QUrl &icon,
- const QStringList &files);
+ const QStringList &files,
+ const QString &downloadPath,
+ const QString &baseWebUrl);
bool filter(const QString &searchText);
+ Q_INVOKABLE bool isDownloaded() const;
+
QUrl icon() const;
QString qml() const;
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:
void materialVisibleChanged();
@@ -52,6 +62,10 @@ private:
bool m_visible = true;
bool m_imported = false;
+
+ QString m_downloadPath;
+ QString m_baseWebUrl;
+ QStringList m_allFiles;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
index 5baf4bd068..127ecb4225 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
@@ -7,14 +7,21 @@
#include "contentlibrarymaterial.h"
#include "contentlibrarymaterialscategory.h"
#include "contentlibrarywidget.h"
+#include "filedownloader.h"
+#include "fileextractor.h"
+#include "multifiledownloader.h"
#include "qmldesignerconstants.h"
+#include "qmldesignerplugin.h"
-#include "utils/algorithm.h"
-#include "utils/qtcassert.h"
+#include <utils/algorithm.h>
+#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QJsonArray>
#include <QJsonDocument>
+#include <QQmlEngine>
+#include <QStandardPaths>
#include <QUrl>
namespace QmlDesigner {
@@ -23,7 +30,19 @@ ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(ContentLibraryWidget
: QAbstractListModel(parent)
, m_widget(parent)
{
- loadMaterialBundle();
+ m_downloadPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
+ + "/QtDesignStudio/bundles/Materials";
+
+ m_baseUrl = QmlDesignerPlugin::settings()
+ .value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL)
+ .toString() + "/materials/v1";
+
+ qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
+ qmlRegisterType<QmlDesigner::MultiFileDownloader>("WebFetcher", 1, 0, "MultiFileDownloader");
+
+ QDir bundleDir{m_downloadPath};
+ if (fetchBundleMetadata(bundleDir) && fetchBundleIcons(bundleDir))
+ loadMaterialBundle(bundleDir);
}
int ContentLibraryMaterialsModel::rowCount(const QModelIndex &) const
@@ -90,24 +109,126 @@ QHash<int, QByteArray> ContentLibraryMaterialsModel::roleNames() const
return roles;
}
-void ContentLibraryMaterialsModel::loadMaterialBundle()
+bool ContentLibraryMaterialsModel::fetchBundleIcons(const QDir &bundleDir)
{
- if (m_matBundleExists || m_probeMatBundleDir)
- return;
+ QString iconsPath = bundleDir.filePath("icons");
- QDir matBundleDir(qEnvironmentVariable("MATERIAL_BUNDLE_PATH"));
+ QDir iconsDir(iconsPath);
+ if (iconsDir.exists() && iconsDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).length() > 0)
+ return true;
- // search for matBundleDir from exec dir and up
- if (matBundleDir.dirName() == ".") {
- m_probeMatBundleDir = true; // probe only once
+ QString zipFileUrl = m_baseUrl + "/icons.zip";
- matBundleDir.setPath(QCoreApplication::applicationDirPath());
- while (!matBundleDir.cd("material_bundle") && matBundleDir.cdUp())
- ; // do nothing
+ FileDownloader *downloader = new FileDownloader(this);
+ downloader->setUrl(zipFileUrl);
+ downloader->setProbeUrl(false);
+ downloader->setDownloadEnabled(true);
- if (matBundleDir.dirName() != "material_bundle") // bundlePathDir not found
- return;
- }
+ QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
+ FileExtractor *extractor = new FileExtractor(this);
+ extractor->setArchiveName(downloader->completeBaseName());
+ extractor->setSourceFile(downloader->outputFile());
+ extractor->setTargetPath(bundleDir.absolutePath());
+ extractor->setAlwaysCreateDir(false);
+ extractor->setClearTargetPathContents(false);
+
+ QObject::connect(extractor, &FileExtractor::finishedChanged, this, [=]() {
+ downloader->deleteLater();
+ extractor->deleteLater();
+
+ loadMaterialBundle(bundleDir);
+ });
+
+ extractor->extract();
+ });
+
+ downloader->start();
+ return false;
+}
+
+bool ContentLibraryMaterialsModel::fetchBundleMetadata(const QDir &bundleDir)
+{
+ QString matBundlePath = bundleDir.filePath("material_bundle.json");
+
+ QFileInfo fi(matBundlePath);
+ if (fi.exists() && fi.size() > 0)
+ return true;
+
+ QString metaFileUrl = m_baseUrl + "/material_bundle.json";
+ FileDownloader *downloader = new FileDownloader(this);
+ downloader->setUrl(metaFileUrl);
+ downloader->setProbeUrl(false);
+ downloader->setDownloadEnabled(true);
+ downloader->setTargetFilePath(matBundlePath);
+
+ QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
+ if (fetchBundleIcons(bundleDir))
+ loadMaterialBundle(bundleDir);
+
+ downloader->deleteLater();
+ });
+
+ downloader->start();
+ return false;
+}
+
+void ContentLibraryMaterialsModel::downloadSharedFiles(const QDir &targetDir, const QStringList &)
+{
+ QString metaFileUrl = m_baseUrl + "/shared_files.zip";
+ FileDownloader *downloader = new FileDownloader(this);
+ downloader->setUrl(metaFileUrl);
+ downloader->setProbeUrl(false);
+ downloader->setDownloadEnabled(true);
+
+ QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
+ FileExtractor *extractor = new FileExtractor(this);
+ extractor->setArchiveName(downloader->completeBaseName());
+ extractor->setSourceFile(downloader->outputFile());
+ extractor->setTargetPath(targetDir.absolutePath());
+ extractor->setAlwaysCreateDir(false);
+ extractor->setClearTargetPathContents(false);
+
+ QObject::connect(extractor, &FileExtractor::finishedChanged, this, [this, downloader, extractor]() {
+ downloader->deleteLater();
+ extractor->deleteLater();
+
+ createImporter(m_importerBundlePath, m_importerBundleId, m_importerSharedFiles);
+ });
+
+ extractor->extract();
+ });
+
+ downloader->start();
+}
+
+void ContentLibraryMaterialsModel::createImporter(const QString &bundlePath, const QString &bundleId,
+ const QStringList &sharedFiles)
+{
+ m_importer = new Internal::ContentLibraryBundleImporter(bundlePath, bundleId, sharedFiles);
+ connect(m_importer, &Internal::ContentLibraryBundleImporter::importFinished, this,
+ [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
+ m_importerRunning = false;
+ emit importerRunningChanged();
+ if (metaInfo.isValid())
+ emit bundleMaterialImported(metaInfo);
+ });
+
+ connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this,
+ [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
+ Q_UNUSED(metaInfo)
+ m_importerRunning = false;
+ emit importerRunningChanged();
+ emit bundleMaterialUnimported(metaInfo);
+ });
+
+ resetModel();
+ updateIsEmpty();
+}
+
+void ContentLibraryMaterialsModel::loadMaterialBundle(const QDir &matBundleDir)
+{
+ if (m_matBundleExists)
+ return;
QString matBundlePath = matBundleDir.filePath("material_bundle.json");
@@ -128,8 +249,6 @@ void ContentLibraryMaterialsModel::loadMaterialBundle()
}
}
- m_matBundleExists = true;
-
QString bundleId = m_matBundleObj.value("id").toString();
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
@@ -154,7 +273,8 @@ void ContentLibraryMaterialsModel::loadMaterialBundle()
bundleId,
qml.chopped(4)).toLatin1(); // chopped(4): remove .qml
- auto bundleMat = new ContentLibraryMaterial(category, mat, qml, type, icon, files);
+ auto bundleMat = new ContentLibraryMaterial(category, mat, qml, type, icon, files,
+ m_downloadPath, m_baseUrl);
category->addBundleMaterial(bundleMat);
}
@@ -166,24 +286,25 @@ void ContentLibraryMaterialsModel::loadMaterialBundle()
for (const auto /*QJson{Const,}ValueRef*/ &file : sharedFilesArr)
sharedFiles.append(file.toString());
- m_importer = new Internal::ContentLibraryBundleImporter(matBundleDir.path(), bundleId, sharedFiles);
- connect(m_importer, &Internal::ContentLibraryBundleImporter::importFinished, this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- m_importerRunning = false;
- emit importerRunningChanged();
- if (metaInfo.isValid())
- emit bundleMaterialImported(metaInfo);
- });
+ QStringList missingSharedFiles;
+ for (const QString &s : std::as_const(sharedFiles)) {
+ const QString fullSharedFilePath = matBundleDir.filePath(s);
- connect(m_importer, &Internal::ContentLibraryBundleImporter::unimportFinished, this,
- [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
- Q_UNUSED(metaInfo)
- m_importerRunning = false;
- emit importerRunningChanged();
- emit bundleMaterialUnimported(metaInfo);
- });
+ if (!QFile::exists(fullSharedFilePath))
+ missingSharedFiles.push_back(s);
+ }
- updateIsEmpty();
+ if (missingSharedFiles.length() > 0) {
+ m_importerBundlePath = matBundleDir.path();
+ m_importerBundleId = bundleId;
+ m_importerSharedFiles = sharedFiles;
+ downloadSharedFiles(matBundleDir, missingSharedFiles);
+ } else {
+ createImporter(matBundleDir.path(), bundleId, sharedFiles);
+ }
+
+ m_matBundleExists = true;
+ emit matBundleExistsChanged();
}
bool ContentLibraryMaterialsModel::hasRequiredQuick3DImport() const
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
index 2fcd152f54..836ebc6c1e 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.h
@@ -6,6 +6,7 @@
#include "nodemetainfo.h"
#include <QAbstractListModel>
+#include <QDir>
#include <QJsonObject>
namespace QmlDesigner {
@@ -70,8 +71,13 @@ signals:
void matBundleExistsChanged();
private:
- void loadMaterialBundle();
+ void loadMaterialBundle(const QDir &matBundleDir);
+ bool fetchBundleIcons(const QDir &bundleDir);
+ 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;
@@ -82,11 +88,17 @@ private:
bool m_isEmpty = true;
bool m_matBundleExists = false;
bool m_hasModelSelection = false;
- bool m_probeMatBundleDir = false;
bool m_importerRunning = 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 d14d56b7d5..fbc5199f98 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp
@@ -4,20 +4,33 @@
#include "contentlibrarytexture.h"
#include "imageutils.h"
+#include <utils/algorithm.h>
+
+#include <QDir>
+#include <QFileInfo>
namespace QmlDesigner {
-ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QString &path, const QUrl &icon)
+ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo,
+ const QString &downloadPath, const QUrl &icon,
+ const QString &webUrl, const QString &fileExt,
+ const QSize &dimensions, const qint64 sizeInBytes)
: QObject(parent)
- , m_path(path)
+ , m_iconPath(iconFileInfo.filePath())
+ , m_downloadPath(downloadPath)
+ , m_webUrl(webUrl)
+ , m_baseName{iconFileInfo.baseName()}
+ , m_fileExt(fileExt)
, m_icon(icon)
+ , m_dimensions(dimensions)
+ , m_sizeInBytes(sizeInBytes)
{
- m_toolTip = QLatin1String("%1\n%2").arg(path.split('/').last(), ImageUtils::imageInfo(path));
+ doSetDownloaded();
}
bool ContentLibraryTexture::filter(const QString &searchText)
{
- if (m_visible != m_path.contains(searchText, Qt::CaseInsensitive)) {
+ if (m_visible != m_iconPath.contains(searchText, Qt::CaseInsensitive)) {
m_visible = !m_visible;
emit textureVisibleChanged();
}
@@ -30,9 +43,83 @@ QUrl ContentLibraryTexture::icon() const
return m_icon;
}
-QString ContentLibraryTexture::path() const
+QString ContentLibraryTexture::iconPath() const
+{
+ return m_iconPath;
+}
+
+QString ContentLibraryTexture::resolveFileExt()
+{
+ const QFileInfoList files = QDir(m_downloadPath).entryInfoList(QDir::Files);
+ const QFileInfoList textureFiles = Utils::filtered(files, [this](const QFileInfo &fi) {
+ return fi.baseName() == m_baseName;
+ });
+
+ if (textureFiles.isEmpty())
+ return {};
+
+ if (textureFiles.count() > 1) {
+ qWarning() << "Found multiple textures with the same name in the same directories: "
+ << Utils::transform(textureFiles, [](const QFileInfo &fi) {
+ return fi.fileName();
+ });
+ }
+
+ return '.' + textureFiles.at(0).completeSuffix();
+}
+
+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;
+ }
+
+ QString fileName = m_baseName + m_fileExt;
+ QString imageInfo;
+
+ if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) {
+ imageInfo = ImageUtils::imageInfo(m_dimensions, m_sizeInBytes);
+ } else {
+ QString fullDownloadPath = m_downloadPath + '/' + fileName;
+ imageInfo = ImageUtils::imageInfo(fullDownloadPath);
+ }
+
+ return QStringLiteral("%1\n%2").arg(fileName, imageInfo);
+}
+
+bool ContentLibraryTexture::isDownloaded() const
+{
+ return m_isDownloaded;
+}
+
+QString ContentLibraryTexture::downloadedTexturePath() const
+{
+ return m_downloadPath + '/' + m_baseName + m_fileExt;
+}
+
+void ContentLibraryTexture::setDownloaded()
+{
+ QString toolTip = m_toolTip;
+
+ doSetDownloaded();
+
+ if (toolTip != m_toolTip)
+ emit textureToolTipChanged();
+}
+
+void ContentLibraryTexture::doSetDownloaded()
+{
+ if (m_fileExt.isEmpty())
+ m_fileExt = resolveFileExt();
+
+ m_isDownloaded = QFileInfo::exists(downloadedTexturePath());
+ m_toolTip = resolveToolTipText();
+}
+
+QString ContentLibraryTexture::parentDirPath() const
{
- return m_path;
+ return m_downloadPath;
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
index 399b7644ce..074d4abb77 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h
@@ -3,7 +3,9 @@
#pragma once
+#include <QFileInfo>
#include <QObject>
+#include <QSize>
#include <QUrl>
namespace QmlDesigner {
@@ -12,26 +14,47 @@ class ContentLibraryTexture : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString texturePath MEMBER m_path CONSTANT)
- Q_PROPERTY(QString textureToolTip MEMBER m_toolTip CONSTANT)
+ Q_PROPERTY(QString textureIconPath MEMBER m_iconPath CONSTANT)
+ Q_PROPERTY(QString textureParentPath READ parentDirPath CONSTANT)
+ 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_webUrl CONSTANT)
public:
- ContentLibraryTexture(QObject *parent, const QString &path, const QUrl &icon);
+ ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo,
+ const QString &downloadPath, const QUrl &icon, const QString &webUrl,
+ const QString &fileExt, const QSize &dimensions, const qint64 sizeInBytes);
+
+ Q_INVOKABLE bool isDownloaded() const;
+ Q_INVOKABLE void setDownloaded();
bool filter(const QString &searchText);
QUrl icon() const;
- QString path() const;
+ QString iconPath() const;
+ QString downloadedTexturePath() const;
+ QString parentDirPath() const;
signals:
void textureVisibleChanged();
+ void textureToolTipChanged();
private:
- QString m_path;
+ QString resolveFileExt();
+ QString resolveToolTipText();
+ void doSetDownloaded();
+
+ QString m_iconPath;
+ QString m_downloadPath;
+ QString m_webUrl;
QString m_toolTip;
+ QString m_baseName;
+ QString m_fileExt;
QUrl m_icon;
+ QSize m_dimensions;
+ qint64 m_sizeInBytes = -1;
+ bool m_isDownloaded = false;
bool m_visible = true;
};
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
index d2de827f03..eecab42552 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp
@@ -12,10 +12,14 @@ namespace QmlDesigner {
ContentLibraryTexturesCategory::ContentLibraryTexturesCategory(QObject *parent, const QString &name)
: QObject(parent), m_name(name) {}
-void ContentLibraryTexturesCategory::addTexture(const QFileInfo &tex)
+void ContentLibraryTexturesCategory::addTexture(const QFileInfo &tex, const QString &downloadPath,
+ const QString &webUrl, const QString &fileExt,
+ const QSize &dimensions, const qint64 sizeInBytes)
{
- QUrl icon = QUrl::fromLocalFile(tex.path() + "/icon/" + tex.baseName() + ".png");
- m_categoryTextures.append(new ContentLibraryTexture(this, tex.filePath(), icon));
+ QUrl icon = QUrl::fromLocalFile(tex.absoluteFilePath());
+
+ m_categoryTextures.append(new ContentLibraryTexture(this, tex, downloadPath, icon, webUrl,
+ fileExt, dimensions, sizeInBytes));
}
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 69aeeb3297..91ecaaac96 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h
@@ -7,6 +7,7 @@
QT_BEGIN_NAMESPACE
class QFileInfo;
+class QSize;
QT_END_NAMESPACE
namespace QmlDesigner {
@@ -26,7 +27,8 @@ class ContentLibraryTexturesCategory : public QObject
public:
ContentLibraryTexturesCategory(QObject *parent, const QString &name);
- void addTexture(const QFileInfo &tex);
+ void addTexture(const QFileInfo &tex, const QString &subPath, const QString &webUrl,
+ const QString &fileExt, const QSize &dimensions, const qint64 sizeInBytes);
bool filter(const QString &searchText);
QString name() const;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
index 0dfc8eb530..0d74be596f 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
@@ -4,20 +4,29 @@
#include "contentlibrarytexturesmodel.h"
#include "contentlibrarytexturescategory.h"
+#include "qmldesignerplugin.h"
-#include "utils/algorithm.h"
-#include "utils/qtcassert.h"
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
#include <QCoreApplication>
#include <QDir>
+#include <QFile>
#include <QFileInfo>
+#include <QJsonDocument>
+#include <QQmlEngine>
+#include <QSize>
+#include <QStandardPaths>
#include <QUrl>
namespace QmlDesigner {
-ContentLibraryTexturesModel::ContentLibraryTexturesModel(QObject *parent)
+ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &category, QObject *parent)
: QAbstractListModel(parent)
{
+ m_category = category; // textures main category (ex: Textures, Environments)
}
int ContentLibraryTexturesModel::rowCount(const QModelIndex &) const
@@ -83,26 +92,53 @@ QHash<int, QByteArray> ContentLibraryTexturesModel::roleNames() const
return roles;
}
-void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath)
+/**
+ * @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
+ */
+void ContentLibraryTexturesModel::loadTextureBundle(const QString &remoteUrl, const QString &bundleIconPath,
+ const QVariantMap &metaData)
{
- QDir bundleDir = QDir(bundlePath);
+ 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." << bundlePath;
+ qWarning() << __FUNCTION__ << "textures bundle folder doesn't exist." << bundleDir.absolutePath();
return;
}
- if (!m_bundleCategories.isEmpty())
- return;
+ const QVariantMap imageItems = metaData.value("image_items").toMap();
- const QFileInfoList dirs = bundleDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ 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)
- category->addTexture(tex);
+ for (const QFileInfo &tex : texFiles) {
+ QString fullRemoteUrl = QString("%1/%2/%3.zip").arg(remoteUrl, dir.fileName(),
+ tex.baseName());
+ QString localDownloadPath = QString("%1/%2/%3").arg(QmlDesignerBasePlugin::bundlesPathSetting(),
+ m_category, dir.fileName());
+ QString key = QString("%1/%2/%3").arg(m_category, dir.fileName(), tex.baseName());
+ QString fileExt;
+ QSize dimensions;
+ qint64 sizeInBytes = -1;
+
+ if (imageItems.contains(key)) {
+ QVariantMap dataMap = imageItems[key].toMap();
+ fileExt = '.' + dataMap.value("format").toString();
+ dimensions = QSize(dataMap.value("width").toInt(), dataMap.value("height").toInt());
+ sizeInBytes = dataMap.value("file_size").toLongLong();
+ }
+
+ category->addTexture(tex, localDownloadPath, fullRemoteUrl, fileExt, dimensions, sizeInBytes);
+ }
m_bundleCategories.append(category);
}
+ resetModel();
updateIsEmpty();
}
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
index 077199d84f..3f7e4d4868 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h
@@ -18,7 +18,7 @@ class ContentLibraryTexturesModel : public QAbstractListModel
Q_PROPERTY(bool hasSceneEnv READ hasSceneEnv NOTIFY hasSceneEnvChanged)
public:
- ContentLibraryTexturesModel(QObject *parent = nullptr);
+ ContentLibraryTexturesModel(const QString &category, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@@ -33,7 +33,8 @@ public:
void setHasSceneEnv(bool b);
void resetModel();
- void loadTextureBundle(const QString &bundlePath);
+ void loadTextureBundle(const QString &remoteUrl, const QString &bundlePath,
+ const QVariantMap &metaData);
signals:
void isEmptyChanged();
@@ -45,6 +46,7 @@ private:
void updateIsEmpty();
QString m_searchText;
+ QString m_category;
QList<ContentLibraryTexturesCategory *> m_bundleCategories;
bool m_isEmpty = true;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
index ca1e288815..9ce7a4e737 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
@@ -30,7 +30,7 @@ namespace QmlDesigner {
ContentLibraryView::ContentLibraryView(ExternalDependenciesInterface &externalDependencies)
: AbstractView(externalDependencies)
- , m_createTexture(this, true)
+ , m_createTexture(this)
{}
ContentLibraryView::~ContentLibraryView()
@@ -132,6 +132,8 @@ void ContentLibraryView::modelAttached(Model *model)
m_widget->setHasQuick3DImport(m_hasQuick3DImport);
m_sceneId = model->active3DSceneId();
+
+ m_widget->clearSearchFilter();
}
void ContentLibraryView::modelAboutToBeDetached(Model *model)
@@ -323,6 +325,8 @@ ModelNode ContentLibraryView::createMaterial(const NodeMetaInfo &metaInfo)
VariantProperty objNameProp = newMatNode.variantProperty("objectName");
objNameProp.setValue(newName);
+ emitCustomNotification("focus_material_section", {});
+
return newMatNode;
}
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
index 89256a1e5f..a1dfff5ef5 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
@@ -8,26 +8,36 @@
#include "contentlibrarytexture.h"
#include "contentlibrarytexturesmodel.h"
+#include "utils/filedownloader.h"
+#include "utils/fileextractor.h"
+
#include <coreplugin/icore.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
+#include <studioquickwidget.h>
#include <theme.h>
#include <utils/algorithm.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
+#include <QDir>
+#include <QJsonDocument>
#include <QMimeData>
#include <QMouseEvent>
#include <QQmlContext>
-#include <QQuickWidget>
#include <QQmlEngine>
#include <QQuickItem>
+#include <QQuickWidget>
#include <QShortcut>
+#include <QStandardPaths>
#include <QVBoxLayout>
namespace QmlDesigner {
+constexpr int TextureBundleMetadataVersion = 1;
+
static QString propertyEditorResourcesPath()
{
#ifdef SHARE_QML_PATH
@@ -40,7 +50,7 @@ static QString propertyEditorResourcesPath()
bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FocusOut) {
- if (obj == m_quickWidget.data())
+ if (obj == m_quickWidget->quickWidget())
QMetaObject::invokeMethod(m_quickWidget->rootObject(), "closeContextMenu");
} else if (event->type() == QMouseEvent::MouseMove) {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -50,7 +60,8 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
if (m_materialToDrag) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
- if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) {
+ if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20
+ && m_materialToDrag->isDownloaded()) {
QByteArray data;
QMimeData *mimeData = new QMimeData;
QDataStream stream(&data, QIODevice::WriteOnly);
@@ -64,13 +75,14 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
}
} else if (m_textureToDrag) {
QMouseEvent *me = static_cast<QMouseEvent *>(event);
- if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20) {
- QByteArray data;
+ if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20
+ && m_textureToDrag->isDownloaded()) {
QMimeData *mimeData = new QMimeData;
- QDataStream stream(&data, QIODevice::WriteOnly);
- stream << m_textureToDrag->path();
- mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE, data);
- mimeData->removeFormat("text/plain");
+ mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE,
+ {m_textureToDrag->downloadedTexturePath().toUtf8()});
+
+ // Allows standard file drag-n-drop. As of now needed to drop on Assets view
+ mimeData->setUrls({QUrl::fromLocalFile(m_textureToDrag->downloadedTexturePath())});
emit bundleTextureDragStarted(m_textureToDrag);
model->startDrag(mimeData, m_textureToDrag->icon().toLocalFile());
@@ -80,37 +92,43 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event)
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_materialToDrag = nullptr;
m_textureToDrag = nullptr;
+ setIsDragging(false);
}
return QObject::eventFilter(obj, event);
}
ContentLibraryWidget::ContentLibraryWidget()
- : m_quickWidget(new QQuickWidget(this))
+ : m_quickWidget(new StudioQuickWidget(this))
, m_materialsModel(new ContentLibraryMaterialsModel(this))
- , m_texturesModel(new ContentLibraryTexturesModel(this))
- , m_environmentsModel(new ContentLibraryTexturesModel(this))
+ , m_texturesModel(new ContentLibraryTexturesModel("Textures", this))
+ , m_environmentsModel(new ContentLibraryTexturesModel("Environments", this))
{
+ qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
+ qmlRegisterType<QmlDesigner::FileExtractor>("WebFetcher", 1, 0, "FileExtractor");
+
setWindowTitle(tr("Content Library", "Title of content library widget"));
setMinimumWidth(120);
+ m_quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_CONTENT_LIBRARY);
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
- QString textureBundlePath = findTextureBundlePath();
- m_texturesModel->loadTextureBundle(textureBundlePath + "/Textures");
- m_environmentsModel->loadTextureBundle(textureBundlePath + "/Environments");
+ m_baseUrl = QmlDesignerPlugin::settings()
+ .value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString()
+ + "/textures/v1";
- m_quickWidget->rootContext()->setContextProperties({
- {"rootView", QVariant::fromValue(this)},
- {"materialsModel", QVariant::fromValue(m_materialsModel.data())},
- {"texturesModel", QVariant::fromValue(m_texturesModel.data())},
- {"environmentsModel", QVariant::fromValue(m_environmentsModel.data())},
- });
+ m_texturesUrl = m_baseUrl + "/Textures";
+ m_environmentsUrl = m_baseUrl + "/Environments";
+
+ m_downloadPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
+ + "/QtDesignStudio/bundles";
+
+ loadTextureBundle();
Theme::setupTheme(m_quickWidget->engine());
- m_quickWidget->installEventFilter(this);
+ m_quickWidget->quickWidget()->installEventFilter(this);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
@@ -125,11 +143,127 @@ ContentLibraryWidget::ContentLibraryWidget()
m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F11), this);
connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ContentLibraryWidget::reloadQmlSource);
-// QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_MATERIALBROWSER_TIME); // TODO
+ QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_CONTENTLIBRARY_TIME);
+
+ auto map = m_quickWidget->registerPropertyMap("ContentLibraryBackend");
+
+ map->setProperties({{"rootView", QVariant::fromValue(this)},
+ {"materialsModel", QVariant::fromValue(m_materialsModel.data())},
+ {"texturesModel", QVariant::fromValue(m_texturesModel.data())},
+ {"environmentsModel", QVariant::fromValue(m_environmentsModel.data())}});
reloadQmlSource();
}
+QVariantMap ContentLibraryWidget::readBundleMetadata()
+{
+ QVariantMap metaData;
+ QFile jsonFile(m_downloadPath + "/texture_bundle.json");
+ if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ metaData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap();
+
+ int version = metaData["version"].toInt();
+ if (version > TextureBundleMetadataVersion) {
+ qWarning() << "Unrecognized texture metadata file version: " << version;
+ return {};
+ }
+
+ return metaData;
+}
+
+void ContentLibraryWidget::loadTextureBundle()
+{
+ QDir bundleDir{m_downloadPath};
+
+ if (fetchTextureBundleMetadata(bundleDir) && fetchTextureBundleIcons(bundleDir)) {
+ QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
+ QVariantMap metaData = readBundleMetadata();
+ m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
+ m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
+ }
+}
+
+bool ContentLibraryWidget::fetchTextureBundleMetadata(const QDir &bundleDir)
+{
+ QString filePath = bundleDir.filePath("texture_bundle.json");
+
+ QFileInfo fi(filePath);
+ if (fi.exists() && fi.size() > 0)
+ return true;
+
+ QString metaFileUrl = m_baseUrl + "/texture_bundle.zip";
+ FileDownloader *downloader = new FileDownloader(this);
+ downloader->setUrl(metaFileUrl);
+ downloader->setProbeUrl(false);
+ downloader->setDownloadEnabled(true);
+
+ QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
+ FileExtractor *extractor = new FileExtractor(this);
+ extractor->setArchiveName(downloader->completeBaseName());
+ extractor->setSourceFile(downloader->outputFile());
+ extractor->setTargetPath(bundleDir.absolutePath());
+ extractor->setAlwaysCreateDir(false);
+ extractor->setClearTargetPathContents(false);
+
+ QObject::connect(extractor, &FileExtractor::finishedChanged, this, [=]() {
+ downloader->deleteLater();
+ extractor->deleteLater();
+
+ if (fetchTextureBundleIcons(bundleDir)) {
+ QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
+ QVariantMap metaData = readBundleMetadata();
+ m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
+ m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
+ }
+ });
+
+ extractor->extract();
+ });
+
+ downloader->start();
+ return false;
+}
+
+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)
+ return true;
+
+ QString zipFileUrl = m_baseUrl + "/icons.zip";
+
+ FileDownloader *downloader = new FileDownloader(this);
+ downloader->setUrl(zipFileUrl);
+ downloader->setProbeUrl(false);
+ downloader->setDownloadEnabled(true);
+
+ QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
+ FileExtractor *extractor = new FileExtractor(this);
+ extractor->setArchiveName(downloader->completeBaseName());
+ extractor->setSourceFile(downloader->outputFile());
+ extractor->setTargetPath(bundleDir.absolutePath());
+ extractor->setAlwaysCreateDir(false);
+ extractor->setClearTargetPathContents(false);
+
+ QObject::connect(extractor, &FileExtractor::finishedChanged, this, [=]() {
+ downloader->deleteLater();
+ extractor->deleteLater();
+
+ QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
+ QVariantMap metaData = readBundleMetadata();
+ m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
+ m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
+ });
+
+ extractor->extract();
+ });
+
+ downloader->start();
+ return false;
+}
+
QList<QToolButton *> ContentLibraryWidget::createToolBarWidgets()
{
return {};
@@ -201,7 +335,6 @@ void ContentLibraryWidget::reloadQmlSource()
QTC_ASSERT(QFileInfo::exists(materialBrowserQmlPath), return);
- m_quickWidget->engine()->clearComponentCache();
m_quickWidget->setSource(QUrl::fromLocalFile(materialBrowserQmlPath));
}
@@ -213,9 +346,22 @@ void ContentLibraryWidget::updateSearch()
m_quickWidget->update();
}
+void ContentLibraryWidget::setIsDragging(bool val)
+{
+ if (m_isDragging != val) {
+ m_isDragging = val;
+ emit isDraggingChanged();
+ }
+}
+
QString ContentLibraryWidget::findTextureBundlePath()
{
- QDir texBundleDir(qEnvironmentVariable("TEXTURE_BUNDLE_PATH"));
+ 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() == ".") {
@@ -235,6 +381,7 @@ void ContentLibraryWidget::startDragMaterial(QmlDesigner::ContentLibraryMaterial
{
m_materialToDrag = mat;
m_dragStartPoint = mousePos.toPoint();
+ setIsDragging(true);
}
void ContentLibraryWidget::startDragTexture(QmlDesigner::ContentLibraryTexture *tex,
@@ -242,21 +389,31 @@ void ContentLibraryWidget::startDragTexture(QmlDesigner::ContentLibraryTexture *
{
m_textureToDrag = tex;
m_dragStartPoint = mousePos.toPoint();
+ setIsDragging(true);
}
void ContentLibraryWidget::addImage(ContentLibraryTexture *tex)
{
- emit addTextureRequested(tex->path(), AddTextureMode::Image);
+ if (!tex->isDownloaded())
+ return;
+
+ emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Image);
}
void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex)
{
- emit addTextureRequested(tex->path(), AddTextureMode::Texture);
+ if (!tex->isDownloaded())
+ return;
+
+ emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Texture);
}
void ContentLibraryWidget::addLightProbe(ContentLibraryTexture *tex)
{
- emit addTextureRequested(tex->path(), AddTextureMode::LightProbe);
+ if (!tex->isDownloaded())
+ return;
+
+ emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::LightProbe);
}
void ContentLibraryWidget::updateSceneEnvState()
@@ -279,4 +436,18 @@ QPointer<ContentLibraryTexturesModel> ContentLibraryWidget::environmentsModel()
return m_environmentsModel;
}
+bool ContentLibraryWidget::markTextureDownloading()
+{
+ if (m_anyTextureBeingDownloaded)
+ return false;
+
+ m_anyTextureBeingDownloaded = true;
+ return true; // let the caller know it can begin download
+}
+
+void ContentLibraryWidget::markNoTextureDownloading()
+{
+ m_anyTextureBeingDownloaded = false; // allow other textures to be downloaded
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
index 6de5042ed6..519d6fcf78 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
@@ -9,11 +9,13 @@
#include <QPointer>
QT_BEGIN_NAMESPACE
+class QDir;
class QShortcut;
class QToolButton;
-class QQuickWidget;
QT_END_NAMESPACE
+class StudioQuickWidget;
+
namespace QmlDesigner {
class ContentLibraryTexture;
@@ -28,6 +30,9 @@ class ContentLibraryWidget : public QFrame
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasMaterialLibrary READ hasMaterialLibrary NOTIFY hasMaterialLibraryChanged)
+ // 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)
+
public:
ContentLibraryWidget();
@@ -56,6 +61,8 @@ public:
Q_INVOKABLE void addTexture(QmlDesigner::ContentLibraryTexture *tex);
Q_INVOKABLE void addLightProbe(QmlDesigner::ContentLibraryTexture *tex);
Q_INVOKABLE void updateSceneEnvState();
+ Q_INVOKABLE bool markTextureDownloading();
+ Q_INVOKABLE void markNoTextureDownloading();
signals:
void bundleMaterialDragStarted(QmlDesigner::ContentLibraryMaterial *bundleMat);
@@ -64,6 +71,7 @@ signals:
void updateSceneEnvStateRequested();
void hasQuick3DImportChanged();
void hasMaterialLibraryChanged();
+ void isDraggingChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -71,9 +79,14 @@ protected:
private:
void reloadQmlSource();
void updateSearch();
+ void setIsDragging(bool val);
QString findTextureBundlePath();
+ void loadTextureBundle();
+ QVariantMap readBundleMetadata();
+ bool fetchTextureBundleMetadata(const QDir &bundleDir);
+ bool fetchTextureBundleIcons(const QDir &bundleDir);
- QScopedPointer<QQuickWidget> m_quickWidget;
+ QScopedPointer<StudioQuickWidget> m_quickWidget;
QPointer<ContentLibraryMaterialsModel> m_materialsModel;
QPointer<ContentLibraryTexturesModel> m_texturesModel;
QPointer<ContentLibraryTexturesModel> m_environmentsModel;
@@ -88,6 +101,12 @@ private:
bool m_hasMaterialLibrary = false;
bool m_hasQuick3DImport = false;
+ bool m_isDragging = false;
+ bool m_anyTextureBeingDownloaded = false;
+ QString m_baseUrl;
+ QString m_texturesUrl;
+ QString m_environmentsUrl;
+ QString m_downloadPath;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/createtexture.cpp b/src/plugins/qmldesigner/components/createtexture.cpp
index 1ef8190048..8ef538bd2f 100644
--- a/src/plugins/qmldesigner/components/createtexture.cpp
+++ b/src/plugins/qmldesigner/components/createtexture.cpp
@@ -4,7 +4,9 @@
#include "createtexture.h"
#include "abstractview.h"
+#include "asset.h"
#include "documentmanager.h"
+#include "modelnode.h"
#include "modelnodeoperations.h"
#include "nodelistproperty.h"
#include "nodemetainfo.h"
@@ -17,27 +19,39 @@
namespace QmlDesigner {
-CreateTexture::CreateTexture(AbstractView *view, bool importFile)
+CreateTexture::CreateTexture(AbstractView *view)
: m_view{view}
- , m_importFile{importFile}
{}
-void CreateTexture::execute(const QString &filePath, AddTextureMode mode, int sceneId)
+ModelNode CreateTexture::execute(const QString &filePath, AddTextureMode mode, int sceneId)
{
- if (m_importFile && !addFileToProject(filePath))
- return;
+ Asset asset(filePath);
+ if (!asset.isValidTextureSource())
+ return {};
+
+ Utils::FilePath assetPath = Utils::FilePath::fromString(filePath);
+ if (!assetPath.isChildOf(DocumentManager::currentResourcePath())) {
+ if (!addFileToProject(filePath))
+ return {};
+
+ // after importing change assetPath to path in project
+ QString assetName = assetPath.fileName();
+ assetPath = ModelNodeOperations::getImagesDefaultDirectory().pathAppended(assetName);
+ }
- ModelNode texture = createTextureFromImage(filePath, mode);
+ ModelNode texture = createTextureFromImage(assetPath, mode);
if (!texture.isValid())
- return;
+ return {};
if (mode == AddTextureMode::LightProbe && sceneId != -1)
assignTextureAsLightProbe(texture, sceneId);
QTimer::singleShot(0, m_view, [this, texture]() {
if (m_view->model())
- m_view->emitCustomNotification("selected_texture_changed", {texture});
+ m_view->emitCustomNotification("select_texture", {texture}, {true});
});
+
+ return texture;
}
bool CreateTexture::addFileToProject(const QString &filePath)
@@ -54,7 +68,7 @@ bool CreateTexture::addFileToProject(const QString &filePath)
return true;
}
-ModelNode CreateTexture::createTextureFromImage(const QString &assetPath, AddTextureMode mode)
+ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPath, AddTextureMode mode)
{
if (mode != AddTextureMode::Texture && mode != AddTextureMode::LightProbe)
return {};
@@ -65,25 +79,16 @@ ModelNode CreateTexture::createTextureFromImage(const QString &assetPath, AddTex
NodeMetaInfo metaInfo = m_view->model()->qtQuick3DTextureMetaInfo();
- Utils::FilePath currentDocumentPath = QmlDesigner::DocumentManager::currentFilePath();
- Utils::FilePath imageTargetPath;
- if (m_importFile) {
- QString assetName = Utils::FilePath::fromString(assetPath).fileName();
- // if the asset had to be imported from somewhere else, then assetPath is the source where
- // the asset was taken from, and we have to compute where it was placed in the project.
- imageTargetPath = ModelNodeOperations::getImagesDefaultDirectory().pathAppended(assetName);
- } else {
- imageTargetPath = Utils::FilePath::fromString(assetPath);
- }
-
- QString textureSource = imageTargetPath.relativePathFrom(currentDocumentPath).toString();
+ QString textureSource = assetPath.relativePathFrom(DocumentManager::currentFilePath()).toString();
ModelNode newTexNode = m_view->getTextureDefaultInstance(textureSource);
if (!newTexNode.isValid()) {
newTexNode = m_view->createModelNode("QtQuick3D.Texture",
metaInfo.majorVersion(),
metaInfo.minorVersion());
- newTexNode.validId();
+
+ newTexNode.setIdWithoutRefactoring(m_view->model()->generateNewId(assetPath.baseName()));
+
VariantProperty sourceProp = newTexNode.variantProperty("source");
sourceProp.setValue(textureSource);
matLib.defaultNodeListProperty().reparentHere(newTexNode);
@@ -130,4 +135,10 @@ ModelNode CreateTexture::resolveSceneEnv(int sceneId)
return activeSceneEnv;
}
+void CreateTextures::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId)
+{
+ for (const QString &path : filePaths)
+ CreateTexture::execute(path, mode, sceneId);
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/createtexture.h b/src/plugins/qmldesigner/components/createtexture.h
index d02eacc1ee..326696c67d 100644
--- a/src/plugins/qmldesigner/components/createtexture.h
+++ b/src/plugins/qmldesigner/components/createtexture.h
@@ -3,40 +3,42 @@
#pragma once
-#include <modelnode.h>
+#include <QObject>
+
+namespace Utils {
+class FilePath;
+}
namespace QmlDesigner {
class AbstractView;
+class ModelNode;
enum class AddTextureMode { Image, Texture, LightProbe };
-class CreateTexture
+class CreateTexture : public QObject
{
+ Q_OBJECT
+
public:
- CreateTexture(AbstractView *view, bool importFiles = false);
- void execute(const QString &filePath, AddTextureMode mode, int sceneId);
+ CreateTexture(AbstractView *view);
+
+ ModelNode execute(const QString &filePath, AddTextureMode mode = AddTextureMode::Texture, int sceneId = -1);
ModelNode resolveSceneEnv(int sceneId);
void assignTextureAsLightProbe(const ModelNode &texture, int sceneId);
private:
bool addFileToProject(const QString &filePath);
- ModelNode createTextureFromImage(const QString &assetPath, AddTextureMode mode);
+ ModelNode createTextureFromImage(const Utils::FilePath &assetPath, AddTextureMode mode);
-private:
AbstractView *m_view = nullptr;
- bool m_importFile = false;
};
class CreateTextures : public CreateTexture
{
public:
using CreateTexture::CreateTexture;
- void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId)
- {
- for (const QString &path : filePaths)
- CreateTexture::execute(path, mode, sceneId);
- }
+ void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1);
};
-}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
index 54b7c14cc7..d0452fd6e2 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp
@@ -8,6 +8,8 @@
#include "detail/graphicsview.h"
#include "detail/treeview.h"
+#include <utils/fileutils.h>
+
#include <QDoubleSpinBox>
#include <QLabel>
#include <QScrollArea>
@@ -29,6 +31,10 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
"To create an animation, add a timeline by clicking the + button in the \"Timeline\" view."
);
m_infoText = new QLabel(labelText);
+ setContentsMargins(0, 0, 0, 0);
+
+ m_toolbar->setStyleSheet(Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
auto *splitter = new QSplitter;
splitter->addWidget(m_tree);
@@ -38,10 +44,12 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
QScrollArea* area = new QScrollArea;
area->setWidget(splitter);
area->setWidgetResizable(true);
+ area->setContentsMargins(0, 0, 0, 0);
m_statusLine = new QLabel();
auto *box = new QVBoxLayout;
+ box->setContentsMargins(0, 0, 0, 0);
box->addWidget(m_infoText);
box->addWidget(m_toolbar);
box->addWidget(area);
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorconstants.h b/src/plugins/qmldesigner/components/curveeditor/curveeditorconstants.h
new file mode 100644
index 0000000000..23cb29b8e1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorconstants.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+namespace QmlDesigner {
+namespace CurveEditorConstants {
+
+constexpr char C_QMLCURVEEDITOR[] = "QmlDesigner::CurveEditor";
+
+constexpr char C_ZOOM_IN[] = "QmlDesigner.ZoomIn";
+constexpr char C_ZOOM_OUT[] = "QmlDesigner.ZoomOut";
+} // CurveEditorConstants
+} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
index 5f3d49a879..452940aa5f 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.cpp
@@ -2,8 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "curveeditortoolbar.h"
+#include "curveeditorconstants.h"
#include "curveeditormodel.h"
+#include "coreplugin/actionmanager/actionmanager.h"
+#include "coreplugin/icontext.h"
+#include "theme.h"
+#include "utils/id.h"
+
#include <QAction>
#include <QHBoxLayout>
#include <QLabel>
@@ -14,7 +20,11 @@ namespace QmlDesigner {
ValidatableSpinBox::ValidatableSpinBox(std::function<bool(int)> validator, QWidget* parent)
: QSpinBox(parent)
, m_validator(validator)
-{ }
+{
+ setButtonSymbols(NoButtons);
+ setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ setFrame(false);
+}
QValidator::State ValidatableSpinBox::validate(QString &text, int &pos) const
{
@@ -28,6 +38,20 @@ QValidator::State ValidatableSpinBox::validate(QString &text, int &pos) const
return result;
}
+static QAction *createAction(const Utils::Id &id,
+ const QIcon &icon,
+ const QString &name,
+ const QKeySequence &shortcut)
+{
+ Core::Context context(CurveEditorConstants::C_QMLCURVEEDITOR);
+
+ auto *action = new QAction(icon, name);
+ auto *command = Core::ActionManager::registerAction(action, id, context);
+ command->setDefaultKeySequence(shortcut);
+ command->augmentActionWithShortcutToolTip(action);
+
+ return action;
+}
CurveEditorToolBar::CurveEditorToolBar(CurveEditorModel *model, QWidget* parent)
: QToolBar(parent)
@@ -37,15 +61,16 @@ CurveEditorToolBar::CurveEditorToolBar(CurveEditorModel *model, QWidget* parent)
{
setFloatable(false);
+ setFixedHeight(Theme::toolbarSize());
+ setContentsMargins(0, 0, 0, 0);
- QAction *tangentLinearAction = addAction(
- QIcon(":/curveeditor/images/tangetToolsLinearIcon.png"), "Linear");
- QAction *tangentStepAction = addAction(
- QIcon(":/curveeditor/images/tangetToolsStepIcon.png"), "Step");
- QAction *tangentSplineAction = addAction(
- QIcon(":/curveeditor/images/tangetToolsSplineIcon.png"), "Spline");
+ addSpace(5);
- QAction *tangentUnifyAction = addAction(tr("Unify"));
+ QAction *tangentLinearAction = addAction(Theme::iconFromName(Theme::linear_medium), "Linear");
+ QAction *tangentStepAction = addAction(Theme::iconFromName(Theme::step_medium), "Step");
+ QAction *tangentSplineAction = addAction(Theme::iconFromName(Theme::bezier_medium), "Spline");
+
+ QAction *tangentUnifyAction = addAction(Theme::iconFromName(Theme::unify_medium), tr("Unify"));
auto setLinearInterpolation = [this]() {
emit interpolationClicked(Keyframe::Interpolation::Linear);
@@ -96,33 +121,70 @@ CurveEditorToolBar::CurveEditorToolBar(CurveEditorModel *model, QWidget* parent)
m_currentSpin->setMinimum(0);
m_currentSpin->setMaximum(std::numeric_limits<int>::max());
m_currentSpin->setFixedWidth(70);
+ m_currentSpin->setButtonSymbols(QSpinBox::NoButtons);
+ m_currentSpin->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ m_currentSpin->setFrame(false);
connect(m_currentSpin, &QSpinBox::valueChanged, this, &CurveEditorToolBar::currentFrameChanged);
+ addSpacer();
+
auto *durationBox = new QHBoxLayout;
+ durationBox->setContentsMargins(0, 0, 0, 0);
durationBox->addWidget(new QLabel(tr("Start Frame")));
durationBox->addWidget(m_startSpin);
+ addSpace(durationBox);
durationBox->addWidget(new QLabel(tr("End Frame")));
durationBox->addWidget(m_endSpin);
auto *durationWidget = new QWidget;
durationWidget->setLayout(durationBox);
addWidget(durationWidget);
+ addSpace();
auto *positionBox = new QHBoxLayout;
+ positionBox->setContentsMargins(0, 0, 0, 0);
positionBox->addWidget(new QLabel(tr("Current Frame")));
positionBox->addWidget(m_currentSpin);
auto *positionWidget = new QWidget;
positionWidget->setLayout(positionBox);
addWidget(positionWidget);
+ addSpace();
m_zoomSlider = new QSlider(Qt::Horizontal);
m_zoomSlider->setRange(0, 100);
+ m_zoomSlider->setProperty("panelwidget", true);
+ m_zoomSlider->setProperty("panelwidget_singlerow", true);
+ m_zoomSlider->setFixedWidth(120);
+
connect(m_zoomSlider, &QSlider::valueChanged, [this](int value) {
emit zoomChanged(static_cast<double>(value)/100.0f);
});
+
+ auto *zoomOut = createAction(CurveEditorConstants::C_ZOOM_OUT,
+ Theme::iconFromName(Theme::Icon::zoomOut_medium),
+ tr("Zoom Out"),
+ QKeySequence(QKeySequence::ZoomOut));
+
+ connect(zoomOut, &QAction::triggered, [this]() {
+ m_zoomSlider->setValue(m_zoomSlider->value() - m_zoomSlider->pageStep());
+ });
+
+ auto *zoomIn = createAction(CurveEditorConstants::C_ZOOM_IN,
+ Theme::iconFromName(Theme::Icon::zoomIn_medium),
+ tr("Zoom In"),
+ QKeySequence(QKeySequence::ZoomIn));
+
+ connect(zoomIn, &QAction::triggered, [this]() {
+ m_zoomSlider->setValue(m_zoomSlider->value() + m_zoomSlider->pageStep());
+ });
+
+ addAction(zoomOut);
addWidget(m_zoomSlider);
+ addAction(zoomIn);
+
+ addSpace(5);
}
void CurveEditorToolBar::setZoom(double zoom)
@@ -150,4 +212,27 @@ void CurveEditorToolBar::updateBoundsSilent(int start, int end)
m_endSpin->setValue(end);
}
+void CurveEditorToolBar::addSpacer()
+{
+ QWidget *spacerWidget = new QWidget(this);
+ spacerWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+ addWidget(spacerWidget);
+}
+
+void CurveEditorToolBar::addSpace(int spaceSize)
+{
+ QWidget *spacerWidget = new QWidget(this);
+ spacerWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ spacerWidget->setFixedSize(spaceSize, 1);
+ addWidget(spacerWidget);
+}
+
+void CurveEditorToolBar::addSpace(QLayout *layout, int spaceSize)
+{
+ QWidget *spacerWidget = new QWidget(layout->widget());
+ spacerWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ spacerWidget->setFixedSize(spaceSize, 1);
+ layout->addWidget(spacerWidget);
+}
+
} // End namespace QmlDesigner.
diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.h b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.h
index bb368364e6..c7bb6bc818 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.h
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditortoolbar.h
@@ -18,10 +18,13 @@ class CurveEditorModel;
class ValidatableSpinBox : public QSpinBox
{
Q_OBJECT
+
public:
ValidatableSpinBox(std::function<bool(int)> validator, QWidget* parent=nullptr);
+
protected:
QValidator::State validate(QString &text, int &pos) const override;
+
private:
std::function<bool(int)> m_validator;
};
@@ -54,6 +57,10 @@ public:
void updateBoundsSilent(int start, int end);
private:
+ void addSpacer();
+ void addSpace(int spaceSize = 32);
+ void addSpace(QLayout *layout, int spaceSize = 32);
+
ValidatableSpinBox *m_startSpin;
ValidatableSpinBox *m_endSpin;
QSpinBox *m_currentSpin;
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp
index df5b081814..2888575e44 100644
--- a/src/plugins/qmldesigner/components/debugview/debugview.cpp
+++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp
@@ -283,7 +283,8 @@ void DebugView::selectedNodesChanged(const QList<ModelNode> &selectedNodes /*sel
if (selectedNode.metaInfo().isValid()) {
for (const NodeMetaInfo &metaInfo : selectedNode.metaInfo().classHierarchy())
- message << metaInfo.typeName() << lineBreak;
+ message << metaInfo.typeName() << " " << metaInfo.majorVersion() << "."
+ << metaInfo.minorVersion() << lineBreak;
message << lineBreak;
message << selectedNode.metaInfo().typeName();
@@ -425,7 +426,11 @@ void DebugView::rewriterEndTransaction()
WidgetInfo DebugView::widgetInfo()
{
- return createWidgetInfo(m_debugViewWidget.data(), QStringLiteral("DebugView"), WidgetInfo::LeftPane, 0, tr("Debug View"));
+ return createWidgetInfo(m_debugViewWidget.data(),
+ QStringLiteral("DebugView"),
+ WidgetInfo::LeftPane,
+ 0,
+ tr("Debug View"));
}
bool DebugView::hasWidget() const
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
index 39f6442095..61731c578f 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
@@ -6,8 +6,9 @@
#include <viewmanager.h>
#include <nodeinstanceview.h>
-#include <qmldesignerplugin.h>
#include <nodemetainfo.h>
+#include <qmldesignerplugin.h>
+#include "seekerslider.h"
#include <utils/algorithm.h>
@@ -36,22 +37,27 @@ void Edit3DActionTemplate::actionTriggered(bool b)
m_action(m_selectionContext);
}
+Edit3DWidgetActionTemplate::Edit3DWidgetActionTemplate(QWidgetAction *widget)
+ : PureActionInterface(widget)
+{
+
+}
+
Edit3DAction::Edit3DAction(const QByteArray &menuId,
View3DActionType type,
const QString &description,
const QKeySequence &key,
bool checkable,
bool checked,
- const QIcon &iconOff,
- const QIcon &iconOn,
+ const QIcon &icon,
Edit3DView *view,
SelectionContextOperation selectionAction,
const QString &toolTip)
- : AbstractAction(new Edit3DActionTemplate(description, selectionAction, view, type))
- , m_menuId(menuId)
- , m_actionTemplate(qobject_cast<Edit3DActionTemplate *>(defaultAction()))
+ : Edit3DAction(menuId, type, view, new Edit3DActionTemplate(description,
+ selectionAction,
+ view,
+ type))
{
- view->registerEdit3DAction(this);
action()->setShortcut(key);
action()->setShortcutContext(Qt::WidgetWithChildrenShortcut);
action()->setCheckable(checkable);
@@ -61,22 +67,18 @@ Edit3DAction::Edit3DAction(const QByteArray &menuId,
if (!toolTip.isEmpty())
action()->setToolTip(toolTip);
- if (checkable) {
- QIcon onOffIcon;
- const auto onAvail = iconOn.availableSizes(); // Assume both icons have same sizes available
- for (const auto &size : onAvail) {
- onOffIcon.addPixmap(iconOn.pixmap(size), QIcon::Normal, QIcon::On);
- onOffIcon.addPixmap(iconOff.pixmap(size), QIcon::Normal, QIcon::Off);
- }
- action()->setIcon(onOffIcon);
- } else {
- action()->setIcon(iconOff);
- }
+ action()->setIcon(icon);
}
-Edit3DAction::~Edit3DAction()
+Edit3DAction::Edit3DAction(const QByteArray &menuId,
+ View3DActionType type,
+ Edit3DView *view,
+ PureActionInterface *pureInt)
+ : AbstractAction(pureInt)
+ , m_menuId(menuId)
+ , m_actionType(type)
{
- m_actionTemplate->m_view->unregisterEdit3DAction(this);
+ view->registerEdit3DAction(this);
}
QByteArray Edit3DAction::category() const
@@ -86,7 +88,7 @@ QByteArray Edit3DAction::category() const
View3DActionType Edit3DAction::actionType() const
{
- return m_actionTemplate->m_type;
+ return m_actionType;
}
bool Edit3DAction::isVisible([[maybe_unused]] const SelectionContext &selectionContext) const
@@ -105,11 +107,10 @@ Edit3DCameraAction::Edit3DCameraAction(const QByteArray &menuId,
const QKeySequence &key,
bool checkable,
bool checked,
- const QIcon &iconOff,
- const QIcon &iconOn,
+ const QIcon &icon,
Edit3DView *view,
SelectionContextOperation selectionAction)
- : Edit3DAction(menuId, type, description, key, checkable, checked, iconOff, iconOn, view, selectionAction)
+ : Edit3DAction(menuId, type, description, key, checkable, checked, icon, view, selectionAction)
{
}
@@ -119,5 +120,31 @@ bool Edit3DCameraAction::isEnabled(const SelectionContext &selectionContext) con
[](const ModelNode &node) { return node.metaInfo().isQtQuick3DCamera(); });
}
+Edit3DParticleSeekerAction::Edit3DParticleSeekerAction(const QByteArray &menuId,
+ View3DActionType type,
+ Edit3DView *view)
+ : Edit3DAction(menuId,
+ type,
+ view,
+ new Edit3DWidgetActionTemplate(
+ new SeekerSliderAction(nullptr)))
+{
+ m_seeker = qobject_cast<SeekerSliderAction *>(action());
+}
+
+SeekerSliderAction *Edit3DParticleSeekerAction::seekerAction()
+{
+ return m_seeker;
+}
+
+bool Edit3DParticleSeekerAction::isVisible(const SelectionContext &) const
+{
+ return m_seeker->isVisible();
+}
+
+bool Edit3DParticleSeekerAction::isEnabled(const SelectionContext &) const
+{
+ return m_seeker->isEnabled();
}
+}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
index 5b87563c30..bad427a25b 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
@@ -5,12 +5,15 @@
#include <abstractaction.h>
#include <QAction>
+#include <QWidgetAction>
#include <QIcon>
+class QWidgetAction;
namespace QmlDesigner {
using SelectionContextOperation = std::function<void(const SelectionContext &)>;
class Edit3DView;
+class SeekerSliderAction;
class Edit3DActionTemplate : public DefaultAction
{
@@ -29,6 +32,15 @@ public:
View3DActionType m_type;
};
+class Edit3DWidgetActionTemplate : public PureActionInterface
+{
+ Q_DISABLE_COPY(Edit3DWidgetActionTemplate)
+
+public:
+ explicit Edit3DWidgetActionTemplate(QWidgetAction *widget);
+ virtual void setSelectionContext(const SelectionContext &) {}
+};
+
class Edit3DAction : public AbstractAction
{
public:
@@ -38,13 +50,15 @@ public:
const QKeySequence &key,
bool checkable,
bool checked,
- const QIcon &iconOff,
- const QIcon &iconOn,
+ const QIcon &icon,
Edit3DView *view,
SelectionContextOperation selectionAction = nullptr,
const QString &toolTip = {});
- virtual ~Edit3DAction();
+ Edit3DAction(const QByteArray &menuId,
+ View3DActionType type,
+ Edit3DView *view,
+ PureActionInterface *pureInt);
QByteArray category() const override;
@@ -71,7 +85,7 @@ protected:
private:
QByteArray m_menuId;
- Edit3DActionTemplate *m_actionTemplate = nullptr;
+ View3DActionType m_actionType;
};
class Edit3DCameraAction : public Edit3DAction
@@ -83,8 +97,7 @@ public:
const QKeySequence &key,
bool checkable,
bool checked,
- const QIcon &iconOff,
- const QIcon &iconOn,
+ const QIcon &icon,
Edit3DView *view,
SelectionContextOperation selectionAction = nullptr);
@@ -92,4 +105,21 @@ protected:
bool isEnabled(const SelectionContext &selectionContext) const override;
};
+class Edit3DParticleSeekerAction : public Edit3DAction
+{
+public:
+ Edit3DParticleSeekerAction(const QByteArray &menuId,
+ View3DActionType type,
+ Edit3DView *view);
+
+ SeekerSliderAction *seekerAction();
+
+protected:
+ bool isVisible(const SelectionContext &) const override;
+ bool isEnabled(const SelectionContext &) const override;
+
+private:
+ SeekerSliderAction *m_seeker = nullptr;
+};
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
index cb03b5906c..60cba02584 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp
@@ -35,6 +35,8 @@ static QQuickWidget *createBusyIndicator(QWidget *p)
widget->setAttribute(Qt::WA_AlwaysStackOnTop);
widget->setClearColor(Qt::transparent);
widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ widget->setObjectName(Constants::OBJECT_NAME_BUSY_INDICATOR);
+
return widget;
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index afd4558f5c..d92e76362b 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
@@ -4,17 +4,19 @@
#include "edit3dview.h"
#include "backgroundcolorselection.h"
+#include "designeractionmanager.h"
+#include "designericons.h"
#include "designersettings.h"
#include "designmodecontext.h"
#include "edit3dactions.h"
#include "edit3dcanvas.h"
#include "edit3dviewconfig.h"
#include "edit3dwidget.h"
+#include "materialutils.h"
#include "metainfo.h"
#include "nodehints.h"
#include "nodeinstanceview.h"
#include "qmldesignerconstants.h"
-#include "qmldesignericons.h"
#include "qmldesignerplugin.h"
#include "qmlvisualnode.h"
#include "seekerslider.h"
@@ -22,14 +24,39 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
+#include <theme.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <utils/stylehelper.h>
#include <utils/utilsicons.h>
#include <QToolButton>
namespace QmlDesigner {
+static inline QIcon contextIcon (const DesignerIcons::IconId &iconId) {
+ return DesignerActionManager::instance().contextIcon(iconId);
+};
+
+static QIcon toolbarIcon (const Theme::Icon &iconOffId, const Theme::Icon &iconnOnId) {
+ QIcon iconOff = Theme::iconFromName(iconOffId);
+ QIcon iconOn= Theme::iconFromName(iconnOnId,
+ Theme::getColor(Theme::Color::DStextSelectedTextColor));
+ QIcon retIcon;
+
+ const auto onAvail = iconOff.availableSizes(); // Assume both icons have same sizes available
+ for (const auto &size : onAvail) {
+ retIcon.addPixmap(iconOff.pixmap(size), QIcon::Normal, QIcon::Off);
+ retIcon.addPixmap(iconOn.pixmap(size), QIcon::Normal, QIcon::On);
+ }
+
+ return retIcon;
+};
+
+static inline QIcon toolbarIcon (const Theme::Icon &iconOffId) {
+ return toolbarIcon(iconOffId, iconOffId);
+};
+
Edit3DView::Edit3DView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
{
@@ -38,11 +65,6 @@ Edit3DView::Edit3DView(ExternalDependenciesInterface &externalDependencies)
connect(&m_compressionTimer, &QTimer::timeout, this, &Edit3DView::handleEntriesChanged);
}
-Edit3DView::~Edit3DView()
-{
- qDeleteAll(m_edit3DActions);
-}
-
void Edit3DView::createEdit3DWidget()
{
createEdit3DActions();
@@ -62,7 +84,13 @@ WidgetInfo Edit3DView::widgetInfo()
if (!m_edit3DWidget)
createEdit3DWidget();
- return createWidgetInfo(m_edit3DWidget.data(), "Editor3D", WidgetInfo::CentralPane, 0, tr("3D"), DesignerWidgetFlags::IgnoreErrors);
+ return createWidgetInfo(m_edit3DWidget.data(),
+ "Editor3D",
+ WidgetInfo::CentralPane,
+ 0,
+ tr("3D"),
+ tr("3D view"),
+ DesignerWidgetFlags::IgnoreErrors);
}
Edit3DWidget *Edit3DView::edit3DWidget() const
@@ -202,27 +230,8 @@ void Edit3DView::onEntriesChanged()
void Edit3DView::registerEdit3DAction(Edit3DAction *action)
{
- View3DActionType actionType = action->actionType();
- if (actionType == View3DActionType::Empty)
- return;
-
- if (m_edit3DActions.contains(actionType)) {
- Edit3DAction *formerAction = m_edit3DActions.value(actionType);
- if (formerAction == action)
- return;
-
- qWarning() << Q_FUNC_INFO << __LINE__ << "Reregistering action for" << int(actionType);
- delete formerAction;
- }
-
- m_edit3DActions.insert(actionType, action);
-}
-
-void Edit3DView::unregisterEdit3DAction(Edit3DAction *action)
-{
- View3DActionType actionType = action->actionType();
- if (m_edit3DActions.value(actionType, nullptr) == action)
- m_edit3DActions.remove(actionType);
+ if (action->actionType() != View3DActionType::Empty)
+ m_edit3DActions.insert(action->actionType(), QSharedPointer<Edit3DAction>(action));
}
void Edit3DView::handleEntriesChanged()
@@ -230,37 +239,42 @@ void Edit3DView::handleEntriesChanged()
if (!model())
return;
- const QString cameras = tr("Cameras");
- const QString lights = tr("Lights");
- const QString primitives = tr("Primitives");
- const QString importedModels = tr("Imported Models");
- const QStringList keys {cameras, lights, primitives, importedModels}; // used to maintain order
-
- QHash<QString, QList<ItemLibraryEntry>> entriesMap {
- {cameras, {}},
- {lights, {}},
- {primitives, {}},
- {importedModels, {}}
+ enum ItemLibraryEntryKeys : int { // used to maintain order
+ EK_cameras,
+ EK_lights,
+ EK_primitives,
+ EK_importedModels
+ };
+
+ QMap<ItemLibraryEntryKeys, ItemLibraryDetails> entriesMap {
+ {EK_cameras, {tr("Cameras"), contextIcon(DesignerIcons::CameraIcon)}},
+ {EK_lights, {tr("Lights"), contextIcon(DesignerIcons::LightIcon)}},
+ {EK_primitives, {tr("Primitives"), contextIcon(DesignerIcons::PrimitivesIcon)}},
+ {EK_importedModels, {tr("Imported Models"), contextIcon(DesignerIcons::ImportedModelsIcon)}}
};
const QList<ItemLibraryEntry> itemLibEntries = model()->metaInfo().itemLibraryInfo()->entries();
for (const ItemLibraryEntry &entry : itemLibEntries) {
+ ItemLibraryEntryKeys entryKey;
if (entry.typeName() == "QtQuick3D.Model" && entry.name() != "Empty") {
- entriesMap[primitives].append(entry);
+ entryKey = EK_primitives;
} else if (entry.typeName() == "QtQuick3D.DirectionalLight"
|| entry.typeName() == "QtQuick3D.PointLight"
|| entry.typeName() == "QtQuick3D.SpotLight") {
- entriesMap[lights].append(entry);
+ entryKey = EK_lights;
} else if (entry.typeName() == "QtQuick3D.OrthographicCamera"
|| entry.typeName() == "QtQuick3D.PerspectiveCamera") {
- entriesMap[cameras].append(entry);
+ entryKey = EK_cameras;
} else if (entry.typeName().startsWith("Quick3DAssets.")
&& NodeHints::fromItemLibraryEntry(entry).canBeDroppedInView3D()) {
- entriesMap[importedModels].append(entry);
+ entryKey = EK_importedModels;
+ } else {
+ continue;
}
+ entriesMap[entryKey].entryList.append(entry);
}
- m_edit3DWidget->updateCreateSubMenu(keys, entriesMap);
+ m_edit3DWidget->updateCreateSubMenu(entriesMap.values());
}
void Edit3DView::modelAboutToBeDetached(Model *model)
@@ -311,24 +325,29 @@ void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos
createdNode = QmlVisualNode::createQml3DNode(
this, m_droppedEntry, edit3DWidget()->canvas()->activeScene(), pos3d).modelNode();
if (createdNode.metaInfo().isQtQuick3DModel())
- assignMaterialTo3dModel(createdNode);
+ MaterialUtils::assignMaterialTo3dModel(this, createdNode);
});
if (createdNode.isValid())
setSelectedModelNode(createdNode);
} else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) {
bool isModel = modelNode.metaInfo().isQtQuick3DModel();
- if (m_droppedModelNode.isValid() && modelNode.isValid() && isModel) {
+ if (m_droppedModelNode.isValid() && isModel) {
executeInTransaction(__FUNCTION__, [&] {
- assignMaterialTo3dModel(modelNode, m_droppedModelNode);
+ MaterialUtils::assignMaterialTo3dModel(this, modelNode, m_droppedModelNode);
});
}
} else if (m_nodeAtPosReqType == NodeAtPosReqType::BundleMaterialDrop) {
emitCustomNotification("drop_bundle_material", {modelNode}); // To ContentLibraryView
} else if (m_nodeAtPosReqType == NodeAtPosReqType::TextureDrop) {
emitCustomNotification("apply_texture_to_model3D", {modelNode, m_droppedModelNode});
+ } else if (m_nodeAtPosReqType == NodeAtPosReqType::AssetDrop) {
+ bool isModel = modelNode.metaInfo().isQtQuick3DModel();
+ if (!m_droppedFile.isEmpty() && isModel)
+ emitCustomNotification("apply_asset_to_model3D", {modelNode}, {m_droppedFile}); // To MaterialBrowserView
}
m_droppedModelNode = {};
+ m_droppedFile.clear();
m_nodeAtPosReqType = NodeAtPosReqType::None;
}
@@ -352,11 +371,6 @@ QSize Edit3DView::canvasSize() const
return {};
}
-void Edit3DView::setSeeker(SeekerSlider *slider)
-{
- m_seeker = slider;
-}
-
Edit3DAction *Edit3DView::createSelectBackgroundColorAction(QAction *syncBackgroundColorAction)
{
QString description = QCoreApplication::translate("SelectBackgroundColorAction",
@@ -385,7 +399,6 @@ Edit3DAction *Edit3DView::createSelectBackgroundColorAction(QAction *syncBackgro
false,
false,
{},
- {},
this,
operation,
tooltip);
@@ -412,7 +425,6 @@ Edit3DAction *Edit3DView::createGridColorSelectionAction()
false,
false,
{},
- {},
this,
operation,
tooltip);
@@ -447,7 +459,6 @@ Edit3DAction *Edit3DView::createResetColorAction(QAction *syncBackgroundColorAct
false,
false,
{},
- {},
this,
operation,
tooltip);
@@ -468,24 +479,41 @@ Edit3DAction *Edit3DView::createSyncBackgroundColorAction()
true,
false,
{},
- {},
this,
{},
tooltip);
}
+Edit3DAction *Edit3DView::createSeekerSliderAction()
+{
+ Edit3DParticleSeekerAction *seekerAction = new Edit3DParticleSeekerAction(
+ QmlDesigner::Constants::EDIT3D_PARTICLES_SEEKER,
+ View3DActionType::ParticlesSeek,
+ this);
+
+ seekerAction->action()->setEnabled(false);
+ seekerAction->action()->setToolTip(QLatin1String("Seek particle system time when paused."));
+
+ connect(seekerAction->seekerAction(),
+ &SeekerSliderAction::valueChanged,
+ this, [=] (int value) {
+ this->emitView3DAction(View3DActionType::ParticlesSeek, value);
+ });
+
+ return seekerAction;
+}
+
void Edit3DView::createEdit3DActions()
{
m_selectionModeAction = new Edit3DAction(
- QmlDesigner::Constants::EDIT3D_SELECTION_MODE,
- View3DActionType::SelectionModeToggle,
- QCoreApplication::translate("SelectionModeToggleAction", "Toggle Group/Single Selection Mode"),
- QKeySequence(Qt::Key_Q),
- true,
- false,
- Icons::EDIT3D_SELECTION_MODE_OFF.icon(),
- Icons::EDIT3D_SELECTION_MODE_ON.icon(),
- this);
+ QmlDesigner::Constants::EDIT3D_SELECTION_MODE,
+ View3DActionType::SelectionModeToggle,
+ QCoreApplication::translate("SelectionModeToggleAction", "Toggle Group/Single Selection Mode"),
+ QKeySequence(Qt::Key_Q),
+ true,
+ false,
+ toolbarIcon(Theme::selectOutline_medium, Theme::selectFill_medium),
+ this);
m_moveToolAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_MOVE_TOOL,
View3DActionType::MoveTool,
@@ -494,8 +522,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_W),
true,
true,
- Icons::EDIT3D_MOVE_TOOL_OFF.icon(),
- Icons::EDIT3D_MOVE_TOOL_ON.icon(),
+ toolbarIcon(Theme::move_medium),
this);
m_rotateToolAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_ROTATE_TOOL,
@@ -505,8 +532,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_E),
true,
false,
- Icons::EDIT3D_ROTATE_TOOL_OFF.icon(),
- Icons::EDIT3D_ROTATE_TOOL_ON.icon(),
+ toolbarIcon(Theme::roatate_medium),
this);
m_scaleToolAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_SCALE_TOOL,
@@ -516,8 +542,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_R),
true,
false,
- Icons::EDIT3D_SCALE_TOOL_OFF.icon(),
- Icons::EDIT3D_SCALE_TOOL_ON.icon(),
+ toolbarIcon(Theme::scale_medium),
this);
m_fitAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_FIT_SELECTED,
@@ -527,8 +552,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_F),
false,
false,
- Icons::EDIT3D_FIT_SELECTED_OFF.icon(),
- {},
+ toolbarIcon(Theme::fitToView_medium),
this);
m_alignCamerasAction = new Edit3DCameraAction(
@@ -538,8 +562,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(),
false,
false,
- Icons::EDIT3D_ALIGN_CAMERA_ON.icon(),
- {},
+ toolbarIcon(Theme::alignToCam_medium),
this);
m_alignViewAction = new Edit3DCameraAction(
@@ -549,8 +572,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(),
false,
false,
- Icons::EDIT3D_ALIGN_VIEW_ON.icon(),
- {},
+ toolbarIcon(Theme::alignToView_medium),
this);
m_cameraModeAction = new Edit3DAction(
@@ -561,8 +583,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_T),
true,
false,
- Icons::EDIT3D_EDIT_CAMERA_OFF.icon(),
- Icons::EDIT3D_EDIT_CAMERA_ON.icon(),
+ toolbarIcon(Theme::orthCam_small, Theme::perspectiveCam_small),
this);
m_orientationModeAction = new Edit3DAction(
@@ -572,20 +593,19 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_Y),
true,
false,
- Icons::EDIT3D_ORIENTATION_OFF.icon(),
- Icons::EDIT3D_ORIENTATION_ON.icon(),
+ toolbarIcon(Theme::localOrient_medium),
this);
- m_editLightAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_EDIT_LIGHT,
- View3DActionType::EditLightToggle,
- QCoreApplication::translate("EditLightToggleAction",
- "Toggle Edit Light On/Off"),
- QKeySequence(Qt::Key_U),
- true,
- false,
- Icons::EDIT3D_LIGHT_OFF.icon(),
- Icons::EDIT3D_LIGHT_ON.icon(),
- this);
+ m_editLightAction = new Edit3DAction(
+ QmlDesigner::Constants::EDIT3D_EDIT_LIGHT,
+ View3DActionType::EditLightToggle,
+ QCoreApplication::translate("EditLightToggleAction",
+ "Toggle Edit Light On/Off"),
+ QKeySequence(Qt::Key_U),
+ true,
+ false,
+ toolbarIcon(Theme::editLightOff_medium, Theme::editLightOn_medium),
+ this);
m_showGridAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_EDIT_SHOW_GRID,
@@ -595,7 +615,6 @@ void Edit3DView::createEdit3DActions()
true,
true,
{},
- {},
this,
nullptr,
QCoreApplication::translate("ShowGridAction", "Toggle the visibility of the helper grid."));
@@ -608,7 +627,6 @@ void Edit3DView::createEdit3DActions()
true,
true,
{},
- {},
this,
nullptr,
QCoreApplication::translate("ShowSelectionBoxAction",
@@ -622,7 +640,6 @@ void Edit3DView::createEdit3DActions()
true,
true,
{},
- {},
this,
nullptr,
QCoreApplication::translate(
@@ -637,7 +654,6 @@ void Edit3DView::createEdit3DActions()
true,
false,
{},
- {},
this,
nullptr,
QCoreApplication::translate(
@@ -654,7 +670,6 @@ void Edit3DView::createEdit3DActions()
true,
false,
{},
- {},
this,
nullptr,
QCoreApplication::translate(
@@ -667,8 +682,8 @@ void Edit3DView::createEdit3DActions()
m_particlesRestartAction->action()->setEnabled(particlemode);
if (particlemode)
m_particlesPlayAction->action()->setChecked(true);
- if (m_seeker)
- m_seeker->setEnabled(false);
+ if (m_seekerAction)
+ m_seekerAction->action()->setEnabled(false);
resetPuppet();
};
@@ -676,62 +691,60 @@ void Edit3DView::createEdit3DActions()
particlemode = !particlemode;
m_particlesPlayAction->action()->setEnabled(particlemode);
m_particlesRestartAction->action()->setEnabled(particlemode);
- if (m_seeker)
- m_seeker->setEnabled(false);
+ if (m_seekerAction)
+ m_seekerAction->action()->setEnabled(false);
QmlDesignerPlugin::settings().insert("particleMode", particlemode);
resetPuppet();
};
SelectionContextOperation particlesPlayTrigger = [this](const SelectionContext &) {
- if (m_seeker)
- m_seeker->setEnabled(!m_particlesPlayAction->action()->isChecked());
+ if (m_seekerAction)
+ m_seekerAction->action()->setEnabled(!m_particlesPlayAction->action()->isChecked());
};
m_particleViewModeAction = new Edit3DAction(
- QmlDesigner::Constants::EDIT3D_PARTICLE_MODE,
- View3DActionType::Edit3DParticleModeToggle,
- QCoreApplication::translate("ParticleViewModeAction", "Toggle particle animation On/Off"),
- QKeySequence(Qt::Key_V),
- true,
- false,
- Icons::EDIT3D_PARTICLE_OFF.icon(),
- Icons::EDIT3D_PARTICLE_ON.icon(),
- this,
- particlesTrigger);
+ QmlDesigner::Constants::EDIT3D_PARTICLE_MODE,
+ View3DActionType::Edit3DParticleModeToggle,
+ QCoreApplication::translate("ParticleViewModeAction", "Toggle particle animation On/Off"),
+ QKeySequence(Qt::Key_V),
+ true,
+ false,
+ toolbarIcon(Theme::particleAnimation_medium),
+ this,
+ particlesTrigger);
particlemode = false;
- m_particlesPlayAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_PARTICLES_PLAY,
- View3DActionType::ParticlesPlay,
- QCoreApplication::translate("ParticlesPlayAction",
- "Play Particles"),
- QKeySequence(Qt::Key_Comma),
- true,
- true,
- Icons::EDIT3D_PARTICLE_PLAY.icon(),
- Icons::EDIT3D_PARTICLE_PAUSE.icon(),
- this,
- particlesPlayTrigger);
+ m_particlesPlayAction = new Edit3DAction(
+ QmlDesigner::Constants::EDIT3D_PARTICLES_PLAY,
+ View3DActionType::ParticlesPlay,
+ QCoreApplication::translate("ParticlesPlayAction", "Play Particles"),
+ QKeySequence(Qt::Key_Comma),
+ true,
+ true,
+ toolbarIcon(Theme::playOutline_medium, Theme::pause), // Icons::EDIT3D_PARTICLE_PLAY.icon(), Icons::EDIT3D_PARTICLE_PAUSE.icon(),
+ this,
+ particlesPlayTrigger);
m_particlesRestartAction = new Edit3DAction(
- QmlDesigner::Constants::EDIT3D_PARTICLES_RESTART,
- View3DActionType::ParticlesRestart,
- QCoreApplication::translate("ParticlesRestartAction", "Restart Particles"),
- QKeySequence(Qt::Key_Slash),
- false,
- false,
- Icons::EDIT3D_PARTICLE_RESTART.icon(),
- Icons::EDIT3D_PARTICLE_RESTART.icon(),
- this);
+ QmlDesigner::Constants::EDIT3D_PARTICLES_RESTART,
+ View3DActionType::ParticlesRestart,
+ QCoreApplication::translate("ParticlesRestartAction", "Restart Particles"),
+ QKeySequence(Qt::Key_Slash),
+ false,
+ false,
+ toolbarIcon(Theme::restartParticles_medium),
+ this);
m_particlesPlayAction->action()->setEnabled(particlemode);
m_particlesRestartAction->action()->setEnabled(particlemode);
- m_resetAction = new Edit3DAction(QmlDesigner::Constants::EDIT3D_RESET_VIEW,
- View3DActionType::Empty,
- QCoreApplication::translate("ResetView", "Reset View"),
- QKeySequence(Qt::Key_P),
- false,
- false,
- Utils::Icons::RESET_TOOLBAR.icon(),
- {},
- this,
- resetTrigger);
+
+ m_resetAction = new Edit3DAction(
+ QmlDesigner::Constants::EDIT3D_RESET_VIEW,
+ View3DActionType::Empty,
+ QCoreApplication::translate("ResetView", "Reset View"),
+ QKeySequence(Qt::Key_P),
+ false,
+ false,
+ toolbarIcon(Theme::reload_medium),
+ this,
+ resetTrigger);
SelectionContextOperation visibilityTogglesTrigger = [this](const SelectionContext &) {
if (!edit3DWidget()->visibilityTogglesMenu())
@@ -757,8 +770,7 @@ void Edit3DView::createEdit3DActions()
QKeySequence(),
false,
false,
- Utils::Icons::EYE_OPEN_TOOLBAR.icon(),
- {},
+ toolbarIcon(Theme::invisible_medium, Theme::visible_medium),
this,
visibilityTogglesTrigger);
@@ -786,11 +798,12 @@ void Edit3DView::createEdit3DActions()
QKeySequence(),
false,
false,
- Icons::COLOR_PALETTE.icon(),
- {},
+ toolbarIcon(Theme::colorSelection_medium),
this,
backgroundColorActionsTrigger);
+ m_seekerAction = createSeekerSliderAction();
+
m_leftActions << m_selectionModeAction;
m_leftActions << nullptr; // Null indicates separator
m_leftActions << nullptr; // Second null after separator indicates an exclusive group
@@ -815,6 +828,8 @@ void Edit3DView::createEdit3DActions()
m_rightActions << m_particlesPlayAction;
m_rightActions << m_particlesRestartAction;
m_rightActions << nullptr;
+ m_rightActions << m_seekerAction;
+ m_rightActions << nullptr;
m_rightActions << m_resetAction;
m_visibilityToggleActions << m_showGridAction;
@@ -852,7 +867,7 @@ QVector<Edit3DAction *> Edit3DView::backgroundColorActions() const
Edit3DAction *Edit3DView::edit3DAction(View3DActionType type) const
{
- return m_edit3DActions.value(type, nullptr);
+ return m_edit3DActions.value(type, nullptr).data();
}
void Edit3DView::addQuick3DImport()
@@ -910,6 +925,17 @@ void Edit3DView::dropComponent(const ItemLibraryEntry &entry, const QPointF &pos
{
m_nodeAtPosReqType = NodeAtPosReqType::ComponentDrop;
m_droppedEntry = entry;
+ NodeMetaInfo metaInfo = model()->metaInfo(entry.typeName());
+ if (metaInfo.isQtQuick3DNode())
+ emitView3DAction(View3DActionType::GetNodeAtPos, pos);
+ else
+ nodeAtPosReady({}, {}); // No need to actually resolve position for non-node items
+}
+
+void Edit3DView::dropAsset(const QString &file, const QPointF &pos)
+{
+ m_nodeAtPosReqType = NodeAtPosReqType::AssetDrop;
+ m_droppedFile = file;
emitView3DAction(View3DActionType::GetNodeAtPos, pos);
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
index 03dc13b4ac..2b746cf1af 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
@@ -25,7 +25,6 @@ namespace QmlDesigner {
class Edit3DWidget;
class Edit3DAction;
class Edit3DCameraAction;
-class SeekerSlider;
class QMLDESIGNERCOMPONENTS_EXPORT Edit3DView : public AbstractView
{
@@ -33,7 +32,6 @@ class QMLDESIGNERCOMPONENTS_EXPORT Edit3DView : public AbstractView
public:
Edit3DView(ExternalDependenciesInterface &externalDependencies);
- ~Edit3DView() override;
WidgetInfo widgetInfo() override;
@@ -59,7 +57,6 @@ public:
QVector<Edit3DAction *> visibilityToggleActions() const;
QVector<Edit3DAction *> backgroundColorActions() const;
Edit3DAction *edit3DAction(View3DActionType type) const;
- void setSeeker(SeekerSlider *slider);
void addQuick3DImport();
void startContextMenu(const QPoint &pos);
@@ -67,6 +64,7 @@ public:
void dropBundleMaterial(const QPointF &pos);
void dropTexture(const ModelNode &textureNode, const QPointF &pos);
void dropComponent(const ItemLibraryEntry &entry, const QPointF &pos);
+ void dropAsset(const QString &file, const QPointF &pos);
private slots:
void onEntriesChanged();
@@ -78,11 +76,11 @@ private:
MaterialDrop,
TextureDrop,
ContextMenu,
+ AssetDrop,
None
};
void registerEdit3DAction(Edit3DAction *action);
- void unregisterEdit3DAction(Edit3DAction *action);
void createEdit3DWidget();
void checkImports();
@@ -93,13 +91,15 @@ private:
Edit3DAction *createGridColorSelectionAction();
Edit3DAction *createResetColorAction(QAction *syncBackgroundColorAction);
Edit3DAction *createSyncBackgroundColorAction();
+ Edit3DAction *createSeekerSliderAction();
QPointer<Edit3DWidget> m_edit3DWidget;
QVector<Edit3DAction *> m_leftActions;
QVector<Edit3DAction *> m_rightActions;
QVector<Edit3DAction *> m_visibilityToggleActions;
QVector<Edit3DAction *> m_backgroundColorActions;
- QMap<View3DActionType, Edit3DAction *> m_edit3DActions;
+
+ QMap<View3DActionType, QSharedPointer<Edit3DAction>> m_edit3DActions;
Edit3DAction *m_selectionModeAction = nullptr;
Edit3DAction *m_moveToolAction = nullptr;
Edit3DAction *m_rotateToolAction = nullptr;
@@ -121,11 +121,12 @@ private:
Edit3DAction *m_particlesRestartAction = nullptr;
Edit3DAction *m_visibilityTogglesAction = nullptr;
Edit3DAction *m_backgrondColorMenuAction = nullptr;
- SeekerSlider *m_seeker = nullptr;
+ Edit3DAction *m_seekerAction = nullptr;
int particlemode;
ModelCache<QImage> m_canvasCache;
ModelNode m_droppedModelNode;
ItemLibraryEntry m_droppedEntry;
+ QString m_droppedFile;
NodeAtPosReqType m_nodeAtPosReqType;
QPoint m_contextMenuPos;
QTimer m_compressionTimer;
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index 701237dd71..408584e166 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -3,16 +3,19 @@
#include "edit3dwidget.h"
#include "designdocument.h"
+#include "designericons.h"
#include "edit3dactions.h"
#include "edit3dcanvas.h"
#include "edit3dview.h"
#include "edit3dvisibilitytogglesmenu.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"
@@ -26,6 +29,7 @@
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/icore.h>
#include <toolbox.h>
+#include <utils/asset.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -37,11 +41,41 @@
namespace QmlDesigner {
+static inline QIcon contextIcon(const DesignerIcons::IconId &iconId) {
+ return DesignerActionManager::instance().contextIcon(iconId);
+};
+
+static QIcon getEntryIcon(const ItemLibraryEntry &entry)
+{
+ static const QMap<QString, DesignerIcons::IconId> itemLibraryDesignerIconId = {
+ {"QtQuick3D.OrthographicCamera__Camera Orthographic", DesignerIcons::CameraOrthographicIcon},
+ {"QtQuick3D.PerspectiveCamera__Camera Perspective", DesignerIcons::CameraPerspectiveIcon},
+ {"QtQuick3D.DirectionalLight__Light Directional", DesignerIcons::LightDirectionalIcon},
+ {"QtQuick3D.PointLight__Light Point", DesignerIcons::LightPointIcon},
+ {"QtQuick3D.SpotLight__Light Spot", DesignerIcons::LightSpotIcon},
+ {"QtQuick3D.Model__Cone", DesignerIcons::ModelConeIcon},
+ {"QtQuick3D.Model__Cube", DesignerIcons::ModelCubeIcon},
+ {"QtQuick3D.Model__Cylinder", DesignerIcons::ModelCylinderIcon},
+ {"QtQuick3D.Model__Plane", DesignerIcons::ModelPlaneIcon},
+ {"QtQuick3D.Model__Sphere", DesignerIcons::ModelSphereIcon},
+ };
+
+ QString entryKey = entry.typeName() + "__" + entry.name();
+ if (itemLibraryDesignerIconId.contains(entryKey)) {
+ return contextIcon(itemLibraryDesignerIconId.value(entryKey));
+ }
+ return QIcon(entry.libraryEntryIconPath());
+}
+
Edit3DWidget::Edit3DWidget(Edit3DView *view)
: m_view(view)
{
setAcceptDrops(true);
+ QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
+ sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
+ setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
+
Core::Context context(Constants::C_QMLEDITOR3D);
m_context = new Core::IContext(this);
m_context->setContext(context);
@@ -55,11 +89,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view)
fillLayout->setSpacing(0);
setLayout(fillLayout);
- SeekerSlider *seeker = new SeekerSlider(this);
- seeker->setEnabled(false);
-
// Initialize toolbar
- m_toolBox = new ToolBox(seeker, this);
+ m_toolBox = new ToolBox(this);
fillLayout->addWidget(m_toolBox.data());
// Iterate through view actions. A null action indicates a separator and a second null action
@@ -136,13 +167,6 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view)
createContextMenu();
- view->setSeeker(seeker);
- seeker->setToolTip(QLatin1String("Seek particle system time when paused."));
-
- QObject::connect(seeker, &SeekerSlider::positionChanged, [seeker, view]() {
- view->emitView3DAction(View3DActionType::ParticlesSeek, seeker->position());
- });
-
// Onboarding label contains instructions for new users how to get 3D content into the project
m_onboardingLabel = new QLabel(this);
QString labelText =
@@ -172,13 +196,17 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view)
void Edit3DWidget::createContextMenu()
{
- m_contextMenu = new QMenu(this);
+ m_contextMenu = new QmlEditorMenu(this);
- m_editComponentAction = m_contextMenu->addAction(tr("Edit Component"), [&] {
+ m_editComponentAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::EditComponentIcon),
+ tr("Edit Component"), [&] {
DocumentManager::goIntoComponent(m_view->singleSelectedModelNode());
});
- m_editMaterialAction = m_contextMenu->addAction(tr("Edit Material"), [&] {
+ m_editMaterialAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::MaterialIcon),
+ tr("Edit Material"), [&] {
SelectionContext selCtx(m_view);
selCtx.setTargetNode(m_contextMenuTarget);
ModelNodeOperations::editMaterial(selCtx);
@@ -186,42 +214,58 @@ void Edit3DWidget::createContextMenu()
m_contextMenu->addSeparator();
- m_duplicateAction = m_contextMenu->addAction(tr("Duplicate"), [&] {
- QmlDesignerPlugin::instance()->currentDesignDocument()->duplicateSelected();
- });
-
- m_copyAction = m_contextMenu->addAction(tr("Copy"), [&] {
+ m_copyAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::CopyIcon),
+ tr("Copy"), [&] {
QmlDesignerPlugin::instance()->currentDesignDocument()->copySelected();
});
- m_pasteAction = m_contextMenu->addAction(tr("Paste"), [&] {
+ m_pasteAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::PasteIcon),
+ tr("Paste"), [&] {
QmlDesignerPlugin::instance()->currentDesignDocument()->pasteToPosition(m_contextMenuPos3d);
});
- m_deleteAction = m_contextMenu->addAction(tr("Delete"), [&] {
+ m_deleteAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::DeleteIcon),
+ tr("Delete"), [&] {
view()->executeInTransaction("Edit3DWidget::createContextMenu", [&] {
for (ModelNode &node : m_view->selectedModelNodes())
node.destroy();
});
});
+ m_duplicateAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::DuplicateIcon),
+ tr("Duplicate"), [&] {
+ QmlDesignerPlugin::instance()->currentDesignDocument()->duplicateSelected();
+ });
+
m_contextMenu->addSeparator();
- m_fitSelectedAction = m_contextMenu->addAction(tr("Fit Selected Items to View"), [&] {
+ m_fitSelectedAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::FitSelectedIcon),
+ tr("Fit Selected Items to View"), [&] {
view()->emitView3DAction(View3DActionType::FitToView, true);
});
- m_alignCameraAction = m_contextMenu->addAction(tr("Align Camera to View"), [&] {
+ m_alignCameraAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::AlignCameraToViewIcon),
+ tr("Align Camera to View"), [&] {
view()->emitView3DAction(View3DActionType::AlignCamerasToView, true);
});
- m_alignViewAction = m_contextMenu->addAction(tr("Align View to Camera"), [&] {
+ m_alignViewAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::AlignViewToCameraIcon),
+ tr("Align View to Camera"), [&] {
view()->emitView3DAction(View3DActionType::AlignViewToCamera, true);
});
m_contextMenu->addSeparator();
- m_selectParentAction = m_contextMenu->addAction(tr("Select Parent"), [&] {
+ m_selectParentAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::ParentIcon),
+ tr("Select Parent"), [&] {
ModelNode parentNode = ModelNode::lowestCommonAncestor(view()->selectedModelNodes());
if (!parentNode.isValid())
return;
@@ -233,8 +277,9 @@ void Edit3DWidget::createContextMenu()
});
QAction *defaultToggleGroupAction = view()->edit3DAction(View3DActionType::SelectionModeToggle)->action();
- m_toggleGroupAction = m_contextMenu->addAction(tr("Group Selection Mode"), [&](const bool &mode) {
- Q_UNUSED(mode)
+ m_toggleGroupAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::ToggleGroupIcon),
+ tr("Group Selection Mode"), [&]() {
view()->edit3DAction(View3DActionType::SelectionModeToggle)->action()->trigger();
});
connect(defaultToggleGroupAction, &QAction::toggled, m_toggleGroupAction, &QAction::setChecked);
@@ -260,8 +305,7 @@ bool Edit3DWidget::isSceneLocked() const
}
// Called by the view to update the "create" sub-menu when the Quick3D entries are ready.
-void Edit3DWidget::updateCreateSubMenu(const QStringList &keys,
- const QHash<QString, QList<ItemLibraryEntry>> &entriesMap)
+void Edit3DWidget::updateCreateSubMenu(const QList<ItemLibraryDetails> &entriesList)
{
if (!m_contextMenu)
return;
@@ -272,21 +316,45 @@ void Edit3DWidget::updateCreateSubMenu(const QStringList &keys,
}
m_nameToEntry.clear();
- m_createSubMenu = m_contextMenu->addMenu(tr("Create"));
- for (const QString &cat : keys) {
- QList<ItemLibraryEntry> entries = entriesMap.value(cat);
+ m_createSubMenu = new QmlEditorMenu(tr("Create"), m_contextMenu);
+ m_createSubMenu->setIcon(contextIcon(DesignerIcons::CreateIcon));
+ m_contextMenu->addMenu(m_createSubMenu);
+
+ const QString docPath = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName().toString();
+
+ auto isEntryValid = [&](const ItemLibraryEntry &entry) -> bool {
+ // Don't allow entries that match current document
+ const QString path = entry.customComponentSource();
+ return path.isEmpty() || docPath != path;
+ };
+
+ for (const auto &details : entriesList) {
+ QList<ItemLibraryEntry> entries = details.entryList;
if (entries.isEmpty())
continue;
- QMenu *catMenu = m_createSubMenu->addMenu(cat);
+ QMenu *catMenu = nullptr;
std::sort(entries.begin(), entries.end(), [](const ItemLibraryEntry &a, const ItemLibraryEntry &b) {
return a.name() < b.name();
});
for (const ItemLibraryEntry &entry : std::as_const(entries)) {
- QAction *action = catMenu->addAction(entry.name(), this, &Edit3DWidget::onCreateAction);
+ if (!isEntryValid(entry))
+ continue;
+
+ if (!catMenu) {
+ catMenu = new QmlEditorMenu(details.name, m_createSubMenu);
+ catMenu->setIcon(details.icon);
+ m_createSubMenu->addMenu(catMenu);
+ }
+
+ QAction *action = catMenu->addAction(
+ getEntryIcon(entry),
+ entry.name(),
+ this,
+ &Edit3DWidget::onCreateAction);
action->setData(entry.name());
m_nameToEntry.insert(entry.name(), entry);
}
@@ -320,7 +388,7 @@ void Edit3DWidget::onCreateAction()
// if added node is a Model, assign it a material
if (modelNode.metaInfo().isQtQuick3DModel())
- m_view->assignMaterialTo3dModel(modelNode);
+ MaterialUtils::assignMaterialTo3dModel(m_view, modelNode);
});
}
@@ -431,10 +499,17 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
const DesignerActionManager &actionManager = QmlDesignerPlugin::instance()
->viewManager().designerActionManager();
- 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_TEXTURE)) {
+ if (dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_ASSETS)
+ || dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
+ const auto urls = dragEnterEvent->mimeData()->urls();
+ if (!urls.isEmpty()) {
+ if (Asset(urls.first().toLocalFile()).isValidTextureSource())
+ dragEnterEvent->acceptProposedAction();
+ }
+ } 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_TEXTURE)) {
dragEnterEvent->acceptProposedAction();
} else if (dragEnterEvent->mimeData()->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
QByteArray data = dragEnterEvent->mimeData()->data(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
@@ -449,6 +524,8 @@ void Edit3DWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
{
+ dropEvent->accept();
+ setFocus();
const QPointF pos = m_canvas->mapFrom(this, dropEvent->position());
// handle dropping materials and textures
@@ -464,12 +541,14 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
else
m_view->dropTexture(dropNode, pos);
}
+ m_view->model()->endDrag();
return;
}
// handle dropping bundle materials
if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
m_view->dropBundleMaterial(pos);
+ m_view->model()->endDrag();
return;
}
@@ -477,6 +556,15 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
if (!m_draggedEntry.name().isEmpty())
m_view->dropComponent(m_draggedEntry, pos);
+ m_view->model()->endDrag();
+ return;
+ }
+
+ // handle dropping image assets
+ if (dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_ASSETS)
+ || dropEvent->mimeData()->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
+ m_view->dropAsset(dropEvent->mimeData()->urls().first().toLocalFile(), pos);
+ m_view->model()->endDrag();
return;
}
@@ -501,6 +589,8 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
}
}
});
+
+ m_view->model()->endDrag();
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
index 728d81646d..092abd313a 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
@@ -18,6 +18,19 @@ class Edit3DView;
class Edit3DCanvas;
class ToolBox;
+struct ItemLibraryDetails {
+ QString name;
+ QIcon icon;
+ QList<ItemLibraryEntry> entryList;
+
+ ItemLibraryDetails(
+ const QString &name = QString(),
+ const QIcon &icon = QIcon())
+ : name (name)
+ , icon(icon)
+ {}
+};
+
class Edit3DWidget : public QWidget
{
Q_OBJECT
@@ -37,8 +50,7 @@ public:
void showBackgroundColorMenu(bool show, const QPoint &pos);
void showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d);
- void updateCreateSubMenu(const QStringList &keys,
- const QHash<QString, QList<ItemLibraryEntry>> &entriesMap);
+ void updateCreateSubMenu(const QList<ItemLibraryDetails> &entriesList);
private slots:
void onCreateAction();
diff --git a/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp b/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp
index 9d57112747..72205bd760 100644
--- a/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp
+++ b/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp
@@ -51,7 +51,7 @@ void EventListPluginView::registerActions()
&SelectionContextFunctors::always,
&SelectionContextFunctors::always));
auto eventListAction = new EventListAction();
- connect(eventListAction->defaultAction(), &QAction::triggered, [this]() {
+ connect(eventListAction->action(), &QAction::triggered, [this]() {
if (!m_eventListDialog)
m_eventListDialog = new EventListDialog(Core::ICore::dialogParent());
@@ -62,7 +62,7 @@ void EventListPluginView::registerActions()
designerActionManager.addDesignerAction(eventListAction);
auto assignEventAction = new AssignEventEditorAction();
- connect(assignEventAction->defaultAction(), &QAction::triggered, [this]() {
+ connect(assignEventAction->action(), &QAction::triggered, [this]() {
if (!m_assigner)
m_assigner = new AssignEventDialog(Core::ICore::dialogParent());
if (!m_eventListDialog)
@@ -78,7 +78,7 @@ void EventListPluginView::registerActions()
auto *connectSignalAction = new ConnectSignalAction();
- connect(connectSignalAction->defaultAction(), &QAction::triggered, [this, connectSignalAction]() {
+ connect(connectSignalAction->action(), &QAction::triggered, [this, connectSignalAction]() {
if (!m_signalConnector)
m_signalConnector = new ConnectSignalDialog(Core::ICore::dialogParent());
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
index 0077755d90..8695186605 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -7,6 +7,7 @@
#include "formeditorview.h"
#include "assetslibrarywidget.h"
#include "assetslibrarymodel.h"
+#include "materialutils.h"
#include <metainfo.h>
#include <modelnodeoperations.h>
#include <nodehints.h>
@@ -284,6 +285,7 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneD
}
view()->changeToSelectionTool();
+ view()->model()->endDrag();
}
}
@@ -440,7 +442,7 @@ void DragTool::handleView3dDrop()
const QList<ModelNode> models = dragNode.modelNode().subModelNodesOfType(
model->qtQuick3DModelMetaInfo());
QTC_ASSERT(models.size() == 1, return);
- view()->assignMaterialTo3dModel(models.at(0));
+ MaterialUtils::assignMaterialTo3dModel(view(), models.at(0));
}
}
}
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
index 0e9873dd19..1f4d526285 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
@@ -271,7 +271,7 @@ void FormEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVer
for (FormEditorItem *item : items) {
item->setParentItem(nullptr);
m_scene->removeItemFromHash(item);
- delete item;
+ deleteWithoutChildren({item});
}
QmlItemNode newItemNode(rootModelNode());
@@ -341,7 +341,13 @@ WidgetInfo FormEditorView::widgetInfo()
if (!m_formEditorWidget)
createFormEditorWidget();
- return createWidgetInfo(m_formEditorWidget.data(), "FormEditor", WidgetInfo::CentralPane, 0, tr("2D"), DesignerWidgetFlags::IgnoreErrors);
+ return createWidgetInfo(m_formEditorWidget.data(),
+ "FormEditor",
+ WidgetInfo::CentralPane,
+ 0,
+ tr("2D"),
+ tr("2D view"),
+ DesignerWidgetFlags::IgnoreErrors);
}
FormEditorWidget *FormEditorView::formEditorWidget()
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp
index 648a51b91b..bfc03d2b23 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp
@@ -105,7 +105,8 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view)
m_showBoundingRectAction = new QAction(tr("Show Bounds"), this);
m_showBoundingRectAction->setCheckable(true);
m_showBoundingRectAction->setChecked(false);
- m_showBoundingRectAction->setIcon(DesignerActionManager::instance().contextIcon(DesignerIcons::ShowBoundsIcon));
+ m_showBoundingRectAction->setIcon(
+ DesignerActionManager::instance().contextIcon(DesignerIcons::ShowBoundsIcon));
registerActionAsCommand(m_showBoundingRectAction,
Constants::FORMEDITOR_NO_SHOW_BOUNDING_RECTANGLE,
QKeySequence(Qt::Key_A),
@@ -116,53 +117,49 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view)
m_rootWidthAction = new LineEditAction(tr("Override Width"), this);
m_rootWidthAction->setToolTip(tr("Override width of root component."));
- connect(m_rootWidthAction.data(), &LineEditAction::textChanged,
- this, &FormEditorWidget::changeRootItemWidth);
+ connect(m_rootWidthAction.data(),
+ &LineEditAction::textChanged,
+ this,
+ &FormEditorWidget::changeRootItemWidth);
addAction(m_rootWidthAction.data());
upperActions.append(m_rootWidthAction.data());
m_rootHeightAction = new LineEditAction(tr("Override Height"), this);
m_rootHeightAction->setToolTip(tr("Override height of root component."));
- connect(m_rootHeightAction.data(), &LineEditAction::textChanged,
- this, &FormEditorWidget::changeRootItemHeight);
+ connect(m_rootHeightAction.data(),
+ &LineEditAction::textChanged,
+ this,
+ &FormEditorWidget::changeRootItemHeight);
addAction(m_rootHeightAction.data());
upperActions.append(m_rootHeightAction.data());
- m_toolBox = new ToolBox(nullptr, this);
+ m_toolBox = new ToolBox(this);
fillLayout->addWidget(m_toolBox.data());
m_toolBox->setLeftSideActions(upperActions);
m_backgroundAction = new BackgroundAction(m_toolActionGroup.data());
- connect(m_backgroundAction.data(), &BackgroundAction::backgroundChanged, this, &FormEditorWidget::changeBackgound);
+ connect(m_backgroundAction.data(),
+ &BackgroundAction::backgroundChanged,
+ this,
+ &FormEditorWidget::changeBackgound);
addAction(m_backgroundAction.data());
upperActions.append(m_backgroundAction.data());
m_toolBox->addRightSideAction(m_backgroundAction.data());
// Zoom actions
- const QString fontName = "qtds_propertyIconFont.ttf";
- const QColor iconColorNormal(Theme::getColor(Theme::IconsBaseColor));
- const QColor iconColorDisabled(Theme::getColor(Theme::IconsDisabledColor));
- const QIcon zoomAllIcon = Utils::StyleHelper::getIconFromIconFont(
- fontName, Theme::getIconUnicode(Theme::Icon::zoomAll), 28, 28, iconColorNormal);
-
- const QString zoomSelectionUnicode = Theme::getIconUnicode(Theme::Icon::zoomSelection);
- const auto zoomSelectionNormal = Utils::StyleHelper::IconFontHelper(zoomSelectionUnicode,
- iconColorNormal,
- QSize(28, 28),
- QIcon::Normal);
- const auto zoomSelectionDisabeld = Utils::StyleHelper::IconFontHelper(zoomSelectionUnicode,
- iconColorDisabled,
- QSize(28, 28),
- QIcon::Disabled);
-
- const QIcon zoomSelectionIcon = Utils::StyleHelper::getIconFromIconFont(fontName,
- {zoomSelectionNormal,
- zoomSelectionDisabeld});
- const QIcon zoomInIcon = Utils::StyleHelper::getIconFromIconFont(
- fontName, Theme::getIconUnicode(Theme::Icon::zoomIn), 28, 28, iconColorNormal);
- const QIcon zoomOutIcon = Utils::StyleHelper::getIconFromIconFont(
- fontName, Theme::getIconUnicode(Theme::Icon::zoomOut), 28, 28, iconColorNormal);
+ const QIcon zoomAllIcon = Theme::iconFromName(Theme::Icon::fitAll_medium);
+ auto zoomSelectionNormal = Theme::iconFromName(Theme::Icon::fitSelection_medium);
+ auto zoomSelectionDisabeld = Theme::iconFromName(Theme::Icon::fitSelection_medium,
+ Theme::getColor(
+ Theme::Color::DStoolbarIcon_blocked));
+ QIcon zoomSelectionIcon;
+ zoomSelectionIcon.addPixmap(zoomSelectionNormal.pixmap({16, 16}), QIcon::Normal);
+ zoomSelectionIcon.addPixmap(zoomSelectionDisabeld.pixmap({16, 16}), QIcon::Disabled);
+
+ const QIcon zoomInIcon = Theme::iconFromName(Theme::Icon::zoomIn_medium);
+ const QIcon zoomOutIcon = Theme::iconFromName(Theme::Icon::zoomOut_medium);
+ const QIcon reloadIcon = Theme::iconFromName(Theme::Icon::reload_medium);
auto writeZoomLevel = [this]() {
double level = m_graphicsView->transform().m11();
@@ -270,7 +267,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view)
m_toolBox->addRightSideAction(m_zoomSelectionAction.data());
connect(m_zoomSelectionAction.data(), &QAction::triggered, frameSelection);
- m_resetAction = new QAction(Utils::Icons::RESET_TOOLBAR.icon(), tr("Reset View"), this);
+ m_resetAction = new QAction(reloadIcon, tr("Reload View"), this);
registerActionAsCommand(m_resetAction,
Constants::FORMEDITOR_REFRESH,
QKeySequence(Qt::Key_R),
@@ -611,7 +608,8 @@ void FormEditorWidget::showEvent(QShowEvent *event)
void FormEditorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
{
const DesignerActionManager &actionManager = QmlDesignerPlugin::instance()
- ->viewManager().designerActionManager();
+ ->viewManager()
+ .designerActionManager();
if (actionManager.externalDragHasSupportedAssets(dragEnterEvent->mimeData()))
dragEnterEvent->acceptProposedAction();
}
@@ -619,25 +617,34 @@ void FormEditorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
void FormEditorWidget::dropEvent(QDropEvent *dropEvent)
{
const DesignerActionManager &actionManager = QmlDesignerPlugin::instance()
- ->viewManager().designerActionManager();
- QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData());
+ ->viewManager()
+ .designerActionManager();
+ QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(
+ dropEvent->mimeData());
m_formEditorView->executeInTransaction("FormEditorWidget::dropEvent", [&] {
// Create Image components for added image assets
- const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString);
+ const QStringList addedImages = addedAssets.value(
+ ComponentCoreConstants::addImagesDisplayString);
for (const QString &imgPath : addedImages) {
- QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {},
- m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
- false);
+ QmlItemNode::createQmlItemNodeFromImage(
+ m_formEditorView,
+ imgPath,
+ {},
+ m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
+ false);
}
// Create Text components for added font assets
const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString);
for (const QString &fontPath : addedFonts) {
QString fontFamily = QFileInfo(fontPath).baseName();
- QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(),
- m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
- false);
+ QmlItemNode::createQmlItemNodeFromFont(
+ m_formEditorView,
+ fontFamily,
+ rootItemRect().center(),
+ m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
+ false);
}
});
}
diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp
index 284dff1e55..caa7dcbd30 100644
--- a/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.cpp
@@ -5,112 +5,102 @@
#include <utils/icon.h>
+#include <QMouseEvent>
#include <QStyleOption>
#include <QSlider>
-#include <QDebug>
#include <QPainter>
namespace QmlDesigner {
-SeekerSlider::SeekerSlider(QWidget *parentWidget)
- : QWidget(parentWidget),
- m_bgIcon(QLatin1String(":/icon/layout/scrubbg.png"))
+SeekerSlider::SeekerSlider(QWidget *parent)
+ : QSlider(parent)
{
- m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-24.png"), QSize(24, 24));
- m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-48.png"), QSize(48, 48));
- m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-24.png"), QSize(24, 24), QIcon::Disabled);
- m_handleIcon.addFile(QLatin1String(":/icon/layout/scrubhandle-disabled-48.png"), QSize(48, 48), QIcon::Disabled);
- const Utils::Icon bg({{":/icon/layout/scrubbg.png", Utils::Theme::IconsBaseColor}});
- m_bgWidth = bg.pixmap().width();
- m_bgHeight = bg.pixmap().height();
- m_handleWidth = m_bgHeight;
- m_handleHeight = m_bgHeight;
- int width = m_bgWidth + m_handleWidth * 2;
- m_sliderHalfWidth = m_bgWidth / 2;
- setMinimumWidth(width);
- setMaximumWidth(width);
setProperty("panelwidget", true);
setProperty("panelwidget_singlerow", true);
+ setOrientation(Qt::Horizontal);
+ setFixedWidth(120);
+ setMaxValue(30);
}
-void SeekerSlider::paintEvent([[maybe_unused]] QPaintEvent *event)
+int SeekerSlider::maxValue() const
{
- QPainter painter(this);
- {
- QStyleOptionToolBar option;
- option.rect = rect();
- option.state = QStyle::State_Horizontal;
- style()->drawControl(QStyle::CE_ToolBar, &option, &painter, this);
- }
-
- int x = rect().width() / 2;
- int y = rect().height() / 2;
-
- const QPixmap bg = m_bgIcon.pixmap(QSize(m_bgWidth, m_bgHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On);
- painter.drawPixmap(x - m_bgWidth / 2, y - m_bgHeight / 2, bg);
-
- if (m_moving) {
- const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), QIcon::Active, QIcon::On);
- painter.drawPixmap(x - m_handleWidth / 2 + m_sliderPos, y - m_handleHeight / 2, handle);
- } else {
- const QPixmap handle = m_handleIcon.pixmap(QSize(m_handleWidth, m_handleHeight), isEnabled() ? QIcon::Normal : QIcon::Disabled, QIcon::On);
- painter.drawPixmap(x - m_handleWidth / 2, y - m_handleHeight / 2, handle);
- }
+ return maximum();
+}
+
+void SeekerSlider::setMaxValue(int maxValue)
+{
+ maxValue = std::abs(maxValue);
+ setRange(-maxValue, +maxValue);
}
void SeekerSlider::mousePressEvent(QMouseEvent *event)
{
- if (event->button() != Qt::LeftButton) {
- QWidget::mousePressEvent(event);
+ if (event->button() != Qt::LeftButton)
return;
- }
-
- int x = rect().width() / 2;
- int y = rect().height() / 2;
- auto pos = event->localPos();
- if (pos.x() >= x - m_handleWidth / 2 && pos.x() <= x + m_handleWidth / 2
- && pos.y() >= y - m_handleHeight / 2 && pos.y() <= y + m_handleHeight / 2) {
- m_moving = true;
- m_startPos = pos.x();
- }
+
+ QStyleOptionSlider os;
+ initStyleOption(&os);
+ QRect handleRect = style()->subControlRect(QStyle::CC_Slider, &os, QStyle::SC_SliderHandle, this);
+ m_moving = handleRect.contains(event->localPos().toPoint());
+ if (m_moving)
+ QSlider::mousePressEvent(event);
+ else
+ event->setAccepted(false);
}
void SeekerSlider::mouseMoveEvent(QMouseEvent *event)
{
- if (!m_moving) {
- QWidget::mouseMoveEvent(event);
+ if (!m_moving)
return;
- }
-
- auto pos = event->localPos();
- int delta = pos.x() - m_startPos;
- m_sliderPos = qBound(-m_sliderHalfWidth, delta, m_sliderHalfWidth);
- delta = m_maxPosition * m_sliderPos / m_sliderHalfWidth;
- if (delta != m_position) {
- m_position = delta;
- Q_EMIT positionChanged();
- update();
- }
+
+ QSlider::mouseMoveEvent(event);
}
void SeekerSlider::mouseReleaseEvent(QMouseEvent *event)
{
- if (!m_moving) {
- QWidget::mouseReleaseEvent(event);
+ if (!m_moving)
return;
- }
+ setValue(0);
m_moving = false;
- m_position = 0;
- m_startPos = 0;
- m_sliderPos = 0;
- Q_EMIT positionChanged();
- update();
+ QSlider::mouseReleaseEvent(event);
+}
+
+SeekerSliderAction::SeekerSliderAction(QObject *parent)
+ : QWidgetAction(parent)
+ , m_defaultSlider(new SeekerSlider())
+{
+ setDefaultWidget(m_defaultSlider);
+ QObject::connect(m_defaultSlider, &QSlider::valueChanged, this, &SeekerSliderAction::valueChanged);
+}
+
+SeekerSliderAction::~SeekerSliderAction()
+{
+ m_defaultSlider->deleteLater();
+}
+
+SeekerSlider *SeekerSliderAction::defaultSlider() const
+{
+ return m_defaultSlider;
+}
+
+int SeekerSliderAction::value()
+{
+ return m_defaultSlider->value();
}
-int SeekerSlider::position() const
+QWidget *SeekerSliderAction::createWidget(QWidget *parent)
{
- return m_position;
+ SeekerSlider *slider = new SeekerSlider(parent);
+
+ QObject::connect(m_defaultSlider, &SeekerSlider::valueChanged, slider, &SeekerSlider::setValue);
+ QObject::connect(slider, &SeekerSlider::valueChanged, m_defaultSlider, &SeekerSlider::setValue);
+ QObject::connect(m_defaultSlider, &QSlider::rangeChanged, slider, &QSlider::setRange);
+
+ slider->setValue(m_defaultSlider->value());
+ slider->setMaxValue(m_defaultSlider->maxValue());
+
+ return slider;
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/seekerslider.h b/src/plugins/qmldesigner/components/formeditor/seekerslider.h
index 0c9a6a65dc..d8bc8686ca 100644
--- a/src/plugins/qmldesigner/components/formeditor/seekerslider.h
+++ b/src/plugins/qmldesigner/components/formeditor/seekerslider.h
@@ -2,50 +2,54 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
-#include <QWidget>
-#include <QMouseEvent>
-#include <QIcon>
+#include <QSlider>
+#include <QWidgetAction>
namespace QmlDesigner {
-
-class SeekerSlider : public QWidget
+class SeekerSlider : public QSlider
{
Q_OBJECT
-public:
- SeekerSlider(QWidget *parentWidget);
- int position() const;
- int maxPosition() const
- {
- return m_maxPosition;
- }
- void setMaxPosition(int pos)
- {
- m_maxPosition = qMax(0, pos);
- }
+public:
+ explicit SeekerSlider(QWidget *parent = nullptr);
-Q_SIGNALS:
- void positionChanged();
+ int maxValue() const;
+ void setMaxValue(int maxValue);
protected:
- void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
private:
- int m_position = 0;
- int m_startPos = 0;
- int m_sliderPos = 0;
- int m_sliderHalfWidth = 0;
- int m_maxPosition = 30;
+ using QSlider::setMinimum;
+ using QSlider::setMaximum;
+ using QSlider::setRange;
+
bool m_moving = false;
- int m_bgWidth;
- int m_bgHeight;
- int m_handleWidth;
- int m_handleHeight;
- QIcon m_bgIcon;
- QIcon m_handleIcon;
+};
+
+class SeekerSlider;
+class SeekerSliderAction : public QWidgetAction
+{
+ Q_OBJECT
+
+public:
+ explicit SeekerSliderAction(QObject *parent);
+ virtual ~SeekerSliderAction();
+
+ SeekerSlider *defaultSlider() const;
+ int value();
+
+signals:
+ void valueChanged(int);
+
+protected:
+ virtual QWidget *createWidget(QWidget *parent) override;
+
+private:
+ using QWidgetAction::setDefaultWidget;
+ SeekerSlider *m_defaultSlider = nullptr;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
index b81bdeba0f..d10e14e7cb 100644
--- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
@@ -3,6 +3,8 @@
#include "toolbox.h"
+#include <theme.h>
+
#include <QToolBar>
#include <QHBoxLayout>
#include <QDebug>
@@ -10,12 +12,13 @@
namespace QmlDesigner {
-ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget)
- : Utils::StyledBar(parentWidget),
- m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this)),
- m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this)),
- m_seeker(seeker)
+ToolBox::ToolBox(QWidget *parentWidget)
+ : Utils::StyledBar(parentWidget)
+ , m_leftToolBar(new QToolBar(QLatin1String("LeftSidebar"), this))
+ , m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this))
{
+ setProperty("panelwidget", false);
+
m_leftToolBar->setFloatable(true);
m_leftToolBar->setMovable(true);
m_leftToolBar->setOrientation(Qt::Horizontal);
@@ -24,24 +27,25 @@ ToolBox::ToolBox(SeekerSlider *seeker, QWidget *parentWidget)
horizontalLayout->setContentsMargins(0, 0, 0, 0);
horizontalLayout->setSpacing(0);
- auto stretchToolbar = new QToolBar(this);
+ setFixedHeight(Theme::toolbarSize());
- m_leftToolBar->setProperty("panelwidget", true);
+ m_leftToolBar->setProperty("panelwidget", false);
m_leftToolBar->setProperty("panelwidget_singlerow", false);
+ m_leftToolBar->setFixedHeight(Theme::toolbarSize());
- m_rightToolBar->setProperty("panelwidget", true);
+ m_rightToolBar->setProperty("panelwidget", false);
m_rightToolBar->setProperty("panelwidget_singlerow", false);
+ m_rightToolBar->setFixedHeight(Theme::toolbarSize());
+ m_rightToolBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);
- stretchToolbar->setProperty("panelwidget", true);
+ auto stretchToolbar = new QToolBar(this);
+ stretchToolbar->setProperty("panelwidget", false);
stretchToolbar->setProperty("panelwidget_singlerow", false);
-
stretchToolbar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
m_rightToolBar->setOrientation(Qt::Horizontal);
horizontalLayout->addWidget(m_leftToolBar);
horizontalLayout->addWidget(stretchToolbar);
- if (seeker)
- horizontalLayout->addWidget(m_seeker);
horizontalLayout->addWidget(m_rightToolBar);
}
@@ -74,9 +78,4 @@ QList<QAction*> ToolBox::actions() const
return m_leftToolBar->actions() + m_rightToolBar->actions();
}
-SeekerSlider *ToolBox::seeker() const
-{
- return m_seeker;
-}
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.h b/src/plugins/qmldesigner/components/formeditor/toolbox.h
index 793c328a7e..9d3b86c686 100644
--- a/src/plugins/qmldesigner/components/formeditor/toolbox.h
+++ b/src/plugins/qmldesigner/components/formeditor/toolbox.h
@@ -16,18 +16,16 @@ namespace QmlDesigner {
class ToolBox : public Utils::StyledBar
{
public:
- ToolBox(SeekerSlider *seeker, QWidget *parentWidget);
+ explicit ToolBox(QWidget *parentWidget);
void setLeftSideActions(const QList<QAction*> &actions);
void setRightSideActions(const QList<QAction*> &actions);
void addLeftSideAction(QAction *action);
void addRightSideAction(QAction *action);
QList<QAction*> actions() const;
- SeekerSlider *seeker() const;
private:
QToolBar *m_leftToolBar;
QToolBar *m_rightToolBar;
- SeekerSlider *m_seeker;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp
index 9c73789c91..fecaaefadf 100644
--- a/src/plugins/qmldesigner/components/integration/designdocument.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp
@@ -700,16 +700,20 @@ ModelNode DesignDocument::rootModelNode() const
void DesignDocument::undo()
{
- if (rewriterView() && !rewriterView()->modificationGroupActive())
+ if (rewriterView() && !rewriterView()->modificationGroupActive()) {
plainTextEdit()->undo();
+ rewriterView()->forceAmend();
+ }
viewManager().resetPropertyEditorView();
}
void DesignDocument::redo()
{
- if (rewriterView() && !rewriterView()->modificationGroupActive())
+ if (rewriterView() && !rewriterView()->modificationGroupActive()) {
plainTextEdit()->redo();
+ rewriterView()->forceAmend();
+ }
viewManager().resetPropertyEditorView();
}
diff --git a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
index d7862f926f..a587580590 100644
--- a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
@@ -148,6 +148,7 @@ void DesignDocumentView::fromText(const QString &text)
RewriterView rewriterView{externalDependencies()};
rewriterView.setCheckSemanticErrors(false);
+ rewriterView.setPossibleImportsEnabled(false);
rewriterView.setTextModifier(&modifier);
inputModel->setRewriterView(&rewriterView);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png
index ef59d89279..d211de4554 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png
+++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon@2x.png
index 6540cc859c..8de2aeea05 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon@2x.png
+++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-default-icon@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index df9f273797..91f403f218 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -63,6 +63,9 @@ const int labelMinWidth = 130;
const int controlMinWidth = 65;
const int columnSpacing = 16;
+constexpr QStringView qdsWorkaroundsKey{u"designStudioWorkarounds"};
+constexpr QStringView expandValuesKey{u"expandValueComponents"};
+
} // namespace
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
@@ -172,6 +175,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
while (optIt != supportedOpts.constEnd()) {
QJsonObject options = QJsonObject::fromVariantMap(qvariant_cast<QVariantMap>(optIt.value()));
m_importOptions << options.value("options").toObject();
+ if (m_importOptions.last().contains(qdsWorkaroundsKey)) {
+ QJsonObject optObj = m_importOptions.last()[qdsWorkaroundsKey].toObject();
+ optObj.insert("value", QJsonValue{true});
+ m_importOptions.last().insert(qdsWorkaroundsKey, optObj);
+ }
auto it = defaultOpts.constBegin();
while (it != defaultOpts.constEnd()) {
if (m_importOptions.last().contains(it.key())) {
@@ -477,7 +485,7 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
QJsonObject &options = m_importOptions[optionsIndex];
const auto optKeys = options.keys();
for (const auto &optKey : optKeys) {
- if (!advanced && !isSimpleOption(optKey))
+ if ((!advanced && !isSimpleOption(optKey)) || isHiddenOption(optKey))
continue;
QJsonObject optObj = options.value(optKey).toObject();
const QString optName = optObj.value("name").toString();
@@ -589,11 +597,34 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
m_labelToControlWidgetMaps[optionsIndex].insert(optKey, optControl);
}
- // Handle conditions
+ // Find condition chains (up to two levels supported)
+ // key: Option that has condition and is also specified in another condition as property
+ // value: List of extra widgets that are affected by key property via condition
+ QHash<QString, QList<QWidget *>> conditionChains;
auto it = conditionMap.constBegin();
while (it != conditionMap.constEnd()) {
const QString &option = it.key();
const QJsonArray &conditions = it.value();
+ if (!conditions.isEmpty()) {
+ const QString optItem = conditions[0].toObject().value("property").toString();
+ if (conditionMap.contains(optItem)) {
+ if (!conditionChains.contains(optItem))
+ conditionChains.insert(optItem, {});
+ QPair<QWidget *, QWidget *> widgetPair = optionToWidgetsMap.value(option);
+ if (widgetPair.first)
+ conditionChains[optItem].append(widgetPair.first);
+ if (widgetPair.second)
+ conditionChains[optItem].append(widgetPair.second);
+ }
+ }
+ ++it;
+ }
+
+ // Handle conditions
+ it = conditionMap.constBegin();
+ while (it != conditionMap.constEnd()) {
+ const QString &option = it.key();
+ const QJsonArray &conditions = it.value();
const auto &conWidgets = optionToWidgetsMap.value(option);
QWidget *conLabel = conWidgets.first;
QWidget *conControl = conWidgets.second;
@@ -622,21 +653,33 @@ QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid(
auto optSpin = qobject_cast<QDoubleSpinBox *>(optWidgets.second);
if (optCb) {
auto enableConditionally = [optValue](QCheckBox *cb, QWidget *w1,
- QWidget *w2, Mode mode) {
+ QWidget *w2, const QList<QWidget *> &extraWidgets, Mode mode) {
bool equals = (mode == Mode::equals) == optValue.toBool();
bool enable = cb->isChecked() == equals;
w1->setEnabled(enable);
w2->setEnabled(enable);
+ if (extraWidgets.isEmpty())
+ return;
+
+ if (auto conditionCb = qobject_cast<QCheckBox *>(w2)) {
+ for (const auto w : extraWidgets)
+ w->setEnabled(conditionCb->isChecked() && enable);
+ }
};
- enableConditionally(optCb, conLabel, conControl, mode);
+ // Only initialize conditional state if conditional control is enabled.
+ // If it is disabled, it is assumed that previous chained condition handling
+ // already handled this case.
+ if (optCb->isEnabled())
+ enableConditionally(optCb, conLabel, conControl, conditionChains[option], mode);
if (conditionalWidgetMap.contains(optCb))
conditionalWidgetMap.insert(optCb, nullptr);
else
conditionalWidgetMap.insert(optCb, conControl);
QObject::connect(
optCb, &QCheckBox::toggled, optCb,
- [optCb, conLabel, conControl, mode, enableConditionally]() {
- enableConditionally(optCb, conLabel, conControl, mode);
+ [optCb, conLabel, conControl, extraWidgets = conditionChains[option],
+ mode, enableConditionally]() {
+ enableConditionally(optCb, conLabel, conControl, extraWidgets, mode);
});
}
if (optSpin) {
@@ -804,6 +847,16 @@ bool ItemLibraryAssetImportDialog::isSimpleOption(const QString &id)
return simpleOptions.contains(id);
}
+bool ItemLibraryAssetImportDialog::isHiddenOption(const QString &id)
+{
+ static QList<QStringView> hiddenOptions {
+ qdsWorkaroundsKey,
+ expandValuesKey // Hidden because qdsWorkaroundsKey we force true implies this
+ };
+
+ return hiddenOptions.contains(id);
+}
+
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
{
m_dialogHeight = event->size().height();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
index 4de3dba54c..c5da478232 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
@@ -67,6 +67,7 @@ private:
bool isSimpleGroup(const QString &id);
bool isSimpleOption(const QString &id);
+ bool isHiddenOption(const QString &id);
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
index 83bb483907..cdaa3e28a9 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
@@ -3,6 +3,8 @@
#include "itemlibraryiconimageprovider.h"
+#include <imagecacheimageresponse.h>
+
#include <projectexplorer/target.h>
#include <utils/stylehelper.h>
@@ -11,42 +13,15 @@
namespace QmlDesigner {
-class ImageRespose : public QQuickImageResponse
-{
-public:
- QQuickTextureFactory *textureFactory() const override
- {
- return QQuickTextureFactory::textureFactoryForImage(m_image);
- }
-
- void setImage(const QImage &image)
- {
- m_image = image;
-
- emit finished();
- }
-
- void abort()
- {
- m_image = QImage{
- Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-default-icon.png")};
-
- emit finished();
- }
-
-private:
- QImage m_image;
-};
-
-
QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QString &id,
const QSize &)
{
- auto response = std::make_unique<ImageRespose>();
+ auto response = std::make_unique<ImageCacheImageResponse>(QImage{
+ Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-default-icon.png")});
m_cache.requestSmallImage(
id,
- [response = QPointer<ImageRespose>(response.get())](const QImage &image) {
+ [response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
[response, image] {
@@ -55,12 +30,14 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
},
Qt::QueuedConnection);
},
- [response = QPointer<ImageRespose>(response.get())](ImageCache::AbortReason abortReason) {
+ [response = QPointer<ImageCacheImageResponse>(response.get())](
+ ImageCache::AbortReason abortReason) {
QMetaObject::invokeMethod(
response,
[response, abortReason] {
switch (abortReason) {
case ImageCache::AbortReason::Failed:
+ case ImageCache::AbortReason::NoEntry:
if (response)
response->abort();
break;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
index aacbd9b1b5..b5a0567114 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -45,7 +45,12 @@ WidgetInfo ItemLibraryView::widgetInfo()
if (m_widget.isNull())
m_widget = new ItemLibraryWidget{m_imageCache};
- return createWidgetInfo(m_widget.data(), "Components", WidgetInfo::LeftPane, 0, tr("Components"));
+ return createWidgetInfo(m_widget.data(),
+ "Components",
+ WidgetInfo::LeftPane,
+ 0,
+ tr("Components"),
+ tr("Components view"));
}
void ItemLibraryView::modelAttached(Model *model)
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index c22435c18c..549f9e69c1 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -71,7 +71,7 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
Model *model = document ? document->documentModel() : nullptr;
if (event->type() == QEvent::FocusOut) {
- if (obj == m_itemsWidget.data())
+ if (obj == m_itemsWidget->quickWidget())
QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu");
} else if (event->type() == QMouseEvent::MouseMove) {
if (m_itemToDrag.isValid()) {
@@ -105,6 +105,10 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
m_itemToDrag = {};
}
}
+ } else if (event->type() == QMouseEvent::MouseButtonRelease) {
+ m_itemToDrag = {};
+
+ setIsDragging(false);
}
return QObject::eventFilter(obj, event);
@@ -119,7 +123,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
: m_itemIconSize(24, 24)
, m_itemLibraryModel(new ItemLibraryModel(this))
, m_addModuleModel(new ItemLibraryAddImportModel(this))
- , m_itemsWidget(new QQuickWidget(this))
+ , m_itemsWidget(new StudioQuickWidget(this))
, m_imageCache{imageCache}
{
m_compressionTimer.setInterval(1000);
@@ -130,27 +134,17 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
setMinimumWidth(100);
// set up Component Library view and model
+ m_itemsWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_COMPONENT_LIBRARY);
m_itemsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_itemsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
- m_itemsWidget->rootContext()->setContextProperties({
- {"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.data())},
- {"addModuleModel", QVariant::fromValue(m_addModuleModel.data())},
- {"itemLibraryIconWidth", m_itemIconSize.width()},
- {"itemLibraryIconHeight", m_itemIconSize.height()},
- {"rootView", QVariant::fromValue(this)},
- {"widthLimit", HORIZONTAL_LAYOUT_WIDTH_LIMIT},
- {"highlightColor", Utils::StyleHelper::notTooBrightHighlightColor()},
- });
-
m_previewTooltipBackend = std::make_unique<PreviewTooltipBackend>(m_imageCache);
- m_itemsWidget->rootContext()->setContextProperty("tooltipBackend", m_previewTooltipBackend.get());
m_itemsWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
m_itemsWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"),
new Internal::ItemLibraryImageProvider);
Theme::setupTheme(m_itemsWidget->engine());
- m_itemsWidget->installEventFilter(this);
+ m_itemsWidget->quickWidget()->installEventFilter(this);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
@@ -173,6 +167,19 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_ITEMLIBRARY_TIME);
// init the first load of the QML UI elements
+
+ auto map = m_itemsWidget->registerPropertyMap("ItemLibraryBackend");
+
+ map->setProperties({{"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.data())},
+ {"addModuleModel", QVariant::fromValue(m_addModuleModel.data())},
+ {"itemLibraryIconWidth", m_itemIconSize.width()},
+ {"itemLibraryIconHeight", m_itemIconSize.height()},
+ {"rootView", QVariant::fromValue(this)},
+ {"widthLimit", HORIZONTAL_LAYOUT_WIDTH_LIMIT},
+ {"highlightColor", Utils::StyleHelper::notTooBrightHighlightColor()},
+ {"tooltipBackend", QVariant::fromValue(m_previewTooltipBackend.get())}});
+
+
reloadQmlSource();
}
@@ -316,7 +323,6 @@ void ItemLibraryWidget::reloadQmlSource()
{
const QString itemLibraryQmlPath = qmlSourcesPath() + "/ItemsView.qml";
QTC_ASSERT(QFileInfo::exists(itemLibraryQmlPath), return);
- m_itemsWidget->engine()->clearComponentCache();
m_itemsWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath));
}
@@ -366,12 +372,21 @@ void ItemLibraryWidget::handlePriorityImportsChanged()
}
}
+void ItemLibraryWidget::setIsDragging(bool val)
+{
+ if (m_isDragging != val) {
+ m_isDragging = val;
+ emit isDraggingChanged();
+ }
+}
+
void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos)
{
// Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay
// active (and blocks mouse release) if mouse is released at the same spot of the drag start.
m_itemToDrag = itemLibEntry;
m_dragStartPoint = mousePos.toPoint();
+ setIsDragging(true);
}
bool ItemLibraryWidget::subCompEditMode() const
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
index ccf26d42d8..394b3ea610 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
@@ -6,6 +6,8 @@
#include "itemlibraryinfo.h"
#include "import.h"
+#include <studioquickwidget.h>
+
#include <utils/fancylineedit.h>
#include <utils/dropsupport.h>
#include <previewtooltip/previewtooltipbackend.h>
@@ -14,7 +16,6 @@
#include <QFrame>
#include <QPointF>
#include <QQmlPropertyMap>
-#include <QQuickWidget>
#include <QTimer>
#include <QToolButton>
@@ -44,6 +45,9 @@ class ItemLibraryWidget : public QFrame
public:
Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged)
+ // 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)
+
ItemLibraryWidget(AsynchronousImageCache &imageCache);
~ItemLibraryWidget();
@@ -76,6 +80,7 @@ public:
signals:
void itemActivated(const QString &itemName);
void subCompEditModeChanged();
+ void isDraggingChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -86,6 +91,8 @@ private:
void updateSearch();
void handlePriorityImportsChanged();
+ void setIsDragging(bool val);
+
static QString getDependencyImport(const Import &import);
QTimer m_compressionTimer;
@@ -96,7 +103,7 @@ private:
QPointer<ItemLibraryModel> m_itemLibraryModel;
QPointer<ItemLibraryAddImportModel> m_addModuleModel;
- QScopedPointer<QQuickWidget> m_itemsWidget;
+ QScopedPointer<StudioQuickWidget> m_itemsWidget;
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut;
@@ -107,6 +114,7 @@ private:
QString m_filterText;
QPoint m_dragStartPoint;
bool m_subCompEditMode = false;
+ bool m_isDragging = false;
inline static int HORIZONTAL_LAYOUT_WIDTH_LIMIT = 600;
};
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
index 7f288f906a..d4aedb1cec 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
@@ -3,13 +3,13 @@
#include "materialbrowsermodel.h"
-#include <bindingproperty.h>
-#include <designmodewidget.h>
-#include <qmldesignerplugin.h>
-#include <qmlobjectnode.h>
-#include <variantproperty.h>
-#include <qmltimelinekeyframegroup.h>
-#include "utils/qtcassert.h"
+#include "designmodewidget.h"
+#include "qmldesignerplugin.h"
+#include "qmlobjectnode.h"
+#include "variantproperty.h"
+#include "qmltimelinekeyframegroup.h"
+
+#include <utils/qtcassert.h>
namespace QmlDesigner {
@@ -42,7 +42,7 @@ QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
return m_materialList.at(index.row()).internalId();
if (roleName == "materialVisible")
- return isMaterialVisible(index.row());
+ return isVisible(index.row());
if (roleName == "materialType") {
QString matType = QString::fromLatin1(m_materialList.at(index.row()).type());
@@ -57,7 +57,7 @@ QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
return {};
}
-bool MaterialBrowserModel::isMaterialVisible(int idx) const
+bool MaterialBrowserModel::isVisible(int idx) const
{
if (!isValidIndex(idx))
return false;
@@ -221,14 +221,14 @@ void MaterialBrowserModel::refreshSearch()
bool isEmpty = false;
// if selected material goes invisible, select nearest material
- if (!isMaterialVisible(m_selectedIndex)) {
+ if (!isVisible(m_selectedIndex)) {
int inc = 1;
int incCap = m_materialList.count();
while (!isEmpty && inc < incCap) {
- if (isMaterialVisible(m_selectedIndex - inc)) {
+ if (isVisible(m_selectedIndex - inc)) {
selectMaterial(m_selectedIndex - inc);
break;
- } else if (isMaterialVisible(m_selectedIndex + inc)) {
+ } else if (isVisible(m_selectedIndex + inc)) {
selectMaterial(m_selectedIndex + inc);
break;
}
@@ -236,7 +236,7 @@ void MaterialBrowserModel::refreshSearch()
isEmpty = !isValidIndex(m_selectedIndex + inc)
&& !isValidIndex(m_selectedIndex - inc);
}
- if (!isMaterialVisible(m_selectedIndex)) // handles the case of a single material
+ if (!isVisible(m_selectedIndex)) // handles the case of a single material
isEmpty = true;
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
index 5e07606789..23e6a68973 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
@@ -3,11 +3,10 @@
#pragma once
-#include "qjsonobject.h"
-#include <modelnode.h>
-#include <qmlobjectnode.h>
+#include "modelnode.h"
#include <QAbstractListModel>
+#include <QJsonObject>
#include <QObject>
#include <QPointer>
@@ -77,6 +76,7 @@ public:
Q_INVOKABLE void applyToSelected(qint64 internalId, bool add = false);
Q_INVOKABLE void openMaterialEditor();
Q_INVOKABLE bool isCopiedMaterialValid() const;
+ Q_INVOKABLE bool isVisible(int idx) const;
struct PropertyCopyData
{
@@ -105,7 +105,6 @@ signals:
bool all);
private:
- bool isMaterialVisible(int idx) const;
bool isValidIndex(int idx) const;
QString m_searchText;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
index c76ff43d03..10b6660db5 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
@@ -43,7 +43,7 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
}
if (role == RoleTexVisible)
- return isTextureVisible(index.row());
+ return isVisible(index.row());
if (role == RoleTexHasDynamicProps)
return !m_textureList.at(index.row()).dynamicProperties().isEmpty();
@@ -69,7 +69,7 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
return {};
}
-bool MaterialBrowserTexturesModel::isTextureVisible(int idx) const
+bool MaterialBrowserTexturesModel::isVisible(int idx) const
{
if (!isValidIndex(idx))
return false;
@@ -117,14 +117,14 @@ void MaterialBrowserTexturesModel::refreshSearch()
bool isEmpty = false;
// if selected texture goes invisible, select nearest one
- if (!isTextureVisible(m_selectedIndex)) {
+ if (!isVisible(m_selectedIndex)) {
int inc = 1;
int incCap = m_textureList.count();
while (!isEmpty && inc < incCap) {
- if (isTextureVisible(m_selectedIndex - inc)) {
+ if (isVisible(m_selectedIndex - inc)) {
selectTexture(m_selectedIndex - inc);
break;
- } else if (isTextureVisible(m_selectedIndex + inc)) {
+ } else if (isVisible(m_selectedIndex + inc)) {
selectTexture(m_selectedIndex + inc);
break;
}
@@ -132,7 +132,7 @@ void MaterialBrowserTexturesModel::refreshSearch()
isEmpty = !isValidIndex(m_selectedIndex + inc)
&& !isValidIndex(m_selectedIndex - inc);
}
- if (!isTextureVisible(m_selectedIndex)) // handles the case of a single item
+ if (!isVisible(m_selectedIndex)) // handles the case of a single item
isEmpty = true;
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
index 801febdf53..6d66ad13ec 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
@@ -61,6 +61,7 @@ public:
Q_INVOKABLE void updateSceneEnvState();
Q_INVOKABLE void updateModelSelectionState();
Q_INVOKABLE void applyAsLightProbe(qint64 internalId);
+ Q_INVOKABLE bool isVisible(int idx) const;
signals:
void isEmptyChanged();
@@ -76,7 +77,6 @@ signals:
void applyAsLightProbeRequested(const QmlDesigner::ModelNode &texture);
private:
- bool isTextureVisible(int idx) const;
bool isValidIndex(int idx) const;
QString m_searchText;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index 672173b747..5265c70683 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -5,21 +5,18 @@
#include "bindingproperty.h"
#include "createtexture.h"
+#include "designmodecontext.h"
#include "materialbrowsermodel.h"
#include "materialbrowsertexturesmodel.h"
#include "materialbrowserwidget.h"
#include "nodeabstractproperty.h"
+#include "nodeinstanceview.h"
#include "nodemetainfo.h"
+#include "qmldesignerconstants.h"
#include "qmlobjectnode.h"
#include "variantproperty.h"
-#include <designmodecontext.h>
-#include <nodeinstanceview.h>
-#include <nodelistproperty.h>
-#include <qmldesignerconstants.h>
-
#include <coreplugin/icore.h>
-#include <coreplugin/messagebox.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
@@ -28,7 +25,6 @@
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickView>
-#include <QRegularExpression>
#include <QTimer>
namespace QmlDesigner {
@@ -161,7 +157,7 @@ WidgetInfo MaterialBrowserView::widgetInfo()
MaterialBrowserTexturesModel *texturesModel = m_widget->materialBrowserTexturesModel().data();
connect(texturesModel, &MaterialBrowserTexturesModel::selectedIndexChanged, this, [&] (int idx) {
ModelNode texNode = m_widget->materialBrowserTexturesModel()->textureAt(idx);
- emitCustomNotification("selected_texture_changed", {texNode}, {});
+ emitCustomNotification("selected_texture_changed", {texNode});
});
connect(texturesModel, &MaterialBrowserTexturesModel::duplicateTextureTriggered, this,
[&] (const ModelNode &texture) {
@@ -212,7 +208,19 @@ WidgetInfo MaterialBrowserView::widgetInfo()
"MaterialBrowser",
WidgetInfo::LeftPane,
0,
- tr("Material Browser"));
+ tr("Material Browser"),
+ tr("Material Browser view"));
+}
+
+void MaterialBrowserView::createTextures(const QStringList &assetPaths)
+{
+ auto *create = new CreateTextures(this);
+
+ executeInTransaction("MaterialBrowserView::createTextures", [&]() {
+ create->execute(assetPaths, AddTextureMode::Texture, m_sceneId);
+ });
+
+ create->deleteLater();
}
void MaterialBrowserView::modelAttached(Model *model)
@@ -444,7 +452,7 @@ void MaterialBrowserView::requestPreviews()
m_previewRequests.clear();
}
-ModelNode MaterialBrowserView::getMaterialOfModel(const ModelNode &model)
+ModelNode MaterialBrowserView::getMaterialOfModel(const ModelNode &model, int idx)
{
QmlObjectNode qmlObjNode(model);
QString matExp = qmlObjNode.expression("materials");
@@ -455,12 +463,10 @@ ModelNode MaterialBrowserView::getMaterialOfModel(const ModelNode &model)
if (mats.isEmpty())
return {};
- for (const auto &matId : mats) {
- ModelNode mat = modelNodeForId(matId);
- if (mat.isValid())
- return mat;
- }
- return {};
+ ModelNode mat = modelNodeForId(mats.at(idx));
+ QTC_ASSERT(mat.isValid(), return {});
+
+ return mat;
}
void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
@@ -482,20 +488,32 @@ void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &a
void MaterialBrowserView::customNotification(const AbstractView *view,
const QString &identifier,
const QList<ModelNode> &nodeList,
- [[maybe_unused]] const QList<QVariant> &data)
+ const QList<QVariant> &data)
{
- if (view == this)
+ if (view == this && identifier != "select_texture")
return;
- if (identifier == "selected_material_changed") {
- int idx = m_widget->materialBrowserModel()->materialIndex(nodeList.first());
+ if (identifier == "select_material") {
+ ModelNode matNode;
+ if (!data.isEmpty() && !m_selectedModels.isEmpty()) {
+ ModelNode model3D = m_selectedModels.at(0);
+ QTC_ASSERT(model3D.isValid(), return);
+ matNode = getMaterialOfModel(model3D, data[0].toInt());
+ } else {
+ matNode = nodeList.first();
+ }
+ QTC_ASSERT(matNode.isValid(), return);
+
+ int idx = m_widget->materialBrowserModel()->materialIndex(matNode);
if (idx != -1)
m_widget->materialBrowserModel()->selectMaterial(idx);
- } else if (identifier == "selected_texture_changed") {
+ } else if (identifier == "select_texture") {
int idx = m_widget->materialBrowserTexturesModel()->textureIndex(nodeList.first());
if (idx != -1) {
m_widget->materialBrowserTexturesModel()->selectTexture(idx);
m_widget->materialBrowserTexturesModel()->refreshSearch();
+ if (!data.isEmpty() && data[0].toBool())
+ m_widget->focusMaterialSection(false);
}
} else if (identifier == "refresh_material_browser") {
QTimer::singleShot(0, model(), [this]() {
@@ -503,10 +521,15 @@ void MaterialBrowserView::customNotification(const AbstractView *view,
});
} else if (identifier == "delete_selected_material") {
m_widget->deleteSelectedItem();
+ } else if (identifier == "apply_asset_to_model3D") {
+ m_appliedTexturePath = data.at(0).toString();
+ applyTextureToModel3D(nodeList.at(0));
} else if (identifier == "apply_texture_to_model3D") {
applyTextureToModel3D(nodeList.at(0), nodeList.at(1));
} else if (identifier == "apply_texture_to_material") {
applyTextureToMaterial({nodeList.at(0)}, nodeList.at(1));
+ } else if (identifier == "focus_material_section") {
+ m_widget->focusMaterialSection(true);
}
}
@@ -556,7 +579,10 @@ void MaterialBrowserView::instancePropertyChanged(const QList<QPair<ModelNode, P
void MaterialBrowserView::applyTextureToModel3D(const QmlObjectNode &model3D, const ModelNode &texture)
{
- if (!texture.isValid() || !model3D.isValid() || !model3D.modelNode().metaInfo().isQtQuick3DModel())
+ if (!texture.isValid() && m_appliedTexturePath.isEmpty())
+ return;
+
+ if (!model3D.isValid() || !model3D.modelNode().metaInfo().isQtQuick3DModel())
return;
BindingProperty matsProp = model3D.bindingProperty("materials");
@@ -572,42 +598,45 @@ void MaterialBrowserView::applyTextureToModel3D(const QmlObjectNode &model3D, co
void MaterialBrowserView::applyTextureToMaterial(const QList<ModelNode> &materials,
const ModelNode &texture)
{
- if (materials.size() > 0) {
+ if (materials.isEmpty())
+ return;
+
+ if (texture.isValid())
m_appliedTextureId = texture.id();
- m_textureModels.clear();
- QStringList materialsModel;
- for (const ModelNode &mat : std::as_const(materials)) {
- QString matName = mat.variantProperty("objectName").value().toString();
- materialsModel.append(QLatin1String("%1 (%2)").arg(matName, mat.id()));
- QList<PropertyName> texProps;
- for (const PropertyMetaInfo &p : mat.metaInfo().properties()) {
- if (p.propertyType().isQtQuick3DTexture())
- texProps.append(p.name());
- }
- m_textureModels.insert(mat.id(), texProps);
- }
- QString path = MaterialBrowserWidget::qmlSourcesPath() + "/ChooseMaterialProperty.qml";
-
- m_chooseMatPropsView = new QQuickView;
- m_chooseMatPropsView->setTitle(tr("Select a material property"));
- m_chooseMatPropsView->setResizeMode(QQuickView::SizeRootObjectToView);
- m_chooseMatPropsView->setMinimumSize({150, 100});
- m_chooseMatPropsView->setMaximumSize({600, 400});
- m_chooseMatPropsView->setWidth(450);
- m_chooseMatPropsView->setHeight(300);
- m_chooseMatPropsView->setFlags(Qt::Widget);
- m_chooseMatPropsView->setModality(Qt::ApplicationModal);
- m_chooseMatPropsView->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
- m_chooseMatPropsView->rootContext()->setContextProperties({
- {"rootView", QVariant::fromValue(this)},
- {"materialsModel", QVariant::fromValue(materialsModel)},
- {"propertiesModel", QVariant::fromValue(m_textureModels.value(materials.at(0).id()))},
- });
- m_chooseMatPropsView->setSource(QUrl::fromLocalFile(path));
- m_chooseMatPropsView->installEventFilter(this);
- m_chooseMatPropsView->show();
+ m_textureModels.clear();
+ QStringList materialsModel;
+ for (const ModelNode &mat : std::as_const(materials)) {
+ QString matName = mat.variantProperty("objectName").value().toString();
+ materialsModel.append(QLatin1String("%1 (%2)").arg(matName, mat.id()));
+ QList<PropertyName> texProps;
+ for (const PropertyMetaInfo &p : mat.metaInfo().properties()) {
+ if (p.propertyType().isQtQuick3DTexture())
+ texProps.append(p.name());
+ }
+ m_textureModels.insert(mat.id(), texProps);
}
+
+ QString path = MaterialBrowserWidget::qmlSourcesPath() + "/ChooseMaterialProperty.qml";
+
+ m_chooseMatPropsView = new QQuickView;
+ m_chooseMatPropsView->setTitle(tr("Select a material property"));
+ m_chooseMatPropsView->setResizeMode(QQuickView::SizeRootObjectToView);
+ m_chooseMatPropsView->setMinimumSize({150, 100});
+ m_chooseMatPropsView->setMaximumSize({600, 400});
+ m_chooseMatPropsView->setWidth(450);
+ m_chooseMatPropsView->setHeight(300);
+ m_chooseMatPropsView->setFlags(Qt::Widget);
+ m_chooseMatPropsView->setModality(Qt::ApplicationModal);
+ m_chooseMatPropsView->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+ m_chooseMatPropsView->rootContext()->setContextProperties({
+ {"rootView", QVariant::fromValue(this)},
+ {"materialsModel", QVariant::fromValue(materialsModel)},
+ {"propertiesModel", QVariant::fromValue(m_textureModels.value(materials.at(0).id()))},
+ });
+ m_chooseMatPropsView->setSource(QUrl::fromLocalFile(path));
+ m_chooseMatPropsView->installEventFilter(this);
+ m_chooseMatPropsView->show();
}
void MaterialBrowserView::updatePropsModel(const QString &matId)
@@ -618,17 +647,27 @@ void MaterialBrowserView::updatePropsModel(const QString &matId)
void MaterialBrowserView::applyTextureToProperty(const QString &matId, const QString &propName)
{
- QTC_ASSERT(!m_appliedTextureId.isEmpty(), return);
+ executeInTransaction(__FUNCTION__, [&] {
+ if (m_appliedTextureId.isEmpty() && !m_appliedTexturePath.isEmpty()) {
+ auto texCreator = new CreateTexture(this);
+ ModelNode tex = texCreator->execute(m_appliedTexturePath, AddTextureMode::Texture);
+ m_appliedTextureId = tex.id();
+ m_appliedTexturePath.clear();
+ texCreator->deleteLater();
+ }
- QmlObjectNode mat = modelNodeForId(matId);
- QTC_ASSERT(mat.isValid(), return);
+ QTC_ASSERT(!m_appliedTextureId.isEmpty(), return);
- BindingProperty texProp = mat.bindingProperty(propName.toLatin1());
- QTC_ASSERT(texProp.isValid(), return);
+ QmlObjectNode mat = modelNodeForId(matId);
+ QTC_ASSERT(mat.isValid(), return);
- mat.setBindingProperty(propName.toLatin1(), m_appliedTextureId);
+ BindingProperty texProp = mat.bindingProperty(propName.toLatin1());
+ QTC_ASSERT(texProp.isValid(), return);
- closeChooseMatPropsView();
+ mat.setBindingProperty(propName.toLatin1(), m_appliedTextureId);
+
+ closeChooseMatPropsView();
+ });
}
void MaterialBrowserView::closeChooseMatPropsView()
@@ -647,6 +686,7 @@ bool MaterialBrowserView::eventFilter(QObject *obj, QEvent *event)
} else if (event->type() == QEvent::Close) {
if (obj == m_chooseMatPropsView) {
m_appliedTextureId.clear();
+ m_appliedTexturePath.clear();
m_chooseMatPropsView->deleteLater();
}
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
index 0942f7a656..811d6679b6 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
@@ -4,7 +4,6 @@
#pragma once
#include "abstractview.h"
-#include "createtexture.h"
#include <QPointer>
#include <QSet>
@@ -53,9 +52,10 @@ public:
void active3DSceneChanged(qint32 sceneId) override;
void currentStateChanged(const ModelNode &node) override;
- void applyTextureToModel3D(const QmlObjectNode &model3D, const ModelNode &texture);
+ void applyTextureToModel3D(const QmlObjectNode &model3D, const ModelNode &texture = {});
void applyTextureToMaterial(const QList<ModelNode> &materials, const ModelNode &texture);
+ void createTextures(const QStringList &assetPaths);
Q_INVOKABLE void updatePropsModel(const QString &matId);
Q_INVOKABLE void applyTextureToProperty(const QString &matId, const QString &propName);
@@ -71,7 +71,7 @@ private:
void loadPropertyGroups();
void requestPreviews();
ModelNode resolveSceneEnv();
- ModelNode getMaterialOfModel(const ModelNode &model);
+ ModelNode getMaterialOfModel(const ModelNode &model, int idx = 0);
AsynchronousImageCache &m_imageCache;
QPointer<MaterialBrowserWidget> m_widget;
@@ -87,6 +87,7 @@ private:
QPointer<QQuickView> m_chooseMatPropsView;
QHash<QString, QList<PropertyName>> m_textureModels;
QString m_appliedTextureId;
+ QString m_appliedTexturePath; // defers texture creation until dialog apply
int m_sceneId = -1;
};
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
index 372c10fb63..d0c5483bdd 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp
@@ -3,42 +3,34 @@
#include "materialbrowserwidget.h"
+#include "asset.h"
+#include "assetimageprovider.h"
+#include "createtexture.h"
+#include "documentmanager.h"
+#include "hdrimage.h"
#include "materialbrowsermodel.h"
#include "materialbrowsertexturesmodel.h"
#include "materialbrowserview.h"
+#include "qmldesignerconstants.h"
+#include "qmldesignerplugin.h"
+#include "theme.h"
+#include "variantproperty.h"
-#include <designeractionmanager.h>
-#include <designermcumanager.h>
-#include <documentmanager.h>
-#include <propertyeditorimageprovider.h>
-#include <qmldesignerconstants.h>
-#include <qmldesignerplugin.h>
-#include <variantproperty.h>
+#include <coreplugin/icore.h>
-#include <theme.h>
+#include <studioquickwidget.h>
#include <utils/algorithm.h>
#include <utils/environment.h>
-#include <utils/hdrimage.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
-#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QQmlContext>
-#include <QQmlEngine>
#include <QQuickImageProvider>
#include <QQuickItem>
-#include <QQuickWidget>
#include <QShortcut>
-#include <QStackedWidget>
-#include <QTabBar>
-#include <QToolButton>
#include <QVBoxLayout>
-#include <QWheelEvent>
namespace QmlDesigner {
@@ -93,7 +85,7 @@ public:
bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FocusOut) {
- if (obj == m_quickWidget.data())
+ if (obj == m_quickWidget->quickWidget())
QMetaObject::invokeMethod(m_quickWidget->rootObject(), "closeContextMenu");
} else if (event->type() == QMouseEvent::MouseMove) {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -124,6 +116,8 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event)
const QString suffix = iconPath.split('.').last().toLower();
if (suffix == "hdr")
pixmap = HdrImage{iconPath}.toPixmap();
+ else if (suffix == "ktx")
+ pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/textureeditor/images/texture_ktx.png");
else
pixmap = Utils::StyleHelper::dpiSpecificImageFile(iconPath);
if (pixmap.isNull())
@@ -137,6 +131,8 @@ bool MaterialBrowserWidget::eventFilter(QObject *obj, QEvent *event)
} else if (event->type() == QMouseEvent::MouseButtonRelease) {
m_materialToDrag = {};
m_textureToDrag = {};
+
+ setIsDragging(false);
}
return QObject::eventFilter(obj, event);
@@ -147,12 +143,12 @@ MaterialBrowserWidget::MaterialBrowserWidget(AsynchronousImageCache &imageCache,
: m_materialBrowserView(view)
, m_materialBrowserModel(new MaterialBrowserModel(this))
, m_materialBrowserTexturesModel(new MaterialBrowserTexturesModel(this))
- , m_quickWidget(new QQuickWidget(this))
+ , m_quickWidget(new StudioQuickWidget(this))
, m_previewImageProvider(new PreviewImageProvider())
{
QImage defaultImage;
defaultImage.load(Utils::StyleHelper::dpiSpecificImageFile(":/textureeditor/images/texture_default.png"));
- m_textureImageProvider = new PropertyEditorImageProvider(imageCache, defaultImage);
+ m_textureImageProvider = new AssetImageProvider(imageCache, defaultImage);
setWindowTitle(tr("Material Browser", "Title of material browser widget"));
setMinimumWidth(120);
@@ -162,21 +158,16 @@ MaterialBrowserWidget::MaterialBrowserWidget(AsynchronousImageCache &imageCache,
m_context->setContext(context);
m_context->setWidget(this);
+ m_quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_MATERIAL_BROWSER);
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
- m_quickWidget->rootContext()->setContextProperties({
- {"rootView", QVariant::fromValue(this)},
- {"materialBrowserModel", QVariant::fromValue(m_materialBrowserModel.data())},
- {"materialBrowserTexturesModel", QVariant::fromValue(m_materialBrowserTexturesModel.data())},
- });
-
m_quickWidget->engine()->addImageProvider("materialBrowser", m_previewImageProvider);
m_quickWidget->engine()->addImageProvider("materialBrowserTex", m_textureImageProvider);
Theme::setupTheme(m_quickWidget->engine());
- m_quickWidget->installEventFilter(this);
+ m_quickWidget->quickWidget()->installEventFilter(this);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
@@ -203,7 +194,17 @@ MaterialBrowserWidget::MaterialBrowserWidget(AsynchronousImageCache &imageCache,
QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_MATERIALBROWSER_TIME);
+ auto map = m_quickWidget->registerPropertyMap("MaterialBrowserBackend");
+
+ map->setProperties({
+ {"rootView", QVariant::fromValue(this)},
+ {"materialBrowserModel", QVariant::fromValue(m_materialBrowserModel.data())},
+ {"materialBrowserTexturesModel", QVariant::fromValue(m_materialBrowserTexturesModel.data())},
+ });
+
reloadQmlSource();
+
+ setFocusProxy(m_quickWidget.data());
}
void MaterialBrowserWidget::updateMaterialPreview(const ModelNode &node, const QPixmap &pixmap)
@@ -247,22 +248,91 @@ void MaterialBrowserWidget::startDragMaterial(int index, const QPointF &mousePos
{
m_materialToDrag = m_materialBrowserModel->materialAt(index);
m_dragStartPoint = mousePos.toPoint();
+
+ setIsDragging(true);
}
void MaterialBrowserWidget::startDragTexture(int index, const QPointF &mousePos)
{
m_textureToDrag = m_materialBrowserTexturesModel->textureAt(index);
m_dragStartPoint = mousePos.toPoint();
+
+ setIsDragging(true);
}
void MaterialBrowserWidget::acceptBundleMaterialDrop()
{
m_materialBrowserView->emitCustomNotification("drop_bundle_material", {}, {}); // To ContentLibraryView
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
+}
+
+bool MaterialBrowserWidget::hasAcceptableAssets(const QList<QUrl> &urls)
+{
+ return Utils::anyOf(urls, [](const QUrl &url) {
+ return Asset(url.toLocalFile()).isValidTextureSource();
+ });
}
void MaterialBrowserWidget::acceptBundleTextureDrop()
{
m_materialBrowserView->emitCustomNotification("drop_bundle_texture", {}, {}); // To ContentLibraryView
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
+}
+
+void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, const QUrl &bundleTexPath)
+{
+ ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
+ QTC_ASSERT(mat.isValid(), return);
+
+ auto *creator = new CreateTexture(m_materialBrowserView);
+
+ m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
+ ModelNode tex = creator->execute(bundleTexPath.toLocalFile());
+ QTC_ASSERT(tex.isValid(), return);
+
+ m_materialBrowserModel->selectMaterial(matIndex);
+ m_materialBrowserView->applyTextureToMaterial({mat}, tex);
+ });
+
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
+
+ creator->deleteLater();
+}
+
+void MaterialBrowserWidget::acceptAssetsDrop(const QList<QUrl> &urls)
+{
+ QStringList assetPaths = Utils::transform(urls, [](const QUrl &url) { return url.toLocalFile(); });
+ m_materialBrowserView->createTextures(assetPaths);
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
+}
+
+void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList<QUrl> &urls)
+{
+ ModelNode mat = m_materialBrowserModel->materialAt(matIndex);
+ QTC_ASSERT(mat.isValid(), return);
+
+ auto *creator = new CreateTexture(m_materialBrowserView);
+
+ QString imageSrc = Utils::findOrDefault(urls, [] (const QUrl &url) {
+ return Asset(url.toLocalFile()).isValidTextureSource();
+ }).toLocalFile();
+
+ m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] {
+ ModelNode tex = creator->execute(imageSrc);
+ QTC_ASSERT(tex.isValid(), return);
+
+ m_materialBrowserModel->selectMaterial(matIndex);
+ m_materialBrowserView->applyTextureToMaterial({mat}, tex);
+ });
+
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
+
+ creator->deleteLater();
}
void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QString &texId)
@@ -274,6 +344,9 @@ void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QStr
m_materialBrowserModel->selectMaterial(matIndex);
m_materialBrowserView->applyTextureToMaterial({mat}, tex);
}
+
+ if (m_materialBrowserView->model())
+ m_materialBrowserView->model()->endDrag();
}
void MaterialBrowserWidget::focusMaterialSection(bool focusMatSec)
@@ -304,7 +377,6 @@ void MaterialBrowserWidget::reloadQmlSource()
QTC_ASSERT(QFileInfo::exists(materialBrowserQmlPath), return);
- m_quickWidget->engine()->clearComponentCache();
m_quickWidget->setSource(QUrl::fromLocalFile(materialBrowserQmlPath));
}
@@ -315,7 +387,15 @@ void MaterialBrowserWidget::updateSearch()
m_quickWidget->update();
}
-QQuickWidget *MaterialBrowserWidget::quickWidget() const
+void MaterialBrowserWidget::setIsDragging(bool val)
+{
+ if (m_isDragging != val) {
+ m_isDragging = val;
+ emit isDraggingChanged();
+ }
+}
+
+StudioQuickWidget *MaterialBrowserWidget::quickWidget() const
{
return m_quickWidget.data();
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
index 2a3d36fe0a..ea0e5a212a 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.h
@@ -6,29 +6,24 @@
#include "modelnode.h"
#include <coreplugin/icontext.h>
-#include <utils/dropsupport.h>
-#include <utils/fancylineedit.h>
-#include <QFileIconProvider>
#include <QFrame>
-#include <QQmlPropertyMap>
-
-#include <memory>
QT_BEGIN_NAMESPACE
-class QQuickWidget;
class QPointF;
class QShortcut;
class QToolButton;
QT_END_NAMESPACE
+class StudioQuickWidget;
+
namespace QmlDesigner {
+class AssetImageProvider;
class MaterialBrowserView;
class MaterialBrowserModel;
class MaterialBrowserTexturesModel;
class PreviewImageProvider;
-class PropertyEditorImageProvider;
class MaterialBrowserWidget : public QFrame
{
@@ -36,6 +31,9 @@ class MaterialBrowserWidget : public QFrame
Q_PROPERTY(bool materialSectionFocused MEMBER m_materialSectionFocused NOTIFY materialSectionFocusedChanged)
+ // 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)
+
public:
MaterialBrowserWidget(class AsynchronousImageCache &imageCache, MaterialBrowserView *view);
~MaterialBrowserWidget() = default;
@@ -55,16 +53,21 @@ public:
Q_INVOKABLE void startDragMaterial(int index, const QPointF &mousePos);
Q_INVOKABLE void startDragTexture(int index, const QPointF &mousePos);
Q_INVOKABLE void acceptBundleMaterialDrop();
+ Q_INVOKABLE bool hasAcceptableAssets(const QList<QUrl> &urls);
Q_INVOKABLE void acceptBundleTextureDrop();
+ Q_INVOKABLE void acceptBundleTextureDropOnMaterial(int matIndex, const QUrl &bundleTexPath);
+ Q_INVOKABLE void acceptAssetsDrop(const QList<QUrl> &urls);
+ 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);
- QQuickWidget *quickWidget() const;
+ StudioQuickWidget *quickWidget() const;
void clearPreviewCache();
signals:
void materialSectionFocusedChanged();
+ void isDraggingChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -73,14 +76,16 @@ private:
void reloadQmlSource();
void updateSearch();
+ void setIsDragging(bool val);
+
QPointer<MaterialBrowserView> m_materialBrowserView;
QPointer<MaterialBrowserModel> m_materialBrowserModel;
QPointer<MaterialBrowserTexturesModel> m_materialBrowserTexturesModel;
- QScopedPointer<QQuickWidget> m_quickWidget;
+ QScopedPointer<StudioQuickWidget> m_quickWidget;
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
PreviewImageProvider *m_previewImageProvider = nullptr;
- PropertyEditorImageProvider *m_textureImageProvider = nullptr;
+ AssetImageProvider *m_textureImageProvider = nullptr;
Core::IContext *m_context = nullptr;
QString m_filterText;
@@ -90,6 +95,7 @@ private:
QPoint m_dragStartPoint;
bool m_materialSectionFocused = true;
+ bool m_isDragging = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialutils.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialutils.cpp
new file mode 100644
index 0000000000..76924bedbc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialutils.cpp
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "materialutils.h"
+
+#include "abstractview.h"
+#include "nodelistproperty.h"
+#include "nodemetainfo.h"
+#include "qmlobjectnode.h"
+#include "variantproperty.h"
+
+#include <utils/qtcassert.h>
+
+namespace QmlDesigner {
+
+// Assigns given material to a 3D model.
+// The assigned material is also inserted into material library if not already there.
+// If given material is not valid, first existing material from material library is used,
+// or if material library is empty, a new material is created.
+// This function should be called only from inside a transaction, as it potentially does many
+// changes to model.
+void MaterialUtils::assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
+ const ModelNode &materialNode)
+{
+ QTC_ASSERT(modelNode.isValid() && modelNode.metaInfo().isQtQuick3DModel(), return);
+
+ ModelNode matLib = view->materialLibraryNode();
+
+ if (!matLib.isValid())
+ return;
+
+ ModelNode newMaterialNode;
+
+ if (materialNode.isValid() && materialNode.metaInfo().isQtQuick3DMaterial()) {
+ newMaterialNode = materialNode;
+ } else {
+ const QList<ModelNode> materials = matLib.directSubModelNodes();
+ if (materials.size() > 0) {
+ for (const ModelNode &mat : materials) {
+ if (mat.metaInfo().isQtQuick3DMaterial()) {
+ newMaterialNode = mat;
+ break;
+ }
+ }
+ }
+
+ // if no valid material, create a new default material
+ if (!newMaterialNode.isValid()) {
+ NodeMetaInfo metaInfo = view->model()->qtQuick3DPrincipledMaterialMetaInfo();
+ newMaterialNode = view->createModelNode("QtQuick3D.PrincipledMaterial",
+ metaInfo.majorVersion(),
+ metaInfo.minorVersion());
+ newMaterialNode.validId();
+ }
+ }
+
+ QTC_ASSERT(newMaterialNode.isValid(), return);
+
+ VariantProperty matNameProp = newMaterialNode.variantProperty("objectName");
+ if (matNameProp.value().isNull())
+ matNameProp.setValue("New Material");
+
+ if (!newMaterialNode.hasParentProperty()
+ || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) {
+ matLib.defaultNodeListProperty().reparentHere(newMaterialNode);
+ }
+
+ QmlObjectNode(modelNode).setBindingProperty("materials", newMaterialNode.id());
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialutils.h b/src/plugins/qmldesigner/components/materialbrowser/materialutils.h
new file mode 100644
index 0000000000..e273ef74a4
--- /dev/null
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialutils.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include "modelnode.h"
+
+namespace QmlDesigner {
+
+class AbstractView;
+
+class MaterialUtils
+{
+public:
+ MaterialUtils();
+
+ static void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
+ const ModelNode &materialNode = {});
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.cpp
index 147ecd1d5f..c59ca61ff1 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.cpp
@@ -29,7 +29,7 @@
#include <materialeditorview.h>
-using namespace QmlDesigner;
+namespace QmlDesigner {
MaterialEditorDynamicPropertiesProxyModel::MaterialEditorDynamicPropertiesProxyModel(QObject *parent)
: DynamicPropertiesProxyModel(parent)
@@ -43,3 +43,5 @@ void MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType()
DynamicPropertiesProxyModel::registerDeclarativeType();
qmlRegisterType<MaterialEditorDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "MaterialEditorDynamicPropertiesModel");
}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.h b/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.h
index 9d4e6aa9a4..d2add25c65 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditordynamicpropertiesproxymodel.h
@@ -27,6 +27,8 @@
#include "dynamicpropertiesproxymodel.h"
+namespace QmlDesigner {
+
class MaterialEditorDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
{
Q_OBJECT
@@ -35,3 +37,5 @@ public:
static void registerDeclarativeType();
};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
index c08e0c65c2..edae2377bf 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorqmlbackend.cpp
@@ -84,6 +84,7 @@ MaterialEditorQmlBackend::MaterialEditorQmlBackend(MaterialEditorView *materialE
, m_contextObject(new MaterialEditorContextObject(m_view->rootContext()))
, m_materialEditorImageProvider(new MaterialEditorImageProvider())
{
+ m_view->setObjectName(Constants::OBJECT_NAME_MATERIAL_EDITOR);
m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_view->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_view->engine()->addImageProvider("materialEditor", m_materialEditorImageProvider);
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditortransaction.h b/src/plugins/qmldesigner/components/materialeditor/materialeditortransaction.h
index ba5ee7672e..aeda758809 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditortransaction.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditortransaction.h
@@ -4,6 +4,7 @@
#pragma once
#include "materialeditorview.h"
+#include "rewritertransaction.h"
namespace QmlDesigner {
@@ -12,7 +13,7 @@ class MaterialEditorTransaction : public QObject
Q_OBJECT
public:
- MaterialEditorTransaction(QmlDesigner::MaterialEditorView *materialEditor);
+ MaterialEditorTransaction(MaterialEditorView *materialEditor);
Q_INVOKABLE void start();
Q_INVOKABLE void end();
@@ -23,8 +24,8 @@ protected:
void timerEvent(QTimerEvent *event) override;
private:
- QmlDesigner::MaterialEditorView *m_materialEditor = nullptr;
- QmlDesigner::RewriterTransaction m_rewriterTransaction;
+ MaterialEditorView *m_materialEditor = nullptr;
+ RewriterTransaction m_rewriterTransaction;
int m_timerId = -1;
};
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index b174caeb6b..47d47985eb 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -3,48 +3,39 @@
#include "materialeditorview.h"
+#include "asset.h"
+#include "bindingproperty.h"
+#include "auxiliarydataproperties.h"
+#include "designdocument.h"
+#include "designmodewidget.h"
+#include "dynamicpropertiesmodel.h"
+#include "itemlibraryinfo.h"
#include "materialeditorqmlbackend.h"
#include "materialeditorcontextobject.h"
#include "materialeditordynamicpropertiesproxymodel.h"
-#include "propertyeditorvalue.h"
#include "materialeditortransaction.h"
-#include "assetslibrarywidget.h"
-
-#include <auxiliarydataproperties.h>
-#include <bindingproperty.h>
-#include <dynamicpropertiesmodel.h>
-#include <metainfo.h>
-#include <nodeinstanceview.h>
-#include <nodelistproperty.h>
-#include <nodemetainfo.h>
-#include <nodeproperty.h>
-#include <rewritingexception.h>
-#include <variantproperty.h>
-#include <qmldesignerconstants.h>
-#include <qmldesignerplugin.h>
-#include <qmltimeline.h>
-
-#include <theme.h>
+#include "metainfo.h"
+#include "nodeinstanceview.h"
+#include "nodelistproperty.h"
+#include "nodemetainfo.h"
+#include "propertyeditorqmlbackend.h"
+#include "propertyeditorvalue.h"
+#include "qmldesignerconstants.h"
+#include "qmldesignerplugin.h"
+#include "qmltimeline.h"
+#include "variantproperty.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
-#include <designmodewidget.h>
-#include <propertyeditorqmlbackend.h>
+
#include <utils/environment.h>
-#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <qmldesignerplugin.h>
-#include <QApplication>
-#include <QDebug>
#include <QDir>
#include <QFileInfo>
-#include <QQuickWidget>
#include <QQuickItem>
-#include <QScopedPointer>
#include <QStackedWidget>
#include <QShortcut>
-#include <QTimer>
#include <QColorDialog>
namespace QmlDesigner {
@@ -52,7 +43,7 @@ namespace QmlDesigner {
MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDependencies)
: AbstractView{externalDependencies}
, m_stackedWidget(new QStackedWidget)
- , m_dynamicPropertiesModel(new Internal::DynamicPropertiesModel(true, this))
+ , m_dynamicPropertiesModel(new DynamicPropertiesModel(true, this))
{
m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F7), m_stackedWidget);
connect(m_updateShortcut, &QShortcut::activated, this, &MaterialEditorView::reloadQml);
@@ -60,7 +51,9 @@ MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDe
m_ensureMatLibTimer.callOnTimeout([this] {
if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()
&& model()->rewriterView()->errors().isEmpty()) {
- ensureMaterialLibraryNode();
+ DesignDocument *doc = QmlDesignerPlugin::instance()->currentDesignDocument();
+ if (doc && !doc->inFileComponentModelActive())
+ ensureMaterialLibraryNode();
if (m_qmlBackEnd && m_qmlBackEnd->contextObject())
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(materialLibraryNode().isValid());
m_ensureMatLibTimer.stop();
@@ -71,8 +64,6 @@ MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDe
m_typeUpdateTimer.setInterval(500);
connect(&m_typeUpdateTimer, &QTimer::timeout, this, &MaterialEditorView::updatePossibleTypes);
- m_stackedWidget->setStyleSheet(Theme::replaceCssColors(
- QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
m_stackedWidget->setMinimumWidth(250);
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
@@ -180,7 +171,7 @@ void MaterialEditorView::changeExpression(const QString &propertyName)
if (name.isNull() || locked() || noValidSelection())
return;
- executeInTransaction("MaterialEditorView::changeExpression", [this, name] {
+ executeInTransaction(__FUNCTION__, [this, name] {
PropertyName underscoreName(name);
underscoreName.replace('.', '_');
@@ -254,7 +245,7 @@ void MaterialEditorView::exportPropertyAsAlias(const QString &name)
if (name.isNull() || locked() || noValidSelection())
return;
- executeInTransaction("MaterialEditorView::exportPopertyAsAlias", [this, name] {
+ executeInTransaction(__FUNCTION__, [this, name] {
const QString id = m_selectedMaterial.validId();
QString upperCasePropertyName = name;
upperCasePropertyName.replace(0, 1, upperCasePropertyName.at(0).toUpper());
@@ -276,7 +267,7 @@ void MaterialEditorView::removeAliasExport(const QString &name)
if (name.isNull() || locked() || noValidSelection())
return;
- executeInTransaction("MaterialEditorView::removeAliasExport", [this, name] {
+ executeInTransaction(__FUNCTION__, [this, name] {
const QString id = m_selectedMaterial.validId();
const QList<BindingProperty> bindingProps = rootModelNode().bindingProperties();
@@ -299,7 +290,7 @@ void MaterialEditorView::currentTimelineChanged(const ModelNode &)
m_qmlBackEnd->contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(this));
}
-Internal::DynamicPropertiesModel *MaterialEditorView::dynamicPropertiesModel() const
+DynamicPropertiesModel *MaterialEditorView::dynamicPropertiesModel() const
{
return m_dynamicPropertiesModel;
}
@@ -389,7 +380,7 @@ void MaterialEditorView::applyMaterialToSelectedModels(const ModelNode &material
return QString();
};
- executeInTransaction("MaterialEditorView::applyMaterialToSelectedModels", [&] {
+ executeInTransaction(__FUNCTION__, [&] {
for (const ModelNode &node : std::as_const(m_selectedModels)) {
QmlObjectNode qmlObjNode(node);
if (add) {
@@ -422,14 +413,15 @@ void MaterialEditorView::handleToolBarAction(int action)
case MaterialEditorContextObject::AddNewMaterial: {
if (!model())
break;
- executeInTransaction("MaterialEditorView:handleToolBarAction", [&] {
+ executeInTransaction(__FUNCTION__, [&] {
ModelNode matLib = materialLibraryNode();
if (!matLib.isValid())
return;
- NodeMetaInfo metaInfo = model()->metaInfo("QtQuick3D.DefaultMaterial");
- ModelNode newMatNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
- metaInfo.minorVersion());
+ NodeMetaInfo metaInfo = model()->qtQuick3DPrincipledMaterialMetaInfo();
+ ModelNode newMatNode = createModelNode("QtQuick3D.PrincipledMaterial",
+ metaInfo.majorVersion(),
+ metaInfo.minorVersion());
renameMaterial(newMatNode, "New Material");
matLib.defaultNodeListProperty().reparentHere(newMatNode);
});
@@ -451,7 +443,6 @@ void MaterialEditorView::handleToolBarAction(int action)
void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue)
{
- Q_UNUSED(envAndValue);
if (envAndValue.isEmpty() || m_initializingPreviewData)
return;
@@ -514,7 +505,6 @@ void MaterialEditorView::handlePreviewEnvChanged(const QString &envAndValue)
void MaterialEditorView::handlePreviewModelChanged(const QString &modelStr)
{
- Q_UNUSED(modelStr);
if (modelStr.isEmpty() || m_initializingPreviewData)
return;
@@ -609,7 +599,7 @@ void MaterialEditorView::setupQmlBackend()
void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value)
{
m_locked = true;
- executeInTransaction("MaterialEditorView:commitVariantValueToModel", [&] {
+ executeInTransaction(__FUNCTION__, [&] {
QmlObjectNode(m_selectedMaterial).setVariantProperty(propertyName, value);
});
m_locked = false;
@@ -637,7 +627,7 @@ void MaterialEditorView::commitAuxValueToModel(const PropertyName &propertyName,
void MaterialEditorView::removePropertyFromModel(const PropertyName &propertyName)
{
m_locked = true;
- executeInTransaction("MaterialEditorView:removePropertyFromModel", [&] {
+ executeInTransaction(__FUNCTION__, [&] {
QmlObjectNode(m_selectedMaterial).removeProperty(propertyName);
});
m_locked = false;
@@ -692,6 +682,7 @@ 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()));
@@ -908,7 +899,8 @@ WidgetInfo MaterialEditorView::widgetInfo()
"MaterialEditor",
WidgetInfo::RightPane,
0,
- tr("Material Editor"));
+ tr("Material Editor"),
+ tr("Material Editor view"));
}
void MaterialEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
@@ -928,6 +920,7 @@ void MaterialEditorView::currentStateChanged(const ModelNode &node)
{
QmlModelState newQmlModelState(node);
Q_ASSERT(newQmlModelState.isValid());
+
resetView();
}
@@ -1001,7 +994,7 @@ void MaterialEditorView::renameMaterial(ModelNode &material, const QString &newN
if (objName.isValid() && objName.toString() == newName)
return;
- executeInTransaction("MaterialEditorView:renameMaterial", [&] {
+ executeInTransaction(__FUNCTION__, [&] {
material.setIdWithRefactoring(model()->generateIdFromName(newName, "material"));
VariantProperty objNameProp = material.variantProperty("objectName");
@@ -1034,7 +1027,8 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
// set name and id
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
- duplicateMatNode.variantProperty("objectName").setValue(newName);
+ VariantProperty objNameProp = duplicateMatNode.variantProperty("objectName");
+ objNameProp.setValue(newName);
duplicateMatNode.setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
// sync properties. Only the base state is duplicated.
@@ -1047,15 +1041,15 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
if (prop.isDynamic()) {
dynamicProps.append(prop);
} else {
- duplicateMatNode.variantProperty(prop.name())
- .setValue(prop.toVariantProperty().value());
+ VariantProperty variantProp = duplicateMatNode.variantProperty(prop.name());
+ variantProp.setValue(prop.toVariantProperty().value());
}
} else if (prop.isBindingProperty()) {
if (prop.isDynamic()) {
dynamicProps.append(prop);
} else {
- duplicateMatNode.bindingProperty(prop.name())
- .setExpression(prop.toBindingProperty().expression());
+ BindingProperty bindingProp = duplicateMatNode.bindingProperty(prop.name());
+ bindingProp.setExpression(prop.toBindingProperty().expression());
}
}
}
@@ -1070,13 +1064,13 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
executeInTransaction(__FUNCTION__, [&] {
for (const AbstractProperty &prop : std::as_const(dynamicProps)) {
if (prop.isVariantProperty()) {
- duplicateMatNode.variantProperty(prop.name())
- .setDynamicTypeNameAndValue(prop.dynamicTypeName(),
- prop.toVariantProperty().value());
+ VariantProperty variantProp = duplicateMatNode.variantProperty(prop.name());
+ variantProp.setDynamicTypeNameAndValue(prop.dynamicTypeName(),
+ prop.toVariantProperty().value());
} else if (prop.isBindingProperty()) {
- duplicateMatNode.bindingProperty(prop.name())
- .setDynamicTypeNameAndExpression(prop.dynamicTypeName(),
- prop.toBindingProperty().expression());
+ BindingProperty bindingProp = duplicateMatNode.bindingProperty(prop.name());
+ bindingProp.setDynamicTypeNameAndExpression(prop.dynamicTypeName(),
+ prop.toBindingProperty().expression());
}
}
});
@@ -1144,13 +1138,14 @@ void MaterialEditorView::dragStarted(QMimeData *mimeData)
{
if (mimeData->hasFormat(Constants::MIME_TYPE_ASSETS)) {
const QString assetPath = QString::fromUtf8(mimeData->data(Constants::MIME_TYPE_ASSETS)).split(',')[0];
- QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
+ Asset asset(assetPath);
- if (assetType != Constants::MIME_TYPE_ASSET_IMAGE) // currently only image assets have dnd-supported properties
+ if (!asset.isValidTextureSource()) // currently only image assets have dnd-supported properties
return;
highlightSupportedProperties();
- } else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)) {
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)
+ || mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
highlightSupportedProperties();
}
}
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index 77053c5db6..d47d030e57 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -3,28 +3,24 @@
#pragma once
-#include <abstractview.h>
-#include <itemlibraryinfo.h>
+#include "abstractview.h"
+#include "modelnode.h"
#include <QHash>
#include <QPointer>
#include <QTimer>
QT_BEGIN_NAMESPACE
+class QColorDialog;
class QShortcut;
class QStackedWidget;
-class QTimer;
-class QColorDialog;
QT_END_NAMESPACE
namespace QmlDesigner {
-class ModelNode;
-class MaterialEditorQmlBackend;
-
-namespace Internal {
class DynamicPropertiesModel;
-}
+class ItemLibraryInfo;
+class MaterialEditorQmlBackend;
class MaterialEditorView : public AbstractView
{
@@ -79,7 +75,7 @@ public:
void currentTimelineChanged(const ModelNode &node) override;
- Internal::DynamicPropertiesModel *dynamicPropertiesModel() const;
+ DynamicPropertiesModel *dynamicPropertiesModel() const;
static MaterialEditorView *instance();
@@ -133,7 +129,7 @@ private:
QPointer<QColorDialog> m_colorDialog;
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
- Internal::DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
+ DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
index 836e473f8a..35078859de 100644
--- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
+++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
@@ -22,6 +22,7 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
// -> SpriteParticle3D
// -> TextureInput
// -> SceneEnvironment
+ // -> Model
// Effect
// -> SceneEnvironment
// Shader, Command, Buffer
@@ -41,6 +42,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
// -> Model
// Effect
// -> Item
+ // BakedLightmap
+ // -> Model
if (insertInfo.isQtQuick3DTexture()) {
if (parentInfo.isQtQuick3DDefaultMaterial() || parentInfo.isQtQuick3DPrincipledMaterial()
@@ -63,6 +66,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
propertyList.append("skyBoxCubeMap");
else
propertyList.append("lightProbe");
+ } else if (parentInfo.isQtQuick3DModel()) {
+ propertyList.append("materials");
}
} else if (insertInfo.isQtQuick3DEffect()) {
if (parentInfo.isQtQuick3DSceneEnvironment())
@@ -98,6 +103,9 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
} else if (insertInfo.isEffectMaker()) {
if (parentInfo.isQtQuickItem())
propertyList.append("effect");
+ } else if (insertInfo.isQtQuick3DBakedLightmap()) {
+ if (parentInfo.isQtQuick3DModel())
+ propertyList.append("bakedLightmap");
}
}
diff --git a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
index 9f2f0854b3..e9fa8b4925 100644
--- a/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
+++ b/src/plugins/qmldesigner/components/navigator/nameitemdelegate.cpp
@@ -13,6 +13,7 @@
#include <metainfo.h>
#include <modelnodecontextmenu.h>
+#include <qmldesignerconstants.h>
#include <qmlobjectnode.h>
#include <theme.h>
@@ -216,17 +217,28 @@ void NameItemDelegate::paint(QPainter *painter,
if (widget && !widget->dragType().isEmpty()) {
QByteArray dragType = widget->dragType();
const NodeMetaInfo metaInfo = node.metaInfo();
- const NodeMetaInfo dragInfo = node.model()->metaInfo(dragType);
- ChooseFromPropertyListFilter *filter = new ChooseFromPropertyListFilter(dragInfo, metaInfo, true);
- if (!filter->propertyList.isEmpty()) {
+ bool validDrop = false;
+ if (dragType == Constants::MIME_TYPE_BUNDLE_TEXTURE) {
+ validDrop = metaInfo.isQtQuick3DModel();
+ } else if (dragType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
+ validDrop = metaInfo.isQtQuick3DModel() || metaInfo.isQtQuick3DTexture();
+ } else if (dragType == Constants::MIME_TYPE_ASSET_IMAGE) {
+ validDrop = metaInfo.isQtQuick3DModel() || metaInfo.isQtQuick3DTexture()
+ || metaInfo.isQtQuickImage() || metaInfo.isQtQuickBorderImage();
+ } else {
+ const NodeMetaInfo dragInfo = node.model()->metaInfo(dragType);
+ ChooseFromPropertyListFilter *filter = new ChooseFromPropertyListFilter(dragInfo, metaInfo, true);
+ validDrop = !filter->propertyList.isEmpty();
+ delete filter;
+ }
+ if (validDrop) {
painter->setOpacity(0.5);
painter->fillRect(styleOption.rect.adjusted(0, delegateMargin, 0, -delegateMargin),
Theme::getColor(Theme::Color::DSnavigatorDropIndicatorBackground));
painter->setOpacity(1.0);
painter->setPen(Theme::getColor(Theme::Color::DSnavigatorTextSelected));
}
- delete filter;
}
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
index 50dd9e499d..360c893c2d 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp
@@ -20,25 +20,22 @@ LineEdit::LineEdit(QWidget *parent)
clearButton = new QToolButton(this);
const QString fontName = "qtds_propertyIconFont.ttf";
- const int searchIconSize = 16;
- const int clearIconSize = 12;
- const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::DSiconColor));
-
- const QIcon searchIcon
- = Utils::StyleHelper::getIconFromIconFont(fontName,
- QmlDesigner::Theme::getIconUnicode(
- QmlDesigner::Theme::Icon::search),
- searchIconSize,
- searchIconSize,
- iconColor);
-
- const QIcon clearIcon
- = Utils::StyleHelper::getIconFromIconFont(fontName,
- QmlDesigner::Theme::getIconUnicode(
- QmlDesigner::Theme::Icon::closeCross),
- clearIconSize,
- clearIconSize,
- iconColor);
+ const int clearIconSize = 10;
+ const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::DStextColor));
+
+ const QIcon searchIcon = Utils::StyleHelper::getIconFromIconFont(
+ fontName,
+ QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::search_small),
+ 10,
+ 16,
+ iconColor);
+
+ const QIcon clearIcon = Utils::StyleHelper::getIconFromIconFont(
+ fontName,
+ QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::close_small),
+ clearIconSize,
+ clearIconSize,
+ iconColor);
addAction(searchIcon, QLineEdit::LeadingPosition);
@@ -46,9 +43,9 @@ LineEdit::LineEdit(QWidget *parent)
clearButton->setIconSize(QSize(clearIconSize, clearIconSize));
clearButton->setCursor(Qt::ArrowCursor);
clearButton->hide();
- clearButton->setStyleSheet(Theme::replaceCssColors(
- QString("QToolButton { border: none; padding: 0px; }"
- "QToolButton:hover { background: creatorTheme.DScontrolBackgroundHover; }")));
+ clearButton->setStyleSheet(
+ Theme::replaceCssColors(QString("QToolButton { border: none; padding: 0px; }"
+ "QToolButton:hover {}")));
setClearButtonEnabled(false);
@@ -56,8 +53,20 @@ LineEdit::LineEdit(QWidget *parent)
connect(this, &QLineEdit::textChanged, this, &LineEdit::updateClearButton);
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
- setStyleSheet(QString("QLineEdit { padding-right: %1px; } ")
- .arg(clearButton->sizeHint().width() + frameWidth + 8));
+ setStyleSheet(Theme::replaceCssColors(
+ QString("QLineEdit { padding-right: %1px; border-radius: 4;"
+ "color: creatorTheme.DStextColor;"
+ "border-color: creatorTheme.DScontrolOutline_topToolbarIdle;"
+ "background: creatorTheme.DStoolbarBackground; }"
+ "QLineEdit:hover {"
+ "color: creatorTheme.DStextColor;"
+ "border-color: creatorTheme.DScontrolOutline_topToolbarHover;"
+ "background: creatorTheme.DScontrolBackground_toolbarHover; }"
+ "QLineEdit:focus {"
+ "color: creatorTheme.DStextColor;"
+ "border-color: creatorTheme.DSinteraction;"
+ "background: creatorTheme.DStoolbarBackground; }")
+ .arg(clearButton->sizeHint().width() + frameWidth + 8)));
setFixedHeight(29);
}
@@ -81,7 +90,7 @@ NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent)
{
auto layout = new QBoxLayout(QBoxLayout::LeftToRight);
layout->setSpacing(0);
- layout->setContentsMargins(5, 5, 5, 3);
+ layout->setContentsMargins(10, 6, 10, 6);
setLayout(layout);
m_textField = new LineEdit;
@@ -91,6 +100,12 @@ NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent)
connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged);
layout->addWidget(m_textField);
+
+ setFixedHeight(Theme::toolbarSize());
+ QPalette pal = QPalette();
+ pal.setColor(QPalette::Window, Theme::getColor(Utils::Theme::DStoolbarBackground));
+ setAutoFillBackground(true);
+ setPalette(pal);
}
void NavigatorSearchWidget::clear()
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index ccf9bafd9a..6286829028 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -17,6 +17,7 @@
#include <nodeproperty.h>
#include <variantproperty.h>
#include <metainfo.h>
+#include <materialutils.h>
#include <abstractview.h>
#include <invalididexception.h>
#include <rewritingexception.h>
@@ -244,7 +245,7 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
if (role == Qt::CheckStateRole)
return m_view->isNodeInvisible(modelNode) ? Qt::Unchecked : Qt::Checked;
else if (role == Qt::ToolTipRole && !modelNodeForIndex(index).isRootNode())
- return tr("Toggles the visibility of this component in the 2D view.\n"
+ return tr("Toggles the visibility of this component in the 2D and 3D views.\n"
"This is independent of the visibility property.");
} else if (index.column() == ColumnType::Lock) { // lock
if (role == Qt::CheckStateRole)
@@ -451,7 +452,9 @@ QStringList NavigatorTreeModel::mimeTypes() const
{
const static QStringList types({Constants::MIME_TYPE_MODELNODE_LIST,
Constants::MIME_TYPE_ITEM_LIBRARY_INFO,
+ Constants::MIME_TYPE_TEXTURE,
Constants::MIME_TYPE_MATERIAL,
+ Constants::MIME_TYPE_BUNDLE_TEXTURE,
Constants::MIME_TYPE_BUNDLE_MATERIAL,
Constants::MIME_TYPE_ASSETS});
@@ -548,8 +551,15 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
if (dropModelIndex.model() == this) {
if (mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO)) {
handleItemLibraryItemDrop(mimeData, rowNumber, dropModelIndex);
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)) {
+ handleTextureDrop(mimeData, dropModelIndex);
} else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) {
- handleMaterialDrop(mimeData, rowNumber, dropModelIndex);
+ handleMaterialDrop(mimeData, dropModelIndex);
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
+ QByteArray filePath = mimeData->data(Constants::MIME_TYPE_BUNDLE_TEXTURE);
+ ModelNode targetNode(modelNodeForIndex(dropModelIndex));
+ if (targetNode.metaInfo().isQtQuick3DModel())
+ m_view->emitCustomNotification("apply_asset_to_model3D", {targetNode}, {filePath}); // To MaterialBrowserView
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
ModelNode targetNode(modelNodeForIndex(dropModelIndex));
if (targetNode.isValid())
@@ -627,7 +637,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
}
}
- return false; // don't let the view do drag&drop on its own
+ if (m_view && m_view->model())
+ m_view->model()->endDrag();
+
+ return true;
}
void NavigatorTreeModel::handleInternalDrop(const QMimeData *mimeData,
@@ -698,7 +711,7 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
newQmlObjectNode.destroy();
return;
}
- m_view->assignMaterialTo3dModel(targetNode, newModelNode);
+ MaterialUtils::assignMaterialTo3dModel(m_view, targetNode, newModelNode);
}
ChooseFromPropertyListDialog *dialog = ChooseFromPropertyListDialog::createIfNeeded(
@@ -739,9 +752,9 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
const QList<ModelNode> models = newModelNode.subModelNodesOfType(
m_view->model()->qtQuick3DModelMetaInfo());
QTC_ASSERT(models.size() == 1, return);
- m_view->assignMaterialTo3dModel(models.at(0));
+ MaterialUtils::assignMaterialTo3dModel(m_view, models.at(0));
} else if (newModelNode.metaInfo().isQtQuick3DModel()) {
- m_view->assignMaterialTo3dModel(newModelNode);
+ MaterialUtils::assignMaterialTo3dModel(m_view, newModelNode);
}
if (!validContainer) {
@@ -781,19 +794,42 @@ void NavigatorTreeModel::handleItemLibraryItemDrop(const QMimeData *mimeData, in
}
}
-void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex)
+void NavigatorTreeModel::handleTextureDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex)
{
QTC_ASSERT(m_view, return);
const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
- int targetRowNumber = rowNumber;
- NodeAbstractProperty targetProperty;
-
- bool foundTarget = findTargetProperty(rowModelIndex, this, &targetProperty, &targetRowNumber, "materials");
- if (!foundTarget)
+ QmlObjectNode targetNode = modelNodeForIndex(rowModelIndex);
+ if (!targetNode.isValid())
return;
- ModelNode targetNode = targetProperty.parentModelNode();
+ qint32 internalId = mimeData->data(Constants::MIME_TYPE_TEXTURE).toInt();
+ ModelNode texNode = m_view->modelNodeForInternalId(internalId);
+ QTC_ASSERT(texNode.isValid(), return);
+
+ if (targetNode.modelNode().metaInfo().isQtQuick3DModel()) {
+ m_view->emitCustomNotification("apply_texture_to_model3D", {targetNode, texNode});
+ } else {
+ auto *dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, texNode, Core::ICore::dialogParent());
+ if (dialog) {
+ bool soloProperty = dialog->isSoloProperty();
+ if (!soloProperty)
+ dialog->exec();
+
+ if (soloProperty || dialog->result() == QDialog::Accepted)
+ targetNode.setBindingProperty(dialog->selectedProperty(), texNode.id());
+
+ delete dialog;
+ }
+ }
+}
+
+void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex)
+{
+ QTC_ASSERT(m_view, return);
+
+ const QModelIndex rowModelIndex = dropModelIndex.sibling(dropModelIndex.row(), 0);
+ ModelNode targetNode = modelNodeForIndex(rowModelIndex);
if (!targetNode.metaInfo().isQtQuick3DModel())
return;
@@ -801,7 +837,7 @@ void NavigatorTreeModel::handleMaterialDrop(const QMimeData *mimeData, int rowNu
ModelNode matNode = m_view->modelNodeForInternalId(internalId);
m_view->executeInTransaction(__FUNCTION__, [&] {
- m_view->assignMaterialTo3dModel(targetNode, matNode);
+ MaterialUtils::assignMaterialTo3dModel(m_view, targetNode, matNode);
});
}
@@ -1088,6 +1124,16 @@ bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode,
// if dropping an image on an existing texture, set the source
targetNode.variantProperty("source").setValue(imagePath);
return true;
+ } else if (targetNode.metaInfo().isQtQuick3DModel()) {
+ QTimer::singleShot(0, this, [this, targetNode, imagePath]() {
+ if (m_view && targetNode.isValid()) {
+ // To MaterialBrowserView. Done async to avoid custom notification in transaction
+ m_view->emitCustomNotification(
+ "apply_asset_to_model3D", {targetNode},
+ {DocumentManager::currentFilePath().absolutePath().pathAppended(imagePath).cleanPath().toString()});
+ }
+ });
+ return true;
}
return false;
@@ -1187,13 +1233,17 @@ Qt::DropActions NavigatorTreeModel::supportedDragActions() const
bool NavigatorTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
+ QTC_ASSERT(m_view, return false);
ModelNode modelNode = modelNodeForIndex(index);
if (index.column() == ColumnType::Alias && role == Qt::CheckStateRole) {
- QTC_ASSERT(m_view, return false);
m_view->handleChangedExport(modelNode, value.toInt() != 0);
} else if (index.column() == ColumnType::Visibility && role == Qt::CheckStateRole) {
+ if (m_view->isPartOfMaterialLibrary(modelNode))
+ return false;
QmlVisualNode(modelNode).setVisibilityOverride(value.toInt() == 0);
} else if (index.column() == ColumnType::Lock && role == Qt::CheckStateRole) {
+ if (m_view->isPartOfMaterialLibrary(modelNode))
+ return false;
modelNode.setLocked(value.toInt() != 0);
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
index 25122a1dd1..ab45294b75 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h
@@ -93,7 +93,8 @@ private:
int targetIndex, bool executeInTransaction = true);
void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
- void handleMaterialDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex);
+ void handleTextureDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex);
+ void handleMaterialDrop(const QMimeData *mimeData, const QModelIndex &dropModelIndex);
ModelNode handleItemLibraryImageDrop(const QString &imagePath, NodeAbstractProperty targetProperty,
const QModelIndex &rowModelIndex, bool &outMoveNodesAfter);
ModelNode handleItemLibraryFontDrop(const QString &fontFamily, NodeAbstractProperty targetProperty,
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index 2d4cd76cc4..38e6b9ada7 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -117,7 +117,8 @@ WidgetInfo NavigatorView::widgetInfo()
QStringLiteral("Navigator"),
WidgetInfo::LeftPane,
0,
- tr("Navigator"));
+ tr("Navigator"),
+ tr("Navigator view"));
}
void NavigatorView::modelAttached(Model *model)
@@ -254,12 +255,21 @@ void NavigatorView::dragStarted(QMimeData *mimeData)
m_widget->setDragType(itemLibraryEntry.typeName());
m_widget->update();
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_TEXTURE)) {
+ qint32 internalId = mimeData->data(Constants::MIME_TYPE_TEXTURE).toInt();
+ ModelNode texNode = modelNodeForInternalId(internalId);
+
+ m_widget->setDragType(texNode.metaInfo().typeName());
+ m_widget->update();
} else if (mimeData->hasFormat(Constants::MIME_TYPE_MATERIAL)) {
qint32 internalId = mimeData->data(Constants::MIME_TYPE_MATERIAL).toInt();
ModelNode matNode = modelNodeForInternalId(internalId);
m_widget->setDragType(matNode.metaInfo().typeName());
m_widget->update();
+ } else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_TEXTURE)) {
+ m_widget->setDragType(Constants::MIME_TYPE_BUNDLE_TEXTURE);
+ m_widget->update();
} else if (mimeData->hasFormat(Constants::MIME_TYPE_BUNDLE_MATERIAL)) {
QByteArray data = mimeData->data(Constants::MIME_TYPE_BUNDLE_MATERIAL);
QDataStream stream(data);
@@ -278,6 +288,12 @@ void NavigatorView::dragStarted(QMimeData *mimeData)
// specific type
m_widget->setDragType(Storage::Info::EffectMaker);
m_widget->update();
+ } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) {
+ m_widget->setDragType(Constants::MIME_TYPE_ASSET_TEXTURE3D);
+ m_widget->update();
+ } else if (assetType == Constants::MIME_TYPE_ASSET_IMAGE) {
+ m_widget->setDragType(Constants::MIME_TYPE_ASSET_IMAGE);
+ m_widget->update();
}
}
}
@@ -466,7 +482,10 @@ const ProjectExplorer::FileNode *NavigatorView::fileNodeForModelNode(const Model
if (!currentProject)
return nullptr;
- return currentProject->nodeForFilePath(filePath)->asFileNode();
+ const auto fileNode = currentProject->nodeForFilePath(filePath);
+ QTC_ASSERT(fileNode, return nullptr);
+
+ return fileNode->asFileNode();
}
const ProjectExplorer::FileNode *NavigatorView::fileNodeForIndex(const QModelIndex &index) const
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
index 991f99a059..9c04438d71 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp
@@ -21,8 +21,9 @@
#include <QToolButton>
#include <utils/fileutils.h>
-#include <utils/utilsicons.h>
#include <utils/qtcassert.h>
+#include <utils/stylehelper.h>
+#include <utils/utilsicons.h>
namespace QmlDesigner {
@@ -44,15 +45,17 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
- QWidget *toolBar = createToolBar();
+ m_searchWidget = new NavigatorSearchWidget();
+ connect(m_searchWidget,
+ &NavigatorSearchWidget::textChanged,
+ this,
+ &NavigatorWidget::textFilterChanged);
+ layout->addWidget(m_searchWidget);
+ QWidget *toolBar = createToolBar();
toolBar->setParent(this);
layout->addWidget(toolBar);
- m_searchWidget = new NavigatorSearchWidget();
- connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged);
- layout->addWidget(m_searchWidget);
-
layout->addWidget(m_treeView);
setLayout(layout);
@@ -63,6 +66,8 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view)
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_NAVIGATORVIEW_TIME);
+
+ setFocusProxy(m_treeView);
}
void NavigatorWidget::setTreeModel(QAbstractItemModel *model)
@@ -75,73 +80,99 @@ QTreeView *NavigatorWidget::treeView() const
return m_treeView;
}
-QList<QToolButton *> NavigatorWidget::createToolBarWidgets()
+QList<QWidget *> NavigatorWidget::createToolBarWidgets()
{
- QList<QToolButton *> buttons;
+ QList<QWidget *> buttons;
+
+ auto empty = new QWidget();
+ empty->setFixedWidth(5);
+ empty->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ buttons.append(empty);
auto button = new QToolButton();
- button->setIcon(Icons::ARROW_LEFT.icon());
+ button->setIcon(Theme::iconFromName(Theme::Icon::moveUpwards_medium));
button->setToolTip(tr("Become last sibling of parent (CTRL + Left)."));
button->setShortcut(QKeySequence(Qt::Key_Left | Qt::CTRL));
connect(button, &QAbstractButton::clicked, this, &NavigatorWidget::leftButtonClicked);
buttons.append(button);
button = new QToolButton();
- button->setIcon(Icons::ARROW_RIGHT.icon());
+ button->setIcon(Theme::iconFromName(Theme::Icon::moveInwards_medium));
button->setToolTip(tr("Become child of last sibling (CTRL + Right)."));
button->setShortcut(QKeySequence(Qt::Key_Right | Qt::CTRL));
connect(button, &QAbstractButton::clicked, this, &NavigatorWidget::rightButtonClicked);
buttons.append(button);
button = new QToolButton();
- button->setIcon(Icons::ARROW_DOWN.icon());
+ button->setIcon(Theme::iconFromName(Theme::Icon::moveDown_medium));
button->setToolTip(tr("Move down (CTRL + Down)."));
button->setShortcut(QKeySequence(Qt::Key_Down | Qt::CTRL));
connect(button, &QAbstractButton::clicked, this, &NavigatorWidget::downButtonClicked);
buttons.append(button);
button = new QToolButton();
- button->setIcon(Icons::ARROW_UP.icon());
+ button->setIcon(Theme::iconFromName(Theme::Icon::moveUp_medium));
button->setToolTip(tr("Move up (CTRL + Up)."));
button->setShortcut(QKeySequence(Qt::Key_Up | Qt::CTRL));
connect(button, &QAbstractButton::clicked, this, &NavigatorWidget::upButtonClicked);
buttons.append(button);
- auto filter = new QToolButton;
- filter->setIcon(Utils::Icons::FILTER.icon());
- filter->setToolTip(tr("Filter Tree"));
- filter->setPopupMode(QToolButton::InstantPopup);
- filter->setProperty("noArrow", true);
- auto filterMenu = new QMenu(filter);
- auto filterAction = new QAction(tr("Show Only Visible Components"), nullptr);
- filterAction->setCheckable(true);
-
- bool filterFlag = QmlDesignerPlugin::settings().value(DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS).toBool();
- filterAction->setChecked(filterFlag);
+ empty = new QWidget();
+ empty->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ buttons.append(empty);
- connect(filterAction, &QAction::toggled, this, &NavigatorWidget::filterToggled);
- filterMenu->addAction(filterAction);
+ // Show Only Visible Components
+ auto visibleIcon = Theme::iconFromName(Theme::Icon::visible_medium);
+ auto invisibleIcon = Theme::iconFromName(Theme::Icon::invisible_medium,
+ Theme::getColor(Theme::Color::DStextSelectedTextColor));
+ QIcon vIcon;
+ vIcon.addPixmap(invisibleIcon.pixmap({16, 16}), QIcon::Normal, QIcon::On);
+ vIcon.addPixmap(visibleIcon.pixmap({16, 16}), QIcon::Normal, QIcon::Off);
- auto reverseAction = new QAction(tr("Reverse Component Order"), nullptr);
- reverseAction->setCheckable(true);
+ button = new QToolButton();
+ button->setIcon(vIcon);
+ button->setCheckable(true);
+ bool visibleFlag = QmlDesignerPlugin::settings()
+ .value(DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS)
+ .toBool();
+ button->setChecked(visibleFlag);
+ button->setToolTip(tr("Show Only Visible Components"));
+ connect(button, &QAbstractButton::toggled, this, &NavigatorWidget::filterToggled);
+ buttons.append(button);
- bool reverseFlag = QmlDesignerPlugin::settings().value(DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER).toBool();
- reverseAction->setChecked(reverseFlag);
+ // Reverse Component Order
+ auto reverseOffIcon = Theme::iconFromName(Theme::Icon::reverseOrder_medium);
+ auto reverseOnIcon = Theme::iconFromName(Theme::Icon::reverseOrder_medium,
+ Theme::getColor(Theme::Color::DStextSelectedTextColor));
+ QIcon rIcon;
+ rIcon.addPixmap(reverseOnIcon.pixmap({16, 16}), QIcon::Normal, QIcon::On);
+ rIcon.addPixmap(reverseOffIcon.pixmap({16, 16}), QIcon::Normal, QIcon::Off);
- connect(reverseAction, &QAction::toggled, this, &NavigatorWidget::reverseOrderToggled);
- filterMenu->addAction(reverseAction);
+ button = new QToolButton();
+ button->setIcon(rIcon);
+ button->setCheckable(true);
+ bool reverseFlag = QmlDesignerPlugin::settings()
+ .value(DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER)
+ .toBool();
+ button->setChecked(reverseFlag);
+ button->setToolTip(tr("Reverse Component Order"));
+ connect(button, &QAbstractButton::toggled, this, &NavigatorWidget::reverseOrderToggled);
+ buttons.append(button);
- filter->setMenu(filterMenu);
- buttons.append(filter);
+ empty = new QWidget();
+ empty->setFixedWidth(5);
+ empty->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ buttons.append(empty);
return buttons;
}
QToolBar *NavigatorWidget::createToolBar()
{
- const QList<QToolButton*> buttons = createToolBarWidgets();
+ const QList<QWidget *> buttons = createToolBarWidgets();
auto toolBar = new QToolBar();
+ toolBar->setFixedHeight(Theme::toolbarSize());
for (auto toolButton : buttons)
toolBar->addWidget(toolButton);
@@ -181,6 +212,7 @@ void NavigatorWidget::dragEnterEvent(QDragEnterEvent *dragEnterEvent)
void NavigatorWidget::dropEvent(QDropEvent *dropEvent)
{
+ dropEvent->accept();
const DesignerActionManager &actionManager = QmlDesignerPlugin::instance()
->viewManager().designerActionManager();
actionManager.handleExternalAssetsDrop(dropEvent->mimeData());
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h
index b788b06986..beec6e42b4 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.h
@@ -28,7 +28,7 @@ public:
void setTreeModel(QAbstractItemModel *model);
QTreeView *treeView() const;
- QList<QToolButton *> createToolBarWidgets();
+ QList<QWidget *> createToolBarWidgets();
QToolBar *createToolBar();
void contextHelp(const Core::IContext::HelpCallback &callback) const;
diff --git a/src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.cpp
new file mode 100644
index 0000000000..5ecf048ab1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "assetimageprovider.h"
+
+#include <asset.h>
+#include <imagecacheimageresponse.h>
+
+#include <projectexplorer/target.h>
+#include <utils/hdrimage.h>
+#include <utils/stylehelper.h>
+
+#include <QMetaObject>
+#include <QQuickImageResponse>
+
+namespace QmlDesigner {
+
+QQuickImageResponse *AssetImageProvider::requestImageResponse(const QString &id,
+ const QSize &requestedSize)
+{
+ if (id.endsWith(".mesh"))
+ return m_imageCacheProvider.requestImageResponse(id, {});
+
+ if (id.endsWith(".builtin"))
+ return m_imageCacheProvider.requestImageResponse("#" + id.split('.').first(), {});
+
+ if (id.endsWith(".ktx")) {
+ auto response = std::make_unique<ImageCacheImageResponse>(m_imageCacheProvider.defaultImage());
+
+ QMetaObject::invokeMethod(
+ response.get(),
+ [response = QPointer<ImageCacheImageResponse>(response.get()), requestedSize] {
+ QImage ktxImage;
+ ktxImage.load(Utils::StyleHelper::dpiSpecificImageFile(":/textureeditor/images/texture_ktx.png"));
+ if (ktxImage.isNull())
+ ktxImage = response->image();
+ if (requestedSize.isValid())
+ response->setImage(ktxImage.scaled(requestedSize, Qt::KeepAspectRatio));
+ else
+ response->setImage(ktxImage);
+ },
+ Qt::QueuedConnection);
+
+ return response.release();
+ }
+
+ return m_imageCacheProvider.requestImageResponse(id, requestedSize);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h b/src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.h
index 627750b508..450086d323 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/assetimageprovider.h
@@ -1,26 +1,26 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
-#include "imagecache/smallimagecacheprovider.h"
+#include "imagecache/midsizeimagecacheprovider.h"
#include <QQuickAsyncImageProvider>
namespace QmlDesigner {
-class PropertyEditorImageProvider : public QQuickAsyncImageProvider
+class AssetImageProvider : public QQuickAsyncImageProvider
{
public:
- PropertyEditorImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {})
- : m_smallImageCacheProvider(imageCache, defaultImage)
+ AssetImageProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {})
+ : m_imageCacheProvider(imageCache, defaultImage)
{}
QQuickImageResponse *requestImageResponse(const QString &id,
const QSize &requestedSize) override;
private:
- SmallImageCacheProvider m_smallImageCacheProvider;
+ MidSizeImageCacheProvider m_imageCacheProvider;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
index ee89eebffe..689753ff8b 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.cpp
@@ -25,6 +25,7 @@
#include "dynamicpropertiesproxymodel.h"
+#include "bindingproperty.h"
#include "propertyeditorvalue.h"
#include <dynamicpropertiesmodel.h>
@@ -40,7 +41,7 @@
#include <QScopeGuard>
-using namespace QmlDesigner;
+namespace QmlDesigner {
static const int propertyNameRole = Qt::UserRole + 1;
static const int propertyTypeRole = Qt::UserRole + 2;
@@ -52,7 +53,7 @@ DynamicPropertiesProxyModel::DynamicPropertiesProxyModel(QObject *parent)
{
}
-void DynamicPropertiesProxyModel::initModel(QmlDesigner::Internal::DynamicPropertiesModel *model)
+void DynamicPropertiesProxyModel::initModel(DynamicPropertiesModel *model)
{
m_model = model;
@@ -79,14 +80,14 @@ void DynamicPropertiesProxyModel::initModel(QmlDesigner::Internal::DynamicProper
int DynamicPropertiesProxyModel::rowCount(const QModelIndex &) const
{
- return m_model->rowCount();
+ return m_model ? m_model->rowCount() : 0;
}
QHash<int, QByteArray> DynamicPropertiesProxyModel::roleNames() const
{
- static QHash<int, QByteArray> roleNames{{propertyNameRole, "propertyName"},
- {propertyTypeRole, "propertyType"},
- {propertyValueRole, "propertyValue"},
+ static QHash<int, QByteArray> roleNames{{propertyNameRole, "propertyName"},
+ {propertyTypeRole, "propertyType"},
+ {propertyValueRole, "propertyValue"},
{propertyBindingRole, "propertyBinding"}};
return roleNames;
@@ -99,26 +100,30 @@ QVariant DynamicPropertiesProxyModel::data(const QModelIndex &index, int role) c
QTC_ASSERT(property.isValid(), return QVariant());
- if (role == propertyNameRole) {
+ if (role == propertyNameRole)
return property.name();
- } else if (propertyTypeRole) {
+
+ if (propertyTypeRole)
return property.dynamicTypeName();
- } else if (role == propertyValueRole) {
+
+ if (role == propertyValueRole) {
QmlObjectNode objectNode = property.parentQmlObjectNode();
return objectNode.modelValue(property.name());
- } else if (role == propertyBindingRole) {
- if (property.isBindingProperty()) {
- QmlObjectNode objectNode = property.parentQmlObjectNode();
- return objectNode.expression(property.name());
- }
- return QVariant();
}
+
+ if (role == propertyBindingRole) {
+ if (property.isBindingProperty())
+ return property.parentQmlObjectNode().expression(property.name());
+
+ return {};
+ }
+
qWarning() << Q_FUNC_INFO << "invalid role";
} else {
qWarning() << Q_FUNC_INFO << "invalid index";
}
- return QVariant();
+ return {};
}
void DynamicPropertiesProxyModel::registerDeclarativeType()
@@ -128,17 +133,16 @@ void DynamicPropertiesProxyModel::registerDeclarativeType()
qmlRegisterType<DynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "DynamicPropertiesModel");
}
-QmlDesigner::Internal::DynamicPropertiesModel *DynamicPropertiesProxyModel::dynamicPropertiesModel() const
+DynamicPropertiesModel *DynamicPropertiesProxyModel::dynamicPropertiesModel() const
{
return m_model;
}
QString DynamicPropertiesProxyModel::newPropertyName() const
{
- auto propertiesModel = dynamicPropertiesModel();
+ DynamicPropertiesModel *propsModel = dynamicPropertiesModel();
- return QString::fromUtf8(propertiesModel->unusedProperty(
- propertiesModel->singleSelectedNode()));
+ return QString::fromUtf8(propsModel->unusedProperty(propsModel->singleSelectedNode()));
}
void DynamicPropertiesProxyModel::createProperty(const QString &name, const QString &type)
@@ -158,23 +162,22 @@ void DynamicPropertiesProxyModel::createProperty(const QString &name, const QStr
return;
}
try {
- if (Internal::DynamicPropertiesModel::isValueType(typeName)) {
- QVariant value = Internal::DynamicPropertiesModel::defaultValueForType(typeName);
- modelNode.variantProperty(name.toUtf8())
- .setDynamicTypeNameAndValue(typeName, value);
+ if (DynamicPropertiesModel::isValueType(typeName)) {
+ QVariant value = DynamicPropertiesModel::defaultValueForType(typeName);
+ VariantProperty variantProp = modelNode.variantProperty(name.toUtf8());
+ variantProp.setDynamicTypeNameAndValue(typeName, value);
} else {
- QString expression = Internal::DynamicPropertiesModel::defaultExpressionForType(
- typeName);
+ QString expression = DynamicPropertiesModel::defaultExpressionForType(typeName);
- modelNode.bindingProperty(name.toUtf8())
- .setDynamicTypeNameAndExpression(typeName, expression);
+ BindingProperty bindingProp = modelNode.bindingProperty(name.toUtf8());
+ bindingProp.setDynamicTypeNameAndExpression(typeName, expression);
}
} catch (Exception &e) {
e.showException();
}
}
} else {
- qWarning() << " BindingModel::addBindingForCurrentNode not one node selected";
+ qWarning() << __FUNCTION__ << ": not one node selected";
}
}
@@ -191,7 +194,7 @@ DynamicPropertyRow::DynamicPropertyRow()
&PropertyEditorValue::expressionChanged,
this,
[this](const QString &name) {
- if (!name.isEmpty()) //If name is empty the notifer is only for QML
+ if (!name.isEmpty()) // If name is empty the notifer is only for QML
commitExpression(m_backendValue->expression());
else if (m_backendValue->expression().isEmpty())
resetValue();
@@ -263,8 +266,7 @@ void DynamicPropertyRow::remove()
PropertyEditorValue *DynamicPropertyRow::createProxyBackendValue()
{
-
- PropertyEditorValue *newValue = new PropertyEditorValue(this);
+ auto *newValue = new PropertyEditorValue(this);
m_proxyBackendValues.append(newValue);
return newValue;
@@ -281,7 +283,7 @@ void DynamicPropertyRow::setupBackendValue()
if (!m_model)
return;
- QmlDesigner::AbstractProperty property = m_model->dynamicPropertiesModel()->abstractPropertyForRow(m_row);
+ AbstractProperty property = m_model->dynamicPropertiesModel()->abstractPropertyForRow(m_row);
if (!property.isValid())
return;
@@ -324,15 +326,14 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
auto propertiesModel = m_model->dynamicPropertiesModel();
VariantProperty variantProperty = propertiesModel->variantPropertyForRow(m_row);
- if (!Internal::DynamicPropertiesModel::isValueType(variantProperty.dynamicTypeName()))
+ if (!DynamicPropertiesModel::isValueType(variantProperty.dynamicTypeName()))
return;
m_lock = true;
auto unlock = qScopeGuard([this] { m_lock = false; });
auto view = propertiesModel->view();
- RewriterTransaction transaction = view->beginRewriterTransaction(
- QByteArrayLiteral("DynamicPropertiesModel::commitValue"));
+ RewriterTransaction transaction = view->beginRewriterTransaction(__FUNCTION__);
try {
QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
if (view->currentState().isBaseState()
@@ -345,7 +346,7 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
if (objectNode.isValid() && objectNode.modelValue(name) != value)
objectNode.setVariantProperty(name, value);
}
- transaction.commit(); //committing in the try block
+ transaction.commit(); // committing in the try block
} catch (Exception &e) {
e.showException();
}
@@ -353,10 +354,7 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
void DynamicPropertyRow::commitExpression(const QString &expression)
{
- if (m_lock)
- return;
-
- if (m_row < 0)
+ if (m_lock || m_row < 0)
return;
auto propertiesModel = m_model->dynamicPropertiesModel();
@@ -367,7 +365,7 @@ void DynamicPropertyRow::commitExpression(const QString &expression)
const QVariant literal = BindingProperty::convertToLiteral(bindingProperty.dynamicTypeName(),
expression);
- if (literal.isValid()) { //If the string can be converted to a literal we set it as a literal/value
+ if (literal.isValid()) { // If the string can be converted to a literal we set it as a literal/value
commitValue(literal);
return;
}
@@ -376,8 +374,7 @@ void DynamicPropertyRow::commitExpression(const QString &expression)
auto unlock = qScopeGuard([this] { m_lock = false; });
auto view = propertiesModel->view();
- RewriterTransaction transaction = view->beginRewriterTransaction(
- QByteArrayLiteral("DynamicPropertyRow::commitExpression"));
+ RewriterTransaction transaction = view->beginRewriterTransaction(__FUNCTION__);
try {
QString theExpression = expression;
if (theExpression.isEmpty())
@@ -396,11 +393,10 @@ void DynamicPropertyRow::commitExpression(const QString &expression)
objectNode.setBindingProperty(name, theExpression);
}
- transaction.commit(); //committing in the try block
+ transaction.commit(); // committing in the try block
} catch (Exception &e) {
e.showException();
}
- return;
}
void DynamicPropertyRow::handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &)
@@ -411,10 +407,7 @@ void DynamicPropertyRow::handleDataChanged(const QModelIndex &topLeft, const QMo
void DynamicPropertyRow::resetValue()
{
- if (m_lock)
- return;
-
- if (m_row < 0)
+ if (m_lock || m_row < 0)
return;
auto propertiesModel = m_model->dynamicPropertiesModel();
@@ -424,20 +417,18 @@ void DynamicPropertyRow::resetValue()
TypeName typeName = property.dynamicTypeName();
if (view->currentState().isBaseState()) {
- if (Internal::DynamicPropertiesModel::isValueType(typeName)) {
- QVariant value = Internal::DynamicPropertiesModel::defaultValueForType(typeName);
+ if (DynamicPropertiesModel::isValueType(typeName)) {
+ QVariant value = DynamicPropertiesModel::defaultValueForType(typeName);
commitValue(value);
} else {
- QString expression = Internal::DynamicPropertiesModel::defaultExpressionForType(
- typeName);
+ QString expression = DynamicPropertiesModel::defaultExpressionForType(typeName);
commitExpression(expression);
}
} else {
m_lock = true;
auto unlock = qScopeGuard([this] { m_lock = false; });
- RewriterTransaction transaction = view->beginRewriterTransaction(
- QByteArrayLiteral("DynamicPropertyRow::resetValue"));
+ RewriterTransaction transaction = view->beginRewriterTransaction(__FUNCTION__);
try {
QmlObjectNode objectNode = property.parentQmlObjectNode();
QTC_CHECK(objectNode.isValid());
@@ -445,9 +436,11 @@ void DynamicPropertyRow::resetValue()
if (objectNode.isValid() && objectNode.propertyAffectedByCurrentState(name))
objectNode.removeProperty(name);
- transaction.commit(); //committing in the try block
+ transaction.commit(); // committing in the try block
} catch (Exception &e) {
e.showException();
}
}
}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.h b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.h
index 16a59d2cf2..ec16a466d4 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/dynamicpropertiesproxymodel.h
@@ -30,16 +30,13 @@
#include <abstractview.h>
#include <qmlitemnode.h>
-#include <enumeration.h>
#include <QAbstractListModel>
#include <QColor>
#include <QtQml>
namespace QmlDesigner {
-namespace Internal {
+
class DynamicPropertiesModel;
-}
-} // namespace QmlDesigner
class DynamicPropertiesProxyModel : public QAbstractListModel
{
@@ -55,16 +52,16 @@ public:
static void registerDeclarativeType();
- QmlDesigner::Internal::DynamicPropertiesModel *dynamicPropertiesModel() const;
+ DynamicPropertiesModel *dynamicPropertiesModel() const;
Q_INVOKABLE QString newPropertyName() const;
Q_INVOKABLE void createProperty(const QString &name, const QString &type);
protected:
- void initModel(QmlDesigner::Internal::DynamicPropertiesModel *model);
+ void initModel(DynamicPropertiesModel *model);
private:
- QmlDesigner::Internal::DynamicPropertiesModel *m_model = nullptr;
+ DynamicPropertiesModel *m_model = nullptr;
};
class DynamicPropertyRow : public QObject
@@ -72,7 +69,7 @@ class DynamicPropertyRow : public QObject
Q_OBJECT
Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
- Q_PROPERTY(PropertyEditorValue *backendValue READ backendValue NOTIFY rowChanged FINAL)
+ Q_PROPERTY(QmlDesigner::PropertyEditorValue *backendValue READ backendValue NOTIFY rowChanged FINAL)
Q_PROPERTY(DynamicPropertiesProxyModel *model READ model WRITE setModel NOTIFY modelChanged FINAL)
public:
@@ -85,10 +82,10 @@ public:
int row() const;
void setModel(DynamicPropertiesProxyModel *model);
DynamicPropertiesProxyModel *model() const;
- PropertyEditorValue *backendValue() const;
+ QmlDesigner::PropertyEditorValue *backendValue() const;
Q_INVOKABLE void remove();
- Q_INVOKABLE PropertyEditorValue *createProxyBackendValue();
+ Q_INVOKABLE QmlDesigner::PropertyEditorValue *createProxyBackendValue();
Q_INVOKABLE void clearProxyBackendValues();
signals:
@@ -103,10 +100,12 @@ private:
void resetValue();
int m_row = -1;
- PropertyEditorValue *m_backendValue = nullptr;
+ QmlDesigner::PropertyEditorValue *m_backendValue = nullptr;
DynamicPropertiesProxyModel *m_model = nullptr;
- QList<PropertyEditorValue *> m_proxyBackendValues;
+ QList<QmlDesigner::PropertyEditorValue *> m_proxyBackendValues;
bool m_lock = false;
};
-QML_DECLARE_TYPE(DynamicPropertyRow)
+} // namespace QmlDesigner
+
+QML_DECLARE_TYPE(QmlDesigner::DynamicPropertyRow)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp
index 02ffd84c93..aae0867c91 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp
@@ -51,7 +51,7 @@ void FileResourcesModel::setModelNodeBackend(const QVariant &modelNodeBackend)
QmlDesigner::DocumentManager::currentProjectDirPath().toFileInfo().absoluteFilePath());
}
- setupModel();
+ refreshModel();
emit modelNodeBackendChanged();
}
@@ -78,7 +78,7 @@ void FileResourcesModel::setFileName(const QUrl &fileName)
void FileResourcesModel::setPath(const QUrl &url)
{
m_path = url;
- setupModel();
+ refreshModel();
emit pathChanged(url);
}
@@ -99,7 +99,7 @@ void FileResourcesModel::setFilter(const QString &filter)
return;
m_filter = filter;
- setupModel();
+ refreshModel();
emit filterChanged(filter);
}
@@ -201,33 +201,30 @@ bool filterMetaIcons(const QString &fileName)
return true;
}
-void FileResourcesModel::setupModel()
-{
- m_dirPath = QDir(m_path.toLocalFile());
- refreshModel();
-}
-
void FileResourcesModel::refreshModel()
{
m_model.clear();
- QStringList filterList = m_filter.split(QLatin1Char(' '));
-
- QDirIterator it(m_dirPath.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories);
- while (it.hasNext()) {
- QString absolutePath = it.next();
- if (filterMetaIcons(absolutePath)) {
- QString relativeFilePath = m_docPath.relativeFilePath(absolutePath);
- m_model.append(
- FileResourcesItem(absolutePath,
- relativeFilePath,
- relativeFilePath.mid(relativeFilePath.lastIndexOf('/') + 1)));
+ if (m_path.isValid()) {
+ const QDir dirPath = QDir(m_path.toLocalFile());
+ const QStringList filterList = m_filter.split(QLatin1Char(' '));
+
+ QDirIterator it(dirPath.absolutePath(), filterList, QDir::Files, QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ const QString absolutePath = it.next();
+ if (filterMetaIcons(absolutePath)) {
+ const QString relativeFilePath = m_docPath.relativeFilePath(absolutePath);
+ m_model.append(
+ FileResourcesItem(absolutePath,
+ relativeFilePath,
+ relativeFilePath.mid(relativeFilePath.lastIndexOf('/') + 1)));
+ }
}
- }
- Utils::sort(m_model, [](const FileResourcesItem &i1, const FileResourcesItem &i2) {
- return i1.fileName().toLower() < i2.fileName().toLower();
- });
+ Utils::sort(m_model, [](const FileResourcesItem &i1, const FileResourcesItem &i2) {
+ return i1.fileName().toLower() < i2.fileName().toLower();
+ });
+ }
emit modelChanged();
}
diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h
index 3426c67579..4bca3f531a 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.h
@@ -67,7 +67,6 @@ public:
QString filter() const;
QList<FileResourcesItem> model() const;
- void setupModel();
void refreshModel();
Q_INVOKABLE void openFileDialog();
@@ -89,7 +88,6 @@ private:
private:
QUrl m_fileName;
QUrl m_path;
- QDir m_dirPath;
QDir m_docPath;
QString m_filter;
QString m_currentPath;
diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
index 7957948f25..d52e47c367 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
@@ -6,14 +6,28 @@
#include <abstractview.h>
#include <model.h>
#include <nodemetainfo.h>
+#include <qmlmodelnodeproxy.h>
+#include "variantproperty.h"
#include <QFileDialog>
#include <QDirIterator>
-#include <qmlmodelnodeproxy.h>
+#include <QMetaEnum>
+
+using namespace QmlDesigner;
+
+QHash<int, QByteArray> ItemFilterModel::m_roles;
-ItemFilterModel::ItemFilterModel(QObject *parent) :
- QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false), m_selectionOnly(false)
+ItemFilterModel::ItemFilterModel(QObject *parent)
+ : QAbstractListModel(parent)
+ , m_typeFilter("QtQuick.Item")
+ , m_selectionOnly(false)
{
+ if (m_roles.empty()) {
+ m_roles = QAbstractListModel::roleNames();
+ QMetaEnum roleEnum = QMetaEnum::fromType<Roles>();
+ for (int i = 0; i < roleEnum.keyCount(); i++)
+ m_roles.insert(roleEnum.value(i), roleEnum.key(i));
+ }
}
void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
@@ -22,7 +36,7 @@ void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
auto modelNodeBackendObject = modelNodeBackend.value<QObject*>();
const auto backendObjectCasted =
- qobject_cast<const QmlDesigner::QmlModelNodeProxy *>(modelNodeBackendObject);
+ qobject_cast<const QmlModelNodeProxy *>(modelNodeBackendObject);
if (backendObjectCasted)
m_modelNode = backendObjectCasted->qmlObjectNode().modelNode();
@@ -62,19 +76,79 @@ void ItemFilterModel::registerDeclarativeType()
qmlRegisterType<ItemFilterModel>("HelperWidgets",2,0,"ItemFilterModel");
}
+QModelIndex ItemFilterModel::index(int row, int column, const QModelIndex &parent) const
+{
+ return QAbstractListModel::index(row, column, parent);
+}
+
+int ItemFilterModel::rowCount(const QModelIndex &) const
+{
+ return m_modelInternalIds.size();
+}
+
+QVariant ItemFilterModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return {};
+
+ ModelNode node = modelNodeForRow(index.row());
+
+ QVariant value;
+ switch (role) {
+ case IdRole:
+ value = node.id();
+ break;
+ case NameRole:
+ value = node.variantProperty("objectName").value();
+ break;
+ case IdAndNameRole:
+ value = QString("%1 [%2]").arg(
+ node.variantProperty("objectName").value().toString()
+ ,node.id());
+ break;
+ default:
+ value = node.id();
+ break;
+ }
+
+ return value;
+}
+
+// TODO: Handle model data manipulation here.
+bool ItemFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ return QAbstractListModel::setData(index, value, role);
+}
+
+QHash<int, QByteArray> ItemFilterModel::roleNames() const
+{
+ return m_roles;
+}
+
QVariant ItemFilterModel::modelNodeBackend() const
{
- return QVariant();
+ return {};
}
+ModelNode ItemFilterModel::modelNodeForRow(const int &row) const
+{
+ if (row < 0 || row >= m_modelInternalIds.size())
+ return {};
+
+ AbstractView *view = m_modelNode.view();
+ if (!view || !view->model())
+ return {};
+
+ return view->modelNodeForInternalId(m_modelInternalIds.at(row));
+}
void ItemFilterModel::setupModel()
{
if (!m_modelNode.isValid() || !m_modelNode.view()->isAttached())
return;
- m_lock = true;
- m_model.clear();
+ beginResetModel();
+ m_modelInternalIds.clear();
const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes()
: m_modelNode.view()->allModelNodes();
@@ -82,15 +156,22 @@ void ItemFilterModel::setupModel()
auto base = m_modelNode.model()->metaInfo(m_typeFilter.toUtf8());
for (const QmlDesigner::ModelNode &node : nodes) {
if (node.hasId() && node.metaInfo().isBasedOn(base))
- m_model.append(node.id());
+ m_modelInternalIds.append(node.internalId());
}
- m_lock = false;
-
+ endResetModel();
emit itemModelChanged();
}
QStringList ItemFilterModel::itemModel() const
{
- return m_model;
+ AbstractView *view = m_modelNode.view();
+ if (!view || !view->model())
+ return {};
+
+ QStringList retval;
+ for (const auto &internalId : std::as_const(m_modelInternalIds))
+ retval << view->modelNodeForInternalId(internalId).id();
+
+ return retval;
}
diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
index 1b9ef1f18e..6876f1edff 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
@@ -6,12 +6,13 @@
#include <qmlitemnode.h>
#include <QDir>
+#include <QHash>
#include <QObject>
#include <QStringList>
#include <QUrl>
#include <QtQml>
-class ItemFilterModel : public QObject
+class ItemFilterModel : public QAbstractListModel
{
Q_OBJECT
@@ -21,6 +22,13 @@ class ItemFilterModel : public QObject
Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged)
public:
+ enum Roles {
+ IdRole = Qt::UserRole + 1,
+ NameRole,
+ IdAndNameRole
+ };
+ Q_ENUM(Roles)
+
explicit ItemFilterModel(QObject *parent = nullptr);
void setModelNodeBackend(const QVariant &modelNodeBackend);
@@ -33,6 +41,14 @@ public:
static void registerDeclarativeType();
+ // Make index accessible for Qml side since it's not accessible by default in QAbstractListModel
+ Q_INVOKABLE QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
+ Q_INVOKABLE virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ Q_INVOKABLE virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ Q_INVOKABLE virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+
+ virtual QHash<int,QByteArray> roleNames() const override;
+
signals:
void modelNodeBackendChanged();
void itemModelChanged();
@@ -40,13 +56,14 @@ signals:
private:
QVariant modelNodeBackend() const;
+ QmlDesigner::ModelNode modelNodeForRow(const int &row) const;
private:
QString m_typeFilter;
- bool m_lock;
- QStringList m_model;
+ QList<qint32> m_modelInternalIds;
QmlDesigner::ModelNode m_modelNode;
bool m_selectionOnly;
+ static QHash<int, QByteArray> m_roles;
};
QML_DECLARE_TYPE(ItemFilterModel)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
index 421db6c478..a8aebbfb07 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp
@@ -19,6 +19,7 @@
#include <QApplication>
#include <QCursor>
#include <QFontDatabase>
+#include <QLoggingCategory>
#include <QMessageBox>
#include <QQmlContext>
#include <QWindow>
@@ -68,7 +69,9 @@ QColor convertColorFromString(const QString &s)
namespace QmlDesigner {
-PropertyEditorContextObject::PropertyEditorContextObject(QObject *parent)
+static Q_LOGGING_CATEGORY(urlSpecifics, "qtc.propertyeditor.specifics", QtWarningMsg)
+
+ PropertyEditorContextObject::PropertyEditorContextObject(QObject *parent)
: QObject(parent)
, m_isBaseState(false)
, m_selectionChanged(false)
@@ -443,6 +446,8 @@ void PropertyEditorContextObject::setSpecificsUrl(const QUrl &newSpecificsUrl)
if (newSpecificsUrl == m_specificsUrl)
return;
+ qCInfo(urlSpecifics) << Q_FUNC_INFO << newSpecificsUrl;
+
m_specificsUrl = newSpecificsUrl;
emit specificsUrlChanged();
}
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp
deleted file mode 100644
index 6cb65a9562..0000000000
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "propertyeditorimageprovider.h"
-#include "asset.h"
-
-#include <projectexplorer/target.h>
-#include <utils/hdrimage.h>
-#include <utils/stylehelper.h>
-
-#include <QMetaObject>
-#include <QQuickImageResponse>
-
-namespace QmlDesigner {
-
-QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QString &id,
- const QSize &requestedSize)
-{
- Asset asset(id);
-
- if (asset.suffix() == "*.mesh")
- return m_smallImageCacheProvider.requestImageResponse(id, requestedSize);
-
- if (asset.suffix() == "*.builtin")
- return m_smallImageCacheProvider.requestImageResponse("#" + id.split('.').first(),
- requestedSize);
-
- auto response = std::make_unique<QmlDesigner::ImageResponse>(m_smallImageCacheProvider.defaultImage());
-
- QMetaObject::invokeMethod(
- response.get(),
- [response = QPointer<QmlDesigner::ImageResponse>(response.get()), asset, requestedSize] {
- if (asset.isImage()) {
- QImage image = QImage(Utils::StyleHelper::dpiSpecificImageFile(asset.id()));
- if (!image.isNull()) {
- response->setImage(image.scaled(requestedSize, Qt::KeepAspectRatio));
- return;
- }
- } else if (asset.isHdrFile()) {
- HdrImage hdr{asset.id()};
- if (!hdr.image().isNull()) {
- response->setImage(hdr.image().scaled(requestedSize, Qt::KeepAspectRatio));
- return;
- }
- }
- response->setImage(response->image().scaled(requestedSize, Qt::KeepAspectRatio));
- },
- Qt::QueuedConnection);
-
- return response.release();
-}
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
index 41cdb431b8..909530dbc3 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp
@@ -365,6 +365,13 @@ void PropertyEditorQmlBackend::setValue(const QmlObjectNode & , const PropertyNa
}
}
+void PropertyEditorQmlBackend::setExpression(const PropertyName &propName, const QString &exp)
+{
+ PropertyEditorValue *propertyValue = propertyValueForName(QString::fromUtf8(propName));
+ if (propertyValue)
+ propertyValue->setExpression(exp);
+}
+
QQmlContext *PropertyEditorQmlBackend::context() {
return m_view->rootContext();
}
@@ -373,7 +380,7 @@ PropertyEditorContextObject* PropertyEditorQmlBackend::contextObject() {
return m_contextObject.data();
}
-QWidget *PropertyEditorQmlBackend::widget() {
+QQuickWidget *PropertyEditorQmlBackend::widget() {
return m_view;
}
@@ -637,7 +644,7 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
if (!superType.hasProperty(propertyName) // TODO add property.isLocalProperty()
&& property.isWritable() && dotPropertyHeuristic(node, metaType, propertyName)) {
- QString typeName = QString::fromUtf8(property.propertyType().typeName());
+ QString typeName = QString::fromUtf8(property.propertyType().simplifiedTypeName());
if (typeName == "alias" && node.isValid())
typeName = QString::fromUtf8(node.instanceType(propertyName));
@@ -649,10 +656,19 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
} else {
if (propertyName.contains('.')) {
const PropertyName parentPropertyName = propertyName.split('.').first();
- const PropertyMetaInfo parentProperty = metaType.property(
- parentPropertyName);
+ const PropertyMetaInfo parentProperty = metaType.property(parentPropertyName);
+
+ auto vectorFound = std::find(separateSectionProperties.begin(),
+ separateSectionProperties.end(),
+ parentProperty);
+
+ auto propertyMapFound = propertyMap.find(parentProperty);
+
+ const bool exists = propertyMapFound != propertyMap.end()
+ || vectorFound != separateSectionProperties.end();
- propertyMap[parentProperty].push_back(property);
+ if (!exists)
+ propertyMap[parentProperty].push_back(property);
} else {
propertyMap[property];
}
@@ -681,7 +697,7 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
PropertyName underscoreProperty = propertyName;
underscoreProperty.replace('.', '_');
- TypeName typeName = property.propertyType().typeName();
+ TypeName typeName = property.propertyType().simplifiedTypeName();
// alias resolution only possible with instance
if (!useProjectStorage() && typeName == "alias" && node.isValid())
typeName = node.instanceType(propertyName);
@@ -757,7 +773,7 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &metaTyp
emptyTemplate = false;
for (auto &[property, properties] : propertyMap) {
// for (auto it = propertyMap.cbegin(); it != propertyMap.cend(); ++it) {
- TypeName parentTypeName = property.propertyType().typeName();
+ TypeName parentTypeName = property.propertyType().simplifiedTypeName();
// alias resolution only possible with instance
if (!useProjectStorage() && parentTypeName == "alias" && node.isValid())
parentTypeName = node.instanceType(property.name());
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
index 741eab394e..092d411dfa 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.h
@@ -35,10 +35,11 @@ public:
void setup(const QmlObjectNode &fxObjectNode, const QString &stateName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor);
void initialSetup(const TypeName &typeName, const QUrl &qmlSpecificsFile, PropertyEditorView *propertyEditor);
void setValue(const QmlObjectNode &fxObjectNode, const PropertyName &name, const QVariant &value);
+ void setExpression(const PropertyName &propName, const QString &exp);
QQmlContext *context();
PropertyEditorContextObject* contextObject();
- QWidget *widget();
+ QQuickWidget *widget();
void setSource(const QUrl& url);
Internal::QmlAnchorBindingProxy &backendAnchorBinding();
DesignerPropertyMap &backendValuesPropertyMap();
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h
index 90faa0f06d..a6fb43baf1 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditortransaction.h
@@ -4,6 +4,7 @@
#pragma once
#include "propertyeditorview.h"
+#include "rewritertransaction.h"
namespace QmlDesigner {
@@ -11,7 +12,7 @@ class PropertyEditorTransaction : public QObject
{
Q_OBJECT
public:
- PropertyEditorTransaction(QmlDesigner::PropertyEditorView *propertyEditor);
+ PropertyEditorTransaction(PropertyEditorView *propertyEditor);
Q_INVOKABLE void start();
Q_INVOKABLE void end();
@@ -22,8 +23,8 @@ protected:
void timerEvent(QTimerEvent *event) override;
private:
- QmlDesigner::PropertyEditorView *m_propertyEditor;
- QmlDesigner::RewriterTransaction m_rewriterTransaction;
+ PropertyEditorView *m_propertyEditor;
+ RewriterTransaction m_rewriterTransaction;
int m_timerId;
};
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
index 7a6147a209..6a9ce6164a 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp
@@ -5,14 +5,16 @@
#include "abstractview.h"
#include "bindingproperty.h"
+#include "createtexture.h"
#include "designermcumanager.h"
-#include "documentmanager.h"
-#include "nodelistproperty.h"
+#include "designmodewidget.h"
#include "nodemetainfo.h"
#include "nodeproperty.h"
#include "qmlitemnode.h"
#include "qmlobjectnode.h"
-#include "variantproperty.h"
+#include "qmldesignerplugin.h"
+
+#include <enumeration.h>
#include <utils/qtcassert.h>
@@ -20,12 +22,10 @@
#include <QScopedPointer>
#include <QUrl>
+namespace QmlDesigner {
+
PropertyEditorValue::PropertyEditorValue(QObject *parent)
: QObject(parent),
- m_isInSubState(false),
- m_isInModel(false),
- m_isBound(false),
- m_isValid(false),
m_complexNode(new PropertyEditorNodeWrapper(this))
{
}
@@ -33,16 +33,16 @@ PropertyEditorValue::PropertyEditorValue(QObject *parent)
QVariant PropertyEditorValue::value() const
{
QVariant returnValue = m_value;
- if (auto metaInfo = modelNode().metaInfo(); metaInfo.property(name()).propertyType().isUrl()) {
+ if (auto metaInfo = modelNode().metaInfo(); metaInfo.property(name()).propertyType().isUrl())
returnValue = returnValue.toUrl().toString();
- }
return returnValue;
}
static bool cleverDoubleCompare(const QVariant &value1, const QVariant &value2)
-{ //we ignore slight changes on doubles
- if ((value1.type() == QVariant::Double) && (value2.type() == QVariant::Double)) {
+{
+ if (value1.type() == QVariant::Double && value2.type() == QVariant::Double) {
+ // ignore slight changes on doubles
if (qFuzzyCompare(value1.toDouble(), value2.toDouble()))
return true;
}
@@ -51,31 +51,27 @@ static bool cleverDoubleCompare(const QVariant &value1, const QVariant &value2)
static bool cleverColorCompare(const QVariant &value1, const QVariant &value2)
{
- if ((value1.type() == QVariant::Color) && (value2.type() == QVariant::Color)) {
+ if (value1.type() == QVariant::Color && value2.type() == QVariant::Color) {
QColor c1 = value1.value<QColor>();
QColor c2 = value2.value<QColor>();
- QString a = c1.name();
- QString b = c2.name();
- if (a != b)
- return false;
- return (c1.alpha() == c2.alpha());
+ return c1.name() == c2.name() && c1.alpha() == c2.alpha();
}
- if ((value1.type() == QVariant::String) && (value2.type() == QVariant::Color))
+
+ if (value1.type() == QVariant::String && value2.type() == QVariant::Color)
return cleverColorCompare(QVariant(QColor(value1.toString())), value2);
- if ((value1.type() == QVariant::Color) && (value2.type() == QVariant::String))
+
+ if (value1.type() == QVariant::Color && value2.type() == QVariant::String)
return cleverColorCompare(value1, QVariant(QColor(value2.toString())));
+
return false;
}
-
-/* "red" is the same color as "#ff0000"
- To simplify editing we convert all explicit color names in the hash format */
-static void fixAmbigousColorNames(const QmlDesigner::ModelNode &modelNode,
- const QmlDesigner::PropertyName &name,
- QVariant *value)
+// "red" is the same color as "#ff0000"
+// To simplify editing we convert all explicit color names in the hash format
+static void fixAmbigousColorNames(const ModelNode &modelNode, const PropertyName &name, QVariant *value)
{
if (auto metaInfo = modelNode.metaInfo(); metaInfo.property(name).propertyType().isColor()) {
- if ((value->type() == QVariant::Color)) {
+ if (value->type() == QVariant::Color) {
QColor color = value->value<QColor>();
int alpha = color.alpha();
color = QColor(color.name());
@@ -87,7 +83,7 @@ static void fixAmbigousColorNames(const QmlDesigner::ModelNode &modelNode,
}
}
-static void fixUrl(const QmlDesigner::ModelNode &modelNode, const QmlDesigner::PropertyName &name, QVariant *value)
+static void fixUrl(const ModelNode &modelNode, const PropertyName &name, QVariant *value)
{
if (auto metaInfo = modelNode.metaInfo(); metaInfo.property(name).propertyType().isUrl()) {
if (!value->isValid())
@@ -95,28 +91,24 @@ static void fixUrl(const QmlDesigner::ModelNode &modelNode, const QmlDesigner::P
}
}
-static bool compareVariants(const QVariant &value1, const QVariant &value2)
/* The comparison of variants is not symmetric because of implicit conversion.
* QVariant(string) == QVariant(QColor) does for example ignore the alpha channel,
* because the color is converted to a string ignoring the alpha channel.
* By comparing the variants in both directions we gain a symmetric comparison.
*/
+static bool compareVariants(const QVariant &value1, const QVariant &value2)
{
- return (value1 == value2)
- && (value2 == value1);
+ return value1 == value2 && value2 == value1;
}
void PropertyEditorValue::setValueWithEmit(const QVariant &value)
{
- if (!compareVariants(value, m_value ) || isBound()) {
+ if (!compareVariants(value, m_value) || isBound()) {
QVariant newValue = value;
- if (auto metaInfo = modelNode().metaInfo(); metaInfo.property(name()).propertyType().isUrl()) {
+ if (auto metaInfo = modelNode().metaInfo(); metaInfo.property(name()).propertyType().isUrl())
newValue = QUrl(newValue.toString());
- }
- if (cleverDoubleCompare(newValue, m_value))
- return;
- if (cleverColorCompare(newValue, m_value))
+ if (cleverDoubleCompare(newValue, m_value) || cleverColorCompare(newValue, m_value))
return;
setValue(newValue);
@@ -133,9 +125,7 @@ void PropertyEditorValue::setValue(const QVariant &value)
{
const bool colorsEqual = cleverColorCompare(value, m_value);
- if (!compareVariants(m_value, value) &&
- !cleverDoubleCompare(value, m_value) &&
- !colorsEqual)
+ if (!compareVariants(m_value, value) && !cleverDoubleCompare(value, m_value) && !colorsEqual)
m_value = value;
fixAmbigousColorNames(modelNode(), name(), &m_value);
@@ -150,7 +140,7 @@ void PropertyEditorValue::setValue(const QVariant &value)
QString PropertyEditorValue::enumeration() const
{
- return m_value.value<QmlDesigner::Enumeration>().nameToString();
+ return m_value.value<Enumeration>().nameToString();
}
QString PropertyEditorValue::expression() const
@@ -160,10 +150,10 @@ QString PropertyEditorValue::expression() const
void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
{
- if ( m_expression != 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()); // Note that we set the name in this case
}
}
@@ -182,13 +172,14 @@ QString PropertyEditorValue::valueToString() const
bool PropertyEditorValue::isInSubState() const
{
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
- return objectNode.isValid() && objectNode.currentState().isValid() && objectNode.propertyAffectedByCurrentState(name());
+ const QmlObjectNode objectNode(modelNode());
+ return objectNode.isValid() && objectNode.currentState().isValid()
+ && objectNode.propertyAffectedByCurrentState(name());
}
bool PropertyEditorValue::isBound() const
{
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
+ const QmlObjectNode objectNode(modelNode());
return objectNode.isValid() && objectNode.hasBindingProperty(name());
}
@@ -197,7 +188,7 @@ bool PropertyEditorValue::isInModel() const
return modelNode().hasProperty(name());
}
-QmlDesigner::PropertyName PropertyEditorValue::name() const
+PropertyName PropertyEditorValue::name() const
{
return m_name;
}
@@ -207,12 +198,11 @@ QString PropertyEditorValue::nameAsQString() const
return QString::fromUtf8(m_name);
}
-void PropertyEditorValue::setName(const QmlDesigner::PropertyName &name)
+void PropertyEditorValue::setName(const PropertyName &name)
{
m_name = name;
}
-
bool PropertyEditorValue::isValid() const
{
return m_isValid;
@@ -229,16 +219,15 @@ bool PropertyEditorValue::isTranslated() const
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).propertyType().isString()) {
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
+ const QmlObjectNode objectNode(modelNode());
if (objectNode.hasBindingProperty(name())) {
const QRegularExpression rx(
QRegularExpression::anchoredPattern("qsTr(|Id|anslate)\\(\".*\"\\)"));
//qsTr()
- if (objectNode.propertyAffectedByCurrentState(name())) {
- return expression().contains(rx);
- } else {
+ if (objectNode.propertyAffectedByCurrentState(name()))
+ return m_expression.contains(rx);
+ else
return modelNode().bindingProperty(name()).expression().contains(rx);
- }
}
}
}
@@ -258,9 +247,7 @@ void PropertyEditorValue::setHasActiveDrag(bool val)
}
}
-static bool isAllowedSubclassType(const QString &type,
- const QmlDesigner::NodeMetaInfo &metaInfo,
- QmlDesigner::Model *model)
+static bool isAllowedSubclassType(const QString &type, const NodeMetaInfo &metaInfo, Model *model)
{
if (!metaInfo.isValid())
return false;
@@ -275,7 +262,7 @@ bool PropertyEditorValue::isAvailable() const
if (!m_modelNode.isValid())
return true;
- const QmlDesigner::DesignerMcuManager &mcuManager = QmlDesigner::DesignerMcuManager::instance();
+ const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
if (mcuManager.isMCUProject()) {
const QSet<QString> nonMcuProperties = mcuManager.bannedProperties();
@@ -293,11 +280,11 @@ bool PropertyEditorValue::isAvailable() const
const auto itemTypes = mcuAllowedItemProperties.keys();
for (const auto &itemType : itemTypes) {
if (isAllowedSubclassType(itemType, m_modelNode.metaInfo(), m_modelNode.model())) {
- const QmlDesigner::DesignerMcuManager::ItemProperties allowedItemProps =
+ const DesignerMcuManager::ItemProperties allowedItemProps =
mcuAllowedItemProperties.value(itemType);
if (allowedItemProps.properties.contains(pureNameStr)) {
- if (QmlDesigner::QmlItemNode::isValidQmlItemNode(m_modelNode)) {
- const bool itemHasChildren = QmlDesigner::QmlItemNode(m_modelNode).hasChildren();
+ if (QmlItemNode::isValidQmlItemNode(m_modelNode)) {
+ const bool itemHasChildren = QmlItemNode(m_modelNode).hasChildren();
if (itemHasChildren)
return allowedItemProps.allowChildren;
@@ -308,26 +295,24 @@ bool PropertyEditorValue::isAvailable() const
}
}
- //banned properties:
- //with prefixes:
+ // banned properties, with prefixes:
if (mcuBannedComplexProperties.value(pureNameStr).contains(endingStr))
return false;
- //general group:
+ // general group:
if (nonMcuProperties.contains(pureNameStr))
return false;
-
}
return true;
}
-QmlDesigner::ModelNode PropertyEditorValue::modelNode() const
+ModelNode PropertyEditorValue::modelNode() const
{
return m_modelNode;
}
-void PropertyEditorValue::setModelNode(const QmlDesigner::ModelNode &modelNode)
+void PropertyEditorValue::setModelNode(const ModelNode &modelNode)
{
if (modelNode != m_modelNode) {
m_modelNode = modelNode;
@@ -336,14 +321,14 @@ void PropertyEditorValue::setModelNode(const QmlDesigner::ModelNode &modelNode)
}
}
-PropertyEditorNodeWrapper* PropertyEditorValue::complexNode()
+PropertyEditorNodeWrapper *PropertyEditorValue::complexNode()
{
return m_complexNode;
}
void PropertyEditorValue::resetValue()
{
- if (m_value.isValid() || isBound()) {
+ if (m_value.isValid() || !m_expression.isEmpty() || isBound()) {
m_value = QVariant();
m_isBound = false;
m_expression = QString();
@@ -354,7 +339,7 @@ void PropertyEditorValue::resetValue()
void PropertyEditorValue::setEnumeration(const QString &scope, const QString &name)
{
- QmlDesigner::Enumeration newEnumeration(scope, name);
+ Enumeration newEnumeration(scope, name);
setValueWithEmit(QVariant::fromValue(newEnumeration));
}
@@ -377,19 +362,18 @@ bool PropertyEditorValue::hasPropertyAlias() const
QString id = modelNode().id();
- for (const QmlDesigner::BindingProperty &property : modelNode().view()->rootModelNode().bindingProperties())
- if (property.expression() == (id + "." + nameAsQString()))
+ const QList<BindingProperty> bindingProps = modelNode().view()->rootModelNode().bindingProperties();
+ for (const BindingProperty &property : bindingProps) {
+ if (property.expression() == (id + '.' + nameAsQString()))
return true;
+ }
return false;
}
bool PropertyEditorValue::isAttachedProperty() const
{
- if (nameAsQString().isEmpty())
- return false;
-
- return nameAsQString().at(0).isUpper();
+ return !nameAsQString().isEmpty() && nameAsQString().at(0).isUpper();
}
void PropertyEditorValue::removeAliasExport()
@@ -403,7 +387,7 @@ QString PropertyEditorValue::getTranslationContext() const
if (auto metaInfo = modelNode().metaInfo();
metaInfo.isValid() && metaInfo.hasProperty(name())
&& metaInfo.property(name()).propertyType().isString()) {
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
+ const QmlObjectNode objectNode(modelNode());
if (objectNode.hasBindingProperty(name())) {
const QRegularExpression rx(QRegularExpression::anchoredPattern(
"qsTranslate\\(\"(.*)\"\\s*,\\s*\".*\"\\s*\\)"));
@@ -419,19 +403,19 @@ QString PropertyEditorValue::getTranslationContext() const
bool PropertyEditorValue::isIdList() const
{
if (modelNode().isValid() && modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name())) {
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
+ const QmlObjectNode objectNode(modelNode());
if (objectNode.hasBindingProperty(name())) {
static const QRegularExpression rx(QRegularExpression::anchoredPattern(
"^[a-z_]\\w*|^[A-Z]\\w*\\.{1}([a-z_]\\w*\\.?)+"));
- const QString exp = objectNode.propertyAffectedByCurrentState(name()) ? expression() : modelNode().bindingProperty(name()).expression();
- for (const auto &str : generateStringList(exp))
- {
- if (!str.contains(rx))
+ const QString exp = objectNode.propertyAffectedByCurrentState(name())
+ ? expression() : modelNode().bindingProperty(name()).expression();
+ const QStringList idList = generateStringList(exp);
+ for (const auto &id : idList) {
+ if (!id.contains(rx))
return false;
}
return true;
}
- return false;
}
return false;
}
@@ -443,8 +427,8 @@ QStringList PropertyEditorValue::getExpressionAsList() const
bool PropertyEditorValue::idListAdd(const QString &value)
{
- const QmlDesigner::QmlObjectNode objectNode(modelNode());
- if (!isIdList() && (objectNode.isValid() && objectNode.hasProperty(name())))
+ const QmlObjectNode objectNode(modelNode());
+ if (!isIdList() && objectNode.isValid() && objectNode.hasProperty(name()))
return false;
static const QRegularExpression rx(QRegularExpression::anchoredPattern(
@@ -467,8 +451,12 @@ bool PropertyEditorValue::idListRemove(int idx)
if (idx < 0 || idx >= stringList.size())
return false;
- stringList.removeAt(idx);
- setExpressionWithEmit(generateString(stringList));
+ if (stringList.size() == 1) {
+ resetValue();
+ } else {
+ stringList.removeAt(idx);
+ setExpressionWithEmit(generateString(stringList));
+ }
return true;
}
@@ -498,30 +486,11 @@ void PropertyEditorValue::commitDrop(const QString &dropData)
if (m_modelNode.metaInfo().isQtQuick3DMaterial()
&& m_modelNode.metaInfo().property(m_name).propertyType().isQtQuick3DTexture()) {
m_modelNode.view()->executeInTransaction(__FUNCTION__, [&] {
- QmlDesigner::ModelNode texture = m_modelNode.view()->modelNodeForInternalId(dropData.toInt());
+ ModelNode texture = m_modelNode.view()->modelNodeForInternalId(dropData.toInt());
if (!texture || !texture.metaInfo().isQtQuick3DTexture()) {
- Utils::FilePath imagePath = Utils::FilePath::fromString(dropData);
- Utils::FilePath currFilePath = QmlDesigner::DocumentManager::currentFilePath();
- QString sourceVal = imagePath.relativePathFrom(currFilePath).toString();
- texture = m_modelNode.view()->getTextureDefaultInstance(sourceVal);
-
- if (!texture.isValid()) {
- // create a texture node
- QmlDesigner::NodeMetaInfo metaInfo = m_modelNode.view()->model()->metaInfo("QtQuick3D.Texture");
- texture = m_modelNode.view()->createModelNode("QtQuick3D.Texture", metaInfo.majorVersion(),
- metaInfo.minorVersion());
- texture.validId();
- m_modelNode.view()->materialLibraryNode().defaultNodeListProperty().reparentHere(texture);
- }
-
- // set texture source
- QmlDesigner::VariantProperty srcProp = texture.variantProperty("source");
- srcProp.setValue(sourceVal);
-
- QTimer::singleShot(0, this, [this, texture]() {
- if (m_modelNode.isValid() && texture.isValid() && m_modelNode.view())
- m_modelNode.view()->emitCustomNotification("selected_texture_changed", {texture});
- });
+ auto texCreator = new CreateTexture(m_modelNode.view());
+ texture = texCreator->execute(dropData, AddTextureMode::Texture);
+ texCreator->deleteLater();
}
// assign the texture to the property
@@ -532,6 +501,12 @@ void PropertyEditorValue::commitDrop(const QString &dropData)
m_modelNode.view()->model()->endDrag();
}
+void PropertyEditorValue::openMaterialEditor(int idx)
+{
+ QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialEditor", true);
+ m_modelNode.view()->emitCustomNotification("select_material", {}, {idx});
+}
+
QStringList PropertyEditorValue::generateStringList(const QString &string) const
{
QString copy = string;
@@ -556,40 +531,40 @@ QString PropertyEditorValue::generateString(const QStringList &stringList) const
void PropertyEditorValue::registerDeclarativeTypes()
{
- qmlRegisterType<PropertyEditorValue>("HelperWidgets",2,0,"PropertyEditorValue");
- qmlRegisterType<PropertyEditorNodeWrapper>("HelperWidgets",2,0,"PropertyEditorNodeWrapper");
- qmlRegisterType<QQmlPropertyMap>("HelperWidgets",2,0,"QQmlPropertyMap");
+ qmlRegisterType<PropertyEditorValue>("HelperWidgets", 2, 0, "PropertyEditorValue");
+ qmlRegisterType<PropertyEditorNodeWrapper>("HelperWidgets", 2, 0, "PropertyEditorNodeWrapper");
+ qmlRegisterType<QQmlPropertyMap>("HelperWidgets", 2, 0, "QQmlPropertyMap");
}
-PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(PropertyEditorValue* parent) : QObject(parent), m_valuesPropertyMap(this)
+PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(PropertyEditorValue *parent)
+ : QObject(parent),
+ m_valuesPropertyMap(this)
{
m_editorValue = parent;
connect(m_editorValue, &PropertyEditorValue::modelNodeChanged, this, &PropertyEditorNodeWrapper::update);
}
-PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(QObject *parent) : QObject(parent), m_editorValue(nullptr)
+PropertyEditorNodeWrapper::PropertyEditorNodeWrapper(QObject *parent)
+ : QObject(parent)
{
}
-bool PropertyEditorNodeWrapper::exists()
+bool PropertyEditorNodeWrapper::exists() const
{
- if (!(m_editorValue && m_editorValue->modelNode().isValid()))
- return false;
-
- return m_modelNode.isValid();
+ return m_editorValue && m_editorValue->modelNode().isValid() && m_modelNode.isValid();
}
-QString PropertyEditorNodeWrapper::type()
+QString PropertyEditorNodeWrapper::type() const
{
return m_modelNode.simplifiedTypeName();
}
-QmlDesigner::ModelNode PropertyEditorNodeWrapper::parentModelNode() const
+ModelNode PropertyEditorNodeWrapper::parentModelNode() const
{
return m_editorValue->modelNode();
}
-QmlDesigner::PropertyName PropertyEditorNodeWrapper::propertyName() const
+PropertyName PropertyEditorNodeWrapper::propertyName() const
{
return m_editorValue->name();
}
@@ -601,7 +576,7 @@ QQmlPropertyMap *PropertyEditorNodeWrapper::properties()
void PropertyEditorNodeWrapper::add(const QString &type)
{
- QmlDesigner::TypeName propertyType = type.toUtf8();
+ TypeName propertyType = type.toUtf8();
if ((m_editorValue && m_editorValue->modelNode().isValid())) {
if (propertyType.isEmpty()) {
@@ -611,7 +586,7 @@ void PropertyEditorNodeWrapper::add(const QString &type)
.propertyType()
.typeName();
}
- while (propertyType.contains('*')) //strip star
+ while (propertyType.contains('*')) // strip star
propertyType.chop(1);
m_modelNode = m_editorValue->modelNode().view()->createModelNode(propertyType, 4, 7);
m_editorValue->modelNode().nodeAbstractProperty(m_editorValue->name()).reparentHere(m_modelNode);
@@ -626,12 +601,12 @@ void PropertyEditorNodeWrapper::add(const QString &type)
void PropertyEditorNodeWrapper::remove()
{
if ((m_editorValue && m_editorValue->modelNode().isValid())) {
- QmlDesigner::QmlObjectNode(m_modelNode).destroy();
+ QmlObjectNode(m_modelNode).destroy();
m_editorValue->modelNode().removeProperty(m_editorValue->name());
} else {
qWarning("PropertyEditorNodeWrapper::remove failed - node invalid");
}
- m_modelNode = QmlDesigner::ModelNode();
+ m_modelNode = ModelNode();
const QStringList propertyNames = m_valuesPropertyMap.keys();
for (const QString &propertyName : propertyNames)
@@ -643,13 +618,14 @@ void PropertyEditorNodeWrapper::remove()
void PropertyEditorNodeWrapper::changeValue(const QString &propertyName)
{
- const QmlDesigner::PropertyName name = propertyName.toUtf8();
+ const PropertyName name = propertyName.toUtf8();
if (name.isNull())
return;
+
if (m_modelNode.isValid()) {
- QScopedPointer<QmlDesigner::QmlObjectNode> qmlObjectNode{
- QmlDesigner::QmlObjectNode::getQmlObjectNodeOfCorrectType(m_modelNode)};
+ QScopedPointer<QmlObjectNode> qmlObjectNode{
+ QmlObjectNode::getQmlObjectNodeOfCorrectType(m_modelNode)};
auto valueObject = qvariant_cast<PropertyEditorValue *>(m_valuesPropertyMap.value(QString::fromLatin1(name)));
@@ -664,14 +640,16 @@ void PropertyEditorNodeWrapper::setup()
{
Q_ASSERT(m_editorValue);
Q_ASSERT(m_editorValue->modelNode().isValid());
- if ((m_editorValue->modelNode().isValid() && m_modelNode.isValid())) {
+
+ if (m_editorValue->modelNode().isValid() && m_modelNode.isValid()) {
const QStringList propertyNames = m_valuesPropertyMap.keys();
for (const QString &propertyName : propertyNames)
m_valuesPropertyMap.clear(propertyName);
qDeleteAll(m_valuesPropertyMap.children());
- if (QmlDesigner::QmlObjectNode qmlObjectNode = m_modelNode) {
- for (const auto &property : m_modelNode.metaInfo().properties()) {
+ if (QmlObjectNode qmlObjectNode = m_modelNode) {
+ const PropertyMetaInfos props = m_modelNode.metaInfo().properties();
+ for (const auto &property : props) {
const auto &propertyName = property.name();
auto valueObject = new PropertyEditorValue(&m_valuesPropertyMap);
valueObject->setName(propertyName);
@@ -689,11 +667,17 @@ void PropertyEditorNodeWrapper::setup()
void PropertyEditorNodeWrapper::update()
{
- if (m_editorValue && m_editorValue->modelNode().isValid()) {
- if (m_editorValue->modelNode().hasProperty(m_editorValue->name()) && m_editorValue->modelNode().property(m_editorValue->name()).isNodeProperty())
- m_modelNode = m_editorValue->modelNode().nodeProperty(m_editorValue->name()).modelNode();
- setup();
- emit existsChanged();
- emit typeChanged();
+ if (!m_editorValue || !m_editorValue->modelNode().isValid())
+ return;
+
+ if (m_editorValue->modelNode().hasProperty(m_editorValue->name())
+ && m_editorValue->modelNode().property(m_editorValue->name()).isNodeProperty()) {
+ m_modelNode = m_editorValue->modelNode().nodeProperty(m_editorValue->name()).modelNode();
}
+
+ setup();
+ emit existsChanged();
+ emit typeChanged();
}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
index fa995bd619..9a4bbd280e 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h
@@ -3,31 +3,34 @@
#pragma once
-#include <qmldesignercorelib_global.h>
+#include "modelnode.h"
+#include "qmldesignercorelib_global.h"
#include <QObject>
#include <QQmlPropertyMap>
#include <QtQml>
-#include <modelnode.h>
-#include <enumeration.h>
+
+namespace QmlDesigner {
class PropertyEditorValue;
-class PropertyEditorNodeWrapper : public QObject {
+class PropertyEditorNodeWrapper : public QObject
+{
Q_OBJECT
Q_PROPERTY(bool exists READ exists NOTIFY existsChanged)
- Q_PROPERTY(QQmlPropertyMap* properties READ properties NOTIFY propertiesChanged)
+ Q_PROPERTY(QQmlPropertyMap *properties READ properties NOTIFY propertiesChanged)
Q_PROPERTY(QString type READ type NOTIFY typeChanged)
public:
- PropertyEditorNodeWrapper(QObject *parent=nullptr);
- PropertyEditorNodeWrapper(PropertyEditorValue* parent);
- bool exists();
- QString type();
- QQmlPropertyMap* properties();
- QmlDesigner::ModelNode parentModelNode() const;
- QmlDesigner::PropertyName propertyName() const;
+ PropertyEditorNodeWrapper(QObject *parent = nullptr);
+ PropertyEditorNodeWrapper(PropertyEditorValue *parent);
+
+ bool exists() const;
+ QString type() const;
+ QQmlPropertyMap *properties();
+ ModelNode parentModelNode() const;
+ PropertyName propertyName() const;
public slots:
void add(const QString &type = QString());
@@ -43,14 +46,15 @@ signals:
private:
void setup();
- QmlDesigner::ModelNode m_modelNode;
+ ModelNode m_modelNode;
QQmlPropertyMap m_valuesPropertyMap;
- PropertyEditorValue* m_editorValue;
+ PropertyEditorValue *m_editorValue = nullptr;
};
class PropertyEditorValue : public QObject
{
Q_OBJECT
+
Q_PROPERTY(QVariant value READ value WRITE setValueWithEmit NOTIFY valueChangedQml)
Q_PROPERTY(QVariant enumeration READ enumeration NOTIFY valueChangedQml)
Q_PROPERTY(QString expression READ expression WRITE setExpressionWithEmit NOTIFY expressionChanged FINAL)
@@ -65,13 +69,13 @@ class PropertyEditorValue : public QObject
Q_PROPERTY(bool isIdList READ isIdList NOTIFY expressionChanged FINAL)
Q_PROPERTY(QStringList expressionAsList READ getExpressionAsList NOTIFY expressionChanged FINAL)
- Q_PROPERTY(QString name READ nameAsQString FINAL)
- Q_PROPERTY(PropertyEditorNodeWrapper* complexNode READ complexNode NOTIFY complexNodeChanged FINAL)
+ Q_PROPERTY(QString name READ nameAsQString CONSTANT FINAL)
+ Q_PROPERTY(PropertyEditorNodeWrapper *complexNode READ complexNode NOTIFY complexNodeChanged FINAL)
Q_PROPERTY(bool isAvailable READ isAvailable NOTIFY isBoundChanged)
public:
- PropertyEditorValue(QObject *parent=nullptr);
+ PropertyEditorValue(QObject *parent = nullptr);
QVariant value() const;
void setValueWithEmit(const QVariant &value);
@@ -101,14 +105,14 @@ public:
bool isAvailable() const;
- QmlDesigner::PropertyName name() const;
+ PropertyName name() const;
QString nameAsQString() const;
- void setName(const QmlDesigner::PropertyName &name);
+ void setName(const PropertyName &name);
- QmlDesigner::ModelNode modelNode() const;
- void setModelNode(const QmlDesigner::ModelNode &modelNode);
+ ModelNode modelNode() const;
+ void setModelNode(const ModelNode &modelNode);
- PropertyEditorNodeWrapper* complexNode();
+ PropertyEditorNodeWrapper *complexNode();
static void registerDeclarativeTypes();
@@ -126,19 +130,18 @@ public:
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);
public slots:
void resetValue();
void setEnumeration(const QString &scope, const QString &name);
signals:
- void valueChanged(const QString &name, const QVariant&);
+ void valueChanged(const QString &name, const QVariant &);
void valueChangedQml();
- 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 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 exportPropertyAsAliasRequested(const QString &name);
void removeAliasExportRequested(const QString &name);
@@ -155,17 +158,19 @@ private:
QStringList generateStringList(const QString &string) const;
QString generateString(const QStringList &stringList) const;
- QmlDesigner::ModelNode m_modelNode;
+ ModelNode m_modelNode;
QVariant m_value;
QString m_expression;
- QmlDesigner::PropertyName m_name;
- bool m_isInSubState;
- bool m_isInModel;
- bool m_isBound;
+ PropertyName m_name;
+ bool m_isInSubState = false;
+ bool m_isInModel = false;
+ bool m_isBound = false;
bool m_hasActiveDrag = false;
- bool m_isValid; // if the property value belongs to a non-existing complexProperty it is invalid
+ bool m_isValid = false; // if the property value belongs to a non-existing complexProperty it is invalid
PropertyEditorNodeWrapper *m_complexNode;
};
-QML_DECLARE_TYPE(PropertyEditorValue)
-QML_DECLARE_TYPE(PropertyEditorNodeWrapper)
+} // namespace QmlDesigner
+
+QML_DECLARE_TYPE(QmlDesigner::PropertyEditorValue)
+QML_DECLARE_TYPE(QmlDesigner::PropertyEditorNodeWrapper)
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
index 809ad79e7c..5dff76453a 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp
@@ -6,6 +6,7 @@
#include "propertyeditorqmlbackend.h"
#include "propertyeditortransaction.h"
#include "propertyeditorvalue.h"
+#include "propertyeditorwidget.h"
#include <auxiliarydataproperties.h>
#include <nodemetainfo.h>
@@ -33,6 +34,7 @@
#include <QFileSystemWatcher>
#include <QFileInfo>
#include <QDebug>
+#include <QQuickItem>
#include <QTimer>
#include <QShortcut>
#include <QApplication>
@@ -501,6 +503,7 @@ void PropertyEditorView::setupQmlBackend()
currentQmlBackend->contextObject()->setSpecificQmlData(specificQmlData);
}
+ currentQmlBackend->widget()->installEventFilter(this);
m_stackedWidget->setCurrentWidget(currentQmlBackend->widget());
currentQmlBackend->contextObject()->triggerSelectionChanged();
@@ -629,7 +632,7 @@ void PropertyEditorView::modelAboutToBeDetached(Model *model)
resetView();
}
-void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty>& propertyList)
+void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
{
if (noValidSelection())
return;
@@ -641,7 +644,11 @@ void PropertyEditorView::propertiesRemoved(const QList<AbstractProperty>& proper
m_qmlBackEndForCurrentType->contextObject()->setHasAliasExport(QmlObjectNode(m_selectedNode).isAliasExported());
if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) {
- setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).instanceValue(property.name()));
+ m_locked = true;
+ PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(QString::fromUtf8(property.name()));
+ if (value)
+ value->resetValue();
+ m_locked = false;
if (propertyIsAttachedLayoutProperty(property.name())) {
m_qmlBackEndForCurrentType->setValueforLayoutAttachedProperties(m_selectedNode, property.name());
@@ -697,12 +704,9 @@ void PropertyEditorView::variantPropertiesChanged(const QList<VariantProperty>&
}
}
-void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
+void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags /*propertyChange*/)
{
- if (locked())
- return;
-
- if (noValidSelection())
+ if (locked() || noValidSelection())
return;
for (const BindingProperty &property : propertyList) {
@@ -714,11 +718,11 @@ void PropertyEditorView::bindingPropertiesChanged(const QList<BindingProperty>&
if (node == m_selectedNode || QmlObjectNode(m_selectedNode).propertyChangeForCurrentState() == node) {
if (property.name().contains("anchor"))
m_qmlBackEndForCurrentType->backendAnchorBinding().invalidate(m_selectedNode);
- if ( QmlObjectNode(m_selectedNode).modelNode().property(property.name()).isBindingProperty())
- setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).instanceValue(property.name()));
- else
- setValue(m_selectedNode, property.name(), QmlObjectNode(m_selectedNode).modelValue(property.name()));
+ m_locked = true;
+ QString exp = QmlObjectNode(m_selectedNode).bindingProperty(property.name()).expression();
+ m_qmlBackEndForCurrentType->setExpression(property.name(), exp);
+ m_locked = false;
}
}
}
@@ -806,7 +810,12 @@ bool PropertyEditorView::hasWidget() const
WidgetInfo PropertyEditorView::widgetInfo()
{
- return createWidgetInfo(m_stackedWidget, QStringLiteral("Properties"), WidgetInfo::RightPane, 0, tr("Properties"));
+ return createWidgetInfo(m_stackedWidget,
+ QStringLiteral("Properties"),
+ WidgetInfo::RightPane,
+ 0,
+ tr("Properties"),
+ tr("Property Editor view"));
}
void PropertyEditorView::currentStateChanged(const ModelNode &node)
@@ -892,6 +901,15 @@ void PropertyEditorView::setValue(const QmlObjectNode &qmlObjectNode,
m_locked = false;
}
+bool PropertyEditorView::eventFilter(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::FocusOut) {
+ if (m_qmlBackEndForCurrentType && m_qmlBackEndForCurrentType->widget() == obj)
+ QMetaObject::invokeMethod(m_qmlBackEndForCurrentType->widget()->rootObject(), "closeContextMenu");
+ }
+ return AbstractView::eventFilter(obj, event);
+}
+
void PropertyEditorView::reloadQml()
{
m_qmlBackendHash.clear();
diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
index 7964420251..bb2f9dc360 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h
@@ -3,13 +3,15 @@
#pragma once
-#include <abstractview.h>
+#include "abstractview.h"
+
#include <QHash>
+#include <QObject>
#include <QTimer>
-#include "propertyeditorwidget.h"
QT_BEGIN_NAMESPACE
+class QEvent;
class QShortcut;
class QStackedWidget;
class QTimer;
@@ -17,14 +19,13 @@ QT_END_NAMESPACE
namespace QmlDesigner {
-class PropertyEditorTransaction;
class CollapseButton;
-class PropertyEditorWidget;
-class PropertyEditorView;
-class PropertyEditorQmlBackend;
class ModelNode;
+class PropertyEditorQmlBackend;
+class PropertyEditorView;
+class PropertyEditorWidget;
-class PropertyEditorView: public AbstractView
+class PropertyEditorView : public AbstractView
{
Q_OBJECT
@@ -84,6 +85,7 @@ protected:
void timerEvent(QTimerEvent *event) override;
void setupPane(const TypeName &typeName);
void setValue(const QmlObjectNode &fxObjectNode, const PropertyName &name, const QVariant &value);
+ bool eventFilter(QObject *obj, QEvent *event) override;
private: //functions
void reloadQml();
diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp
index 5a1e10220c..610c0e2731 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp
@@ -3,7 +3,10 @@
#include "quick2propertyeditorview.h"
+#include <qmldesignerconstants.h>
+
#include "aligndistribute.h"
+#include "assetimageprovider.h"
#include "annotationeditor/annotationeditor.h"
#include "bindingeditor/actioneditor.h"
#include "bindingeditor/bindingeditor.h"
@@ -16,7 +19,6 @@
#include "itemfiltermodel.h"
#include "propertychangesmodel.h"
#include "propertyeditorcontextobject.h"
-#include "propertyeditorimageprovider.h"
#include "propertyeditorqmlbackend.h"
#include "propertyeditorvalue.h"
#include "propertymodel.h"
@@ -30,10 +32,11 @@ namespace QmlDesigner {
Quick2PropertyEditorView::Quick2PropertyEditorView(AsynchronousImageCache &imageCache)
: QQuickWidget()
{
+ setObjectName(Constants::OBJECT_NAME_PROPERTY_EDITOR);
setResizeMode(QQuickWidget::SizeRootObjectToView);
Theme::setupTheme(engine());
engine()->addImageProvider("qmldesigner_thumbnails",
- new PropertyEditorImageProvider(imageCache));
+ new AssetImageProvider(imageCache));
}
void Quick2PropertyEditorView::registerQmlTypes()
diff --git a/src/plugins/qmldesigner/components/resources/dockwidgets.css b/src/plugins/qmldesigner/components/resources/dockwidgets.css
index 84865f4749..3404065521 100644
--- a/src/plugins/qmldesigner/components/resources/dockwidgets.css
+++ b/src/plugins/qmldesigner/components/resources/dockwidgets.css
@@ -29,6 +29,7 @@ ADS--DockWidgetTab {
border-color: creatorTheme.DStabSplitter;
border-style: solid;
border-width: 0 1px 0 0;
+ padding-left: 16px;
}
ADS--DockWidgetTab QLabel {
@@ -44,7 +45,7 @@ ADS--DockWidgetTab[activeTab="true"] QLabel {
}
ADS--DockWidgetTab[activeTab="true"] > #tabCloseButton:hover {
- background: creatorTheme.DStabActiveButtonHover;
+ background: creatorTheme.DStabActiveBackground;
}
ADS--DockWidgetTab[activeTab="true"] > #tabCloseButton:pressed {
@@ -105,7 +106,7 @@ QScrollArea#dockWidgetScrollArea {
}
#tabCloseButton:hover {
- background: creatorTheme.DStabInactiveButtonHover;
+ background: creatorTheme.DStabActiveBackground;
}
#tabCloseButton:pressed {
diff --git a/src/plugins/qmldesigner/components/resources/stylesheet.css b/src/plugins/qmldesigner/components/resources/stylesheet.css
index 501e9ab1d5..e8587d57b4 100644
--- a/src/plugins/qmldesigner/components/resources/stylesheet.css
+++ b/src/plugins/qmldesigner/components/resources/stylesheet.css
@@ -95,3 +95,44 @@ QLineEdit:focus {
background-color: creatorTheme.DScontrolBackgroundInteraction;
border-color: creatorTheme.DScontrolOutlineInteraction;
}
+
+QToolBar QLineEdit {
+ height: 27px; min-height: 27px; max-height: 27px;
+ border-radius: 4;
+ color: creatorTheme.DStextColor;
+ border: 1px solid creatorTheme.DScontrolOutline_topToolbarIdle;
+ background: creatorTheme.DStoolbarBackground;
+ /*font-size: 12px;*/
+}
+
+QToolBar QLineEdit:hover {
+ color: creatorTheme.DStextColor;
+ border: 1px solid creatorTheme.DScontrolOutline_topToolbarHover;
+ background: creatorTheme.DScontrolBackground_toolbarHover;
+}
+
+QToolBar QLineEdit:focus {
+ color: creatorTheme.DStextColor;
+ border: 1px solid creatorTheme.DSinteraction;
+ background: creatorTheme.DStoolbarBackground;
+}
+
+QToolBar QToolButton {
+ border: none;
+ padding: 0px;
+ width: 29px; min-width: 29px; max-width: 29px;
+ height: 29px; min-height: 29px; max-height: 29px;
+ border-radius: 4px;
+}
+
+QToolBar QToolButton:hover {
+ background-color: creatorTheme.DScontrolBackground_topToolbarHover;
+}
+
+QToolBar QToolButton:pressed {
+ background-color: creatorTheme.DSinteraction;
+}
+
+QToolBar QToolButton:checked {
+ background-color: creatorTheme.DSinteraction;
+}
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.cpp
index 9f0e871044..55fcf61932 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.cpp
@@ -6,14 +6,11 @@
#include <QDebug>
-namespace QmlDesigner {
-
-namespace Internal {
+namespace QmlDesigner::Internal {
StatesEditorImageProvider::StatesEditorImageProvider()
: QQuickImageProvider(QQuickImageProvider::Image)
-{
-}
+{}
QImage StatesEditorImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
@@ -28,7 +25,8 @@ QImage StatesEditorImageProvider::requestImage(const QString &id, QSize *size, c
bool canBeConverted;
int instanceId = imageId.toInt(&canBeConverted);
if (canBeConverted && m_nodeInstanceView->hasModelNodeForInternalId(instanceId)) {
- image = m_nodeInstanceView->statePreviewImage(m_nodeInstanceView->modelNodeForInternalId(instanceId));
+ image = m_nodeInstanceView->statePreviewImage(
+ m_nodeInstanceView->modelNodeForInternalId(instanceId));
}
}
}
@@ -37,7 +35,7 @@ QImage StatesEditorImageProvider::requestImage(const QString &id, QSize *size, c
//creating white QImage
QSize newSize = requestedSize;
if (newSize.isEmpty())
- newSize = QSize (100, 100);
+ newSize = QSize(100, 100);
QImage image(newSize, QImage::Format_ARGB32);
image.fill(0xFFFFFFFF);
@@ -54,7 +52,4 @@ void StatesEditorImageProvider::setNodeInstanceView(const NodeInstanceView *node
m_nodeInstanceView = nodeInstanceView;
}
-}
-
-}
-
+} // QmlDesigner::Internal
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.h
index 29357c80f3..0bfb0bf330 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.h
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorimageprovider.h
@@ -3,10 +3,10 @@
#pragma once
-#include"abstractview.h"
+#include "abstractview.h"
-#include <QQuickImageProvider>
#include <QPointer>
+#include <QQuickImageProvider>
namespace QmlDesigner {
namespace Internal {
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp
index 0568d3c523..96ec3fa8e6 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp
@@ -6,30 +6,26 @@
#include <QDebug>
-#include <nodelistproperty.h>
-#include <modelnode.h>
#include <bindingproperty.h>
-#include <variantproperty.h>
+#include <modelnode.h>
+#include <nodelistproperty.h>
#include <rewriterview.h>
+#include <variantproperty.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <QWidget>
-enum {
- debug = false
-};
-
+enum { debug = false };
namespace QmlDesigner {
StatesEditorModel::StatesEditorModel(StatesEditorView *view)
- : QAbstractListModel(view),
- m_statesEditorView(view),
- m_updateCounter(0)
-{
-}
+ : QAbstractListModel(view)
+ , m_statesEditorView(view)
+ , m_updateCounter(0)
+{}
int StatesEditorModel::count() const
{
@@ -43,9 +39,12 @@ QModelIndex StatesEditorModel::index(int row, int column, const QModelIndex &par
int internalNodeId = 0;
if (row > 0 && row < rowCount() - 1) // first and last rows are base state, add state
- internalNodeId = m_statesEditorView->acitveStatesGroupNode().nodeListProperty("states").at(row - 1).internalId();
+ internalNodeId = m_statesEditorView->acitveStatesGroupNode()
+ .nodeListProperty("states")
+ .at(row - 1)
+ .internalId();
- return hasIndex(row, column, parent) ? createIndex(row, column, internalNodeId) : QModelIndex();
+ return hasIndex(row, column, parent) ? createIndex(row, column, internalNodeId) : QModelIndex();
}
int StatesEditorModel::rowCount(const QModelIndex &parent) const
@@ -56,7 +55,8 @@ int StatesEditorModel::rowCount(const QModelIndex &parent) const
if (!m_statesEditorView->acitveStatesGroupNode().hasNodeListProperty("states"))
return 2; // base state + add new state
- return m_statesEditorView->acitveStatesGroupNode().nodeListProperty("states").count() + 2; // 2 = base state + add new state
+ return m_statesEditorView->acitveStatesGroupNode().nodeListProperty("states").count()
+ + 2; // 2 = base state + add new state
}
void StatesEditorModel::reset()
@@ -67,7 +67,8 @@ void StatesEditorModel::reset()
QVariant StatesEditorModel::data(const QModelIndex &index, int role) const
{
- if (index.parent().isValid() || index.column() != 0 || m_statesEditorView.isNull() || !m_statesEditorView->hasModelNodeForInternalId(index.internalId()))
+ if (index.parent().isValid() || index.column() != 0 || m_statesEditorView.isNull()
+ || !m_statesEditorView->hasModelNodeForInternalId(index.internalId()))
return QVariant();
ModelNode stateNode;
@@ -121,16 +122,14 @@ QVariant StatesEditorModel::data(const QModelIndex &index, int role) const
QHash<int, QByteArray> StatesEditorModel::roleNames() const
{
- static QHash<int, QByteArray> roleNames {
- {StateNameRole, "stateName"},
- {StateImageSourceRole, "stateImageSource"},
- {InternalNodeId, "internalNodeId"},
- {HasWhenCondition, "hasWhenCondition"},
- {WhenConditionString, "whenConditionString"},
- {IsDefault, "isDefault"},
- {ModelHasDefaultState, "modelHasDefaultState"},
- {StateType, "type"}
- };
+ static QHash<int, QByteArray> roleNames{{StateNameRole, "stateName"},
+ {StateImageSourceRole, "stateImageSource"},
+ {InternalNodeId, "internalNodeId"},
+ {HasWhenCondition, "hasWhenCondition"},
+ {WhenConditionString, "whenConditionString"},
+ {IsDefault, "isDefault"},
+ {ModelHasDefaultState, "modelHasDefaultState"},
+ {StateType, "type"}};
return roleNames;
}
@@ -167,19 +166,17 @@ void StatesEditorModel::renameState(int internalNodeId, const QString &newName)
if (newName == m_statesEditorView->currentStateName())
return;
- if (newName.isEmpty() ||! m_statesEditorView->validStateName(newName)) {
- QTimer::singleShot(0, [newName]{
+ if (newName.isEmpty() || !m_statesEditorView->validStateName(newName)) {
+ QTimer::singleShot(0, [newName] {
Core::AsynchronousMessageBox::warning(
- tr("Invalid State Name"),
- newName.isEmpty() ?
- tr("The empty string as a name is reserved for the base state.") :
- tr("Name already used in another state."));
+ tr("Invalid State Name"),
+ newName.isEmpty() ? tr("The empty string as a name is reserved for the base state.")
+ : tr("Name already used in another state."));
});
reset();
} else {
m_statesEditorView->renameState(internalNodeId, newName);
}
-
}
void StatesEditorModel::setWhenCondition(int internalNodeId, const QString &condition)
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h
index 83e3cb743e..832f0cdbff 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.h
@@ -6,7 +6,6 @@
#include <QAbstractListModel>
#include <QPointer>
-
namespace QmlDesigner {
class StatesEditorView;
@@ -52,7 +51,6 @@ public:
void reset();
-
signals:
void changedToState(int n);
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
index 54711a4168..2b64138387 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp
@@ -2,30 +2,30 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "stateseditorview.h"
-#include "stateseditorwidget.h"
-#include "stateseditormodel.h"
-#include <rewritingexception.h>
-#include <QDebug>
-#include <QRegularExpression>
-#include <QMessageBox>
-#include <cmath>
-#include <memory>
-
-#include <nodemetainfo.h>
+#include "stateseditormodel.h"
+#include "stateseditorwidget.h"
+#include <rewritingexception.h>
#include <bindingproperty.h>
-#include <variantproperty.h>
#include <nodelistproperty.h>
-
+#include <nodemetainfo.h>
+#include <variantproperty.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
#include <qmlstate.h>
+
#include <annotationeditor/annotationeditor.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
+#include <QDebug>
+#include <QMessageBox>
+#include <QRegularExpression>
+
+#include <cmath>
+#include <memory>
namespace QmlDesigner {
@@ -55,10 +55,17 @@ WidgetInfo StatesEditorView::widgetInfo()
if (!m_statesEditorWidget)
m_statesEditorWidget = new StatesEditorWidget(this, m_statesEditorModel.data());
- return createWidgetInfo(m_statesEditorWidget.data(), QLatin1String("StatesEditor"), WidgetInfo::BottomPane, 0, tr("States"));
+ return createWidgetInfo(m_statesEditorWidget.data(),
+ QLatin1String("StatesEditor"),
+ WidgetInfo::BottomPane,
+ 0,
+ tr("States"),
+ tr("States view"));
}
-void StatesEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)
+void StatesEditorView::rootNodeTypeChanged(const QString & /*type*/,
+ int /*majorVersion*/,
+ int /*minorVersion*/)
{
checkForStatesAvailability();
}
@@ -89,13 +96,14 @@ void StatesEditorView::removeState(int nodeId)
QStringList lockedTargets;
const auto propertyChanges = modelState.propertyChanges();
- // confirm removing not empty states
+ // confirm removing not empty states
if (!propertyChanges.isEmpty()) {
QMessageBox msgBox;
msgBox.setTextFormat(Qt::RichText);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("Remove State"));
- msgBox.setText(tr("This state is not empty. Are you sure you want to remove it?"));
+ msgBox.setText(
+ tr("This state is not empty. Are you sure you want to remove it?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Yes);
@@ -124,8 +132,9 @@ void StatesEditorView::removeState(int nodeId)
msgBox.setTextFormat(Qt::RichText);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(tr("Remove State"));
- msgBox.setText(QString(tr("Removing this state will modify locked components.") + "<br><br>%1")
- .arg(detailedText));
+ msgBox.setText(QString(tr("Removing this state will modify locked components.")
+ + "<br><br>%1")
+ .arg(detailedText));
msgBox.setInformativeText(tr("Continue by removing the state?"));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
@@ -149,7 +158,7 @@ void StatesEditorView::removeState(int nodeId)
stateNode.destroy();
}
- } catch (const RewritingException &e) {
+ } catch (const RewritingException &e) {
e.showException();
}
}
@@ -480,12 +489,14 @@ void StatesEditorView::modelAboutToBeDetached(Model *model)
resetModel();
}
-void StatesEditorView::propertiesRemoved(const QList<AbstractProperty>& propertyList)
+void StatesEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
{
for (const AbstractProperty &property : propertyList) {
- if (property.name() == "states" && property.parentModelNode() == activeStateGroup().modelNode())
+ if (property.name() == "states"
+ && property.parentModelNode() == activeStateGroup().modelNode())
resetModel();
- if (property.name() == "when" && QmlModelState::isValidQmlModelState(property.parentModelNode()))
+ if (property.name() == "when"
+ && QmlModelState::isValidQmlModelState(property.parentModelNode()))
resetModel();
}
}
@@ -494,22 +505,29 @@ void StatesEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
if (removedNode.hasParentProperty()) {
const NodeAbstractProperty propertyParent = removedNode.parentProperty();
- if (propertyParent.parentModelNode() == activeStateGroup().modelNode() && propertyParent.name() == "states")
+ if (propertyParent.parentModelNode() == activeStateGroup().modelNode()
+ && propertyParent.name() == "states")
m_lastIndex = propertyParent.indexOf(removedNode);
}
if (currentState().isValid() && removedNode == currentState())
setCurrentState(baseState());
}
-void StatesEditorView::nodeRemoved(const ModelNode & /*removedNode*/, const NodeAbstractProperty &parentProperty, PropertyChangeFlags /*propertyChange*/)
+void StatesEditorView::nodeRemoved(const ModelNode & /*removedNode*/,
+ const NodeAbstractProperty &parentProperty,
+ PropertyChangeFlags /*propertyChange*/)
{
- if (parentProperty.isValid() && parentProperty.parentModelNode() == activeStateGroup().modelNode() && parentProperty.name() == "states") {
+ if (parentProperty.isValid() && parentProperty.parentModelNode() == activeStateGroup().modelNode()
+ && parentProperty.name() == "states") {
m_statesEditorModel->removeState(m_lastIndex);
m_lastIndex = -1;
}
}
-void StatesEditorView::nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags /*propertyChange*/)
+void StatesEditorView::nodeAboutToBeReparented(const ModelNode &node,
+ const NodeAbstractProperty & /*newPropertyParent*/,
+ const NodeAbstractProperty &oldPropertyParent,
+ AbstractView::PropertyChangeFlags /*propertyChange*/)
{
if (oldPropertyParent.isValid()
&& oldPropertyParent.parentModelNode() == activeStateGroup().modelNode()
@@ -517,8 +535,10 @@ void StatesEditorView::nodeAboutToBeReparented(const ModelNode &node, const Node
m_lastIndex = oldPropertyParent.indexOf(node);
}
-
-void StatesEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags /*propertyChange*/)
+void StatesEditorView::nodeReparented(const ModelNode &node,
+ const NodeAbstractProperty &newPropertyParent,
+ const NodeAbstractProperty &oldPropertyParent,
+ AbstractView::PropertyChangeFlags /*propertyChange*/)
{
if (oldPropertyParent.isValid()
&& oldPropertyParent.parentModelNode() == activeStateGroup().modelNode()
@@ -547,7 +567,8 @@ void StatesEditorView::bindingPropertiesChanged(
[[maybe_unused]] AbstractView::PropertyChangeFlags propertyChange)
{
for (const BindingProperty &property : propertyList) {
- if (property.name() == "when" && QmlModelState::isValidQmlModelState(property.parentModelNode()))
+ if (property.name() == "when"
+ && QmlModelState::isValidQmlModelState(property.parentModelNode()))
resetModel();
}
}
@@ -562,7 +583,8 @@ void StatesEditorView::variantPropertiesChanged(const QList<VariantProperty> &pr
auto guard = qScopeGuard([&]() { m_block = false; });
for (const VariantProperty &property : propertyList) {
- if (property.name() == "name" && QmlModelState::isValidQmlModelState(property.parentModelNode()))
+ if (property.name() == "name"
+ && QmlModelState::isValidQmlModelState(property.parentModelNode()))
resetModel();
else if (property.name() == "state"
&& property.parentModelNode() == activeStateGroup().modelNode())
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
index f81940c592..52329b940d 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.h
@@ -13,14 +13,15 @@ class StatesEditorModel;
class StatesEditorWidget;
class AnnotationEditor;
-class StatesEditorView : public AbstractView {
+class StatesEditorView : public AbstractView
+{
Q_OBJECT
public:
explicit StatesEditorView(ExternalDependenciesInterface &externalDependencies);
~StatesEditorView() override;
- void renameState(int internalNodeId,const QString &newName);
+ void renameState(int internalNodeId, const QString &newName);
void setWhenCondition(int internalNodeId, const QString &condition);
void resetWhenCondition(int internalNodeId);
void setStateAsDefault(int internalNodeId);
@@ -38,7 +39,7 @@ public:
// AbstractView
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void propertiesRemoved(const QList<AbstractProperty>& propertyList) override;
+ void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
@@ -52,9 +53,10 @@ public:
const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override;
void nodeOrderChanged(const NodeListProperty &listProperty) override;
- void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange) override;
- void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange) override;
-
+ void bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
+ PropertyChangeFlags propertyChange) override;
+ void variantPropertiesChanged(const QList<VariantProperty> &propertyList,
+ PropertyChangeFlags propertyChange) override;
// AbstractView
void currentStateChanged(const ModelNode &node) override;
@@ -68,7 +70,6 @@ public:
ModelNode acitveStatesGroupNode() const;
void setAcitveStatesGroupNode(const ModelNode &modelNode);
-
public slots:
void synchonizeCurrentStateFromWidget();
void createNewState();
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
index 14fd7aee26..0501747d98 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.cpp
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "stateseditorwidget.h"
+#include "stateseditorimageprovider.h"
#include "stateseditormodel.h"
#include "stateseditorview.h"
-#include "stateseditorimageprovider.h"
#include <designersettings.h>
#include <theme.h>
@@ -13,8 +13,8 @@
#include <invalidqmlsourceexception.h>
-#include <coreplugin/messagebox.h>
#include <coreplugin/icore.h>
+#include <coreplugin/messagebox.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
@@ -22,17 +22,16 @@
#include <QApplication>
+#include <QBoxLayout>
#include <QFileInfo>
-#include <QShortcut>
#include <QKeySequence>
+#include <QShortcut>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
-enum {
- debug = false
-};
+enum { debug = false };
namespace QmlDesigner {
@@ -69,10 +68,11 @@ void StatesEditorWidget::showAddNewStatesButton(bool showAddNewStatesButton)
rootContext()->setContextProperty(QLatin1String("canAddNewStates"), showAddNewStatesButton);
}
-StatesEditorWidget::StatesEditorWidget(StatesEditorView *statesEditorView, StatesEditorModel *statesEditorModel)
- : m_statesEditorView(statesEditorView),
- m_imageProvider(nullptr),
- m_qmlSourceUpdateShortcut(nullptr)
+StatesEditorWidget::StatesEditorWidget(StatesEditorView *statesEditorView,
+ StatesEditorModel *statesEditorModel)
+ : m_statesEditorView(statesEditorView)
+ , m_imageProvider(nullptr)
+ , m_qmlSourceUpdateShortcut(nullptr)
{
m_imageProvider = new Internal::StatesEditorImageProvider;
m_imageProvider->setNodeInstanceView(statesEditorView->nodeInstanceView());
@@ -88,11 +88,9 @@ StatesEditorWidget::StatesEditorWidget(StatesEditorView *statesEditorView, State
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
rootContext()->setContextProperties(
- QVector<QQmlContext::PropertyPair>{
- {{"statesEditorModel"}, QVariant::fromValue(statesEditorModel)},
- {{"canAddNewStates"}, true}
- }
- );
+ QVector<QQmlContext::PropertyPair>{{{"statesEditorModel"},
+ QVariant::fromValue(statesEditorModel)},
+ {{"canAddNewStates"}, true}});
Theme::setupTheme(engine());
@@ -115,7 +113,7 @@ QString StatesEditorWidget::qmlSourcesPath()
void StatesEditorWidget::showEvent(QShowEvent *event)
{
- QQuickWidget::showEvent(event);
+ StudioQuickWidget::showEvent(event);
update();
}
@@ -123,13 +121,13 @@ void StatesEditorWidget::focusOutEvent(QFocusEvent *focusEvent)
{
QmlDesignerPlugin::emitUsageStatisticsTime(Constants::EVENT_STATESEDITOR_TIME,
m_usageTimer.elapsed());
- QQuickWidget::focusOutEvent(focusEvent);
+ StudioQuickWidget::focusOutEvent(focusEvent);
}
void StatesEditorWidget::focusInEvent(QFocusEvent *focusEvent)
{
m_usageTimer.restart();
- QQuickWidget::focusInEvent(focusEvent);
+ StudioQuickWidget::focusInEvent(focusEvent);
}
void StatesEditorWidget::reloadQmlSource()
@@ -146,14 +144,17 @@ void StatesEditorWidget::reloadQmlSource()
Core::AsynchronousMessageBox::warning(tr("Cannot Create QtQuick View"),
tr("StatesEditorWidget: %1 cannot be created.%2")
- .arg(qmlSourcesPath(), errorString));
+ .arg(qmlSourcesPath(), errorString));
return;
}
- connect(rootObject(), SIGNAL(currentStateInternalIdChanged()), m_statesEditorView.data(), SLOT(synchonizeCurrentStateFromWidget()));
+ connect(rootObject(),
+ SIGNAL(currentStateInternalIdChanged()),
+ m_statesEditorView.data(),
+ SLOT(synchonizeCurrentStateFromWidget()));
connect(rootObject(), SIGNAL(createNewState()), m_statesEditorView.data(), SLOT(createNewState()));
connect(rootObject(), SIGNAL(deleteState(int)), m_statesEditorView.data(), SLOT(removeState(int)));
m_statesEditorView.data()->synchonizeCurrentStateFromWidget();
}
-} // QmlDesigner
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h
index 16e7494794..fb83872a13 100644
--- a/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h
+++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorwidget.h
@@ -3,10 +3,11 @@
#pragma once
+#include <studioquickwidget.h>
+
#include <QElapsedTimer>
#include <QPointer>
#include <QQmlPropertyMap>
-#include <QQuickWidget>
QT_BEGIN_NAMESPACE
class QShortcut;
@@ -18,9 +19,11 @@ class StatesEditorModel;
class StatesEditorView;
class NodeInstanceView;
-namespace Internal { class StatesEditorImageProvider; }
+namespace Internal {
+class StatesEditorImageProvider;
+}
-class StatesEditorWidget : public QQuickWidget
+class StatesEditorWidget : public StudioQuickWidget
{
Q_OBJECT
@@ -51,4 +54,4 @@ private:
QElapsedTimer m_usageTimer;
};
-}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/stateseditornew/stateseditorwidget.cpp b/src/plugins/qmldesigner/components/stateseditornew/stateseditorwidget.cpp
index c47f19e4cb..f3fd945ae6 100644
--- a/src/plugins/qmldesigner/components/stateseditornew/stateseditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/stateseditornew/stateseditorwidget.cpp
@@ -109,6 +109,7 @@ StatesEditorWidget::StatesEditorWidget(StatesEditorView *statesEditorView,
m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F10), this);
connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &StatesEditorWidget::reloadQmlSource);
+ setObjectName(Constants::OBJECT_NAME_STATES_EDITOR);
setResizeMode(QQuickWidget::SizeRootObjectToView);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -162,7 +163,6 @@ void StatesEditorWidget::reloadQmlSource()
{
QString statesListQmlFilePath = qmlSourcesPath() + QStringLiteral("/Main.qml");
QTC_ASSERT(QFileInfo::exists(statesListQmlFilePath), return );
- engine()->clearComponentCache();
setSource(QUrl::fromLocalFile(statesListQmlFilePath));
if (!rootObject()) {
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
index ca9bdbbcb9..a7ada80ed7 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
@@ -124,7 +124,13 @@ void TextEditorView::nodeReparented(const ModelNode &/*node*/, const NodeAbstrac
WidgetInfo TextEditorView::widgetInfo()
{
- return createWidgetInfo(m_widget, "TextEditor", WidgetInfo::CentralPane, 0, tr("Code"), DesignerWidgetFlags::IgnoreErrors);
+ return createWidgetInfo(m_widget,
+ "TextEditor",
+ WidgetInfo::CentralPane,
+ 0,
+ tr("Code"),
+ tr("Code view"),
+ DesignerWidgetFlags::IgnoreErrors);
}
void TextEditorView::qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
index 0bf2146307..1529c0a87c 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
@@ -173,15 +173,11 @@ bool TextEditorWidget::eventFilter(QObject *, QEvent *event)
static std::vector<int> overrideKeys = { Qt::Key_Delete, Qt::Key_Backspace, Qt::Key_Insert,
Qt::Key_Escape };
- static std::vector<QKeySequence> overrideSequences = { QKeySequence::SelectAll, QKeySequence::Cut,
- QKeySequence::Copy, QKeySequence::Delete,
- QKeySequence::Paste, QKeySequence::Undo,
- QKeySequence::Redo, QKeySequence(Qt::CTRL | Qt::ALT),
- QKeySequence(Qt::Key_Left | Qt::CTRL),
- QKeySequence(Qt::Key_Right | Qt::CTRL),
- QKeySequence(Qt::Key_Up | Qt::CTRL),
- QKeySequence(Qt::Key_Down | Qt::CTRL)
- };
+ static std::vector<QKeySequence> overrideSequences = {QKeySequence(Qt::CTRL | Qt::ALT),
+ QKeySequence(Qt::Key_Left | Qt::CTRL),
+ QKeySequence(Qt::Key_Right | Qt::CTRL),
+ QKeySequence(Qt::Key_Up | Qt::CTRL),
+ QKeySequence(Qt::Key_Down | Qt::CTRL)};
if (event->type() == QEvent::ShortcutOverride) {
auto keyEvent = static_cast<QKeyEvent *>(event);
diff --git a/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx.png b/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx.png
new file mode 100644
index 0000000000..cad32f6114
--- /dev/null
+++ b/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx@2x.png b/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx@2x.png
new file mode 100644
index 0000000000..015ae045d7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/textureeditor/images/texture_ktx@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditor.qrc b/src/plugins/qmldesigner/components/textureeditor/textureeditor.qrc
index 680fe7d82b..cb43ec1aa9 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditor.qrc
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditor.qrc
@@ -2,5 +2,7 @@
<qresource prefix="/textureeditor">
<file>images/texture_default.png</file>
<file>images/texture_default@2x.png</file>
+ <file>images/texture_ktx.png</file>
+ <file>images/texture_ktx@2x.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
index 679e07b00c..1148e31e2b 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorcontextobject.cpp
@@ -339,7 +339,8 @@ QString TextureEditorContextObject::resolveResourcePath(const QString &path)
{
if (Utils::FilePath::fromString(path).isAbsolutePath())
return path;
- return DocumentManager::currentResourcePath().path() + '/' + path;
+ return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()
+ ->fileName().absolutePath().pathAppended(path).cleanPath().toString();
}
} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.cpp
index 9095be2d93..e9c9eafc71 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.cpp
@@ -6,7 +6,7 @@
#include "dynamicpropertiesmodel.h"
#include "textureeditorview.h"
-using namespace QmlDesigner;
+namespace QmlDesigner {
TextureEditorDynamicPropertiesProxyModel::TextureEditorDynamicPropertiesProxyModel(QObject *parent)
: DynamicPropertiesProxyModel(parent)
@@ -20,3 +20,5 @@ void TextureEditorDynamicPropertiesProxyModel::registerDeclarativeType()
DynamicPropertiesProxyModel::registerDeclarativeType();
qmlRegisterType<TextureEditorDynamicPropertiesProxyModel>("HelperWidgets", 2, 0, "TextureEditorDynamicPropertiesModel");
}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.h b/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.h
index 9832d6eb4f..f1f5a3059a 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditordynamicpropertiesproxymodel.h
@@ -5,6 +5,8 @@
#include "dynamicpropertiesproxymodel.h"
+namespace QmlDesigner {
+
class TextureEditorDynamicPropertiesProxyModel : public DynamicPropertiesProxyModel
{
Q_OBJECT
@@ -14,3 +16,5 @@ public:
static void registerDeclarativeType();
};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
index 553f32205b..e54909049e 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.cpp
@@ -3,10 +3,10 @@
#include "textureeditorqmlbackend.h"
+#include "assetimageprovider.h"
#include "bindingproperty.h"
#include "documentmanager.h"
#include "nodemetainfo.h"
-#include "propertyeditorimageprovider.h"
#include "propertyeditorvalue.h"
#include "qmldesignerconstants.h"
#include "qmlobjectnode.h"
@@ -49,8 +49,9 @@ TextureEditorQmlBackend::TextureEditorQmlBackend(TextureEditorView *textureEdito
{
QImage defaultImage;
defaultImage.load(Utils::StyleHelper::dpiSpecificImageFile(":/textureeditor/images/texture_default.png"));
- m_textureEditorImageProvider = new PropertyEditorImageProvider(imageCache, defaultImage);
+ 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_contextObject->setBackendValues(&m_backendValuesPropertyMap);
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
index bc84a80a3c..241195bd70 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorqmlbackend.h
@@ -17,9 +17,8 @@ QT_END_NAMESPACE
namespace QmlDesigner {
-class PropertyEditorImageProvider;
+class AssetImageProvider;
class TextureEditorContextObject;
-class TextureEditorImageProvider;
class TextureEditorTransaction;
class TextureEditorView;
@@ -65,7 +64,7 @@ private:
DesignerPropertyMap m_backendValuesPropertyMap;
QScopedPointer<TextureEditorTransaction> m_textureEditorTransaction;
QScopedPointer<TextureEditorContextObject> m_contextObject;
- PropertyEditorImageProvider *m_textureEditorImageProvider = nullptr;
+ AssetImageProvider *m_textureEditorImageProvider = nullptr;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditortransaction.h b/src/plugins/qmldesigner/components/textureeditor/textureeditortransaction.h
index 74565aefd7..ab071473cd 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditortransaction.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditortransaction.h
@@ -3,6 +3,7 @@
#pragma once
+#include "rewritertransaction.h"
#include "textureeditorview.h"
namespace QmlDesigner {
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
index 99b0a6e632..38664c146e 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
@@ -28,6 +28,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
+#include <designdocument.h>
#include <designmodewidget.h>
#include <propertyeditorqmlbackend.h>
#include <utils/environment.h>
@@ -54,7 +55,7 @@ TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache,
: AbstractView{externalDependencies}
, m_imageCache(imageCache)
, m_stackedWidget(new QStackedWidget)
- , m_dynamicPropertiesModel(new Internal::DynamicPropertiesModel(true, this))
+ , m_dynamicPropertiesModel(new DynamicPropertiesModel(true, this))
{
m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F12), m_stackedWidget);
connect(m_updateShortcut, &QShortcut::activated, this, &TextureEditorView::reloadQml);
@@ -62,7 +63,9 @@ TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache,
m_ensureMatLibTimer.callOnTimeout([this] {
if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()
&& model()->rewriterView()->errors().isEmpty()) {
- ensureMaterialLibraryNode();
+ DesignDocument *doc = QmlDesignerPlugin::instance()->currentDesignDocument();
+ if (doc && !doc->inFileComponentModelActive())
+ ensureMaterialLibraryNode();
if (m_qmlBackEnd && m_qmlBackEnd->contextObject())
m_qmlBackEnd->contextObject()->setHasMaterialLibrary(materialLibraryNode().isValid());
m_ensureMatLibTimer.stop();
@@ -288,7 +291,7 @@ void TextureEditorView::currentTimelineChanged(const ModelNode &)
m_qmlBackEnd->contextObject()->setHasActiveTimeline(QmlTimeline::hasActiveTimeline(this));
}
-Internal::DynamicPropertiesModel *TextureEditorView::dynamicPropertiesModel() const
+DynamicPropertiesModel *TextureEditorView::dynamicPropertiesModel() const
{
return m_dynamicPropertiesModel;
}
@@ -670,7 +673,8 @@ WidgetInfo TextureEditorView::widgetInfo()
"TextureEditor",
WidgetInfo::RightPane,
0,
- tr("Texture Editor"));
+ tr("Texture Editor"),
+ tr("Texture Editor view"));
}
void TextureEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
index d932d4c50e..b299a1e99a 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
@@ -19,13 +19,10 @@ QT_END_NAMESPACE
namespace QmlDesigner {
+class DynamicPropertiesModel;
class ModelNode;
class TextureEditorQmlBackend;
-namespace Internal {
-class DynamicPropertiesModel;
-}
-
class TextureEditorView : public AbstractView
{
Q_OBJECT
@@ -77,7 +74,7 @@ public:
void currentTimelineChanged(const ModelNode &node) override;
- Internal::DynamicPropertiesModel *dynamicPropertiesModel() const;
+ DynamicPropertiesModel *dynamicPropertiesModel() const;
static TextureEditorView *instance();
@@ -123,7 +120,7 @@ private:
QPointer<QColorDialog> m_colorDialog;
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
- Internal::DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
+ DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
index 951f1a7841..8c0a9c9d73 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinepropertyitem.cpp
@@ -182,8 +182,10 @@ TimelinePropertyItem *TimelinePropertyItem::create(const QmlTimelineKeyframeGrou
}
});
- QIcon autoKeyIcon = TimelineUtils::mergeIcons(TimelineIcons::GLOBAL_RECORD_KEYFRAMES,
- TimelineIcons::GLOBAL_RECORD_KEYFRAMES_OFF);
+ QIcon autoKeyIcon = TimelineUtils::mergeIcons(
+ Theme::iconFromName(Theme::recordFill_medium, Theme::getColor(Theme::Color::IconsStopColor)),
+ Theme::iconFromName(Theme::recordOutline_medium));
+
auto recact = new QAction(autoKeyIcon, tr("Auto Record"));
recact->setCheckable(true);
recact->setChecked(isRecording);
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp
index 1933fb3eaf..c920b8b428 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp
@@ -96,6 +96,7 @@ TimelineToolBar::TimelineToolBar(QWidget *parent)
, m_grp()
{
setContentsMargins(0, 0, 0, 0);
+ setFixedHeight(Theme::toolbarSize());
createLeftControls();
createCenterControls();
createRightControls();
@@ -220,7 +221,7 @@ void TimelineToolBar::createLeftControls()
addSpacingToGroup(5);
auto *settingsAction = createAction(TimelineConstants::C_SETTINGS,
- TimelineIcons::ANIMATION.icon(),
+ Theme::iconFromName(Theme::Icon::settings_medium),
tr("Timeline Settings"),
QKeySequence(Qt::Key_S));
@@ -255,7 +256,7 @@ void TimelineToolBar::createCenterControls()
addSpacing(5);
auto *toStart = createAction(TimelineConstants::C_TO_START,
- TimelineIcons::TO_FIRST_FRAME.icon(),
+ Theme::iconFromName(Theme::Icon::toStartFrame_medium),
tr("To Start"),
QKeySequence(Qt::Key_Home));
@@ -265,7 +266,7 @@ void TimelineToolBar::createCenterControls()
addSpacing(2);
auto *previous = createAction(TimelineConstants::C_PREVIOUS,
- TimelineIcons::BACK_ONE_FRAME.icon(),
+ Theme::iconFromName(Theme::Icon::toPrevFrame_medium),
tr("Previous"),
QKeySequence(Qt::Key_Comma));
@@ -273,8 +274,12 @@ void TimelineToolBar::createCenterControls()
addAction(previous);
addSpacing(2);
- QIcon playbackIcon = TimelineUtils::mergeIcons(TimelineIcons::PAUSE_PLAYBACK,
- TimelineIcons::START_PLAYBACK);
+ QIcon playbackIcon = TimelineUtils::mergeIcons(
+ Theme::iconFromName(Theme::Icon::pause,
+ Theme::getColor(Theme::Color::DStextSelectedTextColor)),
+ Theme::iconFromName(Theme::Icon::playOutline_medium,
+ Theme::getColor(Theme::Color::IconsRunColor)));
+
m_playing = createAction(TimelineConstants::C_PLAY,
playbackIcon,
tr("Play"),
@@ -286,7 +291,7 @@ void TimelineToolBar::createCenterControls()
addSpacing(2);
auto *next = createAction(TimelineConstants::C_NEXT,
- TimelineIcons::FORWARD_ONE_FRAME.icon(),
+ Theme::iconFromName(Theme::Icon::toNextFrame_medium),
tr("Next"),
QKeySequence(Qt::Key_Period));
@@ -296,7 +301,7 @@ void TimelineToolBar::createCenterControls()
addSpacing(2);
auto *toEnd = createAction(TimelineConstants::C_TO_END,
- TimelineIcons::TO_LAST_FRAME.icon(),
+ Theme::iconFromName(Theme::Icon::toEndFrame_medium),
tr("To End"),
QKeySequence(Qt::Key_End));
@@ -309,10 +314,12 @@ void TimelineToolBar::createCenterControls()
addSpacing(10);
- auto *loopAnimation = createAction(TimelineConstants::C_LOOP_PLAYBACK,
- TimelineIcons::LOOP_PLAYBACK.icon(),
- tr("Loop Playback"),
- QKeySequence((Qt::ControlModifier | Qt::ShiftModifier) + Qt::Key_Space)); // TODO: Toggles looping. Select shortcut for this QDS-4941
+ auto *loopAnimation = createAction(
+ TimelineConstants::C_LOOP_PLAYBACK,
+ Theme::iconFromName(Theme::Icon::loopPlayback_medium),
+ tr("Loop Playback"),
+ QKeySequence((Qt::ControlModifier | Qt::ShiftModifier)
+ + Qt::Key_Space)); // TODO: Toggles looping. Select shortcut for this QDS-4941
loopAnimation->setCheckable(true);
connect(loopAnimation, &QAction::toggled, [&](bool value) { emit loopPlaybackToggled(value);} );
@@ -349,8 +356,10 @@ void TimelineToolBar::createCenterControls()
addSpacing(10);
- QIcon autoKeyIcon = TimelineUtils::mergeIcons(TimelineIcons::GLOBAL_RECORD_KEYFRAMES,
- TimelineIcons::GLOBAL_RECORD_KEYFRAMES_OFF);
+ QIcon autoKeyIcon = TimelineUtils::mergeIcons(
+ Theme::iconFromName(Theme::Icon::recordFill_medium,
+ Theme::getColor(Theme::Color::IconsStopColor)),
+ Theme::iconFromName(Theme::Icon::recordOutline_medium));
m_recording = createAction(TimelineConstants::C_AUTO_KEYFRAME,
autoKeyIcon,
@@ -369,7 +378,7 @@ void TimelineToolBar::createCenterControls()
addSpacing(10);
auto *curvePicker = createAction(TimelineConstants::C_CURVE_PICKER,
- TimelineIcons::CURVE_EDITOR.icon(),
+ Theme::iconFromName(Theme::Icon::curveDesigner_medium),
tr("Easing Curve Editor"),
QKeySequence(Qt::Key_C));
@@ -408,7 +417,7 @@ void TimelineToolBar::createRightControls()
addSpacing(10);
auto *zoomOut = createAction(TimelineConstants::C_ZOOM_OUT,
- TimelineIcons::ZOOM_SMALL.icon(),
+ Theme::iconFromName(Theme::Icon::zoomOut_medium),
tr("Zoom Out"),
QKeySequence(QKeySequence::ZoomOut));
@@ -421,6 +430,8 @@ void TimelineToolBar::createRightControls()
m_scale = new QSlider(this);
m_scale->setOrientation(Qt::Horizontal);
+ m_scale->setProperty("panelwidget", true);
+ m_scale->setProperty("panelwidget_singlerow", true);
m_scale->setMaximumWidth(200);
m_scale->setMinimumWidth(100);
m_scale->setMinimum(0);
@@ -433,7 +444,7 @@ void TimelineToolBar::createRightControls()
addSpacing(10);
auto *zoomIn = createAction(TimelineConstants::C_ZOOM_IN,
- TimelineIcons::ZOOM_BIG.icon(),
+ Theme::iconFromName(Theme::Icon::zoomIn_medium),
tr("Zoom In"),
QKeySequence(QKeySequence::ZoomIn));
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineutils.h b/src/plugins/qmldesigner/components/timelineeditor/timelineutils.h
index 16949295e9..088f6d8f89 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineutils.h
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineutils.h
@@ -44,11 +44,11 @@ inline T reverseLerp(const T &val, const T &lhs, const T &rhs)
return (val - rhs) / (lhs - rhs);
}
-inline QIcon mergeIcons(const Utils::Icon &on, const Utils::Icon &off)
+inline QIcon mergeIcons(const QIcon &on, const QIcon &off)
{
QIcon out;
- out.addPixmap(on.pixmap(), QIcon::Normal, QIcon::On);
- out.addPixmap(off.pixmap(), QIcon::Normal, QIcon::Off);
+ out.addPixmap(on.pixmap({16, 16}), QIcon::Normal, QIcon::On);
+ out.addPixmap(off.pixmap({16, 16}), QIcon::Normal, QIcon::Off);
return out;
}
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
index 0ad9a8741b..b68dc98eaf 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp
@@ -648,7 +648,8 @@ WidgetInfo TimelineView::widgetInfo()
QStringLiteral("Timelines"),
WidgetInfo::BottomPane,
0,
- tr("Timeline"));
+ tr("Timeline"),
+ tr("Timeline view"));
}
bool TimelineView::hasQtQuickTimelineImport()
diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
index 813adcc53c..64fce94848 100644
--- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
+++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp
@@ -110,8 +110,11 @@ TimelineWidget::TimelineWidget(TimelineView *view)
setWindowTitle(tr("Timeline", "Title of timeline view"));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- const QString css = Theme::replaceCssColors(QString::fromUtf8(
- Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
+ m_toolbar->setStyleSheet(Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
+
+ const QString css = Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
m_scrollbar->setStyleSheet(css);
m_scrollbar->setOrientation(Qt::Horizontal);
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp
new file mode 100644
index 0000000000..856546c106
--- /dev/null
+++ b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp
@@ -0,0 +1,132 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "toolbar.h"
+#include "toolbarbackend.h"
+
+#include <studioquickwidget.h>
+
+#include <theme.h>
+#include <qmldesignerconstants.h>
+
+#include <coreplugin/icore.h>
+#include <utils/filepath.h>
+#include <utils/qtcassert.h>
+
+#include <QMainWindow>
+#include <QQmlEngine>
+#include <QStatusBar>
+#include <QToolBar>
+
+namespace QmlDesigner {
+
+static Utils::FilePath propertyEditorResourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources");
+#endif
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources");
+}
+
+Utils::FilePath qmlSourcesStatusBarPath()
+{
+#ifdef SHARE_QML_PATH
+ if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/statusbar");
+#endif
+ return Core::ICore::resourcePath("qmldesigner/statusbar");
+}
+
+Utils::FilePath qmlSourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/toolbar");
+#endif
+ return Core::ICore::resourcePath("qmldesigner/toolbar");
+}
+
+void ToolBar::create()
+{
+ if (!isVisible())
+ return;
+
+ ToolBarBackend::registerDeclarativeType();
+
+ auto window = Core::ICore::mainWindow();
+
+ //Core::ICore::statusBar()->hide();
+
+ auto toolBar = new QToolBar;
+ toolBar->setObjectName("QDS-TOOLBAR");
+
+ toolBar->setContextMenuPolicy(Qt::PreventContextMenu);
+
+ toolBar->setFloatable(false);
+ toolBar->setMovable(false);
+
+ auto quickWidget = new StudioQuickWidget;
+
+ quickWidget->setFixedHeight(48);
+ quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ quickWidget->setMinimumWidth(200);
+ quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+
+ quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_TOP_TOOLBAR);
+
+ quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports");
+
+ Utils::FilePath qmlFilePath = qmlSourcesPath() / "Main.qml";
+ QTC_ASSERT(qmlFilePath.exists(), return);
+
+ Theme::setupTheme(quickWidget->engine());
+
+ quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString()));
+
+ toolBar->addWidget(quickWidget);
+ window->addToolBar(toolBar);
+}
+
+void ToolBar::createStatusBar()
+{
+ if (!isVisible())
+ return;
+
+ ToolBarBackend::registerDeclarativeType();
+
+ auto quickWidget = new StudioQuickWidget;
+
+ quickWidget->setFixedHeight(Theme::toolbarSize());
+ quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ quickWidget->setMinimumWidth(200);
+ quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+
+ quickWidget->quickWidget()->setObjectName(Constants::OBJECT_NAME_STATUSBAR);
+
+ quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports");
+
+ Utils::FilePath qmlFilePath = qmlSourcesStatusBarPath().pathAppended("/Main.qml");
+ QTC_ASSERT(qmlFilePath.exists(), return);
+
+ Theme::setupTheme(quickWidget->engine());
+
+ quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString()));
+
+ for (QWidget *w : Core::ICore::statusBar()->findChildren<QWidget *>(Qt::FindDirectChildrenOnly)) {
+ w->hide();
+ }
+
+ Core::ICore::statusBar()->addWidget(quickWidget);
+ Core::ICore::statusBar()->setFixedHeight(Theme::toolbarSize());
+}
+
+bool ToolBar::isVisible()
+{
+ QSettings *settings = Core::ICore::settings();
+ const QString qdsToolbarEntry = "QML/Designer/TopToolBar";
+
+ return settings->value(qdsToolbarEntry, false).toBool();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.h b/src/plugins/qmldesigner/components/toolbar/toolbar.h
new file mode 100644
index 0000000000..8537757cdf
--- /dev/null
+++ b/src/plugins/qmldesigner/components/toolbar/toolbar.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+namespace QmlDesigner {
+
+class ToolBar
+{
+
+public:
+ static void create();
+ static void createStatusBar();
+ static bool isVisible();
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
new file mode 100644
index 0000000000..d20c765fd6
--- /dev/null
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
@@ -0,0 +1,614 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "toolbarbackend.h"
+
+#include <changestyleaction.h>
+#include <crumblebar.h>
+#include <designeractionmanager.h>
+#include <designmodewidget.h>
+#include <viewmanager.h>
+#include <zoomaction.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+#include <qmleditormenu.h>
+
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/designmode.h>
+#include <coreplugin/editormanager/documentmodel.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/modemanager.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
+
+#include <qmlprojectmanager/qmlproject.h>
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+#include <QQmlEngine>
+
+namespace QmlDesigner {
+
+static Internal::DesignModeWidget *designModeWidget()
+{
+ return QmlDesignerPlugin::instance()->mainWidget();
+}
+
+static DesignDocument *currentDesignDocument()
+{
+ QTC_ASSERT(QmlDesignerPlugin::instance(), return nullptr);
+
+ return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument();
+}
+
+static CrumbleBar *crumbleBar()
+{
+ return designModeWidget()->crumbleBar();
+}
+
+static Utils::FilePath getMainUiFile()
+{
+ auto project = ProjectExplorer::ProjectManager::startupProject();
+ if (!project)
+ return {};
+
+ if (!project->activeTarget())
+ return {};
+
+ auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ project->activeTarget()->buildSystem());
+
+ if (!qmlBuildSystem)
+ return {};
+
+ return qmlBuildSystem->mainUiFilePath();
+}
+
+static void openUiFile()
+{
+ const Utils::FilePath mainUiFile = getMainUiFile();
+
+ if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists())
+ Core::EditorManager::openEditor(mainUiFile, Utils::Id());
+}
+
+void ToolBarBackend::triggerModeChange()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_MODE_CHANGE);
+ QTimer::singleShot(0, [this]() { //Do not trigger mode change directly from QML
+ bool qmlFileOpen = false;
+
+ if (!projectOpened()) {
+ Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
+ return;
+ }
+
+ auto document = Core::EditorManager::currentDocument();
+
+ if (document)
+ qmlFileOpen = document->filePath().fileName().endsWith(".qml");
+
+ if (Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN)
+ Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
+ else if (qmlFileOpen)
+ Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
+ else if (Core::ModeManager::currentModeId() == Core::Constants::MODE_WELCOME)
+ openUiFile();
+ else
+ Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
+ });
+}
+
+void ToolBarBackend::triggerProjectSettings()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_PROJECT_SETTINGS);
+ QTimer::singleShot(0, []() { //Do not trigger mode change directly from QML
+ Core::ModeManager::activateMode(ProjectExplorer::Constants::MODE_SESSION);
+ });
+}
+
+void ToolBarBackend::runProject()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_RUN_PROJECT);
+ ProjectExplorer::ProjectExplorerPlugin::runStartupProject(
+ ProjectExplorer::Constants::NORMAL_RUN_MODE);
+}
+
+void ToolBarBackend::goForward()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_GO_FORWARD);
+ QTC_ASSERT(designModeWidget(), return );
+ designModeWidget()->toolBarOnGoForwardClicked();
+}
+
+void ToolBarBackend::goBackward()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_GO_BACKWARD);
+ QTC_ASSERT(designModeWidget(), return );
+ designModeWidget()->toolBarOnGoBackClicked();
+}
+
+void ToolBarBackend::openFileByIndex(int i)
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_OPEN_FILE);
+ auto fileName = Core::DocumentModel::entries().at(i)->filePath();
+
+ Core::EditorManager::openEditor(fileName, Utils::Id(), Core::EditorManager::DoNotMakeVisible);
+}
+
+void ToolBarBackend::closeCurrentDocument()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_CLOSE_DOCUMENT);
+ Core::EditorManager::slotCloseCurrentEditorOrDocument();
+}
+
+void ToolBarBackend::shareApplicationOnline()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_SHARE_APPLICATION);
+ auto command = Core::ActionManager::command("QmlProject.ShareDesign");
+ if (command)
+ command->action()->trigger();
+}
+
+void ToolBarBackend::setCurrentWorkspace(const QString &workspace)
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_SET_CURRENT_WORKSPACE);
+ designModeWidget()->dockManager()->openWorkspace(workspace);
+}
+
+void ToolBarBackend::editGlobalAnnoation()
+{
+ launchGlobalAnnotations();
+}
+
+void ToolBarBackend::showZoomMenu(int x, int y)
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_STATUSBAR_SHOW_ZOOM);
+ ZoomAction *zoomAction = qobject_cast<ZoomAction *>(m_zoomAction->action());
+
+ QTC_ASSERT(zoomAction, return );
+
+ auto mainMenu = new QmlEditorMenu();
+
+ int currentIndex = zoomAction->currentIndex();
+ int i = 0;
+
+ for (double d : zoomAction->zoomLevels()) {
+ auto action = mainMenu->addAction(QString::number(d * 100) + "%");
+ action->setCheckable(true);
+ if (i == currentIndex)
+ action->setChecked(true);
+ ++i;
+ connect(action, &QAction::triggered, this, [zoomAction, d] { zoomAction->setZoomFactor(d); });
+ }
+
+ mainMenu->exec(QPoint(x, y));
+ mainMenu->deleteLater();
+}
+
+void ToolBarBackend::setCurrentStyle(int index)
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_STATUSBAR_SET_STYLE);
+ const QList<StyleWidgetEntry> items = ChangeStyleWidgetAction::getAllStyleItems();
+
+ QTC_ASSERT(items.count() > index, return );
+ QTC_ASSERT(index > 0, return );
+
+ QTC_ASSERT(currentDesignDocument(), return );
+
+ auto item = items.at(index);
+
+ auto view = currentDesignDocument()->rewriterView();
+
+ const QString qmlFile = view->model()->fileUrl().toLocalFile();
+
+ ChangeStyleWidgetAction::changeCurrentStyle(item.styleName, qmlFile);
+
+ view->resetPuppet();
+}
+
+void ToolBarBackend::setCurrentKit(int index)
+{
+ auto project = ProjectExplorer::ProjectManager::startupProject();
+ QTC_ASSERT(project, return );
+
+ const auto kits = ProjectExplorer::KitManager::kits();
+
+ QTC_ASSERT(kits.count() > index, return );
+ QTC_ASSERT(index >= 0, return );
+
+ const auto kit = kits.at(index);
+
+ auto newTarget = project->target(kit);
+ if (!newTarget)
+ newTarget = project->addTargetForKit(kit);
+
+ project->setActiveTarget(newTarget, ProjectExplorer::SetActive::Cascade);
+
+ emit currentKitChanged();
+}
+
+bool ToolBarBackend::canGoBack() const
+{
+ QTC_ASSERT(designModeWidget(), return false);
+ return designModeWidget()->canGoBack();
+}
+
+bool ToolBarBackend::canGoForward() const
+{
+ QTC_ASSERT(designModeWidget(), return false);
+ return designModeWidget()->canGoForward();
+}
+
+ToolBarBackend::ToolBarBackend(QObject *parent)
+ : QObject(parent)
+{
+ ActionAddedInterface callback = [this](ActionInterface *interface) {
+ if (interface->menuId() == "PreviewZoom")
+ m_zoomAction = interface;
+ };
+
+ QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
+
+ connect(designModeWidget(),
+ &Internal::DesignModeWidget::navigationHistoryChanged,
+ this,
+ &ToolBarBackend::navigationHistoryChanged);
+
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::rowsInserted,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::rowsRemoved,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::dataChanged,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::modelReset,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+
+ connect(Core::EditorManager::instance(),
+ &Core::EditorManager::currentEditorChanged,
+ this,
+ &ToolBarBackend::documentIndexChanged);
+
+ connect(Core::EditorManager::instance(),
+ &Core::EditorManager::currentEditorChanged,
+ this,
+ &ToolBarBackend::currentStyleChanged);
+
+ connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, [this]() {
+ const auto dockManager = designModeWidget()->dockManager();
+
+ connect(dockManager,
+ &ADS::DockManager::workspaceListChanged,
+ this,
+ &ToolBarBackend::setupWorkspaces);
+ connect(dockManager, &ADS::DockManager::workspaceLoaded, this, [this](const QString &) {
+ emit currentWorkspaceChanged();
+ });
+
+ setupWorkspaces();
+ });
+
+ auto editorManager = Core::EditorManager::instance();
+
+ connect(editorManager, &Core::EditorManager::documentClosed, this, [this]() {
+ if (isInDesignMode() && Core::DocumentModel::entryCount() == 0) {
+ QTimer::singleShot(0, []() { /* The mode change has to happen from event loop.
+ Otherwise we and up in an invalid state */
+ Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
+ });
+ }
+ });
+
+ connect(Core::ICore::instance(), &Core::ICore::coreAboutToOpen, this, [this] {
+ connect(Core::DesignMode::instance(), &Core::DesignMode::enabledStateChanged, this, [this] {
+ emit isDesignModeEnabledChanged();
+ });
+ });
+
+ connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this]() {
+ emit isInDesignModeChanged();
+ emit isInEditModeChanged();
+ emit isDesignModeEnabledChanged();
+ });
+
+ connect(ProjectExplorer::ProjectManager::instance(),
+ &ProjectExplorer::ProjectManager::startupProjectChanged,
+ [this](ProjectExplorer::Project *project) {
+ disconnect(m_kitConnection);
+ emit isQt6Changed();
+ emit projectOpenedChanged();
+ if (project) {
+ m_kitConnection = connect(project,
+ &ProjectExplorer::Project::activeTargetChanged,
+ this,
+ &ToolBarBackend::currentKitChanged);
+ emit currentKitChanged();
+ }
+ });
+
+ connect(ProjectExplorer::KitManager::instance(),
+ &ProjectExplorer::KitManager::kitsChanged,
+ this,
+ &ToolBarBackend::kitsChanged);
+}
+
+void ToolBarBackend::registerDeclarativeType()
+{
+ qmlRegisterType<ToolBarBackend>("ToolBar", 1, 0, "ToolBarBackend");
+ qmlRegisterType<ActionSubscriber>("ToolBar", 1, 0, "ActionSubscriber");
+ qmlRegisterType<CrumbleBarModel>("ToolBar", 1, 0, "CrumbleBarModel");
+}
+
+QStringList ToolBarBackend::documentModel() const
+{
+ return m_openDocuments;
+}
+
+void ToolBarBackend::updateDocumentModel()
+{
+ m_openDocuments.clear();
+ for (auto &entry : Core::DocumentModel::entries())
+ m_openDocuments.append(entry->displayName());
+
+ emit openDocumentsChanged();
+}
+
+int ToolBarBackend::documentIndex() const
+{
+ if (Core::EditorManager::currentDocument()) {
+ std::optional index = Core::DocumentModel::indexOfDocument(
+ Core::EditorManager::currentDocument());
+ return index.value_or(-1);
+ }
+
+ return -1;
+}
+
+QString ToolBarBackend::currentWorkspace() const
+{
+ if (designModeWidget() && designModeWidget()->dockManager())
+ return designModeWidget()->dockManager()->activeWorkspace();
+ return {};
+}
+
+QStringList ToolBarBackend::workspaces() const
+{
+ return m_workspaces;
+}
+
+QStringList ToolBarBackend::styles() const
+{
+ const QList<StyleWidgetEntry> items = ChangeStyleWidgetAction::getAllStyleItems();
+ QStringList list;
+ for (const auto &item : items)
+ list.append(item.displayName);
+
+ return list;
+}
+
+bool ToolBarBackend::isInDesignMode() const
+{
+ if (!Core::ModeManager::instance())
+ return false;
+
+ return Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN;
+}
+
+bool ToolBarBackend::isInEditMode() const
+{
+ if (!Core::ModeManager::instance())
+ return false;
+
+ return Core::ModeManager::currentModeId() == Core::Constants::MODE_EDIT;
+}
+
+void ToolBarBackend::launchGlobalAnnotations()
+{
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION);
+ ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
+
+ if (node.isValid()) {
+ designModeWidget()->globalAnnotationEditor().setModelNode(node);
+ designModeWidget()->globalAnnotationEditor().showWidget();
+ }
+}
+
+bool ToolBarBackend::isDesignModeEnabled() const
+{
+ if (Core::DesignMode::instance())
+ return Core::DesignMode::instance()->isEnabled() || getMainUiFile().exists();
+
+ return false;
+}
+
+int ToolBarBackend::currentStyle() const
+{
+ if (!currentDesignDocument())
+ return 0;
+
+ auto view = currentDesignDocument()->rewriterView();
+
+ const QString qmlFile = view->model()->fileUrl().toLocalFile();
+
+ const int index = ChangeStyleWidgetAction::getCurrentStyle(qmlFile);
+
+ return index;
+}
+
+QStringList ToolBarBackend::kits() const
+{
+ return Utils::transform(ProjectExplorer::KitManager::kits(),
+ [](ProjectExplorer::Kit *kit) { return kit->displayName(); });
+}
+
+int ToolBarBackend::currentKit() const
+{
+ if (auto target = ProjectExplorer::ProjectManager::startupTarget()) {
+ auto kit = target->kit();
+ if (kit)
+ return kits().indexOf(kit->displayName());
+ }
+ return 0;
+}
+
+bool ToolBarBackend::isQt6() const
+{
+ if (!ProjectExplorer::ProjectManager::startupTarget())
+ return false;
+
+ const QmlProjectManager::QmlBuildSystem *buildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ ProjectExplorer::ProjectManager::startupTarget()->buildSystem());
+ QTC_ASSERT(buildSystem, return false);
+
+ const bool isQt6Project = buildSystem && buildSystem->qt6Project();
+
+ return isQt6Project;
+}
+
+bool ToolBarBackend::projectOpened() const
+{
+ return ProjectExplorer::ProjectManager::instance()->startupProject();
+}
+
+void ToolBarBackend::setupWorkspaces()
+{
+ m_workspaces.clear();
+ m_workspaces = designModeWidget()->dockManager()->workspaces();
+ Utils::sort(m_workspaces);
+ emit workspacesChanged();
+ emit currentWorkspaceChanged();
+}
+
+ActionSubscriber::ActionSubscriber(QObject *parent)
+ : QObject(parent)
+{
+ ActionAddedInterface callback = [this](ActionInterface *interface) {
+ if (interface->menuId() == m_actionId.toLatin1()) {
+ m_interface = interface;
+ setupNotifier();
+ }
+ };
+
+ QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
+}
+
+void ActionSubscriber::trigger()
+{
+ if (m_interface)
+ m_interface->action()->trigger();
+}
+
+bool ActionSubscriber::available() const
+{
+ if (m_interface)
+ return m_interface->action()->isEnabled();
+ return false;
+}
+
+bool ActionSubscriber::checked() const
+{
+ if (m_interface)
+ return m_interface->action()->isChecked();
+
+ return false;
+}
+
+QString ActionSubscriber::actionId() const
+{
+ return m_actionId;
+}
+
+void ActionSubscriber::setActionId(const QString &id)
+{
+ if (id == m_actionId)
+ return;
+
+ m_actionId = id;
+ emit actionIdChanged();
+ emit tooltipChanged();
+}
+
+QString ActionSubscriber::tooltip() const
+{
+ if (m_interface)
+ return m_interface->action()->text();
+ return {};
+}
+
+void ActionSubscriber::setupNotifier()
+{
+ if (!m_interface)
+ return;
+
+ connect(m_interface->action(), &QAction::enabledChanged, this, &ActionSubscriber::availableChanged);
+
+ emit tooltipChanged();
+}
+
+CrumbleBarModel::CrumbleBarModel(QObject *)
+{
+ connect(crumbleBar(), &CrumbleBar::pathChanged, this, &CrumbleBarModel::handleCrumblePathChanged);
+}
+
+int CrumbleBarModel::rowCount(const QModelIndex &) const
+{
+ return crumbleBar()->path().count();
+}
+
+QHash<int, QByteArray> CrumbleBarModel::roleNames() const
+{
+ static QHash<int, QByteArray> roleNames{{Qt::UserRole + 1, "fileName"},
+ {Qt::UserRole + 2, "fileAddress"}};
+
+ return roleNames;
+}
+
+QVariant CrumbleBarModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid() && index.row() < rowCount()) {
+ auto info = crumbleBar()->infos().at(index.row());
+
+ if (role == Qt::UserRole + 1) {
+ return info.displayName;
+ } else if (role == Qt::UserRole + 2) {
+ return info.fileName.displayName();
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid role";
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid index";
+ }
+
+ return QVariant();
+}
+
+void CrumbleBarModel::handleCrumblePathChanged()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+void CrumbleBarModel::onCrumblePathElementClicked(int i)
+{
+ if (i < rowCount()) {
+ auto info = crumbleBar()->infos().at(i);
+ crumbleBar()->onCrumblePathElementClicked(QVariant::fromValue(info));
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
new file mode 100644
index 0000000000..1aed5aeeaf
--- /dev/null
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
@@ -0,0 +1,159 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QAbstractListModel>
+#include <QObject>
+
+namespace QmlDesigner {
+
+class ActionInterface;
+
+class CrumbleBarModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit CrumbleBarModel(QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QHash<int, QByteArray> roleNames() const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ void handleCrumblePathChanged();
+
+ Q_INVOKABLE void onCrumblePathElementClicked(int i);
+
+private:
+};
+
+class ActionSubscriber : public QObject
+{
+ Q_OBJECT
+
+public:
+ ActionSubscriber(QObject *parent = nullptr);
+
+ Q_PROPERTY(QString actionId READ actionId WRITE setActionId NOTIFY actionIdChanged)
+ Q_PROPERTY(bool available READ available NOTIFY availableChanged)
+ Q_PROPERTY(bool checked READ checked NOTIFY checkedChanged)
+ Q_PROPERTY(QString tooltip READ tooltip NOTIFY tooltipChanged)
+
+ Q_INVOKABLE void trigger();
+
+ bool available() const;
+ bool checked() const;
+
+ QString actionId() const;
+ void setActionId(const QString &id);
+
+ QString tooltip() const;
+
+signals:
+ void actionIdChanged();
+ void availableChanged();
+ void checkedChanged();
+ void tooltipChanged();
+
+private:
+ void setupNotifier();
+
+ ActionInterface *m_interface = nullptr;
+ QString m_actionId;
+};
+
+class ToolBarBackend : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY navigationHistoryChanged)
+ Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY navigationHistoryChanged)
+ Q_PROPERTY(QStringList documentModel READ documentModel NOTIFY openDocumentsChanged)
+ Q_PROPERTY(int documentIndex READ documentIndex NOTIFY documentIndexChanged)
+ Q_PROPERTY(QString currentWorkspace READ currentWorkspace NOTIFY currentWorkspaceChanged)
+ Q_PROPERTY(QStringList workspaces READ workspaces NOTIFY workspacesChanged)
+ Q_PROPERTY(QStringList styles READ styles CONSTANT)
+ Q_PROPERTY(bool isInDesignMode READ isInDesignMode NOTIFY isInDesignModeChanged)
+ Q_PROPERTY(bool isInEditMode READ isInEditMode NOTIFY isInEditModeChanged)
+ Q_PROPERTY(bool isDesignModeEnabled READ isDesignModeEnabled NOTIFY isDesignModeEnabledChanged)
+ Q_PROPERTY(int currentStyle READ currentStyle NOTIFY currentStyleChanged)
+ Q_PROPERTY(QStringList kits READ kits NOTIFY kitsChanged)
+ Q_PROPERTY(int currentKit READ currentKit NOTIFY currentKitChanged)
+ Q_PROPERTY(bool isQt6 READ isQt6 NOTIFY isQt6Changed)
+ Q_PROPERTY(bool projectOpened READ projectOpened NOTIFY projectOpenedChanged)
+
+public:
+ ToolBarBackend(QObject *parent = nullptr);
+ static void registerDeclarativeType();
+
+ Q_INVOKABLE void triggerModeChange();
+ Q_INVOKABLE void triggerProjectSettings();
+ Q_INVOKABLE void runProject();
+ Q_INVOKABLE void goForward();
+ Q_INVOKABLE void goBackward();
+ Q_INVOKABLE void openFileByIndex(int i);
+ Q_INVOKABLE void closeCurrentDocument();
+ Q_INVOKABLE void shareApplicationOnline();
+ Q_INVOKABLE void setCurrentWorkspace(const QString &workspace);
+ Q_INVOKABLE void editGlobalAnnoation();
+ Q_INVOKABLE void showZoomMenu(int x, int y);
+ Q_INVOKABLE void setCurrentStyle(int index);
+ Q_INVOKABLE void setCurrentKit(int index);
+
+ bool canGoBack() const;
+ bool canGoForward() const;
+
+ QStringList documentModel() const;
+
+ void updateDocumentModel();
+ int documentIndex() const;
+
+ QString currentWorkspace() const;
+ QStringList workspaces() const;
+
+ QStringList styles() const;
+
+ bool isInDesignMode() const;
+ bool isDesignModeEnabled() const;
+ int currentStyle() const;
+
+ QStringList kits() const;
+
+ int currentKit() const;
+
+ bool isQt6() const;
+
+ bool projectOpened() const;
+
+ bool isInEditMode() const;
+
+ static void launchGlobalAnnotations();
+
+signals:
+ void navigationHistoryChanged();
+ void openDocumentsChanged();
+ void documentIndexChanged();
+ void currentWorkspaceChanged();
+ void workspacesChanged();
+ void isInDesignModeChanged();
+ void isInEditModeChanged();
+ void isDesignModeEnabledChanged();
+ void currentStyleChanged();
+ void kitsChanged();
+ void currentKitChanged();
+ void isQt6Changed();
+ void projectOpenedChanged();
+
+private:
+ void setupWorkspaces();
+
+ ActionInterface *m_zoomAction;
+
+ QStringList m_openDocuments;
+ QStringList m_workspaces;
+ QMetaObject::Connection m_kitConnection;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp
index bc050582ad..81d6b9a11b 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditortoolbar.cpp
@@ -83,6 +83,7 @@ TransitionEditorToolBar::TransitionEditorToolBar(QWidget *parent)
: QToolBar(parent)
, m_grp()
{
+ setFixedHeight(Theme::toolbarSize());
setContentsMargins(0, 0, 0, 0);
createLeftControls();
createCenterControls();
@@ -165,7 +166,7 @@ void TransitionEditorToolBar::createLeftControls()
addSpacingToGroup(5);
auto *settingsAction = createAction(TransitionEditorConstants::C_SETTINGS,
- TimelineIcons::ANIMATION.icon(),
+ Theme::iconFromName(Theme::Icon::settings_medium),
tr("Transition Settings"),
QKeySequence(Qt::Key_S));
connect(settingsAction,
@@ -206,7 +207,7 @@ void TransitionEditorToolBar::createCenterControls()
addSpacing(10);
auto *curvePicker = createAction(TransitionEditorConstants::C_CURVE_PICKER,
- TimelineIcons::CURVE_EDITOR.icon(),
+ Theme::iconFromName(Theme::Icon::curveDesigner_medium),
tr("Easing Curve Editor"),
QKeySequence(Qt::Key_C));
@@ -236,7 +237,7 @@ void TransitionEditorToolBar::createRightControls()
addSpacing(10);
auto *zoomOut = createAction(TransitionEditorConstants::C_ZOOM_OUT,
- TimelineIcons::ZOOM_SMALL.icon(),
+ Theme::iconFromName(Theme::Icon::zoomOut_medium),
tr("Zoom Out"),
QKeySequence(QKeySequence::ZoomOut));
@@ -248,6 +249,8 @@ void TransitionEditorToolBar::createRightControls()
addSpacing(10);
m_scale = new QSlider(this);
+ m_scale->setProperty("panelwidget", true);
+ m_scale->setProperty("panelwidget_singlerow", true);
m_scale->setOrientation(Qt::Horizontal);
m_scale->setMaximumWidth(200);
m_scale->setMinimumWidth(100);
@@ -261,7 +264,7 @@ void TransitionEditorToolBar::createRightControls()
addSpacing(10);
auto *zoomIn = createAction(TransitionEditorConstants::C_ZOOM_IN,
- TimelineIcons::ZOOM_BIG.icon(),
+ Theme::iconFromName(Theme::Icon::zoomIn_medium),
tr("Zoom In"),
QKeySequence(QKeySequence::ZoomIn));
@@ -279,6 +282,8 @@ void TransitionEditorToolBar::createRightControls()
auto emitEndChanged = [this]() { emit durationChanged(m_duration->text().toInt()); };
connect(m_duration, &QLineEdit::editingFinished, emitEndChanged);
+
+ addSpacing(5);
}
void TransitionEditorToolBar::addSpacing(int width)
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
index eb183050e4..03ebf4738e 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorview.cpp
@@ -311,7 +311,8 @@ WidgetInfo TransitionEditorView::widgetInfo()
"TransitionEditor",
WidgetInfo::BottomPane,
0,
- tr("Transitions"));
+ tr("Transitions"),
+ tr("Transitions view"));
}
void TransitionEditorView::openSettingsDialog()
diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
index e532c6e741..adbe164201 100644
--- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp
@@ -92,6 +92,9 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
setWindowTitle(tr("Transition", "Title of transition view"));
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ m_toolbar->setStyleSheet(Theme::replaceCssColors(
+ QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
+
const QString css = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
index f1964bf131..ed168b8a09 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
@@ -44,14 +44,30 @@ void AsynchronousExplicitImageCache::request(Utils::SmallStringView name,
const auto id = extraId.empty() ? Utils::PathString{name}
: Utils::PathString::join({name, "+", extraId});
- const auto entry = requestType == RequestType::Image
- ? storage.fetchImage(id, Sqlite::TimeStamp{})
- : storage.fetchSmallImage(id, Sqlite::TimeStamp{});
-
- if (entry && !entry->isNull())
- captureCallback(*entry);
- else
- abortCallback(ImageCache::AbortReason::Failed);
+ auto requestImageFromStorage = [&](RequestType requestType) {
+ switch (requestType) {
+ case RequestType::Image:
+ return storage.fetchImage(id, Sqlite::TimeStamp{});
+ case RequestType::MidSizeImage:
+ return storage.fetchMidSizeImage(id, Sqlite::TimeStamp{});
+ case RequestType::SmallImage:
+ return storage.fetchSmallImage(id, Sqlite::TimeStamp{});
+ default:
+ break;
+ }
+
+ return storage.fetchImage(id, Sqlite::TimeStamp{});
+ };
+ const auto entry = requestImageFromStorage(requestType);
+
+ if (entry) {
+ if (entry->isNull())
+ abortCallback(ImageCache::AbortReason::Failed);
+ else
+ captureCallback(*entry);
+ } else {
+ abortCallback(ImageCache::AbortReason::NoEntry);
+ }
}
void AsynchronousExplicitImageCache::wait()
@@ -75,6 +91,19 @@ void AsynchronousExplicitImageCache::requestImage(Utils::PathString name,
m_condition.notify_all();
}
+void AsynchronousExplicitImageCache::requestMidSizeImage(Utils::PathString name,
+ ImageCache::CaptureImageCallback captureCallback,
+ ImageCache::AbortCallback abortCallback,
+ Utils::SmallString extraId)
+{
+ addEntry(std::move(name),
+ std::move(extraId),
+ std::move(captureCallback),
+ std::move(abortCallback),
+ RequestType::MidSizeImage);
+ m_condition.notify_all();
+}
+
void AsynchronousExplicitImageCache::requestSmallImage(Utils::PathString name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
index 2e6e77b991..dec46f8725 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
@@ -57,8 +57,21 @@ void AsynchronousImageCache::request(Utils::SmallStringView name,
: Utils::PathString::join({name, "+", extraId});
const auto timeStamp = timeStampProvider.timeStamp(name);
- const auto entry = requestType == RequestType::Image ? storage.fetchImage(id, timeStamp)
- : storage.fetchSmallImage(id, timeStamp);
+ auto requestImageFromStorage = [&](RequestType requestType) {
+ switch (requestType) {
+ case RequestType::Image:
+ return storage.fetchImage(id, timeStamp);
+ case RequestType::MidSizeImage:
+ return storage.fetchMidSizeImage(id, timeStamp);
+ case RequestType::SmallImage:
+ return storage.fetchSmallImage(id, timeStamp);
+ default:
+ break;
+ }
+
+ return storage.fetchImage(id, timeStamp);
+ };
+ const auto entry = requestImageFromStorage(requestType);
if (entry) {
if (entry->isNull())
@@ -66,10 +79,28 @@ void AsynchronousImageCache::request(Utils::SmallStringView name,
else
captureCallback(*entry);
} else {
- auto callback = [captureCallback = std::move(captureCallback),
- requestType](const QImage &image, const QImage &smallImage) {
- captureCallback(requestType == RequestType::Image ? image : smallImage);
- };
+ auto callback =
+ [captureCallback = std::move(captureCallback),
+ requestType](const QImage &image, const QImage &midSizeImage, const QImage &smallImage) {
+ auto selectImage = [](RequestType requestType,
+ const QImage &image,
+ const QImage &midSizeImage,
+ const QImage &smallImage) {
+ switch (requestType) {
+ case RequestType::Image:
+ return image;
+ case RequestType::MidSizeImage:
+ return midSizeImage;
+ case RequestType::SmallImage:
+ return smallImage;
+ default:
+ break;
+ }
+
+ return image;
+ };
+ captureCallback(selectImage(requestType, image, midSizeImage, smallImage));
+ };
generator.generateImage(name,
extraId,
timeStamp,
@@ -102,6 +133,21 @@ void AsynchronousImageCache::requestImage(Utils::PathString name,
m_condition.notify_all();
}
+void AsynchronousImageCache::requestMidSizeImage(Utils::PathString name,
+ ImageCache::CaptureImageCallback captureCallback,
+ ImageCache::AbortCallback abortCallback,
+ Utils::SmallString extraId,
+ ImageCache::AuxiliaryData auxiliaryData)
+{
+ addEntry(std::move(name),
+ std::move(extraId),
+ std::move(captureCallback),
+ std::move(abortCallback),
+ std::move(auxiliaryData),
+ RequestType::MidSizeImage);
+ m_condition.notify_all();
+}
+
void AsynchronousImageCache::requestSmallImage(Utils::PathString name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
index 2807196f43..500359182a 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
@@ -99,8 +99,8 @@ void AsynchronousImageFactory::request(Utils::SmallStringView name,
if (currentModifiedTime < (storageModifiedTime + pause))
return;
- auto capture = [=](const QImage &image, const QImage &smallImage) {
- m_storage.storeImage(id, currentModifiedTime, image, smallImage);
+ auto capture = [=](const QImage &image, const QImage &midSizeImage, const QImage &smallImage) {
+ m_storage.storeImage(id, currentModifiedTime, image, midSizeImage, smallImage);
};
collector.start(name,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
index a1bd876cfd..1f28d4eca6 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
@@ -2,51 +2,23 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "explicitimagecacheimageprovider.h"
+#include "imagecacheimageresponse.h"
#include <asynchronousexplicitimagecache.h>
#include <QMetaObject>
#include <QQuickImageResponse>
-namespace {
-
-class ImageResponse : public QQuickImageResponse
-{
-public:
- ImageResponse(const QImage &defaultImage)
- : m_image(defaultImage)
- {}
-
- QQuickTextureFactory *textureFactory() const override
- {
- return QQuickTextureFactory::textureFactoryForImage(m_image);
- }
-
- void setImage(const QImage &image)
- {
- m_image = image;
-
- emit finished();
- }
-
- void abort() { emit finished(); }
-
-private:
- QImage m_image;
-};
-
-} // namespace
-
namespace QmlDesigner {
QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const QString &id,
const QSize &)
{
- auto response = std::make_unique<::ImageResponse>(m_defaultImage);
+ auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
m_cache.requestImage(
id,
- [response = QPointer<::ImageResponse>(response.get())](const QImage &image) {
+ [response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
[response, image] {
@@ -55,15 +27,20 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const
},
Qt::QueuedConnection);
},
- [response = QPointer<::ImageResponse>(response.get())](ImageCache::AbortReason abortReason) {
+ [response = QPointer<ImageCacheImageResponse>(response.get()),
+ failedImage = m_failedImage](ImageCache::AbortReason abortReason) {
QMetaObject::invokeMethod(
response,
- [response, abortReason] {
+ [response, abortReason, failedImage] {
switch (abortReason) {
- case ImageCache::AbortReason::Failed:
+ case ImageCache::AbortReason::NoEntry:
if (response)
response->abort();
break;
+ case ImageCache::AbortReason::Failed:
+ if (response)
+ response->setImage(failedImage);
+ break;
case ImageCache::AbortReason::Abort:
response->cancel();
break;
diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.h b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.h
index 54a0df652e..bef22d68a7 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.h
@@ -14,9 +14,11 @@ class ExplicitImageCacheImageProvider : public QQuickAsyncImageProvider
{
public:
ExplicitImageCacheImageProvider(AsynchronousExplicitImageCache &imageCache,
- const QImage &defaultImage)
+ const QImage &defaultImage,
+ const QImage &failedImage)
: m_cache(imageCache)
, m_defaultImage(defaultImage)
+ , m_failedImage(failedImage)
{}
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
@@ -24,6 +26,7 @@ public:
private:
AsynchronousExplicitImageCache &m_cache;
QImage m_defaultImage;
+ QImage m_failedImage;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
index 8bc1698524..344bd4a019 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp
@@ -53,6 +53,22 @@ ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connection
ImageCacheCollector::~ImageCacheCollector() = default;
+namespace {
+QImage scaleImage(const QImage &image, QSize targetSize)
+{
+ if (image.isNull())
+ return {};
+
+ const qreal ratio = qGuiApp->devicePixelRatio();
+ if (ratio > 1.0)
+ targetSize *= qRound(ratio);
+ QSize scaledImageSize = image.size().scaled(targetSize.boundedTo(image.size()),
+ Qt::KeepAspectRatio);
+ return image.scaled(scaledImageSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+}
+} // namespace
+
void ImageCacheCollector::start(Utils::SmallStringView name,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &auxiliaryData,
@@ -104,17 +120,9 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
auto callback = [=, captureCallback = std::move(captureCallback)](const QImage &image) {
if (nullImageHandling == ImageCacheCollectorNullImageHandling::CaptureNullImage
|| !image.isNull()) {
- QSize targetSize {96, 96};
- const qreal ratio = qGuiApp->devicePixelRatio();
- if (ratio > 1.0)
- targetSize *= qRound(ratio);
- QSize smallImageSize = image.size().scaled(targetSize.boundedTo(image.size()),
- Qt::KeepAspectRatio);
- QImage smallImage = image.isNull() ? QImage{}
- : image.scaled(smallImageSize,
- Qt::IgnoreAspectRatio,
- Qt::SmoothTransformation);
- captureCallback(image, smallImage);
+ QImage midSizeImage = scaleImage(image, QSize{300, 300});
+ QImage smallImage = scaleImage(midSizeImage, QSize{96, 96});
+ captureCallback(image, midSizeImage, smallImage);
}
};
@@ -138,9 +146,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
abortCallback(ImageCache::AbortReason::Failed);
}
-std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView,
- Utils::SmallStringView,
- const ImageCache::AuxiliaryData &)
+ImageCacheCollectorInterface::ImageTuple ImageCacheCollector::createImage(
+ Utils::SmallStringView, Utils::SmallStringView, const ImageCache::AuxiliaryData &)
{
return {};
}
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
index 753d92a37d..87ebedba04 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h
@@ -43,9 +43,9 @@ public:
CaptureCallback captureCallback,
AbortCallback abortCallback) override;
- std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
- Utils::SmallStringView state,
- const ImageCache::AuxiliaryData &auxiliaryData) override;
+ ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData) override;
QIcon createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView state,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollectorinterface.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollectorinterface.h
index 888fd281a0..057ab6f03e 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollectorinterface.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollectorinterface.h
@@ -14,9 +14,9 @@ namespace QmlDesigner {
class ImageCacheCollectorInterface
{
public:
- using CaptureCallback = ImageCache::CaptureImageWithSmallImageCallback;
+ using CaptureCallback = ImageCache::CaptureImageWithScaledImagesCallback;
using AbortCallback = ImageCache::AbortCallback;
- using ImagePair = std::pair<QImage, QImage>;
+ using ImageTuple = std::tuple<QImage, QImage, QImage>;
virtual void start(Utils::SmallStringView filePath,
Utils::SmallStringView extraId,
@@ -25,9 +25,9 @@ public:
AbortCallback abortCallback)
= 0;
- virtual ImagePair createImage(Utils::SmallStringView filePath,
- Utils::SmallStringView extraId,
- const ImageCache::AuxiliaryData &auxiliaryData)
+ virtual ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView extraId,
+ const ImageCache::AuxiliaryData &auxiliaryData)
= 0;
virtual QIcon createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView extraId,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachedispatchcollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachedispatchcollector.h
index ece8aa3480..274cf72ad6 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachedispatchcollector.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachedispatchcollector.h
@@ -32,9 +32,9 @@ public:
m_collectors);
}
- std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
- Utils::SmallStringView state,
- const ImageCache::AuxiliaryData &auxiliaryData) override
+ ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData) override
{
return std::apply(
[&](const auto &...entries) {
@@ -84,9 +84,10 @@ private:
Utils::SmallStringView,
const ImageCache::AuxiliaryData &,
CaptureCallback,
- AbortCallback)
+ AbortCallback abortCallback)
{
qWarning() << "ImageCacheDispatchCollector: cannot handle file type.";
+ abortCallback(ImageCache::AbortReason::Failed);
}
template<typename Collector, typename... Collectors>
@@ -113,11 +114,11 @@ private:
}
template<typename Collector, typename... Collectors>
- std::pair<QImage, QImage> dispatchCreateImage(Utils::SmallStringView filePath,
- Utils::SmallStringView state,
- const ImageCache::AuxiliaryData &auxiliaryData,
- const Collector &collector,
- const Collectors &...collectors)
+ ImageTuple dispatchCreateImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData,
+ const Collector &collector,
+ const Collectors &...collectors)
{
if (collector.first(filePath, state, auxiliaryData)) {
return collector.second->createImage(filePath, state, auxiliaryData);
@@ -126,9 +127,9 @@ private:
return dispatchCreateImage(filePath, state, auxiliaryData, collectors...);
}
- std::pair<QImage, QImage> dispatchCreateImage(Utils::SmallStringView,
- Utils::SmallStringView,
- const ImageCache::AuxiliaryData &)
+ ImageTuple dispatchCreateImage(Utils::SmallStringView,
+ Utils::SmallStringView,
+ const ImageCache::AuxiliaryData &)
{
qWarning() << "ImageCacheDispatchCollector: cannot handle file type.";
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.cpp
index fb621411b5..d3363e2d63 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.cpp
@@ -106,14 +106,14 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
QImage image = createFontImage(text, textColor, font, size);
if (!image.isNull()) {
- captureCallback(std::move(image), {});
+ captureCallback(std::move(image), {}, {});
return;
}
}
abortCallback(ImageCache::AbortReason::Failed);
}
-std::pair<QImage, QImage> ImageCacheFontCollector::createImage(
+ImageCacheCollectorInterface::ImageTuple ImageCacheFontCollector::createImage(
Utils::SmallStringView name,
Utils::SmallStringView,
const ImageCache::AuxiliaryData &auxiliaryDataValue)
@@ -128,7 +128,7 @@ std::pair<QImage, QImage> ImageCacheFontCollector::createImage(
QImage image = createFontImage(text, textColor, font, size);
if (!image.isNull())
- return {image, {}};
+ return {image, {}, {}};
}
return {};
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.h
index 2129c80307..ff7f624e22 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachefontcollector.h
@@ -20,9 +20,9 @@ public:
CaptureCallback captureCallback,
AbortCallback abortCallback) override;
- std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
- Utils::SmallStringView extraId,
- const ImageCache::AuxiliaryData &auxiliaryData) override;
+ ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView extraId,
+ const ImageCache::AuxiliaryData &auxiliaryData) override;
QIcon createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView extraId,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.cpp
index 5e1fe49ea0..42aef4fd20 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.cpp
@@ -28,7 +28,7 @@ ImageCacheGenerator::~ImageCacheGenerator()
void ImageCacheGenerator::generateImage(Utils::SmallStringView name,
Utils::SmallStringView extraId,
Sqlite::TimeStamp timeStamp,
- ImageCache::CaptureImageWithSmallImageCallback &&captureCallback,
+ ImageCache::CaptureImageWithScaledImagesCallback &&captureCallback,
ImageCache::AbortCallback &&abortCallback,
ImageCache::AuxiliaryData &&auxiliaryData)
{
@@ -113,21 +113,26 @@ void ImageCacheGenerator::startGeneration()
task.filePath,
task.extraId,
std::move(task.auxiliaryData),
- [this, task](const QImage &image, const QImage &smallImage) {
- if (image.isNull())
+ [this, task](const QImage &image, const QImage &midSizeImage, const QImage &smallImage) {
+ if (image.isNull() && midSizeImage.isNull() && smallImage.isNull())
callCallbacks(task.abortCallbacks, ImageCache::AbortReason::Failed);
else
- callCallbacks(task.captureCallbacks, image, smallImage);
+ callCallbacks(task.captureCallbacks, image, midSizeImage, smallImage);
m_storage.storeImage(createId(task.filePath, task.extraId),
task.timeStamp,
image,
+ midSizeImage,
smallImage);
},
[this, task](ImageCache::AbortReason abortReason) {
callCallbacks(task.abortCallbacks, abortReason);
if (abortReason != ImageCache::AbortReason::Abort)
- m_storage.storeImage(createId(task.filePath, task.extraId), task.timeStamp, {}, {});
+ m_storage.storeImage(createId(task.filePath, task.extraId),
+ task.timeStamp,
+ {},
+ {},
+ {});
});
std::lock_guard lock{m_mutex};
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.h
index 5999a2558b..60d8195926 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachegenerator.h
@@ -33,7 +33,7 @@ public:
void generateImage(Utils::SmallStringView filePath,
Utils::SmallStringView extraId,
Sqlite::TimeStamp timeStamp,
- ImageCache::CaptureImageWithSmallImageCallback &&captureCallback,
+ ImageCache::CaptureImageWithScaledImagesCallback &&captureCallback,
ImageCache::AbortCallback &&abortCallback,
ImageCache::AuxiliaryData &&auxiliaryData) override;
void clean() override;
@@ -48,7 +48,7 @@ private:
Utils::SmallStringView extraId,
ImageCache::AuxiliaryData &&auxiliaryData,
Sqlite::TimeStamp timeStamp,
- ImageCache::CaptureImageWithSmallImageCallback &&captureCallback,
+ ImageCache::CaptureImageWithScaledImagesCallback &&captureCallback,
ImageCache::AbortCallback &&abortCallback)
: filePath(filePath)
, extraId(std::move(extraId))
@@ -61,7 +61,7 @@ private:
Utils::PathString filePath;
Utils::SmallString extraId;
ImageCache::AuxiliaryData auxiliaryData;
- std::vector<ImageCache::CaptureImageWithSmallImageCallback> captureCallbacks;
+ std::vector<ImageCache::CaptureImageWithScaledImagesCallback> captureCallbacks;
std::vector<ImageCache::AbortCallback> abortCallbacks;
Sqlite::TimeStamp timeStamp;
};
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachegeneratorinterface.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachegeneratorinterface.h
index 815fb8cc81..d18f0def32 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachegeneratorinterface.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachegeneratorinterface.h
@@ -17,7 +17,7 @@ public:
virtual void generateImage(Utils::SmallStringView name,
Utils::SmallStringView extraId,
Sqlite::TimeStamp timeStamp,
- ImageCache::CaptureImageWithSmallImageCallback &&captureCallback,
+ ImageCache::CaptureImageWithScaledImagesCallback &&captureCallback,
ImageCache::AbortCallback &&abortCallback,
ImageCache::AuxiliaryData &&auxiliaryData)
= 0;
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.cpp
new file mode 100644
index 0000000000..38fc9491d2
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "imagecacheimageresponse.h"
+
+namespace QmlDesigner {
+
+QQuickTextureFactory *ImageCacheImageResponse::textureFactory() const
+{
+ return QQuickTextureFactory::textureFactoryForImage(m_image);
+}
+
+void ImageCacheImageResponse::setImage(const QImage &image)
+{
+ m_image = image;
+
+ emit finished();
+}
+
+void ImageCacheImageResponse::abort()
+{
+ emit finished();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.h b/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.h
new file mode 100644
index 0000000000..1a4400e989
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecacheimageresponse.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QQuickImageResponse>
+
+namespace QmlDesigner {
+
+class AsynchronousImageCache;
+
+class ImageCacheImageResponse : public QQuickImageResponse
+{
+public:
+ ImageCacheImageResponse(const QImage &defaultImage = {})
+ : m_image(defaultImage)
+ {}
+
+ QQuickTextureFactory *textureFactory() const override;
+
+ void setImage(const QImage &image);
+ QImage image() const { return m_image; }
+
+ void abort();
+
+private:
+ QImage m_image;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
index fb81a3405e..6b0df6f1c1 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
@@ -51,6 +51,26 @@ public:
}
}
+ ImageEntry fetchMidSizeImage(Utils::SmallStringView name,
+ Sqlite::TimeStamp minimumTimeStamp) const override
+ {
+ try {
+ Sqlite::DeferredTransaction transaction{database};
+
+ auto optionalBlob = selectMidSizeImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
+ name, minimumTimeStamp.value);
+
+ transaction.commit();
+
+ if (optionalBlob)
+ return {readImage(optionalBlob->byteArray)};
+
+ return {};
+ } catch (const Sqlite::StatementIsBusy &) {
+ return fetchMidSizeImage(name, minimumTimeStamp);
+ }
+ }
+
ImageEntry fetchSmallImage(Utils::SmallStringView name,
Sqlite::TimeStamp minimumTimeStamp) const override
{
@@ -95,22 +115,25 @@ public:
void storeImage(Utils::SmallStringView name,
Sqlite::TimeStamp newTimeStamp,
const QImage &image,
+ const QImage &midSizeImage,
const QImage &smallImage) override
{
try {
Sqlite::ImmediateTransaction transaction{database};
auto imageBuffer = createBuffer(image);
+ auto midSizeImageBuffer = createBuffer(midSizeImage);
auto smallImageBuffer = createBuffer(smallImage);
upsertImageStatement.write(name,
newTimeStamp.value,
createBlobView(imageBuffer.get()),
+ createBlobView(midSizeImageBuffer.get()),
createBlobView(smallImageBuffer.get()));
transaction.commit();
} catch (const Sqlite::StatementIsBusy &) {
- return storeImage(name, newTimeStamp, image, smallImage);
+ return storeImage(name, newTimeStamp, image, midSizeImage, smallImage);
}
}
@@ -158,12 +181,15 @@ private:
Sqlite::ExclusiveTransaction transaction{database};
createImagesTable(database);
+ database.setVersion(1);
transaction.commit();
database.setIsInitialized(true);
database.walCheckpointFull();
+ } else if (database.version() < 1) {
+ updateTableToVersion1(database);
}
}
@@ -179,6 +205,7 @@ private:
imageTable.addColumn("mtime", Sqlite::ColumnType::Integer);
imageTable.addColumn("image", Sqlite::ColumnType::Blob);
imageTable.addColumn("smallImage", Sqlite::ColumnType::Blob);
+ imageTable.addColumn("midSizeImage", Sqlite::ColumnType::Blob);
imageTable.initialize(database);
@@ -194,6 +221,17 @@ private:
iconTable.initialize(database);
}
+
+ void updateTableToVersion1(DatabaseType &database)
+ {
+ Sqlite::ExclusiveTransaction transaction{database};
+
+ database.execute("DELETE FROM images");
+ database.execute("ALTER TABLE images ADD COLUMN midSizeImage");
+ database.setVersion(1);
+
+ transaction.commit();
+ }
};
Sqlite::BlobView createBlobView(QBuffer *buffer)
@@ -264,14 +302,17 @@ public:
Sqlite::ImmediateNonThrowingDestructorTransaction<DatabaseType> transaction{database};
mutable ReadStatement<1, 2> selectImageStatement{
"SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database};
+ mutable ReadStatement<1, 2> selectMidSizeImageStatement{
+ "SELECT midSizeImage FROM images WHERE name=?1 AND mtime >= ?2", database};
mutable ReadStatement<1, 2> selectSmallImageStatement{
"SELECT smallImage FROM images WHERE name=?1 AND mtime >= ?2", database};
mutable ReadStatement<1, 2> selectIconStatement{
"SELECT icon FROM icons WHERE name=?1 AND mtime >= ?2", database};
- WriteStatement<4> upsertImageStatement{
- "INSERT INTO images(name, mtime, image, smallImage) VALUES (?1, ?2, ?3, ?4) ON "
- "CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, image=excluded.image, "
- "smallImage=excluded.smallImage",
+ WriteStatement<5> upsertImageStatement{
+ "INSERT INTO images(name, mtime, image, midSizeImage, smallImage) "
+ "VALUES (?1, ?2, ?3, ?4, ?5) "
+ "ON CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, image=excluded.image, "
+ "midSizeImage=excluded.midSizeImage, smallImage=excluded.smallImage",
database};
WriteStatement<3> upsertIconStatement{
"INSERT INTO icons(name, mtime, icon) VALUES (?1, ?2, ?3) ON "
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorageinterface.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorageinterface.h
index c25cc9db75..4a2ff0944c 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorageinterface.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorageinterface.h
@@ -21,6 +21,8 @@ public:
virtual ImageEntry fetchImage(Utils::SmallStringView name,
Sqlite::TimeStamp minimumTimeStamp) const = 0;
+ virtual ImageEntry fetchMidSizeImage(Utils::SmallStringView name,
+ Sqlite::TimeStamp minimumTimeStamp) const = 0;
virtual ImageEntry fetchSmallImage(Utils::SmallStringView name,
Sqlite::TimeStamp minimumTimeStamp) const = 0;
virtual IconEntry fetchIcon(Utils::SmallStringView name,
@@ -28,6 +30,7 @@ public:
virtual void storeImage(Utils::SmallStringView name,
Sqlite::TimeStamp newTimeStamp,
const QImage &image,
+ const QImage &midSizeImage,
const QImage &smallImage)
= 0;
virtual void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) = 0;
diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp
index 12c05c4e6f..2063de8f3a 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.cpp
@@ -66,9 +66,8 @@ void MeshImageCacheCollector::start(Utils::SmallStringView name,
m_imageCacheCollector.start(path, state, auxiliaryData, captureCallback, abortCallback);
}
-std::pair<QImage, QImage> MeshImageCacheCollector::createImage(Utils::SmallStringView,
- Utils::SmallStringView,
- const ImageCache::AuxiliaryData &)
+ImageCacheCollectorInterface::ImageTuple MeshImageCacheCollector::createImage(
+ Utils::SmallStringView, Utils::SmallStringView, const ImageCache::AuxiliaryData &)
{
return {};
}
diff --git a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h
index 6c669d246b..17b1a412bc 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/meshimagecachecollector.h
@@ -31,9 +31,9 @@ public:
CaptureCallback captureCallback,
AbortCallback abortCallback) override;
- std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
- Utils::SmallStringView state,
- const ImageCache::AuxiliaryData &auxiliaryData) override;
+ ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData) override;
QIcon createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView state,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp
new file mode 100644
index 0000000000..fd37f02f04
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "midsizeimagecacheprovider.h"
+#include "imagecacheimageresponse.h"
+
+#include <asynchronousimagecache.h>
+
+#include <QMetaObject>
+
+namespace QmlDesigner {
+
+QQuickImageResponse *MidSizeImageCacheProvider::requestImageResponse(const QString &id, const QSize &)
+{
+ auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
+
+ m_cache.requestMidSizeImage(
+ id,
+ [response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
+ QMetaObject::invokeMethod(
+ response,
+ [response, image] {
+ if (response)
+ response->setImage(image);
+ },
+ Qt::QueuedConnection);
+ },
+ [response = QPointer<ImageCacheImageResponse>(response.get())](
+ ImageCache::AbortReason abortReason) {
+ QMetaObject::invokeMethod(
+ response,
+ [response, abortReason] {
+ switch (abortReason) {
+ case ImageCache::AbortReason::Failed:
+ case ImageCache::AbortReason::NoEntry:
+ if (response)
+ response->abort();
+ break;
+ case ImageCache::AbortReason::Abort:
+ response->cancel();
+ break;
+ }
+ },
+ Qt::QueuedConnection);
+ });
+
+ return response.release();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h
new file mode 100644
index 0000000000..b3a84f0abd
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QQuickAsyncImageProvider>
+
+namespace QmlDesigner {
+
+class AsynchronousImageCache;
+
+class MidSizeImageCacheProvider : public QQuickAsyncImageProvider
+{
+public:
+ MidSizeImageCacheProvider(AsynchronousImageCache &imageCache, const QImage &defaultImage = {})
+ : m_cache{imageCache}
+ , m_defaultImage(defaultImage)
+ {}
+
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
+ QImage defaultImage() const { return m_defaultImage; }
+
+private:
+ AsynchronousImageCache &m_cache;
+ QImage m_defaultImage;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
index d0860054ca..3fae3bb175 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
@@ -3,36 +3,21 @@
#include "smallimagecacheprovider.h"
+#include "imagecacheimageresponse.h"
+
#include <asynchronousimagecache.h>
#include <QMetaObject>
namespace QmlDesigner {
-QQuickTextureFactory *ImageResponse::textureFactory() const
-{
- return QQuickTextureFactory::textureFactoryForImage(m_image);
-}
-
-void ImageResponse::setImage(const QImage &image)
-{
- m_image = image;
-
- emit finished();
-}
-
-void ImageResponse::abort()
-{
- emit finished();
-}
-
QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString &id, const QSize &)
{
- auto response = std::make_unique<QmlDesigner::ImageResponse>(m_defaultImage);
+ auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
m_cache.requestSmallImage(
id,
- [response = QPointer<QmlDesigner::ImageResponse>(response.get())](const QImage &image) {
+ [response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
[response, image] {
@@ -41,13 +26,14 @@ QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString
},
Qt::QueuedConnection);
},
- [response = QPointer<QmlDesigner::ImageResponse>(response.get())](
+ [response = QPointer<ImageCacheImageResponse>(response.get())](
ImageCache::AbortReason abortReason) {
QMetaObject::invokeMethod(
response,
[response, abortReason] {
switch (abortReason) {
case ImageCache::AbortReason::Failed:
+ case ImageCache::AbortReason::NoEntry:
if (response)
response->abort();
break;
diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h
index 03e0d089a1..40b542ebe4 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.h
@@ -4,30 +4,11 @@
#pragma once
#include <QQuickAsyncImageProvider>
-#include <QQuickImageResponse>
namespace QmlDesigner {
class AsynchronousImageCache;
-class ImageResponse : public QQuickImageResponse
-{
-public:
- ImageResponse(const QImage &defaultImage)
- : m_image(defaultImage)
- {}
-
- QQuickTextureFactory *textureFactory() const override;
-
- void setImage(const QImage &image);
- QImage image() const { return m_image; }
-
- void abort();
-
-private:
- QImage m_image;
-};
-
class SmallImageCacheProvider : public QQuickAsyncImageProvider
{
public:
diff --git a/src/plugins/qmldesigner/designercore/imagecache/synchronousimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/synchronousimagecache.cpp
index ddb1cba666..e9a07b2b31 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/synchronousimagecache.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/synchronousimagecache.cpp
@@ -32,13 +32,36 @@ QImage SynchronousImageCache::image(Utils::PathString filePath,
if (entry)
return *entry;
- const auto &[image, smallImage] = m_collector.createImage(filePath, extraId, auxiliaryData);
+ const auto &[image, midSizeImage, smallImage] = m_collector.createImage(filePath,
+ extraId,
+ auxiliaryData);
- m_storage.storeImage(id, timeStamp, image, smallImage);
+ m_storage.storeImage(id, timeStamp, image, midSizeImage, smallImage);
return image;
}
+QImage SynchronousImageCache::midSizeImage(Utils::PathString filePath,
+ Utils::SmallString extraId,
+ const ImageCache::AuxiliaryData &auxiliaryData)
+{
+ const auto id = createId(filePath, extraId);
+
+ const auto timeStamp = m_timeStampProvider.timeStamp(filePath);
+ const auto entry = m_storage.fetchMidSizeImage(id, timeStamp);
+
+ if (entry)
+ return *entry;
+
+ const auto &[image, midSizeImage, smallImage] = m_collector.createImage(filePath,
+ extraId,
+ auxiliaryData);
+
+ m_storage.storeImage(id, timeStamp, image, midSizeImage, smallImage);
+
+ return midSizeImage;
+}
+
QImage SynchronousImageCache::smallImage(Utils::PathString filePath,
Utils::SmallString extraId,
const ImageCache::AuxiliaryData &auxiliaryData)
@@ -51,9 +74,11 @@ QImage SynchronousImageCache::smallImage(Utils::PathString filePath,
if (entry)
return *entry;
- const auto &[image, smallImage] = m_collector.createImage(filePath, extraId, auxiliaryData);
+ const auto &[image, midSizeImage, smallImage] = m_collector.createImage(filePath,
+ extraId,
+ auxiliaryData);
- m_storage.storeImage(id, timeStamp, image, smallImage);
+ m_storage.storeImage(id, timeStamp, image, midSizeImage, smallImage);
return smallImage;
}
diff --git a/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.cpp
new file mode 100644
index 0000000000..af310ae6e7
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "textureimagecachecollector.h"
+
+#include <utils/asset.h>
+#include <utils/hdrimage.h>
+#include <utils/smallstring.h>
+#include <utils/stylehelper.h>
+
+namespace QmlDesigner {
+
+TextureImageCacheCollector::TextureImageCacheCollector() = default;
+TextureImageCacheCollector::~TextureImageCacheCollector() = default;
+
+void TextureImageCacheCollector::start(Utils::SmallStringView name,
+ Utils::SmallStringView,
+ const ImageCache::AuxiliaryData &,
+ CaptureCallback captureCallback,
+ AbortCallback abortCallback)
+{
+ Asset asset {QString(name)};
+ QImage image;
+
+ if (asset.isImage()) {
+ image = QImage(Utils::StyleHelper::dpiSpecificImageFile(asset.id()));
+ } else if (asset.isHdrFile()) {
+ HdrImage hdr{asset.id()};
+ if (!hdr.image().isNull())
+ image = hdr.image().copy(); // Copy to ensure image data survives HdrImage destruction
+ }
+
+ if (image.isNull())
+ abortCallback(ImageCache::AbortReason::Failed);
+ else
+ image = image.scaled(QSize{300, 300}, Qt::KeepAspectRatio);
+
+ captureCallback({}, image, {});
+}
+
+ImageCacheCollectorInterface::ImageTuple TextureImageCacheCollector::createImage(
+ Utils::SmallStringView, Utils::SmallStringView, const ImageCache::AuxiliaryData &)
+{
+ return {};
+}
+
+QIcon TextureImageCacheCollector::createIcon(Utils::SmallStringView,
+ Utils::SmallStringView,
+ const ImageCache::AuxiliaryData &)
+{
+ return {};
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.h
new file mode 100644
index 0000000000..67876d7641
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/imagecache/textureimagecachecollector.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "imagecachecollectorinterface.h"
+
+namespace QmlDesigner {
+
+class TextureImageCacheCollector final : public ImageCacheCollectorInterface
+{
+public:
+ TextureImageCacheCollector();
+ ~TextureImageCacheCollector();
+
+ void start(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData,
+ CaptureCallback captureCallback,
+ AbortCallback abortCallback) override;
+
+ ImageTuple createImage(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData) override;
+
+ QIcon createIcon(Utils::SmallStringView filePath,
+ Utils::SmallStringView state,
+ const ImageCache::AuxiliaryData &auxiliaryData) override;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 8f18da1544..2d886d959b 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -3,43 +3,35 @@
#pragma once
-#include <qmldesignercorelib_global.h>
-
-#include <model.h>
-#include <modelnode.h>
-#include <abstractproperty.h>
-#include <documentmessage.h>
-#include <rewritertransaction.h>
+#include "model.h"
+#include "modelnode.h"
+#include "qmldesignercorelib_global.h"
#include <commondefines.h>
#include <QObject>
#include <QPointer>
-#include <QVector3D>
-
-#include <functional>
-#include <memory>
QT_BEGIN_NAMESPACE
-class QStyle;
-class QToolButton;
class QImage;
class QPixmap;
+class QVector3D;
QT_END_NAMESPACE
namespace QmlDesigner {
- namespace Internal {
- class InternalNode;
- using InternalNodePointer = std::shared_ptr<InternalNode>;
- }
-}
-
-namespace QmlDesigner {
+class AbstractProperty;
+class DocumentMessage;
+class ExternalDependenciesInterface;
class NodeInstanceView;
-class RewriterView;
class QmlModelState;
class QmlTimeline;
-class ExternalDependenciesInterface;
+class RewriterTransaction;
+class RewriterView;
+
+namespace Internal {
+class InternalNode;
+using InternalNodePointer = std::shared_ptr<InternalNode>;
+}
enum DesignerWidgetFlags {
DisableOnError,
@@ -60,6 +52,7 @@ public:
QString uniqueId;
QString tabName;
+ QString feedbackDisplayName;
QWidget *widget = nullptr;
int placementPriority;
PlacementHint placementHint;
@@ -74,18 +67,19 @@ public:
Q_FLAGS(PropertyChangeFlag PropertyChangeFlags)
enum PropertyChangeFlag {
- NoAdditionalChanges = 0x0,
- PropertiesAdded = 0x1,
+ NoAdditionalChanges = 0x0,
+ PropertiesAdded = 0x1,
EmptyPropertiesRemoved = 0x2
};
Q_DECLARE_FLAGS(PropertyChangeFlags, PropertyChangeFlag)
+
AbstractView(ExternalDependenciesInterface &externalDependencies)
: m_externalDependencies{externalDependencies}
{}
~AbstractView() override;
- Model* model() const;
+ Model *model() const;
bool isAttached() const;
RewriterTransaction beginRewriterTransaction(const QByteArray &identifier);
@@ -127,7 +121,7 @@ public:
QList<ModelNode> allModelNodes() const;
QList<ModelNode> allModelNodesOfType(const NodeMetaInfo &typeName) const;
- void emitDocumentMessage(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings = QList<DocumentMessage>());
+ void emitDocumentMessage(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings = {});
void emitDocumentMessage(const QString &error);
void emitCustomNotification(const QString &identifier);
void emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList);
@@ -155,19 +149,25 @@ public:
virtual void nodeCreated(const ModelNode &createdNode);
virtual void nodeAboutToBeRemoved(const ModelNode &removedNode);
- virtual void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange);
- virtual void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
- virtual void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
- virtual void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
- virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList);
- virtual void propertiesRemoved(const QList<AbstractProperty>& propertyList);
- virtual void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange);
+ virtual void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty,
+ PropertyChangeFlags propertyChange);
+ virtual void nodeAboutToBeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent,
+ const NodeAbstractProperty &oldPropertyParent, PropertyChangeFlags propertyChange);
+ virtual void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent,
+ const NodeAbstractProperty &oldPropertyParent, PropertyChangeFlags propertyChange);
+ virtual void nodeIdChanged(const ModelNode &node, const QString &newId, const QString &oldId);
+ virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList);
+ virtual void propertiesRemoved(const QList<AbstractProperty> &propertyList);
+ virtual void variantPropertiesChanged(const QList<VariantProperty> &propertyList,
+ PropertyChangeFlags propertyChange);
virtual void bindingPropertiesAboutToBeChanged(const QList<BindingProperty> &propertyList);
- virtual void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange);
- virtual void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange);
- virtual void signalDeclarationPropertiesChanged(const QVector<SignalDeclarationProperty>& propertyList, PropertyChangeFlags propertyChange);
+ virtual void bindingPropertiesChanged(const QList<BindingProperty> &propertyList, PropertyChangeFlags propertyChange);
+ virtual void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &propertyList,
+ PropertyChangeFlags propertyChange);
+ virtual void signalDeclarationPropertiesChanged(const QVector<SignalDeclarationProperty> &propertyList,
+ PropertyChangeFlags propertyChange);
virtual void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion);
- virtual void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion);
+ virtual void nodeTypeChanged(const ModelNode &node, const TypeName &type, int majorVersion, int minorVersion);
virtual void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList);
virtual void instanceErrorChanged(const QVector<ModelNode> &errorNodeList);
@@ -228,8 +228,8 @@ public:
void ensureMaterialLibraryNode();
ModelNode materialLibraryNode();
+ bool isPartOfMaterialLibrary(const ModelNode &node);
ModelNode active3DSceneNode();
- void assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode = {});
ModelNode getTextureDefaultInstance(const QString &source);
const NodeInstanceView *nodeInstanceView() const;
@@ -244,7 +244,6 @@ public:
int minorQtQuickVersion() const;
void resetView();
-
void resetPuppet();
virtual bool hasWidget() const;
@@ -286,16 +285,18 @@ public:
protected:
void setModel(Model *model);
void removeModel();
- static WidgetInfo createWidgetInfo(QWidget *widget = nullptr,
- const QString &uniqueId = QString(),
- WidgetInfo::PlacementHint placementHint = WidgetInfo::NoPane,
- int placementPriority = 0,
- const QString &tabName = QString(), DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError);
+ static WidgetInfo createWidgetInfo(
+ QWidget *widget = nullptr,
+ const QString &uniqueId = QString(),
+ WidgetInfo::PlacementHint placementHint = WidgetInfo::NoPane,
+ int placementPriority = 0,
+ const QString &tabName = QString(),
+ const QString &feedbackDisplayName = QString(),
+ DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError);
-private: //functions
+private:
QList<ModelNode> toModelNodeList(const QList<Internal::InternalNodePointer> &nodeList) const;
-private:
QPointer<Model> m_model;
ExternalDependenciesInterface &m_externalDependencies;
bool m_enabled = true;
@@ -304,5 +305,4 @@ private:
QMLDESIGNERCORE_EXPORT QList<Internal::InternalNodePointer> toInternalNodeList(const QList<ModelNode> &nodeList);
QMLDESIGNERCORE_EXPORT QList<ModelNode> toModelNodeList(const QList<Internal::InternalNodePointer> &nodeList, AbstractView *view);
-
-}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
index a8d9ff17b7..7cddfd29d9 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
@@ -27,6 +27,10 @@ public:
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
Utils::SmallString extraId = {});
+ void requestMidSizeImage(Utils::PathString name,
+ ImageCache::CaptureImageCallback captureCallback,
+ ImageCache::AbortCallback abortCallback,
+ Utils::SmallString extraId = {});
void requestSmallImage(Utils::PathString name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
@@ -35,7 +39,7 @@ public:
void clean();
private:
- enum class RequestType { Image, SmallImage, Icon };
+ enum class RequestType { Image, MidSizeImage, SmallImage, Icon };
struct RequestEntry
{
RequestEntry() = default;
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
index aff814b8d8..04882d61eb 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
@@ -33,6 +33,11 @@ public:
ImageCache::AbortCallback abortCallback,
Utils::SmallString extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {}) override;
+ void requestMidSizeImage(Utils::PathString name,
+ ImageCache::CaptureImageCallback captureCallback,
+ ImageCache::AbortCallback abortCallback,
+ Utils::SmallString extraId = {},
+ ImageCache::AuxiliaryData auxiliaryData = {}) override;
void requestSmallImage(Utils::PathString name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
@@ -42,7 +47,7 @@ public:
void clean();
private:
- enum class RequestType { Image, SmallImage, Icon };
+ enum class RequestType { Image, MidSizeImage, SmallImage, Icon };
struct Entry
{
Entry() = default;
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
index c71b6ab758..da8bda079e 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
@@ -20,6 +20,12 @@ public:
Utils::SmallString extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {})
= 0;
+ virtual void requestMidSizeImage(Utils::PathString name,
+ ImageCache::CaptureImageCallback captureCallback,
+ ImageCache::AbortCallback abortCallback,
+ Utils::SmallString extraId = {},
+ ImageCache::AuxiliaryData auxiliaryData = {})
+ = 0;
virtual void requestSmallImage(Utils::PathString name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
diff --git a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
index ed4fe77b57..7b2b8a2c55 100644
--- a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
+++ b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
@@ -4,6 +4,7 @@
#pragma once
#include <instances/puppetstartdata.h>
+#include <utils/filepath.h>
namespace QmlDesigner {
@@ -38,6 +39,7 @@ public:
virtual bool hasStartupTarget() const = 0;
virtual PuppetStartData puppetStartData(const class Model &model) const = 0;
virtual bool instantQmlTextUpdate() const = 0;
+ virtual Utils::FilePath qmlPuppetPath() const = 0;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h
index 3c688c5dc5..c147fb0753 100644
--- a/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h
+++ b/src/plugins/qmldesigner/designercore/include/imagecacheauxiliarydata.h
@@ -43,10 +43,11 @@ using AuxiliaryData = std::variant<std::monostate,
FontCollectorSizeAuxiliaryData,
FontCollectorSizesAuxiliaryData>;
-enum class AbortReason : char { Abort, Failed };
+enum class AbortReason : char { Abort, Failed, NoEntry };
using CaptureImageCallback = std::function<void(const QImage &)>;
-using CaptureImageWithSmallImageCallback = std::function<void(const QImage &image, const QImage &smallImage)>;
+using CaptureImageWithScaledImagesCallback = std::function<
+ void(const QImage &image, const QImage &midSizeImage, const QImage &smallImage)>;
using AbortCallback = std::function<void(ImageCache::AbortReason)>;
} // namespace ImageCache
diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h
index 2d4378e937..9e6c7ca36a 100644
--- a/src/plugins/qmldesigner/designercore/include/model.h
+++ b/src/plugins/qmldesigner/designercore/include/model.h
@@ -91,6 +91,7 @@ public:
NodeMetaInfo qtQuick3DMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DModelMetaInfo() const;
NodeMetaInfo qtQuick3DNodeMetaInfo() const;
+ NodeMetaInfo qtQuick3DPrincipledMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DTextureMetaInfo() const;
NodeMetaInfo qtQuickConnectionsMetaInfo() const;
NodeMetaInfo qtQuickControlsTextAreaMetaInfo() const;
@@ -145,7 +146,9 @@ public:
bool hasId(const QString &id) const;
bool hasImport(const QString &importUrl) const;
- QString generateNewId(const QString &prefixName, const QString &fallbackPrefix = "element") 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;
void setActive3DSceneId(qint32 sceneId);
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index 4bf86fbf43..a48713ee86 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -223,6 +223,7 @@ public:
static bool isThisOrAncestorLocked(const ModelNode &node);
static ModelNode lowestCommonAncestor(const QList<ModelNode> &nodes);
+ static QList<ModelNode> pruneChildren(const QList<ModelNode> &nodes);
qint32 internalId() const;
diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
index 82d5bf21d4..467cef0ed3 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
@@ -6,6 +6,7 @@
#include "qmldesignercorelib_global.h"
#include "abstractview.h"
#include "modelcache.h"
+#include "rewritertransaction.h"
#include <modelnode.h>
#include <nodeinstance.h>
diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
index 35f2c25f46..69ac5f2a97 100644
--- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
@@ -118,6 +118,7 @@ public:
bool isQtMultimediaSoundEffect() const;
bool isQtObject() const;
bool isQtQuick3D() const;
+ bool isQtQuick3DBakedLightmap() const;
bool isQtQuick3DBuffer() const;
bool isQtQuick3DCamera() const;
bool isQtQuick3DCommand() const;
diff --git a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
index ce9b766fa9..6cda405f61 100644
--- a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
@@ -51,6 +51,12 @@ public:
bool isPointer() const;
QVariant castedValue(const QVariant &value) const;
+ friend bool operator==(const PropertyMetaInfo &first, const PropertyMetaInfo &second)
+ {
+ return first.m_nodeMetaInfoPrivateData == second.m_nodeMetaInfoPrivateData
+ && first.name() == second.name();
+ }
+
private:
const Storage::Info::PropertyDeclaration &propertyData() const;
TypeName propertyTypeName() const;
diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h
index 85ef99c6af..9387fdb345 100644
--- a/src/plugins/qmldesigner/designercore/include/rewriterview.h
+++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h
@@ -4,9 +4,9 @@
#pragma once
#include "qmldesignercorelib_global.h"
-#include "exception.h"
#include "abstractview.h"
#include "documentmessage.h"
+#include "rewritertransaction.h"
#include <QScopedPointer>
#include <QTimer>
@@ -170,6 +170,8 @@ public:
bool possibleImportsEnabled() const;
void setPossibleImportsEnabled(bool b);
+ void forceAmend();
+
signals:
void modelInterfaceProjectUpdated();
diff --git a/src/plugins/qmldesigner/designercore/include/synchronousimagecache.h b/src/plugins/qmldesigner/designercore/include/synchronousimagecache.h
index db91faa843..a2d7a13410 100644
--- a/src/plugins/qmldesigner/designercore/include/synchronousimagecache.h
+++ b/src/plugins/qmldesigner/designercore/include/synchronousimagecache.h
@@ -39,6 +39,9 @@ public:
QImage image(Utils::PathString filePath,
Utils::SmallString extraId = {},
const ImageCache::AuxiliaryData &auxiliaryData = {});
+ QImage midSizeImage(Utils::PathString filePath,
+ Utils::SmallString extraId = {},
+ const ImageCache::AuxiliaryData &auxiliaryData = {});
QImage smallImage(Utils::PathString filePath,
Utils::SmallString extraId = {},
const ImageCache::AuxiliaryData &auxiliaryData = {});
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp
index 5f9cd51670..2893d0e131 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp
@@ -46,12 +46,13 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
+#include <nanotrace/nanotrace.h>
#include <projectexplorer/kit.h>
#include <utils/hostosinfo.h>
+#include <utils/qtcassert.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>
-#include <nanotrace/nanotrace.h>
#include <QCoreApplication>
#include <QDir>
@@ -132,6 +133,7 @@ void NodeInstanceServerProxy::dispatchCommand(const QVariant &command)
} else if (command.userType() == SyncNanotraceCommandType) {
// ignore.
} else {
+ QTC_ASSERT(false, );
Q_ASSERT(false);
}
diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
index d15ef9227c..f4b505c4e7 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
@@ -2245,7 +2245,17 @@ bool NodeMetaInfo::isQtQuick3DCamera() const
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Camera>(m_projectStorage, m_typeId);
} else {
- return isValid() && isSubclassOf("QQuick3D.Camera");
+ return isValid() && isSubclassOf("QtQuick3D.Camera");
+ }
+}
+
+bool NodeMetaInfo::isQtQuick3DBakedLightmap() const
+{
+ if constexpr (useProjectStorage()) {
+ using namespace Storage::Info;
+ return isBasedOnCommonType<QtQuick3D, BakedLightmap>(m_projectStorage, m_typeId);
+ } else {
+ return isValid() && isSubclassOf("QtQuick3D.BakedLightmap");
}
}
@@ -2255,7 +2265,7 @@ bool NodeMetaInfo::isQtQuick3DBuffer() const
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, Buffer>(m_projectStorage, m_typeId);
} else {
- return isValid() && isSubclassOf("QQuick3D.Buffer");
+ return isValid() && isSubclassOf("QtQuick3D.Buffer");
}
}
@@ -2265,7 +2275,7 @@ bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, InstanceListEntry>(m_projectStorage, m_typeId);
} else {
- return isValid() && isSubclassOf("QQuick3D.InstanceListEntry");
+ return isValid() && isSubclassOf("QtQuick3D.InstanceListEntry");
}
}
@@ -2275,7 +2285,7 @@ bool NodeMetaInfo::isQtQuick3DInstanceList() const
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, InstanceList>(m_projectStorage, m_typeId);
} else {
- return isValid() && isSubclassOf("QQuick3D.InstanceList");
+ return isValid() && isSubclassOf("QtQuick3D.InstanceList");
}
}
@@ -2564,7 +2574,7 @@ bool NodeMetaInfo::isBool() const
if (!isValid())
return false;
- auto type = m_privateData->qualfiedTypeName();
+ auto type = simplifiedTypeName();
return type == "bool" || type == "boolean";
}
@@ -2579,7 +2589,7 @@ bool NodeMetaInfo::isInteger() const
if (!isValid())
return false;
- auto type = m_privateData->qualfiedTypeName();
+ auto type = simplifiedTypeName();
return type == "int" || type == "integer";
}
@@ -2597,7 +2607,7 @@ bool NodeMetaInfo::isFloat() const
if (!isValid())
return false;
- auto type = m_privateData->qualfiedTypeName();
+ auto type = simplifiedTypeName();
return type == "qreal" || type == "double" || type == "float";
}
@@ -2609,7 +2619,7 @@ bool NodeMetaInfo::isVariant() const
using namespace Storage::Info;
return isTypeId(m_typeId, m_projectStorage->builtinTypeId<QVariant>());
} else {
- return isValid() && m_privateData->qualfiedTypeName() == "QVariant";
+ return isValid() && simplifiedTypeName() == "QVariant";
}
}
@@ -2622,7 +2632,7 @@ bool NodeMetaInfo::isString() const
if (!isValid())
return false;
- auto type = m_privateData->qualfiedTypeName();
+ auto type = simplifiedTypeName();
return type == "string" || type == "QString";
}
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index 21112df36a..b9f0315c19 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -4,24 +4,23 @@
#include "abstractview.h"
#include "auxiliarydataproperties.h"
+#include "bindingproperty.h"
+#include "internalnode_p.h"
#include "model.h"
#include "model_p.h"
-#include "internalnode_p.h"
#include "nodeinstanceview.h"
-#include <qmlstate.h>
-#include <qmltimeline.h>
-#include <nodemetainfo.h>
-#include <qmldesignerconstants.h>
-#include <nodelistproperty.h>
-#include <variantproperty.h>
-#include <bindingproperty.h>
-
-#include <coreplugin/helpmanager.h>
+#include "nodelistproperty.h"
+#include "nodemetainfo.h"
+#include "qmlstate.h"
+#include "qmltimeline.h"
+#include "qmldesignerconstants.h"
+#include "rewritertransaction.h"
+#include "variantproperty.h"
+
#include <utils/qtcassert.h>
#include <utils/algorithm.h>
#include <QWidget>
-#include <QtGui/qimage.h>
namespace QmlDesigner {
@@ -78,35 +77,27 @@ ModelNode AbstractView::createModelNode(const TypeName &typeName,
ModelNode::NodeSourceType nodeSourceType,
const QString &behaviorPropertyName)
{
- return ModelNode(model()->d->createNode(typeName, majorVersion, minorVersion, propertyList, auxPropertyList, nodeSource, nodeSourceType, behaviorPropertyName), model(), this);
+ return ModelNode(model()->d->createNode(typeName, majorVersion, minorVersion, propertyList,
+ auxPropertyList, nodeSource, nodeSourceType,
+ behaviorPropertyName), model(), this);
}
-/*!
- Returns the constant root model node.
-*/
-
+// Returns the constant root model node.
ModelNode AbstractView::rootModelNode() const
{
Q_ASSERT(model());
- return ModelNode(model()->d->rootNode(), model(), const_cast<AbstractView*>(this));
+ return ModelNode(model()->d->rootNode(), model(), const_cast<AbstractView *>(this));
}
-
-/*!
- Returns the root model node.
-*/
-
+// Returns the root model node.
ModelNode AbstractView::rootModelNode()
{
Q_ASSERT(model());
return ModelNode(model()->d->rootNode(), model(), this);
}
-/*!
- Sets the reference to a model to a null pointer.
-
-*/
+// Sets the reference to a model to a null pointer.
void AbstractView::removeModel()
{
m_model.clear();
@@ -117,6 +108,7 @@ WidgetInfo AbstractView::createWidgetInfo(QWidget *widget,
WidgetInfo::PlacementHint placementHint,
int placementPriority,
const QString &tabName,
+ const QString &feedbackDisplayName,
DesignerWidgetFlags widgetFlags)
{
WidgetInfo widgetInfo;
@@ -126,14 +118,13 @@ WidgetInfo AbstractView::createWidgetInfo(QWidget *widget,
widgetInfo.placementHint = placementHint;
widgetInfo.placementPriority = placementPriority;
widgetInfo.tabName = tabName;
+ widgetInfo.feedbackDisplayName = feedbackDisplayName;
widgetInfo.widgetFlags = widgetFlags;
return widgetInfo;
}
-/*!
- Returns the model of the view.
-*/
+// Returns the model of the view.
Model* AbstractView::model() const
{
return m_model.data();
@@ -185,7 +176,6 @@ void AbstractView::modelAboutToBeDetached(Model *)
\value EmptyPropertiesRemoved
Empty properties were removed.
*/
-
void AbstractView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &/*propertyList*/)
{
}
@@ -259,72 +249,60 @@ void AbstractView::nodeOrderChanged(const NodeListProperty &listProperty, const
nodeOrderChanged(listProperty);
}
-/*!
-\fn void AbstractView::nodeAboutToBeRemoved(const ModelNode &removedNode)
-Called when the node specified by \a removedNode will be removed.
-*/
void AbstractView::nodeAboutToBeRemoved(const ModelNode &/*removedNode*/)
{
}
-void AbstractView::nodeRemoved(const ModelNode &/*removedNode*/, const NodeAbstractProperty &/*parentProperty*/, PropertyChangeFlags /*propertyChange*/)
+void AbstractView::nodeRemoved(const ModelNode &/*removedNode*/, const NodeAbstractProperty &/*parentProperty*/,
+ PropertyChangeFlags /*propertyChange*/)
{
}
-void AbstractView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/)
+void AbstractView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &/*propertyList*/)
{
}
-/*!
-Called when the properties specified by \a propertyList are removed.
-*/
-void AbstractView::propertiesRemoved(const QList<AbstractProperty>& /*propertyList*/)
+void AbstractView::propertiesRemoved(const QList<AbstractProperty> &/*propertyList*/)
{
}
-/*!
-\fn void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange)
-Called when the parent of \a node will be changed from \a oldPropertyParent to
-\a newPropertyParent.
-*/
-
-/*!
-\fn void QmlDesigner::AbstractView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
- const QList<ModelNode> &lastSelectedNodeList)
-Called when the selection is changed from \a lastSelectedNodeList to
-\a selectedNodeList.
-*/
void AbstractView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/)
{
}
-void AbstractView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
+void AbstractView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/,
+ const NodeAbstractProperty &/*oldPropertyParent*/, PropertyChangeFlags /*propertyChange*/)
{
}
-void AbstractView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
+void AbstractView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/,
+ const NodeAbstractProperty &/*oldPropertyParent*/, PropertyChangeFlags /*propertyChange*/)
{
}
-void AbstractView::nodeIdChanged(const ModelNode& /*node*/, const QString& /*newId*/, const QString& /*oldId*/)
+void AbstractView::nodeIdChanged(const ModelNode &/*node*/, const QString &/*newId*/, const QString &/*oldId*/)
{
}
-void AbstractView::variantPropertiesChanged(const QList<VariantProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
+void AbstractView::variantPropertiesChanged(const QList<VariantProperty>& /*propertyList*/,
+ PropertyChangeFlags /*propertyChange*/)
{
}
void AbstractView::bindingPropertiesAboutToBeChanged(const QList<BindingProperty> &) {}
-void AbstractView::bindingPropertiesChanged(const QList<BindingProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
+void AbstractView::bindingPropertiesChanged(const QList<BindingProperty>& /*propertyList*/,
+ PropertyChangeFlags /*propertyChange*/)
{
}
-void AbstractView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
+void AbstractView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &/*propertyList*/,
+ PropertyChangeFlags /*propertyChange*/)
{
}
-void AbstractView::signalDeclarationPropertiesChanged(const QVector<SignalDeclarationProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
+void AbstractView::signalDeclarationPropertiesChanged(const QVector<SignalDeclarationProperty> &/*propertyList*/,
+ PropertyChangeFlags /*propertyChange*/)
{
}
@@ -349,13 +327,14 @@ void AbstractView::usedImportsChanged(const QList<Import> &/*usedImports*/)
{
}
-void AbstractView::auxiliaryDataChanged(const ModelNode & /*node*/,
+void AbstractView::auxiliaryDataChanged(const ModelNode &/*node*/,
AuxiliaryDataKeyView /*key*/,
- const QVariant & /*data*/)
+ const QVariant &/*data*/)
{
}
-void AbstractView::customNotification(const AbstractView * /*view*/, const QString & /*identifier*/, const QList<ModelNode> & /*nodeList*/, const QList<QVariant> & /*data*/)
+void AbstractView::customNotification(const AbstractView * /*view*/, const QString & /*identifier*/,
+ const QList<ModelNode> & /*nodeList*/, const QList<QVariant> & /*data*/)
{
}
@@ -367,27 +346,27 @@ void AbstractView::documentMessagesChanged(const QList<DocumentMessage> &/*error
{
}
-void AbstractView::currentTimelineChanged(const ModelNode & /*node*/)
+void AbstractView::currentTimelineChanged(const ModelNode &/*node*/)
{
}
-void AbstractView::renderImage3DChanged(const QImage & /*image*/)
+void AbstractView::renderImage3DChanged(const QImage &/*image*/)
{
}
-void AbstractView::updateActiveScene3D(const QVariantMap & /*sceneState*/)
+void AbstractView::updateActiveScene3D(const QVariantMap &/*sceneState*/)
{
}
-void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/)
+void AbstractView::updateImport3DSupport(const QVariantMap &/*supportMap*/)
{
}
// a Quick3DNode that is picked at the requested view position in the 3D Editor and the 3D scene
// position of the requested view position.
-void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/, const QVector3D &/*pos3d*/) {}
+void AbstractView::nodeAtPosReady(const ModelNode &/*modelNode*/, const QVector3D &/*pos3d*/) {}
-void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
+void AbstractView::modelNodePreviewPixmapChanged(const ModelNode &/*node*/, const QPixmap &/*pixmap*/)
{
}
@@ -446,9 +425,6 @@ void AbstractView::setSelectedModelNode(const ModelNode &modelNode)
setSelectedModelNodes({modelNode});
}
-/*!
- Clears the selection.
-*/
void AbstractView::clearSelectedModelNodes()
{
model()->d->clearSelectedNodes();
@@ -469,10 +445,6 @@ bool AbstractView::isSelectedModelNode(const ModelNode &modelNode) const
return model()->d->selectedNodes().contains(modelNode.internalNode());
}
-/*!
- Sets the list of nodes to the actual selected nodes. Returns a list of the
- selected nodes.
-*/
QList<ModelNode> AbstractView::selectedModelNodes() const
{
return toModelNodeList(model()->d->selectedNodes());
@@ -494,18 +466,12 @@ ModelNode AbstractView::singleSelectedModelNode() const
return ModelNode();
}
-/*!
- Adds \a node to the selection list.
-*/
void AbstractView::selectModelNode(const ModelNode &modelNode)
{
QTC_ASSERT(modelNode.isInHierarchy(), return);
model()->d->selectNode(modelNode.internalNode());
}
-/*!
- Removes \a node from the selection list.
-*/
void AbstractView::deselectModelNode(const ModelNode &node)
{
model()->d->deselectNode(node.internalNode());
@@ -535,22 +501,23 @@ const NodeInstanceView *AbstractView::nodeInstanceView() const
{
if (model())
return model()->d->nodeInstanceView();
- else
- return nullptr;
+
+ return nullptr;
}
RewriterView *AbstractView::rewriterView() const
{
if (model())
return model()->d->rewriterView();
- else
- return nullptr;
+
+ return nullptr;
}
void AbstractView::resetView()
{
if (!model())
return;
+
Model *currentModel = model();
currentModel->detachView(this);
@@ -628,7 +595,7 @@ void AbstractView::deactivateTimelineRecording()
model()->d->notifyCurrentTimelineChanged(ModelNode());
}
-bool AbstractView::executeInTransaction(const QByteArray &identifier, const AbstractView::OperationBlock &lambda)
+bool AbstractView::executeInTransaction(const QByteArray &identifier, const OperationBlock &lambda)
{
try {
RewriterTransaction transaction = beginRewriterTransaction(identifier);
@@ -851,6 +818,18 @@ ModelNode AbstractView::materialLibraryNode()
return modelNodeForId(Constants::MATERIAL_LIB_ID);
}
+bool AbstractView::isPartOfMaterialLibrary(const ModelNode &node)
+{
+ if (!node.isValid())
+ return false;
+
+ ModelNode matLib = materialLibraryNode();
+
+ return matLib.isValid()
+ && (node == matLib
+ || (node.hasParentProperty() && node.parentProperty().parentModelNode() == matLib));
+}
+
ModelNode AbstractView::active3DSceneNode()
{
auto activeSceneAux = rootModelNode().auxiliaryData(active3dSceneProperty);
@@ -864,59 +843,6 @@ ModelNode AbstractView::active3DSceneNode()
return {};
}
-// Assigns given material to a 3D model.
-// The assigned material is also inserted into material library if not already there.
-// If given material is not valid, first existing material from material library is used,
-// or if material library is empty, a new material is created.
-// This function should be called only from inside a transaction, as it potentially does many
-// changes to model.
-void AbstractView::assignMaterialTo3dModel(const ModelNode &modelNode, const ModelNode &materialNode)
-{
- QTC_ASSERT(modelNode.isValid() && modelNode.metaInfo().isQtQuick3DModel(), return );
-
- ModelNode matLib = materialLibraryNode();
-
- if (!matLib.isValid())
- return;
-
- ModelNode newMaterialNode;
-
- if (materialNode.isValid() && materialNode.metaInfo().isQtQuick3DMaterial()) {
- newMaterialNode = materialNode;
- } else {
- const QList<ModelNode> materials = matLib.directSubModelNodes();
- if (materials.size() > 0) {
- for (const ModelNode &mat : materials) {
- if (mat.metaInfo().isQtQuick3DMaterial()) {
- newMaterialNode = mat;
- break;
- }
- }
- }
-
- // if no valid material, create a new default material
- if (!newMaterialNode.isValid()) {
- NodeMetaInfo metaInfo = model()->qtQuick3DDefaultMaterialMetaInfo();
- newMaterialNode = createModelNode("QtQuick3D.DefaultMaterial", metaInfo.majorVersion(),
- metaInfo.minorVersion());
- newMaterialNode.validId();
- }
- }
-
- QTC_ASSERT(newMaterialNode.isValid(), return);
-
- VariantProperty matNameProp = newMaterialNode.variantProperty("objectName");
- if (matNameProp.value().isNull())
- matNameProp.setValue("New Material");
-
- if (!newMaterialNode.hasParentProperty()
- || newMaterialNode.parentProperty() != matLib.defaultNodeListProperty()) {
- matLib.defaultNodeListProperty().reparentHere(newMaterialNode);
- }
- BindingProperty modelMatsProp = modelNode.bindingProperty("materials");
- modelMatsProp.setExpression(newMaterialNode.id());
-}
-
ModelNode AbstractView::getTextureDefaultInstance(const QString &source)
{
ModelNode matLib = materialLibraryNode();
@@ -946,7 +872,7 @@ ModelNode AbstractView::currentStateNode() const
if (model())
return ModelNode(m_model.data()->d->currentStateNode(), m_model.data(), const_cast<AbstractView*>(this));
- return ModelNode();
+ return {};
}
QmlModelState AbstractView::currentState() const
@@ -956,12 +882,13 @@ QmlModelState AbstractView::currentState() const
QmlTimeline AbstractView::currentTimeline() const
{
- if (model())
+ if (model()) {
return QmlTimeline(ModelNode(m_model.data()->d->currentTimelineNode(),
- m_model.data(),
- const_cast<AbstractView*>(this)));
+ m_model.data(),
+ const_cast<AbstractView *>(this)));
+ }
- return QmlTimeline();
+ return {};
}
static int getMinorVersionFromImport(const Model *model)
@@ -1001,13 +928,14 @@ static int getMajorVersionFromNode(const ModelNode &modelNode)
if (modelNode.metaInfo().isValid()) {
for (const NodeMetaInfo &info : modelNode.metaInfo().classHierarchy()) {
if (info.typeName() == "QtQml.QtObject"
- || info.typeName() == "QtQuick.QtObject"
- || info.typeName() == "QtQuick.Item")
+ || info.typeName() == "QtQuick.QtObject"
+ || info.typeName() == "QtQuick.Item") {
return info.majorVersion();
+ }
}
}
- return 1; //default
+ return 1; // default
}
static int getMinorVersionFromNode(const ModelNode &modelNode)
@@ -1020,7 +948,7 @@ static int getMinorVersionFromNode(const ModelNode &modelNode)
}
}
- return 1; //default
+ return 1; // default
}
int AbstractView::majorQtQuickVersion() const
@@ -1041,5 +969,4 @@ int AbstractView::minorQtQuickVersion() const
return getMinorVersionFromNode(rootModelNode());
}
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
index f07b74f869..69c74ec6cf 100644
--- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
+++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "basetexteditmodifier.h"
+#include "qmljseditor/qmljseditor.h"
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/parser/qmljsast_p.h>
@@ -111,7 +112,10 @@ bool BaseTextEditModifier::moveToComponent(int nodeOffset)
if (!object)
return false;
- QmlJSEditor::performComponentFromObjectDef(document->filePath().toString(), object);
+ QmlJSEditor::performComponentFromObjectDef(qobject_cast<QmlJSEditor::QmlJSEditorWidget *>(
+ m_textEdit),
+ document->filePath().toString(),
+ object);
return true;
}
}
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index 4fb8a7a75a..a234c11e1f 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -1516,7 +1516,9 @@ static QString firstCharToLower(const QString &string)
return resultString;
}
-QString Model::generateNewId(const QString &prefixName, const QString &fallbackPrefix) const
+QString Model::generateNewId(const QString &prefixName,
+ const QString &fallbackPrefix,
+ std::optional<std::function<bool(const QString &)>> isDuplicate) const
{
// First try just the prefixName without number as postfix, then continue with 2 and further
// as postfix until id does not already exist.
@@ -1538,7 +1540,10 @@ QString Model::generateNewId(const QString &prefixName, const QString &fallbackP
QString newId = newBaseId;
- while (!ModelNode::isValidId(newId) || hasId(newId)
+ if (!isDuplicate.has_value())
+ isDuplicate = std::bind(&Model::hasId, this, std::placeholders::_1);
+
+ while (!ModelNode::isValidId(newId) || isDuplicate.value()(newId)
|| d->rootNode()->hasProperty(newId.toUtf8())) {
++counter;
newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(newBaseId)).arg(counter);
@@ -1954,6 +1959,16 @@ NodeMetaInfo Model::qtQuick3DDefaultMaterialMetaInfo() const
}
}
+NodeMetaInfo Model::qtQuick3DPrincipledMaterialMetaInfo() const
+{
+ if constexpr (useProjectStorage()) {
+ using namespace Storage::Info;
+ return createNodeMetaInfo<QtQuick3D, PrincipledMaterial>();
+ } else {
+ return metaInfo("QtQuick3D.PrincipledMaterial");
+ }
+}
+
NodeMetaInfo Model::qtQuickTimelineTimelineMetaInfo() const
{
if constexpr (useProjectStorage()) {
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index af612ca3f4..aab0d13c24 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -19,6 +19,7 @@
#include <rewriterview.h>
#include <utils/algorithm.h>
+#include <utils/ranges.h>
#include <QHash>
#include <QRegularExpression>
@@ -1402,6 +1403,31 @@ ModelNode ModelNode::lowestCommonAncestor(const QList<ModelNode> &nodes)
return accumulatedNode;
}
+QList<ModelNode> ModelNode::pruneChildren(const QList<ModelNode> &nodes)
+{
+ QList<ModelNode> forwardNodes;
+ QList<ModelNode> backNodes;
+
+ auto pushIfIsNotChild = [] (QList<ModelNode> &container, const ModelNode &node) {
+ bool hasAncestor = Utils::anyOf(container,
+ [node] (const ModelNode &testNode) -> bool {
+ return testNode.isAncestorOf(node);
+ });
+ if (!hasAncestor)
+ container.append(node);
+ };
+
+ for (const ModelNode &node : nodes | Utils::views::reverse) {
+ if (node)
+ pushIfIsNotChild(forwardNodes, node);
+ }
+
+ for (const ModelNode &node : forwardNodes | Utils::views::reverse)
+ pushIfIsNotChild(backNodes, node);
+
+ return backNodes;
+}
+
void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
{
model()->d->setScriptFunctions(m_internalNode, scriptFunctionList);
diff --git a/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp b/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
index 83310b963a..5029fdc79d 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
@@ -3,6 +3,7 @@
#include "qmlchangeset.h"
#include "bindingproperty.h"
+#include "rewritertransaction.h"
#include "variantproperty.h"
#include "abstractview.h"
#include <metainfo.h>
diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
index 54978bc4a8..6d79375b6d 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp
@@ -214,6 +214,9 @@ void QmlItemNode::placeEffectNode(NodeAbstractProperty &parentProperty, const Qm
} else {
parentProperty.parentModelNode().variantProperty("layer.enabled").setValue(true);
}
+
+ if (effectNode.modelNode().metaInfo().hasProperty("timeRunning"))
+ effectNode.modelNode().variantProperty("timeRunning").setValue(true);
}
bool QmlItemNode::isValid() const
diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
index 33f91a137b..d8088de64b 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
@@ -703,6 +703,12 @@ void RewriterView::setPossibleImportsEnabled(bool b)
m_possibleImportsEnabled = b;
}
+void RewriterView::forceAmend()
+{
+ m_amendTimer.stop();
+ amendQmlText();
+}
+
Internal::ModelNodePositionStorage *RewriterView::positionStorage() const
{
return m_positionStorage.data();
diff --git a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
index cb92f7df2c..2a6b9f0fbf 100644
--- a/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/stylesheetmerger.cpp
@@ -555,6 +555,7 @@ void StylesheetMerger::styleMerge(const QString &qmlTemplateString,
templateRewriterView->setTextModifier(&textModifierTemplate);
templateModel->attachView(templateRewriterView.data());
templateRewriterView->setCheckSemanticErrors(false);
+ templateRewriterView->setPossibleImportsEnabled(false);
ModelNode templateRootNode = templateRewriterView->rootModelNode();
QTC_ASSERT(templateRootNode.isValid(), return );
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index ca321b5687..4469793db8 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -36,11 +36,12 @@
#include <utils/qrcparser.h>
#include <utils/qtcassert.h>
-#include <QSet>
#include <QDir>
+#include <QElapsedTimer>
#include <QLoggingCategory>
#include <QRegularExpression>
-#include <QElapsedTimer>
+#include <QScopeGuard>
+#include <QSet>
#include <memory>
@@ -428,91 +429,43 @@ public:
void leaveScope()
{ m_scopeBuilder.pop(); }
- void lookup(AST::UiQualifiedId *astTypeNode, QString &typeName, int &majorVersion,
- int &minorVersion, QString &defaultPropertyName)
+ NodeMetaInfo lookup(AST::UiQualifiedId *astTypeNode)
{
- const ObjectValue *value = m_context->lookupType(m_doc.data(), astTypeNode);
- defaultPropertyName = m_context->defaultPropertyName(value);
-
- const CppComponentValue *qmlValue = value_cast<CppComponentValue>(value);
- if (qmlValue) {
- typeName = qmlValue->moduleName() + QStringLiteral(".") + qmlValue->className();
-
- majorVersion = qmlValue->componentVersion().majorVersion();
- minorVersion = qmlValue->componentVersion().minorVersion();
- } else {
- for (AST::UiQualifiedId *iter = astTypeNode; iter; iter = iter->next)
- if (!iter->next && !iter->name.isEmpty())
- typeName = iter->name.toString();
-
- QString fullTypeName;
- for (AST::UiQualifiedId *iter = astTypeNode; iter; iter = iter->next)
- if (!iter->name.isEmpty())
- fullTypeName += iter->name.toString() + QLatin1Char('.');
-
- if (fullTypeName.endsWith(QLatin1Char('.')))
- fullTypeName.chop(1);
-
- majorVersion = ComponentVersion::NoVersion;
- minorVersion = ComponentVersion::NoVersion;
-
- const Imports *imports = m_context->imports(m_doc.data());
- ImportInfo importInfo = imports->info(fullTypeName, m_context.data());
- if (importInfo.isValid() && importInfo.type() == ImportType::Library) {
- QString name = importInfo.name();
- majorVersion = importInfo.version().majorVersion();
- minorVersion = importInfo.version().minorVersion();
- typeName.prepend(name + QLatin1Char('.'));
- } else if (importInfo.isValid() && importInfo.type() == ImportType::Directory) {
- const Utils::FilePath path = Utils::FilePath::fromString(importInfo.path());
- const Utils::FilePath dir = m_doc->path();
- // should probably try to make it relative to some import path, not to the document path
- const Utils::FilePath relativePath = path.relativeChildPath(dir);
- QString name = relativePath.path().replace(QLatin1Char('/'), QLatin1Char('.'));
- if (!name.isEmpty() && name != QLatin1String("."))
- typeName.prepend(name + QLatin1Char('.'));
- } else if (importInfo.isValid() && importInfo.type() == ImportType::QrcDirectory) {
- QString path = Utils::QrcParser::normalizedQrcDirectoryPath(importInfo.path());
- path = path.mid(1, path.size() - ((path.size() > 1) ? 2 : 1));
- const QString name = path.replace(QLatin1Char('/'), QLatin1Char('.'));
- if (!name.isEmpty())
- typeName.prepend(name + QLatin1Char('.'));
- }
- }
-
- {
- TypeName fullTypeName;
- for (AST::UiQualifiedId *iter = astTypeNode; iter; iter = iter->next)
- if (!iter->name.isEmpty())
- fullTypeName += iter->name.toUtf8() + '.';
-
- if (fullTypeName.endsWith('.'))
- fullTypeName.chop(1);
+ TypeName fullTypeName;
+ for (AST::UiQualifiedId *iter = astTypeNode; iter; iter = iter->next)
+ if (!iter->name.isEmpty())
+ fullTypeName += iter->name.toUtf8() + '.';
- NodeMetaInfo metaInfo = m_model->metaInfo(fullTypeName);
+ if (fullTypeName.endsWith('.'))
+ fullTypeName.chop(1);
- bool ok = metaInfo.typeName() == typeName.toUtf8()
- && metaInfo.majorVersion() == majorVersion
- && metaInfo.minorVersion() == minorVersion;
+ NodeMetaInfo metaInfo = m_model->metaInfo(fullTypeName);
+ return metaInfo;
+ }
+ bool lookupProperty(const QString &propertyPrefix,
+ const ModelNode &node,
+ const AST::UiQualifiedId *propertyId)
+ {
+ const QString propertyName = propertyPrefix.isEmpty() ? propertyId->name.toString()
+ : propertyPrefix;
- if (!ok) {
- qDebug() << Q_FUNC_INFO;
- qDebug() << astTypeNode->name.toString() << typeName;
- qDebug() << metaInfo.isValid() << metaInfo.typeName();
- }
+ if (propertyName == QStringLiteral("id") && !propertyId->next)
+ return false; // ### should probably be a special value
- typeName = QString::fromUtf8(metaInfo.typeName());
- majorVersion = metaInfo.majorVersion();
- minorVersion = metaInfo.minorVersion();
- }
+ //compare to lookupProperty(propertyPrefix, propertyId);
+ 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)
+ ///
+ 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())
@@ -685,7 +638,11 @@ public:
return value;
}
- QVariant convertToEnum(AST::Statement *rhs, const QString &propertyPrefix, AST::UiQualifiedId *propertyId, const QString &astValue)
+ QVariant convertToEnum(AST::Statement *rhs,
+ const NodeMetaInfo &metaInfo,
+ const QString &propertyPrefix,
+ AST::UiQualifiedId *propertyId,
+ const QString &astValue)
{
QStringList astValueList = astValue.split(QStringLiteral("."));
@@ -704,42 +661,12 @@ public:
if (!eStmt || !eStmt->expression)
return QVariant();
- const ObjectValue *containingObject = nullptr;
- QString name;
- if (!lookupProperty(propertyPrefix, propertyId, nullptr, &containingObject, &name))
- return QVariant();
+ const QString propertyName = propertyPrefix.isEmpty() ? propertyId->name.toString()
+ : propertyPrefix;
- if (containingObject)
- containingObject->lookupMember(name, m_context, &containingObject);
- const CppComponentValue * lhsCppComponent = value_cast<CppComponentValue>(containingObject);
- if (!lhsCppComponent)
- return QVariant();
- const QString lhsPropertyTypeName = lhsCppComponent->propertyType(name);
-
- const ObjectValue *rhsValueObject = nullptr;
- QString rhsValueName;
- if (auto idExp = AST::cast<AST::IdentifierExpression *>(eStmt->expression)) {
- if (!m_scopeChain.qmlScopeObjects().isEmpty())
- rhsValueObject = m_scopeChain.qmlScopeObjects().constLast();
- if (!idExp->name.isEmpty())
- rhsValueName = idExp->name.toString();
- } else if (auto memberExp = AST::cast<AST::FieldMemberExpression *>(eStmt->expression)) {
- Evaluate evaluate(&m_scopeChain);
- const Value *result = evaluate(memberExp->base);
- rhsValueObject = result->asObjectValue();
-
- if (!memberExp->name.isEmpty())
- rhsValueName = memberExp->name.toString();
- }
-
- if (rhsValueObject)
- rhsValueObject->lookupMember(rhsValueName, m_context, &rhsValueObject);
-
- const CppComponentValue *rhsCppComponentValue = value_cast<CppComponentValue>(rhsValueObject);
- if (!rhsCppComponentValue)
- return QVariant();
+ const PropertyMetaInfo pInfo = metaInfo.property(propertyName.toUtf8());
- if (rhsCppComponentValue->getEnum(lhsPropertyTypeName).hasKey(rhsValueName))
+ if (pInfo.isEnumType())
return QVariant::fromValue(Enumeration(astValue));
else
return QVariant();
@@ -1092,6 +1019,9 @@ Document::MutablePtr TextToModelMerger::createParsedDocument(const QUrl &url, co
bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceHandler)
{
+ QmlJS::ScopeChain::setSkipmakeComponentChain(true);
+ QScopeGuard unSkip([]() { QmlJS::ScopeChain::setSkipmakeComponentChain(false); });
+
qCInfo(rewriterBenchmark) << Q_FUNC_INFO;
const bool justSanityCheck = !differenceHandler.isAmender();
@@ -1228,23 +1158,21 @@ void TextToModelMerger::syncNode(ModelNode &modelNode,
m_rewriterView->positionStorage()->setNodeOffset(modelNode, astObjectType->identifierToken.offset);
- QString typeNameString;
- QString defaultPropertyNameString;
- int majorVersion;
- int minorVersion;
- context->lookup(astObjectType, typeNameString, majorVersion, minorVersion, defaultPropertyNameString);
+ NodeMetaInfo info = context->lookup(astObjectType);
+ if (!info.isValid()) {
+ qWarning() << "Skipping node with unknown type" << toString(astObjectType) << info.typeName();
+ return;
+ }
- TypeName typeName = typeNameString.toUtf8();
- PropertyName defaultPropertyName = defaultPropertyNameString.toUtf8();
+ int majorVersion = info.majorVersion();
+ int minorVersion = info.minorVersion();
+
+ TypeName typeName = info.typeName();
+ PropertyName defaultPropertyName = info.defaultPropertyName();
if (defaultPropertyName.isEmpty()) //fallback and use the meta system of the model
defaultPropertyName = modelNode.metaInfo().defaultPropertyName();
- if (typeName.isEmpty()) {
- qWarning() << "Skipping node with unknown type" << toString(astObjectType);
- return;
- }
-
if (modelNode.isRootNode() && !m_rewriterView->allowComponentRoot() && isComponentType(typeName)) {
for (AST::UiObjectMemberList *iter = astInitializer->members; iter; iter = iter->next) {
if (auto def = AST::cast<AST::UiObjectDefinition *>(iter->member)) {
@@ -1536,7 +1464,11 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN
}
}
- const QVariant enumValue = context->convertToEnum(script->statement, prefix, script->qualifiedId, astValue);
+ const QVariant enumValue = context->convertToEnum(script->statement,
+ modelNode.metaInfo(),
+ prefix,
+ script->qualifiedId,
+ astValue);
if (enumValue.isValid()) { // It is a qualified enum:
AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8());
syncVariantProperty(modelProperty, enumValue, TypeName(), differenceHandler); // TODO: parse type
@@ -1583,20 +1515,16 @@ void TextToModelMerger::syncNodeProperty(AbstractProperty &modelProperty,
const TypeName &dynamicPropertyType,
DifferenceHandler &differenceHandler)
{
+ NodeMetaInfo info = context->lookup(binding->qualifiedTypeNameId);
- QString typeNameString;
- QString dummy;
- int majorVersion;
- int minorVersion;
- context->lookup(binding->qualifiedTypeNameId, typeNameString, majorVersion, minorVersion, dummy);
-
- TypeName typeName = typeNameString.toUtf8();
-
-
- if (typeName.isEmpty()) {
- qWarning() << "Skipping node with unknown type" << toString(binding->qualifiedTypeNameId);
+ if (!info.isValid()) {
+ qWarning() << "SNP"
+ << "Skipping node with unknown type" << toString(binding->qualifiedTypeNameId);
return;
}
+ TypeName typeName = info.typeName();
+ int majorVersion = info.majorVersion();
+ int minorVersion = info.minorVersion();
if (modelProperty.isNodeProperty() && dynamicPropertyType == modelProperty.dynamicTypeName()) {
ModelNode nodePropertyNode = modelProperty.toNodeProperty().modelNode();
@@ -2114,18 +2042,14 @@ ModelNode ModelAmender::listPropertyMissingModelNode(NodeListProperty &modelProp
if (!astObjectType || !astInitializer)
return ModelNode();
- QString typeNameString;
- QString dummy;
- int majorVersion;
- int minorVersion;
- context->lookup(astObjectType, typeNameString, majorVersion, minorVersion, dummy);
-
- TypeName typeName = typeNameString.toUtf8();
-
- if (typeName.isEmpty()) {
+ NodeMetaInfo info = context->lookup(astObjectType);
+ if (!info.isValid()) {
qWarning() << "Skipping node with unknown type" << toString(astObjectType);
- return ModelNode();
+ return {};
}
+ TypeName typeName = info.typeName();
+ int majorVersion = info.majorVersion();
+ int minorVersion = info.minorVersion();
const bool propertyTakesComponent = propertyIsComponentType(modelProperty, typeName, m_merger->view()->model());
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
index 4878b59783..3cd7f3a016 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
@@ -23,6 +23,7 @@ namespace QmlDesigner::Storage::Info {
inline constexpr char Affector3D[] = "Affector3D";
inline constexpr char Attractor3D[] = "Attractor3D";
+inline constexpr char BakedLightmap[] = "BakedLightmap";
inline constexpr char BoolType[] = "bool";
inline constexpr char BorderImage[] = "BorderImage";
inline constexpr char Buffer[] = "Buffer";
@@ -184,6 +185,7 @@ class CommonTypeCache
CacheType<QtQuick, vector2d>,
CacheType<QtQuick, vector3d>,
CacheType<QtQuick, vector4d>,
+ CacheType<QtQuick3D, BakedLightmap>,
CacheType<QtQuick3D, Buffer>,
CacheType<QtQuick3D, Camera>,
CacheType<QtQuick3D, Command>,
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
new file mode 100644
index 0000000000..d574ef5475
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
@@ -0,0 +1,98 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "projectstorageexceptions.h"
+
+namespace QmlDesigner {
+
+const char *NoSourcePathForInvalidSourceId::what() const noexcept
+{
+ return "You cannot get a file path for an invalid file path id!";
+}
+
+const char *NoSourceContextPathForInvalidSourceContextId::what() const noexcept
+{
+ return "You cannot get a directory path for an invalid directory path id!";
+}
+
+const char *SourceContextIdDoesNotExists::what() const noexcept
+{
+ return "The source context id does not exist in the database!";
+}
+
+const char *SourceIdDoesNotExists::what() const noexcept
+{
+ return "The source id does not exist in the database!";
+}
+
+const char *TypeHasInvalidSourceId::what() const noexcept
+{
+ return "The source id is invalid!";
+}
+
+const char *ModuleDoesNotExists::what() const noexcept
+{
+ return "The module does not exist!";
+}
+
+const char *ModuleAlreadyExists::what() const noexcept
+{
+ return "The module does already exist!";
+}
+
+const char *ExportedTypeCannotBeInserted::what() const noexcept
+{
+ return "The exported type cannot be inserted!";
+}
+
+const char *TypeNameDoesNotExists::what() const noexcept
+{
+ return "The type name does not exist!";
+}
+
+const char *PropertyNameDoesNotExists::what() const noexcept
+{
+ return "The property name does not exist!";
+}
+
+const char *PrototypeChainCycle::what() const noexcept
+{
+ return "There is a prototype chain cycle!";
+}
+
+const char *AliasChainCycle::what() const noexcept
+{
+ return "There is a prototype chain cycle!";
+}
+
+const char *CannotParseQmlTypesFile::what() const noexcept
+{
+ return "Cannot parse qml types file!";
+}
+
+const char *CannotParseQmlDocumentFile::what() const noexcept
+{
+ return "Cannot parse qml types file!";
+}
+
+const char *ProjectDataHasInvalidProjectSourceId::what() const noexcept
+{
+ return "The project source id is invalid!";
+}
+
+const char *ProjectDataHasInvalidSourceId::what() const noexcept
+{
+ return "The source id is invalid!";
+}
+
+const char *ProjectDataHasInvalidModuleId::what() const noexcept
+{
+ return "The module id is invalid!";
+}
+
+const char *FileStatusHasInvalidSourceId::what() const noexcept
+{
+ return "The source id in file status is invalid!";
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
index bf540fb64d..d78283ca18 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
@@ -3,131 +3,118 @@
#pragma once
+#include "../include/qmldesignercorelib_global.h"
+
#include <exception>
namespace QmlDesigner {
-class NoSourcePathForInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT NoSourcePathForInvalidSourceId : std::exception
{
public:
- const char *what() const noexcept override
- {
- return "You cannot get a file path for an invalid file path id!";
- }
+ const char *what() const noexcept override;
};
-class NoSourceContextPathForInvalidSourceContextId : std::exception
+class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : std::exception
{
public:
- const char *what() const noexcept override
- {
- return "You cannot get a directory path for an invalid directory path id!";
- }
+ const char *what() const noexcept override;
};
-class SourceContextIdDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : std::exception
{
public:
- const char *what() const noexcept override
- {
- return "The source context id does not exist in the database!";
- }
+ const char *what() const noexcept override;
};
-class SourceIdDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : std::exception
{
public:
- const char *what() const noexcept override
- {
- return "The source id does not exist in the database!";
- }
+ const char *what() const noexcept override;
};
-class TypeHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT TypeHasInvalidSourceId : std::exception
{
public:
- const char *what() const noexcept override { return "The source id is invalid!"; }
+ const char *what() const noexcept override;
};
-class ModuleDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT ModuleDoesNotExists : std::exception
{
public:
- const char *what() const noexcept override { return "The module does not exist!"; }
+ const char *what() const noexcept override;
};
-class ModuleAlreadyExists : std::exception
+class QMLDESIGNERCORE_EXPORT ModuleAlreadyExists : std::exception
{
public:
- const char *what() const noexcept override { return "The module does already exist!"; }
+ const char *what() const noexcept override;
};
-class ExportedTypeCannotBeInserted : std::exception
+class QMLDESIGNERCORE_EXPORT ExportedTypeCannotBeInserted : std::exception
{
public:
- const char *what() const noexcept override { return "The exported type cannot be inserted!"; }
+ const char *what() const noexcept override;
};
-class TypeNameDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT TypeNameDoesNotExists : std::exception
{
public:
- const char *what() const noexcept override { return "The type name does not exist!"; }
+ const char *what() const noexcept override;
};
-class PropertyNameDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : std::exception
{
public:
- const char *what() const noexcept override { return "The property name does not exist!"; }
+ const char *what() const noexcept override;
};
-class PrototypeChainCycle : std::exception
+class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : std::exception
{
public:
- const char *what() const noexcept override { return "There is a prototype chain cycle!"; }
+ const char *what() const noexcept override;
};
-class AliasChainCycle : std::exception
+class QMLDESIGNERCORE_EXPORT AliasChainCycle : std::exception
{
public:
- const char *what() const noexcept override { return "There is a prototype chain cycle!"; }
+ const char *what() const noexcept override;
};
-class CannotParseQmlTypesFile : std::exception
+class QMLDESIGNERCORE_EXPORT CannotParseQmlTypesFile : std::exception
{
public:
- const char *what() const noexcept override { return "Cannot parse qml types file!"; }
+ const char *what() const noexcept override;
};
-class CannotParseQmlDocumentFile : std::exception
+class QMLDESIGNERCORE_EXPORT CannotParseQmlDocumentFile : std::exception
{
public:
- const char *what() const noexcept override { return "Cannot parse qml types file!"; }
+ const char *what() const noexcept override;
};
-class ProjectDataHasInvalidProjectSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidProjectSourceId : std::exception
{
public:
- const char *what() const noexcept override { return "The project source id is invalid!"; }
+ const char *what() const noexcept override;
};
-class ProjectDataHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidSourceId : std::exception
{
public:
- const char *what() const noexcept override { return "The source id is invalid!"; }
+ const char *what() const noexcept override;
};
-class ProjectDataHasInvalidModuleId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidModuleId : std::exception
{
public:
- const char *what() const noexcept override { return "The module id is invalid!"; }
+ const char *what() const noexcept override;
};
-class FileStatusHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT FileStatusHasInvalidSourceId : std::exception
{
public:
- const char *what() const noexcept override
- {
- return "The source id in file status is invalid!";
- }
+ const char *what() const noexcept override;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
index c27dcc0363..0d3bc730f8 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
@@ -32,7 +32,6 @@ void set_greedy_intersection_call(
}
}
-
template<typename FileSystemWatcher, typename Timer, class SourcePathCache>
class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface
{
@@ -61,10 +60,31 @@ public:
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
{
- auto entriesAndIds = convertIdPathsToWatcherEntriesAndIds(idPaths);
+ const auto &[entires, ids] = convertIdPathsToWatcherEntriesAndIds(idPaths);
+
+ addEntries(entires);
+
+ auto notContainsdId = [&, &ids = ids](WatcherEntry entry) {
+ return !std::binary_search(ids.begin(), ids.end(), entry.id);
+ };
+ removeUnusedEntries(entires, notContainsdId);
+ }
+
+ void updateContextIdPaths(const std::vector<IdPaths> &idPaths,
+ const SourceContextIds &sourceContextIds)
+ {
+ const auto &[entires, ids] = convertIdPathsToWatcherEntriesAndIds(idPaths);
+
+ addEntries(entires);
- addEntries(entriesAndIds.first);
- removeUnusedEntries(entriesAndIds.first, entriesAndIds.second);
+ auto notContainsdId = [&, &ids = ids](WatcherEntry entry) {
+ return !std::binary_search(ids.begin(), ids.end(), entry.id)
+ || !std::binary_search(sourceContextIds.begin(),
+ sourceContextIds.end(),
+ entry.sourceContextId);
+ };
+
+ removeUnusedEntries(entires, notContainsdId);
}
void removeIds(const ProjectPartIds &ids) override
@@ -134,9 +154,10 @@ public:
m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
- void removeUnusedEntries(const WatcherEntries &entries, const ProjectChunkIds &ids)
+ template<typename Filter>
+ void removeUnusedEntries(const WatcherEntries &entries, Filter filter)
{
- auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
+ auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, filter);
removeFromWatchedEntries(oldEntries);
@@ -195,10 +216,8 @@ public:
return notWatchedDirectoryIds;
}
- template <typename Compare>
- WatcherEntries notAnymoreWatchedEntries(
- const WatcherEntries &newEntries,
- Compare compare) const
+ template<typename Compare>
+ WatcherEntries notAnymoreWatchedEntries(const WatcherEntries &newEntries, Compare compare) const
{
WatcherEntries notAnymoreWatchedEntries;
notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
@@ -213,16 +232,12 @@ public:
return notAnymoreWatchedEntries;
}
- WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries,
- const ProjectChunkIds &ids) const
+ template<typename Filter>
+ WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries, Filter filter) const
{
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
- auto newEnd = std::remove_if(oldEntries.begin(),
- oldEntries.end(),
- [&] (WatcherEntry entry) {
- return !std::binary_search(ids.begin(), ids.end(), entry.id);
- });
+ auto newEnd = std::remove_if(oldEntries.begin(), oldEntries.end(), filter);
oldEntries.erase(newEnd, oldEntries.end());
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
index a15482120f..a9185d91e8 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatchertypes.h
@@ -10,7 +10,7 @@
namespace QmlDesigner {
-enum class SourceType : int { Qml, QmlUi, QmlTypes, QmlDir };
+enum class SourceType : int { Qml, QmlUi, QmlTypes, QmlDir, Directory };
class ProjectChunkId
{
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
index fd22a7b26d..f98c69734a 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
@@ -6,6 +6,7 @@
#include "filestatuscache.h"
#include "filesysteminterface.h"
#include "projectstorage.h"
+#include "projectstoragepathwatcherinterface.h"
#include "qmldocumentparserinterface.h"
#include "qmltypesparserinterface.h"
#include "sourcepath.h"
@@ -59,11 +60,11 @@ ProjectStorageUpdater::Components createComponents(
ModuleId moduleId,
ModuleId pathModuleId,
FileSystemInterface &fileSystem,
- const QString &directory)
+ const Utils::PathString &directory)
{
ProjectStorageUpdater::Components components;
- auto qmlFileNames = fileSystem.qmlFileNames(directory);
+ auto qmlFileNames = fileSystem.qmlFileNames(QString{directory});
components.reserve(static_cast<std::size_t>(qmlDirParserComponents.size() + qmlFileNames.size()));
@@ -160,28 +161,39 @@ void addModuleExportedImports(Storage::Synchronization::ModuleExportedImports &i
} // namespace
-void ProjectStorageUpdater::update(QStringList directories, QStringList qmlTypesPaths)
+void ProjectStorageUpdater::update(QStringList directories,
+ QStringList qmlTypesPaths,
+ ProjectPartId projectPartId)
{
Storage::Synchronization::SynchronizationPackage package;
+ SourceIdsData sourceIdsData{static_cast<std::size_t>(directories.size())};
+ std::vector<IdPaths> idPaths;
+ idPaths.reserve(4);
- SourceIds notUpdatedFileStatusSourceIds;
- SourceIds notUpdatedSourceIds;
-
- updateDirectories(directories, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
- updateQmlTypes(qmlTypesPaths, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
+ updateDirectories(directories, package, sourceIdsData);
+ updateQmlTypes(qmlTypesPaths, package, sourceIdsData);
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
- std::move(notUpdatedSourceIds));
+ std::move(sourceIdsData.notUpdatedSourceIds));
package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
- std::move(package.updatedFileStatusSourceIds), std::move(notUpdatedFileStatusSourceIds));
+ std::move(package.updatedFileStatusSourceIds),
+ std::move(sourceIdsData.notUpdatedFileStatusSourceIds));
m_projectStorage.synchronize(std::move(package));
+
+ idPaths.push_back(
+ {projectPartId, SourceType::Directory, std::move(sourceIdsData.watchedDirectorySourceIds)});
+ idPaths.push_back(
+ {projectPartId, SourceType::QmlDir, std::move(sourceIdsData.watchedQmldirSourceIds)});
+ idPaths.push_back({projectPartId, SourceType::Qml, std::move(sourceIdsData.watchedQmlSourceIds)});
+ idPaths.push_back(
+ {projectPartId, SourceType::QmlTypes, std::move(sourceIdsData.watchedQmltypesSourceIds)});
+ m_pathWatcher.updateIdPaths(idPaths);
}
void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds)
+ SourceIdsData &sourceIdsData)
{
if (qmlTypesPaths.empty())
return;
@@ -190,6 +202,7 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
for (const QString &qmlTypesPath : qmlTypesPaths) {
SourceId sourceId = m_pathCache.sourceId(SourcePath{qmlTypesPath});
+ sourceIdsData.watchedQmltypesSourceIds.push_back(sourceId);
Storage::Synchronization::ProjectData projectData{sourceId,
sourceId,
@@ -199,8 +212,7 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
FileState state = parseTypeInfo(projectData,
Utils::PathString{qmlTypesPath},
package,
- notUpdatedFileStatusSourceIds,
- notUpdatedSourceIds);
+ sourceIdsData);
if (state == FileState::Changed)
package.projectDatas.push_back(std::move(projectData));
@@ -223,113 +235,118 @@ ProjectStorageUpdater::FileState combineState(FileStates... fileStates)
void ProjectStorageUpdater::updateDirectories(const QStringList &directories,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds)
+ SourceIdsData &sourceIdsData)
+{
+ for (const QString &directory : directories)
+ updateDirectory({directory}, package, sourceIdsData);
+}
+
+void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath,
+ Storage::Synchronization::SynchronizationPackage &package,
+ SourceIdsData &sourceIdsData)
{
- for (const QString &directory : directories) {
- Utils::PathString directoryPath = directory;
- SourcePath qmldirSourcePath{directory + "/qmldir"};
- auto [directoryId, qmlDirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath);
-
- SourcePath directorySourcePath{directory + "/."};
- auto directorySourceId = m_pathCache.sourceId(directorySourcePath);
-
- auto directoryState = fileState(directorySourceId,
- package.fileStatuses,
- package.updatedFileStatusSourceIds,
- notUpdatedFileStatusSourceIds);
-
- auto qmldirState = fileState(qmlDirSourceId,
- package.fileStatuses,
- package.updatedFileStatusSourceIds,
- notUpdatedFileStatusSourceIds);
-
- switch (combineState(directoryState, qmldirState)) {
- case FileState::Changed: {
- QmlDirParser parser;
+ SourcePath qmldirSourcePath{directoryPath + "/qmldir"};
+ auto [directoryId, qmlDirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath);
+
+ SourcePath directorySourcePath{directoryPath + "/."};
+ auto directorySourceId = m_pathCache.sourceId(directorySourcePath);
+ auto directoryState = fileState(directorySourceId, package, sourceIdsData);
+ if (directoryState != FileState::NotExists)
+ sourceIdsData.watchedDirectorySourceIds.push_back(directorySourceId);
+
+ auto qmldirState = fileState(qmlDirSourceId, package, sourceIdsData);
+ if (qmldirState != FileState::NotExists)
+ sourceIdsData.watchedQmldirSourceIds.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(qmlDirSourceId);
- addSourceIds(package.updatedSourceIds, qmlProjectDatas);
- addSourceIds(package.updatedFileStatusSourceIds, qmlProjectDatas);
-
- auto qmlTypes = filterMultipleEntries(parser.typeInfos());
-
- if (!qmlTypes.isEmpty()) {
- parseTypeInfos(qmlTypes,
- filterMultipleEntries(parser.dependencies()),
- imports,
- qmlDirSourceId,
- directoryPath,
- cppModuleId,
- package,
- notUpdatedFileStatusSourceIds,
- notUpdatedSourceIds);
- }
- parseQmlComponents(
- createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directory),
- qmlDirSourceId,
- directoryId,
- package,
- notUpdatedFileStatusSourceIds);
- package.updatedProjectSourceIds.push_back(qmlDirSourceId);
- break;
+ 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,
+ sourceIdsData);
}
- case FileState::NotChanged: {
- parseProjectDatas(m_projectStorage.fetchProjectDatas(qmlDirSourceId),
- package,
- notUpdatedFileStatusSourceIds,
- notUpdatedSourceIds,
- directoryPath);
- break;
+ parseQmlComponents(
+ createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath),
+ directorySourceId,
+ directoryId,
+ package,
+ sourceIdsData,
+ qmldirState);
+ package.updatedProjectSourceIds.push_back(directorySourceId);
+ break;
+ }
+ case FileState::NotChanged: {
+ parseProjectDatas(m_projectStorage.fetchProjectDatas(directorySourceId), package, sourceIdsData);
+ break;
+ }
+ case FileState::NotExists: {
+ 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);
}
- case FileState::NotExists: {
- package.updatedSourceIds.push_back(qmlDirSourceId);
- auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
- for (const Storage::Synchronization::ProjectData &projectData : qmlProjectDatas) {
- package.updatedSourceIds.push_back(projectData.sourceId);
- }
- break;
- }
- }
+ break;
+ }
}
}
-void ProjectStorageUpdater::pathsWithIdsChanged([[maybe_unused]] const std::vector<IdPaths> &idPaths)
-{}
+void ProjectStorageUpdater::pathsWithIdsChanged([[maybe_unused]] const std::vector<IdPaths> &) {}
+
+void ProjectStorageUpdater::pathsChanged(const SourceIds &) {}
void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
Utils::SmallStringView directoryPath,
ModuleId moduleId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds)
+ SourceIdsData &sourceIdData)
{
for (const QString &typeInfo : typeInfos) {
Utils::PathString qmltypesPath = Utils::PathString::join(
{directoryPath, "/", Utils::SmallString{typeInfo}});
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath});
+ sourceIdData.watchedQmltypesSourceIds.push_back(sourceId);
+
addDependencies(package.moduleDependencies,
sourceId,
joinImports(qmldirDependencies, qmldirImports),
@@ -337,43 +354,29 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
package.updatedModuleDependencySourceIds.push_back(sourceId);
auto projectData = package.projectDatas.emplace_back(
- qmldirSourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes);
+ directorySourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes);
- parseTypeInfo(projectData,
- qmltypesPath,
- package,
- notUpdatedFileStatusSourceIds,
- notUpdatedSourceIds);
+ parseTypeInfo(projectData, qmltypesPath, package, sourceIdData);
}
}
void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds,
- Utils::SmallStringView directoryPath)
+ SourceIdsData &sourceIdData)
{
for (const Storage::Synchronization::ProjectData &projectData : projectDatas) {
switch (projectData.fileType) {
case Storage::Synchronization::FileType::QmlTypes: {
- auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
+ sourceIdData.watchedQmltypesSourceIds.push_back(projectData.sourceId);
- parseTypeInfo(projectData,
- qmltypesPath,
- package,
- notUpdatedFileStatusSourceIds,
- notUpdatedSourceIds);
+ auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
+ parseTypeInfo(projectData, qmltypesPath, package, sourceIdData);
break;
}
case Storage::Synchronization::FileType::QmlDocument: {
- SourcePath qmlDocumentPath = m_pathCache.sourcePath(projectData.sourceId);
-
- parseQmlComponent(qmlDocumentPath.name(),
- qmlDocumentPath,
- directoryPath,
- projectData.sourceId,
- package,
- notUpdatedFileStatusSourceIds);
+ sourceIdData.watchedQmlSourceIds.push_back(projectData.sourceId);
+
+ parseQmlComponent(projectData.sourceId, package, sourceIdData);
}
};
}
@@ -382,13 +385,9 @@ void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::Pr
auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds) -> FileState
+ SourceIdsData &sourceIdData) -> FileState
{
- auto state = fileState(projectData.sourceId,
- package.fileStatuses,
- package.updatedFileStatusSourceIds,
- notUpdatedFileStatusSourceIds);
+ auto state = fileState(projectData.sourceId, package, sourceIdData);
switch (state) {
case FileState::Changed: {
package.updatedSourceIds.push_back(projectData.sourceId);
@@ -398,10 +397,11 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Projec
break;
}
case FileState::NotChanged: {
- notUpdatedSourceIds.push_back(projectData.sourceId);
+ sourceIdData.notUpdatedSourceIds.push_back(projectData.sourceId);
break;
}
case FileState::NotExists:
+ throw CannotParseQmlTypesFile{};
break;
}
@@ -411,9 +411,10 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Projec
void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath,
Utils::SmallStringView directoryPath,
Storage::Synchronization::ExportedTypes exportedTypes,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds)
+ SourceIdsData &sourceIdData,
+ FileState qmldirState)
{
if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end())
return;
@@ -422,13 +423,21 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmlFilePath});
Storage::Synchronization::Type type;
+ auto state = fileState(sourceId, package, sourceIdData);
+
+ sourceIdData.watchedQmlSourceIds.push_back(sourceId);
- auto state = fileState(sourceId,
- package.fileStatuses,
- package.updatedFileStatusSourceIds,
- notUpdatedFileStatusSourceIds);
switch (state) {
case FileState::NotChanged:
+ if (qmldirState == FileState::NotExists) {
+ sourceIdData.notUpdatedSourceIds.emplace_back(sourceId);
+ package.projectDatas.emplace_back(directorySourceId,
+ sourceId,
+ ModuleId{},
+ Storage::Synchronization::FileType::QmlDocument);
+
+ return;
+ }
type.changeLevel = Storage::Synchronization::ChangeLevel::Minimal;
break;
case FileState::NotExists:
@@ -439,7 +448,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
break;
}
- package.projectDatas.emplace_back(qmldirSourceId,
+ package.projectDatas.emplace_back(directorySourceId,
sourceId,
ModuleId{},
Storage::Synchronization::FileType::QmlDocument);
@@ -454,28 +463,22 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
package.types.push_back(std::move(type));
}
-void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName,
- Utils::SmallStringView filePath,
- Utils::SmallStringView directoryPath,
- SourceId sourceId,
+void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds)
+ SourceIdsData &sourceIdData)
{
- auto state = fileState(sourceId,
- package.fileStatuses,
- package.updatedFileStatusSourceIds,
- notUpdatedFileStatusSourceIds);
+ auto state = fileState(sourceId, package, sourceIdData);
if (state != FileState::Changed)
return;
package.updatedSourceIds.push_back(sourceId);
- SourcePath sourcePath{filePath};
+ SourcePath sourcePath = m_pathCache.sourcePath(sourceId);
- const auto content = m_fileSystem.contentAsQString(QString{filePath});
- auto type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
+ const auto content = m_fileSystem.contentAsQString(QString{sourcePath});
+ auto type = m_qmlDocumentParser.parse(content, package.imports, sourceId, sourcePath.directory());
- type.typeName = fileName;
+ type.typeName = sourcePath.name();
type.traits = Storage::TypeTraits::Reference;
type.sourceId = sourceId;
type.changeLevel = Storage::Synchronization::ChangeLevel::ExcludeExportedTypes;
@@ -520,10 +523,11 @@ Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdate
} // namespace
void ProjectStorageUpdater::parseQmlComponents(Components components,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
SourceContextId directoryId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds)
+ SourceIdsData &sourceIdsData,
+ FileState qmldirState)
{
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
return first.fileName < second.fileName;
@@ -537,33 +541,36 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
parseQmlComponent(fileName,
directoryPath,
createExportedTypes(componentsWithSameFileName),
- qmldirSourceId,
+ directorySourceId,
package,
- notUpdatedFileStatusSourceIds);
+ sourceIdsData,
+ qmldirState);
};
rangeForTheSameFileName(components, callback);
}
-ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(SourceId sourceId,
- FileStatuses &fileStatuses,
- SourceIds &updatedSourceIds,
- SourceIds &notUpdatedSourceIds) const
+ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(
+ SourceId sourceId,
+ Storage::Synchronization::SynchronizationPackage &package,
+ SourceIdsData &sourceIdData) const
{
auto currentFileStatus = m_fileStatusCache.find(sourceId);
- if (!currentFileStatus.isValid())
+ if (!currentFileStatus.isValid()) {
+ package.updatedFileStatusSourceIds.push_back(sourceId);
return FileState::NotExists;
+ }
auto projectStorageFileStatus = m_projectStorage.fetchFileStatus(sourceId);
if (!projectStorageFileStatus.isValid() || projectStorageFileStatus != currentFileStatus) {
- fileStatuses.push_back(currentFileStatus);
- updatedSourceIds.push_back(currentFileStatus.sourceId);
+ package.fileStatuses.push_back(currentFileStatus);
+ package.updatedFileStatusSourceIds.push_back(sourceId);
return FileState::Changed;
}
- notUpdatedSourceIds.push_back(currentFileStatus.sourceId);
+ sourceIdData.notUpdatedFileStatusSourceIds.push_back(sourceId);
return FileState::NotChanged;
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
index 417ec715e8..90ce4d543d 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
@@ -6,8 +6,10 @@
#include "filestatus.h"
#include "nonlockingmutex.h"
#include "projectstorageids.h"
+#include "projectstoragepathwatchernotifierinterface.h"
#include "projectstoragepathwatchertypes.h"
#include "projectstoragetypes.h"
+#include "sourcepath.h"
#include <qmljs/parser/qmldirparser_p.h>
@@ -30,7 +32,7 @@ class ProjectStorage;
class QmlDocumentParserInterface;
class QmlTypesParserInterface;
-class ProjectStorageUpdater
+class ProjectStorageUpdater : public ProjectStoragePathWatcherNotifierInterface
{
public:
using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
@@ -40,17 +42,22 @@ public:
FileStatusCache &fileStatusCache,
PathCache &pathCache,
QmlDocumentParserInterface &qmlDocumentParser,
- QmlTypesParserInterface &qmlTypesParser)
+ QmlTypesParserInterface &qmlTypesParser,
+ class ProjectStoragePathWatcherInterface &pathWatcher)
: m_fileSystem{fileSystem}
, m_projectStorage{projectStorage}
, m_fileStatusCache{fileStatusCache}
, m_pathCache{pathCache}
, m_qmlDocumentParser{qmlDocumentParser}
, m_qmlTypesParser{qmlTypesParser}
+ , m_pathWatcher{pathWatcher}
{}
- void update(QStringList directories, QStringList qmlTypesPaths);
- void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths);
+ void update(QStringList directories,
+ QStringList qmlTypesPaths,
+ ProjectPartId projectPartId = ProjectPartId{});
+ void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) override;
+ void pathsChanged(const SourceIds &filePathIds) override;
struct Component
{
@@ -90,57 +97,73 @@ public:
};
private:
+ struct SourceIdsData
+ {
+ SourceIdsData(std::size_t reserve)
+ {
+ notUpdatedFileStatusSourceIds.reserve(reserve * 30);
+ notUpdatedSourceIds.reserve(reserve * 30);
+ watchedDirectorySourceIds.reserve(reserve);
+ watchedQmldirSourceIds.reserve(reserve);
+ watchedQmlSourceIds.reserve(reserve * 30);
+ watchedQmltypesSourceIds.reserve(reserve * 30);
+ }
+
+ SourceIds notUpdatedFileStatusSourceIds;
+ SourceIds notUpdatedSourceIds;
+ SourceIds watchedDirectorySourceIds;
+ SourceIds watchedQmldirSourceIds;
+ SourceIds watchedQmlSourceIds;
+ SourceIds watchedQmltypesSourceIds;
+ };
void updateQmlTypes(const QStringList &qmlTypesPaths,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds);
+ SourceIdsData &sourceIdData);
+
void updateDirectories(const QStringList &directories,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds);
+ SourceIdsData &sourceIdData);
+
+ void updateDirectory(const Utils::PathString &directory,
+ Storage::Synchronization::SynchronizationPackage &package,
+ SourceIdsData &sourceIdData);
void parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
Utils::SmallStringView directoryPath,
ModuleId moduleId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds);
+ SourceIdsData &sourceIdData);
void parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds,
- Utils::SmallStringView directoryPath);
+ SourceIdsData &sourceIdData);
FileState parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds,
- SourceIds &notUpdatedSourceIds);
+ SourceIdsData &sourceIdData);
void parseQmlComponents(Components components,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
SourceContextId directoryId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds);
+ SourceIdsData &sourceIdData,
+ FileState qmldirState);
void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView directory,
Storage::Synchronization::ExportedTypes exportedTypes,
- SourceId qmldirSourceId,
+ SourceId directorySourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds);
- void parseQmlComponent(Utils::SmallStringView fileName,
- Utils::SmallStringView filePath,
- Utils::SmallStringView directoryPath,
- SourceId sourceId,
+ SourceIdsData &sourceIdData,
+ FileState qmldirState);
+ void parseQmlComponent(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIds &notUpdatedFileStatusSourceIds);
+ SourceIdsData &sourceIdData);
FileState fileState(SourceId sourceId,
- FileStatuses &fileStatuses,
- SourceIds &updatedSourceIds,
- SourceIds &notUpdatedSourceIds) const;
+ Storage::Synchronization::SynchronizationPackage &package,
+ SourceIdsData &sourceIdData) const;
private:
FileSystemInterface &m_fileSystem;
@@ -149,6 +172,7 @@ private:
PathCache &m_pathCache;
QmlDocumentParserInterface &m_qmlDocumentParser;
QmlTypesParserInterface &m_qmlTypesParser;
+ ProjectStoragePathWatcherInterface &m_pathWatcher;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
index 89d9b1bf0b..97aac6a857 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
@@ -11,7 +11,7 @@
#include <sqlitedatabase.h>
#ifdef QDS_HAS_QMLDOM
-#include <qmldom/qqmldomtop_p.h>
+#include <private/qqmldomtop_p.h>
#endif
#include <filesystem>
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
index a1e189d9fb..744825aadc 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
@@ -4,10 +4,9 @@
#pragma once
#include "nonlockingmutex.h"
+#include "projectstoragefwd.h"
#include "qmldocumentparserinterface.h"
-#include <projectstoragefwd.h>
-
namespace QmlDesigner {
template<typename ProjectStorage, typename Mutex>
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
index de299347a3..bca7b3279d 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
@@ -9,8 +9,8 @@
#include <sqlitedatabase.h>
#ifdef QDS_HAS_QMLDOM
-#include <qmlcompiler/qqmljstypedescriptionreader_p.h>
-#include <qmldom/qqmldomtop_p.h>
+#include <private/qqmldomtop_p.h>
+#include <private/qqmljstypedescriptionreader_p.h>
#endif
#include <QDateTime>
@@ -21,28 +21,30 @@
namespace QmlDesigner {
#ifdef QDS_HAS_QMLDOM
+
namespace QmlDom = QQmlJS::Dom;
namespace {
using ComponentWithoutNamespaces = QMap<QString, QString>;
-ComponentWithoutNamespaces createComponentNameWithoutNamespaces(
- const QHash<QString, QQmlJSExportedScope> &objects)
+using Storage::TypeNameString;
+
+ComponentWithoutNamespaces createComponentNameWithoutNamespaces(const QList<QQmlJSExportedScope> &objects)
{
ComponentWithoutNamespaces componentWithoutNamespaces;
- for (auto current = objects.keyBegin(), end = objects.keyEnd(); current != end; ++current) {
- const QString &key = *current;
+ for (const auto &object : objects) {
+ const QString &name = object.scope->internalName();
QString searchTerm{"::"};
- auto found = std::search(key.cbegin(), key.cend(), searchTerm.cbegin(), searchTerm.cend());
+ auto found = std::search(name.cbegin(), name.cend(), searchTerm.cbegin(), searchTerm.cend());
- if (found == key.cend())
+ if (found == name.cend())
continue;
- componentWithoutNamespaces.insert(QStringView{std::next(found, 2), key.cend()}.toString(),
- key);
+ componentWithoutNamespaces.insert(QStringView{std::next(found, 2), name.cend()}.toString(),
+ name);
}
return componentWithoutNamespaces;
@@ -79,21 +81,20 @@ void addImports(Storage::Synchronization::Imports &imports,
imports.emplace_back(qmlCppModuleId, Storage::Synchronization::Version{}, sourceId);
}
-Storage::Synchronization::TypeTraits createTypeTraits(
- QQmlJSScope::AccessSemantics accessSematics)
+Storage::TypeTraits createTypeTraits(QQmlJSScope::AccessSemantics accessSematics)
{
switch (accessSematics) {
case QQmlJSScope::AccessSemantics::Reference:
- return Storage::Synchronization::TypeTraits::Reference;
+ return Storage::TypeTraits::Reference;
case QQmlJSScope::AccessSemantics::Value:
- return Storage::Synchronization::TypeTraits::Value;
+ return Storage::TypeTraits::Value;
case QQmlJSScope::AccessSemantics::None:
- return Storage::Synchronization::TypeTraits::None;
+ return Storage::TypeTraits::None;
case QQmlJSScope::AccessSemantics::Sequence:
- return Storage::Synchronization::TypeTraits::Sequence;
+ return Storage::TypeTraits::Sequence;
}
- return Storage::Synchronization::TypeTraits::None;
+ return Storage::TypeTraits::None;
}
Storage::Synchronization::Version createVersion(QTypeRevision qmlVersion)
@@ -227,16 +228,9 @@ Storage::Synchronization::ParameterDeclarations createParameters(
{
Storage::Synchronization::ParameterDeclarations parameterDeclarations;
- const QStringList &parameterNames = qmlMethod.parameterNames();
- const QStringList &parameterTypeNames = qmlMethod.parameterTypeNames();
- auto currentName = parameterNames.begin();
- auto currentType = parameterTypeNames.begin();
- auto nameEnd = parameterNames.end();
- auto typeEnd = parameterTypeNames.end();
-
- for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) {
- parameterDeclarations.emplace_back(Utils::SmallString{*currentName},
- fullyQualifiedTypeName(*currentType,
+ for (const auto &parameter : qmlMethod.parameters()) {
+ parameterDeclarations.emplace_back(Utils::SmallString{parameter.name()},
+ fullyQualifiedTypeName(parameter.typeName(),
componentNameWithoutNamespace));
}
@@ -347,8 +341,8 @@ void addEnumerationType(EnumerationTypes &enumerationTypes,
auto fullTypeName = addEnumerationType(enumerationTypes, typeName, enumerationName);
types.emplace_back(fullTypeName,
Storage::Synchronization::ImportedType{TypeNameString{}},
- Storage::Synchronization::TypeTraits::Value
- | Storage::Synchronization::TypeTraits::IsEnum,
+ Storage::Synchronization::ImportedType{},
+ Storage::TypeTraits::Value | Storage::TypeTraits::IsEnum,
sourceId,
createCppEnumerationExports(typeName,
cppModuleId,
@@ -416,22 +410,22 @@ void addType(Storage::Synchronization::Types &types,
auto exports = exportScope.exports;
auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations);
- types.emplace_back(Utils::SmallStringView{typeName},
- Storage::Synchronization::ImportedType{TypeNameString{component.baseTypeName()}},
- createTypeTraits(component.traits()),
- sourceId,
- createExports(exports, typeName, storage, cppModuleId),
- createProperties(component.ownProperties(),
- enumerationTypes,
- componentNameWithoutNamespace),
- std::move(functionsDeclarations),
- std::move(signalDeclarations),
- createEnumeration(enumerations));
+ types.emplace_back(
+ Utils::SmallStringView{typeName},
+ Storage::Synchronization::ImportedType{TypeNameString{component.baseTypeName()}},
+ Storage::Synchronization::ImportedType{TypeNameString{component.extensionTypeName()}},
+ createTypeTraits(component.accessSemantics()),
+ sourceId,
+ createExports(exports, typeName, storage, cppModuleId),
+ createProperties(component.ownProperties(), enumerationTypes, componentNameWithoutNamespace),
+ std::move(functionsDeclarations),
+ std::move(signalDeclarations),
+ createEnumeration(enumerations));
}
void addTypes(Storage::Synchronization::Types &types,
const Storage::Synchronization::ProjectData &projectData,
- const QHash<QString, QQmlJSExportedScope> &objects,
+ const QList<QQmlJSExportedScope> &objects,
QmlTypesParser::ProjectStorage &storage,
const ComponentWithoutNamespaces &componentNameWithoutNamespaces)
{
@@ -454,7 +448,7 @@ void QmlTypesParser::parse(const QString &sourceContent,
const Storage::Synchronization::ProjectData &projectData)
{
QQmlJSTypeDescriptionReader reader({}, sourceContent);
- QHash<QString, QQmlJSExportedScope> components;
+ QList<QQmlJSExportedScope> components;
QStringList dependencies;
bool isValid = reader(&components, &dependencies);
if (!isValid)
diff --git a/src/plugins/qmldesigner/designmodecontext.cpp b/src/plugins/qmldesigner/designmodecontext.cpp
index 3249e1bc18..ca1b927c3a 100644
--- a/src/plugins/qmldesigner/designmodecontext.cpp
+++ b/src/plugins/qmldesigner/designmodecontext.cpp
@@ -2,12 +2,13 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "designmodecontext.h"
-#include "qmldesignerconstants.h"
+#include "assetslibrarywidget.h"
#include "designmodewidget.h"
-#include "formeditorwidget.h"
#include "edit3dwidget.h"
+#include "formeditorwidget.h"
#include "materialbrowserwidget.h"
#include "navigatorwidget.h"
+#include "qmldesignerconstants.h"
#include "texteditorwidget.h"
namespace QmlDesigner {
@@ -61,6 +62,18 @@ void MaterialBrowserContext::contextHelp(const HelpCallback &callback) const
qobject_cast<MaterialBrowserWidget *>(m_widget)->contextHelp(callback);
}
+AssetsLibraryContext::AssetsLibraryContext(QWidget *widget)
+ : IContext(widget)
+{
+ setWidget(widget);
+ setContext(Core::Context(Constants::C_QMLASSETSLIBRARY, Constants::C_QT_QUICK_TOOLS_MENU));
+}
+
+void AssetsLibraryContext::contextHelp(const HelpCallback &callback) const
+{
+ qobject_cast<AssetsLibraryWidget *>(m_widget)->contextHelp(callback);
+}
+
NavigatorContext::NavigatorContext(QWidget *widget)
: IContext(widget)
{
diff --git a/src/plugins/qmldesigner/designmodecontext.h b/src/plugins/qmldesigner/designmodecontext.h
index c8c728657a..fab7fe0ea3 100644
--- a/src/plugins/qmldesigner/designmodecontext.h
+++ b/src/plugins/qmldesigner/designmodecontext.h
@@ -47,6 +47,15 @@ public:
void contextHelp(const Core::IContext::HelpCallback &callback) const override;
};
+class AssetsLibraryContext : public Core::IContext
+{
+ Q_OBJECT
+
+public:
+ AssetsLibraryContext(QWidget *widget);
+ void contextHelp(const Core::IContext::HelpCallback &callback) const override;
+};
+
class NavigatorContext : public Core::IContext
{
Q_OBJECT
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index d203e2c8ff..2acdff1823 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -12,6 +12,7 @@
#include <nodeinstanceview.h>
#include <itemlibrarywidget.h>
#include <theme.h>
+#include <toolbar.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -90,6 +91,7 @@ DesignModeWidget::DesignModeWidget()
: m_toolBar(new Core::EditorToolBar(this))
, m_crumbleBar(new CrumbleBar(this))
{
+ setAcceptDrops(true);
}
DesignModeWidget::~DesignModeWidget()
@@ -189,11 +191,11 @@ void DesignModeWidget::setup()
const QSize size = QSize(28, 28);
auto tabCloseIconNormal = Utils::StyleHelper::IconFontHelper(
- closeUnicode, Theme::getColor(Theme::DStabInactiveIcon), size, QIcon::Normal, QIcon::Off);
+ closeUnicode, Theme::getColor(Theme::DSdockWidgetTitleBar), size, QIcon::Normal, QIcon::Off);
auto tabCloseIconActive = Utils::StyleHelper::IconFontHelper(
- closeUnicode, Theme::getColor(Theme::DStabActiveIcon), size, QIcon::Active, QIcon::Off);
+ closeUnicode, Theme::getColor(Theme::DSdockWidgetTitleBar), size, QIcon::Active, QIcon::Off);
auto tabCloseIconFocus = Utils::StyleHelper::IconFontHelper(
- closeUnicode, Theme::getColor(Theme::DStabFocusIcon), size, QIcon::Selected, QIcon::Off);
+ closeUnicode, Theme::getColor(Theme::DSdockWidgetTitleBar), size, QIcon::Selected, QIcon::Off);
const QIcon tabsCloseIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, {tabCloseIconNormal,
@@ -326,8 +328,19 @@ void DesignModeWidget::setup()
command->setAttribute(Core::Command::CA_Hide);
viewCommands.append(command);
- connect(outputPanePlaceholder, &Core::OutputPanePlaceHolder::visibilityChangeRequested,
- m_outputPaneDockWidget, &ADS::DockWidget::toggleView);
+ connect(command->action(), &QAction::triggered, this, [command]() {
+ if (!command->action()->isChecked())
+ return;
+
+ auto cmd = Core::ActionManager::command("QtCreator.Pane.ApplicationOutput");
+ QTC_ASSERT(cmd, return);
+ cmd->action()->trigger();
+ });
+
+ connect(outputPanePlaceholder,
+ &Core::OutputPanePlaceHolder::visibilityChangeRequested,
+ m_outputPaneDockWidget,
+ &ADS::DockWidget::toggleView);
}
std::sort(viewCommands.begin(), viewCommands.end(), [](Core::Command *first, Core::Command *second){
@@ -338,27 +351,69 @@ void DesignModeWidget::setup()
mviews->addAction(command);
// Create toolbars
- auto toolBar = new QToolBar();
-
- toolBar->addAction(viewManager().componentViewAction());
- toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
- DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()->viewManager().designerActionManager().createToolBar(m_toolBar);
-
- designerToolBar->layout()->addWidget(toolBar);
+ if (!ToolBar::isVisible()) {
+ auto toolBar = new QToolBar();
+
+ toolBar->addAction(viewManager().componentViewAction());
+ toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()->viewManager().designerActionManager().createToolBar(m_toolBar);
+
+ designerToolBar->layout()->addWidget(toolBar);
+
+ m_toolBar->addCenterToolBar(designerToolBar);
+ m_toolBar->setMinimumWidth(320);
+ m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone);
+ m_toolBar->setNavigationVisible(true);
+
+ connect(m_toolBar, &Core::EditorToolBar::goForwardClicked, this, &DesignModeWidget::toolBarOnGoForwardClicked);
+ connect(m_toolBar, &Core::EditorToolBar::goBackClicked, this, &DesignModeWidget::toolBarOnGoBackClicked);
+
+
+ QToolBar* toolBarWrapper = new QToolBar();
+ toolBarWrapper->addWidget(m_toolBar);
+ toolBarWrapper->addWidget(createCrumbleBarFrame());
+ toolBarWrapper->setMovable(false);
+ addToolBar(Qt::TopToolBarArea, toolBarWrapper);
+
+
+ addSpacerToToolBar(toolBar);
+
+ auto workspaceComboBox = new QComboBox();
+ workspaceComboBox->setMinimumWidth(120);
+ workspaceComboBox->setToolTip(tr("Switch the active workspace."));
+ auto sortedWorkspaces = m_dockManager->workspaces();
+ Utils::sort(sortedWorkspaces);
+ workspaceComboBox->addItems(sortedWorkspaces);
+ workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
+ toolBar->addWidget(workspaceComboBox);
+
+ connect(m_dockManager, &ADS::DockManager::workspaceListChanged,
+ workspaceComboBox, [this, workspaceComboBox]() {
+ workspaceComboBox->clear();
+ auto sortedWorkspaces = m_dockManager->workspaces();
+ Utils::sort(sortedWorkspaces);
+ workspaceComboBox->addItems(sortedWorkspaces);
+ workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
+ });
+ connect(m_dockManager, &ADS::DockManager::workspaceLoaded, workspaceComboBox, &QComboBox::setCurrentText);
+ connect(workspaceComboBox, &QComboBox::activated,
+ m_dockManager, [this, workspaceComboBox]([[maybe_unused]] int index) {
+ m_dockManager->openWorkspace(workspaceComboBox->currentText());
+ });
- m_toolBar->addCenterToolBar(designerToolBar);
- m_toolBar->setMinimumWidth(320);
- m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone);
- m_toolBar->setNavigationVisible(true);
+ const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont(
+ fontName, Theme::getIconUnicode(Theme::Icon::annotationBubble),
+ 36, 36, Theme::getColor(Theme::IconsBaseColor));
+ toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){
+ ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
- connect(m_toolBar, &Core::EditorToolBar::goForwardClicked, this, &DesignModeWidget::toolBarOnGoForwardClicked);
- connect(m_toolBar, &Core::EditorToolBar::goBackClicked, this, &DesignModeWidget::toolBarOnGoBackClicked);
+ if (node.isValid()) {
+ m_globalAnnotationEditor.setModelNode(node);
+ m_globalAnnotationEditor.showWidget();
+ }
+ });
- QToolBar* toolBarWrapper = new QToolBar();
- toolBarWrapper->addWidget(m_toolBar);
- toolBarWrapper->addWidget(createCrumbleBarFrame());
- toolBarWrapper->setMovable(false);
- addToolBar(Qt::TopToolBarArea, toolBarWrapper);
+ }
if (currentDesignDocument())
setupNavigatorHistory(currentDesignDocument()->textEditor());
@@ -389,43 +444,6 @@ void DesignModeWidget::setup()
}
});
- addSpacerToToolBar(toolBar);
-
- auto workspaceComboBox = new QComboBox();
- workspaceComboBox->setMinimumWidth(120);
- workspaceComboBox->setToolTip(tr("Switch the active workspace."));
- auto sortedWorkspaces = m_dockManager->workspaces();
- Utils::sort(sortedWorkspaces);
- workspaceComboBox->addItems(sortedWorkspaces);
- workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
- toolBar->addWidget(workspaceComboBox);
-
- connect(m_dockManager, &ADS::DockManager::workspaceListChanged,
- workspaceComboBox, [this, workspaceComboBox]() {
- workspaceComboBox->clear();
- auto sortedWorkspaces = m_dockManager->workspaces();
- Utils::sort(sortedWorkspaces);
- workspaceComboBox->addItems(sortedWorkspaces);
- workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
- });
- connect(m_dockManager, &ADS::DockManager::workspaceLoaded, workspaceComboBox, &QComboBox::setCurrentText);
- connect(workspaceComboBox, &QComboBox::activated,
- m_dockManager, [this, workspaceComboBox]([[maybe_unused]] int index) {
- m_dockManager->openWorkspace(workspaceComboBox->currentText());
- });
-
- const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont(
- fontName, Theme::getIconUnicode(Theme::Icon::annotationBubble),
- 36, 36, Theme::getColor(Theme::IconsBaseColor));
- toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){
- ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
-
- if (node.isValid()) {
- m_globalAnnotationEditor.setModelNode(node);
- m_globalAnnotationEditor.showWidget();
- }
- });
-
viewManager().enableWidgets();
@@ -497,6 +515,32 @@ void DesignModeWidget::toolBarOnGoForwardClicked()
}
}
+bool DesignModeWidget::canGoForward()
+{
+ return m_canGoForward;
+}
+
+bool DesignModeWidget::canGoBack()
+{
+ return m_canGoBack;
+}
+
+ADS::DockManager *DesignModeWidget::dockManager() const
+{
+ return m_dockManager;
+}
+
+GlobalAnnotationEditor &DesignModeWidget::globalAnnotationEditor()
+{
+ return m_globalAnnotationEditor;
+}
+
+void DesignModeWidget::dragEnterEvent(QDragEnterEvent *event)
+{
+ event->accept();
+ event->setDropAction(Qt::IgnoreAction);
+}
+
DesignDocument *DesignModeWidget::currentDesignDocument() const
{
return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument();
@@ -512,11 +556,14 @@ void DesignModeWidget::setupNavigatorHistory(Core::IEditor *editor)
if (!m_keepNavigatorHistory)
addNavigatorHistoryEntry(editor->document()->filePath());
- const bool canGoBack = m_navigatorHistoryCounter > 0;
- const bool canGoForward = m_navigatorHistoryCounter < (m_navigatorHistory.size() - 1);
- m_toolBar->setCanGoBack(canGoBack);
- m_toolBar->setCanGoForward(canGoForward);
- m_toolBar->setCurrentEditor(editor);
+ m_canGoBack = m_navigatorHistoryCounter > 0;
+ m_canGoForward = m_navigatorHistoryCounter < (m_navigatorHistory.size() - 1);
+ m_toolBar->setCanGoBack(m_canGoBack);
+ m_toolBar->setCanGoForward(m_canGoForward);
+ if (!ToolBar::isVisible())
+ m_toolBar->setCurrentEditor(editor);
+
+ emit navigationHistoryChanged();
}
void DesignModeWidget::addNavigatorHistoryEntry(const Utils::FilePath &fileName)
@@ -573,6 +620,8 @@ void DesignModeWidget::initialize()
}
m_initStatus = Initialized;
+
+ emit initialized();
}
} // namespace Internal
diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h
index ec0e916d53..1dfa79a0b3 100644
--- a/src/plugins/qmldesigner/designmodewidget.h
+++ b/src/plugins/qmldesigner/designmodewidget.h
@@ -64,12 +64,26 @@ public:
static QWidget *createProjectExplorerWidget(QWidget *parent);
-private:
- enum InitializeStatus { NotInitialized, Initializing, Initialized };
-
void toolBarOnGoBackClicked();
void toolBarOnGoForwardClicked();
+ bool canGoForward();
+ bool canGoBack();
+
+ ADS::DockManager *dockManager() const;
+
+ GlobalAnnotationEditor &globalAnnotationEditor();
+
+signals:
+ void navigationHistoryChanged();
+ void initialized();
+
+protected:
+ virtual void dragEnterEvent(QDragEnterEvent *event) override;
+
+private:
+ enum InitializeStatus { NotInitialized, Initializing, Initialized };
+
void setup();
bool isInNodeDefinition(int nodeOffset, int nodeLength, int cursorPos) const;
QmlDesigner::ModelNode nodeForPosition(int cursorPos) const;
@@ -96,6 +110,9 @@ private:
ADS::DockManager *m_dockManager = nullptr;
ADS::DockWidget *m_outputPaneDockWidget = nullptr;
GlobalAnnotationEditor m_globalAnnotationEditor;
+
+ bool m_canGoForward = false;
+ bool m_canGoBack = false;
};
} // namespace Internal
diff --git a/src/plugins/qmldesigner/dynamiclicensecheck.h b/src/plugins/qmldesigner/dynamiclicensecheck.h
index c26267c881..a3ddf6c192 100644
--- a/src/plugins/qmldesigner/dynamiclicensecheck.h
+++ b/src/plugins/qmldesigner/dynamiclicensecheck.h
@@ -32,6 +32,26 @@ inline ExtensionSystem::IPlugin *licenseCheckerPlugin()
return pluginSpec->plugin();
return nullptr;
}
+
+inline ExtensionSystem::IPlugin *dsLicenseCheckerPlugin()
+{
+ const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault(
+ ExtensionSystem::PluginManager::plugins(),
+ Utils::equal(&ExtensionSystem::PluginSpec::name, QString("DSLicense")));
+
+ if (pluginSpec)
+ return pluginSpec->plugin();
+ return nullptr;
+}
+
+inline bool dsLicenseCheckerPluginExists()
+{
+ const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault(
+ ExtensionSystem::PluginManager::plugins(),
+ Utils::equal(&ExtensionSystem::PluginSpec::name, QString("DSLicense")));
+
+ return pluginSpec;
+}
} // namespace Internal
inline FoundLicense checkLicense()
@@ -94,4 +114,23 @@ inline QString licenseeEmail()
return {};
}
+inline bool checkEnterpriseLicense()
+{
+ if (auto plugin = Internal::dsLicenseCheckerPlugin()) {
+ bool retVal = false;
+ bool success = QMetaObject::invokeMethod(plugin,
+ "checkEnterpriseLicense",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, retVal));
+
+ if (success)
+ return retVal;
+ }
+
+ if (Internal::dsLicenseCheckerPluginExists())
+ return false;
+
+ return true;
+}
+
} // namespace Utils
diff --git a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
index 8ce2712817..7d7957753c 100644
--- a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
+++ b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
@@ -33,22 +33,6 @@ void filterOutQtBaseImportPath(QStringList *stringList)
&& !dir.entryInfoList(QStringList("QtTest"), QDir::Dirs).isEmpty();
});
}
-
-Utils::FilePath pathForBinPuppet(ProjectExplorer::Target *target)
-{
- if (!target || !target->kit())
- return {};
-
- QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
-
- if (currentQtVersion)
- return currentQtVersion->binPath()
- .pathAppended(QString{"qml2puppet-"} + Core::Constants::IDE_VERSION_LONG)
- .withExecutableSuffix();
-
- return {};
-}
-
} // namespace
QProcessEnvironment PuppetEnvironmentBuilder::processEnvironment() const
@@ -74,9 +58,12 @@ QProcessEnvironment PuppetEnvironmentBuilder::processEnvironment() const
}
QProcessEnvironment PuppetEnvironmentBuilder::createEnvironment(
- ProjectExplorer::Target *target, const DesignerSettings &designerSettings, const Model &model)
+ ProjectExplorer::Target *target,
+ const DesignerSettings &designerSettings,
+ const Model &model,
+ const Utils::FilePath &qmlPuppetPath)
{
- PuppetEnvironmentBuilder builder{target, designerSettings, model};
+ PuppetEnvironmentBuilder builder{target, designerSettings, model, qmlPuppetPath};
return builder.processEnvironment();
}
@@ -244,7 +231,7 @@ void PuppetEnvironmentBuilder::addCustomFileSelectors() const
PuppetType PuppetEnvironmentBuilder::determinePuppetType() const
{
if (m_target && m_target->kit() && m_target->kit()->isValid()) {
- if (pathForBinPuppet(m_target).isExecutableFile())
+ if (m_qmlPuppetPath.isExecutableFile())
return PuppetType::Kit;
}
diff --git a/src/plugins/qmldesigner/puppetenvironmentbuilder.h b/src/plugins/qmldesigner/puppetenvironmentbuilder.h
index 22629db82c..e3ef33a721 100644
--- a/src/plugins/qmldesigner/puppetenvironmentbuilder.h
+++ b/src/plugins/qmldesigner/puppetenvironmentbuilder.h
@@ -20,17 +20,20 @@ class PuppetEnvironmentBuilder
public:
PuppetEnvironmentBuilder(ProjectExplorer::Target *target,
const class DesignerSettings &designerSettings,
- const class Model &model)
+ const class Model &model,
+ const Utils::FilePath &qmlPuppetPath)
: m_target(target)
, m_designerSettings(designerSettings)
, m_model(model)
+ , m_qmlPuppetPath(qmlPuppetPath)
{}
QProcessEnvironment processEnvironment() const;
static QProcessEnvironment createEnvironment(ProjectExplorer::Target *target,
const class DesignerSettings &designerSettings,
- const class Model &model);
+ const class Model &model,
+ const Utils::FilePath &qmlPuppetPath);
private:
PuppetType determinePuppetType() const;
@@ -53,6 +56,7 @@ private:
const Model &m_model;
mutable PuppetType m_availablePuppetType = {};
mutable Utils::Environment m_environment;
+ Utils::FilePath m_qmlPuppetPath;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index 2b6953ca1f..1803918750 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -17,6 +17,7 @@ const char C_QMLEDITOR3D[] = "QmlDesigner::Editor3D";
const char C_QMLNAVIGATOR[] = "QmlDesigner::Navigator";
const char C_QMLTEXTEDITOR[] = "QmlDesigner::TextEditor";
const char C_QMLMATERIALBROWSER[] = "QmlDesigner::MaterialBrowser";
+const char C_QMLASSETSLIBRARY[] = "QmlDesigner::AssetsLibrary";
// Special context for preview menu, shared b/w designer and text editor
const char C_QT_QUICK_TOOLS_MENU[] = "QmlDesigner::ToolsMenu";
@@ -56,6 +57,7 @@ const char EDIT3D_EDIT_SHOW_PARTICLE_EMITTER[] = "QmlDesigner.Editor3D.TogglePar
const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView";
const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle";
const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay";
+const char EDIT3D_PARTICLES_SEEKER[] = "QmlDesigner.Editor3D.ParticlesSeeker";
const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart";
const char EDIT3D_VISIBILITY_TOGGLES[] = "QmlDesigner.Editor3D.VisibilityToggles";
const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundColorActions";
@@ -123,13 +125,42 @@ const char EVENT_NAVIGATORVIEW_TIME[] = "navigatorView";
const char EVENT_DESIGNMODE_TIME[] = "designMode";
const char EVENT_MATERIALEDITOR_TIME[] = "materialEditor";
const char EVENT_MATERIALBROWSER_TIME[] = "materialBrowser";
+const char EVENT_CONTENTLIBRARY_TIME[] = "contentLibrary";
const char EVENT_INSIGHT_TIME[] = "insight";
+const char EVENT_TOOLBAR_MODE_CHANGE[] = "ToolBarTriggerModeChange";
+const char EVENT_TOOLBAR_PROJECT_SETTINGS[] = "ToolBarTriggerProjectSettings";
+const char EVENT_TOOLBAR_RUN_PROJECT[] = "ToolBarRunProject";
+const char EVENT_TOOLBAR_GO_FORWARD[] = "ToolBarGoForward";
+const char EVENT_TOOLBAR_GO_BACKWARD[] = "ToolBarGoBackward";
+const char EVENT_TOOLBAR_OPEN_FILE[] = "ToolBarOpenFile";
+const char EVENT_TOOLBAR_CLOSE_DOCUMENT[] = "ToolBarCloseCurrentDocument";
+const char EVENT_TOOLBAR_SHARE_APPLICATION[] = "ToolBarShareApplication";
+const char EVENT_TOOLBAR_SET_CURRENT_WORKSPACE[] = "ToolBarSetCurrentWorkspace";
+const char EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION[] = "ToolBarEditGlobalAnnotation";
+const char EVENT_STATUSBAR_SHOW_ZOOM[] = "StatusBarShowZoomMenu";
+const char EVENT_STATUSBAR_SET_STYLE[] = "StatusBarSetCurrentStyle";
const char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal";
// Copy/Paste Headers
const char HEADER_3DPASTE_CONTENT[] = "// __QmlDesigner.Editor3D.Paste__ \n";
+const char OBJECT_NAME_ASSET_LIBRARY[] = "QQuickWidgetAssetLibrary";
+const char OBJECT_NAME_CONTENT_LIBRARY[] = "QQuickWidgetContentLibrary";
+const char OBJECT_NAME_BUSY_INDICATOR[] = "QQuickWidgetBusyIndicator";
+const char OBJECT_NAME_COMPONENT_LIBRARY[] = "QQuickWidgetComponentLibrary";
+const char OBJECT_NAME_MATERIAL_BROWSER[] = "QQuickWidgetMaterialBrowser";
+const char OBJECT_NAME_MATERIAL_EDITOR[] = "QQuickWidgetMaterialEditor";
+const char OBJECT_NAME_PROPERTY_EDITOR[] = "QQuickWidgetPropertyEditor";
+const char OBJECT_NAME_STATES_EDITOR[] = "QQuickWidgetStatesEditor";
+const char OBJECT_NAME_TEXTURE_EDITOR[] = "QQuickWidgetTextureEditor";
+const char OBJECT_NAME_TOP_TOOLBAR[] = "QQuickWidgetTopToolbar";
+const char OBJECT_NAME_STATUSBAR[] = "QQuickWidgetStatusbar";
+const char OBJECT_NAME_TOP_FEEDBACK[] = "QQuickWidgetQDSFeedback";
+const char OBJECT_NAME_NEW_DIALOG[] = "QQuickWidgetQDSNewDialog";
+const char OBJECT_NAME_SPLASH_SCREEN[] = "QQuickWidgetSplashScreen";
+const char OBJECT_NAME_WELCOME_PAGE[] = "QQuickWidgetQDSWelcomePage";
+
namespace Internal {
enum { debug = 0 };
}
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
index 47174ba3d8..8282ea419a 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
@@ -12,6 +12,7 @@
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/target.h>
#include <puppetenvironmentbuilder.h>
+#include <qmlpuppetpaths.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
@@ -135,54 +136,6 @@ bool ExternalDependencies::hasStartupTarget() const
namespace {
-Utils::FilePath qmlPuppetExecutablePath(const Utils::FilePath &workingDirectory)
-{
- return workingDirectory.pathAppended(QString{"qml2puppet-"} + Core::Constants::IDE_VERSION_LONG)
- .withExecutableSuffix();
-}
-
-Utils::FilePath qmlPuppetFallbackDirectory(const DesignerSettings &settings)
-{
- auto puppetFallbackDirectory = Utils::FilePath::fromString(
- settings.value(DesignerSettingsKey::PUPPET_DEFAULT_DIRECTORY).toString());
- if (puppetFallbackDirectory.isEmpty() || !puppetFallbackDirectory.exists())
- return Core::ICore::libexecPath();
- return puppetFallbackDirectory;
-}
-
-std::pair<Utils::FilePath, Utils::FilePath> qmlPuppetFallbackPaths(const DesignerSettings &settings)
-{
- auto workingDirectory = qmlPuppetFallbackDirectory(settings);
-
- return {workingDirectory, qmlPuppetExecutablePath(workingDirectory)};
-}
-
-std::pair<Utils::FilePath, Utils::FilePath> pathsForKitPuppet(ProjectExplorer::Target *target)
-{
- if (!target || !target->kit())
- return {};
-
- QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
-
- if (currentQtVersion) {
- auto path = currentQtVersion->binPath();
- return {path, qmlPuppetExecutablePath(path)};
- }
-
- return {};
-}
-
-std::pair<Utils::FilePath, Utils::FilePath> qmlPuppetPaths(ProjectExplorer::Target *target,
- const DesignerSettings &settings)
-{
- auto [workingDirectoryPath, puppetPath] = pathsForKitPuppet(target);
-
- if (workingDirectoryPath.isEmpty() || !puppetPath.exists())
- return qmlPuppetFallbackPaths(settings);
-
- return {workingDirectoryPath, puppetPath};
-}
-
bool isForcingFreeType(ProjectExplorer::Target *target)
{
if (Utils::HostOsInfo::isWindowsHost() && target) {
@@ -209,11 +162,11 @@ PuppetStartData ExternalDependencies::puppetStartData(const Model &model) const
{
PuppetStartData data;
auto target = ProjectExplorer::ProjectManager::startupTarget();
- auto [workingDirectory, puppetPath] = qmlPuppetPaths(target, m_designerSettings);
+ auto [workingDirectory, puppetPath] = QmlPuppetPaths::qmlPuppetPaths(target, m_designerSettings);
data.puppetPath = puppetPath.toString();
data.workingDirectoryPath = workingDirectory.toString();
- data.environment = PuppetEnvironmentBuilder::createEnvironment(target, m_designerSettings, model);
+ data.environment = PuppetEnvironmentBuilder::createEnvironment(target, m_designerSettings, model, qmlPuppetPath());
data.debugPuppet = m_designerSettings.value(DesignerSettingsKey::DEBUG_PUPPET).toString();
data.freeTypeOption = createFreeTypeOption(target);
data.forwardOutput = m_designerSettings.value(DesignerSettingsKey::FORWARD_PUPPET_OUTPUT).toString();
@@ -226,4 +179,11 @@ bool ExternalDependencies::instantQmlTextUpdate() const
return false;
}
+Utils::FilePath ExternalDependencies::qmlPuppetPath() const
+{
+ auto target = ProjectExplorer::ProjectManager::startupTarget();
+ auto [workingDirectory, puppetPath] = QmlPuppetPaths::qmlPuppetPaths(target, m_designerSettings);
+ return puppetPath;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
index 84a532bb26..3e57847ce9 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
@@ -35,6 +35,7 @@ public:
bool hasStartupTarget() const override;
PuppetStartData puppetStartData(const class Model &model) const override;
bool instantQmlTextUpdate() const override;
+ Utils::FilePath qmlPuppetPath() const override;
private:
const DesignerSettings &m_designerSettings;
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index b8685ba700..039528475a 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -3,19 +3,21 @@
#include "qmldesignerplugin.h"
#include "qmldesignertr.h"
+
#include "coreplugin/iwizardfactory.h"
#include "designmodecontext.h"
#include "designmodewidget.h"
#include "dynamiclicensecheck.h"
#include "exception.h"
#include "generateresource.h"
-#include "nodeinstanceview.h"
#include "openuiqmlfiledialog.h"
#include "qmldesignerconstants.h"
#include "qmldesignerexternaldependencies.h"
#include "qmldesignerprojectmanager.h"
#include "quick2propertyeditorview.h"
#include "settingspage.h"
+#include "shortcutmanager.h"
+#include "toolbar.h"
#include <colortool/colortool.h>
#include <connectionview.h>
@@ -38,9 +40,10 @@
#include <qmlprojectmanager/qmlproject.h>
+#include <app/app_version.h>
+#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/coreconstants.h>
#include <coreplugin/coreplugintr.h>
#include <coreplugin/designmode.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -56,8 +59,9 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/target.h>
-#include <qmljs/qmljsmodelmanagerinterface.h>
#include <sqlitelibraryinitializer.h>
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
@@ -67,6 +71,7 @@
#include <QApplication>
#include <QDebug>
#include <QProcessEnvironment>
+#include <QQuickItem>
#include <QScreen>
#include <QTimer>
#include <QWindow>
@@ -130,8 +135,7 @@ QtQuickDesignerFactory::QtQuickDesignerFactory()
class QmlDesignerPluginPrivate
{
public:
- DesignerSettings settings{Core::ICore::instance()->settings()};
- ExternalDependencies externalDependencies{settings};
+ ExternalDependencies externalDependencies{QmlDesignerBasePlugin::settings()};
QmlDesignerProjectManager projectManager{externalDependencies};
ViewManager viewManager{projectManager.asynchronousImageCache(), externalDependencies};
DocumentManager documentManager{projectManager, externalDependencies};
@@ -231,6 +235,15 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
Sqlite::LibraryInitializer::initialize();
QDir{}.mkpath(Core::ICore::cacheResourcePath().toString());
+ QAction *action = new QAction(tr("Give Feedback..."), this);
+ Core::Command *cmd = Core::ActionManager::registerAction(action, "Help.GiveFeedback");
+ Core::ActionManager::actionContainer(Core::Constants::M_HELP)
+ ->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
+
+ connect(action, &QAction::triggered, this, [this] {
+ lauchFeedbackPopup(Core::Constants::IDE_DISPLAY_NAME);
+ });
+
if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage))
return false;
d = new QmlDesignerPluginPrivate;
@@ -247,7 +260,7 @@ 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();
- if (QmlDesigner::checkLicense() == QmlDesigner::FoundLicense::enterprise)
+ if (checkEnterpriseLicense())
Core::IWizardFactory::registerFeatureProvider(new EnterpriseFeatureProvider);
Exception::setWarnAboutException(!QmlDesignerPlugin::instance()
->settings()
@@ -259,6 +272,11 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
Core::AsynchronousMessageBox::warning(composedTitle, description.toString());
});
+ if (QmlProjectManager::QmlProject::isQtDesignStudio()) {
+ ToolBar::create();
+ ToolBar::createStatusBar();
+ }
+
return true;
}
@@ -274,29 +292,29 @@ bool QmlDesignerPlugin::delayedInitialize()
MetaInfo::setPluginPaths(pluginPaths);
d->viewManager.registerView(
- std::make_unique<QmlDesigner::Internal::ConnectionView>(d->externalDependencies));
+ std::make_unique<ConnectionView>(d->externalDependencies));
auto timelineView = d->viewManager.registerView(
- std::make_unique<QmlDesigner::TimelineView>(d->externalDependencies));
+ std::make_unique<TimelineView>(d->externalDependencies));
timelineView->registerActions();
d->viewManager.registerView(
- std::make_unique<QmlDesigner::CurveEditorView>(d->externalDependencies));
+ std::make_unique<CurveEditorView>(d->externalDependencies));
auto eventlistView = d->viewManager.registerView(
- std::make_unique<QmlDesigner::EventListPluginView>(d->externalDependencies));
+ std::make_unique<EventListPluginView>(d->externalDependencies));
eventlistView->registerActions();
auto transitionEditorView = d->viewManager.registerView(
- std::make_unique<QmlDesigner::TransitionEditorView>(d->externalDependencies));
+ std::make_unique<TransitionEditorView>(d->externalDependencies));
transitionEditorView->registerActions();
- d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::SourceTool>());
- d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::ColorTool>());
- d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::TextTool>());
+ d->viewManager.registerFormEditorTool(std::make_unique<SourceTool>());
+ d->viewManager.registerFormEditorTool(std::make_unique<ColorTool>());
+ d->viewManager.registerFormEditorTool(std::make_unique<TextTool>());
d->viewManager.registerFormEditorTool(
- std::make_unique<QmlDesigner::PathTool>(d->externalDependencies));
- d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::TransitionTool>());
+ std::make_unique<PathTool>(d->externalDependencies));
+ d->viewManager.registerFormEditorTool(std::make_unique<TransitionTool>());
if (QmlProjectManager::QmlProject::isQtDesignStudio()) {
d->mainWidget.initialize();
@@ -380,17 +398,18 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget)
Core::Context qmlDesignerEditor3dContext(Constants::C_QMLEDITOR3D);
Core::Context qmlDesignerNavigatorContext(Constants::C_QMLNAVIGATOR);
Core::Context qmlDesignerMaterialBrowserContext(Constants::C_QMLMATERIALBROWSER);
+ Core::Context qmlDesignerAssetsLibraryContext(Constants::C_QMLASSETSLIBRARY);
context->context().add(qmlDesignerMainContext);
context->context().add(qmlDesignerFormEditorContext);
context->context().add(qmlDesignerEditor3dContext);
context->context().add(qmlDesignerNavigatorContext);
context->context().add(qmlDesignerMaterialBrowserContext);
+ context->context().add(qmlDesignerAssetsLibraryContext);
context->context().add(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID);
d->shortCutManager.registerActions(qmlDesignerMainContext, qmlDesignerFormEditorContext,
- qmlDesignerEditor3dContext, qmlDesignerNavigatorContext,
- qmlDesignerMaterialBrowserContext);
+ qmlDesignerEditor3dContext, qmlDesignerNavigatorContext);
const QStringList mimeTypes = { QmlJSTools::Constants::QML_MIMETYPE,
QmlJSTools::Constants::QMLUI_MIMETYPE };
@@ -476,7 +495,7 @@ void QmlDesignerPlugin::hideDesigner()
d->shortCutManager.disconnectUndoActions(currentDesignDocument());
d->documentManager.setCurrentDesignDocument(nullptr);
d->shortCutManager.updateUndoActions(nullptr);
- emitUsageStatisticsTime(QmlDesigner::Constants::EVENT_DESIGNMODE_TIME, m_usageTimer.elapsed());
+ emitUsageStatisticsTime(Constants::EVENT_DESIGNMODE_TIME, m_usageTimer.elapsed());
}
void QmlDesignerPlugin::changeEditor()
@@ -576,6 +595,15 @@ void QmlDesignerPlugin::resetModelSelection()
rewriterView()->setSelectedModelNodes(QList<ModelNode>());
}
+QString QmlDesignerPlugin::identiferToDisplayString(const QString &identifier)
+{
+ for (AbstractView *view : viewManager().views())
+ if (view->widgetInfo().uniqueId.toLower() == identifier.toLower())
+ return view->widgetInfo().feedbackDisplayName;
+
+ return identifier;
+}
+
RewriterView *QmlDesignerPlugin::rewriterView() const
{
return currentDesignDocument()->rewriterView();
@@ -701,8 +729,61 @@ void QmlDesignerPlugin::trackWidgetFocusTime(QWidget *widget, const QString &ide
});
}
+void QmlDesignerPlugin::lauchFeedbackPopup(const QString &identifier)
+{
+ m_feedbackWidget = new QQuickWidget(Core::ICore::dialogParent());
+ m_feedbackWidget->setObjectName(Constants::OBJECT_NAME_TOP_FEEDBACK);
+
+ const QString qmlPath = Core::ICore::resourcePath("qmldesigner/feedback/FeedbackPopup.qml").toString();
+
+ m_feedbackWidget->setSource(QUrl::fromLocalFile(qmlPath));
+ if (!m_feedbackWidget->errors().isEmpty()) {
+ qDebug() << qmlPath;
+ qDebug() << m_feedbackWidget->errors().first().toString();
+ }
+ m_feedbackWidget->setWindowModality(Qt::ApplicationModal);
+ if (Utils::HostOsInfo::isMacHost())
+ m_feedbackWidget->setWindowFlags(Qt::Dialog);
+ else
+ m_feedbackWidget->setWindowFlags(Qt::SplashScreen);
+ m_feedbackWidget->setAttribute(Qt::WA_DeleteOnClose);
+
+ QQuickItem *root = m_feedbackWidget->rootObject();
+
+ QTC_ASSERT(root, return );
+
+ QObject *title = root->findChild<QObject *>("title");
+ QString name = QmlDesignerPlugin::tr("Enjoying the %1?").arg(identiferToDisplayString(identifier));
+ title->setProperty("text", name);
+ root->setProperty("identifier", identifier);
+
+ connect(root, SIGNAL(closeClicked()), this, SLOT(closeFeedbackPopup()));
+
+ QObject::connect(root,
+ SIGNAL(submitFeedback(QString, int)),
+ this,
+ SLOT(handleFeedback(QString, int)));
+
+ m_feedbackWidget->show();
+}
+
+void QmlDesignerPlugin::handleFeedback(const QString &feedback, int rating)
+{
+ const QString identifier = sender()->property("identifier").toString();
+ emit usageStatisticsInsertFeedback(identifier, feedback, rating);
+}
+
+void QmlDesignerPlugin::closeFeedbackPopup()
+{
+ if (m_feedbackWidget) {
+ m_feedbackWidget->deleteLater();
+ m_feedbackWidget = nullptr;
+ }
+}
+
void QmlDesignerPlugin::emitUsageStatisticsTime(const QString &identifier, int elapsed)
{
+
QTC_ASSERT(instance(), return);
emit instance()->usageStatisticsUsageTimer(normalizeIdentifier(identifier), elapsed);
}
@@ -744,7 +825,7 @@ ExternalDependenciesInterface &QmlDesignerPlugin::externalDependenciesForPluginI
DesignerSettings &QmlDesignerPlugin::settings()
{
- return instance()->d->settings;
+ return QmlDesignerBasePlugin::settings();
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h
index 2c9531b991..78bf02ac04 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.h
+++ b/src/plugins/qmldesigner/qmldesignerplugin.h
@@ -5,7 +5,6 @@
#include "documentmanager.h"
#include "qmldesigner_global.h"
-#include "shortcutmanager.h"
#include <designersettings.h>
#include <viewmanager.h>
@@ -13,10 +12,12 @@
#include <extensionsystem/iplugin.h>
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
#include <QElapsedTimer>
QT_FORWARD_DECLARE_CLASS(QQmlEngine)
+QT_FORWARD_DECLARE_CLASS(QQuickWidget)
namespace Core {
class IEditor;
@@ -85,8 +86,14 @@ public:
signals:
void usageStatisticsNotifier(const QString &identifier);
void usageStatisticsUsageTimer(const QString &identifier, int elapsed);
+ void usageStatisticsInsertFeedback(const QString &identifier, const QString &feedback, int rating);
void assetChanged(const QString &assetPath);
+private slots:
+ void closeFeedbackPopup();
+ void lauchFeedbackPopup(const QString &identifier);
+ void handleFeedback(const QString &feedback, int rating);
+
private: // functions
void integrateIntoQtCreator(QWidget *modeWidget);
void showDesigner();
@@ -97,13 +104,17 @@ private: // functions
void activateAutoSynchronization();
void deactivateAutoSynchronization();
void resetModelSelection();
+ QString identiferToDisplayString(const QString &identifier);
+
RewriterView *rewriterView() const;
Model *currentModel() const;
+ QQuickWidget *m_feedbackWidget = nullptr;
private: // variables
QmlDesignerPluginPrivate *d = nullptr;
static QmlDesignerPlugin *m_instance;
QElapsedTimer m_usageTimer;
+ StudioConfigSettingsPage m_settingsPage;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
index 60363e5fbd..a80b3148b3 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
@@ -12,6 +12,7 @@
#include <projectstorage/filesystem.h>
#include <projectstorage/nonlockingmutex.h>
#include <projectstorage/projectstorage.h>
+#include <projectstorage/projectstoragepathwatcher.h>
#include <projectstorage/projectstorageupdater.h>
#include <projectstorage/qmldocumentparser.h>
#include <projectstorage/qmltypesparser.h>
@@ -31,10 +32,14 @@
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/meshimagecachecollector.h>
+#include <imagecache/textureimagecachecollector.h>
#include <imagecache/timestampprovider.h>
+#include <utils/asset.h>
+
#include <coreplugin/icore.h>
+#include <QFileSystemWatcher>
#include <QQmlEngine>
namespace QmlDesigner {
@@ -49,11 +54,16 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
return {};
}
-QString defaultImagePath()
+QString previewDefaultImagePath()
{
return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newThumbnail.png").toString();
}
+QString previewBrokenImagePath()
+{
+ return Core::ICore::resourcePath("qmldesigner/welcomepage/images/noPreview.png").toString();
+}
+
::QmlProjectManager::QmlBuildSystem *getQmlBuildSystem(::ProjectExplorer::Target *target)
{
return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
@@ -76,8 +86,9 @@ public:
}
};
-auto makeCollecterDispatcherChain(ImageCacheCollector &nodeInstanceCollector,
- MeshImageCacheCollector &meshImageCollector)
+auto makeCollectorDispatcherChain(ImageCacheCollector &nodeInstanceCollector,
+ MeshImageCacheCollector &meshImageCollector,
+ TextureImageCacheCollector &textureImageCollector)
{
return std::make_tuple(
std::make_pair([](Utils::SmallStringView filePath,
@@ -91,8 +102,15 @@ auto makeCollecterDispatcherChain(ImageCacheCollector &nodeInstanceCollector,
[[maybe_unused]] const QmlDesigner::ImageCache::AuxiliaryData &auxiliaryData) {
return filePath.endsWith(".mesh") || filePath.startsWith("#");
},
- &meshImageCollector));
-}
+ &meshImageCollector),
+ std::make_pair(
+ [](Utils::SmallStringView filePath,
+ [[maybe_unused]] Utils::SmallStringView state,
+ [[maybe_unused]] const QmlDesigner::ImageCache::AuxiliaryData &auxiliaryData) {
+ return Asset{QString(filePath)}.isValidTextureSource();
+ },
+ &textureImageCollector));
+ }
} // namespace
class QmlDesignerProjectManager::ImageCacheData
@@ -111,10 +129,14 @@ public:
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
MeshImageCacheCollector meshImageCollector;
+ TextureImageCacheCollector textureImageCollector;
ImageCacheCollector nodeInstanceCollector;
- ImageCacheDispatchCollector<decltype(makeCollecterDispatcherChain(nodeInstanceCollector,
- meshImageCollector))>
- dispatchCollector{makeCollecterDispatcherChain(nodeInstanceCollector, meshImageCollector)};
+ ImageCacheDispatchCollector<decltype(makeCollectorDispatcherChain(nodeInstanceCollector,
+ meshImageCollector,
+ textureImageCollector))>
+ dispatchCollector{makeCollectorDispatcherChain(nodeInstanceCollector,
+ meshImageCollector,
+ textureImageCollector)};
ImageCacheGenerator generator{dispatchCollector, storage};
TimeStampProvider timeStampProvider;
AsynchronousImageCache asynchronousImageCache{storage, generator, timeStampProvider};
@@ -128,8 +150,10 @@ public:
QSize{300, 300},
QSize{1000, 1000},
externalDependencies,
- ImageCacheCollectorNullImageHandling::DontCaptureNullImage}
- {}
+ ImageCacheCollectorNullImageHandling::CaptureNullImage}
+ {
+ timer.setSingleShot(true);
+ }
public:
Sqlite::Database database{Utils::PathString{
@@ -142,8 +166,10 @@ public:
PreviewTimeStampProvider timeStampProvider;
AsynchronousExplicitImageCache cache{storage};
AsynchronousImageFactory factory{storage, timeStampProvider, collector};
+ QTimer timer;
};
+namespace {
class ProjectStorageData
{
public:
@@ -158,10 +184,27 @@ public:
FileStatusCache fileStatusCache{fileSystem};
QmlDocumentParser qmlDocumentParser{storage, pathCache};
QmlTypesParser qmlTypesParser{pathCache, storage};
- ProjectStorageUpdater updater{
- fileSystem, storage, fileStatusCache, pathCache, qmlDocumentParser, qmlTypesParser};
+ ProjectStoragePathWatcher<QFileSystemWatcher, QTimer, ProjectStorageUpdater::PathCache>
+ pathWatcher{pathCache, fileSystem, &updater};
+ ProjectStorageUpdater updater{fileSystem,
+ storage,
+ fileStatusCache,
+ pathCache,
+ qmlDocumentParser,
+ qmlTypesParser,
+ pathWatcher};
};
+std::unique_ptr<ProjectStorageData> createProjectStorageData(::ProjectExplorer::Project *project)
+{
+ if constexpr (useProjectStorage()) {
+ return std::make_unique<ProjectStorageData>(project);
+ } else {
+ return {};
+ }
+}
+} // namespace
+
class QmlDesignerProjectManager::QmlDesignerProjectManagerProjectData
{
public:
@@ -174,14 +217,14 @@ public:
externalDependencies,
ImageCacheCollectorNullImageHandling::CaptureNullImage}
, factory{storage, timeStampProvider, collector}
- , projectStorageData{project}
+ , projectStorageData{createProjectStorageData(project)}
{}
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector;
PreviewTimeStampProvider timeStampProvider;
AsynchronousImageFactory factory;
- ProjectStorageData projectStorageData;
+ std::unique_ptr<ProjectStorageData> projectStorageData;
QPointer<::ProjectExplorer::Target> activeTarget;
};
@@ -210,7 +253,7 @@ QmlDesignerProjectManager::QmlDesignerProjectManager(ExternalDependenciesInterfa
&::ProjectExplorer::ProjectManager::projectRemoved,
[&](auto *project) { projectRemoved(project); });
- QObject::connect(&m_previewTimer,
+ QObject::connect(&m_previewImageCacheData->timer,
&QTimer::timeout,
this,
&QmlDesignerProjectManager::generatePreview);
@@ -220,8 +263,10 @@ QmlDesignerProjectManager::~QmlDesignerProjectManager() = default;
void QmlDesignerProjectManager::registerPreviewImageProvider(QQmlEngine *engine) const
{
- auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_previewImageCacheData->cache,
- QImage{defaultImagePath()});
+ auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(
+ m_previewImageCacheData->cache,
+ QImage{previewDefaultImagePath()},
+ QImage{previewBrokenImagePath()});
engine->addImageProvider("project_preview", imageProvider.release());
}
@@ -231,19 +276,29 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache()
return imageCacheData()->asynchronousImageCache;
}
+namespace {
+ProjectStorage<Sqlite::Database> *dummyProjectStorage()
+{
+ return nullptr;
+}
+
+} // namespace
+
ProjectStorage<Sqlite::Database> &QmlDesignerProjectManager::projectStorage()
{
- return m_projectData->projectStorageData.storage;
+ if constexpr (useProjectStorage()) {
+ return m_projectData->projectStorageData->storage;
+ } else {
+ return *dummyProjectStorage();
+ }
}
void QmlDesignerProjectManager::editorOpened(::Core::IEditor *) {}
void QmlDesignerProjectManager::currentEditorChanged(::Core::IEditor *)
{
- if (!m_projectData || !m_projectData->activeTarget)
- return;
-
- m_previewTimer.start(10000);
+ using namespace std::chrono_literals;
+ m_previewImageCacheData->timer.start(10s);
}
void QmlDesignerProjectManager::editorsClosed(const QList<::Core::IEditor *> &) {}
@@ -365,26 +420,25 @@ QStringList qmlTypes(::ProjectExplorer::Target *target)
void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project)
{
- if (qEnvironmentVariableIsSet("QDS_ACTIVATE_PROJECT_STORAGE")) {
- m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(
- m_previewImageCacheData->storage, project, m_externalDependencies);
- m_projectData->activeTarget = project->activeTarget();
+ m_projectData = std::make_unique<QmlDesignerProjectManagerProjectData>(m_previewImageCacheData->storage,
+ project,
+ m_externalDependencies);
+ m_projectData->activeTarget = project->activeTarget();
- QObject::connect(project, &::ProjectExplorer::Project::fileListChanged, [&]() {
- fileListChanged();
- });
+ QObject::connect(project, &::ProjectExplorer::Project::fileListChanged, [&]() {
+ fileListChanged();
+ });
- QObject::connect(project,
- &::ProjectExplorer::Project::activeTargetChanged,
- [&](auto *target) { activeTargetChanged(target); });
+ QObject::connect(project, &::ProjectExplorer::Project::activeTargetChanged, [&](auto *target) {
+ activeTargetChanged(target);
+ });
- QObject::connect(project,
- &::ProjectExplorer::Project::aboutToRemoveTarget,
- [&](auto *target) { aboutToRemoveTarget(target); });
+ QObject::connect(project, &::ProjectExplorer::Project::aboutToRemoveTarget, [&](auto *target) {
+ aboutToRemoveTarget(target);
+ });
- if (auto target = project->activeTarget(); target)
- activeTargetChanged(target);
- }
+ if (auto target = project->activeTarget(); target)
+ activeTargetChanged(target);
}
void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project *)
@@ -492,11 +546,11 @@ void QmlDesignerProjectManager::projectChanged()
void QmlDesignerProjectManager::update()
{
- if (!m_projectData)
+ if (!m_projectData || !m_projectData->projectStorageData)
return;
- m_projectData->projectStorageData.updater.update(qmlDirs(m_projectData->activeTarget),
- qmlTypes(m_projectData->activeTarget));
+ m_projectData->projectStorageData->updater.update(qmlDirs(m_projectData->activeTarget),
+ qmlTypes(m_projectData->activeTarget));
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h
index 97a14c21ce..e1803ed14d 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h
@@ -68,7 +68,6 @@ private:
std::unique_ptr<ImageCacheData> m_imageCacheData;
std::unique_ptr<PreviewImageCacheData> m_previewImageCacheData;
std::unique_ptr<QmlDesignerProjectManagerProjectData> m_projectData;
- QTimer m_previewTimer;
ExternalDependenciesInterface &m_externalDependencies;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp
index cba3411ead..ccd9a97009 100644
--- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp
+++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp
@@ -70,9 +70,9 @@ QmlPreviewAction::QmlPreviewAction() : ModelNodeAction(livePreviewId,
&SelectionContextFunctors::always)
{
if (!QmlPreviewWidgetPlugin::getPreviewPlugin())
- defaultAction()->setVisible(false);
+ action()->setVisible(false);
- defaultAction()->setCheckable(true);
+ action()->setCheckable(true);
}
void QmlPreviewAction::updateContext()
@@ -80,7 +80,7 @@ void QmlPreviewAction::updateContext()
if (selectionContext().view()->isAttached())
QmlPreviewWidgetPlugin::setQmlFile();
- defaultAction()->setSelectionContext(selectionContext());
+ pureAction()->setSelectionContext(selectionContext());
}
ActionInterface::Type QmlPreviewAction::type() const
@@ -113,7 +113,7 @@ QByteArray ZoomPreviewAction::category() const
QByteArray ZoomPreviewAction::menuId() const
{
- return QByteArray();
+ return "PreviewZoom";
}
int ZoomPreviewAction::priority() const
diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
index 70d62f71c6..d6cf9f115b 100644
--- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
+++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp
@@ -19,6 +19,9 @@
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/icore.h>
+
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/runcontrol.h>
@@ -56,10 +59,26 @@ QmlPreviewWidgetPlugin::QmlPreviewWidgetPlugin()
auto zoomAction = new ZoomPreviewAction;
designerActionManager.addDesignerAction(zoomAction);
- auto separator = new SeperatorDesignerAction(ComponentCoreConstants::qmlPreviewCategory, 0);
+ auto separator = new SeparatorDesignerAction(ComponentCoreConstants::qmlPreviewCategory, 0);
designerActionManager.addDesignerAction(separator);
- m_previewToggleAction = previewAction->defaultAction();
+ m_previewToggleAction = previewAction->action();
+
+ Core::Context globalContext;
+ auto registerCommand = [&globalContext](ActionInterface *action){
+ const QString id = QStringLiteral("QmlPreview.%1").arg(QString::fromLatin1(action->menuId()));
+ Core::Command *cmd = Core::ActionManager::registerAction(action->action(),
+ id.toLatin1().constData(),
+ globalContext);
+
+ cmd->setDefaultKeySequence(action->action()->shortcut());
+ cmd->setDescription(action->action()->toolTip());
+
+ action->action()->setToolTip(cmd->action()->toolTip());
+ action->action()->setShortcut(cmd->action()->shortcut());
+ };
+ // Only register previewAction as others don't have keyboard shortcuts for them
+ registerCommand(previewAction);
if (s_previewPlugin) {
auto fpsAction = new FpsAction;
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-16.png b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-16.png
new file mode 100644
index 0000000000..6b16d81397
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24.png b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24.png
new file mode 100644
index 0000000000..0549a84758
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24@2x.png
new file mode 100644
index 0000000000..8876f95ae6
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/ambient-sound-24@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-16.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-16.png
new file mode 100644
index 0000000000..da40bc69a2
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24.png
new file mode 100644
index 0000000000..b3ebdf745b
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24@2x.png
new file mode 100644
index 0000000000..476df8640f
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-engine-24@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-16.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-16.png
new file mode 100644
index 0000000000..ecc583b859
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24.png
new file mode 100644
index 0000000000..ee181f57cc
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24@2x.png
new file mode 100644
index 0000000000..2588277e53
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-listener-24@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-room-16.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-16.png
new file mode 100644
index 0000000000..98f245d624
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24.png
new file mode 100644
index 0000000000..294d1574ae
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24@2x.png
new file mode 100644
index 0000000000..bef7f80e3e
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/audio-room-24@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/default3d.png b/src/plugins/qmldesigner/qtquickplugin/images/default3d.png
new file mode 100644
index 0000000000..a3b6c7f6f2
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/default3d.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/default3d16.png b/src/plugins/qmldesigner/qtquickplugin/images/default3d16.png
new file mode 100644
index 0000000000..de8906a724
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/default3d16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/default3d@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/default3d@2x.png
new file mode 100644
index 0000000000..7ca04a01ea
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/default3d@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-16.png b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-16.png
new file mode 100644
index 0000000000..676fe13404
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-16.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24.png b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24.png
new file mode 100644
index 0000000000..29f7f14db3
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24@2x.png
new file mode 100644
index 0000000000..a518cada63
--- /dev/null
+++ b/src/plugins/qmldesigner/qtquickplugin/images/spatial-audio-24@2x.png
Binary files differ
diff --git a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
index 1e78c02b77..30d705ad98 100644
--- a/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
+++ b/src/plugins/qmldesigner/qtquickplugin/qtquickplugin.qrc
@@ -101,5 +101,23 @@
<file>images/timer-16px.png</file>
<file>images/timer-24px.png</file>
<file>images/timer-24px@2x.png</file>
+ <file>images/default3d.png</file>
+ <file>images/default3d@2x.png</file>
+ <file>images/default3d16.png</file>
+ <file>images/ambient-sound-16.png</file>
+ <file>images/ambient-sound-24.png</file>
+ <file>images/ambient-sound-24@2x.png</file>
+ <file>images/audio-engine-16.png</file>
+ <file>images/audio-engine-24.png</file>
+ <file>images/audio-engine-24@2x.png</file>
+ <file>images/audio-listener-16.png</file>
+ <file>images/audio-listener-24.png</file>
+ <file>images/audio-listener-24@2x.png</file>
+ <file>images/audio-room-16.png</file>
+ <file>images/audio-room-24.png</file>
+ <file>images/audio-room-24@2x.png</file>
+ <file>images/spatial-audio-16.png</file>
+ <file>images/spatial-audio-24.png</file>
+ <file>images/spatial-audio-24@2x.png</file>
</qresource>
</RCC>
diff --git a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
index 87b9edcbc0..45e0162128 100644
--- a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
+++ b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
@@ -545,7 +545,7 @@ MetaInfo {
ItemLibraryEntry {
name: "Component"
- category: "e.Qt Quick - Component"
+ category: "e.Qt Quick - Instancers"
libraryIcon: ":/qtquickplugin/images/component-icon.png"
version: "1.0"
@@ -565,7 +565,7 @@ MetaInfo {
ItemLibraryEntry {
name: "Component 3D"
- category: "Qt Quick 3D Component"
+ category: "Instancers"
libraryIcon: ":/qtquickplugin/images/component-icon.png"
version: "1.0"
requiredImport: "QtQuick3D"
@@ -580,7 +580,7 @@ MetaInfo {
ItemLibraryEntry {
name: "Loader"
- category: "e.Qt Quick - Component"
+ category: "e.Qt Quick - Instancers"
libraryIcon: ":/qtquickplugin/images/loader-icon.png"
version: "2.0"
Property { name: "width"; type: "int"; value: 200; }
@@ -600,7 +600,7 @@ MetaInfo {
ItemLibraryEntry {
name: "Repeater"
- category: "e.Qt Quick - Component"
+ category: "e.Qt Quick - Instancers"
libraryIcon: ":/qtquickplugin/images/repeater-icon.png"
version: "2.0"
toolTip: qsTr("Creates a number of copies of the same item.")
@@ -689,4 +689,128 @@ MetaInfo {
Property { name: "height"; type: "int"; value: 200; }
}
}
+
+ Type {
+ name: "QtQuick3D.SpatialAudio.AmbientSound"
+ icon: ":/qtquickplugin/images/ambient-sound-16.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: false
+ canBeContainer: false
+ }
+
+ ItemLibraryEntry {
+ name: "Ambient Sound"
+ category: "Spatial Audio"
+ libraryIcon: ":/qtquickplugin/images/ambient-sound-24.png"
+ version: "6.0"
+ requiredImport: "QtQuick3D.SpatialAudio"
+ toolTip: qsTr("An ambient background sound.")
+ }
+ }
+
+ Type {
+ name: "QtQuick3D.SpatialAudio.AudioEngine"
+ icon: ":/qtquickplugin/images/audio-engine-16.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: false
+ canBeContainer: false
+ }
+
+ ItemLibraryEntry {
+ name: "Audio Engine"
+ category: "Spatial Audio"
+ libraryIcon: ":/qtquickplugin/images/audio-engine-24.png"
+ version: "6.0"
+ requiredImport: "QtQuick3D.SpatialAudio"
+ toolTip: qsTr("Manages sound objects inside a 3D scene.")
+ }
+ }
+
+ Type {
+ name: "QtQuick3D.SpatialAudio.AudioListener"
+ icon: ":/qtquickplugin/images/audio-listener-16.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: true
+ }
+
+ ItemLibraryEntry {
+ name: "Audio Listener"
+ category: "Spatial Audio"
+ libraryIcon: ":/qtquickplugin/images/audio-listener-24.png"
+ version: "6.0"
+ requiredImport: "QtQuick3D.SpatialAudio"
+ toolTip: qsTr("Sets the position and orientation of listening.")
+ }
+ }
+
+ Type {
+ name: "QtQuick3D.SpatialAudio.AudioRoom"
+ icon: ":/qtquickplugin/images/audio-room-16.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: true
+ }
+
+ ItemLibraryEntry {
+ name: "Audio Room"
+ category: "Spatial Audio"
+ libraryIcon: ":/qtquickplugin/images/audio-room-24.png"
+ version: "6.0"
+ requiredImport: "QtQuick3D.SpatialAudio"
+ toolTip: qsTr("Sets up a room for the spatial audio engine.")
+ }
+ }
+
+ Type {
+ name: "QtQuick3D.SpatialAudio.SpatialSound"
+ icon: ":/qtquickplugin/images/spatial-audio-16.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: true
+ }
+
+ ItemLibraryEntry {
+ name: "Spatial Sound"
+ category: "Spatial Audio"
+ libraryIcon: ":/qtquickplugin/images/spatial-audio-24.png"
+ version: "6.0"
+ requiredImport: "QtQuick3D.SpatialAudio"
+ toolTip: qsTr("A sound object in 3D space.")
+ }
+ }
+
+ Type {
+ name: "QtQuick3D.BakedLightmap"
+ icon: ":/ItemLibrary/images/item-default-icon.png"
+
+ Hints {
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: false
+ }
+
+ ItemLibraryEntry {
+ name: "Baked Lightmap"
+ category: "Components"
+ libraryIcon: ":/ItemLibrary/images/item-default-icon.png"
+ version: "6.5"
+ requiredImport: "QtQuick3D"
+ toolTip: qsTr("An object to specify details about baked lightmap of a model.")
+
+ Property { name: "loadPrefix"; type: "string"; value: "lightmaps"; }
+ }
+ }
}
diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp
index 11e27e2d1e..efb3bf49ee 100644
--- a/src/plugins/qmldesigner/shortcutmanager.cpp
+++ b/src/plugins/qmldesigner/shortcutmanager.cpp
@@ -5,6 +5,8 @@
#include <designersettings.h>
+#include <toolbarbackend.h>
+
#include <viewmanager.h>
#include <designeractionmanagerview.h>
#include <componentcore_constants.h>
@@ -59,11 +61,8 @@ ShortCutManager::ShortCutManager()
void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContext,
const Core::Context &qmlDesignerFormEditorContext,
const Core::Context &qmlDesignerEditor3DContext,
- const Core::Context &qmlDesignerNavigatorContext,
- const Core::Context &qmlDesignerMaterialBrowserContext)
+ const Core::Context &qmlDesignerNavigatorContext)
{
- Q_UNUSED(qmlDesignerMaterialBrowserContext)
-
Core::ActionContainer *editMenu = Core::ActionManager::actionContainer(Core::Constants::M_EDIT);
connect(&m_undoAction, &QAction::triggered, this, &ShortCutManager::undo);
@@ -107,6 +106,13 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
QmlDesignerPlugin::instance()->viewManager().exportAsImage();
});
+ QAction *action = new QAction(tr("Edit Global Annotations..."), this);
+ command = Core::ActionManager::registerAction(action, "Edit.Annotations", qmlDesignerMainContext);
+ Core::ActionManager::actionContainer(Core::Constants::M_EDIT)
+ ->addAction(command, Core::Constants::G_EDIT_OTHER);
+
+ connect(action, &QAction::triggered, this, [] { ToolBarBackend::launchGlobalAnnotations(); });
+
Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer(
QmlProjectManager::Constants::EXPORT_MENU);
@@ -136,7 +142,7 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
command->setDefaultKeySequence(QKeySequence::Redo);
designerActionManager.addCreatorCommand(command, ComponentCoreConstants::editCategory, 2, Utils::Icons::REDO_TOOLBAR.icon());
- designerActionManager.addDesignerAction(new SeperatorDesignerAction(ComponentCoreConstants::editCategory, 10));
+ designerActionManager.addDesignerAction(new SeparatorDesignerAction(ComponentCoreConstants::editCategory, 10));
//Edit Menu
m_deleteAction.setIcon(QIcon::fromTheme(QLatin1String("edit-cut"), Utils::Icons::EDIT_CLEAR_TOOLBAR.icon()));
@@ -196,10 +202,11 @@ 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);
if (!context.contains(Constants::C_QMLFORMEDITOR) && !context.contains(Constants::C_QMLEDITOR3D)
&& !context.contains(Constants::C_QMLNAVIGATOR)) {
- m_deleteAction.setEnabled(isMatBrowserActive);
+ m_deleteAction.setEnabled(isMatBrowserActive || isAssetsLibraryActive);
m_cutAction.setEnabled(false);
m_copyAction.setEnabled(false);
m_pasteAction.setEnabled(false);
@@ -254,6 +261,9 @@ void ShortCutManager::deleteSelected()
if (isMatBrowserActive) {
DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->viewManager().designerActionManager();
designerActionManager.view()->emitCustomNotification("delete_selected_material");
+ } else if (isAssetsLibraryActive) {
+ DesignerActionManager &designerActionManager = QmlDesignerPlugin::instance()->viewManager().designerActionManager();
+ designerActionManager.view()->emitCustomNotification("delete_selected_assets");
} else if (currentDesignDocument()) {
currentDesignDocument()->deleteSelected();
}
diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h
index fe13e5a913..9b4762748e 100644
--- a/src/plugins/qmldesigner/shortcutmanager.h
+++ b/src/plugins/qmldesigner/shortcutmanager.h
@@ -25,8 +25,7 @@ public:
void registerActions(const Core::Context &qmlDesignerMainContext,
const Core::Context &qmlDesignerFormEditorContext,
const Core::Context &qmlDesignerEditor3DContext,
- const Core::Context &qmlDesignerNavigatorContext,
- const Core::Context &qmlDesignerMaterialBrowserContext);
+ const Core::Context &qmlDesignerNavigatorContext);
void connectUndoActions(DesignDocument *designDocument);
void disconnectUndoActions(DesignDocument *designDocument);
@@ -67,6 +66,7 @@ private:
QAction m_escapeAction;
bool isMatBrowserActive = false;
+ bool isAssetsLibraryActive = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
index 207cdbb977..94f14c296d 100644
--- a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
+++ b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
@@ -27,6 +27,7 @@ MetaInfo {
"QtQuick.Controls.Universal",
"QtQuick.Controls.Material",
"QtQuick.Controls.NativeStyle",
+ "QtQuick.Controls.Windows",
"QtQuick.NativeStyle",
"QtRemoteObjects",
"Qt5Compat.GraphicalEffects",
diff --git a/src/plugins/qmldesigner/utils/asset.cpp b/src/plugins/qmldesigner/utils/asset.cpp
index 5ec84d5bbc..5d6f42336c 100644
--- a/src/plugins/qmldesigner/utils/asset.cpp
+++ b/src/plugins/qmldesigner/utils/asset.cpp
@@ -10,7 +10,11 @@ namespace QmlDesigner {
Asset::Asset(const QString &filePath)
: m_filePath(filePath)
{
- m_suffix = "*." + filePath.split('.').last().toLower();
+ const QStringList split = filePath.split('.');
+ if (split.size() > 1)
+ m_suffix = "*." + split.last().toLower();
+
+ resolveType();
}
@@ -31,6 +35,12 @@ const QStringList &Asset::supportedFragmentShaderSuffixes()
return retList;
}
+const QStringList &Asset::supportedVertexShaderSuffixes()
+{
+ static const QStringList retList {"*.vert", "*.glsl", "*.glslv", "*.vsh"};
+ return retList;
+}
+
const QStringList &Asset::supportedShaderSuffixes()
{
static const QStringList retList {"*.frag", "*.vert",
@@ -90,68 +100,54 @@ const QSet<QString> &Asset::supportedSuffixes()
return allSuffixes;
}
-Asset::Type Asset::type() const
+bool Asset::isSupported(const QString &path)
{
- if (supportedImageSuffixes().contains(m_suffix))
- return Asset::Type::Image;
-
- if (supportedFragmentShaderSuffixes().contains(m_suffix))
- return Asset::Type::FragmentShader;
-
- if (supportedShaderSuffixes().contains(m_suffix))
- return Asset::Type::Shader;
-
- if (supportedFontSuffixes().contains(m_suffix))
- return Asset::Type::Font;
-
- if (supportedAudioSuffixes().contains(m_suffix))
- return Asset::Type::Audio;
-
- if (supportedVideoSuffixes().contains(m_suffix))
- return Asset::Type::Video;
-
- if (supportedTexture3DSuffixes().contains(m_suffix))
- return Asset::Type::Texture3D;
-
- if (supportedEffectMakerSuffixes().contains(m_suffix))
- return Asset::Type::Effect;
+ return supportedSuffixes().contains(path);
+}
- return Asset::Type::Unknown;
+Asset::Type Asset::type() const
+{
+ return m_type;
}
bool Asset::isImage() const
{
- return type() == Asset::Type::Image;
+ return m_type == Asset::Type::Image;
}
bool Asset::isFragmentShader() const
{
- return type() == Asset::Type::FragmentShader;
+ return m_type == Asset::Type::FragmentShader;
+}
+
+bool Asset::isVertexShader() const
+{
+ return m_type == Asset::Type::VertexShader;
}
bool Asset::isShader() const
{
- return type() == Asset::Type::Shader;
+ return isFragmentShader() || isVertexShader();
}
bool Asset::isFont() const
{
- return type() == Asset::Type::Font;
+ return m_type == Asset::Type::Font;
}
bool Asset::isAudio() const
{
- return type() == Asset::Type::Audio;
+ return m_type == Asset::Type::Audio;
}
bool Asset::isVideo() const
{
- return type() == Asset::Type::Video;
+ return m_type == Asset::Type::Video;
}
bool Asset::isTexture3D() const
{
- return type() == Asset::Type::Texture3D;
+ return m_type == Asset::Type::Texture3D;
}
bool Asset::isHdrFile() const
@@ -159,9 +155,14 @@ bool Asset::isHdrFile() const
return m_suffix == "*.hdr";
}
+bool Asset::isKtxFile() const
+{
+ return m_suffix == "*.ktx";
+}
+
bool Asset::isEffect() const
{
- return type() == Asset::Type::Effect;
+ return m_type == Asset::Type::Effect;
}
const QString Asset::suffix() const
@@ -176,7 +177,35 @@ const QString Asset::id() const
bool Asset::isSupported() const
{
- return supportedSuffixes().contains(m_filePath);
+ return m_type != Asset::Type::Unknown;
+}
+
+bool Asset::isValidTextureSource()
+{
+ return isImage() || isTexture3D();
+}
+
+void Asset::resolveType()
+{
+ if (m_suffix.isEmpty())
+ return;
+
+ if (supportedImageSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Image;
+ else if (supportedFragmentShaderSuffixes().contains(m_suffix))
+ m_type = Asset::Type::FragmentShader;
+ else if (supportedVertexShaderSuffixes().contains(m_suffix))
+ m_type = Asset::Type::VertexShader;
+ else if (supportedFontSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Font;
+ else if (supportedAudioSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Audio;
+ else if (supportedVideoSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Video;
+ else if (supportedTexture3DSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Texture3D;
+ else if (supportedEffectMakerSuffixes().contains(m_suffix))
+ m_type = Asset::Type::Effect;
}
bool Asset::hasSuffix() const
diff --git a/src/plugins/qmldesigner/utils/asset.h b/src/plugins/qmldesigner/utils/asset.h
index 3e6d105ec4..e779d4a734 100644
--- a/src/plugins/qmldesigner/utils/asset.h
+++ b/src/plugins/qmldesigner/utils/asset.h
@@ -3,17 +3,29 @@
#pragma once
+#include <QString>
+
namespace QmlDesigner {
class Asset
{
public:
- enum Type { Unknown, Image, MissingImage, FragmentShader, Font, Audio, Video, Texture3D, Effect, Shader };
+ enum Type { Unknown,
+ Image,
+ MissingImage,
+ FragmentShader,
+ VertexShader,
+ Font,
+ Audio,
+ Video,
+ Texture3D,
+ Effect };
Asset(const QString &filePath);
static const QStringList &supportedImageSuffixes();
static const QStringList &supportedFragmentShaderSuffixes();
+ static const QStringList &supportedVertexShaderSuffixes();
static const QStringList &supportedShaderSuffixes();
static const QStringList &supportedFontSuffixes();
static const QStringList &supportedAudioSuffixes();
@@ -21,6 +33,7 @@ public:
static const QStringList &supportedTexture3DSuffixes();
static const QStringList &supportedEffectMakerSuffixes();
static const QSet<QString> &supportedSuffixes();
+ static bool isSupported(const QString &path);
const QString suffix() const;
const QString id() const;
@@ -29,18 +42,24 @@ public:
Type type() const;
bool isImage() const;
bool isFragmentShader() const;
+ bool isVertexShader() const;
bool isShader() const;
bool isFont() const;
bool isAudio() const;
bool isVideo() const;
bool isTexture3D() const;
bool isHdrFile() const;
+ bool isKtxFile() const;
bool isEffect() const;
bool isSupported() const;
+ bool isValidTextureSource();
private:
+ void resolveType();
+
QString m_filePath;
QString m_suffix;
+ Type m_type = Unknown;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/designersettings.h b/src/plugins/qmldesigner/utils/designersettings.h
deleted file mode 100644
index a97f982063..0000000000
--- a/src/plugins/qmldesigner/utils/designersettings.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "qmldesignerutils_global.h"
-
-#include <QHash>
-#include <QVariant>
-#include <QByteArray>
-#include <QMutex>
-
-QT_BEGIN_NAMESPACE
-class QSettings;
-QT_END_NAMESPACE
-
-namespace QmlDesigner {
-
-namespace DesignerSettingsKey {
-const char ITEMSPACING[] = "ItemSpacing";
-const char CONTAINERPADDING[] = "ContainerPadding";
-const char CANVASWIDTH[] = "CanvasWidth";
-const char CANVASHEIGHT[] = "CanvasHeight";
-const char ROOT_ELEMENT_INIT_WIDTH[] = "RootElementInitWidth";
-const char ROOT_ELEMENT_INIT_HEIGHT[] = "RootElementInitHeight";
-const char WARNING_FOR_FEATURES_IN_DESIGNER[] = "WarnAboutQtQuickFeaturesInDesigner";
-const char WARNING_FOR_QML_FILES_INSTEAD_OF_UIQML_FILES[] = "WarnAboutQmlFilesInsteadOfUiQmlFiles";
-const char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[] = "WarnAboutQtQuickDesignerFeaturesInCodeEditor";
-const char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView";
-const char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView";
-const char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor";
-const char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor";
-const char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar";
-const char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet";
-const char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory";
-const char PUPPET_DEFAULT_DIRECTORY[] = "PuppetDefaultDirectory";
-const char CONTROLS_STYLE[] = "ControlsStyle";
-const char TYPE_OF_QSTR_FUNCTION[] = "TypeOfQsTrFunction";
-const char SHOW_PROPERTYEDITOR_WARNINGS[] = "ShowPropertyEditorWarnings";
-const char ENABLE_MODEL_EXCEPTION_OUTPUT[] = "WarnException";
-const char PUPPET_KILL_TIMEOUT[] = "PuppetKillTimeout";
-const char DEBUG_PUPPET[] = "DebugPuppet";
-const char FORWARD_PUPPET_OUTPUT[] = "ForwardPuppetOutput";
-const char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems";
-const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder";
-const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */
-const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */
-const char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings";
-const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView";
-const char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent";
-const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite";
-const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode";
-const char DISABLE_ITEM_LIBRARY_UPDATE_TIMER[] = "DisableItemLibraryUpdateTimer";
-const char ASK_BEFORE_DELETING_ASSET[] = "AskBeforeDeletingAsset";
-const char SMOOTH_RENDERING[] = "SmoothRendering";
-const char OLD_STATES_EDITOR[] = "ForceOldStatesEditor";
-const char EDITOR_ZOOM_FACTOR[] = "EditorZoomFactor";
-}
-
-class QMLDESIGNERUTILS_EXPORT DesignerSettings
-{
-public:
- DesignerSettings(QSettings *settings);
-
- void insert(const QByteArray &key, const QVariant &value);
- void insert(const QHash<QByteArray, QVariant> &settingsHash);
- QVariant value(const QByteArray &key, const QVariant &defaultValue = {}) const;
-
-private:
- void fromSettings(QSettings *);
- void toSettings(QSettings *) const;
-
- void restoreValue(QSettings *settings, const QByteArray &key,
- const QVariant &defaultValue = QVariant());
- void storeValue(QSettings *settings, const QByteArray &key, const QVariant &value) const;
-
- QSettings *m_settings;
- QHash<QByteArray, QVariant> m_cache;
- mutable QMutex m_mutex;
-};
-
-} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/filedownloader.cpp b/src/plugins/qmldesigner/utils/filedownloader.cpp
new file mode 100644
index 0000000000..b5c735d87a
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/filedownloader.cpp
@@ -0,0 +1,288 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#include "filedownloader.h"
+
+#include <private/qqmldata_p.h>
+#include <utils/networkaccessmanager.h>
+#include <utils/filepath.h>
+
+#include <QDir>
+#include <QQmlEngine>
+#include <QRandomGenerator>
+
+namespace QmlDesigner {
+
+FileDownloader::FileDownloader(QObject *parent)
+ : QObject(parent)
+{
+ QObject::connect(this, &FileDownloader::downloadFailed, this, [this]() {
+ if (m_outputFile.exists())
+ m_outputFile.remove();
+ });
+
+ QObject::connect(this, &FileDownloader::downloadCanceled, this, [this]() {
+ if (m_outputFile.exists())
+ m_outputFile.remove();
+ });
+}
+
+FileDownloader::~FileDownloader()
+{
+ // Delete the temp file only if a target Path was set (i.e. file will be moved)
+ if (deleteFileAtTheEnd() && m_outputFile.exists())
+ m_outputFile.remove();
+}
+
+bool FileDownloader::deleteFileAtTheEnd() const
+{
+ return m_targetFilePath.isEmpty();
+}
+
+void FileDownloader::start()
+{
+ emit downloadStarting();
+
+ auto uniqueText = QByteArray::number(QRandomGenerator::global()->generate(), 16);
+ QString tempFileName = QDir::tempPath() + "/.qds_" + uniqueText + "_download_" + url().fileName();
+
+ m_outputFile.setFileName(tempFileName);
+ m_outputFile.open(QIODevice::WriteOnly);
+
+ auto request = QNetworkRequest(m_url);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
+ QNetworkRequest::UserVerifiedRedirectPolicy);
+ QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request);
+ m_reply = reply;
+
+ QNetworkReply::connect(reply, &QNetworkReply::readyRead, this, [this, reply]() {
+ bool isDownloadingFile = false;
+ QString contentType;
+ if (!reply->hasRawHeader("Content-Type")) {
+ isDownloadingFile = true;
+ } else {
+ contentType = QString::fromUtf8(reply->rawHeader("Content-Type"));
+
+ if (contentType.startsWith("application/")
+ || contentType.startsWith("image/")
+ || contentType.startsWith("binary/")) {
+ isDownloadingFile = true;
+ } else {
+ qWarning() << "FileDownloader: Content type '" << contentType << "' is not supported";
+ }
+ }
+
+ if (isDownloadingFile)
+ m_outputFile.write(reply->readAll());
+ else
+ reply->close();
+ });
+
+ QNetworkReply::connect(reply,
+ &QNetworkReply::downloadProgress,
+ this,
+ [this](qint64 current, qint64 max) {
+ if (max <= 0) {
+ // NOTE: according to doc, we might have the second arg
+ // of QNetworkReply::downloadProgress less than 0.
+ return;
+ }
+
+ m_progress = current * 100 / max;
+ emit progressChanged();
+ });
+
+ QNetworkReply::connect(reply, &QNetworkReply::redirected, [reply](const QUrl &) {
+ emit reply->redirectAllowed();
+ });
+
+ QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() {
+ if (reply->error()) {
+ if (reply->error() != QNetworkReply::OperationCanceledError) {
+ qWarning() << Q_FUNC_INFO << m_url << reply->errorString();
+ emit downloadFailed();
+ } else {
+ emit downloadCanceled();
+ }
+ } else {
+ m_outputFile.flush();
+ m_outputFile.close();
+
+ QString dirPath = QFileInfo(m_targetFilePath).dir().absolutePath();
+ if (!deleteFileAtTheEnd()) {
+ if (!QDir{}.mkpath(dirPath)) {
+ emit downloadFailed();
+ return;
+ }
+
+ if (!QFileInfo().exists(m_targetFilePath) && !m_outputFile.rename(m_targetFilePath)) {
+ emit downloadFailed();
+ return;
+ }
+ }
+
+ m_finished = true;
+ emit outputFileChanged();
+ emit finishedChanged();
+ }
+
+ reply->deleteLater();
+ m_reply = nullptr;
+ });
+}
+
+void FileDownloader::setProbeUrl(bool value)
+{
+ if (m_probeUrl == value)
+ return;
+
+ m_probeUrl = value;
+ emit probeUrlChanged();
+}
+
+bool FileDownloader::probeUrl() const
+{
+ return m_probeUrl;
+}
+
+void FileDownloader::cancel()
+{
+ if (m_reply)
+ m_reply->abort();
+}
+
+void FileDownloader::setUrl(const QUrl &url)
+{
+ if (m_url != url) {
+ m_url = url;
+ emit urlChanged();
+ }
+
+ if (m_probeUrl)
+ doProbeUrl();
+}
+
+QUrl FileDownloader::url() const
+{
+ return m_url;
+}
+
+void FileDownloader::setDownloadEnabled(bool value)
+{
+ if (m_downloadEnabled == value)
+ return;
+
+ m_downloadEnabled = value;
+ emit downloadEnabledChanged();
+
+ if (!m_url.isEmpty() && m_probeUrl)
+ doProbeUrl();
+}
+
+bool FileDownloader::downloadEnabled() const
+{
+ return m_downloadEnabled;
+}
+
+bool FileDownloader::finished() const
+{
+ return m_finished;
+}
+
+bool FileDownloader::error() const
+{
+ return m_error;
+}
+
+QString FileDownloader::name() const
+{
+ const QFileInfo fileInfo(m_url.path());
+ return fileInfo.baseName();
+}
+
+QString FileDownloader::completeBaseName() const
+{
+ return QFileInfo(m_url.path()).completeBaseName();
+}
+
+int FileDownloader::progress() const
+{
+ return m_progress;
+}
+
+QString FileDownloader::outputFile() const
+{
+ return QFileInfo(m_outputFile).canonicalFilePath();
+}
+
+QDateTime FileDownloader::lastModified() const
+{
+ return m_lastModified;
+}
+
+bool FileDownloader::available() const
+{
+ return m_available;
+}
+
+void FileDownloader::doProbeUrl()
+{
+ if (!m_probeUrl)
+ return;
+
+ if (!m_downloadEnabled) {
+ m_available = false;
+ emit availableChanged();
+ return;
+ }
+
+ auto request = QNetworkRequest(m_url);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
+ QNetworkRequest::UserVerifiedRedirectPolicy);
+ QNetworkReply *reply = Utils::NetworkAccessManager::instance()->head(request);
+
+ QNetworkReply::connect(reply, &QNetworkReply::redirected, [reply](const QUrl &) {
+ emit reply->redirectAllowed();
+ });
+
+ QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() {
+ if (reply->error())
+ return;
+
+ m_lastModified = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
+ emit lastModifiedChanged();
+
+ m_available = true;
+ emit availableChanged();
+ });
+
+ QNetworkReply::connect(reply,
+ &QNetworkReply::errorOccurred,
+ this,
+ [this](QNetworkReply::NetworkError) {
+ QQmlData *data = QQmlData::get(this, false);
+ if (!data) {
+ qDebug() << Q_FUNC_INFO << "FileDownloader is nullptr.";
+ return;
+ }
+
+ if (QQmlData::wasDeleted(this)) {
+ qDebug() << Q_FUNC_INFO << "FileDownloader was deleted.";
+ return;
+ }
+
+ m_available = false;
+ emit availableChanged();
+ });
+}
+
+void FileDownloader::setTargetFilePath(const QString &path)
+{
+ m_targetFilePath = path;
+}
+
+QString FileDownloader::targetFilePath() const
+{
+ return m_targetFilePath;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/filedownloader.h b/src/plugins/qmldesigner/utils/filedownloader.h
new file mode 100644
index 0000000000..b1202e57cb
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/filedownloader.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <QFile>
+#include <QNetworkReply>
+#include <QObject>
+#include <QUrl>
+
+namespace QmlDesigner {
+
+class FileDownloader : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool downloadEnabled WRITE setDownloadEnabled READ downloadEnabled NOTIFY downloadEnabledChanged)
+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
+ Q_PROPERTY(QString targetFilePath READ targetFilePath WRITE setTargetFilePath NOTIFY targetFilePathChanged)
+ Q_PROPERTY(bool probeUrl READ probeUrl WRITE setProbeUrl NOTIFY probeUrlChanged)
+ Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
+ Q_PROPERTY(bool error READ error NOTIFY errorChanged)
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
+ Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged)
+ Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(QString outputFile READ outputFile NOTIFY outputFileChanged)
+ Q_PROPERTY(QDateTime lastModified READ lastModified NOTIFY lastModifiedChanged)
+ Q_PROPERTY(bool available READ available NOTIFY availableChanged)
+
+public:
+ explicit FileDownloader(QObject *parent = nullptr);
+
+ ~FileDownloader();
+
+ void setUrl(const QUrl &url);
+ QUrl url() const;
+ void setTargetFilePath(const QString &path);
+ QString targetFilePath() const;
+ bool finished() const;
+ bool error() const;
+ QString name() const;
+ QString completeBaseName() const;
+ int progress() const;
+ QString outputFile() const;
+ QDateTime lastModified() const;
+ bool available() const;
+ void setDownloadEnabled(bool value);
+ bool downloadEnabled() const;
+
+ void setProbeUrl(bool value);
+ bool probeUrl() const;
+
+ Q_INVOKABLE void start();
+ Q_INVOKABLE void cancel();
+
+signals:
+ void finishedChanged();
+ void errorChanged();
+ void nameChanged();
+ void urlChanged();
+ void progressChanged();
+ void outputFileChanged();
+ void downloadFailed();
+ void lastModifiedChanged();
+ void availableChanged();
+ void downloadEnabledChanged();
+
+ void downloadStarting();
+ void downloadCanceled();
+ void probeUrlChanged();
+ void targetFilePathChanged();
+
+private:
+ void doProbeUrl();
+ bool deleteFileAtTheEnd() const;
+
+ QUrl m_url;
+ bool m_probeUrl = false;
+ bool m_finished = false;
+ bool m_error = false;
+ int m_progress = 0;
+ QFile m_outputFile;
+ QDateTime m_lastModified;
+ bool m_available = false;
+
+ QNetworkReply *m_reply = nullptr;
+ bool m_downloadEnabled = false;
+ QString m_targetFilePath;
+};
+
+} // namespace QmlDesigner
+
diff --git a/src/plugins/qmldesigner/utils/fileextractor.cpp b/src/plugins/qmldesigner/utils/fileextractor.cpp
new file mode 100644
index 0000000000..c6aa83fb7a
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/fileextractor.cpp
@@ -0,0 +1,236 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#include "fileextractor.h"
+
+#include <QQmlEngine>
+#include <QStorageInfo>
+
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+
+#include <utils/algorithm.h>
+#include <utils/archive.h>
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+
+namespace QmlDesigner {
+
+FileExtractor::FileExtractor(QObject *parent)
+ : QObject(parent)
+{
+ m_timer.setInterval(100);
+ m_timer.setSingleShot(false);
+
+ QObject::connect(this, &FileExtractor::targetFolderExistsChanged, this, [this]() {
+ if (targetFolderExists())
+ m_birthTime = QFileInfo(m_targetPath.toString() + "/" + m_archiveName).birthTime();
+ else
+ m_birthTime = QDateTime();
+
+ emit birthTimeChanged();
+ });
+
+ QObject::connect(
+ &m_timer, &QTimer::timeout, this, [this]() {
+ static QHash<QString, int> hash;
+ QDirIterator it(m_targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories);
+
+ int count = 0;
+ while (it.hasNext()) {
+ if (!hash.contains(it.fileName())) {
+ m_currentFile = it.fileName();
+ hash.insert(m_currentFile, 0);
+ emit currentFileChanged();
+ }
+ it.next();
+ count++;
+ }
+
+ qint64 currentSize = m_bytesBefore
+ - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
+
+ // We can not get the uncompressed size of the archive yet, that is why we use an
+ // approximation. We assume a 50% compression rate.
+ int progress = std::min(100ll, currentSize * 100 / m_compressedSize * 2);
+ if (progress >= 0) {
+ m_progress = progress;
+ emit progressChanged();
+ } else {
+ qWarning() << "FileExtractor has got negative progress. Likely due to QStorageInfo.";
+ }
+
+ m_size = QString::number(currentSize);
+ m_count = QString::number(count);
+ emit sizeChanged();
+ });
+}
+
+FileExtractor::~FileExtractor() {}
+
+void FileExtractor::changeTargetPath(const QString &path)
+{
+ m_targetPath = Utils::FilePath::fromString(path);
+ emit targetPathChanged();
+ emit targetFolderExistsChanged();
+}
+
+QString FileExtractor::targetPath() const
+{
+ return m_targetPath.toUserOutput();
+}
+
+void FileExtractor::setTargetPath(const QString &path)
+{
+ m_targetPath = Utils::FilePath::fromString(path);
+
+ QDir dir(m_targetPath.toString());
+
+ if (!path.isEmpty() && !dir.exists()) {
+ // Even though m_targetPath will be created eventually, we need to make sure the path exists
+ // before m_bytesBefore is being calculated.
+ dir.mkpath(m_targetPath.toString());
+ }
+}
+
+void FileExtractor::browse()
+{
+ const Utils::FilePath path =
+ Utils::FileUtils::getExistingDirectory(nullptr, tr("Choose Directory"), m_targetPath);
+
+ if (!path.isEmpty())
+ m_targetPath = path;
+
+ emit targetPathChanged();
+ emit targetFolderExistsChanged();
+}
+
+void FileExtractor::setSourceFile(const QString &sourceFilePath)
+{
+ m_sourceFile = Utils::FilePath::fromString(sourceFilePath);
+ emit targetFolderExistsChanged();
+}
+
+void FileExtractor::setArchiveName(const QString &filePath)
+{
+ m_archiveName = filePath;
+ emit targetFolderExistsChanged();
+}
+
+const QString FileExtractor::detailedText() const
+{
+ return m_detailedText;
+}
+
+void FileExtractor::setClearTargetPathContents(bool value)
+{
+ if (m_clearTargetPathContents != value) {
+ m_clearTargetPathContents = value;
+ emit clearTargetPathContentsChanged();
+ }
+}
+
+bool FileExtractor::clearTargetPathContents() const
+{
+ return m_clearTargetPathContents;
+}
+
+void FileExtractor::setAlwaysCreateDir(bool value)
+{
+ if (m_alwaysCreateDir != value) {
+ m_alwaysCreateDir = value;
+ emit alwaysCreateDirChanged();
+ }
+}
+
+bool FileExtractor::alwaysCreateDir() const
+{
+ return m_alwaysCreateDir;
+}
+
+bool FileExtractor::finished() const
+{
+ return m_finished;
+}
+
+QString FileExtractor::currentFile() const
+{
+ return m_currentFile;
+}
+
+QString FileExtractor::size() const
+{
+ return m_size;
+}
+
+QString FileExtractor::count() const
+{
+ return m_count;
+}
+
+bool FileExtractor::targetFolderExists() const
+{
+ return QFileInfo::exists(m_targetPath.toString() + "/" + m_archiveName);
+}
+
+int FileExtractor::progress() const
+{
+ return m_progress;
+}
+
+QDateTime FileExtractor::birthTime() const
+{
+ return m_birthTime;
+}
+
+QString FileExtractor::archiveName() const
+{
+ return m_archiveName;
+}
+
+QString FileExtractor::sourceFile() const
+{
+ return m_sourceFile.toString();
+}
+
+void FileExtractor::extract()
+{
+ m_targetFolder = m_targetPath.toString() + "/" + m_archiveName;
+
+ // If the target directory already exists, remove it and its content
+ QDir targetDir(m_targetFolder);
+ if (targetDir.exists() && m_clearTargetPathContents)
+ targetDir.removeRecursively();
+
+ if (m_alwaysCreateDir) {
+ // Create a new directory to generate a proper creation date
+ targetDir.mkdir(m_targetFolder);
+ }
+
+ Utils::Archive *archive = new Utils::Archive(m_sourceFile, m_targetPath);
+ QTC_ASSERT(archive->isValid(), delete archive; return);
+
+ m_timer.start();
+ m_bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
+ m_compressedSize = QFileInfo(m_sourceFile.toString()).size();
+
+ QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) {
+ m_detailedText += output;
+ emit detailedTextChanged();
+ });
+
+ QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
+ archive->deleteLater();
+ m_finished = ret;
+ m_timer.stop();
+
+ m_progress = 100;
+ emit progressChanged();
+
+ emit targetFolderExistsChanged();
+ emit finishedChanged();
+ QTC_CHECK(ret);
+ });
+ archive->unarchive();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/fileextractor.h b/src/plugins/qmldesigner/utils/fileextractor.h
new file mode 100644
index 0000000000..5dbf12e903
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/fileextractor.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <QDateTime>
+#include <QObject>
+#include <QTimer>
+
+#include <utils/filepath.h>
+
+namespace QmlDesigner {
+
+class FileExtractor : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString targetPath READ targetPath WRITE setTargetPath NOTIFY targetPathChanged)
+ Q_PROPERTY(QString archiveName READ archiveName WRITE setArchiveName)
+ Q_PROPERTY(QString detailedText READ detailedText NOTIFY detailedTextChanged)
+ Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged)
+ Q_PROPERTY(QString size READ size NOTIFY sizeChanged)
+ Q_PROPERTY(QString count READ count NOTIFY sizeChanged)
+ Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile)
+ Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
+ Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged)
+ Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(QDateTime birthTime READ birthTime NOTIFY birthTimeChanged)
+ Q_PROPERTY(bool clearTargetPathContents READ clearTargetPathContents WRITE setClearTargetPathContents NOTIFY clearTargetPathContentsChanged)
+ Q_PROPERTY(bool alwaysCreateDir READ alwaysCreateDir WRITE setAlwaysCreateDir NOTIFY alwaysCreateDirChanged)
+
+public:
+ explicit FileExtractor(QObject *parent = nullptr);
+ ~FileExtractor();
+
+ Q_INVOKABLE void changeTargetPath(const QString &path);
+
+ QString targetPath() const;
+ void setTargetPath(const QString &path);
+ void setSourceFile(const QString &sourceFilePath);
+ void setArchiveName(const QString &filePath);
+ const QString detailedText() const;
+ bool finished() const;
+ QString currentFile() const;
+ QString size() const;
+ QString count() const;
+ bool targetFolderExists() const;
+ int progress() const;
+ QDateTime birthTime() const;
+ void setClearTargetPathContents(bool value);
+ bool clearTargetPathContents() const;
+ void setAlwaysCreateDir(bool value);
+ bool alwaysCreateDir() const;
+
+ QString sourceFile() const;
+ QString archiveName() const;
+
+ Q_INVOKABLE void browse();
+ Q_INVOKABLE void extract();
+
+signals:
+ void targetPathChanged();
+ void detailedTextChanged();
+ void finishedChanged();
+ void currentFileChanged();
+ void sizeChanged();
+ void targetFolderExistsChanged();
+ void progressChanged();
+ void birthTimeChanged();
+ void clearTargetPathContentsChanged();
+ void alwaysCreateDirChanged();
+
+private:
+ Utils::FilePath m_targetPath;
+ QString m_targetFolder; // The same as m_targetPath, but with the archive name also.
+ Utils::FilePath m_sourceFile;
+ QString m_detailedText;
+ bool m_finished = false;
+ QTimer m_timer;
+ QString m_currentFile;
+ QString m_size;
+ QString m_count;
+ QString m_archiveName;
+ int m_progress = 0;
+ QDateTime m_birthTime;
+ bool m_clearTargetPathContents = false;
+ bool m_alwaysCreateDir = false;
+
+ qint64 m_bytesBefore = 0;
+ qint64 m_compressedSize = 0;
+};
+
+} // QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/hdrimage.cpp b/src/plugins/qmldesigner/utils/hdrimage.cpp
index 227c6ab671..74d3acde50 100644
--- a/src/plugins/qmldesigner/utils/hdrimage.cpp
+++ b/src/plugins/qmldesigner/utils/hdrimage.cpp
@@ -21,7 +21,7 @@ typedef unsigned char RGBE[4];
constexpr float GAMMA = 1.f / 2.2f;
-QByteArray fileToByteArray(QString const &filename)
+static QByteArray fileToByteArray(QString const &filename)
{
QFile file(filename);
QFileInfo info(file);
diff --git a/src/plugins/qmldesigner/utils/imageutils.cpp b/src/plugins/qmldesigner/utils/imageutils.cpp
index 97660b2aa3..8fa3131cd3 100644
--- a/src/plugins/qmldesigner/utils/imageutils.cpp
+++ b/src/plugins/qmldesigner/utils/imageutils.cpp
@@ -3,12 +3,23 @@
#include "imageutils.h"
+#include "ktximage.h"
+
#include <QFile>
#include <QFileInfo>
#include <QImageReader>
namespace QmlDesigner {
+QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes)
+{
+ return QLatin1String("%1 x %2\n%3")
+ .arg(QString::number(dimensions.width()),
+ QString::number(dimensions.height()),
+ QLocale::system().formattedDataSize(
+ sizeInBytes, 2, QLocale::DataSizeTraditionalFormat));
+}
+
QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
{
QFileInfo info(path);
@@ -17,7 +28,8 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
int width = 0;
int height = 0;
- if (info.suffix() == "hdr") {
+ const QString suffix = info.suffix();
+ if (suffix == "hdr") {
QFile file(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return {};
@@ -27,20 +39,20 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path)
if (sscanf(line.constData(), "-Y %d +X %d", &height, &width))
break;
}
+ } else if (suffix == "ktx") {
+ KtxImage ktx(path);
+ width = ktx.dimensions().width();
+ height = ktx.dimensions().height();
} else {
QSize size = QImageReader(path).size();
width = size.width();
height = size.height();
}
- if (width == 0 && height == 0)
+ if (width <= 0 || height <= 0)
return {};
- return QLatin1String("%1 x %2\n%3 (%4)")
- .arg(QString::number(width),
- QString::number(height),
- QLocale::system().formattedDataSize(info.size(), 2, QLocale::DataSizeTraditionalFormat),
- info.suffix());
+ return imageInfo(QSize(width, height), info.size());
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/imageutils.h b/src/plugins/qmldesigner/utils/imageutils.h
index 2e1030d48c..a4036614a3 100644
--- a/src/plugins/qmldesigner/utils/imageutils.h
+++ b/src/plugins/qmldesigner/utils/imageutils.h
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
+#include <QSize>
#include <QString>
namespace QmlDesigner {
@@ -11,6 +12,7 @@ class ImageUtils
public:
ImageUtils();
+ static QString imageInfo(const QSize &dimensions, qint64 sizeInBytes);
static QString imageInfo(const QString &path);
};
diff --git a/src/plugins/qmldesigner/utils/ktximage.cpp b/src/plugins/qmldesigner/utils/ktximage.cpp
new file mode 100644
index 0000000000..1bb607403f
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/ktximage.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "ktximage.h"
+
+#include <QFile>
+#include <QFileInfo>
+#include <QDebug>
+
+#include <cmath>
+
+namespace QmlDesigner {
+
+// Ktx images currently support only image metadata
+
+static QByteArray fileToByteArray(QString const &filename)
+{
+ QFile file(filename);
+ QFileInfo info(file);
+
+ if (info.exists() && file.open(QFile::ReadOnly)) {
+ // Read data until we have what we need
+ // Content is:
+ // Byte[12] identifier
+ // UInt32 endianness
+ // UInt32
+ // UInt32
+ // UInt32
+ // Uint32
+ // Uint32
+ // UInt32 pixelWidth
+ // UInt32 pixelHeight
+ // ...
+ return file.read(44);
+ }
+
+ return {};
+}
+
+KtxImage::KtxImage(const QString &fileName)
+ : m_fileName(fileName)
+{
+ loadKtx();
+}
+
+QSize KtxImage::dimensions() const
+{
+ return m_dim;
+}
+
+void KtxImage::loadKtx()
+{
+ QByteArray buf(fileToByteArray(m_fileName));
+
+ auto handleError = [this](const QString &error) {
+ qWarning() << QStringLiteral("Failed to load KTX image '%1': %2.").arg(m_fileName, error).toUtf8();
+ };
+
+ if (buf.isEmpty()) {
+ handleError("File open failed");
+ return;
+ }
+
+ constexpr char ktxIdentifier[12] = {
+ '\xAB', 'K', 'T', 'X', ' ', '1',
+ '1', '\xBB', '\r', '\n', '\x1A', '\n'
+ };
+
+ if (!buf.startsWith(ktxIdentifier)) {
+ handleError("Non-KTX file");
+ return;
+ }
+
+ if (buf.size() < 44) {
+ handleError("Missing metadata");
+ return;
+ }
+
+ quint32 w = 0;
+ quint32 h = 0;
+
+ if (*reinterpret_cast<const quint32 *>(buf.data() + 12) == 0x01020304) {
+ // File endianness is different from our endianness
+ QByteArray convBuf(4, 0);
+ auto convertEndianness = [&convBuf, &buf](int idx) -> quint32 {
+ for (int i = 0; i < 4; ++i)
+ convBuf[i] = buf[idx + 3 - i];
+ return *reinterpret_cast<const quint32 *>(convBuf.data());
+ };
+ w = convertEndianness(36);
+ h = convertEndianness(40);
+ } else {
+ w = *reinterpret_cast<const quint32 *>(buf.data() + 36);
+ h = *reinterpret_cast<const quint32 *>(buf.data() + 40);
+ }
+
+ m_dim = QSize(w, h);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/ktximage.h b/src/plugins/qmldesigner/utils/ktximage.h
new file mode 100644
index 0000000000..19b8132d27
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/ktximage.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include "qmldesignerutils_global.h"
+
+#include <QImage>
+#include <QPixmap>
+#include <QSize>
+#include <QString>
+
+namespace QmlDesigner {
+
+class QMLDESIGNERUTILS_EXPORT KtxImage
+{
+public:
+ KtxImage(const QString &fileName);
+
+ QString fileName() const { return m_fileName; }
+ QSize dimensions() const;
+
+private:
+ void loadKtx();
+
+ QString m_fileName;
+ QSize m_dim;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/multifiledownloader.cpp b/src/plugins/qmldesigner/utils/multifiledownloader.cpp
new file mode 100644
index 0000000000..346c1675f6
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/multifiledownloader.cpp
@@ -0,0 +1,132 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#include "multifiledownloader.h"
+#include "filedownloader.h"
+
+namespace QmlDesigner {
+
+MultiFileDownloader::MultiFileDownloader(QObject *parent)
+ : QObject(parent)
+{}
+
+MultiFileDownloader::~MultiFileDownloader()
+{}
+
+void MultiFileDownloader::setDownloader(FileDownloader *downloader)
+{
+ m_downloader = downloader;
+
+ QObject::connect(this, &MultiFileDownloader::downloadStarting, [this]() {
+ m_nextFile = 0;
+ if (m_files.length() > 0)
+ m_downloader->start();
+ });
+
+ QObject::connect(m_downloader, &FileDownloader::progressChanged, this, [this]() {
+ m_progress = (m_nextFile + m_downloader->progress()) / m_files.count();
+ });
+
+ QObject::connect(m_downloader, &FileDownloader::downloadFailed, this, [this]() {
+ m_failed = true;
+ emit downloadFailed();
+ });
+
+ QObject::connect(m_downloader, &FileDownloader::downloadCanceled, this, [this]() {
+ m_canceled = true;
+ emit downloadCanceled();
+ });
+
+ QObject::connect(m_downloader, &FileDownloader::finishedChanged, this, [this]() {
+ switchToNextFile();
+ });
+}
+
+void MultiFileDownloader::start()
+{
+ emit downloadStarting();
+}
+
+void MultiFileDownloader::cancel()
+{
+ m_canceled = true;
+ m_downloader->cancel();
+}
+
+void MultiFileDownloader::setBaseUrl(const QUrl &baseUrl)
+{
+ if (m_baseUrl != baseUrl) {
+ m_baseUrl = baseUrl;
+ emit baseUrlChanged();
+ }
+}
+
+QUrl MultiFileDownloader::baseUrl() const
+{
+ return m_baseUrl;
+}
+
+bool MultiFileDownloader::finished() const
+{
+ return m_finished;
+}
+
+int MultiFileDownloader::progress() const
+{
+ return m_progress;
+}
+
+void MultiFileDownloader::setTargetDirPath(const QString &path)
+{
+ m_targetDirPath = path;
+}
+
+QString MultiFileDownloader::targetDirPath() const
+{
+ return m_targetDirPath;
+}
+
+QString MultiFileDownloader::nextUrl() const
+{
+ if (m_nextFile >= m_files.length())
+ return {};
+
+ return m_baseUrl.toString() + "/" + m_files[m_nextFile];
+}
+
+QString MultiFileDownloader::nextTargetPath() const
+{
+ if (m_nextFile >= m_files.length())
+ return {};
+
+ return m_targetDirPath + "/" + m_files[m_nextFile];
+}
+
+void MultiFileDownloader::setFiles(const QStringList &files)
+{
+ m_files = files;
+}
+
+QStringList MultiFileDownloader::files() const
+{
+ return m_files;
+}
+
+void MultiFileDownloader::switchToNextFile()
+{
+ ++m_nextFile;
+
+ if (m_nextFile < m_files.length()) {
+ if (m_canceled) {
+ emit downloadCanceled();
+ } else {
+ emit nextUrlChanged();
+ emit nextTargetPathChanged();
+ m_downloader->start();
+ }
+ } else {
+ m_finished = true;
+ emit finishedChanged();
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/multifiledownloader.h b/src/plugins/qmldesigner/utils/multifiledownloader.h
new file mode 100644
index 0000000000..548896dbc8
--- /dev/null
+++ b/src/plugins/qmldesigner/utils/multifiledownloader.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <QObject>
+#include <QUrl>
+
+namespace QmlDesigner {
+
+class FileDownloader;
+
+class MultiFileDownloader : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(FileDownloader *downloader WRITE setDownloader)
+ Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
+ Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
+ Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
+ Q_PROPERTY(QString targetDirPath READ targetDirPath WRITE setTargetDirPath NOTIFY targetDirPathChanged)
+
+ Q_PROPERTY(QString nextUrl READ nextUrl NOTIFY nextUrlChanged)
+ Q_PROPERTY(QString nextTargetPath READ nextTargetPath NOTIFY nextTargetPathChanged)
+ Q_PROPERTY(QStringList files READ files WRITE setFiles NOTIFY filesChanged)
+
+public:
+ explicit MultiFileDownloader(QObject *parent = nullptr);
+
+ ~MultiFileDownloader();
+
+ void setBaseUrl(const QUrl &url);
+ QUrl baseUrl() const;
+
+ void setTargetDirPath(const QString &path);
+ QString targetDirPath() const;
+ void setDownloader(FileDownloader *downloader);
+
+ bool finished() const;
+ int progress() const;
+
+ QString nextUrl() const;
+ QString nextTargetPath() const;
+
+ void setFiles(const QStringList &files);
+ QStringList files() const;
+ void switchToNextFile();
+
+ Q_INVOKABLE void start();
+ Q_INVOKABLE void cancel();
+
+signals:
+ void finishedChanged();
+ void baseUrlChanged();
+ void progressChanged();
+ void downloadFailed();
+
+ void downloadStarting();
+ void downloadCanceled();
+ void targetDirPathChanged();
+ void nextUrlChanged();
+ void filesChanged();
+ void nextTargetPathChanged();
+
+private:
+ QUrl m_baseUrl;
+ bool m_finished = false;
+ int m_progress = 0;
+ QString m_targetDirPath;
+ FileDownloader *m_downloader = nullptr;
+ bool m_canceled = false;
+ bool m_failed = false;
+ QStringList m_files;
+ int m_nextFile = 0;
+};
+
+} // namespace QmlDesigner
+
diff --git a/src/plugins/qmldesignerbase/CMakeLists.txt b/src/plugins/qmldesignerbase/CMakeLists.txt
new file mode 100644
index 0000000000..f03498f28d
--- /dev/null
+++ b/src/plugins/qmldesignerbase/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_qtc_plugin(QmlDesignerBase
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+ DEPENDS Qt::Core Qt::QuickWidgets
+ PLUGIN_DEPENDS Core ProjectExplorer QtSupport
+ SOURCES
+ qmldesignerbase_global.h
+ qmldesignerbaseplugin.cpp qmldesignerbaseplugin.h
+)
+
+extend_qtc_plugin(QmlDesignerBase
+ PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils
+ SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils
+ SOURCES
+ designersettings.cpp designersettings.h
+ qmlpuppetpaths.cpp qmlpuppetpaths.h
+ studioquickwidget.cpp studioquickwidget.h
+)
diff --git a/src/plugins/qmldesignerbase/QmlDesignerBase.json.in b/src/plugins/qmldesignerbase/QmlDesignerBase.json.in
new file mode 100644
index 0000000000..38fb427ae1
--- /dev/null
+++ b/src/plugins/qmldesignerbase/QmlDesignerBase.json.in
@@ -0,0 +1,19 @@
+{
+ \"Name\" : \"QmlDesignerBase\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"The Qt Company Ltd\",
+ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
+ ],
+ \"Category\" : \"Qt Quick\",
+ \"Description\" : \"Provides support code for the qml designer and co..\",
+ \"Url\" : \"http://www.qt.io\",
+ $$dependencyList
+}
diff --git a/src/plugins/qmldesignerbase/qmldesignerbase_global.h b/src/plugins/qmldesignerbase/qmldesignerbase_global.h
new file mode 100644
index 0000000000..89b5dc4a9d
--- /dev/null
+++ b/src/plugins/qmldesignerbase/qmldesignerbase_global.h
@@ -0,0 +1,14 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QtGlobal>
+
+#if defined(QMLDESIGNERBASE_LIBRARY)
+#define QMLDESIGNERBASE_EXPORT Q_DECL_EXPORT
+#elif defined(QMLDESIGNERBASE_STATIC_LIBRARY)
+#define QMLDESIGNERBASE_EXPORT
+#else
+#define QMLDESIGNERBASE_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp
new file mode 100644
index 0000000000..0dc9734e8f
--- /dev/null
+++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp
@@ -0,0 +1,272 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qmldesignerbaseplugin.h"
+
+#include "utils/designersettings.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/dialogs/restartdialog.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <utils/hostosinfo.h>
+
+#include <QCheckBox>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QSpacerItem>
+#include <QStandardPaths>
+#include <QVBoxLayout>
+
+namespace QmlDesigner {
+
+const char EXAMPLES_DOWNLOAD_PATH[] = "StudioConfig/ExamplesDownloadPath";
+const char BUNDLES_DOWNLOAD_PATH[] = "StudioConfig/BundlesDownloadPath";
+
+class QmlDesignerBasePlugin::Data
+{
+public:
+ DesignerSettings settings{Core::ICore::instance()->settings()};
+};
+
+namespace {
+QmlDesignerBasePlugin *global;
+}
+
+QmlDesignerBasePlugin::QmlDesignerBasePlugin()
+{
+ global = this;
+};
+
+QmlDesignerBasePlugin *QmlDesignerBasePlugin::instance()
+{
+ return global;
+};
+
+
+QmlDesignerBasePlugin::~QmlDesignerBasePlugin() = default;
+
+DesignerSettings &QmlDesignerBasePlugin::settings()
+{
+ return global->d->settings;
+}
+
+bool QmlDesignerBasePlugin::initialize(const QStringList &, QString *)
+{
+ d = std::make_unique<Data>();
+
+ return true;
+}
+
+Utils::FilePath QmlDesignerBasePlugin::defaultExamplesPath()
+{
+ QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
+ ? QStandardPaths::HomeLocation
+ : QStandardPaths::DocumentsLocation;
+
+ return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
+ .pathAppended("QtDesignStudio/examples");
+}
+
+Utils::FilePath QmlDesignerBasePlugin::defaultBundlesPath()
+{
+ QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
+ ? QStandardPaths::HomeLocation
+ : QStandardPaths::DocumentsLocation;
+
+ return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
+ .pathAppended("QtDesignStudio/bundles");
+}
+
+QString QmlDesignerBasePlugin::examplesPathSetting()
+{
+ return Core::ICore::settings()
+ ->value(EXAMPLES_DOWNLOAD_PATH, defaultExamplesPath().toString())
+ .toString();
+}
+
+QString QmlDesignerBasePlugin::bundlesPathSetting()
+{
+ return Core::ICore::settings()
+ ->value(BUNDLES_DOWNLOAD_PATH, defaultBundlesPath().toString())
+ .toString();
+}
+
+static bool hideBuildMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD, false)
+ .toBool();
+}
+
+static bool hideDebugMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false)
+ .toBool();
+}
+
+static bool hideAnalyzeMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE, false)
+ .toBool();
+}
+
+static bool hideToolsMenuSetting()
+{
+ return Core::ICore::settings()->value(Core::Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
+}
+
+void setSettingIfDifferent(const QString &key, bool value, bool &dirty)
+{
+ QSettings *s = Core::ICore::settings();
+ if (s->value(key, false).toBool() != value) {
+ dirty = true;
+ s->setValue(key, value);
+ }
+}
+
+StudioSettingsPage::StudioSettingsPage()
+ : m_buildCheckBox(new QCheckBox(tr("Build")))
+ , m_debugCheckBox(new QCheckBox(tr("Debug")))
+ , m_analyzeCheckBox(new QCheckBox(tr("Analyze")))
+ , m_toolsCheckBox(new QCheckBox(tr("Tools")))
+ , m_pathChooserExamples(new Utils::PathChooser())
+ , m_pathChooserBundles(new Utils::PathChooser())
+{
+ const QString toolTip = tr(
+ "Hide top-level menus with advanced functionality to simplify the UI. <b>Build</b> is "
+ "generally not required in the context of Qt Design Studio. <b>Debug</b> and "
+ "<b>Analyze</b> "
+ "are only required for debugging and profiling. <b>Tools</b> can be useful for bookmarks "
+ "and git integration.");
+
+ QVBoxLayout *boxLayout = new QVBoxLayout();
+ setLayout(boxLayout);
+ auto groupBox = new QGroupBox(tr("Hide Menu"));
+ groupBox->setToolTip(toolTip);
+ boxLayout->addWidget(groupBox);
+
+ auto verticalLayout = new QVBoxLayout();
+ groupBox->setLayout(verticalLayout);
+
+ m_buildCheckBox->setToolTip(toolTip);
+ m_debugCheckBox->setToolTip(toolTip);
+ m_analyzeCheckBox->setToolTip(toolTip);
+ m_toolsCheckBox->setToolTip(toolTip);
+
+ verticalLayout->addWidget(m_buildCheckBox);
+ verticalLayout->addWidget(m_debugCheckBox);
+ verticalLayout->addWidget(m_analyzeCheckBox);
+ verticalLayout->addWidget(m_toolsCheckBox);
+
+ verticalLayout->addSpacerItem(
+ new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+ m_buildCheckBox->setChecked(hideBuildMenuSetting());
+ m_debugCheckBox->setChecked(hideDebugMenuSetting());
+ m_analyzeCheckBox->setChecked(hideAnalyzeMenuSetting());
+ m_toolsCheckBox->setChecked(hideToolsMenuSetting());
+
+ // Examples path setting
+ auto examplesGroupBox = new QGroupBox(tr("Examples"));
+ boxLayout->addWidget(examplesGroupBox);
+
+ auto examplesLayout = new QHBoxLayout(this);
+ examplesGroupBox->setLayout(examplesLayout);
+
+ auto examplesLabel = new QLabel(tr("Examples path:"));
+ m_pathChooserExamples->setFilePath(
+ Utils::FilePath::fromString(QmlDesignerBasePlugin::examplesPathSetting()));
+ auto examplesResetButton = new QPushButton(tr("Reset Path"));
+
+ connect(examplesResetButton, &QPushButton::clicked, this, [this]() {
+ m_pathChooserExamples->setFilePath(QmlDesignerBasePlugin::defaultExamplesPath());
+ });
+
+ examplesLayout->addWidget(examplesLabel);
+ examplesLayout->addWidget(m_pathChooserExamples);
+ examplesLayout->addWidget(examplesResetButton);
+
+ // Bundles path setting
+ auto bundlesGroupBox = new QGroupBox(tr("Bundles"));
+ boxLayout->addWidget(bundlesGroupBox);
+
+ auto bundlesLayout = new QHBoxLayout(this);
+ bundlesGroupBox->setLayout(bundlesLayout);
+
+ QLabel *bundlesLabel = new QLabel(tr("Bundles path:"));
+ m_pathChooserBundles->setFilePath(
+ Utils::FilePath::fromString(QmlDesignerBasePlugin::bundlesPathSetting()));
+ QPushButton *bundlesResetButton = new QPushButton(tr("Reset Path"));
+
+ connect(bundlesResetButton, &QPushButton::clicked, this, [this]() {
+ m_pathChooserBundles->setFilePath(QmlDesignerBasePlugin::defaultBundlesPath());
+ });
+
+ bundlesLayout->addWidget(bundlesLabel);
+ bundlesLayout->addWidget(m_pathChooserBundles);
+ bundlesLayout->addWidget(bundlesResetButton);
+
+ boxLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+void StudioSettingsPage::apply()
+{
+ bool dirty = false;
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD,
+ m_buildCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG,
+ m_debugCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE,
+ m_analyzeCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(Core::Constants::SETTINGS_MENU_HIDE_TOOLS,
+ m_toolsCheckBox->isChecked(),
+ dirty);
+
+ if (dirty) {
+ const QString restartText = tr("The menu visibility change will take effect after restart.");
+ Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
+ restartDialog.exec();
+ }
+
+ QSettings *s = Core::ICore::settings();
+ const QString value = m_pathChooserExamples->filePath().toString();
+
+ if (s->value(EXAMPLES_DOWNLOAD_PATH, false).toString() != value) {
+ s->setValue(EXAMPLES_DOWNLOAD_PATH, value);
+ emit global->examplesDownloadPathChanged(value);
+ }
+
+ const QString bundlesPath = m_pathChooserBundles->filePath().toString();
+
+ if (s->value(BUNDLES_DOWNLOAD_PATH).toString() != bundlesPath) {
+ s->setValue(BUNDLES_DOWNLOAD_PATH, bundlesPath);
+ emit global->bundlesDownloadPathChanged(bundlesPath);
+
+ const QString restartText = tr("Changing bundle path will take effect after restart.");
+ Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
+ restartDialog.exec();
+ }
+}
+
+StudioConfigSettingsPage::StudioConfigSettingsPage()
+{
+ setId("Z.StudioConfig.Settings");
+ setDisplayName(tr("Qt Design Studio Configuration"));
+ setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
+ setWidgetCreator([] { return new StudioSettingsPage; });
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h
new file mode 100644
index 0000000000..de9c9cabe3
--- /dev/null
+++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmldesignerbase_global.h"
+
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <extensionsystem/iplugin.h>
+#include <utils/pathchooser.h>
+
+#include <memory>
+
+QT_FORWARD_DECLARE_CLASS(QCheckBox)
+
+namespace QmlDesigner {
+
+class StudioSettingsPage : public Core::IOptionsPageWidget
+{
+ Q_OBJECT
+
+public:
+ void apply() final;
+
+ StudioSettingsPage();
+
+private:
+ QCheckBox *m_buildCheckBox;
+ QCheckBox *m_debugCheckBox;
+ QCheckBox *m_analyzeCheckBox;
+ QCheckBox *m_toolsCheckBox;
+ Utils::PathChooser *m_pathChooserExamples;
+ Utils::PathChooser *m_pathChooserBundles;
+};
+
+class QMLDESIGNERBASE_EXPORT StudioConfigSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ StudioConfigSettingsPage();
+};
+
+class QMLDESIGNERBASE_EXPORT QmlDesignerBasePlugin final : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QmlDesignerBase.json")
+
+public:
+ QmlDesignerBasePlugin();
+ ~QmlDesignerBasePlugin();
+
+ static QmlDesignerBasePlugin *instance();
+
+ static Utils::FilePath defaultExamplesPath();
+ static Utils::FilePath defaultBundlesPath();
+ static QString examplesPathSetting();
+ static QString bundlesPathSetting();
+
+ static class DesignerSettings &settings();
+
+signals:
+ void examplesDownloadPathChanged(const QString &path);
+ void bundlesDownloadPathChanged(const QString &path);
+
+private:
+ bool initialize(const QStringList &arguments, QString *errorMessage) override;
+
+private:
+ class Data;
+ std::unique_ptr<Data> d;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/utils/designersettings.cpp b/src/plugins/qmldesignerbase/utils/designersettings.cpp
index 3e6d5ffb44..fe1ee169c7 100644
--- a/src/plugins/qmldesigner/utils/designersettings.cpp
+++ b/src/plugins/qmldesignerbase/utils/designersettings.cpp
@@ -87,6 +87,9 @@ void DesignerSettings::fromSettings(QSettings *settings)
restoreValue(settings, DesignerSettingsKey::SHOW_DEBUG_SETTINGS, false);
restoreValue(settings, DesignerSettingsKey::OLD_STATES_EDITOR, false);
restoreValue(settings, DesignerSettingsKey::EDITOR_ZOOM_FACTOR, 1.0);
+ restoreValue(settings, DesignerSettingsKey::ACTIONS_MERGE_TEMPLATE_ENABLED, false);
+ restoreValue(settings, DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL,
+ "https://cdn.qt.io/designstudio/bundles");
settings->endGroup();
settings->endGroup();
diff --git a/src/plugins/qmldesignerbase/utils/designersettings.h b/src/plugins/qmldesignerbase/utils/designersettings.h
new file mode 100644
index 0000000000..78b4370526
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/designersettings.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmldesignerbase_global.h"
+
+#include <QHash>
+#include <QVariant>
+#include <QByteArray>
+#include <QMutex>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+namespace DesignerSettingsKey {
+inline constexpr char ITEMSPACING[] = "ItemSpacing";
+inline constexpr char CONTAINERPADDING[] = "ContainerPadding";
+inline constexpr char CANVASWIDTH[] = "CanvasWidth";
+inline constexpr char CANVASHEIGHT[] = "CanvasHeight";
+inline constexpr char ROOT_ELEMENT_INIT_WIDTH[] = "RootElementInitWidth";
+inline constexpr char ROOT_ELEMENT_INIT_HEIGHT[] = "RootElementInitHeight";
+inline constexpr char WARNING_FOR_FEATURES_IN_DESIGNER[] = "WarnAboutQtQuickFeaturesInDesigner";
+inline constexpr char WARNING_FOR_QML_FILES_INSTEAD_OF_UIQML_FILES[]
+ = "WarnAboutQmlFilesInsteadOfUiQmlFiles";
+inline constexpr char WARNING_FOR_DESIGNER_FEATURES_IN_EDITOR[]
+ = "WarnAboutQtQuickDesignerFeaturesInCodeEditor";
+inline constexpr char SHOW_DEBUGVIEW[] = "ShowQtQuickDesignerDebugView";
+inline constexpr char ENABLE_DEBUGVIEW[] = "EnableQtQuickDesignerDebugView";
+inline constexpr char EDIT3DVIEW_BACKGROUND_COLOR[] = "Edit3DViewBackgroundColor";
+inline constexpr char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor";
+inline constexpr char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar";
+inline constexpr char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet";
+inline constexpr char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory";
+inline constexpr char PUPPET_DEFAULT_DIRECTORY[] = "PuppetDefaultDirectory";
+inline constexpr char CONTROLS_STYLE[] = "ControlsStyle";
+inline constexpr char TYPE_OF_QSTR_FUNCTION[] = "TypeOfQsTrFunction";
+inline constexpr char SHOW_PROPERTYEDITOR_WARNINGS[] = "ShowPropertyEditorWarnings";
+inline constexpr char ENABLE_MODEL_EXCEPTION_OUTPUT[] = "WarnException";
+inline constexpr char PUPPET_KILL_TIMEOUT[] = "PuppetKillTimeout";
+inline constexpr char DEBUG_PUPPET[] = "DebugPuppet";
+inline constexpr char FORWARD_PUPPET_OUTPUT[] = "ForwardPuppetOutput";
+inline constexpr char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems";
+inline constexpr char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder";
+inline constexpr char REFORMAT_UI_QML_FILES[]
+ = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */
+inline constexpr char IGNORE_DEVICE_PIXEL_RATIO[]
+ = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */
+inline constexpr char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings";
+inline constexpr char ENABLE_TIMELINEVIEW[] = "EnableTimelineView";
+inline constexpr char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent";
+inline constexpr char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite";
+inline constexpr char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode";
+inline constexpr char DISABLE_ITEM_LIBRARY_UPDATE_TIMER[] = "DisableItemLibraryUpdateTimer";
+inline constexpr char ASK_BEFORE_DELETING_ASSET[] = "AskBeforeDeletingAsset";
+inline constexpr char SMOOTH_RENDERING[] = "SmoothRendering";
+inline constexpr char OLD_STATES_EDITOR[] = "ForceOldStatesEditor";
+inline constexpr char EDITOR_ZOOM_FACTOR[] = "EditorZoomFactor";
+inline constexpr char ACTIONS_MERGE_TEMPLATE_ENABLED[] = "ActionsMergeTemplateEnabled";
+inline constexpr char DOWNLOADABLE_BUNDLES_URL[] = "DownloadableBundlesLocation";
+}
+
+class QMLDESIGNERBASE_EXPORT DesignerSettings
+{
+public:
+ DesignerSettings(QSettings *settings);
+
+ void insert(const QByteArray &key, const QVariant &value);
+ void insert(const QHash<QByteArray, QVariant> &settingsHash);
+ QVariant value(const QByteArray &key, const QVariant &defaultValue = {}) const;
+
+private:
+ void fromSettings(QSettings *);
+ void toSettings(QSettings *) const;
+
+ void restoreValue(QSettings *settings, const QByteArray &key,
+ const QVariant &defaultValue = QVariant());
+ void storeValue(QSettings *settings, const QByteArray &key, const QVariant &value) const;
+
+ QSettings *m_settings;
+ QHash<QByteArray, QVariant> m_cache;
+ mutable QMutex m_mutex;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.cpp b/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.cpp
new file mode 100644
index 0000000000..d73ea62ea9
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qmlpuppetpaths.h"
+
+#include "designersettings.h"
+
+#include <app/app_version.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/target.h>
+#include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
+
+namespace QmlDesigner {
+namespace QmlPuppetPaths {
+
+namespace {
+
+Utils::FilePath qmlPuppetExecutablePath(const Utils::FilePath &workingDirectory)
+{
+ return workingDirectory.pathAppended(QString{"qml2puppet-"} + Core::Constants::IDE_VERSION_LONG)
+ .withExecutableSuffix();
+}
+
+Utils::FilePath qmlPuppetFallbackDirectory(const DesignerSettings &settings)
+{
+ auto puppetFallbackDirectory = Utils::FilePath::fromString(
+ settings.value(DesignerSettingsKey::PUPPET_DEFAULT_DIRECTORY).toString());
+ if (puppetFallbackDirectory.isEmpty() || !puppetFallbackDirectory.exists())
+ return Core::ICore::libexecPath();
+ return puppetFallbackDirectory;
+}
+
+std::pair<Utils::FilePath, Utils::FilePath> qmlPuppetFallbackPaths(const DesignerSettings &settings)
+{
+ auto workingDirectory = qmlPuppetFallbackDirectory(settings);
+
+ return {workingDirectory, qmlPuppetExecutablePath(workingDirectory)};
+}
+
+std::pair<Utils::FilePath, Utils::FilePath> pathsForKitPuppet(ProjectExplorer::Target *target)
+{
+ if (!target || !target->kit())
+ return {};
+
+ QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
+
+ if (currentQtVersion) {
+ auto path = currentQtVersion->binPath();
+ return {path, qmlPuppetExecutablePath(path)};
+ }
+
+ return {};
+}
+} // namespace
+
+std::pair<Utils::FilePath, Utils::FilePath> qmlPuppetPaths(ProjectExplorer::Target *target,
+ const DesignerSettings &settings)
+{
+ auto [workingDirectoryPath, puppetPath] = pathsForKitPuppet(target);
+
+ if (workingDirectoryPath.isEmpty() || !puppetPath.exists())
+ return qmlPuppetFallbackPaths(settings);
+
+ return {workingDirectoryPath, puppetPath};
+}
+
+} // namespace QmlPuppetPaths
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.h b/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.h
new file mode 100644
index 0000000000..a9b3b0b890
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/qmlpuppetpaths.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmldesignerbase_global.h"
+
+#include <utils/filepath.h>
+
+namespace ProjectExplorer {
+class Target;
+}
+namespace QmlDesigner {
+class DesignerSettings;
+
+namespace QmlPuppetPaths {
+QMLDESIGNERBASE_EXPORT std::pair<Utils::FilePath, Utils::FilePath> qmlPuppetPaths(
+ ProjectExplorer::Target *target, const DesignerSettings &settings);
+}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/utils/studioquickwidget.cpp b/src/plugins/qmldesignerbase/utils/studioquickwidget.cpp
new file mode 100644
index 0000000000..2cfe5aa974
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/studioquickwidget.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "studioquickwidget.h"
+
+#include <QQuickItem>
+#include <QVBoxLayout>
+#include <QtQml/QQmlEngine>
+
+QQmlEngine *s_engine = nullptr;
+
+StudioQuickWidget::StudioQuickWidget(QWidget *parent)
+ : QWidget{parent}
+{
+ if (!s_engine)
+ s_engine = new QQmlEngine;
+
+ m_quickWidget = new QQuickWidget(s_engine, this);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(m_quickWidget);
+}
+
+QQmlEngine *StudioQuickWidget::engine() const
+{
+ return m_quickWidget->engine();
+}
+
+QQmlContext *StudioQuickWidget::rootContext() const
+{
+ return m_quickWidget->rootContext();
+}
+
+QQuickItem *StudioQuickWidget::rootObject() const
+{
+ return m_quickWidget->rootObject();
+}
+
+void StudioQuickWidget::setResizeMode(QQuickWidget::ResizeMode mode)
+{
+ m_quickWidget->setResizeMode(mode);
+}
+
+void StudioQuickWidget::setSource(const QUrl &url)
+{
+ m_quickWidget->setSource(url);
+}
+
+void StudioQuickWidget::refresh() {}
+
+void StudioQuickWidget::setClearColor(const QColor &color)
+{
+ m_quickWidget->setClearColor(color);
+}
+
+QList<QQmlError> StudioQuickWidget::errors() const
+{
+ return m_quickWidget->errors();
+}
+
+StudioPropertyMap *StudioQuickWidget::registerPropertyMap(const QByteArray &name)
+{
+ StudioPropertyMap *map = new StudioPropertyMap(this);
+ [[maybe_unused]] const int typeIndex = qmlRegisterSingletonType<StudioPropertyMap>(
+ name.data(), 1, 0, name.data(), [map](QQmlEngine *, QJSEngine *) { return map; });
+ return map;
+}
+
+QQuickWidget *StudioQuickWidget::quickWidget() const
+{
+ return m_quickWidget;
+}
+
+StudioPropertyMap::StudioPropertyMap(QObject *parent)
+ : QQmlPropertyMap(parent)
+{}
+
+void StudioPropertyMap::setProperties(const QList<PropertyPair> &properties)
+{
+ for (const PropertyPair &pair : properties)
+ insert(pair.name, pair.value);
+}
diff --git a/src/plugins/qmldesignerbase/utils/studioquickwidget.h b/src/plugins/qmldesignerbase/utils/studioquickwidget.h
new file mode 100644
index 0000000000..ef64fb6a69
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/studioquickwidget.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmldesignerbase_global.h"
+
+#include <QObject>
+#include <QQmlPropertyMap>
+#include <QtQuickWidgets/QQuickWidget>
+
+class QMLDESIGNERBASE_EXPORT StudioPropertyMap : public QQmlPropertyMap
+{
+public:
+ struct PropertyPair
+ {
+ QString name;
+ QVariant value;
+ };
+
+ explicit StudioPropertyMap(QObject *parent = 0);
+
+ void setProperties(const QList<PropertyPair> &properties);
+};
+
+class QMLDESIGNERBASE_EXPORT StudioQuickWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit StudioQuickWidget(QWidget *parent = nullptr);
+
+ QQmlEngine *engine() const;
+ QQmlContext *rootContext() const;
+
+ QQuickItem *rootObject() const;
+
+ void setResizeMode(QQuickWidget::ResizeMode mode);
+
+ void setSource(const QUrl &url);
+
+ void refresh();
+
+ void setClearColor(const QColor &color);
+
+ QList<QQmlError> errors() const;
+
+ StudioPropertyMap *registerPropertyMap(const QByteArray &name);
+ QQuickWidget *quickWidget() const;
+
+private:
+ QQuickWidget *m_quickWidget = nullptr;
+};
diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
index 98713d1a36..b29d1627db 100644
--- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
+++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp
@@ -246,13 +246,16 @@ void matchComponentFromObjectDefQuickFix(const QmlJSQuickFixAssistInterface *int
}
}
-void performComponentFromObjectDef(const QString &fileName, QmlJS::AST::UiObjectDefinition *objDef)
+void performComponentFromObjectDef(QmlJSEditorWidget *editor,
+ const QString &fileName,
+ QmlJS::AST::UiObjectDefinition *objDef)
{
QmlJSRefactoringChanges refactoring(QmlJS::ModelManagerInterface::instance(),
QmlJS::ModelManagerInterface::instance()->snapshot());
QmlJSRefactoringFilePtr current = refactoring.file(Utils::FilePath::fromString(fileName));
- Operation operation(nullptr, objDef);
+ QmlJSQuickFixAssistInterface interface(editor, TextEditor::AssistReason::ExplicitlyInvoked);
+ Operation operation(&interface, objDef);
operation.performChanges(current, refactoring);
}
diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
index 8ac708aed2..72a0f50e20 100644
--- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
+++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.h
@@ -8,10 +8,13 @@
namespace QmlJSEditor {
+class QmlJSEditorWidget;
+
QMLJSEDITOR_EXPORT void matchComponentFromObjectDefQuickFix(
const Internal::QmlJSQuickFixAssistInterface *interface, QuickFixOperations &result);
-QMLJSEDITOR_EXPORT void performComponentFromObjectDef
- (const QString &fileName, QmlJS::AST::UiObjectDefinition *objDef);
+QMLJSEDITOR_EXPORT void performComponentFromObjectDef(QmlJSEditorWidget *editor,
+ const QString &fileName,
+ QmlJS::AST::UiObjectDefinition *objDef);
} // namespace QmlJSEditor
diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt
index 7d3aa4c10d..4119bae734 100644
--- a/src/plugins/qmlprojectmanager/CMakeLists.txt
+++ b/src/plugins/qmlprojectmanager/CMakeLists.txt
@@ -1,8 +1,9 @@
add_qtc_plugin(QmlProjectManager
CONDITION TARGET Qt::QuickWidgets
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
PLUGIN_CLASS QmlProjectPlugin
DEPENDS QmlJS Qt::QuickWidgets
- PLUGIN_DEPENDS Core ProjectExplorer QtSupport
+ PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesignerBase
SOURCES
fileformat/filefilteritems.cpp fileformat/filefilteritems.h
fileformat/qmlprojectfileformat.cpp fileformat/qmlprojectfileformat.h
diff --git a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp
index e112431919..a9f35c2c5e 100644
--- a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp
+++ b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp
@@ -60,6 +60,16 @@ enum ProjectDirectoryError {
const QString MENU_ITEM_GENERATE = Tr::tr("Generate CMake Build Files...");
+const QmlBuildSystem *getBuildSystem()
+{
+ auto project = ProjectExplorer::ProjectManager::startupProject();
+ if (project && project->activeTarget() && project->activeTarget()->buildSystem()) {
+ return qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ project->activeTarget()->buildSystem());
+ }
+ return nullptr;
+}
+
void generateMenuEntry(QObject *parent)
{
Core::ActionContainer *menu = Core::ActionManager::actionContainer(Core::Constants::M_FILE);
@@ -83,9 +93,8 @@ void generateMenuEntry(QObject *parent)
QObject::connect(ProjectExplorer::ProjectManager::instance(),
&ProjectExplorer::ProjectManager::startupProjectChanged,
[action]() {
- auto qmlProject = qobject_cast<QmlProject *>(
- ProjectExplorer::ProjectManager::startupProject());
- action->setEnabled(qmlProject != nullptr);
+ if (auto buildSystem = getBuildSystem())
+ action->setEnabled(!buildSystem->qtForMCUs());
});
}
@@ -247,17 +256,15 @@ const QString projectEnvironmentVariable(const QString &key)
{
QString value = {};
- auto *target = ProjectExplorer::ProjectManager::startupProject()->activeTarget();
- if (target && target->buildSystem()) {
- auto buildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
- if (buildSystem) {
- auto envItems = buildSystem->environment();
- auto confEnv = std::find_if(envItems.begin(), envItems.end(),
- [key](NameValueItem &item){return item.name == key;});
- if (confEnv != envItems.end())
- value = confEnv->value;
- }
+ if (auto buildSystem = getBuildSystem()) {
+ auto envItems = buildSystem->environment();
+ auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](NameValueItem &item) {
+ return item.name == key;
+ });
+ if (confEnv != envItems.end())
+ value = confEnv->value;
}
+
return value;
}
@@ -532,7 +539,6 @@ bool CmakeFileGenerator::includeFile(const FilePath &filePath)
return !isFileBlacklisted(filePath.fileName());
}
-
bool CmakeFileGenerator::generateEntryPointFiles(const FilePath &dir)
{
const QString qtcontrolsConf = GenerateCmake::projectEnvironmentVariable(ENV_VARIABLE_CONTROLCONF);
@@ -571,22 +577,19 @@ bool CmakeFileGenerator::generateMainCpp(const FilePath &dir)
bool envHeaderOk = true;
QString environment;
- auto *target = ProjectExplorer::ProjectManager::startupProject()->activeTarget();
- if (target && target->buildSystem()) {
- auto buildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
- if (buildSystem) {
- for (EnvironmentItem &envItem : buildSystem->environment()) {
- QString key = envItem.name;
- QString value = envItem.value;
- if (isFileResource(value))
- value.prepend(":/");
- environment.append(QString(ENV_HEADER_VARIABLE_LINE).arg(key).arg(value));
- }
- QString envHeaderContent = GenerateCmake::readTemplate(ENV_HEADER_TEMPLATE_PATH)
- .arg(environment);
- FilePath envHeaderPath = srcDir.pathAppended(FILENAME_ENV_HEADER);
- envHeaderOk = m_fileQueue.queueFile(envHeaderPath, envHeaderContent);
+
+ if (auto buildSystem = getBuildSystem()) {
+ for (EnvironmentItem &envItem : buildSystem->environment()) {
+ QString key = envItem.name;
+ QString value = envItem.value;
+ if (isFileResource(value))
+ value.prepend(":/");
+ environment.append(QString(ENV_HEADER_VARIABLE_LINE).arg(key).arg(value));
}
+ QString envHeaderContent = GenerateCmake::readTemplate(ENV_HEADER_TEMPLATE_PATH)
+ .arg(environment);
+ FilePath envHeaderPath = srcDir.pathAppended(FILENAME_ENV_HEADER);
+ envHeaderOk = m_fileQueue.queueFile(envHeaderPath, envHeaderContent);
}
return cppOk && pluginHeaderOk && envHeaderOk;
@@ -609,6 +612,8 @@ bool CmakeFileGenerator::isFileResource(const QString &relativeFilePath)
return false;
}
+
+
} //GenerateCmake
} //QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qdslandingpage.cpp b/src/plugins/qmlprojectmanager/qdslandingpage.cpp
index 0e0c5a1c7d..19581d9660 100644
--- a/src/plugins/qmlprojectmanager/qdslandingpage.cpp
+++ b/src/plugins/qmlprojectmanager/qdslandingpage.cpp
@@ -23,6 +23,7 @@ namespace QmlProjectManager {
namespace Internal {
const char INSTALL_QDS_URL[] = "https://www.qt.io/product/ui-design-tools";
+const char OBJECT_NAME_LANDING_PAGE[] = "QQuickWidgetQDSLandingPage";
QdsLandingPageWidget::QdsLandingPageWidget(QWidget* parent)
: QWidget(parent)
@@ -50,6 +51,7 @@ QQuickWidget *QdsLandingPageWidget::widget()
QdsLandingPageTheme::setupTheme(m_widget->engine());
m_widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ m_widget->setObjectName(OBJECT_NAME_LANDING_PAGE);
m_widget->engine()->addImportPath(landingPath + "/imports");
m_widget->engine()->addImportPath(resourcePath);
m_widget->engine()->addImportPath("qrc:/studiofonts");
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index f08b9c4bda..aab0fcfe1c 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -10,6 +10,7 @@
#include "qmlprojectmanagertr.h"
#include "qmlprojectnodes.h"
+#include <coreplugin/coreconstants.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -17,6 +18,7 @@
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
+#include <coreplugin/modemanager.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/devicesupport/idevice.h>
@@ -75,15 +77,20 @@ static bool allowOnlySingleProject()
return !settings->value(qdsAllowMultipleProjects, false).toBool();
}
-Utils::FilePaths QmlProject::getUiQmlFilesForFolder(const Utils::FilePath &folder)
+Utils::FilePaths QmlProject::collectUiQmlFilesForFolder(const Utils::FilePath &folder) const
{
const Utils::FilePaths uiFiles = files([&](const ProjectExplorer::Node *node) {
return node->filePath().completeSuffix() == "ui.qml"
- && node->filePath().parentDir() == folder;
+ && node->filePath().parentDir() == folder;
});
return uiFiles;
}
+FilePaths QmlProject::collectQmlFiles() const
+{
+ return files([](const Node *node) { return node->filePath().suffix() == "qml"; });
+}
+
QmlProject::QmlProject(const Utils::FilePath &fileName)
: Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName)
{
@@ -125,10 +132,13 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
Utils::Id());
});
} else {
- Utils::FilePaths uiFiles = getUiQmlFilesForFolder(projectDirectory()
- / "content");
+ Utils::FilePaths uiFiles = collectUiQmlFilesForFolder(
+ projectDirectory().pathAppended("content"));
+ if (uiFiles.isEmpty())
+ uiFiles = collectUiQmlFilesForFolder(projectDirectory());
+
if (uiFiles.isEmpty())
- uiFiles = getUiQmlFilesForFolder(projectDirectory());
+ uiFiles = collectQmlFiles();
if (!uiFiles.isEmpty()) {
Utils::FilePath currentFile;
@@ -139,6 +149,8 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
QTimer::singleShot(1000, [uiFiles]() {
Core::EditorManager::openEditor(uiFiles.first(),
Utils::Id());
+ Core::ModeManager::activateMode(
+ Core::Constants::MODE_DESIGN);
});
}
}
@@ -346,12 +358,22 @@ FilePath QmlBuildSystem::mainUiFile() const
FilePath QmlBuildSystem::mainFilePath() const
{
- return projectDirectory().resolvePath(mainFile());
+ const auto mainFileString = mainFile();
+
+ if (mainFileString.isEmpty())
+ return {};
+
+ return projectDirectory().resolvePath(mainFileString);
}
FilePath QmlBuildSystem::mainUiFilePath() const
{
- return projectDirectory().resolvePath(mainUiFile());
+ const auto mainUiFileString = mainUiFile();
+
+ if (mainUiFileString.isEmpty())
+ return {};
+
+ return projectDirectory().resolvePath(mainUiFileString);
}
bool QmlBuildSystem::setMainFileInProjectFile(const FilePath &newMainFilePath)
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index e7387e030a..f00a4f2b36 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -150,7 +150,8 @@ protected:
private:
ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
- Utils::FilePaths getUiQmlFilesForFolder(const Utils::FilePath &folder);
+ Utils::FilePaths collectUiQmlFilesForFolder(const Utils::FilePath &folder) const;
+ Utils::FilePaths collectQmlFiles() const;
QMetaObject::Connection m_openFileConnection;
};
diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
index e0b1e6a9b1..584bf8773b 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp
@@ -24,6 +24,9 @@
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/target.h>
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
+#include <qmldesignerbase/utils/qmlpuppetpaths.h>
+
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtsupportconstants.h>
@@ -62,6 +65,7 @@ private:
QmlMainFileAspect *m_qmlMainFileAspect = nullptr;
QmlMultiLanguageAspect *m_multiLanguageAspect = nullptr;
SelectionAspect *m_qtversionAspect = nullptr;
+ mutable bool usePuppetAsQmlRuntime = false;
};
QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
@@ -80,6 +84,8 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id)
setCommandLineGetter([this, target] {
const FilePath qmlRuntime = qmlRuntimeFilePath();
CommandLine cmd(qmlRuntime);
+ if (usePuppetAsQmlRuntime)
+ cmd.addArg("--qml-runtime");
// arguments in .user file
cmd.addArgs(aspect<ArgumentsAspect>()->arguments(), CommandLine::Raw);
@@ -193,6 +199,7 @@ QString QmlProjectRunConfiguration::disabledReason() const
FilePath QmlProjectRunConfiguration::qmlRuntimeFilePath() const
{
+ usePuppetAsQmlRuntime = false;
// Give precedence to the manual override in the run configuration.
const FilePath qmlViewer = m_qmlViewerAspect->filePath();
if (!qmlViewer.isEmpty())
@@ -212,6 +219,14 @@ FilePath QmlProjectRunConfiguration::qmlRuntimeFilePath() const
// i.e. not necessarily something the device can use, but the
// device had its chance above.
if (QtVersion *version = QtKitAspect::qtVersion(kit)) {
+ if (version->qtVersion().majorVersion() > 5) {
+ auto [workingDirectoryPath, puppetPath] = QmlDesigner::QmlPuppetPaths::qmlPuppetPaths(
+ target(), QmlDesigner::QmlDesignerBasePlugin::settings());
+ if (!puppetPath.isEmpty()) {
+ usePuppetAsQmlRuntime = true;
+ return puppetPath;
+ }
+ }
const FilePath qmlRuntime = version->qmlRuntimeFilePath();
if (!qmlRuntime.isEmpty())
return qmlRuntime;
diff --git a/src/plugins/qnx/qnxqtversion.cpp b/src/plugins/qnx/qnxqtversion.cpp
index b5dd0518d8..a13f96148b 100644
--- a/src/plugins/qnx/qnxqtversion.cpp
+++ b/src/plugins/qnx/qnxqtversion.cpp
@@ -116,7 +116,7 @@ QVariantMap QnxQtVersion::toMap() const
return result;
}
-void QnxQtVersion::fromMap(const QVariantMap &map)
+void QnxQtVersion::fromMap(const QVariantMap &map, const Utils::FilePath &)
{
QtVersion::fromMap(map);
setSdpPath(FilePath::fromSettings(map.value(SDP_PATH_KEY)));
diff --git a/src/plugins/qnx/qnxqtversion.h b/src/plugins/qnx/qnxqtversion.h
index d881697a16..bcea9b3be3 100644
--- a/src/plugins/qnx/qnxqtversion.h
+++ b/src/plugins/qnx/qnxqtversion.h
@@ -28,7 +28,7 @@ public:
QString cpuDir() const;
QVariantMap toMap() const override;
- void fromMap(const QVariantMap &map) override;
+ void fromMap(const QVariantMap &map, const Utils::FilePath &filePath) override;
ProjectExplorer::Abis detectQtAbis() const override;
diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp
index 446f7d576a..2012fb7470 100644
--- a/src/plugins/qtsupport/baseqtversion.cpp
+++ b/src/plugins/qtsupport/baseqtversion.cpp
@@ -640,7 +640,7 @@ bool QtVersion::hasReleaseBuild() const
return !d->m_defaultConfigIsDebug || d->m_defaultConfigIsDebugAndRelease;
}
-void QtVersion::fromMap(const QVariantMap &map)
+void QtVersion::fromMap(const QVariantMap &map, const FilePath &filePath)
{
d->m_id = map.value(Constants::QTVERSIONID).toInt();
if (d->m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id
@@ -665,6 +665,7 @@ void QtVersion::fromMap(const QVariantMap &map)
d->m_qmakeCommand = BuildableHelperLibrary::qtChooserToQmakePath(qmake);
}
}
+ d->m_qmakeCommand = filePath.resolvePath(d->m_qmakeCommand);
d->m_data.qtSources = FilePath::fromSettings(map.value(QTVERSIONSOURCEPATH));
@@ -2309,12 +2310,12 @@ bool QtVersionFactory::canRestore(const QString &type)
return type == m_supportedType;
}
-QtVersion *QtVersionFactory::restore(const QString &type, const QVariantMap &data)
+QtVersion *QtVersionFactory::restore(const QString &type, const QVariantMap &data, const FilePath &filePath)
{
QTC_ASSERT(canRestore(type), return nullptr);
QTC_ASSERT(m_creator, return nullptr);
QtVersion *version = create();
- version->fromMap(data);
+ version->fromMap(data, filePath);
return version;
}
diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h
index 2c52b80357..b590d15c28 100644
--- a/src/plugins/qtsupport/baseqtversion.h
+++ b/src/plugins/qtsupport/baseqtversion.h
@@ -49,7 +49,7 @@ public:
virtual ~QtVersion();
- virtual void fromMap(const QVariantMap &map);
+ virtual void fromMap(const QVariantMap &map, const Utils::FilePath &filePath = {});
virtual bool equals(QtVersion *other);
bool isAutodetected() const;
diff --git a/src/plugins/qtsupport/qtversionfactory.h b/src/plugins/qtsupport/qtversionfactory.h
index bce5f1b4cf..1f29cf0394 100644
--- a/src/plugins/qtsupport/qtversionfactory.h
+++ b/src/plugins/qtsupport/qtversionfactory.h
@@ -22,7 +22,7 @@ public:
static const QList<QtVersionFactory *> allQtVersionFactories();
bool canRestore(const QString &type);
- QtVersion *restore(const QString &type, const QVariantMap &data);
+ QtVersion *restore(const QString &type, const QVariantMap &data, const Utils::FilePath &workingDirectory);
/// factories with higher priority are asked first to identify
/// a qtversion, the priority of the desktop factory is 0 and
diff --git a/src/plugins/qtsupport/qtversionmanager.cpp b/src/plugins/qtsupport/qtversionmanager.cpp
index bdf00c87d5..c5a0f7b315 100644
--- a/src/plugins/qtsupport/qtversionmanager.cpp
+++ b/src/plugins/qtsupport/qtversionmanager.cpp
@@ -194,7 +194,7 @@ static bool restoreQtVersions()
bool restored = false;
for (QtVersionFactory *f : factories) {
if (f->canRestore(type)) {
- if (QtVersion *qtv = f->restore(type, qtversionMap)) {
+ if (QtVersion *qtv = f->restore(type, qtversionMap, reader.filePath())) {
if (m_versions.contains(qtv->uniqueId())) {
// This shouldn't happen, we are restoring the same id multiple times?
qWarning() << "A Qt version with id"<<qtv->uniqueId()<<"already exists";
@@ -288,7 +288,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal)
qtversionMap[Constants::QTVERSIONNAME] = v->unexpandedDisplayName();
delete v;
- if (QtVersion *qtv = factory->restore(type, qtversionMap)) {
+ if (QtVersion *qtv = factory->restore(type, qtversionMap, reader.filePath())) {
Q_ASSERT(qtv->isAutodetected());
m_versions.insert(id, qtv);
restored = true;
@@ -302,7 +302,7 @@ void QtVersionManager::updateFromInstaller(bool emitSignal)
// Create a new qtversion
if (!restored) { // didn't replace any existing versions
qCDebug(log) << " No Qt version found matching" << autoDetectionSource << " => Creating new version";
- if (QtVersion *qtv = factory->restore(type, qtversionMap)) {
+ if (QtVersion *qtv = factory->restore(type, qtversionMap, reader.filePath())) {
Q_ASSERT(qtv->isAutodetected());
m_versions.insert(qtv->uniqueId(), qtv);
added << qtv->uniqueId();
diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp
index ad9aab9a9c..a0e5d07bab 100644
--- a/src/plugins/studiowelcome/examplecheckout.cpp
+++ b/src/plugins/studiowelcome/examplecheckout.cpp
@@ -7,6 +7,8 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
+
#include <utils/archive.h>
#include <utils/algorithm.h>
#include <utils/networkaccessmanager.h>
@@ -20,6 +22,7 @@
#include <projectexplorer/projectexplorer.h>
#include <qmldesigner/qmldesignerplugin.h>
+#include <qmldesigner/utils/fileextractor.h>
#include <QDialog>
#include <QFileDialog>
@@ -34,218 +37,57 @@
using namespace Utils;
-static bool enableDownload()
-{
- const QString lastQDSVersionEntry = "QML/Designer/EnableWelcomePageDownload";
- return Core::ICore::settings()->value(lastQDSVersionEntry, false).toBool();
-}
-
void ExampleCheckout::registerTypes()
{
static bool once = []() {
- FileDownloader::registerQmlType();
- FileExtractor::registerQmlType();
+ qmlRegisterType<QmlDesigner::FileDownloader>("ExampleCheckout", 1, 0, "FileDownloader");
+ qmlRegisterType<QmlDesigner::FileExtractor>("ExampleCheckout", 1, 0, "FileExtractor");
return true;
}();
QTC_ASSERT(once, ;);
}
-void FileDownloader::registerQmlType()
-{
- qmlRegisterType<FileDownloader>("ExampleCheckout", 1, 0, "FileDownloader");
-}
-
-FileDownloader::FileDownloader(QObject *parent)
- : QObject(parent)
-{}
-
-FileDownloader::~FileDownloader()
-{
- if (m_tempFile.exists())
- m_tempFile.remove();
-}
-
-void FileDownloader::start()
-{
- QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleDownload:" + name());
- m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip");
- m_tempFile.open(QIODevice::WriteOnly);
-
- auto request = QNetworkRequest(m_url);
- request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
- QNetworkRequest::UserVerifiedRedirectPolicy);
- m_reply = Utils::NetworkAccessManager::instance()->get(request);
-
- QNetworkReply::connect(m_reply, &QNetworkReply::readyRead, this, [this]() {
- m_tempFile.write(m_reply->readAll());
- });
-
- QNetworkReply::connect(m_reply,
- &QNetworkReply::downloadProgress,
- this,
- [this](qint64 current, qint64 max) {
- if (max == 0)
- return;
-
- m_progress = current * 100 / max;
- emit progressChanged();
- });
-
- QNetworkReply::connect(m_reply, &QNetworkReply::redirected, [this](const QUrl &) {
- emit m_reply->redirectAllowed();
- });
-
- QNetworkReply::connect(m_reply, &QNetworkReply::finished, this, [this]() {
- if (m_reply->error()) {
- if (m_tempFile.exists())
- m_tempFile.remove();
-
- if (m_reply->error() != QNetworkReply::OperationCanceledError) {
- qWarning() << Q_FUNC_INFO << m_url << m_reply->errorString();
- emit downloadFailed();
- } else {
- emit downloadCanceled();
- }
- } else {
- m_tempFile.flush();
- m_tempFile.close();
- m_finished = true;
- emit tempFileChanged();
- emit finishedChanged();
- }
-
- m_reply = nullptr;
- });
-}
-
-void FileDownloader::cancel()
-{
- if (m_reply)
- m_reply->abort();
-}
-
-void FileDownloader::setUrl(const QUrl &url)
-{
- m_url = url;
- emit nameChanged();
-
- probeUrl();
-}
-
-QUrl FileDownloader::url() const
-{
- return m_url;
-}
-
-bool FileDownloader::finished() const
-{
- return m_finished;
-}
-
-bool FileDownloader::error() const
-{
- return m_error;
-}
-
-QString FileDownloader::name() const
-{
- const QFileInfo fileInfo(m_url.path());
- return fileInfo.baseName();
-}
-
-QString FileDownloader::completeBaseName() const
+void DataModelDownloader::usageStatisticsDownloadExample(const QString &name)
{
- const QFileInfo fileInfo(m_url.path());
- return fileInfo.completeBaseName();
+ QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleDownload:" + name);
}
-int FileDownloader::progress() const
+bool DataModelDownloader::downloadEnabled() const
{
- return m_progress;
-}
-
-QString FileDownloader::tempFile() const
-{
- return QFileInfo(m_tempFile).canonicalFilePath();
-}
-
-QDateTime FileDownloader::lastModified() const
-{
- return m_lastModified;
+ const QString lastQDSVersionEntry = "QML/Designer/EnableWelcomePageDownload";
+ return Core::ICore::settings()->value(lastQDSVersionEntry, false).toBool();
}
-bool FileDownloader::available() const
+QString DataModelDownloader::targetPath() const
{
- return m_available;
+ return QmlDesigner::QmlDesignerBasePlugin::examplesPathSetting();
}
-void FileDownloader::probeUrl()
+static Utils::FilePath tempFilePath()
{
- if (!enableDownload()) {
- m_available = false;
- emit availableChanged();
- return;
- }
-
- auto request = QNetworkRequest(m_url);
- request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
- QNetworkRequest::UserVerifiedRedirectPolicy);
- QNetworkReply *reply = Utils::NetworkAccessManager::instance()->head(request);
-
- QNetworkReply::connect(reply, &QNetworkReply::redirected, [reply](const QUrl &) {
- emit reply->redirectAllowed();
- });
-
- QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() {
- if (reply->error())
- return;
-
- m_lastModified = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime();
- emit lastModifiedChanged();
-
- m_available = true;
- emit availableChanged();
- });
+ QStandardPaths::StandardLocation location = QStandardPaths::CacheLocation;
- QNetworkReply::connect(reply,
- &QNetworkReply::errorOccurred,
- this,
- [this](QNetworkReply::NetworkError) {
- QQmlData *data = QQmlData::get(this, false);
- if (!data) {
- qDebug() << Q_FUNC_INFO << "FileDownloader is nullptr.";
- return;
- }
-
- if (QQmlData::wasDeleted(this)) {
- qDebug() << Q_FUNC_INFO << "FileDownloader was deleted.";
- return;
- }
-
- m_available = false;
- emit availableChanged();
- });
+ return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
+ .pathAppended("QtDesignStudio");
}
-
-FileExtractor::FileExtractor(QObject *parent)
- : QObject(parent)
+DataModelDownloader::DataModelDownloader(QObject * /* parent */)
{
- m_targetPath = Utils::FilePath::fromString(
- StudioWelcome::Internal::StudioWelcomePlugin::examplesPathSetting());
-
- m_timer.setInterval(100);
- m_timer.setSingleShot(false);
+ auto fileInfo = targetFolder().toFileInfo();
+ m_birthTime = fileInfo.lastModified();
+ m_exists = fileInfo.exists();
+ m_fileDownloader.setProbeUrl(true);
- QObject::connect(this, &FileExtractor::targetFolderExistsChanged, this, [this]() {
- if (targetFolderExists()) {
- m_birthTime = QFileInfo(m_targetPath.toString() + "/" + m_archiveName).birthTime();
- } else
- m_birthTime = QDateTime();
+ connect(&m_fileDownloader,
+ &QmlDesigner::FileDownloader::progressChanged,
+ this,
+ &DataModelDownloader::progressChanged);
- emit birthTimeChanged();
- });
+ connect(&m_fileDownloader,
+ &QmlDesigner::FileDownloader::downloadFailed,
+ this,
+ &DataModelDownloader::downloadFailed);
const ExtensionSystem::PluginSpec *pluginSpec
= Utils::findOrDefault(ExtensionSystem::PluginManager::plugins(),
@@ -263,244 +105,66 @@ FileExtractor::FileExtractor(QObject *parent)
auto studioWelcomePlugin = qobject_cast<StudioWelcome::Internal::StudioWelcomePlugin *>(plugin);
if (studioWelcomePlugin) {
- QObject::connect(studioWelcomePlugin,
- &StudioWelcome::Internal::StudioWelcomePlugin::examplesDownloadPathChanged,
+ QObject::connect(QmlDesigner::QmlDesignerBasePlugin::instance(),
+ &QmlDesigner::QmlDesignerBasePlugin::examplesDownloadPathChanged,
this,
- [this](const QString &path) {
- m_targetPath = Utils::FilePath::fromString(path);
- emit targetPathChanged();
- emit targetFolderExistsChanged();
- });
+ &DataModelDownloader::targetPathMustChange);
}
-}
-
-FileExtractor::~FileExtractor() {}
-
-void FileExtractor::registerQmlType()
-{
- qmlRegisterType<FileExtractor>("ExampleCheckout", 1, 0, "FileExtractor");
-}
-
-QString FileExtractor::targetPath() const
-{
- return m_targetPath.toUserOutput();
-}
-
-void FileExtractor::browse()
-{
- const FilePath path =
- FileUtils::getExistingDirectory(nullptr, tr("Choose Directory"), m_targetPath);
-
- if (!path.isEmpty())
- m_targetPath = path;
-
- emit targetPathChanged();
- emit targetFolderExistsChanged();
-}
-
-void FileExtractor::setSourceFile(QString &sourceFilePath)
-{
- m_sourceFile = Utils::FilePath::fromString(sourceFilePath);
- emit targetFolderExistsChanged();
-}
-
-void FileExtractor::setArchiveName(QString &filePath)
-{
- m_archiveName = filePath;
- emit targetFolderExistsChanged();
-}
-
-const QString FileExtractor::detailedText()
-{
- return m_detailedText;
-}
-
-bool FileExtractor::finished() const
-{
- return m_finished;
-}
-QString FileExtractor::currentFile() const
-{
- return m_currentFile;
-}
-
-QString FileExtractor::size() const
-{
- return m_size;
-}
-
-QString FileExtractor::count() const
-{
- return m_count;
-}
-
-bool FileExtractor::targetFolderExists() const
-{
- return QFileInfo::exists(m_targetPath.toString() + "/" + m_archiveName);
-}
-
-int FileExtractor::progress() const
-{
- return m_progress;
-}
-
-QDateTime FileExtractor::birthTime() const
-{
- return m_birthTime;
-}
-
-QString FileExtractor::archiveName() const
-{
- return m_archiveName;
-}
-
-QString FileExtractor::sourceFile() const
-{
- return m_sourceFile.toString();
-}
-
-void FileExtractor::extract()
-{
- const QString targetFolder = m_targetPath.toString() + "/" + m_archiveName;
-
- // If the target directory already exists, remove it and its content
- QDir targetDir(targetFolder);
- if (targetDir.exists())
- targetDir.removeRecursively();
-
- // Create a new directory to generate a proper creation date
- targetDir.mkdir(targetFolder);
-
- Utils::Archive *archive = new Utils::Archive(m_sourceFile, m_targetPath);
- QTC_ASSERT(archive->isValid(), delete archive; return);
-
- m_timer.start();
- qint64 bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
- qint64 compressedSize = QFileInfo(m_sourceFile.toString()).size();
-
- QTimer::connect(
- &m_timer, &QTimer::timeout, this, [this, bytesBefore, targetFolder, compressedSize]() {
- static QHash<QString, int> hash;
- QDirIterator it(targetFolder, {"*.*"}, QDir::Files, QDirIterator::Subdirectories);
-
- int count = 0;
- while (it.hasNext()) {
- if (!hash.contains(it.fileName())) {
- m_currentFile = it.fileName();
- hash.insert(m_currentFile, 0);
- emit currentFileChanged();
- }
- it.next();
- count++;
- }
-
- qint64 currentSize = bytesBefore
- - QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
-
- // We can not get the uncompressed size of the archive yet, that is why we use an
- // approximation. We assume a 50% compression rate.
- m_progress = std::min(100ll, currentSize * 100 / compressedSize * 2);
- emit progressChanged();
-
- m_size = QString::number(currentSize);
- m_count = QString::number(count);
- emit sizeChanged();
- });
-
- QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) {
- m_detailedText += output;
- emit detailedTextChanged();
- });
-
- QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
- archive->deleteLater();
- m_finished = ret;
- m_timer.stop();
-
- m_progress = 100;
- emit progressChanged();
-
- emit targetFolderExistsChanged();
- emit finishedChanged();
- QTC_CHECK(ret);
+ connect(&m_fileDownloader, &QmlDesigner::FileDownloader::finishedChanged, this, [this]() {
+ m_started = false;
+
+ if (m_fileDownloader.finished()) {
+ const Utils::FilePath archiveFile = Utils::FilePath::fromString(
+ m_fileDownloader.outputFile());
+ QTC_ASSERT(Utils::Archive::supportsFile(archiveFile), return );
+ auto archive = new Utils::Archive(archiveFile, tempFilePath());
+ QTC_ASSERT(archive->isValid(), delete archive; return );
+ QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
+ QTC_CHECK(ret);
+ archive->deleteLater();
+ emit finished();
+ });
+ archive->unarchive();
+ }
});
- archive->unarchive();
}
-static Utils::FilePath tempFilePath()
+void DataModelDownloader::onAvailableChanged()
{
- QStandardPaths::StandardLocation location = QStandardPaths::CacheLocation;
+ m_available = m_fileDownloader.available();
- return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
- .pathAppended("QtDesignStudio");
-}
+ emit availableChanged();
-DataModelDownloader::DataModelDownloader(QObject * /* parent */)
-{
- auto fileInfo = targetFolder().toFileInfo();
- m_birthTime = fileInfo.lastModified();
- m_exists = fileInfo.exists();
+ if (!m_available) {
+ qWarning() << m_fileDownloader.url() << "failed to download";
+ return;
+ }
- connect(&m_fileDownloader,
- &FileDownloader::progressChanged,
- this,
- &DataModelDownloader::progressChanged);
+ if (!m_forceDownload && (m_fileDownloader.lastModified() <= m_birthTime))
+ return;
- connect(&m_fileDownloader,
- &FileDownloader::downloadFailed,
- this,
- &DataModelDownloader::downloadFailed);
+ m_started = true;
+
+ m_fileDownloader.start();
}
bool DataModelDownloader::start()
{
-
- if (!enableDownload()) {
+ if (!downloadEnabled()) {
m_available = false;
emit availableChanged();
return false;
}
+ m_fileDownloader.setDownloadEnabled(true);
m_fileDownloader.setUrl(QUrl::fromUserInput(
"https://download.qt.io/learning/examples/qtdesignstudio/dataImports.zip"));
- bool started = false;
-
- connect(&m_fileDownloader, &FileDownloader::availableChanged, this, [this, &started]() {
-
- m_available = m_fileDownloader.available();
+ m_started = false;
- emit availableChanged();
-
- if (!m_available) {
- qWarning() << m_fileDownloader.url() << "failed to download";
- return;
- }
-
- if (!m_forceDownload && (m_fileDownloader.lastModified() <= m_birthTime))
- return;
-
- started = true;
-
- m_fileDownloader.start();
- connect(&m_fileDownloader, &FileDownloader::finishedChanged, this, [this]() {
- if (m_fileDownloader.finished()) {
- const Utils::FilePath archiveFile = Utils::FilePath::fromString(
- m_fileDownloader.tempFile());
- QTC_ASSERT(Utils::Archive::supportsFile(archiveFile), return );
- auto archive = new Utils::Archive(archiveFile, tempFilePath());
- QTC_ASSERT(archive->isValid(), delete archive; return );
- QObject::connect(archive, &Utils::Archive::finished, this, [this, archive](bool ret) {
- QTC_CHECK(ret);
- archive->deleteLater();
- emit finished();
- });
- archive->unarchive();
- }
- });
- });
- return started;
+ connect(&m_fileDownloader, &QmlDesigner::FileDownloader::availableChanged, this, &DataModelDownloader::onAvailableChanged);
+ return m_started;
}
bool DataModelDownloader::exists() const
diff --git a/src/plugins/studiowelcome/examplecheckout.h b/src/plugins/studiowelcome/examplecheckout.h
index 7e22daf002..4726796bfe 100644
--- a/src/plugins/studiowelcome/examplecheckout.h
+++ b/src/plugins/studiowelcome/examplecheckout.h
@@ -4,6 +4,7 @@
#pragma once
#include <utils/fileutils.h>
+#include <qmldesigner/utils/filedownloader.h>
#include <QObject>
#include <QTimer>
@@ -16,135 +17,15 @@ struct ExampleCheckout
static void registerTypes();
};
-class FileExtractor : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QString targetPath READ targetPath NOTIFY targetPathChanged)
- Q_PROPERTY(QString archiveName READ archiveName WRITE setArchiveName)
- Q_PROPERTY(QString detailedText READ detailedText NOTIFY detailedTextChanged)
- Q_PROPERTY(QString currentFile READ currentFile NOTIFY currentFileChanged)
- Q_PROPERTY(QString size READ size NOTIFY sizeChanged)
- Q_PROPERTY(QString count READ count NOTIFY sizeChanged)
- Q_PROPERTY(QString sourceFile READ sourceFile WRITE setSourceFile)
- Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
- Q_PROPERTY(bool targetFolderExists READ targetFolderExists NOTIFY targetFolderExistsChanged)
- Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
- Q_PROPERTY(QDateTime birthTime READ birthTime NOTIFY birthTimeChanged)
-
-public:
- explicit FileExtractor(QObject *parent = nullptr);
- ~FileExtractor();
-
- static void registerQmlType();
-
- QString targetPath() const;
- void setSourceFile(QString &sourceFilePath);
- void setArchiveName(QString &filePath);
- const QString detailedText();
- bool finished() const;
- QString currentFile() const;
- QString size() const;
- QString count() const;
- bool targetFolderExists() const;
- int progress() const;
- QDateTime birthTime() const;
-
- QString sourceFile() const;
- QString archiveName() const;
-
- Q_INVOKABLE void browse();
- Q_INVOKABLE void extract();
-
-signals:
- void targetPathChanged();
- void detailedTextChanged();
- void finishedChanged();
- void currentFileChanged();
- void sizeChanged();
- void targetFolderExistsChanged();
- void progressChanged();
- void birthTimeChanged();
-
-private:
- Utils::FilePath m_targetPath;
- Utils::FilePath m_sourceFile;
- QString m_detailedText;
- bool m_finished = false;
- QTimer m_timer;
- QString m_currentFile;
- QString m_size;
- QString m_count;
- QString m_archiveName;
- int m_progress = 0;
- QDateTime m_birthTime;
-};
-
-class FileDownloader : public QObject
-{
- Q_OBJECT
-
- Q_PROPERTY(QUrl url READ url WRITE setUrl)
- Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)
- Q_PROPERTY(bool error READ error NOTIFY errorChanged)
- Q_PROPERTY(QString name READ name NOTIFY nameChanged)
- Q_PROPERTY(QString completeBaseName READ completeBaseName NOTIFY nameChanged)
- Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
- Q_PROPERTY(QString tempFile READ tempFile NOTIFY tempFileChanged)
- Q_PROPERTY(QDateTime lastModified READ lastModified NOTIFY lastModifiedChanged)
- Q_PROPERTY(bool available READ available NOTIFY availableChanged)
-
-public:
- explicit FileDownloader(QObject *parent = nullptr);
-
- ~FileDownloader();
-
- void setUrl(const QUrl &url);
- QUrl url() const;
- bool finished() const;
- bool error() const;
- static void registerQmlType();
- QString name() const;
- QString completeBaseName() const;
- int progress() const;
- QString tempFile() const;
- QDateTime lastModified() const;
- bool available() const;
-
- Q_INVOKABLE void start();
- Q_INVOKABLE void cancel();
-
-signals:
- void finishedChanged();
- void errorChanged();
- void nameChanged();
- void progressChanged();
- void tempFileChanged();
- void downloadFailed();
- void lastModifiedChanged();
- void availableChanged();
-
- void downloadCanceled();
-
-private:
- void probeUrl();
-
- QUrl m_url;
- bool m_finished = false;
- bool m_error = false;
- int m_progress = 0;
- QFile m_tempFile;
- QDateTime m_lastModified;
- bool m_available = false;
-
- QNetworkReply *m_reply = nullptr;
-};
-
class DataModelDownloader : public QObject
{
Q_OBJECT
public:
+ Q_INVOKABLE void usageStatisticsDownloadExample(const QString &name);
+ Q_INVOKABLE bool downloadEnabled() const;
+ Q_INVOKABLE QString targetPath() const;
+
explicit DataModelDownloader(QObject *parent = nullptr);
bool start();
bool exists() const;
@@ -158,11 +39,14 @@ signals:
void availableChanged();
void progressChanged();
void downloadFailed();
+ void targetPathMustChange(const QString &newPath);
private:
- FileDownloader m_fileDownloader;
+ void onAvailableChanged();
+ QmlDesigner::FileDownloader m_fileDownloader;
QDateTime m_birthTime;
bool m_exists = false;
bool m_available = false;
bool m_forceDownload = false;
+ bool m_started = false;
};
diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp
index d53a86aaa6..455267e901 100644
--- a/src/plugins/studiowelcome/qdsnewdialog.cpp
+++ b/src/plugins/studiowelcome/qdsnewdialog.cpp
@@ -11,6 +11,7 @@
#include <utils/qtcassert.h>
#include <qmldesigner/components/componentcore/theme.h>
+#include <qmldesigner/qmldesignerconstants.h>
#include "createproject.h"
#include "newprojectdialogimageprovider.h"
@@ -61,6 +62,7 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
m_recentsStore.setReverseOrder();
m_recentsStore.setMaximum(10);
+ m_dialog->setObjectName(QmlDesigner::Constants::OBJECT_NAME_NEW_DIALOG);
m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
new Internal::NewProjectDialogImageProvider());
@@ -390,7 +392,7 @@ void QdsNewDialog::accept()
create.withName(m_qmlProjectName)
.atLocation(m_qmlProjectLocation)
.withScreenSizes(m_qmlScreenSizeIndex, m_qmlCustomWidth, m_qmlCustomHeight)
- .withStyle(m_qmlStyleIndex)
+ .withStyle(getStyleIndex())
.useQtVirtualKeyboard(m_qmlUseVirtualKeyboard)
.saveAsDefaultLocation(m_qmlSaveAsDefaultLocation)
.withTargetQtVersion(m_qmlTargetQtVersionIndex)
@@ -450,7 +452,7 @@ UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) c
targetQtVersion = m_wizard.targetQtVersionName(m_qmlTargetQtVersionIndex);
if (m_wizard.haveStyleModel())
- styleName = m_wizard.styleName(m_qmlStyleIndex);
+ styleName = m_wizard.styleName(getStyleIndex());
if (m_wizard.haveVirtualKeyboard())
useVirtualKeyboard = m_qmlUseVirtualKeyboard;
diff --git a/src/plugins/studiowelcome/qml/downloaddialog/main.qml b/src/plugins/studiowelcome/qml/downloaddialog/main.qml
index 7f41fee148..5ed8e36f60 100644
--- a/src/plugins/studiowelcome/qml/downloaddialog/main.qml
+++ b/src/plugins/studiowelcome/qml/downloaddialog/main.qml
@@ -40,7 +40,7 @@ Rectangle {
FileExtractor {
id: fileExtractor
archiveName: root.completeBaseName.length === 0 ? downloader.completeBaseName : root.completeBaseName
- sourceFile: root.tempFile.length === 0 ? downloader.tempFile : root.tempFile
+ sourceFile: root.tempFile.length === 0 ? downloader.outputFile : root.tempFile
}
FileDownloader {
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
index 17acc9b651..ba58c0bd74 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
@@ -10,14 +10,18 @@
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/restartdialog.h>
-#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/documentmanager.h>
+#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/helpmanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/imode.h>
#include <coreplugin/modemanager.h>
+#include "projectexplorer/target.h"
+#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/jsonwizard/jsonwizardfactory.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
@@ -25,10 +29,16 @@
#include <qmlprojectmanager/projectfilecontenttools.h>
#include <qmlprojectmanager/qmlproject.h>
+#include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
+
#include <qmldesigner/components/componentcore/theme.h>
#include <qmldesigner/dynamiclicensecheck.h>
+#include <qmldesigner/qmldesignerconstants.h>
#include <qmldesigner/qmldesignerplugin.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
+
#include <utils/checkablemessagebox.h>
#include <utils/hostosinfo.h>
#include <utils/icon.h>
@@ -38,14 +48,11 @@
#include <QAbstractListModel>
#include <QApplication>
-#include <QCheckBox>
#include <QDesktopServices>
#include <QFileInfo>
#include <QFontDatabase>
-#include <QGroupBox>
#include <QMainWindow>
#include <QPointer>
-#include <QPushButton>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
@@ -90,12 +97,35 @@ const char STATISTICS_COLLECTION_MODE[] = "StatisticsCollectionMode";
const char NO_TELEMETRY[] = "NoTelemetry";
const char CRASH_REPORTER_SETTING[] = "CrashReportingEnabled";
-const char EXAMPLES_DOWNLOAD_PATH[] = "StudioWelcome/ExamplesDownloadPath";
-
QPointer<QQuickView> s_viewWindow = nullptr;
QPointer<QQuickWidget> s_viewWidget = nullptr;
static StudioWelcomePlugin *s_pluginInstance = nullptr;
+static Utils::FilePath getMainUiFileWithFallback()
+{
+ auto project = ProjectExplorer::ProjectManager::startupProject();
+ if (!project)
+ return {};
+
+ if (!project->activeTarget())
+ return {};
+
+ auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ project->activeTarget()->buildSystem());
+
+ auto mainUiFile = qmlBuildSystem->mainUiFilePath();
+ if (mainUiFile.exists())
+ return mainUiFile;
+
+ const Utils::FilePaths uiFiles = project->files([&](const ProjectExplorer::Node *node) {
+ return node->filePath().completeSuffix() == "ui.qml";
+ });
+ if (!uiFiles.isEmpty())
+ return uiFiles.first();
+
+ return {};
+}
+
std::unique_ptr<QSettings> makeUserFeedbackSettings()
{
QStringList domain = QCoreApplication::organizationDomain().split(QLatin1Char('.'));
@@ -223,8 +253,15 @@ public:
m_blockOpenRecent = true;
const FilePath projectFile = FilePath::fromVariant(data(index(row, 0), ProjectModel::FilePathRole));
- if (projectFile.exists())
- ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile);
+ if (projectFile.exists()) {
+ const ProjectExplorerPlugin::OpenProjectResult result
+ = ProjectExplorer::ProjectExplorerPlugin::openProject(projectFile);
+ if (!result && !result.alreadyOpen().isEmpty()) {
+ const auto mainUiFile = getMainUiFileWithFallback();
+ if (mainUiFile.exists())
+ Core::EditorManager::openEditor(mainUiFile, Utils::Id());
+ };
+ }
resetProjects();
}
@@ -241,6 +278,7 @@ public:
const QString &formFile,
const QString &explicitQmlproject)
{
+ QTC_ASSERT(!exampleName.isEmpty(), return );
QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleOpened:"
+ exampleName);
@@ -525,6 +563,7 @@ void StudioWelcomePlugin::extensionsInitialized()
if (showSplashScreen()) {
connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] {
+ Core::ModeManager::setModeStyle(Core::ModeManager::Style::Hidden);
if (Utils::HostOsInfo::isMacHost()) {
s_viewWindow = new QQuickView(Core::ICore::mainWindow()->windowHandle());
@@ -563,11 +602,13 @@ void StudioWelcomePlugin::extensionsInitialized()
s_viewWindow->show();
s_viewWindow->requestActivate();
+ s_viewWindow->setObjectName(QmlDesigner::Constants::OBJECT_NAME_SPLASH_SCREEN);
} else {
s_viewWidget = new QQuickWidget(Core::ICore::dialogParent());
s_viewWidget->setWindowFlag(Qt::SplashScreen, true);
+ s_viewWidget->setObjectName(QmlDesigner::Constants::OBJECT_NAME_SPLASH_SCREEN);
s_viewWidget->setWindowModality(Qt::ApplicationModal);
s_viewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
s_viewWidget->engine()->addImportPath("qrc:/studiofonts");
@@ -601,24 +642,36 @@ void StudioWelcomePlugin::extensionsInitialized()
bool StudioWelcomePlugin::delayedInitialize()
{
- return true;
-}
+ QTimer::singleShot(2000, this, []() {
+ auto modelManager = QmlJS::ModelManagerInterface::instance();
+ if (!modelManager)
+ return;
-Utils::FilePath StudioWelcomePlugin::defaultExamplesPath()
-{
- QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
- ? QStandardPaths::HomeLocation
- : QStandardPaths::DocumentsLocation;
+ QmlJS::PathsAndLanguages importPaths;
- return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
- .pathAppended("QtDesignStudio");
-}
+ const QList<Kit *> kits = Utils::filtered(KitManager::kits(), [](const Kit *k) {
+ const QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
+ const bool isQt6 = version && version->qtVersion().majorVersion() == 6;
-QString StudioWelcomePlugin::examplesPathSetting()
-{
- return Core::ICore::settings()
- ->value(EXAMPLES_DOWNLOAD_PATH, defaultExamplesPath().toString())
- .toString();
+ return isQt6
+ && ProjectExplorer::DeviceTypeKitAspect::deviceTypeId(k)
+ == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ });
+
+ for (const Kit *kit : kits) {
+ const QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(kit);
+
+ const Utils::FilePath qmlPath = version->qmlPath();
+ importPaths.maybeInsert(qmlPath, QmlJS::Dialect::QmlQtQuick2);
+
+ QmlJS::ModelManagerInterface::importScan(QmlJS::ModelManagerInterface::workingCopy(),
+ importPaths,
+ modelManager,
+ false);
+ }
+ });
+
+ return true;
}
WelcomeMode::WelcomeMode()
@@ -706,36 +759,6 @@ WelcomeMode::WelcomeMode()
[](const QString &path) { return QFileInfo::exists(path); }));
}
-static bool hideBuildMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD, false)
- .toBool();
-}
-
-static bool hideDebugMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false)
- .toBool();
-}
-
-static bool hideAnalyzeMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE, false)
- .toBool();
-}
-
-void setSettingIfDifferent(const QString &key, bool value, bool &dirty)
-{
- QSettings *s = Core::ICore::settings();
- if (s->value(key, false).toBool() != value) {
- dirty = true;
- s->setValue(key, value);
- }
-}
-
WelcomeMode::~WelcomeMode()
{
delete m_modeWidget;
@@ -751,10 +774,12 @@ void WelcomeMode::setupQuickWidget(const QString &welcomePagePath)
m_quickWidget->setSource(
QUrl::fromLocalFile(QLatin1String(STUDIO_QML_PATH) + "welcomepage/main.qml"));
#else
+ m_quickWidget->rootContext()->setContextProperty("$dataModel", m_dataModelDownloader);
m_quickWidget->engine()->addImportPath("qrc:/qml/welcomepage/imports");
m_quickWidget->setSource(QUrl("qrc:/qml/welcomepage/main.qml"));
#endif
} else {
+ m_quickWidget->rootContext()->setContextProperty("$dataModel", m_dataModelDownloader);
m_quickWidget->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString());
@@ -778,6 +803,7 @@ void WelcomeMode::createQuickWidget()
m_quickWidget = new QQuickWidget;
m_quickWidget->setMinimumSize(640, 480);
m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ m_quickWidget->setObjectName(QmlDesigner::Constants::OBJECT_NAME_WELCOME_PAGE);
QmlDesigner::Theme::setupTheme(m_quickWidget->engine());
m_quickWidget->engine()->addImportPath("qrc:/studiofonts");
@@ -786,104 +812,6 @@ void WelcomeMode::createQuickWidget()
m_quickWidget->engine()->setOutputWarningsToStandardError(false);
}
-StudioSettingsPage::StudioSettingsPage()
- : m_buildCheckBox(new QCheckBox(tr("Build")))
- , m_debugCheckBox(new QCheckBox(tr("Debug")))
- , m_analyzeCheckBox(new QCheckBox(tr("Analyze")))
- , m_pathChooser(new Utils::PathChooser())
-{
- const QString toolTip = tr(
- "Hide top-level menus with advanced functionality to simplify the UI. <b>Build</b> is "
- "generally not required in the context of Qt Design Studio. <b>Debug</b> and <b>Analyze</b> "
- "are only required for debugging and profiling.");
-
- QVBoxLayout *boxLayout = new QVBoxLayout();
- setLayout(boxLayout);
- auto groupBox = new QGroupBox(tr("Hide Menu"));
- groupBox->setToolTip(toolTip);
- boxLayout->addWidget(groupBox);
-
- auto verticalLayout = new QVBoxLayout();
- groupBox->setLayout(verticalLayout);
-
- m_buildCheckBox->setToolTip(toolTip);
- m_debugCheckBox->setToolTip(toolTip);
- m_analyzeCheckBox->setToolTip(toolTip);
-
- verticalLayout->addWidget(m_buildCheckBox);
- verticalLayout->addWidget(m_debugCheckBox);
- verticalLayout->addWidget(m_analyzeCheckBox);
- verticalLayout->addSpacerItem(
- new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
-
- m_buildCheckBox->setChecked(hideBuildMenuSetting());
- m_debugCheckBox->setChecked(hideDebugMenuSetting());
- m_analyzeCheckBox->setChecked(hideAnalyzeMenuSetting());
-
- auto examplesGroupBox = new QGroupBox(tr("Examples"));
- boxLayout->addWidget(examplesGroupBox);
-
- auto horizontalLayout = new QHBoxLayout();
- examplesGroupBox->setLayout(horizontalLayout);
-
- auto label = new QLabel(tr("Examples path:"));
- m_pathChooser->setFilePath(
- Utils::FilePath::fromString(StudioWelcomePlugin::examplesPathSetting()));
- auto resetButton = new QPushButton(tr("Reset Path"));
-
- connect(resetButton, &QPushButton::clicked, this, [this]() {
- m_pathChooser->setFilePath(StudioWelcomePlugin::defaultExamplesPath());
- });
-
- horizontalLayout->addWidget(label);
- horizontalLayout->addWidget(m_pathChooser);
- horizontalLayout->addWidget(resetButton);
-
-
- boxLayout->addSpacerItem(
- new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
-}
-
-void StudioSettingsPage::apply()
-{
- bool dirty = false;
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD,
- m_buildCheckBox->isChecked(),
- dirty);
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG,
- m_debugCheckBox->isChecked(),
- dirty);
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE,
- m_analyzeCheckBox->isChecked(),
- dirty);
-
-
- if (dirty) {
- const QString restartText = tr("The menu visibility change will take effect after restart.");
- Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
- restartDialog.exec();
- }
-
- QSettings *s = Core::ICore::settings();
- const QString value = m_pathChooser->filePath().toString();
-
- if (s->value(EXAMPLES_DOWNLOAD_PATH, false).toString() != value) {
- s->setValue(EXAMPLES_DOWNLOAD_PATH, value);
- emit s_pluginInstance->examplesDownloadPathChanged(value);
- }
-}
-
-StudioWelcomeSettingsPage::StudioWelcomeSettingsPage()
-{
- setId("Z.StudioWelcome.Settings");
- setDisplayName(tr("Qt Design Studio Configuration"));
- setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
- setWidgetCreator([] { return new StudioSettingsPage; });
-}
-
} // namespace Internal
} // namespace StudioWelcome
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.h b/src/plugins/studiowelcome/studiowelcomeplugin.h
index 5f0a2a4dc6..51ec59bafe 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.h
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.h
@@ -5,39 +5,12 @@
#include <extensionsystem/iplugin.h>
#include <coreplugin/dialogs/ioptionspage.h>
-#include <utils/pathchooser.h>
#include <QTimer>
-QT_FORWARD_DECLARE_CLASS(QCheckBox)
-
namespace StudioWelcome {
namespace Internal {
-class StudioSettingsPage : public Core::IOptionsPageWidget
-{
- Q_OBJECT
-
-public:
- void apply() final;
-
- StudioSettingsPage();
-
-private:
- QCheckBox *m_buildCheckBox;
- QCheckBox *m_debugCheckBox;
- QCheckBox *m_analyzeCheckBox;
- Utils::PathChooser *m_pathChooser;
-};
-
-class StudioWelcomeSettingsPage : public Core::IOptionsPage
-{
- Q_OBJECT
-
-public:
- StudioWelcomeSettingsPage();
-};
-
class StudioWelcomePlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
@@ -54,15 +27,8 @@ public:
void extensionsInitialized() override;
bool delayedInitialize() override;
- static Utils::FilePath defaultExamplesPath();
- static QString examplesPathSetting();
-
-signals:
- void examplesDownloadPathChanged(const QString &path);
-
private:
class WelcomeMode *m_welcomeMode = nullptr;
- StudioWelcomeSettingsPage m_settingsPage;
};
} // namespace Internal
diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt
index 4543091ab7..56a05aa000 100644
--- a/src/tools/qml2puppet/CMakeLists.txt
+++ b/src/tools/qml2puppet/CMakeLists.txt
@@ -203,7 +203,7 @@ extend_qtc_executable(qml2puppet
qmlprivategate.cpp qmlprivategate.h
)
-if(DEFINED MULTILANGUAGE_SUPPORT_SUBDIRECTORY AND Qt6_VERSION VERSION_GREATER_EQUAL 6.2.1)
+if (DEFINED MULTILANGUAGE_SUPPORT_SUBDIRECTORY AND Qt6_VERSION VERSION_GREATER_EQUAL 6.2.1)
add_subdirectory(${MULTILANGUAGE_SUPPORT_SUBDIRECTORY} multilanguagesupport_static_build)
endif()
@@ -224,7 +224,8 @@ extend_qtc_executable(qml2puppet
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.4.0)
extend_qtc_executable(qml2puppet
- DEFINES ENABLE_INTERNAL_QML_RUNTIME
+ # QT_QML_DEBUG is disabled in release builds, but is necessary to have the preview debug channel
+ DEFINES ENABLE_INTERNAL_QML_RUNTIME QT_QML_DEBUG
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/qml2puppet/runner
SOURCES_PREFIX qml2puppet/runner
SOURCES
@@ -253,3 +254,29 @@ extend_qtc_executable(qml2puppet
ENABLE_CRASHPAD
DEPENDS Crashpad::Crashpad
)
+
+# add application icon
+# IDE_LOGO_PATH in a default QtCreator build is empty, all icons are found by relative paths
+# So we can not use the icon then.
+if (TARGET qml2puppet AND NOT "${IDE_LOGO_PATH}" STREQUAL "")
+ if (WIN32)
+ set(RC_APPLICATION_NAME "${IDE_DISPLAY_NAME}")
+ set(RC_VERSION "${IDE_VERSION}.0")
+ set(RC_VERSION_STRING "${IDE_VERSION_DISPLAY}")
+ set(RC_COPYRIGHT "2008-${IDE_COPYRIGHT_YEAR} The Qt Company Ltd")
+
+ string(REPLACE " " "\\x20" RC_APPLICATION_NAME "${RC_APPLICATION_NAME}")
+ string(REPLACE " " "\\x20" RC_COPYRIGHT "${RC_COPYRIGHT}")
+ string(REPLACE "." "," RC_VERSION "${RC_VERSION}")
+
+ target_compile_definitions(qml2puppet PRIVATE
+ RC_APPLICATION_NAME=${RC_APPLICATION_NAME}
+ RC_VERSION=${RC_VERSION}
+ RC_VERSION_STRING=${RC_VERSION_STRING}
+ RC_COPYRIGHT=${RC_COPYRIGHT}
+ RC_ICON_PATH=${IDE_ICON_PATH}
+ )
+
+ target_sources(qml2puppet PRIVATE windows_application_icon/qml2puppet.rc)
+ endif()
+endif()
diff --git a/src/tools/qml2puppet/instances/nodeinstanceclientproxy.cpp b/src/tools/qml2puppet/instances/nodeinstanceclientproxy.cpp
index f3f2b5c8a4..ffafb7bb00 100644
--- a/src/tools/qml2puppet/instances/nodeinstanceclientproxy.cpp
+++ b/src/tools/qml2puppet/instances/nodeinstanceclientproxy.cpp
@@ -367,11 +367,11 @@ void NodeInstanceClientProxy::startNanotrace(const StartNanotraceCommand &comman
std::string fullFilePath =
directory + std::string("/nanotrace_qmlpuppet_") + processName + std::string(".json");
- for (size_t i=0; i<processName.length(); ++i) {
- if (i==0 || processName[i]=='m')
- processName[i] = std::toupper(processName[i]);
+ for (int i=0; i<name.length(); ++i) {
+ if (i==0 || name[i]=='m')
+ name[i] = name.at(i).toUpper();
}
- processName = processName + std::string("Puppet");
+ processName = name.toStdString() + std::string("Puppet");
NANOTRACE_INIT(processName.c_str(), "MainThread", fullFilePath);
diff --git a/src/tools/qml2puppet/qml2puppet/configcrashpad.h b/src/tools/qml2puppet/qml2puppet/configcrashpad.h
index 81cebaeeb1..af82ffca16 100644
--- a/src/tools/qml2puppet/qml2puppet/configcrashpad.h
+++ b/src/tools/qml2puppet/qml2puppet/configcrashpad.h
@@ -17,13 +17,21 @@
namespace {
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
- bool startCrashpad()
+ bool startCrashpad(const QString& libexecPath, const QString& crashReportsPath)
{
using namespace crashpad;
// Cache directory that will store crashpad information and minidumps
- base::FilePath database(L"crashpad_reports");
- base::FilePath handler(L"crashpad_handler.exe");
+ QString databasePath = QDir::cleanPath(crashReportsPath);
+ QString handlerPath = QDir::cleanPath(libexecPath + "/crashpad_handler");
+ #ifdef Q_OS_WIN
+ handlerPath += ".exe";
+ base::FilePath database(databasePath.toStdWString());
+ base::FilePath handler(handlerPath.toStdWString());
+ #elif defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
+ base::FilePath database(databasePath.toStdString());
+ base::FilePath handler(handlerPath.toStdString());
+ #endif
// URL used to submit minidumps to
std::string url(CRASHPAD_BACKEND_URL);
@@ -58,7 +66,7 @@ namespace {
QtSystemExceptionHandler systemExceptionHandler(libexecPath);
#endif //#ifdef ENABLE_QT_BREAKPAD
#else //#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
- bool startCrashpad()
+ bool startCrashpad(const QString&, const QString&)
{
return false;
}
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
index f7e2757e60..8a2a244996 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
@@ -131,6 +131,31 @@ QSSGRenderGraphObject *SelectionBoxGeometry::updateSpatialNode(QSSGRenderGraphOb
updateGeometry();
}
+#if QT_VERSION_MAJOR == 6 && QT_VERSION_MINOR == 4
+ if (!node) {
+ markAllDirty();
+ auto geometryNode = new QSSGRenderGeometry();
+ node = geometryNode;
+ emit geometryNodeDirty();
+
+ // This is a work around for the issue of incorrect geometry objects getting matched for
+ // cached mesh data in QSSGBufferManager::loadRenderMesh in QtQuick3D in 6.4 (see QDS-8843).
+ // Each setting of stride value increments the generation id of the geometry node.
+ // By incrementing generation id by different amounts, we can ensure QSSGBufferManager cache
+ // never matches wrong mesh data.
+ // The cache should be cleared of old objects after they are unused for one frame.
+ // With puppet reset & multiselection, we can create multiple new boxes per frame,
+ // so there's no count that really guarantees there are no invalid cache matches, but
+ // even just 8 should make them very unlikely.
+ // We start count at 12 here to avoid overlapping with gridgeometry cache ids.
+ static int dirtyCount = 12;
+ if (++dirtyCount > 20)
+ dirtyCount = 12;
+ for (int i = 0; i < dirtyCount; ++i)
+ geometryNode->setStride(stride());
+ }
+#endif
+
return QQuick3DGeometry::updateSpatialNode(node);
}
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
index 04439d1c45..8fa29118d7 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
@@ -50,7 +50,20 @@ void QmlPropertyChangesNodeInstance::setPropertyBinding(const PropertyName &name
if (QmlPrivateGate::PropertyChanges::isNormalProperty(name)) { // 'restoreEntryValues', 'explicit'
ObjectNodeInstance::setPropertyBinding(name, expression);
} else {
+ QObject *state = QmlPrivateGate::PropertyChanges::stateObject(object());
+
+ ServerNodeInstance activeState = nodeInstanceServer()->activeStateInstance();
+ auto activeStateInstance = activeState.internalInstance();
+
+ const bool inState = activeStateInstance && activeStateInstance->object() == state;
+
+ if (inState)
+ activeState.deactivateState();
+
QmlPrivateGate::PropertyChanges::changeExpression(object(), name, expression);
+
+ if (inState)
+ activeState.activateState();
}
}
diff --git a/src/tools/qml2puppet/qml2puppet/instances/quickitemnodeinstance.cpp b/src/tools/qml2puppet/qml2puppet/instances/quickitemnodeinstance.cpp
index 99bd116158..f4da2fcc7b 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/quickitemnodeinstance.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/quickitemnodeinstance.cpp
@@ -853,9 +853,14 @@ void QuickItemNodeInstance::setPropertyVariant(const PropertyName &name, const Q
void QuickItemNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression)
{
static QList<PropertyName> anchorsTargets = {"anchors.top",
- "acnhors.bottom",
+ "anchors.bottom",
"anchors.left",
- "achors.right"};
+ "anchors.right",
+ "anchors.horizontalCenter",
+ "anchors.verticalCenter",
+ "anchors.fill",
+ "anchors.centerIn",
+ "anchors.baseline"};
if (ignoredProperties().contains(name))
return;
diff --git a/src/tools/qml2puppet/qml2puppet/qmlbase.h b/src/tools/qml2puppet/qml2puppet/qmlbase.h
index c73bd7fcc6..ae8995f489 100644
--- a/src/tools/qml2puppet/qml2puppet/qmlbase.h
+++ b/src/tools/qml2puppet/qml2puppet/qmlbase.h
@@ -40,10 +40,12 @@ public:
, m_args({argc, argv})
{
m_argParser.setApplicationDescription("QML Runtime Provider for QDS");
- m_argParser.addOptions({{"qml-puppet", "Run QML Puppet (default)"},
- {"qml-runtime", "Run QML Runtime"},
- {"appinfo", "Print build information"},
- {"test", "Run test mode"}});
+ m_argParser.addOption({"qml-puppet", "Run QML Puppet (default)"});
+#ifdef ENABLE_INTERNAL_QML_RUNTIME
+ m_argParser.addOption({"qml-runtime", "Run QML Runtime"});
+#endif
+ m_argParser.addOption({"appinfo", "Print build information"});
+ m_argParser.addOption({"test", "Run test mode"});
}
int run()
@@ -93,8 +95,13 @@ private:
QCommandLineOption optVers = m_argParser.addVersionOption();
if (!m_argParser.parse(m_coreApp->arguments())) {
- std::cout << "Error: " << m_argParser.errorText().toStdString() << std::endl
- << std::endl;
+ std::cout << "Error: " << m_argParser.errorText().toStdString() << std::endl;
+ if (m_argParser.errorText().contains("qml-runtime")) {
+ std::cout << "Note: --qml-runtime is only availabe when Qt is 6.4.x or higher"
+ << std::endl;
+ }
+ std::cout << std::endl;
+
m_argParser.showHelp(1);
} else if (m_argParser.isSet(optVers)) {
m_argParser.showVersion();
diff --git a/src/tools/qml2puppet/qml2puppet/qmlpuppet.cpp b/src/tools/qml2puppet/qml2puppet/qmlpuppet.cpp
index 4025cae41b..6d3fa2ce36 100644
--- a/src/tools/qml2puppet/qml2puppet/qmlpuppet.cpp
+++ b/src/tools/qml2puppet/qml2puppet/qmlpuppet.cpp
@@ -8,6 +8,7 @@
#include <sqlitelibraryinitializer.h>
#endif
+#include <app/app_version.h>
#include <qml2puppet/iconrenderer/iconrenderer.h>
#include <qml2puppet/import3d/import3d.h>
@@ -16,6 +17,7 @@
#include <QFileInfo>
#include <QQmlComponent>
#include <QQmlEngine>
+#include <QSettings>
#if defined(Q_OS_WIN) && defined(QT_NO_DEBUG)
#include <Windows.h>
@@ -75,6 +77,24 @@ void QmlPuppet::populateParser()
{"import3dAsset", "Import 3d asset.", "sourceAsset, outDir, importOptJson"}});
}
+// should be in sync with coreplugin/icore.cpp -> FilePath ICore::crashReportsPath()
+// and src\app\main.cpp
+QString crashReportsPath()
+{
+ QSettings settings(
+ QSettings::IniFormat,
+ QSettings::UserScope,
+ QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
+ QLatin1String(Core::Constants::IDE_CASED_ID));
+
+#if defined(Q_OS_MACOS)
+ return QFileInfo(settings.fileName()).path() + "/crashpad_reports";
+#else
+ return QCoreApplication::applicationDirPath()
+ + '/' + RELATIVE_LIBEXEC_PATH + "crashpad_reports";
+#endif
+}
+
void QmlPuppet::initQmlRunner()
{
if (m_coreApp->arguments().count() < 2
@@ -117,7 +137,8 @@ void QmlPuppet::initQmlRunner()
Import3D::import3D(sourceAsset, outDir, options);
}
- startCrashpad();
+ startCrashpad(QCoreApplication::applicationDirPath()
+ + '/' + RELATIVE_LIBEXEC_PATH, crashReportsPath());
new QmlDesigner::Qt5NodeInstanceClientProxy(m_coreApp.get());
diff --git a/src/tools/qml2puppet/qmlprivategate/qmlprivategate.cpp b/src/tools/qml2puppet/qmlprivategate/qmlprivategate.cpp
index b9a65bb6b2..7fd4e75dc2 100644
--- a/src/tools/qml2puppet/qmlprivategate/qmlprivategate.cpp
+++ b/src/tools/qml2puppet/qmlprivategate/qmlprivategate.cpp
@@ -193,6 +193,14 @@ static bool isDelegateModel(QObject *object)
return false;
}
+static bool isConnections(QObject *object)
+{
+ if (object)
+ return isMetaObjectofType(object->metaObject(), "QQmlConnections");
+
+ return false;
+}
+
// This is used in share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp
QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context)
{
@@ -389,7 +397,7 @@ void doComponentCompleteRecursive(QObject *object, NodeInstanceServer *nodeInsta
doComponentCompleteRecursive(child, nodeInstanceServer);
}
- if (!isQuickStyleItem(object) && !isDelegateModel(object)) {
+ if (!isQuickStyleItem(object) && !isDelegateModel(object) && !isConnections(object)) {
if (item) {
static_cast<QQmlParserStatus *>(item)->componentComplete();
} else {
diff --git a/src/tools/qml2puppet/windows_application_icon/qml2puppet.rc b/src/tools/qml2puppet/windows_application_icon/qml2puppet.rc
new file mode 100644
index 0000000000..b2d07923e3
--- /dev/null
+++ b/src/tools/qml2puppet/windows_application_icon/qml2puppet.rc
@@ -0,0 +1,30 @@
+#include <windows.h>
+
+#define STRINGIFY1(x) #x
+#define STRINGIFY(x) STRINGIFY1(x)
+
+#define ICON_PATH STRINGIFY(RC_ICON_PATH/qtcreator.ico)
+
+IDI_ICON1 ICON DISCARDABLE ICON_PATH
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RC_VERSION
+ PRODUCTVERSION RC_VERSION
+{
+ BLOCK "StringFileInfo"
+ {
+ // U.S. English - Windows, Multilingual
+ BLOCK "040904E4"
+ {
+ VALUE "FileDescription", STRINGIFY(RC_APPLICATION_NAME)
+ VALUE "FileVersion", STRINGIFY(RC_VERSION_STRING)
+ VALUE "ProductName", STRINGIFY(RC_APPLICATION_NAME)
+ VALUE "ProductVersion", STRINGIFY(RC_VERSION_STRING)
+ VALUE "LegalCopyright", STRINGIFY(RC_COPYRIGHT)
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1252 // 1252 = 0x04E4
+ }
+}
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
index f483e1d09d..2206e24242 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
@@ -159,6 +159,7 @@ public:
bool hasStartupTarget() const override { return true; }
PuppetStartData puppetStartData(const class Model &) const override { return {}; }
bool instantQmlTextUpdate() const override { return true; }
+ Utils::FilePath qmlPuppetPath() const override { return {}; }
public:
QSettings qsettings;
diff --git a/tests/unit/unittest/3rdparty/googletest b/tests/unit/unittest/3rdparty/googletest
-Subproject 58d77fa8070e8cec2dc1ed015d66b454c8d7885
+Subproject b796f7d44681514f58a683a3a71ff17c94edb0c
diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt
index ad7858ac91..f220087daf 100644
--- a/tests/unit/unittest/CMakeLists.txt
+++ b/tests/unit/unittest/CMakeLists.txt
@@ -1,5 +1,6 @@
find_package(Googletest MODULE)
find_package(GoogleBenchmark MODULE)
+find_package(Qt6 COMPONENTS QmlDomPrivate QmlCompilerPrivate)
if (NOT Googletest_FOUND)
message(STATUS "Googletest was not found. Please set GOOGLETEST_DIR (CMake or Environment) variable.")
@@ -18,6 +19,7 @@ file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_B
file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}")
add_qtc_test(unittest GTEST
+ PROPERTIES COMPILE_WARNING_AS_ERROR OFF
INCLUDES
BEFORE "../mockup"
BEFORE "../mockup/qmldesigner/designercore/include"
@@ -70,6 +72,7 @@ add_qtc_test(unittest GTEST
sqlitecolumn-test.cpp
sqlitedatabasebackend-test.cpp
sqlitedatabase-test.cpp
+ sqlitefunctionregistry-test.cpp
sqlitesessions-test.cpp
sqlitestatement-test.cpp
sqlitetable-test.cpp
@@ -248,6 +251,7 @@ extend_qtc_test(unittest
projectstorage/filestatus.h
projectstorage/filestatuscache.cpp projectstorage/filestatuscache.h
projectstorage/nonlockingmutex.h
+ projectstorage/projectstorageexceptions.cpp projectstorage/projectstorageexceptions.h
projectstorage/projectstorageinterface.h
projectstorage/projectstorage.cpp projectstorage/projectstorage.h
projectstorage/projectstoragepathwatcher.h
@@ -311,17 +315,18 @@ endif()
extend_qtc_test(unittest DEPENDS Utils CPlusPlus)
extend_qtc_test(unittest
- CONDITION TARGET qmldomlib
- DEPENDS qmldomlib
+ CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
+ DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
SOURCES
qmldocumentparser-test.cpp
qmltypesparser-test.cpp
)
extend_qtc_test(unittest
+ CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
SOURCES_PREFIX "${QmlDesignerDir}/designercore"
- CONDITION TARGET qmldomlib
- DEPENDS qmldomlib
+ DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
+ DEFINES QDS_HAS_QMLDOM
SOURCES
projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
diff --git a/tests/unit/unittest/asynchronousexplicitimagecache-test.cpp b/tests/unit/unittest/asynchronousexplicitimagecache-test.cpp
index 9f0f63d06a..3bad57fc83 100644
--- a/tests/unit/unittest/asynchronousexplicitimagecache-test.cpp
+++ b/tests/unit/unittest/asynchronousexplicitimagecache-test.cpp
@@ -22,6 +22,7 @@ protected:
NiceMock<MockImageCacheStorage> mockStorage;
QmlDesigner::AsynchronousExplicitImageCache cache{mockStorage};
QImage image1{10, 10, QImage::Format_ARGB32};
+ QImage midSizeImage1{5, 5, QImage::Format_ARGB32};
QImage smallImage1{1, 1, QImage::Format_ARGB32};
};
@@ -73,7 +74,7 @@ TEST_F(AsynchronousExplicitImageCache, RequestImageCallsAbortCallbackWithoutEntr
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
- EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
.WillRepeatedly([&](auto) { notification.notify(); });
cache.requestImage("/path/to/Component.qml",
@@ -96,6 +97,63 @@ TEST_F(AsynchronousExplicitImageCache, RequestImageCallsAbortCallbackWithoutImag
notification.wait();
}
+TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageFetchesMidSizeImageFromStorage)
+{
+ EXPECT_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{})))
+ .WillRepeatedly([&](Utils::SmallStringView, auto) {
+ notification.notify();
+ return QmlDesigner::ImageCacheStorageInterface::ImageEntry{};
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageCallsCaptureCallbackWithImageFromStorage)
+{
+ ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{midSizeImage1}));
+
+ EXPECT_CALL(mockCaptureCallback, Call(Eq(midSizeImage1))).WillRepeatedly([&](const QImage &) {
+ notification.notify();
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageCallsAbortCallbackWithoutEntry)
+{
+ ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
+
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
+ .WillRepeatedly([&](auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageCallsAbortCallbackWithoutMidSizeImage)
+{
+ ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}}));
+
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
+ .WillRepeatedly([&](auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
TEST_F(AsynchronousExplicitImageCache, RequestSmallImageFetchesSmallImageFromStorage)
{
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{})))
@@ -130,7 +188,7 @@ TEST_F(AsynchronousExplicitImageCache, RequestSmallImageCallsAbortCallbackWithou
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
- EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
.WillRepeatedly([&](auto) { notification.notify(); });
cache.requestSmallImage("/path/to/Component.qml",
@@ -223,6 +281,21 @@ TEST_F(AsynchronousExplicitImageCache, RequestImageWithExtraIdFetchesImageFromSt
notification.wait();
}
+TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageWithExtraIdFetchesImageFromStorage)
+{
+ EXPECT_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml+extraId1"), _))
+ .WillRepeatedly([&](Utils::SmallStringView, auto) {
+ notification.notify();
+ return QmlDesigner::ImageCacheStorageInterface::ImageEntry{};
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction(),
+ "extraId1");
+ notification.wait();
+}
+
TEST_F(AsynchronousExplicitImageCache, RequestSmallImageWithExtraIdFetchesImageFromStorage)
{
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml+extraId1"), _))
diff --git a/tests/unit/unittest/asynchronousimagecache-test.cpp b/tests/unit/unittest/asynchronousimagecache-test.cpp
index 711a34da19..16e1a59d19 100644
--- a/tests/unit/unittest/asynchronousimagecache-test.cpp
+++ b/tests/unit/unittest/asynchronousimagecache-test.cpp
@@ -24,6 +24,7 @@ protected:
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
QmlDesigner::AsynchronousImageCache cache{mockStorage, mockGenerator, mockTimeStampProvider};
QImage image1{10, 10, QImage::Format_ARGB32};
+ QImage midSizeImage1{5, 5, QImage::Format_ARGB32};
QImage smallImage1{1, 1, QImage::Format_ARGB32};
};
@@ -105,7 +106,7 @@ TEST_F(AsynchronousImageCache, RequestImageCallsCaptureCallbackWithImageFromGene
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto &&callback, auto, auto) {
- callback(QImage{image1}, QImage{smallImage1});
+ callback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
notification.notify();
});
@@ -133,6 +134,113 @@ TEST_F(AsynchronousImageCache, RequestImageCallsAbortCallbackFromGenerator)
notification.wait();
}
+TEST_F(AsynchronousImageCache, RequestMidSizeImageFetchesMidSizeImageFromStorage)
+{
+ EXPECT_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillRepeatedly([&](Utils::SmallStringView, auto) {
+ notification.notify();
+ return QmlDesigner::ImageCacheStorageInterface::ImageEntry{};
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageFetchesMidSizeImageFromStorageWithTimeStamp)
+{
+ EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillRepeatedly(Return(Sqlite::TimeStamp{123}));
+ EXPECT_CALL(mockStorage,
+ fetchMidSizeImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
+ .WillRepeatedly([&](Utils::SmallStringView, auto) {
+ notification.notify();
+ return QmlDesigner::ImageCacheStorageInterface::ImageEntry{};
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageCallsCaptureCallbackWithImageFromStorage)
+{
+ ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage1}));
+
+ EXPECT_CALL(mockCaptureCallback, Call(Eq(smallImage1))).WillRepeatedly([&](const QImage &) {
+ notification.notify();
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageCallsAbortCallbackWithoutMidSizeImage)
+{
+ ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}}));
+
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
+ .WillRepeatedly([&](auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageRequestImageFromGenerator)
+{
+ ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillByDefault(Return(Sqlite::TimeStamp{123}));
+
+ EXPECT_CALL(mockGenerator,
+ generateImage(Eq("/path/to/Component.qml"), _, Eq(Sqlite::TimeStamp{123}), _, _, _))
+ .WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageCallsCaptureCallbackWithImageFromGenerator)
+{
+ ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto &&callback, auto, auto) {
+ callback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
+ notification.notify();
+ });
+
+ EXPECT_CALL(mockCaptureCallback, Call(Eq(midSizeImage1)));
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
+TEST_F(AsynchronousImageCache, RequestMidSizeImageCallsAbortCallbackFromGenerator)
+{
+ ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto &&, auto &&abortCallback, auto) {
+ abortCallback(QmlDesigner::ImageCache::AbortReason::Failed);
+ notification.notify();
+ });
+
+ EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)));
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction());
+ notification.wait();
+}
+
TEST_F(AsynchronousImageCache, RequestSmallImageFetchesSmallImageFromStorage)
{
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
@@ -211,7 +319,7 @@ TEST_F(AsynchronousImageCache, RequestSmallImageCallsCaptureCallbackWithImageFro
{
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto &&callback, auto, auto) {
- callback(QImage{image1}, QImage{smallImage1});
+ callback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
notification.notify();
});
@@ -243,7 +351,7 @@ TEST_F(AsynchronousImageCache, CleanRemovesEntries)
{
EXPECT_CALL(mockGenerator, generateImage(_, _, _, _, _, _))
.WillRepeatedly([&](auto, auto, auto, auto &&captureCallback, auto &&, auto) {
- captureCallback(QImage{}, QImage{});
+ captureCallback(QImage{}, QImage{}, QImage{});
waitInThread.wait();
});
cache.requestSmallImage("/path/to/Component1.qml",
@@ -315,6 +423,21 @@ TEST_F(AsynchronousImageCache, RequestImageWithExtraIdFetchesImageFromStorage)
notification.wait();
}
+TEST_F(AsynchronousImageCache, RequestMidSizeImageWithExtraIdFetchesImageFromStorage)
+{
+ EXPECT_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml+extraId1"), _))
+ .WillRepeatedly([&](Utils::SmallStringView, auto) {
+ notification.notify();
+ return QmlDesigner::ImageCacheStorageInterface::ImageEntry{};
+ });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction(),
+ "extraId1");
+ notification.wait();
+}
+
TEST_F(AsynchronousImageCache, RequestSmallImageWithExtraIdFetchesImageFromStorage)
{
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml+extraId1"), _))
@@ -347,6 +470,23 @@ TEST_F(AsynchronousImageCache, RequestImageWithExtraIdRequestImageFromGenerator)
notification.wait();
}
+TEST_F(AsynchronousImageCache, RequestMidSizeImageWithExtraIdRequestImageFromGenerator)
+{
+ ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillByDefault(Return(Sqlite::TimeStamp{123}));
+
+ EXPECT_CALL(mockGenerator,
+ generateImage(
+ Eq("/path/to/Component.qml"), Eq("extraId1"), Eq(Sqlite::TimeStamp{123}), _, _, _))
+ .WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction(),
+ "extraId1");
+ notification.wait();
+}
+
TEST_F(AsynchronousImageCache, RequestSmallImageWithExtraIdRequestImageFromGenerator)
{
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
@@ -392,6 +532,34 @@ TEST_F(AsynchronousImageCache, RequestImageWithAuxiliaryDataRequestImageFromGene
notification.wait();
}
+TEST_F(AsynchronousImageCache, RequestMidSizeImageWithAuxiliaryDataRequestImageFromGenerator)
+{
+ using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
+ std::vector<QSize> sizes{{20, 11}};
+ ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillByDefault(Return(Sqlite::TimeStamp{123}));
+
+ EXPECT_CALL(mockGenerator,
+ generateImage(Eq("/path/to/Component.qml"),
+ Eq("extraId1"),
+ Eq(Sqlite::TimeStamp{123}),
+ _,
+ _,
+ VariantWith<FontCollectorSizesAuxiliaryData>(
+ AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
+ ElementsAre(QSize{20, 11})),
+ Field(&FontCollectorSizesAuxiliaryData::colorName,
+ Eq(u"color"))))))
+ .WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
+
+ cache.requestMidSizeImage("/path/to/Component.qml",
+ mockCaptureCallback.AsStdFunction(),
+ mockAbortCallback.AsStdFunction(),
+ "extraId1",
+ FontCollectorSizesAuxiliaryData{sizes, "color", "text"});
+ notification.wait();
+}
+
TEST_F(AsynchronousImageCache, RequestSmallImageWithAuxiliaryDataRequestImageFromGenerator)
{
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
diff --git a/tests/unit/unittest/asynchronousimagefactory-test.cpp b/tests/unit/unittest/asynchronousimagefactory-test.cpp
index bb76117432..49a44c9afe 100644
--- a/tests/unit/unittest/asynchronousimagefactory-test.cpp
+++ b/tests/unit/unittest/asynchronousimagefactory-test.cpp
@@ -32,6 +32,7 @@ protected:
NiceMock<MockTimeStampProvider> timeStampProviderMock;
QmlDesigner::AsynchronousImageFactory factory{storageMock, timeStampProviderMock, collectorMock};
QImage image1{10, 10, QImage::Format_ARGB32};
+ QImage midSizeImage1{5, 5, QImage::Format_ARGB32};
QImage smallImage1{1, 1, QImage::Format_ARGB32};
};
@@ -162,14 +163,17 @@ TEST_F(AsynchronousImageFactory, CaptureImageCallbackStoresImage)
VariantWith<std::monostate>(std::monostate{}),
_,
_))
- .WillByDefault([&](auto, auto, auto, auto capture, auto) { capture(image1, smallImage1); });
+ .WillByDefault([&](auto, auto, auto, auto capture, auto) {
+ capture(image1, midSizeImage1, smallImage1);
+ });
EXPECT_CALL(storageMock,
storeImage(Eq("/path/to/Component.qml+id"),
Sqlite::TimeStamp{125},
Eq(image1),
+ Eq(midSizeImage1),
Eq(smallImage1)))
- .WillOnce([&](auto, auto, auto, auto) { notification.notify(); });
+ .WillOnce([&](auto, auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml", "id");
notification.wait();
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 85335f084d..4da2cee485 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -454,6 +454,8 @@ const char *sourceTypeToText(SourceType sourceType)
return "QmlDir";
case SourceType::QmlTypes:
return "QmlTypes";
+ case SourceType::Directory:
+ return "Directory";
}
return "";
diff --git a/tests/unit/unittest/imagecachecollectormock.h b/tests/unit/unittest/imagecachecollectormock.h
index d31ff6daeb..81575b7604 100644
--- a/tests/unit/unittest/imagecachecollectormock.h
+++ b/tests/unit/unittest/imagecachecollectormock.h
@@ -19,7 +19,7 @@ public:
ImageCacheCollectorInterface::AbortCallback abortCallback),
(override));
- MOCK_METHOD(ImagePair,
+ MOCK_METHOD(ImageTuple,
createImage,
(Utils::SmallStringView filePath,
Utils::SmallStringView state,
diff --git a/tests/unit/unittest/imagecachedispatchcollector-test.cpp b/tests/unit/unittest/imagecachedispatchcollector-test.cpp
index 540641837c..756304e7d1 100644
--- a/tests/unit/unittest/imagecachedispatchcollector-test.cpp
+++ b/tests/unit/unittest/imagecachedispatchcollector-test.cpp
@@ -19,14 +19,16 @@ MATCHER_P(IsIcon, icon, std::string(negation ? "isn't " : "is ") + PrintToString
return icon.availableSizes() == other.availableSizes();
}
-MATCHER_P2(IsImage,
+MATCHER_P3(IsImage,
image,
+ midSizeImage,
smallImage,
- std::string(negation ? "aren't " : "are ") + PrintToString(image) + " and "
- + PrintToString(smallImage))
+ std::string(negation ? "aren't " : "are ") + PrintToString(image) + ", "
+ + PrintToString(midSizeImage) + " and " + PrintToString(smallImage))
{
- const std::pair<QImage, QImage> &other = arg;
- return other.first == image && other.second == smallImage;
+ const std::tuple<QImage, QImage, QImage> &other = arg;
+ return std::get<0>(other) == image && std::get<1>(other) == midSizeImage
+ && std::get<2>(other) == smallImage;
}
class ImageCacheDispatchCollector : public ::testing::Test
@@ -38,21 +40,23 @@ protected:
ON_CALL(collectorMock2, createIcon(_, _, _)).WillByDefault(Return(icon2));
ON_CALL(collectorMock1, createImage(_, _, _))
- .WillByDefault(Return(std::pair{image1, smallImage1}));
+ .WillByDefault(Return(std::tuple{image1, midSizeImage1, smallImage1}));
ON_CALL(collectorMock2, createImage(_, _, _))
- .WillByDefault(Return(std::pair{image2, smallImage2}));
+ .WillByDefault(Return(std::tuple{image2, midSizeImage2, smallImage2}));
}
protected:
std::vector<QSize> sizes{{20, 11}};
- NiceMock<MockFunction<void(const QImage &, const QImage &)>> captureCallbackMock;
+ NiceMock<MockFunction<void(const QImage &, const QImage &, const QImage &)>> captureCallbackMock;
NiceMock<MockFunction<void(QmlDesigner::ImageCache::AbortReason)>> abortCallbackMock;
NiceMock<ImageCacheCollectorMock> collectorMock1;
NiceMock<ImageCacheCollectorMock> collectorMock2;
QImage image1{1, 1, QImage::Format_ARGB32};
- QImage image2{2, 2, QImage::Format_ARGB32};
- QImage smallImage1{1, 1, QImage::Format_ARGB32};
- QImage smallImage2{2, 1, QImage::Format_ARGB32};
+ QImage image2{1, 2, QImage::Format_ARGB32};
+ QImage midSizeImage1{2, 1, QImage::Format_ARGB32};
+ QImage midSizeImage2{2, 2, QImage::Format_ARGB32};
+ QImage smallImage1{3, 1, QImage::Format_ARGB32};
+ QImage smallImage2{3, 2, QImage::Format_ARGB32};
QIcon icon1{QPixmap::fromImage(image1)};
QIcon icon2{QPixmap::fromImage(image2)};
};
@@ -79,7 +83,7 @@ TEST_F(ImageCacheDispatchCollector, CallQmlCollectorStart)
},
&collectorMock2))};
- EXPECT_CALL(captureCallbackMock, Call(_, _));
+ EXPECT_CALL(captureCallbackMock, Call(_, _, _));
EXPECT_CALL(abortCallbackMock, Call(_));
EXPECT_CALL(collectorMock2,
start(Eq("foo.qml"),
@@ -91,7 +95,7 @@ TEST_F(ImageCacheDispatchCollector, CallQmlCollectorStart)
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto captureCallback, auto abortCallback) {
- captureCallback(QImage{}, QImage{});
+ captureCallback({}, {}, {});
abortCallback(QmlDesigner::ImageCache::AbortReason::Abort);
});
EXPECT_CALL(collectorMock1, start(_, _, _, _, _)).Times(0);
@@ -115,7 +119,7 @@ TEST_F(ImageCacheDispatchCollector, CallUiFileCollectorStart)
const QmlDesigner::ImageCache::AuxiliaryData &) { return true; },
&collectorMock2))};
- EXPECT_CALL(captureCallbackMock, Call(_, _));
+ EXPECT_CALL(captureCallbackMock, Call(_, _, _));
EXPECT_CALL(abortCallbackMock, Call(_));
EXPECT_CALL(collectorMock1,
start(Eq("foo.ui.qml"),
@@ -127,7 +131,7 @@ TEST_F(ImageCacheDispatchCollector, CallUiFileCollectorStart)
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto captureCallback, auto abortCallback) {
- captureCallback(QImage{}, QImage{});
+ captureCallback({}, {}, {});
abortCallback(QmlDesigner::ImageCache::AbortReason::Abort);
});
EXPECT_CALL(collectorMock2, start(_, _, _, _, _)).Times(0);
@@ -288,7 +292,7 @@ TEST_F(ImageCacheDispatchCollector, CallFirstCollectorCreateImage)
"state",
FontCollectorSizesAuxiliaryData{sizes, "color", "text"});
- ASSERT_THAT(image, IsImage(image1, smallImage1));
+ ASSERT_THAT(image, IsImage(image1, midSizeImage1, smallImage1));
}
TEST_F(ImageCacheDispatchCollector, FirstCollectorCreateImageCalls)
@@ -334,7 +338,7 @@ TEST_F(ImageCacheDispatchCollector, CallSecondCollectorCreateImage)
"state",
FontCollectorSizesAuxiliaryData{sizes, "color", "text"});
- ASSERT_THAT(image, IsImage(image2, smallImage2));
+ ASSERT_THAT(image, IsImage(image2, midSizeImage2, smallImage2));
}
TEST_F(ImageCacheDispatchCollector, SecondCollectorCreateImageCalls)
@@ -380,7 +384,8 @@ TEST_F(ImageCacheDispatchCollector, DontCallCollectorCreateImageForUnknownFile)
"state",
FontCollectorSizesAuxiliaryData{sizes, "color", "text"});
- ASSERT_TRUE(image.first.isNull() && image.second.isNull());
+ ASSERT_TRUE(std::get<0>(image).isNull() && std::get<1>(image).isNull()
+ && std::get<2>(image).isNull());
}
} // namespace
diff --git a/tests/unit/unittest/imagecachegenerator-test.cpp b/tests/unit/unittest/imagecachegenerator-test.cpp
index e39def87d4..871a3768bb 100644
--- a/tests/unit/unittest/imagecachegenerator-test.cpp
+++ b/tests/unit/unittest/imagecachegenerator-test.cpp
@@ -32,8 +32,9 @@ protected:
Notification waitInThread;
Notification notification;
QImage image1{10, 10, QImage::Format_ARGB32};
+ QImage midSizeImage1{5, 5, QImage::Format_ARGB32};
QImage smallImage1{1, 1, QImage::Format_ARGB32};
- NiceMock<MockFunction<void(const QImage &, const QImage &)>> imageCallbackMock;
+ NiceMock<MockFunction<void(const QImage &, const QImage &, const QImage &)>> imageCallbackMock;
NiceMock<MockFunction<void(QmlDesigner::ImageCache::AbortReason)>> abortCallbackMock;
NiceMock<ImageCacheCollectorMock> collectorMock;
NiceMock<MockImageCacheStorage> storageMock;
@@ -44,11 +45,11 @@ TEST_F(ImageCacheGenerator, CallsCollectorWithCaptureCallback)
{
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillRepeatedly([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
- EXPECT_CALL(imageCallbackMock, Call(_, _)).WillRepeatedly([&](const QImage &, const QImage &) {
- notification.notify();
- });
+ EXPECT_CALL(imageCallbackMock, Call(_, _, _))
+ .WillRepeatedly(
+ [&](const QImage &, const QImage &, const QImage &) { notification.notify(); });
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
notification.wait();
@@ -66,17 +67,16 @@ TEST_F(ImageCacheGenerator, CallsCollectorOnlyIfNotProcessing)
TEST_F(ImageCacheGenerator, ProcessTaskAfterFirstFinished)
{
- ON_CALL(imageCallbackMock, Call(_, _)).WillByDefault([&](const QImage &, const QImage &) {
- notification.notify();
- });
+ ON_CALL(imageCallbackMock, Call(_, _, _))
+ .WillByDefault([&](const QImage &, const QImage &, const QImage &) { notification.notify(); });
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
EXPECT_CALL(collectorMock, start(Eq("name2"), _, _, _, _))
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
@@ -88,7 +88,7 @@ TEST_F(ImageCacheGenerator, DontCrashAtDestructingGenerator)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
generator.generateImage(
@@ -105,12 +105,16 @@ TEST_F(ImageCacheGenerator, StoreImage)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
EXPECT_CALL(storageMock,
- storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(image1), Eq(smallImage1)))
- .WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
+ storeImage(Eq("name"),
+ Eq(Sqlite::TimeStamp{11}),
+ Eq(image1),
+ Eq(midSizeImage1),
+ Eq(smallImage1)))
+ .WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
generator.generateImage("name", {}, {11}, imageCallbackMock.AsStdFunction(), {}, {});
notification.wait();
@@ -120,12 +124,16 @@ TEST_F(ImageCacheGenerator, StoreImageWithExtraId)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
EXPECT_CALL(storageMock,
- storeImage(Eq("name+extraId"), Eq(Sqlite::TimeStamp{11}), Eq(image1), Eq(smallImage1)))
- .WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
+ storeImage(Eq("name+extraId"),
+ Eq(Sqlite::TimeStamp{11}),
+ Eq(image1),
+ Eq(midSizeImage1),
+ Eq(smallImage1)))
+ .WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
generator.generateImage("name", "extraId", {11}, imageCallbackMock.AsStdFunction(), {}, {});
notification.wait();
@@ -135,12 +143,13 @@ TEST_F(ImageCacheGenerator, StoreNullImage)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{}, QImage{});
+ captureCallback(QImage{}, QImage{}, QImage{});
});
- EXPECT_CALL(storageMock,
- storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
- .WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
+ EXPECT_CALL(
+ storageMock,
+ storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{}), Eq(QImage{})))
+ .WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
generator.generateImage(
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
@@ -151,12 +160,16 @@ TEST_F(ImageCacheGenerator, StoreNullImageWithExtraId)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{}, QImage{});
+ captureCallback(QImage{}, QImage{}, QImage{});
});
EXPECT_CALL(storageMock,
- storeImage(Eq("name+extraId"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
- .WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
+ storeImage(Eq("name+extraId"),
+ Eq(Sqlite::TimeStamp{11}),
+ Eq(QImage{}),
+ Eq(QImage{}),
+ Eq(QImage{})))
+ .WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
generator.generateImage("name",
"extraId",
@@ -171,16 +184,15 @@ TEST_F(ImageCacheGenerator, AbortCallback)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
ON_CALL(collectorMock, start(Eq("name2"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto, auto abortCallback) {
abortCallback(QmlDesigner::ImageCache::AbortReason::Failed);
});
- EXPECT_CALL(imageCallbackMock, Call(_, _)).WillOnce([&](const QImage &, const QImage &) {
- notification.notify();
- });
+ EXPECT_CALL(imageCallbackMock, Call(_, _, _))
+ .WillOnce([&](const QImage &, const QImage &, const QImage &) { notification.notify(); });
EXPECT_CALL(abortCallbackMock, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
.WillOnce([&](auto) { notification.notify(); });
@@ -200,7 +212,7 @@ TEST_F(ImageCacheGenerator, StoreNullImageForAbortCallbackAbort)
ON_CALL(collectorMock, start(Eq("dummyNotify"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto, auto) { notification.notify(); });
- EXPECT_CALL(storageMock, storeImage(Eq("name"), _, _, _)).Times(0);
+ EXPECT_CALL(storageMock, storeImage(Eq("name"), _, _, _, _)).Times(0);
generator.generateImage(
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
@@ -215,20 +227,21 @@ TEST_F(ImageCacheGenerator, DontStoreNullImageForAbortCallbackFailed)
abortCallback(QmlDesigner::ImageCache::AbortReason::Failed);
});
- EXPECT_CALL(storageMock,
- storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
- .WillOnce([&](auto, auto, auto, auto) { notification.notify(); });
+ EXPECT_CALL(
+ storageMock,
+ storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{}), Eq(QImage{})))
+ .WillOnce([&](auto, auto, auto, auto, auto) { notification.notify(); });
generator.generateImage(
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
notification.wait();
}
-TEST_F(ImageCacheGenerator, AbortForEmptyImage)
+TEST_F(ImageCacheGenerator, AbortForNullImage)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{}, QImage{});
+ captureCallback(QImage{}, QImage{}, QImage{});
});
EXPECT_CALL(abortCallbackMock, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed)))
@@ -239,10 +252,99 @@ TEST_F(ImageCacheGenerator, AbortForEmptyImage)
notification.wait();
}
+TEST_F(ImageCacheGenerator, CallImageCallbackIfSmallImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
+ captureCallback({}, {}, smallImage1);
+ });
+
+ EXPECT_CALL(imageCallbackMock, Call(Eq(QImage()), Eq(QImage()), Eq(smallImage1)))
+ .WillOnce([&](auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
+TEST_F(ImageCacheGenerator, StoreImageIfSmallImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
+ captureCallback({}, {}, smallImage1);
+ });
+
+ EXPECT_CALL(storageMock, storeImage(_, _, Eq(QImage()), Eq(QImage()), Eq(smallImage1)))
+ .WillOnce([&](auto, auto, auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
+TEST_F(ImageCacheGenerator, CallImageCallbackIfMidSizeImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
+ captureCallback({}, midSizeImage1, {});
+ });
+
+ EXPECT_CALL(imageCallbackMock, Call(Eq(QImage()), Eq(midSizeImage1), Eq(QImage{})))
+ .WillOnce([&](auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
+TEST_F(ImageCacheGenerator, StoreImageIfMidSizeImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
+ captureCallback({}, midSizeImage1, {});
+ });
+
+ EXPECT_CALL(storageMock, storeImage(_, _, Eq(QImage()), Eq(midSizeImage1), Eq(QImage())))
+ .WillOnce([&](auto, auto, auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
+TEST_F(ImageCacheGenerator, CallImageCallbackIfImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault(
+ [&](auto, auto, auto, auto captureCallback, auto) { captureCallback(image1, {}, {}); });
+
+ EXPECT_CALL(imageCallbackMock, Call(Eq(image1), Eq(QImage{}), Eq(QImage{})))
+ .WillOnce([&](auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
+TEST_F(ImageCacheGenerator, StoreImageIfImageIsNotNull)
+{
+ ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
+ .WillByDefault(
+ [&](auto, auto, auto, auto captureCallback, auto) { captureCallback(image1, {}, {}); });
+
+ EXPECT_CALL(storageMock, storeImage(_, _, Eq(image1), Eq(QImage{}), Eq(QImage{})))
+ .WillOnce([&](auto, auto, auto, auto, auto) { notification.notify(); });
+
+ generator.generateImage(
+ "name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
+ notification.wait();
+}
+
TEST_F(ImageCacheGenerator, CallWalCheckpointFullIfQueueIsEmpty)
{
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
- .WillByDefault([&](auto, auto, auto, auto captureCallback, auto) { captureCallback({}, {}); });
+ .WillByDefault(
+ [&](auto, auto, auto, auto captureCallback, auto) { captureCallback({}, {}, {}); });
EXPECT_CALL(storageMock, walCheckpointFull()).WillRepeatedly([&]() { notification.notify(); });
@@ -277,11 +379,11 @@ TEST_F(ImageCacheGenerator, WaitForFinished)
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
waitInThread.wait();
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
ON_CALL(collectorMock, start(Eq("name2"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{image1}, QImage{smallImage1});
+ captureCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
generator.generateImage(
@@ -289,7 +391,7 @@ TEST_F(ImageCacheGenerator, WaitForFinished)
generator.generateImage(
"name2", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
- EXPECT_CALL(imageCallbackMock, Call(_, _)).Times(2);
+ EXPECT_CALL(imageCallbackMock, Call(_, _, _)).Times(2);
waitInThread.notify();
generator.waitForFinished();
@@ -407,7 +509,7 @@ TEST_F(ImageCacheGenerator, UseLastTimeStampIfTasksAreMerged)
abortCallback(QmlDesigner::ImageCache::AbortReason::Failed);
});
- EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{4}), _, _));
+ EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{4}), _, _, _));
generator.generateImage("waitDummy", {}, {}, {}, {}, {});
generator.generateImage("name", {}, {3}, {}, abortCallbackMock.AsStdFunction(), {});
@@ -419,18 +521,18 @@ TEST_F(ImageCacheGenerator, UseLastTimeStampIfTasksAreMerged)
TEST_F(ImageCacheGenerator, MergeCaptureCallbackIfTasksAreMerged)
{
- NiceMock<MockFunction<void(const QImage &, const QImage &)>> newerImageCallbackMock;
+ NiceMock<MockFunction<void(const QImage &, const QImage &, const QImage &)>> newerImageCallbackMock;
ON_CALL(collectorMock, start(Eq("waitDummy"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto, auto) { waitInThread.wait(); });
ON_CALL(collectorMock, start(Eq("notificationDummy"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto, auto) { notification.notify(); });
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
.WillByDefault([&](auto, auto, auto, auto imageCallback, auto) {
- imageCallback(QImage{image1}, QImage{smallImage1});
+ imageCallback(QImage{image1}, QImage{midSizeImage1}, QImage{smallImage1});
});
- EXPECT_CALL(imageCallbackMock, Call(_, _));
- EXPECT_CALL(newerImageCallbackMock, Call(_, _));
+ EXPECT_CALL(imageCallbackMock, Call(_, _, _));
+ EXPECT_CALL(newerImageCallbackMock, Call(_, _, _));
generator.generateImage("waitDummy", {}, {}, {}, {}, {});
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
@@ -467,7 +569,7 @@ TEST_F(ImageCacheGenerator, DontCallNullImageCallback)
{
EXPECT_CALL(collectorMock, start(_, _, _, _, _))
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(image1, smallImage1);
+ captureCallback(image1, midSizeImage1, smallImage1);
notification.notify();
});
@@ -479,7 +581,7 @@ TEST_F(ImageCacheGenerator, DontCallNullAbortCallbackForNullImage)
{
EXPECT_CALL(collectorMock, start(_, _, _, _, _))
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
- captureCallback(QImage{}, QImage{});
+ captureCallback(QImage{}, QImage{}, QImage{});
notification.notify();
});
diff --git a/tests/unit/unittest/imagecachestorage-test.cpp b/tests/unit/unittest/imagecachestorage-test.cpp
index 4ad6a90eae..f596fce9d2 100644
--- a/tests/unit/unittest/imagecachestorage-test.cpp
+++ b/tests/unit/unittest/imagecachestorage-test.cpp
@@ -14,6 +14,83 @@ MATCHER_P(IsIcon, icon, std::string(negation ? "is't" : "is") + PrintToString(ic
{
return arg.availableSizes() == icon.availableSizes();
}
+
+TEST(ImageCacheStorageUpdateTest, CheckVersionIfDatabaseIsAlreadyInitialized)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(true));
+
+ EXPECT_CALL(databaseMock, version());
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, AddColumnMidSizeIfVersionIsZero)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(true));
+ EXPECT_CALL(databaseMock, execute(_)).Times(AnyNumber());
+
+ EXPECT_CALL(databaseMock, execute(Eq("ALTER TABLE images ADD COLUMN midSizeImage")));
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, DeleteAllRowsBeforeAddingMidSizeColumn)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(true));
+ InSequence s;
+
+ EXPECT_CALL(databaseMock, execute(Eq("DELETE FROM images")));
+ EXPECT_CALL(databaseMock, execute(Eq("ALTER TABLE images ADD COLUMN midSizeImage")));
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, DontCallAddColumnMidSizeIfDatabaseWasNotAlreadyInitialized)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(false));
+ EXPECT_CALL(databaseMock, execute(_)).Times(2);
+
+ EXPECT_CALL(databaseMock, execute(Eq("ALTER TABLE images ADD COLUMN midSizeImage"))).Times(0);
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, SetVersionToOneIfVersionIsZero)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(true));
+
+ EXPECT_CALL(databaseMock, setVersion(Eq(1)));
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, DontSetVersionIfVersionIsOne)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(true));
+ ON_CALL(databaseMock, version()).WillByDefault(Return(1));
+
+ EXPECT_CALL(databaseMock, setVersion(_)).Times(0);
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
+TEST(ImageCacheStorageUpdateTest, SetVersionToOneForInitialization)
+{
+ NiceMock<SqliteDatabaseMock> databaseMock;
+ ON_CALL(databaseMock, isInitialized()).WillByDefault(Return(false));
+ ON_CALL(databaseMock, version()).WillByDefault(Return(1));
+
+ EXPECT_CALL(databaseMock, setVersion(Eq(1)));
+
+ QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
+}
+
class ImageCacheStorageTest : public testing::Test
{
protected:
@@ -26,12 +103,14 @@ protected:
NiceMock<SqliteDatabaseMock> databaseMock;
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
ReadStatement<1, 2> &selectImageStatement = storage.selectImageStatement;
+ ReadStatement<1, 2> &selectMidSizeImageStatement = storage.selectMidSizeImageStatement;
ReadStatement<1, 2> &selectSmallImageStatement = storage.selectSmallImageStatement;
ReadStatement<1, 2> &selectIconStatement = storage.selectIconStatement;
- WriteStatement<4> &upsertImageStatement = storage.upsertImageStatement;
+ WriteStatement<5> &upsertImageStatement = storage.upsertImageStatement;
WriteStatement<3> &upsertIconStatement = storage.upsertIconStatement;
QImage image1{10, 10, QImage::Format_ARGB32};
- QImage smallImage1{10, 10, QImage::Format_ARGB32};
+ QImage midSizeImage1{5, 5, QImage::Format_ARGB32};
+ QImage smallImage1{1, 1, QImage::Format_ARGB32};
QIcon icon1{QPixmap::fromImage(image1)};
};
@@ -67,6 +146,38 @@ TEST_F(ImageCacheStorageTest, FetchImageCallsIsBusy)
storage.fetchImage("/path/to/component", {123});
}
+TEST_F(ImageCacheStorageTest, FetchMidSizeImageCalls)
+{
+ InSequence s;
+
+ EXPECT_CALL(databaseMock, deferredBegin());
+ EXPECT_CALL(selectMidSizeImageStatement,
+ valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
+ TypedEq<long long>(123)));
+ EXPECT_CALL(databaseMock, commit());
+
+ storage.fetchMidSizeImage("/path/to/component", {123});
+}
+
+TEST_F(ImageCacheStorageTest, FetchMidSizeImageCallsIsBusy)
+{
+ InSequence s;
+
+ EXPECT_CALL(databaseMock, deferredBegin());
+ EXPECT_CALL(selectMidSizeImageStatement,
+ valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
+ TypedEq<long long>(123)))
+ .WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
+ EXPECT_CALL(databaseMock, rollback());
+ EXPECT_CALL(databaseMock, deferredBegin());
+ EXPECT_CALL(selectMidSizeImageStatement,
+ valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
+ TypedEq<long long>(123)));
+ EXPECT_CALL(databaseMock, commit());
+
+ storage.fetchMidSizeImage("/path/to/component", {123});
+}
+
TEST_F(ImageCacheStorageTest, FetchSmallImageCalls)
{
InSequence s;
@@ -140,10 +251,11 @@ TEST_F(ImageCacheStorageTest, StoreImageCalls)
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
Not(IsEmpty()),
+ Not(IsEmpty()),
Not(IsEmpty())));
EXPECT_CALL(databaseMock, commit());
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
}
TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
@@ -155,10 +267,11 @@ TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
IsEmpty(),
+ IsEmpty(),
IsEmpty()));
EXPECT_CALL(databaseMock, commit());
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, QImage{});
}
TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
@@ -171,10 +284,11 @@ TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
TypedEq<long long>(123),
IsEmpty(),
+ IsEmpty(),
IsEmpty()));
EXPECT_CALL(databaseMock, commit());
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, QImage{});
}
TEST_F(ImageCacheStorageTest, StoreIconCalls)
@@ -253,29 +367,62 @@ protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
QmlDesigner::ImageCacheStorage<Sqlite::Database> storage{database};
QImage image1{createImage()};
- QImage smallImage1{image1.scaled(96, 96)};
+ QImage midSizeImage1{image1.scaled(96, 96)};
+ QImage smallImage1{image1.scaled(48, 48)};
QIcon icon1{QPixmap::fromImage(image1)};
};
TEST_F(ImageCacheStorageSlowTest, StoreImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, QImage{}, QImage{});
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), Optional(image1));
}
TEST_F(ImageCacheStorageSlowTest, StoreEmptyImageAfterEntry)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, midSizeImage1, smallImage1);
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), Optional(QImage{}));
}
+TEST_F(ImageCacheStorageSlowTest, StoreMidSizeImage)
+{
+ storage.storeImage("/path/to/component", {123}, QImage{}, midSizeImage1, QImage{});
+
+ ASSERT_THAT(storage.fetchMidSizeImage("/path/to/component", {123}), Optional(midSizeImage1));
+}
+
+TEST_F(ImageCacheStorageSlowTest, StoreEmptyMidSizeImageAfterEntry)
+{
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
+
+ storage.storeImage("/path/to/component", {123}, image1, QImage{}, smallImage1);
+
+ ASSERT_THAT(storage.fetchMidSizeImage("/path/to/component", {123}), Optional(QImage{}));
+}
+
+TEST_F(ImageCacheStorageSlowTest, StoreSmallImage)
+{
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, smallImage1);
+
+ ASSERT_THAT(storage.fetchSmallImage("/path/to/component", {123}), Optional(smallImage1));
+}
+
+TEST_F(ImageCacheStorageSlowTest, StoreEmptySmallImageAfterEntry)
+{
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
+
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, QImage{});
+
+ ASSERT_THAT(storage.fetchSmallImage("/path/to/component", {123}), Optional(QImage{}));
+}
+
TEST_F(ImageCacheStorageSlowTest, StoreEmptyEntry)
{
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, QImage{});
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), Optional(QImage{}));
}
@@ -289,7 +436,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchNonExistingImageIsEmpty)
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchImage("/path/to/component", {123});
@@ -298,7 +445,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage)
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchImage("/path/to/component", {124});
@@ -307,13 +454,47 @@ TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage)
TEST_F(ImageCacheStorageSlowTest, FetchNewerImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchImage("/path/to/component", {122});
ASSERT_THAT(image, Optional(image1));
}
+TEST_F(ImageCacheStorageSlowTest, FetchNonExistingMidSizeImageIsEmpty)
+{
+ auto image = storage.fetchMidSizeImage("/path/to/component", {123});
+
+ ASSERT_THAT(image, Eq(std::nullopt));
+}
+
+TEST_F(ImageCacheStorageSlowTest, FetchSameTimeMidSizeImage)
+{
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
+
+ auto image = storage.fetchMidSizeImage("/path/to/component", {123});
+
+ ASSERT_THAT(image, Optional(midSizeImage1));
+}
+
+TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderMidSizeImage)
+{
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
+
+ auto image = storage.fetchMidSizeImage("/path/to/component", {124});
+
+ ASSERT_THAT(image, Eq(std::nullopt));
+}
+
+TEST_F(ImageCacheStorageSlowTest, FetchNewerMidSizeImage)
+{
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
+
+ auto image = storage.fetchMidSizeImage("/path/to/component", {122});
+
+ ASSERT_THAT(image, Optional(midSizeImage1));
+}
+
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingSmallImageIsEmpty)
{
auto image = storage.fetchSmallImage("/path/to/component", {123});
@@ -323,7 +504,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchNonExistingSmallImageIsEmpty)
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeSmallImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchSmallImage("/path/to/component", {123});
@@ -332,7 +513,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchSameTimeSmallImage)
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderSmallImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchSmallImage("/path/to/component", {124});
@@ -341,7 +522,7 @@ TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderSmallImage)
TEST_F(ImageCacheStorageSlowTest, FetchNewerSmallImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto image = storage.fetchSmallImage("/path/to/component", {122});
@@ -407,7 +588,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchNewerIcon)
TEST_F(ImageCacheStorageSlowTest, FetchModifiedImageTime)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto timeStamp = storage.fetchModifiedImageTime("/path/to/component");
@@ -416,7 +597,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchModifiedImageTime)
TEST_F(ImageCacheStorageSlowTest, FetchInvalidModifiedImageTimeForNoEntry)
{
- storage.storeImage("/path/to/component2", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component2", {123}, image1, midSizeImage1, smallImage1);
auto timeStamp = storage.fetchModifiedImageTime("/path/to/component");
@@ -425,7 +606,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchInvalidModifiedImageTimeForNoEntry)
TEST_F(ImageCacheStorageSlowTest, FetchHasImage)
{
- storage.storeImage("/path/to/component", {123}, image1, smallImage1);
+ storage.storeImage("/path/to/component", {123}, image1, midSizeImage1, smallImage1);
auto hasImage = storage.fetchHasImage("/path/to/component");
@@ -434,7 +615,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchHasImage)
TEST_F(ImageCacheStorageSlowTest, FetchHasImageForNullImage)
{
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, QImage{});
auto hasImage = storage.fetchHasImage("/path/to/component");
@@ -443,7 +624,7 @@ TEST_F(ImageCacheStorageSlowTest, FetchHasImageForNullImage)
TEST_F(ImageCacheStorageSlowTest, FetchHasImageForNoEntry)
{
- storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
+ storage.storeImage("/path/to/component", {123}, QImage{}, QImage{}, QImage{});
auto hasImage = storage.fetchHasImage("/path/to/component");
diff --git a/tests/unit/unittest/mockimagecachegenerator.h b/tests/unit/unittest/mockimagecachegenerator.h
index f466e29a48..e7118de566 100644
--- a/tests/unit/unittest/mockimagecachegenerator.h
+++ b/tests/unit/unittest/mockimagecachegenerator.h
@@ -15,7 +15,7 @@ public:
(Utils::SmallStringView name,
Utils::SmallStringView state,
Sqlite::TimeStamp timeStamp,
- QmlDesigner::ImageCache::CaptureImageWithSmallImageCallback &&captureCallback,
+ QmlDesigner::ImageCache::CaptureImageWithScaledImagesCallback &&captureCallback,
QmlDesigner::ImageCache::AbortCallback &&abortCallback,
QmlDesigner::ImageCache::AuxiliaryData &&auxiliaryData),
(override));
diff --git a/tests/unit/unittest/mockimagecachestorage.h b/tests/unit/unittest/mockimagecachestorage.h
index 7e3ad3d2d7..9eb8af5372 100644
--- a/tests/unit/unittest/mockimagecachestorage.h
+++ b/tests/unit/unittest/mockimagecachestorage.h
@@ -16,6 +16,11 @@ public:
(const, override));
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::ImageEntry,
+ fetchMidSizeImage,
+ (Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
+ (const, override));
+
+ MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::ImageEntry,
fetchSmallImage,
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
(const, override));
@@ -30,6 +35,7 @@ public:
(Utils::SmallStringView name,
Sqlite::TimeStamp newTimeStamp,
const QImage &image,
+ const QImage &midSizeImage,
const QImage &smallImage),
(override));
diff --git a/tests/unit/unittest/projectstoragepathwatcher-test.cpp b/tests/unit/unittest/projectstoragepathwatcher-test.cpp
index 6b13075ff0..ad5e0d1487 100644
--- a/tests/unit/unittest/projectstoragepathwatcher-test.cpp
+++ b/tests/unit/unittest/projectstoragepathwatcher-test.cpp
@@ -7,18 +7,19 @@
#include "mockqfilesystemwatcher.h"
#include "mocktimer.h"
#include "projectstoragepathwatchernotifiermock.h"
-#include "sourcepathcachemock.h"
+#include <projectstorage/projectstorage.h>
#include <projectstorage/projectstoragepathwatcher.h>
-#include <projectstorage/sourcepath.h>
+#include <projectstorage/sourcepathcache.h>
+#include <sqlitedatabase.h>
#include <utils/smallstring.h>
namespace {
-
+using SourcePathCache = QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>>;
using Watcher = QmlDesigner::ProjectStoragePathWatcher<NiceMock<MockQFileSytemWatcher>,
NiceMock<MockTimer>,
- NiceMock<SourcePathCacheMock>>;
+ SourcePathCache>;
using QmlDesigner::FileStatus;
using QmlDesigner::IdPaths;
using QmlDesigner::ProjectChunkId;
@@ -40,47 +41,16 @@ class ProjectStoragePathWatcher : public testing::Test
protected:
ProjectStoragePathWatcher()
{
- ON_CALL(sourcePathCacheMock, sourceId(Eq(path1))).WillByDefault(Return(pathIds[0]));
- ON_CALL(sourcePathCacheMock, sourceId(Eq(path2))).WillByDefault(Return(pathIds[1]));
- ON_CALL(sourcePathCacheMock, sourceId(Eq(path3))).WillByDefault(Return(pathIds[2]));
- ON_CALL(sourcePathCacheMock, sourceId(Eq(path4))).WillByDefault(Return(pathIds[3]));
- ON_CALL(sourcePathCacheMock, sourceId(Eq(path5))).WillByDefault(Return(pathIds[4]));
- ON_CALL(sourcePathCacheMock, sourcePath(Eq(pathIds[0]))).WillByDefault(Return(SourcePath{path1}));
- ON_CALL(sourcePathCacheMock, sourcePath(Eq(pathIds[1]))).WillByDefault(Return(SourcePath{path2}));
- ON_CALL(sourcePathCacheMock, sourcePath(Eq(pathIds[2]))).WillByDefault(Return(SourcePath{path3}));
- ON_CALL(sourcePathCacheMock, sourcePath(Eq(pathIds[3]))).WillByDefault(Return(SourcePath{path4}));
- ON_CALL(sourcePathCacheMock, sourcePath(Eq(pathIds[4]))).WillByDefault(Return(SourcePath{path5}));
- ON_CALL(sourcePathCacheMock, sourceContextId(TypedEq<SourceId>(pathIds[0])))
- .WillByDefault(Return(sourceContextIds[0]));
- ON_CALL(sourcePathCacheMock, sourceContextId(TypedEq<SourceId>(pathIds[1])))
- .WillByDefault(Return(sourceContextIds[0]));
- ON_CALL(sourcePathCacheMock, sourceContextId(TypedEq<SourceId>(pathIds[2])))
- .WillByDefault(Return(sourceContextIds[1]));
- ON_CALL(sourcePathCacheMock, sourceContextId(TypedEq<SourceId>(pathIds[3])))
- .WillByDefault(Return(sourceContextIds[1]));
- ON_CALL(sourcePathCacheMock, sourceContextId(TypedEq<SourceId>(pathIds[4])))
- .WillByDefault(Return(sourceContextIds[2]));
ON_CALL(mockFileSystem, fileStatus(_)).WillByDefault([](auto sourceId) {
return FileStatus{sourceId, 1, 1};
});
- ON_CALL(sourcePathCacheMock,
- sourceContextId(TypedEq<Utils::SmallStringView>(sourceContextPathString)))
- .WillByDefault(Return(sourceContextIds[0]));
- ON_CALL(sourcePathCacheMock,
- sourceContextId(TypedEq<Utils::SmallStringView>(sourceContextPathString2)))
- .WillByDefault(Return(sourceContextIds[1]));
- ON_CALL(sourcePathCacheMock, sourceContextPath(Eq(sourceContextIds[0])))
- .WillByDefault(Return(sourceContextPath));
- ON_CALL(sourcePathCacheMock, sourceContextPath(Eq(sourceContextIds[1])))
- .WillByDefault(Return(sourceContextPath2));
- ON_CALL(sourcePathCacheMock, sourceContextPath(Eq(sourceContextIds[2])))
- .WillByDefault(Return(sourceContextPath3));
+
ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath)))
- .WillByDefault(Return(SourceIds{pathIds[0], pathIds[1]}));
+ .WillByDefault(Return(SourceIds{sourceIds[0], sourceIds[1]}));
ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath2)))
- .WillByDefault(Return(SourceIds{pathIds[2], pathIds[3]}));
+ .WillByDefault(Return(SourceIds{sourceIds[2], sourceIds[3]}));
ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath3)))
- .WillByDefault(Return(SourceIds{pathIds[4]}));
+ .WillByDefault(Return(SourceIds{sourceIds[4]}));
}
static WatcherEntries sorted(WatcherEntries &&entries)
{
@@ -90,14 +60,17 @@ protected:
}
protected:
- NiceMock<SourcePathCacheMock> sourcePathCacheMock;
NiceMock<ProjectStoragePathWatcherNotifierMock> notifier;
NiceMock<FileSystemMock> mockFileSystem;
- Watcher watcher{sourcePathCacheMock, mockFileSystem, &notifier};
+ Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
+ QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
+ SourcePathCache pathCache{storage};
+ Watcher watcher{pathCache, mockFileSystem, &notifier};
NiceMock<MockQFileSytemWatcher> &mockQFileSytemWatcher = watcher.fileSystemWatcher();
- ProjectChunkId id1{ProjectPartId::create(2), SourceType::Qml};
- ProjectChunkId id2{ProjectPartId::create(2), SourceType::QmlUi};
- ProjectChunkId id3{ProjectPartId::create(4), SourceType::QmlTypes};
+ ProjectChunkId projectChunkId1{ProjectPartId::create(2), SourceType::Qml};
+ ProjectChunkId projectChunkId2{ProjectPartId::create(2), SourceType::QmlUi};
+ ProjectChunkId projectChunkId3{ProjectPartId::create(3), SourceType::QmlTypes};
+ ProjectChunkId projectChunkId4{ProjectPartId::create(4), SourceType::Qml};
SourcePathView path1{"/path/path1"};
SourcePathView path2{"/path/path2"};
SourcePathView path3{"/path2/path1"};
@@ -110,23 +83,28 @@ protected:
QString sourceContextPath3 = "/path3";
Utils::PathString sourceContextPathString = sourceContextPath;
Utils::PathString sourceContextPathString2 = sourceContextPath2;
- SourceIds pathIds = {SourceId::create(1),
- SourceId::create(2),
- SourceId::create(3),
- SourceId::create(4),
- SourceId::create(5)};
- SourceContextIds sourceContextIds = {SourceContextId::create(1),
- SourceContextId::create(2),
- SourceContextId::create(3)};
- ProjectChunkIds ids{id1, id2, id3};
- WatcherEntry watcherEntry1{id1, sourceContextIds[0], pathIds[0]};
- WatcherEntry watcherEntry2{id2, sourceContextIds[0], pathIds[0]};
- WatcherEntry watcherEntry3{id1, sourceContextIds[0], pathIds[1]};
- WatcherEntry watcherEntry4{id2, sourceContextIds[0], pathIds[1]};
- WatcherEntry watcherEntry5{id3, sourceContextIds[0], pathIds[1]};
- WatcherEntry watcherEntry6{id1, sourceContextIds[1], pathIds[2]};
- WatcherEntry watcherEntry7{id2, sourceContextIds[1], pathIds[3]};
- WatcherEntry watcherEntry8{id3, sourceContextIds[1], pathIds[3]};
+ SourceIds sourceIds = {pathCache.sourceId(path1),
+ pathCache.sourceId(path2),
+ pathCache.sourceId(path3),
+ pathCache.sourceId(path4),
+ pathCache.sourceId(path5)};
+ SourceContextIds sourceContextIds = {pathCache.sourceContextId(sourceIds[0]),
+ pathCache.sourceContextId(sourceIds[2]),
+ pathCache.sourceContextId(sourceIds[4])};
+ ProjectChunkIds ids{projectChunkId1, projectChunkId2, projectChunkId3};
+ WatcherEntry watcherEntry1{projectChunkId1, sourceContextIds[0], sourceIds[0]};
+ WatcherEntry watcherEntry2{projectChunkId2, sourceContextIds[0], sourceIds[0]};
+ WatcherEntry watcherEntry3{projectChunkId1, sourceContextIds[0], sourceIds[1]};
+ WatcherEntry watcherEntry4{projectChunkId2, sourceContextIds[0], sourceIds[1]};
+ WatcherEntry watcherEntry5{projectChunkId3, sourceContextIds[0], sourceIds[1]};
+ WatcherEntry watcherEntry6{projectChunkId1, sourceContextIds[1], sourceIds[2]};
+ WatcherEntry watcherEntry7{projectChunkId2, sourceContextIds[1], sourceIds[3]};
+ WatcherEntry watcherEntry8{projectChunkId3, sourceContextIds[1], sourceIds[3]};
+ WatcherEntry watcherEntry9{projectChunkId4, sourceContextIds[0], sourceIds[0]};
+ WatcherEntry watcherEntry10{projectChunkId4, sourceContextIds[0], sourceIds[1]};
+ WatcherEntry watcherEntry11{projectChunkId4, sourceContextIds[1], sourceIds[2]};
+ WatcherEntry watcherEntry12{projectChunkId4, sourceContextIds[1], sourceIds[3]};
+ WatcherEntry watcherEntry13{projectChunkId4, sourceContextIds[2], sourceIds[4]};
};
TEST_F(ProjectStoragePathWatcher, AddIdPaths)
@@ -135,53 +113,59 @@ TEST_F(ProjectStoragePathWatcher, AddIdPaths)
addPaths(
UnorderedElementsAre(QString(sourceContextPath), QString(sourceContextPath2))));
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
}
TEST_F(ProjectStoragePathWatcher, UpdateIdPathsCallsAddPathInFileWatcher)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1]}}});
EXPECT_CALL(mockQFileSytemWatcher, addPaths(UnorderedElementsAre(QString(sourceContextPath2))));
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
}
TEST_F(ProjectStoragePathWatcher, UpdateIdPathsAndRemoveUnusedPathsCallsRemovePathInFileWatcher)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(UnorderedElementsAre(QString(sourceContextPath2))));
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1]}}});
}
TEST_F(ProjectStoragePathWatcher, UpdateIdPathsAndRemoveUnusedPathsDoNotCallsRemovePathInFileWatcher)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}},
- {id2, {pathIds[0], pathIds[1], pathIds[3]}},
- {id3, {pathIds[0]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}},
+ {projectChunkId3, {sourceIds[0]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0);
- watcher.updateIdPaths({{id1, {pathIds[1]}}, {id2, {pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[1]}}, {projectChunkId2, {sourceIds[3]}}});
}
TEST_F(ProjectStoragePathWatcher, UpdateIdPathsAndRemoveUnusedPaths)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId3, {sourceIds[1]}}});
- watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0]}}, {projectChunkId2, {sourceIds[1]}}});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4, watcherEntry5));
}
TEST_F(ProjectStoragePathWatcher, ExtractSortedEntriesFromConvertIdPaths)
{
- auto entriesAndIds = watcher.convertIdPathsToWatcherEntriesAndIds({{id2, {pathIds[0], pathIds[1]}}, {id1, {pathIds[0], pathIds[1]}}});
+ auto entriesAndIds = watcher.convertIdPathsToWatcherEntriesAndIds(
+ {{projectChunkId2, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId1, {sourceIds[0], sourceIds[1]}}});
ASSERT_THAT(entriesAndIds.first,
ElementsAre(watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4));
@@ -189,23 +173,24 @@ TEST_F(ProjectStoragePathWatcher, ExtractSortedEntriesFromConvertIdPaths)
TEST_F(ProjectStoragePathWatcher, ExtractSortedIdsFromConvertIdPaths)
{
- auto entriesAndIds = watcher.convertIdPathsToWatcherEntriesAndIds({{id2, {}}, {id1, {}}, {id3, {}}});
+ auto entriesAndIds = watcher.convertIdPathsToWatcherEntriesAndIds(
+ {{projectChunkId2, {}}, {projectChunkId1, {}}, {projectChunkId3, {}}});
ASSERT_THAT(entriesAndIds.second, ElementsAre(ids[0], ids[1], ids[2]));
}
TEST_F(ProjectStoragePathWatcher, MergeEntries)
{
- watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0]}}, {projectChunkId2, {sourceIds[1]}}});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4));
}
TEST_F(ProjectStoragePathWatcher, MergeMoreEntries)
{
- watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId2, {sourceIds[0], sourceIds[1]}}});
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4));
}
@@ -223,39 +208,44 @@ TEST_F(ProjectStoragePathWatcher, AddEntriesWithSameIdAndDifferentPaths)
EXPECT_CALL(mockQFileSytemWatcher,
addPaths(ElementsAre(sourceContextPath, sourceContextPath2, sourceContextPath3)));
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[4]}}});
+ watcher.updateIdPaths(
+ {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[4]}}});
}
TEST_F(ProjectStoragePathWatcher, AddEntriesWithDifferentIdAndSamePaths)
{
EXPECT_CALL(mockQFileSytemWatcher, addPaths(ElementsAre(sourceContextPath)));
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}});
}
TEST_F(ProjectStoragePathWatcher, DontAddNewEntriesWithSameIdAndSamePaths)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
+ watcher.updateIdPaths(
+ {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}});
EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0);
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
+ watcher.updateIdPaths(
+ {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}});
}
TEST_F(ProjectStoragePathWatcher, DontAddNewEntriesWithDifferentIdAndSamePaths)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
+ watcher.updateIdPaths(
+ {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}});
EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0);
- watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
+ watcher.updateIdPaths(
+ {{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}});
}
TEST_F(ProjectStoragePathWatcher, RemoveEntriesWithId)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}},
- {id2, {pathIds[0], pathIds[1]}},
- {id3, {pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId3, {sourceIds[1], sourceIds[3]}}});
watcher.removeIds({ProjectPartId::create(2)});
@@ -272,62 +262,67 @@ TEST_F(ProjectStoragePathWatcher, RemoveNoPathsForEmptyIds)
TEST_F(ProjectStoragePathWatcher, RemoveNoPathsForOneId)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(_))
.Times(0);
- watcher.removeIds({id3.id});
+ watcher.removeIds({projectChunkId3.id});
}
TEST_F(ProjectStoragePathWatcher, RemovePathForOneId)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1]}}, {id3, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId3, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(sourceContextPath2)));
- watcher.removeIds({id3.id});
+ watcher.removeIds({projectChunkId3.id});
}
TEST_F(ProjectStoragePathWatcher, RemoveNoPathSecondTime)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- watcher.removeIds({id2.id});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
+ watcher.removeIds({projectChunkId2.id});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0);
- watcher.removeIds({id2.id});
+ watcher.removeIds({projectChunkId2.id});
}
TEST_F(ProjectStoragePathWatcher, RemoveAllPathsForThreeId)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher,
removePaths(ElementsAre(sourceContextPath, sourceContextPath2)));
- watcher.removeIds({id1.id, id2.id, id3.id});
+ watcher.removeIds({projectChunkId1.id, projectChunkId2.id, projectChunkId3.id});
}
TEST_F(ProjectStoragePathWatcher, RemoveOnePathForTwoId)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1]}},
+ {projectChunkId3, {sourceIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(sourceContextPath)));
- watcher.removeIds({id1.id, id2.id});
+ watcher.removeIds({projectChunkId1.id, projectChunkId2.id});
}
TEST_F(ProjectStoragePathWatcher, NotAnymoreWatchedEntriesWithId)
{
+ auto notContainsdId = [&](WatcherEntry entry) {
+ return entry.id != ids[0] && entry.id != ids[1];
+ };
watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
- auto oldEntries = watcher.notAnymoreWatchedEntriesWithIds({watcherEntry1, watcherEntry4}, {ids[0], ids[1]});
+ auto oldEntries = watcher.notAnymoreWatchedEntriesWithIds({watcherEntry1, watcherEntry4},
+ notContainsdId);
ASSERT_THAT(oldEntries, ElementsAre(watcherEntry2, watcherEntry3));
}
@@ -343,20 +338,22 @@ TEST_F(ProjectStoragePathWatcher, RemoveUnusedEntries)
TEST_F(ProjectStoragePathWatcher, TwoNotifyFileChanges)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}},
- {id2, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}},
- {id3, {pathIds[4]}}});
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[0])))
- .WillByDefault(Return(FileStatus{pathIds[0], 1, 2}));
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[1])))
- .WillByDefault(Return(FileStatus{pathIds[1], 1, 2}));
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[3])))
- .WillByDefault(Return(FileStatus{pathIds[3], 1, 2}));
+ watcher.updateIdPaths(
+ {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}},
+ {projectChunkId3, {sourceIds[4]}}});
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0])))
+ .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2}));
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[1])))
+ .WillByDefault(Return(FileStatus{sourceIds[1], 1, 2}));
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3])))
+ .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2}));
EXPECT_CALL(notifier,
pathsWithIdsChanged(ElementsAre(
- IdPaths{id1, {SourceId::create(1), SourceId::create(2)}},
- IdPaths{id2, {SourceId::create(1), SourceId::create(2), SourceId::create(4)}})));
+ IdPaths{projectChunkId1, {SourceId::create(1), SourceId::create(2)}},
+ IdPaths{projectChunkId2,
+ {SourceId::create(1), SourceId::create(2), SourceId::create(4)}})));
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
mockQFileSytemWatcher.directoryChanged(sourceContextPath2);
@@ -364,22 +361,22 @@ TEST_F(ProjectStoragePathWatcher, TwoNotifyFileChanges)
TEST_F(ProjectStoragePathWatcher, NotifyForPathChanges)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[0])))
- .WillByDefault(Return(FileStatus{pathIds[0], 1, 2}));
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0])))
+ .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2}));
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[3])))
- .WillByDefault(Return(FileStatus{pathIds[3], 1, 2}));
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3])))
+ .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2}));
- EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0])));
+ EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0])));
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
}
TEST_F(ProjectStoragePathWatcher, NoNotifyForUnwatchedPathChanges)
{
- watcher.updateIdPaths({{id1, {pathIds[3]}}, {id2, {pathIds[3]}}});
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[3]}}, {projectChunkId2, {sourceIds[3]}}});
EXPECT_CALL(notifier, pathsChanged(IsEmpty()));
@@ -388,14 +385,74 @@ TEST_F(ProjectStoragePathWatcher, NoNotifyForUnwatchedPathChanges)
TEST_F(ProjectStoragePathWatcher, NoDuplicatePathChanges)
{
- watcher.updateIdPaths(
- {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- ON_CALL(mockFileSystem, fileStatus(Eq(pathIds[0])))
- .WillByDefault(Return(FileStatus{pathIds[0], 1, 2}));
+ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}});
+ ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0])))
+ .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2}));
- EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0])));
+ EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0])));
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
mockQFileSytemWatcher.directoryChanged(sourceContextPath);
}
+
+TEST_F(ProjectStoragePathWatcher, UpdateContextIdPathsAddsEntryInNewDirectory)
+{
+ watcher.updateIdPaths({
+ {projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId4, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}},
+ });
+
+ watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[4]}}}, {sourceContextIds[2]});
+
+ ASSERT_THAT(watcher.watchedEntries(),
+ UnorderedElementsAre(watcherEntry1,
+ watcherEntry3,
+ watcherEntry6,
+ watcherEntry9,
+ watcherEntry10,
+ watcherEntry11,
+ watcherEntry12,
+ watcherEntry13));
+}
+
+TEST_F(ProjectStoragePathWatcher, UpdateContextIdPathsAddsEntryToDirectory)
+{
+ watcher.updateIdPaths({
+ {projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId4, {sourceIds[1], sourceIds[3]}},
+ });
+
+ watcher.updateContextIdPaths({{projectChunkId4,
+ {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}}},
+ {sourceContextIds[1]});
+
+ ASSERT_THAT(watcher.watchedEntries(),
+ UnorderedElementsAre(watcherEntry1,
+ watcherEntry3,
+ watcherEntry6,
+ watcherEntry9,
+ watcherEntry10,
+ watcherEntry11,
+ watcherEntry12));
+}
+
+TEST_F(ProjectStoragePathWatcher, UpdateContextIdPathsRemovesEntry)
+{
+ watcher.updateIdPaths({
+ {projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}},
+ {projectChunkId4, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}},
+ });
+
+ watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[3]}}}, {sourceContextIds[1]});
+
+ ASSERT_THAT(watcher.watchedEntries(),
+ UnorderedElementsAre(watcherEntry1,
+ watcherEntry3,
+ watcherEntry6,
+ watcherEntry9,
+ watcherEntry10,
+ watcherEntry12));
+}
+
} // namespace
diff --git a/tests/unit/unittest/projectstoragepathwatchermock.h b/tests/unit/unittest/projectstoragepathwatchermock.h
index 22e81b35d7..2c47291256 100644
--- a/tests/unit/unittest/projectstoragepathwatchermock.h
+++ b/tests/unit/unittest/projectstoragepathwatchermock.h
@@ -7,7 +7,7 @@
#include "projectstorage/projectstoragepathwatcherinterface.h"
-class MockProjectStoragePathWatcher : public QmlDesigner::ProjectStoragePathWatcherInterface
+class ProjectStoragePathWatcherMock : public QmlDesigner::ProjectStoragePathWatcherInterface
{
public:
MOCK_METHOD(void, updateIdPaths, (const std::vector<QmlDesigner::IdPaths> &idPaths), ());
diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp
index 46fa202f90..da7e2f3adb 100644
--- a/tests/unit/unittest/projectstorageupdater-test.cpp
+++ b/tests/unit/unittest/projectstorageupdater-test.cpp
@@ -5,6 +5,7 @@
#include "filesystemmock.h"
#include "projectstoragemock.h"
+#include "projectstoragepathwatchermock.h"
#include "qmldocumentparsermock.h"
#include "qmltypesparsermock.h"
@@ -124,44 +125,29 @@ class ProjectStorageUpdater : public testing::Test
public:
ProjectStorageUpdater()
{
- ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypesPathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 2, 421}));
-
- ON_CALL(fileSystemMock, fileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 2, 421}));
-
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421}));
-
- ON_CALL(fileSystemMock, fileStatus(Eq(directoryPathSourceId)))
- .WillByDefault(Return(FileStatus{directoryPathSourceId, 2, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(directoryPathSourceId)))
- .WillByDefault(Return(FileStatus{directoryPathSourceId, 2, 421}));
-
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillByDefault(Return(qmldirContent));
-
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml", "Second.qml"}));
-
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 12}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 13}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId3)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 2}));
+ setFilesChanged({qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3});
+
+ setFilesDontChanged({directoryPathSourceId,
+ path1SourceId,
+ path2SourceId,
+ path3SourceId,
+ firstSourceId,
+ secondSourceId,
+ thirdSourceId,
+ qmltypes1SourceId,
+ qmltypes2SourceId});
+
+ setFilesAdded({qmldir1SourceId, qmldir2SourceId, qmldir3SourceId});
+
+ setContent(u"/path/qmldir", qmldirContent);
+
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml", "Second.qml"});
+
ON_CALL(projectStorageMock, moduleId(_)).WillByDefault([&](const auto &name) {
return storage.moduleId(name);
});
@@ -170,16 +156,16 @@ public:
secondType.prototype = Storage::Synchronization::ImportedType{"Object2"};
thirdType.prototype = Storage::Synchronization::ImportedType{"Object3"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
- .WillByDefault(Return(qmlDocument1));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))))
- .WillByDefault(Return(qmlDocument2));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
- .WillByDefault(Return(qmlDocument3));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
- .WillByDefault(Return(qmltypes1));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/types/example2.qmltypes"))))
- .WillByDefault(Return(qmltypes2));
+ setContent(u"/path/First.qml", qmlDocument1);
+ setContent(u"/path/First2.qml", qmlDocument2);
+ setContent(u"/path/Second.qml", qmlDocument3);
+ setContent(u"/path/example.qmltypes", qmltypes1);
+ setContent(u"/path/types/example2.qmltypes", qmltypes2);
+ setContent(u"/path/one/First.qml", qmlDocument1);
+ setContent(u"/path/one/Second.qml", qmlDocument2);
+ setContent(u"/path/two/Third.qml", qmlDocument3);
+ setContent(u"/path/one/example.qmltypes", qmltypes1);
+ setContent(u"/path/two/example2.qmltypes", qmltypes2);
ON_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _))
.WillByDefault([&](auto, auto &imports, auto, auto) {
@@ -208,6 +194,76 @@ public:
});
}
+ void setFilesDontChanged(const QmlDesigner::SourceIds &sourceIds)
+ {
+ for (auto sourceId : sourceIds) {
+ ON_CALL(fileSystemMock, fileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 2, 421}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 2, 421}));
+ }
+ }
+
+ void setFilesChanged(const QmlDesigner::SourceIds &sourceIds)
+ {
+ for (auto sourceId : sourceIds) {
+ ON_CALL(fileSystemMock, fileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 1, 21}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 2, 421}));
+ }
+ }
+
+ void setFilesAdded(const QmlDesigner::SourceIds &sourceIds)
+ {
+ for (auto sourceId : sourceIds) {
+ ON_CALL(fileSystemMock, fileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 1, 21}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{}));
+ }
+ }
+
+ void setFilesRemoved(const QmlDesigner::SourceIds &sourceIds)
+ {
+ for (auto sourceId : sourceIds) {
+ ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))).WillByDefault(Return(FileStatus{}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{sourceId, 1, 21}));
+ }
+ }
+
+ void setFilesDontExists(const QmlDesigner::SourceIds &sourceIds)
+ {
+ for (auto sourceId : sourceIds) {
+ ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))).WillByDefault(Return(FileStatus{}));
+ ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId)))
+ .WillByDefault(Return(FileStatus{}));
+ }
+ }
+
+ void setQmlFileNames(QStringView directoryPath, const QStringList &qmlFileNames)
+ {
+ ON_CALL(fileSystemMock, qmlFileNames(Eq(directoryPath))).WillByDefault(Return(qmlFileNames));
+ }
+
+ void setProjectDatas(SourceId directoryPathSourceId,
+ const QmlDesigner::Storage::Synchronization::ProjectDatas &projectDatas)
+ {
+ ON_CALL(projectStorageMock, fetchProjectDatas(Eq(directoryPathSourceId)))
+ .WillByDefault(Return(projectDatas));
+ }
+
+ void setContent(QStringView path, const QString &content)
+ {
+ ON_CALL(fileSystemMock, contentAsQString(Eq(path))).WillByDefault(Return(content));
+ }
+
+ void setExpectedContent(QStringView path, const QString &content)
+ {
+ EXPECT_CALL(fileSystemMock, contentAsQString(Eq(path))).WillRepeatedly(Return(content));
+ }
+
protected:
NiceMock<FileSystemMock> fileSystemMock;
NiceMock<ProjectStorageMock> projectStorageMock;
@@ -218,12 +274,14 @@ protected:
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage};
+ NiceMock<ProjectStoragePathWatcherMock> patchWatcherMock;
QmlDesigner::ProjectStorageUpdater updater{fileSystemMock,
projectStorageMock,
fileStatusCache,
sourcePathCache,
qmlDocumentParserMock,
- qmlTypesParserMock};
+ qmlTypesParserMock,
+ patchWatcherMock};
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/types/example2.qmltypes");
SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
@@ -281,22 +339,31 @@ protected:
QString qmltypes1{"Module {\ndependencies: [module1]}"};
QString qmltypes2{"Module {\ndependencies: [module2]}"};
QStringList directories = {"/path"};
+ QStringList directories2 = {"/path/one", "/path/two"};
+ QStringList directories3 = {"/path/one", "/path/two", "/path/three"};
+ QmlDesigner::ProjectPartId projectPartId = QmlDesigner::ProjectPartId::create(1);
+ SourceId path1SourceId = sourcePathCache.sourceId("/path/one/.");
+ SourceId path2SourceId = sourcePathCache.sourceId("/path/two/.");
+ SourceId path3SourceId = sourcePathCache.sourceId("/path/three/.");
+ SourceId qmldir1SourceId = sourcePathCache.sourceId("/path/one/qmldir");
+ SourceId qmldir2SourceId = sourcePathCache.sourceId("/path/two/qmldir");
+ SourceId qmldir3SourceId = sourcePathCache.sourceId("/path/three/qmldir");
+ SourceId firstSourceId = sourcePathCache.sourceId("/path/one/First.qml");
+ SourceId secondSourceId = sourcePathCache.sourceId("/path/one/Second.qml");
+ SourceId thirdSourceId = sourcePathCache.sourceId("/path/two/Third.qml");
+ SourceId qmltypes1SourceId = sourcePathCache.sourceId("/path/one/example.qmltypes");
+ SourceId qmltypes2SourceId = sourcePathCache.sourceId("/path/two/example2.qmltypes");
};
TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
{
+ SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir");
+ SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir");
SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir");
+ SourceId path3SourceId = sourcePathCache.sourceId("/path/three/.");
QStringList directories = {"/path/one", "/path/two", "/path/three"};
- ON_CALL(fileSystemMock, fileStatus(_)).WillByDefault([](auto sourceId) {
- return FileStatus{sourceId, 21, 421};
- });
- ON_CALL(projectStorageMock, fetchFileStatus(_)).WillByDefault([](auto sourceId) {
- return FileStatus{sourceId, 2, 421};
- });
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDir3PathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDir3PathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDir3PathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDir3PathSourceId, 21, 421}));
+ setFilesChanged({qmlDir1PathSourceId, qmlDir2PathSourceId});
+ setFilesDontChanged({qmlDir3PathSourceId, path3SourceId});
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/one/qmldir"))));
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir"))));
@@ -306,9 +373,9 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlDirPathsIfFileStatusIsDifferent)
TEST_F(ProjectStorageUpdater, RequestFileStatusFromFileSystem)
{
- EXPECT_CALL(fileSystemMock, fileStatus(Ne(qmlDirPathSourceId))).Times(AnyNumber());
+ EXPECT_CALL(fileSystemMock, fileStatus(Ne(directoryPathSourceId))).Times(AnyNumber());
- EXPECT_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)));
+ EXPECT_CALL(fileSystemMock, fileStatus(Eq(directoryPathSourceId)));
updater.update(directories, {});
}
@@ -317,9 +384,8 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypes)
{
QString qmldir{R"(module Example
typeinfo example.qmltypes)"};
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path")))).WillByDefault(Return(QStringList{}));
- EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillRepeatedly(Return(qmldir));
+ setQmlFileNames(u"/path", {});
+ setExpectedContent(u"/path/qmldir", qmldir);
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
@@ -330,43 +396,25 @@ TEST_F(ProjectStorageUpdater, GetContentForQmlTypesIfProjectStorageFileStatusIsI
{
QString qmldir{R"(module Example
typeinfo example.qmltypes)"};
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path")))).WillByDefault(Return(QStringList{}));
- EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillRepeatedly(Return(qmldir));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypesPathSourceId)))
- .WillByDefault(Return(FileStatus{}));
+ setQmlFileNames(u"/path", {});
+ setExpectedContent(u"/path/qmldir", qmldir);
+ setFilesAdded({qmltypesPathSourceId});
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))));
updater.update(directories, {});
}
-TEST_F(ProjectStorageUpdater, DontGetContentForQmlTypesIfFileSystemFileStatusIsInvalid)
-{
- QString qmldir{R"(module Example
- typeinfo example.qmltypes)"};
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path")))).WillByDefault(Return(QStringList{}));
- EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillRepeatedly(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId))).WillByDefault(Return(FileStatus{}));
-
- EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))).Times(0);
-
- updater.update(directories, {});
-}
-
TEST_F(ProjectStorageUpdater, ParseQmlTypes)
{
QString qmldir{R"(module Example
typeinfo example.qmltypes
typeinfo types/example2.qmltypes)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
QString qmltypes{"Module {\ndependencies: []}"};
QString qmltypes2{"Module {\ndependencies: [foo]}"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
- .WillByDefault(Return(qmltypes));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/types/example2.qmltypes"))))
- .WillByDefault(Return(qmltypes2));
+ setContent(u"/path/example.qmltypes", qmltypes);
+ setContent(u"/path/types/example2.qmltypes", qmltypes2);
EXPECT_CALL(qmlTypesParserMock,
parse(qmltypes, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
@@ -378,12 +426,7 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes)
TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
{
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypesPathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
+ setFilesDontChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId});
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
@@ -396,9 +439,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
Storage::Synchronization::Version{2, 3},
qmltypesPathSourceId};
QString qmltypes{"Module {\ndependencies: []}"};
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path")))).WillByDefault(Return(QStringList{}));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
- .WillByDefault(Return(qmltypes));
+ setQmlFileNames(u"/path", {});
+ setContent(u"/path/example.qmltypes", qmltypes);
ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
.WillByDefault([&](auto, auto &imports, auto &types, auto) {
types.push_back(objectType);
@@ -415,32 +457,36 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmltypesPathSourceId, 21, 421))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmltypesPathSourceId, 1, 21))),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
qmltypesPathSourceId,
exampleCppNativeModuleId,
FileType::QmlTypes))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)))));
+ UnorderedElementsAre(directoryPathSourceId)))));
updater.update(directories, {});
}
+TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesThrowsIfQmltpesDoesNotExists)
+{
+ Storage::Synchronization::Import import{qmlModuleId,
+ Storage::Synchronization::Version{2, 3},
+ qmltypesPathSourceId};
+ setFilesDontExists({qmltypesPathSourceId});
+
+ ASSERT_THROW(updater.update(directories, {}), QmlDesigner::CannotParseQmlTypesFile);
+}
+
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
{
QString qmltypes{"Module {\ndependencies: []}"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
- .WillByDefault(Return(qmltypes));
+ setContent(u"/path/example.qmltypes", qmltypes);
ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
.WillByDefault([&](auto, auto &, auto &types, auto) { types.push_back(objectType); });
- ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypesPathSourceId, 2, 421}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 2, 421}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 2, 421}));
+ setFilesDontChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId});
EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
@@ -450,19 +496,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
TEST_F(ProjectStorageUpdater, GetContentForQmlDocuments)
{
SourceId oldSecondSourceId3 = sourcePathCache.sourceId("/path/OldSecond.qml");
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml", "OldSecond.qml", "Second.qml"}));
- ON_CALL(fileSystemMock, fileStatus(Eq(oldSecondSourceId3)))
- .WillByDefault(Return(FileStatus{oldSecondSourceId3, 22, 14}));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/OldSecond.qml"))))
- .WillByDefault(Return(qmlDocument3));
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml", "OldSecond.qml", "Second.qml"});
+ setFilesAdded({oldSecondSourceId3});
+ setContent(u"/path/OldSecond.qml", qmlDocument3);
QString qmldir{R"(module Example
FirstType 1.0 First.qml
FirstTypeV2 2.2 First2.qml
SecondType 2.1 OldSecond.qml
SecondType 2.2 Second.qml)"};
- EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir"))))
- .WillRepeatedly(Return(qmldir));
+ setExpectedContent(u"/path/qmldir", qmldir);
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))));
EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))));
@@ -481,13 +523,10 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocuments)
QString qmlDocument1{"First{}"};
QString qmlDocument2{"Second{}"};
QString qmlDocument3{"Third{}"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
- .WillByDefault(Return(qmlDocument1));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First2.qml"))))
- .WillByDefault(Return(qmlDocument2));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/Second.qml"))))
- .WillByDefault(Return(qmlDocument3));
+ setContent(u"/path/qmldir", qmldir);
+ setContent(u"/path/First.qml", qmlDocument1);
+ setContent(u"/path/First2.qml", qmlDocument2);
+ setContent(u"/path/Second.qml", qmlDocument3);
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument1, _, _, _));
EXPECT_CALL(qmlDocumentParserMock, parse(qmlDocument2, _, _, _));
@@ -500,7 +539,7 @@ TEST_F(ProjectStorageUpdater, ParseQmlDocumentsWithNonExistingQmlDocumentThrows)
{
QString qmldir{R"(module Example
NonexitingType 1.0 NonexitingType.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
ASSERT_THROW(updater.update(directories, {}), QmlDesigner::CannotParseQmlDocumentFile);
}
@@ -511,7 +550,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
FirstType 1.0 First.qml
FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(
projectStorageMock,
@@ -555,20 +594,25 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocuments)
qmlDocumentSourceId2,
qmlDocumentSourceId3)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12),
- IsFileStatus(qmlDocumentSourceId2, 22, 13),
- IsFileStatus(qmlDocumentSourceId3, 22, 14))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(
- IsProjectData(qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
- qmlDocumentSourceId3,
- ModuleId{},
- FileType::QmlDocument))))));
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
updater.update(directories, {});
}
@@ -577,50 +621,54 @@ TEST_F(ProjectStorageUpdater, SynchronizeAddOnlyQmlDocumentInDirectory)
{
QString qmldir{R"(module Example
FirstType 1.0 First.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId});
+ setFilesDontChanged({qmlDirPathSourceId, qmlDocumentSourceId1});
+ setFilesAdded({qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
- EXPECT_CALL(
- projectStorageMock,
- synchronize(AllOf(
- Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
- Field(&SynchronizationPackage::types,
- UnorderedElementsAre(
- AllOf(IsStorageType("First.qml",
- Storage::Synchronization::ImportedType{"Object"},
- TypeTraits::Reference,
- qmlDocumentSourceId1,
- Storage::Synchronization::ChangeLevel::Minimal),
- Field(&Storage::Synchronization::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
- IsExportedType(pathModuleId, "First", -1, -1)))),
- AllOf(IsStorageType("First2.qml",
- Storage::Synchronization::ImportedType{"Object2"},
- TypeTraits::Reference,
- qmlDocumentSourceId2,
- Storage::Synchronization::ChangeLevel::Full),
- Field(&Storage::Synchronization::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(pathModuleId, "First2", -1, -1)))))),
- Field(&SynchronizationPackage::updatedSourceIds,
- UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
- Field(&SynchronizationPackage::updatedFileStatusSourceIds,
- UnorderedElementsAre(qmlDocumentSourceId2)),
- Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId2, 22, 13))),
- Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
- Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
- qmlDocumentSourceId1,
- ModuleId{},
- FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
- qmlDocumentSourceId2,
- ModuleId{},
- FileType::QmlDocument))))));
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import2)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(directoryPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
updater.update(directories, {});
}
@@ -631,22 +679,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemovesQmlDocument)
FirstType 1.0 First.qml
FirstType 2.2 First2.qml
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 422}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId3)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, -1, -1}));
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}}));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesRemoved({qmlDocumentSourceId3});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
EXPECT_CALL(projectStorageMock,
synchronize(AllOf(
@@ -679,15 +720,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemovesQmlDocument)
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 422))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
qmlDocumentSourceId1,
ModuleId{},
FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
+ IsProjectData(directoryPathSourceId,
qmlDocumentSourceId2,
ModuleId{},
FileType::QmlDocument))))));
@@ -700,19 +741,13 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemovesQmlDocumentInQmldirOnly)
QString qmldir{R"(module Example
FirstType 1.0 First.qml
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 422}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
EXPECT_CALL(
projectStorageMock,
@@ -740,15 +775,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeRemovesQmlDocumentInQmldirOnly)
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 422))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
qmlDocumentSourceId1,
ModuleId{},
FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
+ IsProjectData(directoryPathSourceId,
qmlDocumentSourceId2,
ModuleId{},
FileType::QmlDocument))))));
@@ -762,19 +797,13 @@ TEST_F(ProjectStorageUpdater, SynchronizeAddQmlDocumentToQmldir)
FirstType 1.0 First.qml
FirstType 2.2 First2.qml
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 422}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
EXPECT_CALL(
projectStorageMock,
@@ -804,15 +833,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeAddQmlDocumentToQmldir)
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 422))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
qmlDocumentSourceId1,
ModuleId{},
FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
+ IsProjectData(directoryPathSourceId,
qmlDocumentSourceId2,
ModuleId{},
FileType::QmlDocument))))));
@@ -820,24 +849,18 @@ TEST_F(ProjectStorageUpdater, SynchronizeAddQmlDocumentToQmldir)
updater.update(directories, {});
}
-TEST_F(ProjectStorageUpdater, SynchronizeAddQmlDocumentToDirectory)
+TEST_F(ProjectStorageUpdater, SynchronizeRemoveQmlDocumentFromQmldir)
{
QString qmldir{R"(module Example
FirstType 1.0 First.qml
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 422}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId1)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId1, 22, 2}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 2}));
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml", "First2.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesChanged({qmlDirPathSourceId});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
EXPECT_CALL(
projectStorageMock,
@@ -865,15 +888,15 @@ TEST_F(ProjectStorageUpdater, SynchronizeAddQmlDocumentToDirectory)
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 422))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(qmlDirPathSourceId,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
qmlDocumentSourceId1,
ModuleId{},
FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
+ IsProjectData(directoryPathSourceId,
qmlDocumentSourceId2,
ModuleId{},
FileType::QmlDocument))))));
@@ -887,9 +910,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
FirstType 1.0 First.qml
FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId3});
EXPECT_CALL(
projectStorageMock,
@@ -928,21 +950,26 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
qmlDocumentSourceId2,
qmlDocumentSourceId3)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12),
- IsFileStatus(qmlDocumentSourceId2, 22, 13))),
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
+ UnorderedElementsAre(directoryPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(
- IsProjectData(qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument),
- IsProjectData(qmlDirPathSourceId,
- qmlDocumentSourceId3,
- ModuleId{},
- FileType::QmlDocument))))));
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
updater.update(directories, {});
}
@@ -953,44 +980,21 @@ TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
FirstType 1.1 First.qml
FirstType 2.2 First2.qml
SecondType 2.2 Second.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId3)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId3, 22, 14}));
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId3});
updater.pathsWithIdsChanged({});
}
-TEST_F(ProjectStorageUpdater, AddSourceIdForForInvalidQmldirFileStatus)
-{
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
- {qmlDirPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}));
- ON_CALL(fileSystemMock, fileStatus(Eq(qmlDirPathSourceId))).WillByDefault(Return(FileStatus{}));
-
- EXPECT_CALL(projectStorageMock,
- synchronize(AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
- Field(&SynchronizationPackage::types, IsEmpty()),
- Field(&SynchronizationPackage::updatedSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId,
- qmltypesPathSourceId,
- qmltypes2PathSourceId)),
- Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
- Field(&SynchronizationPackage::updatedFileStatusSourceIds, IsEmpty()),
- Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
- updater.update(directories, {});
-}
-
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
{
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
- {qmlDirPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
- {qmlDirPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ setFilesDontChanged({qmlDirPathSourceId});
EXPECT_CALL(
projectStorageMock,
@@ -1019,10 +1023,10 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
qmlDocumentSourceId1,
qmlDocumentSourceId2)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
- IsFileStatus(qmltypes2PathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12),
- IsFileStatus(qmlDocumentSourceId2, 22, 13))),
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmltypesPathSourceId,
qmltypes2PathSourceId,
@@ -1035,18 +1039,13 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedFiles)
{
- ON_CALL(projectStorageMock, fetchProjectDatas(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(QmlDesigner::Storage::Synchronization::ProjectDatas{
- {qmlDirPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
- {qmlDirPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
- {qmlDirPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
- {qmlDirPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDirPathSourceId)))
- .WillByDefault(Return(FileStatus{qmlDirPathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmlDocumentSourceId2)))
- .WillByDefault(Return(FileStatus{qmlDocumentSourceId2, 22, 13}));
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ setFilesDontChanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2});
EXPECT_CALL(
projectStorageMock,
@@ -1064,8 +1063,8 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedF
Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12))),
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21))),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmlDocumentSourceId1)),
Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
@@ -1097,8 +1096,8 @@ TEST_F(ProjectStorageUpdater, UpdateQmlTypesFiles)
Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421),
- IsFileStatus(qmltypes2PathSourceId, 21, 421))),
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
Field(&SynchronizationPackage::projectDatas,
@@ -1117,8 +1116,7 @@ TEST_F(ProjectStorageUpdater, UpdateQmlTypesFiles)
TEST_F(ProjectStorageUpdater, DontUpdateQmlTypesFilesIfUnchanged)
{
- ON_CALL(projectStorageMock, fetchFileStatus(Eq(qmltypes2PathSourceId)))
- .WillByDefault(Return(FileStatus{qmltypes2PathSourceId, 21, 421}));
+ setFilesDontChanged({qmltypes2PathSourceId});
EXPECT_CALL(projectStorageMock,
synchronize(
@@ -1127,7 +1125,7 @@ TEST_F(ProjectStorageUpdater, DontUpdateQmlTypesFilesIfUnchanged)
Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmltypesPathSourceId)),
Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 21, 421))),
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21))),
Field(&SynchronizationPackage::updatedFileStatusSourceIds,
UnorderedElementsAre(qmltypesPathSourceId)),
Field(&SynchronizationPackage::projectDatas,
@@ -1146,38 +1144,39 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithDifferentVersionButSame
FirstType 1.0 First.qml
FirstType 1.1 First.qml
FirstType 6.0 First.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setQmlFileNames(u"/path", {"First.qml"});
- EXPECT_CALL(
- projectStorageMock,
- synchronize(AllOf(
- Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
- Field(&SynchronizationPackage::types,
- UnorderedElementsAre(AllOf(
- IsStorageType("First.qml",
- Storage::Synchronization::ImportedType{"Object"},
- TypeTraits::Reference,
- qmlDocumentSourceId1,
- Storage::Synchronization::ChangeLevel::Full),
- Field(&Storage::Synchronization::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
- IsExportedType(exampleModuleId, "FirstType", 1, 1),
- IsExportedType(exampleModuleId, "FirstType", 6, 0),
- IsExportedType(pathModuleId, "First", -1, -1)))))),
- Field(&SynchronizationPackage::updatedSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
- Field(&SynchronizationPackage::updatedFileStatusSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
- Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12))),
- Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
- Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(
- qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument))))));
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(AllOf(
+ IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(exampleModuleId, "FirstType", 1, 1),
+ IsExportedType(exampleModuleId, "FirstType", 6, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument))))));
updater.update(directories, {});
}
@@ -1187,52 +1186,50 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithDifferentTypeNameButSam
QString qmldir{R"(module Example
FirstType 1.0 First.qml
FirstType2 1.0 First.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setQmlFileNames(u"/path", {"First.qml"});
- EXPECT_CALL(
- projectStorageMock,
- synchronize(AllOf(
- Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
- Field(&SynchronizationPackage::types,
- UnorderedElementsAre(AllOf(
- IsStorageType("First.qml",
- Storage::Synchronization::ImportedType{"Object"},
- TypeTraits::Reference,
- qmlDocumentSourceId1,
- Storage::Synchronization::ChangeLevel::Full),
- Field(&Storage::Synchronization::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
- IsExportedType(exampleModuleId, "FirstType2", 1, 0),
- IsExportedType(pathModuleId, "First", -1, -1)))))),
- Field(&SynchronizationPackage::updatedSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
- Field(&SynchronizationPackage::updatedFileStatusSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
- Field(&SynchronizationPackage::fileStatuses,
- UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 21, 421),
- IsFileStatus(qmlDocumentSourceId1, 22, 12))),
- Field(&SynchronizationPackage::updatedProjectSourceIds,
- UnorderedElementsAre(qmlDirPathSourceId)),
- Field(&SynchronizationPackage::projectDatas,
- UnorderedElementsAre(IsProjectData(
- qmlDirPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument))))));
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(AllOf(
+ IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(exampleModuleId, "FirstType2", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument))))));
updater.update(directories, {});
}
TEST_F(ProjectStorageUpdater, DontSynchronizeSelectors)
{
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/+First.qml"))))
- .WillByDefault(Return(qmlDocument1));
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qml/+First.qml"))))
- .WillByDefault(Return(qmlDocument1));
+ setContent(u"/path/+First.qml", qmlDocument1);
+ setContent(u"/path/qml/+First.qml", qmlDocument1);
QString qmldir{R"(module Example
FirstType 1.0 +First.qml)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
- ON_CALL(fileSystemMock, qmlFileNames(Eq(QString("/path"))))
- .WillByDefault(Return(QStringList{"First.qml"}));
+ setContent(u"/path/qmldir", qmldir);
+ setQmlFileNames(u"/path", {"First.qml"});
EXPECT_CALL(projectStorageMock,
synchronize(Not(Field(
@@ -1251,7 +1248,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependencies)
typeinfo example.qmltypes
typeinfo types/example2.qmltypes
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(projectStorageMock,
synchronize(
@@ -1283,7 +1280,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithDoubleEntries)
typeinfo example.qmltypes
typeinfo types/example2.qmltypes
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(projectStorageMock,
synchronize(
@@ -1315,7 +1312,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithCollidingImports)
typeinfo example.qmltypes
typeinfo types/example2.qmltypes
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(projectStorageMock,
synchronize(
@@ -1344,7 +1341,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirWithNoDependencies)
typeinfo example.qmltypes
typeinfo types/example2.qmltypes
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(projectStorageMock,
synchronize(
@@ -1362,7 +1359,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirImports)
import QML 2.1
import Quick
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(
projectStorageMock,
@@ -1401,7 +1398,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirWithNoImports)
{
QString qmldir{R"(module Example
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(projectStorageMock,
synchronize(AllOf(Field(&SynchronizationPackage::moduleExportedImports, IsEmpty()),
@@ -1419,7 +1416,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirImportsWithDoubleEntries)
import Quick
import Qml
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(
projectStorageMock,
@@ -1461,7 +1458,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirOptionalImports)
import QML 2.1
optional import Quick
)"};
- ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
+ setContent(u"/path/qmldir", qmldir);
EXPECT_CALL(
projectStorageMock,
@@ -1496,4 +1493,453 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirOptionalImports)
updater.update(directories, {});
}
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectories)
+{
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Directory,
+ {path1SourceId, path2SourceId, path3SourceId}})));
+
+ updater.update(directories3, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotExists)
+{
+ setFilesDontExists({path2SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Directory,
+ {path1SourceId, path3SourceId}})));
+
+ updater.update(directories3, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotChanged)
+{
+ setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Directory,
+ {path1SourceId, path2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryRemoved)
+{
+ setFilesRemoved({qmldir1SourceId, path1SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(
+ IdPaths{projectPartId, QmlDesigner::SourceType::Directory, {path2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirs)
+{
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlDir,
+ {qmldir1SourceId, qmldir2SourceId, qmldir3SourceId}})));
+
+ updater.update(directories3, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotExists)
+{
+ setFilesDontExists({qmldir2SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlDir,
+ {qmldir1SourceId, qmldir3SourceId}})));
+
+ updater.update(directories3, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotChanged)
+{
+ setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlDir,
+ {qmldir1SourceId, qmldir2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirRemoved)
+{
+ setFilesRemoved({qmldir1SourceId, path1SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(
+ IdPaths{projectPartId, QmlDesigner::SourceType::QmlDir, {qmldir2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFiles)
+{
+ QString qmldir1{R"(module Example
+ FirstType 1.0 First.qml
+ Second 1.0 Second.qml)"};
+ setQmlFileNames(u"/path/one", {"First.qml", "Second.qml"});
+ setQmlFileNames(u"/path/two", {"Third.qml"});
+ setContent(u"/path/one/qmldir", qmldir1);
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {firstSourceId, secondSourceId, thirdSourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesDontChanged)
+{
+ QString qmldir1{R"(module Example
+ FirstType 1.0 First.qml
+ Second 1.0 Second.qml)"};
+ setQmlFileNames(u"/path/one", {"First.qml", "Second.qml"});
+ setQmlFileNames(u"/path/two", {"Third.qml"});
+ setContent(u"/path/one/qmldir", qmldir1);
+ setFilesDontChanged({firstSourceId, secondSourceId, thirdSourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {firstSourceId, secondSourceId, thirdSourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesChanged)
+{
+ setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId});
+ setFilesChanged({firstSourceId, secondSourceId, thirdSourceId});
+ setProjectDatas(path1SourceId,
+ {{path1SourceId, firstSourceId, exampleModuleId, FileType::QmlDocument},
+ {path1SourceId, secondSourceId, exampleModuleId, FileType::QmlDocument}});
+ setProjectDatas(path2SourceId,
+ {{path2SourceId, thirdSourceId, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {firstSourceId, secondSourceId, thirdSourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFilesAndDirectoriesDontChanged)
+{
+ setFilesDontChanged({qmldir1SourceId,
+ qmldir2SourceId,
+ path1SourceId,
+ path2SourceId,
+ firstSourceId,
+ secondSourceId,
+ thirdSourceId});
+ setProjectDatas(path1SourceId,
+ {{path1SourceId, firstSourceId, exampleModuleId, FileType::QmlDocument},
+ {path1SourceId, secondSourceId, exampleModuleId, FileType::QmlDocument}});
+ setProjectDatas(path2SourceId,
+ {{path2SourceId, thirdSourceId, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {firstSourceId, secondSourceId, thirdSourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesInQmldir)
+{
+ QString qmldir1{R"(module Example
+ typeinfo example.qmltypes)"};
+ QString qmldir2{R"(module Example2
+ typeinfo example2.qmltypes)"};
+ setContent(u"/path/one/qmldir", qmldir1);
+ setContent(u"/path/two/qmldir", qmldir2);
+
+ setFilesDontChanged({firstSourceId, secondSourceId, thirdSourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlTypes,
+ {qmltypes1SourceId, qmltypes2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesInQmldirDontChanged)
+{
+ QString qmldir1{R"(module Example
+ typeinfo example.qmltypes)"};
+ QString qmldir2{R"(module Example2
+ typeinfo example2.qmltypes)"};
+ setContent(u"/path/one/qmldir", qmldir1);
+ setContent(u"/path/two/qmldir", qmldir2);
+ setFilesDontChanged({qmltypes1SourceId, qmltypes2SourceId});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlTypes,
+ {qmltypes1SourceId, qmltypes2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesChanged)
+{
+ setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId});
+ setFilesChanged({qmltypes1SourceId, qmltypes2SourceId});
+ setProjectDatas(path1SourceId,
+ {{path1SourceId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}});
+ setProjectDatas(path2SourceId,
+ {{path2SourceId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlTypes,
+ {qmltypes1SourceId, qmltypes2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesAndDirectoriesDontChanged)
+{
+ setFilesDontChanged({qmldir1SourceId,
+ qmldir2SourceId,
+ path1SourceId,
+ path2SourceId,
+ qmltypes1SourceId,
+ qmltypes2SourceId});
+ setProjectDatas(path1SourceId,
+ {{path1SourceId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}});
+ setProjectDatas(path2SourceId,
+ {{path2SourceId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}});
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlTypes,
+ {qmltypes1SourceId, qmltypes2SourceId}})));
+
+ updater.update(directories2, {}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, UpdatePathWatcherBuiltinQmltypesFiles)
+{
+ QString builtinQmltyplesPath1{"/path/one/example.qmltypes"};
+ QString builtinQmltyplesPath2{"/path/two/example2.qmltypes"};
+ setContent(builtinQmltyplesPath1, qmltypes1);
+ setContent(builtinQmltyplesPath2, qmltypes2);
+
+ EXPECT_CALL(patchWatcherMock,
+ updateIdPaths(Contains(IdPaths{projectPartId,
+ QmlDesigner::SourceType::QmlTypes,
+ {qmltypes1SourceId, qmltypes2SourceId}})));
+
+ updater.update({}, {builtinQmltyplesPath1, builtinQmltyplesPath2}, projectPartId);
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldir)
+{
+ setFilesDontExists({qmlDirPathSourceId});
+ setFilesChanged({directoryPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.update(directories, {});
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldirThrowsIfQmlDocumentDoesNotExists)
+{
+ setFilesDontExists({qmlDirPathSourceId, qmlDocumentSourceId1});
+ setFilesAdded({directoryPathSourceId});
+
+ ASSERT_THROW(updater.update(directories, {}), QmlDesigner::CannotParseQmlDocumentFile);
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldirThrowsIfDirectoryDoesNotExists)
+{
+ setFilesDontExists({qmlDirPathSourceId, directoryPathSourceId});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types, IsEmpty()),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses, IsEmpty()),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.update(directories, {});
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldirAddQmlDocument)
+{
+ setFilesDontExists({qmlDirPathSourceId});
+ setFilesChanged({directoryPathSourceId});
+ setFilesAdded({qmlDocumentSourceId3});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import3)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(AllOf(
+ IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.update(directories, {});
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldirRemovesQmlDocument)
+{
+ setFilesDontExists({qmlDirPathSourceId});
+ setFilesChanged({directoryPathSourceId});
+ setFilesRemoved({qmlDocumentSourceId3});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types, IsEmpty()),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.update(directories, {});
+}
+
} // namespace
diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp
index fd2a333964..7ed83ef891 100644
--- a/tests/unit/unittest/qmldocumentparser-test.cpp
+++ b/tests/unit/unittest/qmldocumentparser-test.cpp
@@ -11,7 +11,7 @@
namespace {
-namespace Storage = QmlDesigner::Storage;
+namespace Storage = QmlDesigner::Storage::Synchronization;
using QmlDesigner::ModuleId;
using QmlDesigner::SourceContextId;
using QmlDesigner::SourceId;
@@ -177,9 +177,10 @@ TEST_F(QmlDocumentParser, Properties)
auto type = parser.parse(R"(Example{ property int foo })", imports, qmlFileSourceId, directoryPath);
ASSERT_THAT(type.propertyDeclarations,
- UnorderedElementsAre(IsPropertyDeclaration("foo",
- Storage::ImportedType{"int"},
- Storage::PropertyDeclarationTraits::None)));
+ UnorderedElementsAre(
+ IsPropertyDeclaration("foo",
+ Storage::ImportedType{"int"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, QualifiedProperties)
@@ -199,7 +200,7 @@ TEST_F(QmlDocumentParser, QualifiedProperties)
Storage::Import{exampleModuleId,
Storage::Version{2, 1},
qmlFileSourceId}),
- Storage::PropertyDeclarationTraits::None)));
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, EnumerationInProperties)
@@ -211,9 +212,10 @@ TEST_F(QmlDocumentParser, EnumerationInProperties)
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
- UnorderedElementsAre(IsPropertyDeclaration("foo",
- Storage::ImportedType("Enumeration.Foo"),
- Storage::PropertyDeclarationTraits::None)));
+ UnorderedElementsAre(
+ IsPropertyDeclaration("foo",
+ Storage::ImportedType("Enumeration.Foo"),
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, QualifiedEnumerationInProperties)
@@ -233,7 +235,7 @@ TEST_F(QmlDocumentParser, QualifiedEnumerationInProperties)
Storage::Import{exampleModuleId,
Storage::Version{2, 1},
qmlFileSourceId}),
- Storage::PropertyDeclarationTraits::None)));
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, Imports)
@@ -393,9 +395,10 @@ TEST_F(QmlDocumentParser, AliasItemProperties)
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
- UnorderedElementsAre(IsPropertyDeclaration("delegate",
- Storage::ImportedType{"Item"},
- Storage::PropertyDeclarationTraits::None)));
+ UnorderedElementsAre(
+ IsPropertyDeclaration("delegate",
+ Storage::ImportedType{"Item"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, AliasProperties)
@@ -411,10 +414,11 @@ TEST_F(QmlDocumentParser, AliasProperties)
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
- UnorderedElementsAre(IsAliasPropertyDeclaration("text",
- Storage::ImportedType{"Item"},
- Storage::PropertyDeclarationTraits::None,
- "text2")));
+ UnorderedElementsAre(
+ IsAliasPropertyDeclaration("text",
+ Storage::ImportedType{"Item"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None,
+ "text2")));
}
TEST_F(QmlDocumentParser, IndirectAliasProperties)
@@ -430,11 +434,12 @@ TEST_F(QmlDocumentParser, IndirectAliasProperties)
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
- UnorderedElementsAre(IsAliasPropertyDeclaration("textSize",
- Storage::ImportedType{"Item"},
- Storage::PropertyDeclarationTraits::None,
- "text",
- "size")));
+ UnorderedElementsAre(
+ IsAliasPropertyDeclaration("textSize",
+ Storage::ImportedType{"Item"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None,
+ "text",
+ "size")));
}
TEST_F(QmlDocumentParser, InvalidAliasPropertiesAreSkipped)
@@ -465,7 +470,7 @@ TEST_F(QmlDocumentParser, ListProperty)
UnorderedElementsAre(
IsPropertyDeclaration("foos",
Storage::ImportedType{"Foo"},
- Storage::PropertyDeclarationTraits::IsList)));
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsList)));
}
TEST_F(QmlDocumentParser, AliasOnListProperty)
@@ -486,7 +491,7 @@ TEST_F(QmlDocumentParser, AliasOnListProperty)
UnorderedElementsAre(
IsPropertyDeclaration("foos",
Storage::ImportedType{"Foo"},
- Storage::PropertyDeclarationTraits::IsList)));
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsList)));
}
TEST_F(QmlDocumentParser, QualifiedListProperty)
@@ -507,7 +512,7 @@ TEST_F(QmlDocumentParser, QualifiedListProperty)
Storage::Import{exampleModuleId,
Storage::Version{2, 1},
qmlFileSourceId}},
- Storage::PropertyDeclarationTraits::IsList)));
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsList)));
}
} // namespace
diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp
index f7f8548c79..405eec57df 100644
--- a/tests/unit/unittest/qmltypesparser-test.cpp
+++ b/tests/unit/unittest/qmltypesparser-test.cpp
@@ -12,7 +12,7 @@
namespace {
-namespace Storage = QmlDesigner::Storage;
+namespace Storage = QmlDesigner::Storage::Synchronization;
using QmlDesigner::ModuleId;
using QmlDesigner::SourceContextId;
using QmlDesigner::SourceId;
@@ -36,18 +36,20 @@ MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + Pr
return Storage::ImportedTypeName{prototype} == type.prototype;
}
-MATCHER_P4(IsType,
+MATCHER_P5(IsType,
typeName,
prototype,
+ extension,
traits,
sourceId,
std::string(negation ? "isn't " : "is ")
- + PrintToString(Storage::Type{typeName, prototype, traits, sourceId}))
+ + PrintToString(Storage::Type{typeName, prototype, extension, traits, sourceId}))
{
const Storage::Type &type = arg;
return type.typeName == typeName && type.prototype == Storage::ImportedTypeName{prototype}
- && type.traits == traits && type.sourceId == sourceId;
+ && type.extension == Storage::ImportedTypeName{extension} && type.traits == traits
+ && type.sourceId == sourceId;
}
MATCHER_P3(IsPropertyDeclaration,
@@ -152,10 +154,10 @@ protected:
Storage::Types types;
SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml-cppnative");
- QmlDesigner::Storage::ProjectData projectData{qmltypesFileSourceId,
- qmltypesFileSourceId,
- qtQmlNativeModuleId,
- Storage::FileType::QmlTypes};
+ Storage::ProjectData projectData{qmltypesFileSourceId,
+ qmltypesFileSourceId,
+ qtQmlNativeModuleId,
+ Storage::FileType::QmlTypes};
SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
ModuleId directoryModuleId{storage.moduleId("path/to/")};
};
@@ -184,6 +186,28 @@ TEST_F(QmlTypesParser, Types)
QString source{R"(import QtQuick.tooling 1.2
Module{
Component { name: "QObject"}
+ Component { name: "QQmlComponent"}})"};
+
+ parser.parse(source, imports, types, projectData);
+
+ ASSERT_THAT(types,
+ UnorderedElementsAre(IsType("QObject",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Reference,
+ qmltypesFileSourceId),
+ IsType("QQmlComponent",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Reference,
+ qmltypesFileSourceId)));
+}
+
+TEST_F(QmlTypesParser, Prototype)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"}
Component { name: "QQmlComponent"
prototype: "QObject"}})"};
@@ -192,11 +216,36 @@ TEST_F(QmlTypesParser, Types)
ASSERT_THAT(types,
UnorderedElementsAre(IsType("QObject",
Storage::ImportedType{},
- Storage::TypeTraits::Reference,
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Reference,
qmltypesFileSourceId),
IsType("QQmlComponent",
Storage::ImportedType{"QObject"},
- Storage::TypeTraits::Reference,
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Reference,
+ qmltypesFileSourceId)));
+}
+
+TEST_F(QmlTypesParser, Extension)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"}
+ Component { name: "QQmlComponent"
+ extension: "QObject"}})"};
+
+ parser.parse(source, imports, types, projectData);
+
+ ASSERT_THAT(types,
+ UnorderedElementsAre(IsType("QObject",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Reference,
+ qmltypesFileSourceId),
+ IsType("QQmlComponent",
+ Storage::ImportedType{},
+ Storage::ImportedType{"QObject"},
+ QmlDesigner::Storage::TypeTraits::Reference,
qmltypesFileSourceId)));
}
@@ -234,24 +283,25 @@ TEST_F(QmlTypesParser, Properties)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(types,
- ElementsAre(Field(
- &Storage::Type::propertyDeclarations,
- UnorderedElementsAre(
- IsPropertyDeclaration("objectName",
- Storage::ImportedType{"string"},
- Storage::PropertyDeclarationTraits::None),
- IsPropertyDeclaration("target",
- Storage::ImportedType{"QObject"},
- Storage::PropertyDeclarationTraits::IsPointer),
- IsPropertyDeclaration("progress",
- Storage::ImportedType{"double"},
- Storage::PropertyDeclarationTraits::IsReadOnly),
- IsPropertyDeclaration("targets",
- Storage::ImportedType{"QQuickItem"},
- Storage::PropertyDeclarationTraits::IsReadOnly
- | Storage::PropertyDeclarationTraits::IsList
- | Storage::PropertyDeclarationTraits::IsPointer)))));
+ ASSERT_THAT(
+ types,
+ ElementsAre(Field(
+ &Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("objectName",
+ Storage::ImportedType{"string"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None),
+ IsPropertyDeclaration("target",
+ Storage::ImportedType{"QObject"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsPointer),
+ IsPropertyDeclaration("progress",
+ Storage::ImportedType{"double"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsReadOnly),
+ IsPropertyDeclaration("targets",
+ Storage::ImportedType{"QQuickItem"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsReadOnly
+ | QmlDesigner::Storage::PropertyDeclarationTraits::IsList
+ | QmlDesigner::Storage::PropertyDeclarationTraits::IsPointer)))));
}
TEST_F(QmlTypesParser, PropertiesWithQualifiedTypes)
@@ -268,18 +318,20 @@ TEST_F(QmlTypesParser, PropertiesWithQualifiedTypes)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(types,
- Contains(Field(&Storage::Type::propertyDeclarations,
- UnorderedElementsAre(
- IsPropertyDeclaration("values",
- Storage::ImportedType{"Qt::Vector"},
- Storage::PropertyDeclarationTraits::None),
- IsPropertyDeclaration("items",
- Storage::ImportedType{"Qt::List"},
- Storage::PropertyDeclarationTraits::None),
- IsPropertyDeclaration("values2",
- Storage::ImportedType{"Qt::Vector"},
- Storage::PropertyDeclarationTraits::None)))));
+ ASSERT_THAT(
+ types,
+ Contains(
+ Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("values",
+ Storage::ImportedType{"Qt::Vector"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None),
+ IsPropertyDeclaration("items",
+ Storage::ImportedType{"Qt::List"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None),
+ IsPropertyDeclaration("values2",
+ Storage::ImportedType{"Qt::Vector"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)))));
}
TEST_F(QmlTypesParser, PropertiesWithoutType)
@@ -294,12 +346,11 @@ TEST_F(QmlTypesParser, PropertiesWithoutType)
parser.parse(source, imports, types, projectData);
ASSERT_THAT(types,
- ElementsAre(
- Field(&Storage::Type::propertyDeclarations,
- UnorderedElementsAre(
- IsPropertyDeclaration("target",
- Storage::ImportedType{"QObject"},
- Storage::PropertyDeclarationTraits::IsPointer)))));
+ ElementsAre(Field(&Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(IsPropertyDeclaration(
+ "target",
+ Storage::ImportedType{"QObject"},
+ QmlDesigner::Storage::PropertyDeclarationTraits::IsPointer)))));
}
TEST_F(QmlTypesParser, Functions)
@@ -516,26 +567,30 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsType)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(
- types,
- UnorderedElementsAre(
- AllOf(IsType("QObject::NamedColorSpace",
- Storage::ImportedType{},
- Storage::TypeTraits::Value | Storage::TypeTraits::IsEnum,
- qmltypesFileSourceId),
- Field(&Storage::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
- "QObject::NamedColorSpace",
- Storage::Version{})))),
- AllOf(IsType("QObject::VerticalLayoutDirection",
- Storage::ImportedType{},
- Storage::TypeTraits::Value | Storage::TypeTraits::IsEnum,
- qmltypesFileSourceId),
- Field(&Storage::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
- "QObject::VerticalLayoutDirection",
- Storage::Version{})))),
- _));
+ ASSERT_THAT(types,
+ UnorderedElementsAre(
+ AllOf(IsType("QObject::NamedColorSpace",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value
+ | QmlDesigner::Storage::TypeTraits::IsEnum,
+ qmltypesFileSourceId),
+ Field(&Storage::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
+ "QObject::NamedColorSpace",
+ Storage::Version{})))),
+ AllOf(IsType("QObject::VerticalLayoutDirection",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value
+ | QmlDesigner::Storage::TypeTraits::IsEnum,
+ qmltypesFileSourceId),
+ Field(&Storage::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(qtQmlNativeModuleId,
+ "QObject::VerticalLayoutDirection",
+ Storage::Version{})))),
+ _));
}
TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAlias)
@@ -562,7 +617,9 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAlias)
UnorderedElementsAre(
AllOf(IsType("QObject::NamedColorSpaces",
Storage::ImportedType{},
- Storage::TypeTraits::Value | Storage::TypeTraits::IsEnum,
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value
+ | QmlDesigner::Storage::TypeTraits::IsEnum,
qmltypesFileSourceId),
Field(&Storage::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
@@ -607,7 +664,9 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAliasToo)
UnorderedElementsAre(
AllOf(IsType("QObject::NamedColorSpaces",
Storage::ImportedType{},
- Storage::TypeTraits::Value | Storage::TypeTraits::IsEnum,
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value
+ | QmlDesigner::Storage::TypeTraits::IsEnum,
qmltypesFileSourceId),
Field(&Storage::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
@@ -643,7 +702,7 @@ TEST_F(QmlTypesParser, EnumerationIsReferencedByQualifiedName)
ElementsAre(IsPropertyDeclaration(
"colorSpace",
Storage::ImportedType{"QObject::NamedColorSpace"},
- Storage::PropertyDeclarationTraits::None)))));
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)))));
}
TEST_F(QmlTypesParser, AliasEnumerationIsReferencedByQualifiedName)
@@ -671,7 +730,7 @@ TEST_F(QmlTypesParser, AliasEnumerationIsReferencedByQualifiedName)
ElementsAre(IsPropertyDeclaration(
"colorSpace",
Storage::ImportedType{"QObject::NamedColorSpaces"},
- Storage::PropertyDeclarationTraits::None)))));
+ QmlDesigner::Storage::PropertyDeclarationTraits::None)))));
}
} // namespace
diff --git a/tests/unit/unittest/smallstring-test.cpp b/tests/unit/unittest/smallstring-test.cpp
index f708fd605e..d8321ec98f 100644
--- a/tests/unit/unittest/smallstring-test.cpp
+++ b/tests/unit/unittest/smallstring-test.cpp
@@ -1535,6 +1535,11 @@ TEST(SmallString, LongPathStringMoveConstuctor)
"text"));
}
+#if __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wself-move"
+#endif
+
TEST(SmallString, ShortSmallStringMoveConstuctorToSelf)
{
SmallString text("text");
@@ -1580,6 +1585,10 @@ TEST(SmallString, LongPathStringMoveConstuctorToSelf)
"text"));
}
+#if __clang__
+#pragma clang diagnostic pop
+#endif
+
TEST(SmallString, ShortSmallStringCopyAssignment)
{
SmallString text("text");
@@ -1600,6 +1609,11 @@ TEST(SmallString, LongSmallStringCopyAssignment)
ASSERT_THAT(copy, text);
}
+#if __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wself-assign-overloaded"
+#endif
+
TEST(SmallString, LongSmallStringCopySelfAssignment)
{
SmallString text("this is a very very very very long text");
@@ -1609,6 +1623,10 @@ TEST(SmallString, LongSmallStringCopySelfAssignment)
ASSERT_THAT(text, SmallString("this is a very very very very long text"));
}
+#if __clang__
+#pragma clang diagnostic pop
+#endif
+
TEST(SmallString, ShortSmallStringMoveAssignment)
{
SmallString text("text");
diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp
index 771969446a..a7a8585db5 100644
--- a/tests/unit/unittest/sqlitedatabase-test.cpp
+++ b/tests/unit/unittest/sqlitedatabase-test.cpp
@@ -6,6 +6,7 @@
#include "spydummy.h"
#include <sqlitedatabase.h>
+#include <sqliteprogresshandler.h>
#include <sqlitereadstatement.h>
#include <sqlitetable.h>
#include <sqlitewritestatement.h>
@@ -32,16 +33,10 @@ class SqliteDatabase : public ::testing::Test
protected:
SqliteDatabase()
{
- database.lock();
- database.setJournalMode(JournalMode::Memory);
- database.setDatabaseFilePath(databaseFilePath);
- Table table;
table.setName("test");
table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
table.addColumn("name");
- database.open();
-
table.initialize(database);
}
@@ -49,7 +44,6 @@ protected:
{
if (database.isOpen())
database.close();
- database.unlock();
}
std::vector<Utils::SmallString> names() const
@@ -68,17 +62,18 @@ protected:
protected:
SpyDummy spyDummy;
- QString databaseFilePath{":memory:"};
- mutable Sqlite::Database database;
+ Table table;
+ mutable Sqlite::Database database{":memory:", JournalMode::Memory};
Sqlite::TransactionInterface &transactionInterface = database;
MockFunction<void(Sqlite::ChangeType tupe, char const *, char const *, long long)> callbackMock;
std::function<void(Sqlite::ChangeType tupe, char const *, char const *, long long)>
callback = callbackMock.AsStdFunction();
+ std::unique_lock<Sqlite::Database> lock{database};
};
TEST_F(SqliteDatabase, SetDatabaseFilePath)
{
- ASSERT_THAT(database.databaseFilePath(), databaseFilePath);
+ ASSERT_THAT(database.databaseFilePath(), ":memory:");
}
TEST_F(SqliteDatabase, SetJournalMode)
@@ -335,7 +330,7 @@ TEST_F(SqliteDatabase, SessionsCommit)
.write(2, "hoo");
database.applyAndUpdateSessions();
- ASSERT_THAT(names(), ElementsAre("foo", "bar"));
+ ASSERT_THAT(names(), UnorderedElementsAre("foo", "bar"));
}
TEST_F(SqliteDatabase, SessionsRollback)
@@ -353,7 +348,41 @@ TEST_F(SqliteDatabase, SessionsRollback)
.write(2, "hoo");
database.applyAndUpdateSessions();
- ASSERT_THAT(names(), ElementsAre("foo", "hoo"));
+ ASSERT_THAT(names(), UnorderedElementsAre("foo", "hoo"));
+}
+
+TEST_F(SqliteDatabase, ProgressHandlerInterrupts)
+{
+ Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database);
+ lock.unlock();
+ Sqlite::ProgressHandler handler{[] { return Sqlite::Progress::Interrupt; }, 1, database};
+ lock.lock();
+
+ ASSERT_THROW(statement.write(42), Sqlite::ExecutionInterrupted);
+ lock.unlock();
+}
+
+TEST_F(SqliteDatabase, ProgressHandlerContinues)
+{
+ Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database);
+ lock.unlock();
+ Sqlite::ProgressHandler handler{[] { return Sqlite::Progress::Continue; }, 1, database};
+ lock.lock();
+
+ ASSERT_NO_THROW(statement.write(42));
+ lock.unlock();
+}
+
+TEST_F(SqliteDatabase, ProgressHandlerResetsAfterLeavingScope)
+{
+ lock.unlock();
+ {
+ Sqlite::ProgressHandler handler{[] { return Sqlite::Progress::Interrupt; }, 1, database};
+ }
+ lock.lock();
+ Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database);
+
+ ASSERT_NO_THROW(statement.write(42));
}
} // namespace
diff --git a/tests/unit/unittest/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp
index 81d0d9a219..9e08eb5b00 100644
--- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp
+++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp
@@ -31,7 +31,7 @@ protected:
{
database.lock();
QDir::temp().remove(QStringLiteral("SqliteDatabaseBackendTest.db"));
- databaseBackend.open(databaseFilePath, OpenMode::ReadWrite);
+ databaseBackend.open(databaseFilePath, OpenMode::ReadWrite, Sqlite::JournalMode::Wal);
}
~SqliteDatabaseBackend() noexcept(true)
@@ -49,7 +49,7 @@ using SqliteDatabaseBackendSlowTest = SqliteDatabaseBackend;
TEST_F(SqliteDatabaseBackend, OpenAlreadyOpenDatabase)
{
- ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite),
+ ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite, Sqlite::JournalMode::Wal),
Sqlite::DatabaseIsAlreadyOpen);
}
@@ -62,7 +62,9 @@ TEST_F(SqliteDatabaseBackend, CloseAlreadyClosedDatabase)
TEST_F(SqliteDatabaseBackend, OpenWithWrongPath)
{
- ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db", OpenMode::ReadWrite),
+ ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db",
+ OpenMode::ReadWrite,
+ Sqlite::JournalMode::Wal),
Sqlite::WrongFilePath);
}
@@ -101,15 +103,24 @@ TEST_F(SqliteDatabaseBackend, PersistJournalMode)
TEST_F(SqliteDatabaseBackend, OpenModeReadOnly)
{
- auto mode = Backend::openMode(OpenMode::ReadOnly);
+ auto mode = Backend::createOpenFlags(OpenMode::ReadOnly, Sqlite::JournalMode::Wal);
- ASSERT_THAT(mode, SQLITE_OPEN_CREATE | SQLITE_OPEN_READONLY);
+ ASSERT_THAT(mode, SQLITE_OPEN_CREATE | SQLITE_OPEN_READONLY | SQLITE_OPEN_EXRESCODE);
}
TEST_F(SqliteDatabaseBackend, OpenModeReadWrite)
{
- auto mode = Backend::openMode(OpenMode::ReadWrite);
+ auto mode = Backend::createOpenFlags(OpenMode::ReadWrite, Sqlite::JournalMode::Wal);
- ASSERT_THAT(mode, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE);
+ ASSERT_THAT(mode, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXRESCODE);
+}
+
+TEST_F(SqliteDatabaseBackend, OpenModeReadWriteAndMemoryJournal)
+{
+ auto mode = Backend::createOpenFlags(OpenMode::ReadWrite, Sqlite::JournalMode::Memory);
+
+ ASSERT_THAT(mode,
+ SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXRESCODE
+ | SQLITE_OPEN_MEMORY);
}
} // namespace
diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h
index 1316e3f680..62a1d6585b 100644
--- a/tests/unit/unittest/sqlitedatabasemock.h
+++ b/tests/unit/unittest/sqlitedatabasemock.h
@@ -32,7 +32,10 @@ public:
MOCK_METHOD(int64_t, lastInsertedRowId, (), (const));
- MOCK_METHOD(void, setLastInsertedRowId, (int64_t), (const));
+ MOCK_METHOD(void, setLastInsertedRowId, (int64_t), ());
+
+ MOCK_METHOD(int, version, (), (const));
+ MOCK_METHOD(void, setVersion, (int), ());
MOCK_METHOD(bool, isInitialized, (), (const));
diff --git a/tests/unit/unittest/sqlitefunctionregistry-test.cpp b/tests/unit/unittest/sqlitefunctionregistry-test.cpp
new file mode 100644
index 0000000000..de9a566fd5
--- /dev/null
+++ b/tests/unit/unittest/sqlitefunctionregistry-test.cpp
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "googletest.h"
+
+#include <sqlitefunctionregistry.h>
+
+namespace {
+
+class SqliteFunctionRegistry : public testing::Test
+{
+public:
+ SqliteFunctionRegistry() { Sqlite::FunctionRegistry::registerPathExists(database); }
+
+protected:
+ Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
+};
+
+TEST_F(SqliteFunctionRegistry, PathExists)
+{
+ std::lock_guard lock{database};
+ Sqlite::ReadStatement<1> statement{"SELECT pathExists('" TESTDATA_DIR "/sqlite_database.db')",
+ database};
+
+ auto pathExists = statement.value<bool>();
+
+ ASSERT_TRUE(pathExists);
+}
+
+TEST_F(SqliteFunctionRegistry, PathDoesntExists)
+{
+ std::lock_guard lock{database};
+ Sqlite::ReadStatement<1> statement{"SELECT pathExists('" TESTDATA_DIR "/sqlite_database2.db')",
+ database};
+
+ auto pathExists = statement.value<bool>();
+
+ ASSERT_FALSE(pathExists);
+}
+
+} // namespace
diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp
index 7777358f78..fa502218c7 100644
--- a/tests/unit/unittest/sqlitetransaction-test.cpp
+++ b/tests/unit/unittest/sqlitetransaction-test.cpp
@@ -203,8 +203,7 @@ TEST_F(SqliteTransaction, ExclusiveTNonThrowingDestructorransactionRollBack)
TEST_F(SqliteTransaction, DeferredTransactionBeginThrows)
{
- ON_CALL(mockTransactionBackend, deferredBegin())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, deferredBegin()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(DeferredTransaction{mockTransactionBackend},
Sqlite::Exception);
@@ -212,8 +211,7 @@ TEST_F(SqliteTransaction, DeferredTransactionBeginThrows)
TEST_F(SqliteTransaction, ImmediateTransactionBeginThrows)
{
- ON_CALL(mockTransactionBackend, immediateBegin())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, immediateBegin()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(ImmediateTransaction{mockTransactionBackend},
Sqlite::Exception);
@@ -221,8 +219,7 @@ TEST_F(SqliteTransaction, ImmediateTransactionBeginThrows)
TEST_F(SqliteTransaction, ExclusiveTransactionBeginThrows)
{
- ON_CALL(mockTransactionBackend, exclusiveBegin())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, exclusiveBegin()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(ExclusiveTransaction{mockTransactionBackend},
Sqlite::Exception);
@@ -233,8 +230,7 @@ TEST_F(SqliteTransaction, DeferredTransactionBeginThrowsAndNotRollback)
InSequence s;
EXPECT_CALL(mockTransactionBackend, lock());
- EXPECT_CALL(mockTransactionBackend, deferredBegin())
- .WillOnce(Throw(Sqlite::Exception("foo")));
+ EXPECT_CALL(mockTransactionBackend, deferredBegin()).WillOnce(Throw(Sqlite::Exception()));
EXPECT_CALL(mockTransactionBackend, rollback()).Times(0);
EXPECT_CALL(mockTransactionBackend, unlock());
@@ -246,8 +242,7 @@ TEST_F(SqliteTransaction, ImmediateTransactionBeginThrowsAndNotRollback)
InSequence s;
EXPECT_CALL(mockTransactionBackend, lock());
- EXPECT_CALL(mockTransactionBackend, immediateBegin())
- .WillOnce(Throw(Sqlite::Exception("foo")));
+ EXPECT_CALL(mockTransactionBackend, immediateBegin()).WillOnce(Throw(Sqlite::Exception()));
EXPECT_CALL(mockTransactionBackend, rollback()).Times(0);
EXPECT_CALL(mockTransactionBackend, unlock());
@@ -260,8 +255,7 @@ TEST_F(SqliteTransaction, ExclusiveTransactionBeginThrowsAndNotRollback)
InSequence s;
EXPECT_CALL(mockTransactionBackend, lock());
- EXPECT_CALL(mockTransactionBackend, exclusiveBegin())
- .WillOnce(Throw(Sqlite::Exception("foo")));
+ EXPECT_CALL(mockTransactionBackend, exclusiveBegin()).WillOnce(Throw(Sqlite::Exception()));
EXPECT_CALL(mockTransactionBackend, rollback()).Times(0);
EXPECT_CALL(mockTransactionBackend, unlock());
@@ -270,8 +264,7 @@ TEST_F(SqliteTransaction, ExclusiveTransactionBeginThrowsAndNotRollback)
TEST_F(SqliteTransaction, TransactionCommitThrows)
{
- ON_CALL(mockTransactionBackend, commit())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, commit()).WillByDefault(Throw(Sqlite::Exception()));
ImmediateTransaction transaction{mockTransactionBackend};
ASSERT_THROW(transaction.commit(),
@@ -280,8 +273,7 @@ TEST_F(SqliteTransaction, TransactionCommitThrows)
TEST_F(SqliteTransaction, TransactionRollbackInDestructorThrows)
{
- ON_CALL(mockTransactionBackend, rollback())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, rollback()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(ExclusiveTransaction{mockTransactionBackend},
Sqlite::Exception);
@@ -289,8 +281,7 @@ TEST_F(SqliteTransaction, TransactionRollbackInDestructorThrows)
TEST_F(SqliteTransaction, TransactionRollbackInDestructorDontThrows)
{
- ON_CALL(mockTransactionBackend, rollback())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, rollback()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_NO_THROW(ExclusiveNonThrowingDestructorTransaction{mockTransactionBackend});
}
@@ -322,15 +313,14 @@ TEST_F(SqliteTransaction, ImmediateSessionTransactionRollBack)
TEST_F(SqliteTransaction, SessionTransactionRollbackInDestructorThrows)
{
- ON_CALL(mockTransactionBackend, sessionRollback()).WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, sessionRollback()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(ImmediateSessionTransaction{mockTransactionBackend}, Sqlite::Exception);
}
TEST_F(SqliteTransaction, ImmidiateSessionTransactionBeginThrows)
{
- ON_CALL(mockTransactionBackend, immediateSessionBegin())
- .WillByDefault(Throw(Sqlite::Exception("foo")));
+ ON_CALL(mockTransactionBackend, immediateSessionBegin()).WillByDefault(Throw(Sqlite::Exception()));
ASSERT_THROW(ImmediateSessionTransaction{mockTransactionBackend}, Sqlite::Exception);
}
@@ -340,7 +330,7 @@ TEST_F(SqliteTransaction, ImmediateSessionTransactionBeginThrowsAndNotRollback)
InSequence s;
EXPECT_CALL(mockTransactionBackend, lock());
- EXPECT_CALL(mockTransactionBackend, immediateSessionBegin()).WillOnce(Throw(Sqlite::Exception("foo")));
+ EXPECT_CALL(mockTransactionBackend, immediateSessionBegin()).WillOnce(Throw(Sqlite::Exception()));
EXPECT_CALL(mockTransactionBackend, sessionRollback()).Times(0);
EXPECT_CALL(mockTransactionBackend, unlock());
diff --git a/tests/unit/unittest/sqlitewritestatementmock.h b/tests/unit/unittest/sqlitewritestatementmock.h
index 47f7917985..2fa3146601 100644
--- a/tests/unit/unittest/sqlitewritestatementmock.h
+++ b/tests/unit/unittest/sqlitewritestatementmock.h
@@ -40,6 +40,10 @@ public:
MOCK_METHOD(void, write, (Utils::SmallStringView, long long, Sqlite::BlobView, Sqlite::BlobView), ());
MOCK_METHOD(void,
write,
+ (Utils::SmallStringView, long long, Sqlite::BlobView, Sqlite::BlobView, Sqlite::BlobView),
+ ());
+ MOCK_METHOD(void,
+ write,
(Utils::SmallStringView,
Utils::SmallStringView,
Utils::SmallStringView,
diff --git a/tests/unit/unittest/synchronousimagecache-test.cpp b/tests/unit/unittest/synchronousimagecache-test.cpp
index 02b3571508..d239c22b0d 100644
--- a/tests/unit/unittest/synchronousimagecache-test.cpp
+++ b/tests/unit/unittest/synchronousimagecache-test.cpp
@@ -29,9 +29,15 @@ protected:
ON_CALL(mockStorage,
fetchImage(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image2}));
+ ON_CALL(mockStorage,
+ fetchMidSizeImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{midSizeImage1}));
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage1}));
ON_CALL(mockStorage,
+ fetchMidSizeImage(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
+ .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{midSizeImage2}));
+ ON_CALL(mockStorage,
fetchSmallImage(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage2}));
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
@@ -40,7 +46,7 @@ protected:
fetchIcon(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::IconEntry{icon2}));
ON_CALL(mockCollector, createImage(Eq("/path/to/Component.qml"), Eq("extraId1"), _))
- .WillByDefault(Return(std::make_pair(image3, smallImage3)));
+ .WillByDefault(Return(std::make_tuple(image3, midSizeImage3, smallImage3)));
ON_CALL(mockCollector, createIcon(Eq("/path/to/Component.qml"), Eq("extraId1"), _))
.WillByDefault(Return(icon3));
}
@@ -52,10 +58,13 @@ protected:
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
QmlDesigner::SynchronousImageCache cache{mockStorage, mockTimeStampProvider, mockCollector};
QImage image1{1, 1, QImage::Format_ARGB32};
- QImage image2{2, 2, QImage::Format_ARGB32};
- QImage image3{3, 3, QImage::Format_ARGB32};
- QImage smallImage1{1, 1, QImage::Format_ARGB32};
- QImage smallImage2{2, 1, QImage::Format_ARGB32};
+ QImage image2{1, 2, QImage::Format_ARGB32};
+ QImage image3{1, 3, QImage::Format_ARGB32};
+ QImage midSizeImage1{2, 1, QImage::Format_ARGB32};
+ QImage midSizeImage2{2, 2, QImage::Format_ARGB32};
+ QImage midSizeImage3{2, 3, QImage::Format_ARGB32};
+ QImage smallImage1{3, 1, QImage::Format_ARGB32};
+ QImage smallImage2{3, 1, QImage::Format_ARGB32};
QImage smallImage3{3, 1, QImage::Format_ARGB32};
QIcon icon1{QPixmap::fromImage(image1)};
QIcon icon2{QPixmap::fromImage(image2)};
@@ -95,11 +104,51 @@ TEST_F(SynchronousImageCache, GetImageWithOutdatedTimeStampStored)
storeImage(Eq("/path/to/Component.qml+extraId1"),
Eq(Sqlite::TimeStamp{124}),
Eq(image3),
+ Eq(midSizeImage3),
Eq(smallImage3)));
auto image = cache.image("/path/to/Component.qml", "extraId1");
}
+TEST_F(SynchronousImageCache, GetMidSizeImageFromStorage)
+{
+ auto image = cache.midSizeImage("/path/to/Component.qml");
+
+ ASSERT_THAT(image, midSizeImage1);
+}
+
+TEST_F(SynchronousImageCache, GetMidSizeImageWithExtraIdFromStorage)
+{
+ auto image = cache.midSizeImage("/path/to/Component.qml", "extraId1");
+
+ ASSERT_THAT(image, midSizeImage2);
+}
+
+TEST_F(SynchronousImageCache, GetMidSizeImageWithOutdatedTimeStampFromCollector)
+{
+ ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillByDefault(Return(Sqlite::TimeStamp{124}));
+
+ auto image = cache.midSizeImage("/path/to/Component.qml", "extraId1");
+
+ ASSERT_THAT(image, midSizeImage3);
+}
+
+TEST_F(SynchronousImageCache, GetMidSizeImageWithOutdatedTimeStampStored)
+{
+ ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
+ .WillByDefault(Return(Sqlite::TimeStamp{124}));
+
+ EXPECT_CALL(mockStorage,
+ storeImage(Eq("/path/to/Component.qml+extraId1"),
+ Eq(Sqlite::TimeStamp{124}),
+ Eq(image3),
+ Eq(midSizeImage3),
+ Eq(smallImage3)));
+
+ auto image = cache.midSizeImage("/path/to/Component.qml", "extraId1");
+}
+
TEST_F(SynchronousImageCache, GetSmallImageFromStorage)
{
auto image = cache.smallImage("/path/to/Component.qml");
@@ -133,6 +182,7 @@ TEST_F(SynchronousImageCache, GetSmallImageWithOutdatedTimeStampStored)
storeImage(Eq("/path/to/Component.qml+extraId1"),
Eq(Sqlite::TimeStamp{124}),
Eq(image3),
+ Eq(midSizeImage3),
Eq(smallImage3)));
auto image = cache.smallImage("/path/to/Component.qml", "extraId1");