diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 91f70ca05ef..ea6f1d77a58 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -709,14 +709,14 @@ jobs: - name: Download qtcreatorcdbext artifact if: matrix.config.artifact == 'Windows-MSVC' - uses: actions/upload-artifact@v2 + uses: actions/download-artifact@v2 with: name: qtcreatorcdbext-${{ matrix.config.artifact }}-${{ github.run_id }}.7z path: ./ - name: Download disk image artifact if: matrix.config.artifact == 'macOS' - uses: actions/upload-artifact@v2 + uses: actions/download-artifact@v2 with: name: qt-creator-${{ matrix.config.artifact }}-${{ github.run_id }}.dmg path: ./ diff --git a/cmake/FindGoogletest.cmake b/cmake/FindGoogletest.cmake index 84d8018ffdf..eee8127a959 100644 --- a/cmake/FindGoogletest.cmake +++ b/cmake/FindGoogletest.cmake @@ -100,6 +100,7 @@ if(Googletest_FOUND AND NOT TARGET Googletest) GTEST_HAS_PARAM_TEST GTEST_HAS_DEATH_TEST ) + set_target_properties(Googletest PROPERTIES AUTOMOC OFF AUTOUIC OFF) target_link_libraries(Googletest Threads::Threads) endif() diff --git a/cmake/Findyaml-cpp.cmake b/cmake/Findyaml-cpp.cmake index 277d8069e0a..9325e891b70 100644 --- a/cmake/Findyaml-cpp.cmake +++ b/cmake/Findyaml-cpp.cmake @@ -26,6 +26,7 @@ else() INCLUDES ${YAML_SOURCE_DIR}/include PUBLIC_DEFINES YAML_CPP_DLL PUBLIC_INCLUDES ${YAML_SOURCE_DIR}/include + PROPERTIES AUTOMOC OFF AUTOUIC OFF SOURCES ${YAML_SOURCE_DIR}/include/yaml-cpp ${YAML_SOURCE_DIR}/include/yaml-cpp/anchor.h diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 363c9b9a8f9..d06e0ce0ca0 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -869,7 +869,7 @@ function(finalize_qtc_gtest test_name exclude_sources_regex) list(FILTER test_sources EXCLUDE REGEX "${exclude_sources_regex}") endif() include(GoogleTest) - gtest_add_tests(TARGET ${test_name} SOURCES ${test_sources} TEST_LIST test_list) + gtest_add_tests(TARGET ${test_name} SOURCES ${test_sources} TEST_LIST test_list SKIP_DEPENDENCY) foreach(test IN LISTS test_list) finalize_test_setup(${test}) @@ -1021,6 +1021,7 @@ function(qtc_add_resources target resourceName) target_sources(${target} PRIVATE "${generatedSourceCode}") set_property(SOURCE "${generatedSourceCode}" PROPERTY SKIP_AUTOGEN ON) + set_property(SOURCE "${generatedResourceFile}.in" PROPERTY SKIP_AUTOGEN ON) endfunction() function(qtc_add_public_header header) diff --git a/dist/changes-6.0.1.md b/dist/changes-6.0.1.md new file mode 100644 index 00000000000..97560c7a08c --- /dev/null +++ b/dist/changes-6.0.1.md @@ -0,0 +1,118 @@ +Qt Creator 6.0.1 +================ + +Qt Creator version 6.0.1 contains bug fixes. + +The most important changes are listed in this document. For a complete list of +changes, see the Git log for the Qt Creator sources that you can check out from +the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/v6.0.0..v6.0.1 + +Editing +------- + +* Fixed cursor position after pasting and moving (QTCREATORBUG-26635) +* Fixed deletion of start or end of word when camel case navigation is off + (QTCREATORBUG-26646) +* Fixed crash when removing built-in snippets (QTCREATORBUG-26648) + +### C++ + +* Clangd + * Improved indexing performance on macOS + * Fixed issues with refactoring (QTCREATORBUG-26649) + * Fixed warnings for multiple `/Tx` options with MSVC (QTCREATORBUG-26664) + +### Language Client + +* Fixed sending of `textDocument/didChange` notifications (QTCREATORBUG-26651) + +Projects +-------- + +* Fixed canceling GUI processes as build steps (QTCREATORBUG-26687) + +### CMake + +* Fixed initial CMake arguments for Windows ARM targets (QTCREATORBUG-26636) + +### Qbs + +* Fixed support for C++23 with MSVC (QTCREATORBUG-26663) + +Debugging +--------- + +* Fixed interrupting console applications + +### GDB + +* Fixed `PATH` for debugging MinGW applications (QTCREATORBUG-26670) + +Test Integration +---------------- + +### Google Test + +* Fixed that application arguments could change order + +Platforms +--------- + +### Linux + +* Removed dependency of prebuilt packages on libGLX and libOpenGL + (QTCREATORBUG-26652) + +### macOS + +* Fixed running applications that access Bluetooth (QTCREATORBUG-26666) +* Fixed saving of file system case sensitivity setting + +### Android + +* Fixed keystore handling on Windows (QTCREATORBUG-26647) + +### Boot2Qt + +* Fixed flashing wizard on Windows + +### QNX + +* Fixed codemodel issues (QTCREATORBUG-23483) + +Credits for these changes go to: +-------------------------------- +Aleksei German +Alessandro Portale +André Pönitz +Antti Määttä +BogDan Vatra +Christiaan Janssen +Christian Kandeler +Christian Stenger +Cristian Adam +David Schulz +Dawid Śliwa +Eike Ziller +Henning Gruendl +Jaroslaw Kobus +Joni Poikelin +Kai Köhne +Kaj Grönholm +Knud Dollereder +Leena Miettinen +Mahmoud Badri +Marco Bubke +Miikka Heikkinen +Oliver Wolff +Petar Perisin +Robert Löhning +Samuel Ghinet +Sergey Levin +Tapani Mattila +Thomas Hartmann +Vikas Pachdha +Youri Westerman diff --git a/doc/qtcreator/images/icons/navigator.png b/doc/qtcreator/images/icons/navigator.png index d4629fd8964..69d9a6e491e 100644 Binary files a/doc/qtcreator/images/icons/navigator.png and b/doc/qtcreator/images/icons/navigator.png differ diff --git a/doc/qtcreator/images/icons/recordfill.png b/doc/qtcreator/images/icons/recordfill.png index 57dc3054c83..ab0e225db13 100644 Binary files a/doc/qtcreator/images/icons/recordfill.png and b/doc/qtcreator/images/icons/recordfill.png differ diff --git a/doc/qtcreator/images/icons/visual.png b/doc/qtcreator/images/icons/visual.png deleted file mode 100644 index 62fd49061f5..00000000000 Binary files a/doc/qtcreator/images/icons/visual.png and /dev/null differ diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index 05b89ebab89..6f6ca89f450 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -132,8 +132,18 @@ \li Build the application by using the appropriate configuration parameters (if you build the application with \QC, it automatically uses the correct configuration): + \list + \li When using CMake, the + \l{CMake: target_compile_definitions command} + {target_compile_definitions} command is defined + in the CMakeLists.txt file: + \c {target_compile_definitions(myapp PRIVATE QT_QML_DEBUG)} - \c {CONFIG+=qml_debug} + Where \e myapp is the application to debug. + \li When using qmake, the following value is defined for the + \l CONFIG property in the .pro file: + \c {CONFIG += qml_debug} + \endlist \endif \li Start the application with the following arguments: diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index 76cabbde5c3..dc3f15c4863 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -121,6 +121,14 @@ \externalpage https://cmake.org/cmake/help/latest/command/set_property.html \title CMake: set_property command */ +/*! + \externalpage https://cmake.org/cmake/help/latest/command/target_compile_definitions.html + \title CMake: target_compile_definitions command +*/ +/*! + \externalpage https://cmake.org/cmake/help/latest/command/target_link_libraries.html + \title CMake: target_link_libraries command +*/ /*! \externalpage https://cmake.org/cmake/help/latest/command/target_sources.html \title CMake: target_sources command diff --git a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc index 198148def46..25e6686750c 100644 --- a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc +++ b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc @@ -197,7 +197,8 @@ \section1 Supported Qt for MCUs SDKs - Since version 4.12.4, \QC supports version 1.3 and later of the Qt for MCUs SDK. + Since version 4.12.4, \QC supports versions 1.3 through 1.9 of the Qt for MCUs SDK. + Since version 6.0.0, \QC adds support for versions 2.0 and later of the Qt for MCUs SDK. For older versions refer to the following table. \table @@ -205,8 +206,11 @@ \li \QC version \li Qt for MCUs SDK version \row - \li 4.12.4 or later - \li 1.3 or later + \li 6.0.0 or later + \li 1.3 or later, including 2.0 or later + \row + \li 4.12.4 up to 5.0.3 + \li 1.3 up to 1.9 \row \li 4.12.2 or 4.12.3 \li 1.2 diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc index 699a8f0fd8c..dd6e514b970 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -59,7 +59,8 @@ Specify whether the library is statically or dynamically linked. For a statically linked internal library, \QC adds dependencies - (PRE_TARGETDEPS) in the project file. + (\l{CMake: target_link_libraries command}{target_link_libraries} when using + CMake or \l PRE_TARGETDEPS when using qmake) in the project file. Depending on the development platform, some options might be detected automatically. For example, on \macos, the library type (\uicontrol Library or @@ -128,22 +129,29 @@ \li In the \uicontrol Library field, select \b mylib, and then select \uicontrol Next. - \li Select \uicontrol Finish to add the following library declaration to the - project file: - - \code - win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../projects/mylib/release/ -lmylib - else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../projects/mylib/debug/ -lmylib - else:unix: LIBS += -L$$OUT_PWD/../../../projects/mylib/ -lmylib - - INCLUDEPATH += $$PWD/../../../projects/mylib - DEPENDPATH += $$PWD/../../../projects/mylib - - win32:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/release/mylib.lib - else:win32:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/debug/mylib.lib - else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/libmylib.a - \endcode + \li Select \uicontrol Finish to add the library declaration to the + project file. \endlist + When using CMake, the \c target_link_libraries command is added to the + CMakeLists.txt file: + + \badcode + target_link_libraries(myapp PRIVATE mylib) + \endcode + + When using qmake, the following library declaration is added to the .pro + file: + + \badcode + win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../../../projects/mylib/release/ -lmylib + else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../../../projects/mylib/debug/ -lmylib + else:unix: LIBS += -L$$OUT_PWD/../../../projects/mylib/ -lmylib + INCLUDEPATH += $$PWD/../../../projects/mylib + DEPENDPATH += $$PWD/../../../projects/mylib + win32:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/release/mylib.lib + else:win32:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/debug/mylib.lib + else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../../projects/mylib/libmylib.a + \endcode */ diff --git a/doc/qtdesignstudio/config/qtdesignstudio.qdocconf b/doc/qtdesignstudio/config/qtdesignstudio.qdocconf index 2b3cf9879c8..50687fbb36c 100644 --- a/doc/qtdesignstudio/config/qtdesignstudio.qdocconf +++ b/doc/qtdesignstudio/config/qtdesignstudio.qdocconf @@ -19,7 +19,6 @@ sourcedirs = ../src \ imagedirs = ../images \ ../examples/doc/images \ ../../qtcreator/images \ - ../../../plugins/qmldesigner/qmlpreviewplugin/images \ ../../../share/qtcreator/qml/qmlpuppet/mockfiles/images \ ../../../share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images \ ../../../src/libs/qmleditorwidgets/images \ diff --git a/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc b/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc index 49a135949e3..78daecb3821 100644 --- a/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc +++ b/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc @@ -122,14 +122,14 @@ \image coffee-machine-timeline.png Our viewport contains 200 frames, so we select the - \inlineimage plus.png "Plus button" + \inlineimage icons/plus.png "Plus button" button to add a 1200-frame timeline to the root component. We use the default values for all other fields. To start recording the transition from the startup screen to the coffee selection screen on the timeline, we select \e choosingCoffee in \l Navigator. We check that the playhead is at frame 0, and then - select the \inlineimage recordfill.png + select the \inlineimage icons/recordfill.png (\uicontrol {Auto Key (K)}) button (or press \key k). At frame 0, we set the X coordinate to 0 in \l Properties > diff --git a/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc b/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc index 7caed4225f9..addef38bcdb 100644 --- a/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc +++ b/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc @@ -55,14 +55,14 @@ the screens in \e {Screen01.ui.qml}. Our viewport contains 1000 frames, so we select the - \inlineimage plus.png "Plus button" + \inlineimage icons/plus.png "Plus button" button to add a 5000-frame timeline to the root component. We use the default values for all other fields. To start recording the transitions between the Standard screen and the Trip and Navigator screens on the timeline, we select \e screenCanvas in the \l Navigator view. We check that the playhead is at frame 0, and then - select the \inlineimage recordfill.png + select the \inlineimage icons/recordfill.png (\uicontrol {Auto Key (K)}) button (or press \key k). \image ebikedesign-timeline.png "Timeline view" diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc index 31e1ebb549d..fec8c664a14 100644 --- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc @@ -160,7 +160,7 @@ To add the assets to \l Library: \list 1 \li Select \uicontrol Library > \uicontrol Assets - > \inlineimage plus.png + > \inlineimage icons/plus.png . \li Select the asset files, and then select \uicontrol Open. \li Select the location where the files will be saved in the @@ -281,7 +281,7 @@ The \l {Images}{Image} component is used for adding images to the UI in several supported formats, including bitmap formats such as PNG and JPEG and vector graphics formats such as SVG. To add an image to \uicontrol Library, select - \uicontrol Assets > \inlineimage plus.png + \uicontrol Assets > \inlineimage icons/plus.png , and then select the image file. If you need to display animated images, use the \l {Animated Image} diff --git a/doc/qtdesignstudio/examples/doc/loginui3.qdoc b/doc/qtdesignstudio/examples/doc/loginui3.qdoc index d04690b224f..79a708160a3 100644 --- a/doc/qtdesignstudio/examples/doc/loginui3.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui3.qdoc @@ -177,7 +177,7 @@ \li Select \uicontrol View > \uicontrol Views > \uicontrol {Connection View} to open the \uicontrol Connections tab. \li Select \e createAccount in \uicontrol Navigator. - \li In the \uicontrol Connections tab, select the \inlineimage plus.png + \li In the \uicontrol Connections tab, select the \inlineimage icons/plus.png button to add the action that the \c onClicked signal handler of \e createAccount should apply. \li Double-click the value \uicontrol Action column and select diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc index 5c8bdca033b..3997945e7f0 100644 --- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc @@ -85,7 +85,7 @@ \li Double-click \e Screen01.ui.qml in \l Projects to open it in \l {Form Editor}. \li In the \l States view, select \e login, and then select - \inlineimage close.png + \inlineimage icons/close.png to remove the state. Repeat for the \e createAccount state. \li Select \e username in \l Navigator, and then select \inlineimage arrowleft.png @@ -143,7 +143,7 @@ \list 1 \li Select \uicontrol View > \uicontrol Views > \uicontrol Timeline to open the \l Timeline view. - \li In \uicontrol Timeline, select \inlineimage plus.png + \li In \uicontrol Timeline, select \inlineimage icons/plus.png to add a 1000-frame timeline and settings for running the animation. \image loginui4-timeline-settings.png \li In the \uicontrol {Animation ID} field, enter @@ -172,7 +172,7 @@ opacity property of the component. \image loginui4-keyframe-opacity.png "Inserting keyframe for opacity property" \li In \uicontrol Timeline, check that the playhead is in - frame 0, and select the \inlineimage recordfill.png + frame 0, and select the \inlineimage icons/recordfill.png (\uicontrol {Per Property Recording}) button for the \uicontrol opacity property of \e repeatPassword to start recording property changes. @@ -183,7 +183,7 @@ to show the button. To fine-tune the value of a keyframe, you can also right-click the - keyframe marker \inlineimage keyframe_linear_inactive.png + keyframe marker \inlineimage icons/keyframe_linear_active.png , and select \uicontrol {Edit Keyframe}. \li Select the record button again to stop recording property changes. If you forget this, all the following changes will be recorded, and @@ -236,7 +236,7 @@ margin animation that will make the transition seem smoother: \list 1 - \li Click the keyframe marker \inlineimage keyframe_linear_inactive.png + \li Click the keyframe marker \inlineimage icons/keyframe_linear_active.png for the \e anchors.topMargin property at frame 1000 on the timeline to select it. \image loginui4-easing-curve-top-anchor-margin.png "Top anchor margin keyframe marker" @@ -249,8 +249,8 @@ \endlist When you attach easing curves to keyframes, the shape of the keyframe - marker changes from \inlineimage keyframe_linear_inactive.png - to \inlineimage keyframe_manualbezier_inactive.png + marker changes from \inlineimage icons/keyframe_linear_active.png + to \inlineimage icons/keyframe_manualbezier_active.png . Your timeline should now look something like this: diff --git a/doc/qtdesignstudio/examples/doc/progressbar.qdoc b/doc/qtdesignstudio/examples/doc/progressbar.qdoc index 14c841fd729..80074c3d973 100644 --- a/doc/qtdesignstudio/examples/doc/progressbar.qdoc +++ b/doc/qtdesignstudio/examples/doc/progressbar.qdoc @@ -90,14 +90,14 @@ \section2 Adding Color Animation First, we add a color animation to the \e root component in the \e Root.qml - file. We select the \inlineimage plus.png + file. We select the \inlineimage icons/plus.png button to add a 100-frame timeline to root. You can use the default values for all other fields. \image progressbar-timeline-settings.png "Timeline settings" To start recording a color animation on the timeline, we check that the - playhead is at frame 0 and then select the \inlineimage recordfill.png + playhead is at frame 0 and then select the \inlineimage icons/recordfill.png (\uicontrol {Auto Key (K)}) button (or press \key k). \image progressbar-timeline.png "Color animation timeline" @@ -194,7 +194,7 @@ use a column layout to lay out the progress bar instances. We can now add timelines for each progress bar instance, with different - settings. We select the \inlineimage plus.png + settings. We select the \inlineimage icons/plus.png button to add a 4000-frame timeline to the first progress bar instance (\e root). We select the \uicontrol Continuous check box so that the animation will loop. @@ -236,8 +236,8 @@ \image studio-easing-curve-editor.png "Easing Curve Editor" When we apply easing curves to animations, the shape of the keyframe - marker changes from \inlineimage keyframe_linear_inactive.png - to \inlineimage keyframe_manualbezier_inactive.png + marker changes from \inlineimage icons/keyframe_linear_active.png + to \inlineimage icons/keyframe_manualbezier_active.png . For more information, see \l{Editing Easing Curves}. diff --git a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc index 28695ad5d4e..391f9cb630e 100644 --- a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc +++ b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc @@ -120,7 +120,7 @@ In addition, we set the \uicontrol Checked property to \c true for the first button instance on the menu bar to make it appear selected. - We can now select the \inlineimage run_small.png "Run button" + We can now select the \inlineimage icons/run_small.png "Run button" (\uicontrol Run) button to run the application and test our menu bar. \section1 Creating a Side Menu @@ -153,7 +153,7 @@ \image sidemenu-states.png "Side menu states" - We then select the \inlineimage plus.png + We then select the \inlineimage icons/plus.png button in the \l Timeline view to add animation for transitions to the \e open and \e close states: @@ -167,7 +167,7 @@ We want to change the position of the outline and background images. To start recording the transition from the closed state to the open state, we select \e imageOutline in \uicontrol Navigator. We check that the - playhead is at frame 0, and then select the \inlineimage recordfill.png + playhead is at frame 0, and then select the \inlineimage icons/recordfill.png (\uicontrol {Auto Key (K)}) button (or press \key k). At frame 0, we set the X coordinate to -423 in \uicontrol Properties > diff --git a/doc/qtdesignstudio/examples/doc/simplekeyboard.qdoc b/doc/qtdesignstudio/examples/doc/simplekeyboard.qdoc index ab63deab976..1b2c2363a09 100644 --- a/doc/qtdesignstudio/examples/doc/simplekeyboard.qdoc +++ b/doc/qtdesignstudio/examples/doc/simplekeyboard.qdoc @@ -40,7 +40,7 @@ text into \l{Text Edit} or \l{Text Input} components. For more information about using it, see \l{User Guide}{Virtual Keyboard: User Guide}. - To test the virtual keyboard, you need to select the \inlineimage run_small.png + To test the virtual keyboard, you need to select the \inlineimage icons/run_small.png (\uicontrol Run) button to run the example on the desktop or a device. The keyboard is not available during preview. diff --git a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc index 7d6177c35e0..bc7e35a543e 100644 --- a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc +++ b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc @@ -134,7 +134,7 @@ We can now add a timeline animation to make the arc move around the button when the button is pressed. In the \uicontrol Timeline view, we select the - \inlineimage plus.png + \inlineimage icons/plus.png button to add a 1000-frame timeline to the \e root of the component. We'll use the default values for all other fields. @@ -150,7 +150,7 @@ \image washingmachineui-insert-keyframe.png "Inserting keyframe for Rotation property" To start recording a rotation animation on the timeline, we check that the - playhead is at frame 0 and then select the \inlineimage recordfill.png + playhead is at frame 0 and then select the \inlineimage icons/recordfill.png (\uicontrol {Auto Key (K)}) button (or press \key k). First, we set the rotation at frame 0 to -90 in \uicontrol Properties > @@ -214,7 +214,7 @@ Then, we select the mouse area for the start button, \e startMA, in \uicontrol Navigator. In \l {Connection View} > \uicontrol Connections, - we select the \inlineimage plus.png + we select the \inlineimage icons/plus.png (\uicontrol Add) button to connect the \c onClicked() signal handler of the button to the \c startClicked() signal. diff --git a/doc/qtdesignstudio/images/icons/boundingrect.png b/doc/qtdesignstudio/images/icons/boundingrect.png new file mode 100644 index 00000000000..0a91478d6d0 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/boundingrect.png differ diff --git a/doc/qtdesignstudio/images/icons/close.png b/doc/qtdesignstudio/images/icons/close.png new file mode 100644 index 00000000000..dfe3144d141 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/close.png differ diff --git a/doc/qtdesignstudio/images/icons/eye_open.png b/doc/qtdesignstudio/images/icons/eye_open.png new file mode 100644 index 00000000000..7cb34bf982f Binary files /dev/null and b/doc/qtdesignstudio/images/icons/eye_open.png differ diff --git a/doc/qtdesignstudio/images/icons/keyframe_autobezier_active.png b/doc/qtdesignstudio/images/icons/keyframe_autobezier_active.png new file mode 100644 index 00000000000..8a3eaa7888b Binary files /dev/null and b/doc/qtdesignstudio/images/icons/keyframe_autobezier_active.png differ diff --git a/doc/qtdesignstudio/images/icons/keyframe_linear_active.png b/doc/qtdesignstudio/images/icons/keyframe_linear_active.png new file mode 100644 index 00000000000..a195ac5fca5 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/keyframe_linear_active.png differ diff --git a/doc/qtdesignstudio/images/icons/keyframe_lineartobezier_active.png b/doc/qtdesignstudio/images/icons/keyframe_lineartobezier_active.png new file mode 100644 index 00000000000..f85d3f78fd2 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/keyframe_lineartobezier_active.png differ diff --git a/doc/qtdesignstudio/images/icons/keyframe_manualbezier_active.png b/doc/qtdesignstudio/images/icons/keyframe_manualbezier_active.png new file mode 100644 index 00000000000..4b6a7c8978b Binary files /dev/null and b/doc/qtdesignstudio/images/icons/keyframe_manualbezier_active.png differ diff --git a/doc/qtdesignstudio/images/icons/live_preview.png b/doc/qtdesignstudio/images/icons/live_preview.png new file mode 100644 index 00000000000..b56467d4eac Binary files /dev/null and b/doc/qtdesignstudio/images/icons/live_preview.png differ diff --git a/doc/qtdesignstudio/images/icons/unlocked.png b/doc/qtdesignstudio/images/icons/unlocked.png new file mode 100644 index 00000000000..a281db1a8c9 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/unlocked.png differ diff --git a/doc/qtdesignstudio/images/keyframe_linear_inactive.png b/doc/qtdesignstudio/images/keyframe_linear_inactive.png deleted file mode 100644 index f53c5c25cec..00000000000 Binary files a/doc/qtdesignstudio/images/keyframe_linear_inactive.png and /dev/null differ diff --git a/doc/qtdesignstudio/images/keyframe_manualbezier_inactive.png b/doc/qtdesignstudio/images/keyframe_manualbezier_inactive.png deleted file mode 100644 index ab6ced5af04..00000000000 Binary files a/doc/qtdesignstudio/images/keyframe_manualbezier_inactive.png and /dev/null differ diff --git a/doc/qtdesignstudio/images/navigator.png b/doc/qtdesignstudio/images/navigator.png deleted file mode 100644 index 69d9a6e491e..00000000000 Binary files a/doc/qtdesignstudio/images/navigator.png and /dev/null differ diff --git a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc index d6ef4744b3c..3d9f56c4bec 100644 --- a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc @@ -176,7 +176,7 @@ \list 1 \li Click \uicontrol {Design} to edit the UI file in \l {Form Editor}. - \li Select \l Library > \uicontrol Assets > \inlineimage plus.png + \li Select \l Library > \uicontrol Assets > \inlineimage icons/plus.png to copy the image files you want to use to the project folder. \li In \l Navigator, select the root component and set the width (\uicontrol W) and height (\uicontrol H) of the button in the diff --git a/doc/qtdesignstudio/src/components/qtquick-images.qdoc b/doc/qtdesignstudio/src/components/qtquick-images.qdoc index 407c2715b51..acd01eddb39 100644 --- a/doc/qtdesignstudio/src/components/qtquick-images.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-images.qdoc @@ -37,7 +37,7 @@ first add them to \l Library: \list 1 \li Select \uicontrol Library > \uicontrol Assets - > \inlineimage plus.png + > \inlineimage icons/plus.png . \li Select the image file, and then select \uicontrol Open. \li Select the location where the image will be saved in the diff --git a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc index 1076e7a3746..185b6844468 100644 --- a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc @@ -117,7 +117,7 @@ For convenience, you can click the \inlineimage icons/anchor-fill.png (\uicontrol {Fill to Parent}) toolbar button to apply fill anchors to a - component and the \inlineimage qtcreator-anchors-reset-icon.png + component and the \inlineimage icons/qtcreator-anchors-reset-icon.png (\uicontrol {Reset Anchors}) button to reset the anchors to their saved state. @@ -484,10 +484,10 @@ \image qtquick-designer-stacked-view.png To add components to a \uicontrol {Stack Layout}, select the - \inlineimage plus.png + \inlineimage icons/plus.png button next to the component name in \l {Form Editor}. - To move between components, select the \inlineimage prev.png - (\uicontrol Previous) and \inlineimage next.png + To move between components, select the \inlineimage icons/prev.png + (\uicontrol Previous) and \inlineimage icons/next.png (\uicontrol Next) buttons. To add a tab bar to a stack layout, right-click on the diff --git a/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc index 488dbbdfe04..6907c70e6f2 100644 --- a/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc @@ -31,7 +31,7 @@ \title Preset Components To use preset components, add the modules that contain them to your project - by selecting \l Library > \uicontrol Components > \inlineimage plus.png + by selecting \l Library > \uicontrol Components > \inlineimage icons/plus.png . For more information, see \l{Adding and Removing Modules}. You can then create instances of the components by dragging-and-dropping them from \uicontrol Library to \l {Form Editor}, \l {3D Editor}, or \l Navigator. diff --git a/doc/qtdesignstudio/src/components/qtquick-text.qdoc b/doc/qtdesignstudio/src/components/qtquick-text.qdoc index 8202082341f..e1af7084f95 100644 --- a/doc/qtdesignstudio/src/components/qtquick-text.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-text.qdoc @@ -123,7 +123,7 @@ \list 1 \li Select \uicontrol Library > \l Assets - > \inlineimage plus.png + > \inlineimage icons/plus.png . \li Select the font file, and then select \uicontrol Open. \li Select the location where the file will be saved in the diff --git a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc index 8c493319b9b..f9d781961db 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc @@ -77,10 +77,10 @@ \li Select \uicontrol OK. \endlist - To add more comments about the component, select the \inlineimage plus.png + To add more comments about the component, select the \inlineimage icons/plus.png (\uicontrol {Add Comment}) button. - To remove the active comment, select the \inlineimage minus.png + To remove the active comment, select the \inlineimage icons/minus.png (\uicontrol {Remove Comment}) button. To remove the annotation, right-click the annotation icon, and then select \uicontrol {Remove Annotation}. diff --git a/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc index bf79ffa20b9..3f516d8bcc5 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc @@ -46,7 +46,7 @@ \list 1 \li Select \uicontrol Library > \l Assets - > \inlineimage plus.png + > \inlineimage icons/plus.png . \li Browse to the folder that contains the font files and select them, and then select \uicontrol Open. diff --git a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc index 1240adaab0c..9acda5268cb 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc @@ -510,7 +510,7 @@ \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 In the \uicontrol {Event List} dialog, select \inlineimage plus.png + \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" \li In the \uicontrol {Event ID} field, enter an identifier for the diff --git a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc index 4107275d08e..a7b40242549 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc @@ -36,7 +36,7 @@ To import an asset, drag-and-drop the external file containing the asset from, for example, File Explorer on Windows, to \uicontrol {Form Editor}, \uicontrol Navigator, or \uicontrol {Text Editor}. Alternatively, select - \l Library > \uicontrol Assets > \inlineimage plus.png + \l Library > \uicontrol Assets > \inlineimage icons/plus.png and follow the instructions in the \uicontrol {Asset Import} dialog. You can also multiselect several external asset files to drag-and-drop them to \QDS simultaneously. @@ -76,7 +76,7 @@ create an empty project. \li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to the Design mode. - \li Select \l Library > \uicontrol Assets > \inlineimage plus.png + \li Select \l Library > \uicontrol Assets > \inlineimage icons/plus.png . \li Select the folder where you exported the assets. \li Select \uicontrol {Exported Assets (*.metadata)} in the dropdown @@ -121,7 +121,7 @@ After importing the metadata files, wait a few moments to allow all imported assets to appear in your project files before selecting your - metadata filename from \uicontrol Assets > \inlineimage plus.png + metadata filename from \uicontrol Assets > \inlineimage icons/plus.png . If asset importer conflicts, warnings, and errors are displayed in the diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index f46b302cb31..07af4c6decb 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -169,7 +169,7 @@ \endlist To use JavaScript and image files in the UI, select \uicontrol Library > - \uicontrol Assets > \inlineimage plus.png + \uicontrol Assets > \inlineimage icons/plus.png . \section1 Adding Files to Projects diff --git a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc index 85922710550..b88f812f3c0 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc @@ -146,7 +146,7 @@ To integrate the Simulink model into \QDS, you first need to add the Simulink connector module to your project. In the \l Library view, select - \uicontrol Components > \inlineimage plus.png + \uicontrol Components > \inlineimage icons/plus.png > \uicontrol SimulinkConnector. \QDS is now ready to communicate with the Simulink model. @@ -156,7 +156,7 @@ \uicontrol SimulinkConnector item in \l Navigator and set the IP address and/or port in the \l Properties view. If you cannot see \uicontrol SimulinkConnector in \uicontrol Navigator, you need to click - \inlineimage filtericon.png + \inlineimage icons/filtericon.png (\uicontrol {Filter Tree}) and unselect \uicontrol {Show only visible items}. To communicate with a specific model in Simulink, you need to create diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc index 3b24cf2815a..112a7f73a57 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc @@ -166,7 +166,7 @@ \section2 Importing Assets \list 1 - \li Select \uicontrol Library > \uicontrol Assets > \inlineimage plus.png + \li Select \uicontrol Library > \uicontrol Assets > \inlineimage icons/plus.png . \image exporting-from-qt3ds/09-add-new-assets.png diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-custom-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-custom-shaders.qdoc index 4bf5e030116..489ca9519f0 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-custom-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-custom-shaders.qdoc @@ -155,7 +155,7 @@ The \uicontrol Passes property contains a list of render passes implemented by the effect. You can add more entry fields to the list - by selecting \inlineimage plus.png + by selecting \inlineimage icons/plus.png . For more information, see \l {Custom Effects and Materials}. \row diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index 43b307c27ff..caaa5bc635b 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -44,7 +44,7 @@ \l{Lights}{light}, \l{3D Models}{model}, and \l {Materials and Shaders}{materials}. If your scene did not contain them, you can add the corresponding \l {3D Components}{Qt Quick 3D} - components from \l Library > \uicontrol Components > \inlineimage plus.png + components from \l Library > \uicontrol Components > \inlineimage icons/plus.png > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D}. You can use the \l{Summary of the 3D Editor Toolbar Buttons}{toolbar buttons} @@ -71,7 +71,7 @@ grid. To refresh the contents of \uicontrol {3D Editor}, press \key P or - select the \inlineimage reset.png + select the \inlineimage icons/reset.png (\uicontrol {Reset View}) button. \image studio-3d-editor.png "3D Editor" @@ -297,7 +297,7 @@ \li \key G \li \row - \li \inlineimage reset.png + \li \inlineimage icons/reset.png \li Reset View \li \key R \li diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc index ae12772cf4d..b46ce6b005d 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc @@ -66,7 +66,7 @@ \list 1 \li In the \l{Design Views}{Design mode}, select \l Library > - \uicontrol Assets > \inlineimage plus.png + \uicontrol Assets > \inlineimage icons/plus.png . \li Select \uicontrol {3D Assets} in the dropdown menu to filter 3D graphics files. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc index 31a9c90be95..1641fe159d3 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc @@ -119,7 +119,7 @@ \uicontrol Instances, select each \uicontrol {Instance List Entry} you wish to include in the \uicontrol {Instance List} by using the dropdown menu. You can add more fields for the property by - clicking the \inlineimage plus.png + clicking the \inlineimage icons/plus.png icon. \li To define an \uicontrol {Instance List Entry}, select it in \uicontrol Navigator, and specify its properties in diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc index b593f544e02..2485481e3ab 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc @@ -227,6 +227,6 @@ You can apply the same material to another component as well. Again, delete the default material first. You should then select the component and go to the \uicontrol Properties view. Find the \uicontrol Materials property, - select the \inlineimage plus.png + select the \inlineimage icons/plus.png icon, and choose the new material in the dropdown menu. */ diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc index 4f98406dd9d..97a0303989e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc @@ -54,7 +54,7 @@ \l Properties view. You can apply the same material to another component as well. Again, delete the default material first. You should then select the component and go to the \uicontrol Properties view. Find the - \uicontrol Materials property, select the \inlineimage plus.png + \uicontrol Materials property, select the \inlineimage icons/plus.png icon, and choose the new material in the dropdown menu. Each material has its own set of properties that can be used to further diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-model.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-model.qdoc index 33c5e23b9a0..a55c90ea806 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-model.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-model.qdoc @@ -53,7 +53,7 @@ \section1 Model Properties You can change the model type in \uicontrol Properties > \uicontrol Model - > \uicontrol Source field. Select the \inlineimage plus.png + > \uicontrol Source field. Select the \inlineimage icons/plus.png button to add custom model types to the list. \image studio-qtquick-3d-model.png "Model properties" @@ -69,7 +69,7 @@ A model can consist of several sub-meshes, each of which can have its own material. Select the material from the list in the \uicontrol {Materials} - field. Select the \inlineimage plus.png + field. Select the \inlineimage icons/plus.png button to add materials to the list. For more information about materials, see \l {Materials and Shaders}. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc index 06e08b267a3..b965fa4454e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc @@ -86,7 +86,7 @@ To add a particle system that emits sprite particles: \list 1 - \li Select \uicontrol Library > \uicontrol Assets > \inlineimage plus.png + \li Select \uicontrol Library > \uicontrol Assets > \inlineimage icons/plus.png to add your sprites, 3D models, textures, and other graphical \l{Assets}{assets} to the project. \li Drag-and-drop an instance of the \uicontrol {Particle System} @@ -1016,7 +1016,7 @@ \uicontrol System. To only affect some of the particles in the particle system, select - them in \uicontrol Particles. Select \inlineimage plus.png + them in \uicontrol Particles. Select \inlineimage icons/plus.png to add logical particles to the list. Deselect \uicontrol Enabled to turn the affector off. Usually, this diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc index 82107b75074..7fb91b2c90a 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc @@ -54,7 +54,7 @@ \list 1 \li Select \uicontrol View > \uicontrol Views > \l {Connection View} > \uicontrol {Bindings}. - \li Select the \inlineimage plus.png + \li Select the \inlineimage icons/plus.png (\uicontrol Add) button to add a binding for the currently selected component. The component ID is displayed in the \uicontrol Item column. diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc index c0db8d22e79..55c7f9ce1d5 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc @@ -65,7 +65,7 @@ \list 1 \li Select \uicontrol View > \uicontrol Views > \uicontrol {Connection View} > \uicontrol {Properties}. - \li Select the \inlineimage plus.png + \li Select the \inlineimage icons/plus.png (\uicontrol Add) button to add a dynamic property for the currently selected component. The component ID is displayed in the \uicontrol Item column. diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc index 754066a93c4..fffd8d53956 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc @@ -70,7 +70,7 @@ \list 1 \li Select \uicontrol View > \uicontrol Views > \l {Connection View} > \uicontrol {Connections}. - \li Select the \inlineimage plus.png + \li Select the \inlineimage icons/plus.png (\uicontrol Add) button to add a connection. \li Double-click the value in the \uicontrol Target column to add the component to connect to a signal. diff --git a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc index 7536e8c7574..8d0efbfb4da 100644 --- a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc @@ -148,19 +148,19 @@ \li Keyboard Shortcut \li Read More \row - \li \inlineimage prev.png + \li \inlineimage icons/prev.png \li \uicontrol {Go Back}: moves a step backwards in your location history. That is, returns the focus to the last location in the last file it was on. \li \key Alt+< (\key Opt+Cmd+< on \macos) \li \l{Navigating Between Open Files and Symbols} \row - \li \inlineimage next.png + \li \inlineimage icons/next.png \li \uicontrol {Go Forward}: moves a step forward in your location history. \li \key Alt+> (\key Opt+Cmd+> on \macos) \li \l{Navigating Between Open Files and Symbols} \row - \li \inlineimage unlocked.png + \li \inlineimage icons/unlocked.png \li File is writable: the currently open file can be modified and saved. \li \li \l{Open Documents} @@ -178,7 +178,7 @@ \li \li \l{Open Documents} \row - \li \inlineimage close.png + \li \inlineimage icons/close.png \li \uicontrol {Close Document}: closes the current file. \li \key Ctrl+W (\key Cmd+W on \macos) \li @@ -226,7 +226,7 @@ \li \key Shift+F \li \l{Setting Anchors and Margins} \row - \li \inlineimage qtcreator-anchors-reset-icon.png + \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} diff --git a/doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc index 5a6825ca6cb..9a530cb661d 100644 --- a/doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-easing-curve-editor.qdoc @@ -102,7 +102,7 @@ When you attach easing curves to keyframes, the shape of the \l{keyframe_marker}{keyframe marker} on a keyframe track in - \l Timeline changes from \inlineimage keyframe_linear_inactive.png + \l Timeline changes from \inlineimage icons/keyframe_linear_active.png to a marker that describes the type of the selected easing curve. \section1 Attaching Easing Curves to Transitions diff --git a/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc index bcd93176159..babada1e631 100644 --- a/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-form-editor.qdoc @@ -72,7 +72,7 @@ align them. \li \l{Snapping to Parent and Sibling Components} \row - \li \inlineimage boundingrect.png + \li \inlineimage icons/boundingrect.png \li Hides and shows component instance boundaries. \li \l{Hiding Component Boundaries} \row @@ -108,7 +108,7 @@ \li Zooms to fit the current selection. \li \l{Zooming} \row - \li \inlineimage reset.png + \li \inlineimage icons/reset.png \li Refreshes the contents of \uicontrol {Form Editor}. \li \l{Refreshing Form Editor Contents} \endtable @@ -199,7 +199,7 @@ \section1 Hiding Component Boundaries \uicontrol {Form Editor} displays the boundaries of component instances. - To hide them, select the \inlineimage boundingrect.png + To hide them, select the \inlineimage icons/boundingrect.png button. \section1 Previewing Component Size @@ -254,7 +254,7 @@ \uicontrol {Form Editor}. To refresh the contents of \uicontrol {Form Editor}, press \key R or - select the \inlineimage reset.png + select the \inlineimage icons/reset.png (\uicontrol {Reset View}) button. \include qtquick-component-context-menu.qdocinc context-menu diff --git a/doc/qtdesignstudio/src/views/qtquick-library.qdoc b/doc/qtdesignstudio/src/views/qtquick-library.qdoc index adf66688b16..b70cb1ddde4 100644 --- a/doc/qtdesignstudio/src/views/qtquick-library.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-library.qdoc @@ -98,7 +98,7 @@ contains basic components and UI controls, while a 3D application project contains additional 3D components. - To view the list of available modules, select \inlineimage plus.png + To view the list of available modules, select \inlineimage icons/plus.png . Most commonly used modules are placed at the top of the list in alphabetical order. You can search for components and modules by entering search criteria in the \uicontrol Search field. @@ -120,7 +120,7 @@ \uicontrol Library > \uicontrol {Assets} displays the images and other files that you add to the project folder by dragging-and-dropping external asset - files to \QDS or by selecting \inlineimage plus.png + files to \QDS or by selecting \inlineimage icons/plus.png . For more information about importing assets to \QDS, see \l {Importing 2D Assets} and \l {Importing 3D Assets}. diff --git a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc index 3e50256a205..5bdc89095a5 100644 --- a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc @@ -86,7 +86,7 @@ \li Moves the component up within its parent. \li \l{Arranging Components} \row - \li \inlineimage filtericon.png + \li \inlineimage icons/filtericon.png \li Shows and hides invisible components in \uicontrol Navigator. \li \l{Showing and Hiding Components} \row @@ -122,7 +122,7 @@ parent component. To hide invisible components in \uicontrol Navigator, click - \inlineimage filtericon.png + \inlineimage icons/filtericon.png (\uicontrol {Filter Tree}) and select \uicontrol {Show Only Visible Components}. @@ -164,7 +164,7 @@ the bottom of the \uicontrol Navigator tree and behind overlapping components in \uicontrol {Form Editor}. To list the components in the order in which they appear in the file, as some other tools do, click - \inlineimage filtericon.png + \inlineimage icons/filtericon.png (\uicontrol {Filter Tree}), and select \uicontrol {Reverse Component Order}. To move a component to the top or bottom of the tree within its parent, diff --git a/doc/qtdesignstudio/src/views/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc index 71d4eba388c..bd30a1bf40a 100644 --- a/doc/qtdesignstudio/src/views/qtquick-states.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-states.qdoc @@ -178,7 +178,7 @@ \list 1 \li In the base state, add all components you will need in the application (1). While you work on one view, you can click the - \inlineimage eye_open.png + \inlineimage icons/eye_open.png icon in \l Navigator to hide components on the canvas that are not part of a view. \li In \uicontrol States, select \uicontrol {Create New State} to create diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc index 246442def94..6cf56cfb267 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc @@ -37,7 +37,7 @@ \image studio-timeline-empty.png "Empty Timeline view" - Select the \inlineimage plus.png + Select the \inlineimage icons/plus.png (\uicontrol {Add Timeline}) button to \l{Creating Timelines} {create a timeline} and specify settings for it in the \uicontrol {Timeline Settings} dialog. @@ -225,13 +225,13 @@ gray, and when a keyframe itself is selected, its marker turns brown: \list - \li \inlineimage keyframe_linear_inactive.png + \li \inlineimage icons/keyframe_linear_active.png - linear easing curve - \li \inlineimage keyframe_manualbezier_inactive.png + \li \inlineimage icons/keyframe_manualbezier_active.png - manually set Bezier curve - \li \inlineimage keyframe_autobezier_inactive.png + \li \inlineimage icons/keyframe_autobezier_active.png - automatically set Bezier curve - \li \inlineimage keyframe_lineartobezier_inactive.png + \li \inlineimage icons/keyframe_lineartobezier_active.png - linear-to-Bezier curve \endlist \li \l {Editing Easing Curves} diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc index ab3e3768727..df221b57760 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc @@ -46,7 +46,7 @@ To create a timeline to animate a UI component: \list 1 - \li In the \l Timeline view, select the \inlineimage plus.png + \li In the \l Timeline view, select the \inlineimage icons/plus.png (\uicontrol {Add Timeline}) button to specify settings for the timeline and running the animation in the \uicontrol {Timeline Settings} dialog. @@ -82,12 +82,12 @@ \li Select \uicontrol Close to close the dialog and save the settings. \endlist - To create additional timelines, select the \inlineimage plus.png + To create additional timelines, select the \inlineimage icons/plus.png (\uicontrol {Add Timeline}) button next to the \uicontrol {Timeline Settings} tab. To specify settings for running timeline animations, select the - \inlineimage plus.png + \inlineimage icons/plus.png (\uicontrol {Add Animation}) button next to the \uicontrol {Animation Settings} tab. For example, you could create settings for running a part of the timeline animation between specified diff --git a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc index 12ade5c3c4b..21e270a9c8a 100644 --- a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc @@ -101,7 +101,7 @@ \li Select \uicontrol View > \uicontrol Views > \uicontrol {Transition Editor}. \image qmldesigner-transition-editor-startup.png "Empty Transition Editor" - \li Select the \inlineimage plus.png + \li Select the \inlineimage icons/plus.png (\uicontrol {Add Transition}) button to add a transition. This works only if you have added at least one state and modified at least one property in it. @@ -125,7 +125,7 @@ To add transitions: \list 1 - \li Select the \inlineimage plus.png + \li Select the \inlineimage icons/plus.png (\uicontrol {Add Transition}) button. \li In the \uicontrol {Transition ID} field, enter an ID for the transition. @@ -133,7 +133,7 @@ \li In the \uicontrol To field, select the state to transition to. \endlist - To remove the current transition, select the \inlineimage minus.png + To remove the current transition, select the \inlineimage icons/minus.png (\uicontrol {Remove Transition}) button. \if defined(qtcreator) diff --git a/scripts/build_plugin.py b/scripts/build_plugin.py index f54cf64fd8b..d3e9c7bb9e9 100755 --- a/scripts/build_plugin.py +++ b/scripts/build_plugin.py @@ -49,6 +49,8 @@ def get_arguments(): parser.add_argument('--output-path', help='Output path for resulting 7zip files') parser.add_argument('--add-path', help='Prepends a CMAKE_PREFIX_PATH to the build', action='append', dest='prefix_paths', default=[]) + parser.add_argument('--add-module-path', help='Prepends a CMAKE_MODULE_PATH to the build', + action='append', dest='module_paths', default=[]) parser.add_argument('--add-make-arg', help='Passes the argument to the make tool.', action='append', dest='make_args', default=[]) parser.add_argument('--add-config', help=('Adds the argument to the CMake configuration call. ' @@ -93,6 +95,10 @@ def build(args, paths): '-DCMAKE_INSTALL_PREFIX=' + common.to_posix_path(paths.install), '-G', 'Ninja'] + if args.module_paths: + module_paths = [common.to_posix_path(os.path.abspath(fp)) for fp in args.module_paths] + cmake_args += ['-DCMAKE_MODULE_PATH=' + ';'.join(module_paths)] + # force MSVC on Windows, because it looks for GCC in the PATH first, # even if MSVC is first mentioned in the PATH... # TODO would be nicer if we only did this if cl.exe is indeed first in the PATH diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index 4d6c87a901f..27302c374b7 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -360,6 +360,14 @@ bool GeneralHelper::isPickable(QQuick3DNode *node) const if (!node) return false; +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) + // Instancing doesn't hide child nodes, so only check for instancing on the requested node + if (auto model = qobject_cast(node)) { + if (model->instancing()) + return false; + } +#endif + QQuick3DNode *n = node; while (n) { if (!n->visible() || isLocked(n) || isHidden(n)) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 70dc4b8cc9c..76b3475872f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -100,6 +100,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include "../editor3d/qt5compat/qquick3darealight_p.h" #endif @@ -1227,7 +1228,7 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC m_inputEventTimer.setSingleShot(true); m_renderModelNodeImageViewTimer.setSingleShot(true); m_modelNode3DImageViewAsyncData.timer.setSingleShot(true); - m_repeaterAddObjectTimer.setSingleShot(true); + m_dynamicAddObjectTimer.setSingleShot(true); #ifdef FPS_COUNTER if (!_fpsTimer) { @@ -1253,7 +1254,7 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() m_inputEventTimer.stop(); m_renderModelNodeImageViewTimer.stop(); m_modelNode3DImageViewAsyncData.timer.stop(); - m_repeaterAddObjectTimer.stop(); + m_dynamicAddObjectTimer.stop(); if (m_editView3DData.rootItem) m_editView3DData.rootItem->disconnect(this); @@ -1397,20 +1398,27 @@ void Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout() changeSelection(m_lastSelectionChangeCommand); } -void Qt5InformationNodeInstanceServer::handleRepeaterAddObjectTimeout() +void Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout() { #ifdef QUICK3D_MODULE - for (auto obj : std::as_const(m_addObjectRepeaters)) { - if (auto repObj = qobject_cast(obj)) { - if (hasInstanceForObject(repObj)) { - ServerNodeInstance instance = instanceForObject(repObj); + for (auto obj : std::as_const(m_dynamicObjectConstructors)) { + auto handleHiding = [this](QQuick3DNode *node) -> bool { + if (node && hasInstanceForObject(node)) { + ServerNodeInstance instance = instanceForObject(node); handleInstanceHidden(instance, instance.internalInstance()->isHiddenInEditor(), false); + return true; } + return false; + }; + auto nodeObj = qobject_cast(obj); + if (!handleHiding(nodeObj)) { + if (auto pickTarget = obj->property("_pickTarget").value()) + handleHiding(pickTarget); } } #endif - m_addObjectRepeaters.clear(); + m_dynamicObjectConstructors.clear(); } void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos( @@ -1664,8 +1672,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList(m_3dHelper); @@ -1824,7 +1832,7 @@ void Qt5InformationNodeInstanceServer::clearScene(const ClearSceneCommand &comma m_parentChangedSet.clear(); m_completedComponentList.clear(); - m_addObjectRepeaters.clear(); + m_dynamicObjectConstructors.clear(); } void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &command) @@ -2296,6 +2304,23 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst #if QT_VERSION < QT_VERSION_CHECK(6, 2, 1) checkModel->setPickable(!edit3dHidden); #endif + } else { + auto checkRepeater = qobject_cast(checkNode); + auto checkLoader = qobject_cast(checkNode); + if (checkRepeater || checkLoader) { + // Repeaters/loaders may not yet have created their children, so we set + // _pickTarget on them and connect the notifier. + if (checkNode->property("_pickTarget").isNull()) { + if (checkRepeater) { + QObject::connect(checkRepeater, &QQuick3DRepeater::objectAdded, + this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + } else { + QObject::connect(checkLoader, &QQuick3DLoader::loaded, + this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + } + } + checkNode->setProperty("_pickTarget", QVariant::fromValue(node)); + } } }; if (auto childNode = qobject_cast(childItem)) @@ -2315,10 +2340,12 @@ bool Qt5InformationNodeInstanceServer::isInformationServer() const return true; } -void Qt5InformationNodeInstanceServer::handleRepeaterAddObject() +// This method should be connected to signals indicating a new object has been constructed outside +// normal scene creation. E.g. QQuick3DRepeater::objectAdded. +void Qt5InformationNodeInstanceServer::handleDynamicAddObject() { - m_addObjectRepeaters.insert(sender()); - m_repeaterAddObjectTimer.start(); + m_dynamicObjectConstructors.insert(sender()); + m_dynamicAddObjectTimer.start(); } // update 3D view size when it changes in creator side diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index 439b7b17a3a..b63b6ae6ed4 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -82,7 +82,7 @@ public: void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors) override; bool isInformationServer() const override; - void handleRepeaterAddObject(); + void handleDynamicAddObject(); private slots: void handleSelectionChanged(const QVariant &objs); @@ -109,7 +109,7 @@ protected: private: void handleObjectPropertyChangeTimeout(); void handleSelectionChangeTimeout(); - void handleRepeaterAddObjectTimeout(); + void handleDynamicAddObjectTimeout(); void createEditView3D(); void create3DPreviewView(); void setup3DEditView(const QList &instanceList, @@ -176,7 +176,7 @@ private: QTimer m_render3DEditViewTimer; QTimer m_renderModelNodeImageViewTimer; QTimer m_inputEventTimer; - QTimer m_repeaterAddObjectTimer; + QTimer m_dynamicAddObjectTimer; #ifdef QUICK3D_PARTICLES_MODULE bool m_particleAnimationPlaying = true; AnimationDriver *m_particleAnimationDriver = nullptr; @@ -189,7 +189,7 @@ private: QList m_pendingInputEventCommands; QObject *m_3dHelper = nullptr; int m_need3DEditViewRender = 0; - QSet m_addObjectRepeaters; + QSet m_dynamicObjectConstructors; struct ModelNode3DImageViewAsyncData { QTimer timer; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 783bfba87f4..734eeee470e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #endif namespace QmlDesigner { @@ -59,10 +60,18 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo InstanceContainer::NodeFlags flags) { #ifdef QUICK3D_MODULE - if (auto repObj = qobject_cast(object())) { + QObject *obj = object(); + auto repObj = qobject_cast(obj); + auto loadObj = qobject_cast(obj); + if (repObj || loadObj) { if (auto infoServer = qobject_cast(nodeInstanceServer())) { - QObject::connect(repObj, &QQuick3DRepeater::objectAdded, - infoServer, &Qt5InformationNodeInstanceServer::handleRepeaterAddObject); + if (repObj) { + QObject::connect(repObj, &QQuick3DRepeater::objectAdded, + infoServer, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + } else { + QObject::connect(loadObj, &QQuick3DLoader::loaded, + infoServer, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + } } } #endif diff --git a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp index 03b28bbf658..7febd56b820 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp +++ b/share/qtcreator/qml/qmlpuppet/qmlprivategate/qmlprivategate_56.cpp @@ -25,7 +25,6 @@ #include "qmlprivategate.h" -#include "metaobject.h" #include "designercustomobjectdata.h" #include diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index f37a0e05d01..6f7fbc454f4 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -121,27 +121,27 @@ Item { } StudioControls.MenuSeparator { - visible: itemsView.currentCategory === null - height: StudioTheme.Values.border + visible: itemsView.currentCategory === null && !rootView.searchActive + height: visible ? StudioTheme.Values.border : 0 } StudioControls.MenuItem { text: qsTr("Expand All") - visible: itemsView.currentCategory === null + visible: itemsView.currentCategory === null && !rootView.searchActive height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.expandAll() } StudioControls.MenuItem { text: qsTr("Collapse All") - visible: itemsView.currentCategory === null + visible: itemsView.currentCategory === null && !rootView.searchActive height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.collapseAll() } StudioControls.MenuSeparator { - visible: itemsView.currentCategory === null - height: StudioTheme.Values.border + visible: itemsView.currentCategory === null && !rootView.searchActive + height: visible ? StudioTheme.Values.border : 0 } StudioControls.MenuItem { @@ -154,18 +154,22 @@ Item { StudioControls.MenuSeparator { visible: itemsView.currentCategory - height: StudioTheme.Values.border + height: visible ? StudioTheme.Values.border : 0 } StudioControls.MenuItem { text: qsTr("Show Module Hidden Categories") + visible: !rootView.searchActive enabled: itemsView.currentImport && !itemsView.currentImport.allCategoriesVisible + height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.showImportHiddenCategories(itemsView.currentImport.importUrl) } StudioControls.MenuItem { text: qsTr("Show All Hidden Categories") + visible: !rootView.searchActive enabled: itemLibraryModel.isAnyCategoryHidden + height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.showAllHiddenCategories() } } @@ -230,8 +234,7 @@ Item { itemsView.importToRemove = importRemovable ? importUrl : "" itemsView.currentImport = model itemsView.currentCategory = null - if (!rootView.isSearchActive()) - moduleContextMenu.popup() + moduleContextMenu.popup() } Column { @@ -257,10 +260,11 @@ Item { onToggleExpand: categoryExpanded = !categoryExpanded useDefaulContextMenu: false onShowContextMenu: { - itemsView.currentCategory = model - itemsView.currentImport = parent.currentImportModel - if (!rootView.isSearchActive()) + if (!rootView.searchActive) { + itemsView.currentCategory = model + itemsView.currentImport = parent.currentImportModel moduleContextMenu.popup() + } } Grid { @@ -344,8 +348,7 @@ Item { itemsView.importToRemove = importRemovable ? importUrl : "" itemsView.currentImport = model itemsView.currentCategory = null - if (!rootView.isSearchActive()) - moduleContextMenu.popup() + moduleContextMenu.popup() } Column { @@ -385,7 +388,9 @@ Item { onClicked: (mouse) => { itemLibraryModel.selectImportCategory(parent.parent.currentImportModel.importUrl, model.index) - if (mouse.button === Qt.RightButton && !rootView.isSearchActive() && categoryModel.rowCount() !== 1) { + if (mouse.button === Qt.RightButton + && categoryModel.rowCount() !== 1 + && !rootView.searchActive) { itemsView.currentCategory = model itemsView.currentImport = parent.parent.currentImportModel moduleContextMenu.popup() diff --git a/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml index 3e91ab70f11..aa5b346b4ee 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml @@ -58,41 +58,66 @@ Item { anchors.fill: parent Item { width: parent.width; implicitHeight: 20 } // spacer + Row { width: parent.width height: DialogValues.dialogTitleTextHeight - Layout.alignment: Qt.AlignHCenter + + Item { width: DialogValues.dialogLeftPadding; height: 1 } // horizontal spacer + + Image { + asynchronous: false + source: "image://newprojectdialog_library/logo" + width: DialogValues.logoWidth + height: DialogValues.logoHeight + } + + Item { width: 10; height: 1 } + Text { - text: qsTr("Welcome to ") + text: qsTr("Let's create something wonderful with ") font.pixelSize: DialogValues.dialogTitlePixelSize font.family: "Titillium Web" height: DialogValues.dialogTitleTextHeight lineHeight: DialogValues.dialogTitleLineHeight lineHeightMode: Text.FixedHeight color: DialogValues.textColor + verticalAlignment: Text.AlignVCenter } Text { - text: qsTr("Qt Design Studio") + text: qsTr("Qt Design Studio!") font.pixelSize: DialogValues.dialogTitlePixelSize font.family: "Titillium Web" height: DialogValues.dialogTitleTextHeight lineHeight: DialogValues.dialogTitleLineHeight lineHeightMode: Text.FixedHeight - color: DialogValues.textColorInteraction + color: DialogValues.brandTextColor + verticalAlignment: Text.AlignVCenter + } + } // Row + + Item { width: 1; height: 11 } // spacer + + Item { + width: parent.width + height: DialogValues.paneTitleLineHeight + Row { + width: parent.width + height: DialogValues.paneTitleLineHeight + + Item { width: DialogValues.dialogLeftPadding; height: 1} // spacer + + Text { + width: parent.width - DialogValues.dialogLeftPadding + text: qsTr("Create new project by selecting a suitable Preset and then adjust details.") + color: DialogValues.textColor + font.pixelSize: DialogValues.paneTitlePixelSize + lineHeight: DialogValues.paneTitleLineHeight + lineHeightMode: Text.FixedHeight + } } } - - Text { - width: parent.width - text: qsTr("Create new project by selecting a suitable Preset and then adjust details.") - color: DialogValues.textColor - font.pixelSize: DialogValues.paneTitlePixelSize - lineHeight: DialogValues.paneTitleLineHeight - lineHeightMode: Text.FixedHeight - Layout.alignment: Qt.AlignHCenter - } - Item { width: parent.width; Layout.fillHeight: true} // spacer } // ColumnLayout } // Header Item @@ -102,7 +127,7 @@ Item { Layout.fillHeight: true RowLayout { - x: 35 + x: DialogValues.dialogLeftPadding width: parent.width - 70 height: parent.height spacing: 0 @@ -113,6 +138,7 @@ Item { Layout.fillHeight: true Layout.minimumWidth: 379 // figured out this number visually Layout.minimumHeight: 261 // figured out this number visually + radius: 6 Column { x: DialogValues.defaultPadding // left padding @@ -294,7 +320,7 @@ Item { } // RowLayout } // Dialog Button Box - Item { implicitWidth: 35 - DialogValues.defaultPadding } + Item { implicitWidth: DialogValues.dialogLeftPadding - DialogValues.defaultPadding } } // RowLayout } // Footer } // ColumnLayout diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/logo.png b/share/qtcreator/qmldesigner/newprojectdialog/image/logo.png new file mode 100644 index 00000000000..555e0cac58d Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/logo.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/logo@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/logo@2x.png new file mode 100644 index 00000000000..5c443d177a0 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/logo@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml index d622253a688..ab4c081db4c 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml @@ -58,7 +58,7 @@ Item { Text { id: detailsHeading text: qsTr("Details") - height: DialogValues.dialogTitleTextHeight + height: DialogValues.paneTitleTextHeight width: parent.width; font.weight: Font.DemiBold font.pixelSize: DialogValues.paneTitlePixelSize @@ -388,6 +388,7 @@ Item { width: parent.width height: orientationButton.height / 2 anchors.verticalCenter: parent.verticalCenter + radius: 3 } } @@ -401,6 +402,7 @@ Item { width: orientationButton.width / 4 height: orientationButton.height color: "white" + radius: 3 } } } diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml index b99b99dc952..ae26727e07b 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml @@ -36,7 +36,11 @@ QtObject { readonly property int dialogContentHeight: projectViewHeight + 300 // i.e. dialog without header and footer readonly property int loadedPanesWidth: detailsPaneWidth + stylesPaneWidth readonly property int detailsPaneWidth: 330 + detailsPanePadding * 2 - readonly property int dialogTitleTextHeight: 47 + readonly property int dialogTitleTextHeight: 85 + readonly property int paneTitleTextHeight: 47 + readonly property int logoWidth: 85 + readonly property int logoHeight: 85 + /* detailsScrollableContentHeight - the full height that may need to be scrolled to be fully visible, if the dialog box is too small. */ readonly property int detailsScrollableContentHeight: 428 @@ -44,6 +48,7 @@ QtObject { readonly property int detailsPanePadding: 18 readonly property int stylesPanePadding: 18 readonly property int defaultPadding: 18 + readonly property int dialogLeftPadding: 35 readonly property int styleImageWidth: 200 readonly property int styleImageBorderWidth: 2 @@ -73,9 +78,11 @@ QtObject { readonly property real viewHeaderLineHeight: 24 readonly property real paneTitlePixelSize: 18 readonly property real paneTitleLineHeight: 27 - readonly property int dialogTitlePixelSize: 32 + readonly property int dialogTitlePixelSize: 38 readonly property int dialogTitleLineHeight: 49 + readonly property string brandTextColor: "#2e769e" + // for a spacer item function narrowSpacing(value, layoutSpacing = DialogValues.defaultPadding) { /* e.g. if we want narrow spacing value = 11, then for the spacer item residing inside a diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml index 09350f56010..1464449ee75 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml @@ -52,6 +52,7 @@ Item { Rectangle { color: DialogValues.lightPaneColor anchors.fill: parent + radius: 6 Item { x: DialogValues.stylesPanePadding // left padding @@ -65,7 +66,7 @@ Item { Text { id: styleTitleText text: qsTr("Style") - Layout.minimumHeight: DialogValues.dialogTitleTextHeight + Layout.minimumHeight: DialogValues.paneTitleTextHeight font.weight: Font.DemiBold font.pixelSize: DialogValues.paneTitlePixelSize lineHeight: DialogValues.paneTitleLineHeight @@ -118,7 +119,7 @@ Item { delegate: ItemDelegate { id: delegateId - height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + 1 + height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + extraPadding.height + 1 width: stylesList.width Rectangle { @@ -134,7 +135,7 @@ Item { border.width: index == stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0 color: "transparent" width: parent.width - height: parent.height - styleText.height + height: parent.height - styleText.height - extraPadding.height Image { id: styleImage @@ -158,6 +159,8 @@ Item { width: parent.width color: DialogValues.textColor } + + Item { id: extraPadding; width: 1; height: 10 } } // Column } // Rectangle diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/PropertyTemplates/TextEditorTemplate.template b/share/qtcreator/qmldesigner/propertyEditorQmlSources/PropertyTemplates/TextEditorTemplate.template index 8e435818dea..a8ba20cafd8 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/PropertyTemplates/TextEditorTemplate.template +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/PropertyTemplates/TextEditorTemplate.template @@ -136,7 +136,7 @@ Section { SpinBox { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth - backendValue: (backendValues.%2_lineHeight === undefined) ? dummyBackendValue : backendValues.lineHeight + backendValue: (backendValues.%2_lineHeight === undefined) ? 1.0 : backendValues.lineHeight maximumValue: 500 minimumValue: 0 decimals: 2 diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/AudioSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/AudioSection.qml new file mode 100644 index 00000000000..db226e755a9 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/AudioSection.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import HelperWidgets 2.0 +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Section { + caption: qsTr("Audio") + + anchors.left: parent.left + anchors.right: parent.right + + SectionLayout { + PropertyLabel { text: qsTr("Volume") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.volume + decimals: 1 + minimumValue: 0.0 + maximumValue: 1.0 + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Muted") } + + SecondColumnLayout { + CheckBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.muted + text: backendValues.muted.valueToString + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml index 979a276e6e2..2e58189a4dd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSection.qml @@ -30,11 +30,15 @@ import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme Section { + id: root caption: qsTr("Media Player") anchors.left: parent.left anchors.right: parent.right + property bool showAudioOutput: false + property bool showVideoOutput: false + // TODO position property, what should be the range?! SectionLayout { @@ -54,11 +58,14 @@ Section { } PropertyLabel { + visible: root.showAudioOutput text: qsTr("Audio Output") tooltip: qsTr("Holds the target audio output.") } SecondColumnLayout { + visible: root.showAudioOutput + ItemFilterComboBox { implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth @@ -72,11 +79,14 @@ Section { } PropertyLabel { + visible: root.showVideoOutput text: qsTr("Video Output") tooltip: qsTr("Holds the target video output.") } SecondColumnLayout { + visible: root.showVideoOutput + ItemFilterComboBox { implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSpecifics.qml index 1a6c41ecf88..dbf25df2f69 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtMultimedia/MediaPlayerSpecifics.qml @@ -33,5 +33,8 @@ Column { anchors.left: parent.left anchors.right: parent.right - MediaPlayerSection {} + MediaPlayerSection { + showAudioOutput: true + showVideoOutput: true + } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml index 0deb638a363..f8deaaf8b8e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml @@ -199,7 +199,7 @@ Section { id: checkBox implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth - text: backendValue.valueToString + text: (checkBox.backendValue === undefined) ? "" : checkBox.backendValue.valueToString } ExpandingSpacer {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSpecifics.qml index 18d0c00b326..f5beae9ce1e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSpecifics.qml @@ -35,18 +35,17 @@ Column { showVerticalAlignment: true } - TextInputSection { - isTextInput: true - } + TextInputSection { + isTextInput: true + } - TextExtrasSection { - showWrapMode: true - showFormatProperty: true - } + TextExtrasSection { + showWrapMode: true + } - FontExtrasSection { - showStyle: false - } + FontExtrasSection { + showStyle: false + } - PaddingSection {} + PaddingSection {} } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml index 127c7a38324..acca2a0dd19 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml @@ -353,13 +353,14 @@ Section { id: lineHeightSpinBox implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth - backendValue: (backendValues.lineHeight === undefined) ? dummyBackendValue + backendValue: (backendValues.lineHeight === undefined) ? 1.0 : backendValues.lineHeight decimals: 2 minimumValue: 0 maximumValue: 500 stepSize: 0.1 - enabled: backendValue.isAvailable + enabled: (backendValues.lineHeight === undefined) ? false + : backendValue.isAvailable } ExpandingSpacer {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml index 9084df11ab7..8cf3c0fedca 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/FontExtrasSection.qml @@ -42,6 +42,13 @@ Section { return backendValues[root.fontName + "_" + name] } + function isBackendValueAvailable(name) { + if (backendValues[name] !== undefined) + return backendValues[name].isAvailable + + return false + } + SectionLayout { PropertyLabel { text: qsTr("Capitalization") @@ -89,11 +96,11 @@ Section { PropertyLabel { text: qsTr("Style color") - visible: backendValues.styleColor.isAvailable + visible: root.isBackendValueAvailable("styleColor") } ColorEditor { - visible: backendValues.styleColor.isAvailable + visible: root.isBackendValueAvailable("styleColor") backendValue: backendValues.styleColor supportGradient: false } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml index a38e5a17faf..7f98244ab2f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/StandardTextSection.qml @@ -326,13 +326,14 @@ Section { id: lineHeightSpinBox implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth - backendValue: (backendValues.lineHeight === undefined) ? dummyBackendValue + backendValue: (backendValues.lineHeight === undefined) ? 1.0 : backendValues.lineHeight decimals: 2 minimumValue: 0 maximumValue: 500 stepSize: 0.1 - enabled: backendValue.isAvailable + enabled: (backendValues.lineHeight === undefined) ? false + : backendValue.isAvailable } ExpandingSpacer {} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml index 234fea36f8a..d9dab055e2b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextExtrasSection.qml @@ -41,11 +41,20 @@ Section { property bool showFontSizeMode: false property bool showLineHeight: false + function isBackendValueAvailable(name) { + if (backendValues[name] !== undefined) + return backendValues[name].isAvailable + + return false + } + SectionLayout { + id: sectionLayout + PropertyLabel { visible: root.showWrapMode text: qsTr("Wrap mode") - blockedByTemplate: !backendValues.wrapMode.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("wrapMode") } SecondColumnLayout { @@ -58,7 +67,7 @@ Section { backendValue: backendValues.wrapMode scope: "Text" model: ["NoWrap", "WordWrap", "WrapAnywhere", "Wrap"] - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("wrapMode") } ExpandingSpacer {} @@ -67,7 +76,7 @@ Section { PropertyLabel { visible: root.showElide text: qsTr("Elide") - blockedByTemplate: !backendValues.elide.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("elide") } SecondColumnLayout { @@ -80,7 +89,7 @@ Section { backendValue: backendValues.elide scope: "Text" model: ["ElideNone", "ElideLeft", "ElideMiddle", "ElideRight"] - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("elide") } ExpandingSpacer {} @@ -89,7 +98,7 @@ Section { PropertyLabel { visible: root.showFormatProperty text: qsTr("Format") - blockedByTemplate: !backendValues.textFormat.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("textFormat") } SecondColumnLayout { @@ -100,9 +109,9 @@ Section { + StudioTheme.Values.actionIndicatorWidth width: implicitWidth scope: "Text" - model: ["PlainText", "RichText", "AutoText"] + model: ["PlainText", "RichText", "AutoText", "StyledText", "MarkdownText"] backendValue: backendValues.textFormat - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("textFormat") } ExpandingSpacer {} @@ -111,7 +120,7 @@ Section { PropertyLabel { text: qsTr("Render type") tooltip: qsTr("Overrides the default rendering type for this component.") - blockedByTemplate: !backendValues.renderType.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("renderType") } SecondColumnLayout { @@ -122,7 +131,7 @@ Section { scope: "Text" model: ["QtRendering", "NativeRendering"] backendValue: backendValues.renderType - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("renderType") } ExpandingSpacer {} @@ -132,7 +141,7 @@ Section { visible: root.showLineHeight text: qsTr("Line height mode") tooltip: qsTr("Determines how the line height is specified.") - blockedByTemplate: !backendValues.lineHeightMode.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("lineHeightMode") } SecondColumnLayout { @@ -145,7 +154,7 @@ Section { implicitWidth: StudioTheme.Values.singleControlColumnWidth + StudioTheme.Values.actionIndicatorWidth width: implicitWidth - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("lineHeightMode") } ExpandingSpacer {} @@ -155,7 +164,7 @@ Section { visible: root.showFontSizeMode text: qsTr("Size mode") tooltip: qsTr("Specifies how the font size of the displayed text is determined.") - blockedByTemplate: !backendValues.fontSizeMode.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("fontSizeMode") } SecondColumnLayout { @@ -169,7 +178,7 @@ Section { scope: "Text" model: ["FixedSize", "HorizontalFit", "VerticalFit", "Fit"] backendValue: backendValues.fontSizeMode - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("fontSizeMode") } ExpandingSpacer {} @@ -178,15 +187,16 @@ Section { PropertyLabel { visible: root.showFontSizeMode text: qsTr("Min size") - blockedByTemplate: !backendValues.minimumPixelSize.isAvailable - && !backendValues.minimumPointSize.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("minimumPixelSize") + && !root.isBackendValueAvailable("minimumPointSize") } SecondColumnLayout { visible: root.showFontSizeMode SpinBox { - enabled: (fontSizeMode.currentIndex !== 0) || backendValue.isAvailable + enabled: (fontSizeMode.currentIndex !== 0) + || root.isBackendValueAvailable("minimumPixelSize") minimumValue: 0 maximumValue: 500 decimals: 0 @@ -200,13 +210,14 @@ Section { ControlLabel { text: "px" tooltip: qsTr("Minimum font pixel size of scaled text.") - enabled: backendValues.minimumPixelSize.isAvailable + enabled: root.isBackendValueAvailable("minimumPixelSize") } Spacer { implicitWidth: StudioTheme.Values.controlGap } SpinBox { - enabled: (fontSizeMode.currentIndex !== 0) || backendValue.isAvailable + enabled: (fontSizeMode.currentIndex !== 0) + || root.isBackendValueAvailable("minimumPointSize") minimumValue: 0 maximumValue: 500 decimals: 0 @@ -220,7 +231,7 @@ Section { ControlLabel { text: "pt" tooltip: qsTr("Minimum font point size of scaled text.") - enabled: backendValues.minimumPointSize.isAvailable + enabled: root.isBackendValueAvailable("minimumPointSize") } ExpandingSpacer {} @@ -230,7 +241,7 @@ Section { visible: root.showElide text: qsTr("Max line count") tooltip: qsTr("Limits the number of lines that the text component will show.") - blockedByTemplate: !backendValues.maximumLineCount.isAvailable + blockedByTemplate: !root.isBackendValueAvailable("maximumLineCount") } SecondColumnLayout { @@ -243,7 +254,7 @@ Section { minimumValue: 0 maximumValue: 10000 decimals: 0 - enabled: backendValue.isAvailable + enabled: root.isBackendValueAvailable("maximumLineCount") } ExpandingSpacer {} diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index 1e592865cff..faae1210b5b 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -40,7 +40,6 @@ Rectangle { property color baseColor property string delegateStateName property string delegateStateImageSource - property int delegateStateImageSize property bool delegateHasWhenCondition property string delegateWhenConditionString property bool hasAnnotation: checkAnnotation() @@ -70,7 +69,6 @@ Rectangle { MouseArea { id: mouseArea anchors.fill: parent - acceptedButtons: Qt.LeftButton onClicked: { focus = true root.currentStateInternalId = internalNodeId @@ -168,7 +166,7 @@ Rectangle { } - Rectangle { + Rectangle { // highlight for default state anchors.margins: (isDefaultState || (isBaseState && !modelHasDefaultState)) ? -myRoot.highlightBorderWidth : 0 anchors.fill: column color: StudioTheme.Values.themeStateSeparator @@ -176,7 +174,6 @@ Rectangle { border.width: (isDefaultState || (isBaseState && !modelHasDefaultState)) ? myRoot.highlightBorderWidth : 0 } - Column { id: column @@ -185,7 +182,6 @@ Rectangle { spacing: expanded ? myRoot.columnSpacing : 0 Rectangle { - width: myRoot.width - 2 * myRoot.stateMargin height: myRoot.topAreaHeight @@ -261,13 +257,12 @@ Rectangle { font.pixelSize: StudioTheme.Values.myFontSize font.family: StudioTheme.Constants.font - visible: (isDefaultState || (isBaseState && !modelHasDefaultState)) + visible: isDefaultState || (isBaseState && !modelHasDefaultState) text: qsTr("Default") } } - Rectangle { id: stateImageArea width: myRoot.width - 2 * myRoot.stateMargin @@ -297,8 +292,6 @@ Rectangle { anchors.centerIn: parent anchors.fill: parent source: delegateStateImageSource - sourceSize.width: delegateStateImageSize - sourceSize.height: delegateStateImageSize fillMode: Image.PreserveAspectFit } } @@ -329,5 +322,4 @@ Rectangle { hideWidget() } } - } diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml index 5bb834011f3..6f2dfbbf3d0 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesList.qml @@ -34,20 +34,18 @@ FocusScope { id: root property int delegateTopAreaHeight: StudioTheme.Values.height + 8 - property int delegateBottomAreaHeight: 200 + property int delegateBottomAreaHeight: delegateHeight - 2 * delegateStateMargin - delegateTopAreaHeight - delegateColumnSpacing property int delegateColumnSpacing: 2 property int delegateStateMargin: 16 - property int delegatePreviewMargin: 16 - property int effectiveHeight: root.expanded ? 287 : 85 // height of the states area + property int delegatePreviewMargin: 10 + property int effectiveHeight: root.expanded ? Math.max(85, Math.min(287, root.height)) : 85 // height of the states area signal createNewState signal deleteState(int internalNodeId) signal duplicateCurrentState - property int stateImageSize: 200 property int padding: 2 - property int delegateWidth: root.stateImageSize - + 2 * (root.delegateStateMargin + root.delegatePreviewMargin) + property int delegateWidth: 264 property int delegateHeight: effectiveHeight - StudioTheme.Values.scrollBarThickness - 2 * (root.padding + StudioTheme.Values.border) @@ -102,8 +100,8 @@ FocusScope { anchors.right: parent.right anchors.rightMargin: 8 y: (Math.min(effectiveHeight, root.height) - height) / 2 - width: Math.max(root.delegateHeight / 2 - 8, 18) - height: root.expanded ? 60 : width + width: root.expanded ? 140 : 18 + height: root.expanded ? 60 : 18 onClicked: { contextMenu.dismiss() @@ -144,7 +142,6 @@ FocusScope { baseColor: isCurrentState ? StudioTheme.Values.themeInteraction : background.color delegateStateName: stateName delegateStateImageSource: stateImageSource - delegateStateImageSize: stateImageSize delegateHasWhenCondition: hasWhenCondition delegateWhenConditionString: whenConditionString onDelegateInteraction: contextMenu.dismiss() diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt index c2009339259..3ad2d371e8e 100644 --- a/src/libs/sqlite/CMakeLists.txt +++ b/src/libs/sqlite/CMakeLists.txt @@ -14,7 +14,7 @@ add_qtc_library(Sqlite ../3rdparty/sqlite/config.h ../3rdparty/sqlite/sqlite.h constraints.h - createtablesqlstatementbuilder.cpp createtablesqlstatementbuilder.h + createtablesqlstatementbuilder.h lastchangedrowid.h sqlitealgorithms.h sqlitebasestatement.cpp sqlitebasestatement.h diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.cpp b/src/libs/sqlite/createtablesqlstatementbuilder.cpp deleted file mode 100644 index d237d8e8fca..00000000000 --- a/src/libs/sqlite/createtablesqlstatementbuilder.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "createtablesqlstatementbuilder.h" - -namespace Sqlite { - -CreateTableSqlStatementBuilder::CreateTableSqlStatementBuilder() - : m_sqlStatementBuilder("CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId") -{ -} - -void CreateTableSqlStatementBuilder::setTableName(Utils::SmallString &&tableName) -{ - m_sqlStatementBuilder.clear(); - - this->m_tableName = std::move(tableName); -} - -void CreateTableSqlStatementBuilder::addColumn(Utils::SmallStringView columnName, - ColumnType columnType, - Constraints &&constraints) -{ - m_sqlStatementBuilder.clear(); - - m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints)); -} - -void CreateTableSqlStatementBuilder::addConstraint(TableConstraint &&constraint) -{ - m_tableConstraints.push_back(std::move(constraint)); -} - -void CreateTableSqlStatementBuilder::setConstraints(TableConstraints constraints) -{ - m_tableConstraints = std::move(constraints); -} - -void CreateTableSqlStatementBuilder::setColumns(SqliteColumns columns) -{ - m_sqlStatementBuilder.clear(); - - m_columns = std::move(columns); -} - -void CreateTableSqlStatementBuilder::setUseWithoutRowId(bool useWithoutRowId) -{ - m_useWithoutRowId = useWithoutRowId; -} - -void CreateTableSqlStatementBuilder::setUseIfNotExists(bool useIfNotExists) -{ - m_useIfNotExits = useIfNotExists; -} - -void CreateTableSqlStatementBuilder::setUseTemporaryTable(bool useTemporaryTable) -{ - m_useTemporaryTable = useTemporaryTable; -} - -void CreateTableSqlStatementBuilder::clear() -{ - m_sqlStatementBuilder.clear(); - m_columns.clear(); - m_tableName.clear(); - m_useWithoutRowId = false; -} - -void CreateTableSqlStatementBuilder::clearColumns() -{ - m_sqlStatementBuilder.clear(); - m_columns.clear(); -} - -Utils::SmallStringView CreateTableSqlStatementBuilder::sqlStatement() const -{ - if (!m_sqlStatementBuilder.isBuild()) - bindAll(); - - return m_sqlStatementBuilder.sqlStatement(); -} - -bool CreateTableSqlStatementBuilder::isValid() const -{ - return m_tableName.hasContent() && !m_columns.empty(); -} - -namespace { -Utils::SmallStringView actionToText(ForeignKeyAction action) -{ - switch (action) { - case ForeignKeyAction::NoAction: - return "NO ACTION"; - case ForeignKeyAction::Restrict: - return "RESTRICT"; - case ForeignKeyAction::SetNull: - return "SET NULL"; - case ForeignKeyAction::SetDefault: - return "SET DEFAULT"; - case ForeignKeyAction::Cascade: - return "CASCADE"; - } - - return ""; -} - -class ContraintsVisiter -{ -public: - ContraintsVisiter(Utils::SmallString &columnDefinitionString) - : columnDefinitionString(columnDefinitionString) - {} - - void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); } - - void operator()(const PrimaryKey &primaryKey) - { - columnDefinitionString.append(" PRIMARY KEY"); - if (primaryKey.autoincrement == AutoIncrement::Yes) - columnDefinitionString.append(" AUTOINCREMENT"); - } - - void operator()(const ForeignKey &foreignKey) - { - columnDefinitionString.append(" REFERENCES "); - columnDefinitionString.append(foreignKey.table); - - if (foreignKey.column.hasContent()) { - columnDefinitionString.append("("); - columnDefinitionString.append(foreignKey.column); - columnDefinitionString.append(")"); - } - - if (foreignKey.updateAction != ForeignKeyAction::NoAction) { - columnDefinitionString.append(" ON UPDATE "); - columnDefinitionString.append(actionToText(foreignKey.updateAction)); - } - - if (foreignKey.deleteAction != ForeignKeyAction::NoAction) { - columnDefinitionString.append(" ON DELETE "); - columnDefinitionString.append(actionToText(foreignKey.deleteAction)); - } - - if (foreignKey.enforcement == Enforment::Deferred) - columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED"); - } - - void operator()(const NotNull &) { columnDefinitionString.append(" NOT NULL"); } - - void operator()(const Check &check) - { - columnDefinitionString.append(" CHECK ("); - columnDefinitionString.append(check.expression); - columnDefinitionString.append(")"); - } - - void operator()(const DefaultValue &defaultValue) - { - columnDefinitionString.append(" DEFAULT "); - switch (defaultValue.value.type()) { - case Sqlite::ValueType::Integer: - columnDefinitionString.append( - Utils::SmallString::number(defaultValue.value.toInteger())); - break; - case Sqlite::ValueType::Float: - columnDefinitionString.append(Utils::SmallString::number(defaultValue.value.toFloat())); - break; - case Sqlite::ValueType::String: - columnDefinitionString.append("'"); - columnDefinitionString.append(defaultValue.value.toStringView()); - columnDefinitionString.append("'"); - break; - default: - break; - } - } - - void operator()(const DefaultExpression &defaultexpression) - { - columnDefinitionString.append(" DEFAULT ("); - columnDefinitionString.append(defaultexpression.expression); - columnDefinitionString.append(")"); - } - - void operator()(const Collate &collate) - { - columnDefinitionString.append(" COLLATE "); - columnDefinitionString.append(collate.collation); - } - - void operator()(const GeneratedAlways &generatedAlways) - { - columnDefinitionString.append(" GENERATED ALWAYS AS ("); - columnDefinitionString.append(generatedAlways.expression); - columnDefinitionString.append(")"); - - if (generatedAlways.storage == Sqlite::GeneratedAlwaysStorage::Virtual) - columnDefinitionString.append(" VIRTUAL"); - else - columnDefinitionString.append(" STORED"); - } - - Utils::SmallString &columnDefinitionString; -}; - -class TableContraintsVisiter -{ -public: - TableContraintsVisiter(Utils::SmallString &columnDefinitionString) - : columnDefinitionString(columnDefinitionString) - {} - - void operator()(const TablePrimaryKey &primaryKey) - { - columnDefinitionString.append("PRIMARY KEY("); - columnDefinitionString.append(primaryKey.columns.join(", ")); - columnDefinitionString.append(")"); - } - - Utils::SmallString &columnDefinitionString; -}; -} // namespace -void CreateTableSqlStatementBuilder::bindColumnDefinitionsAndTableConstraints() const -{ - Utils::SmallStringVector columnDefinitionStrings; - columnDefinitionStrings.reserve(m_columns.size()); - - for (const Column &column : m_columns) { - auto columnDefinitionString = Utils::SmallString::join( - {column.name, SqlStatementBuilder::columnTypeToString(column.type)}); - - ContraintsVisiter visiter{columnDefinitionString}; - - for (const Constraint &constraint : column.constraints) - Utils::visit(visiter, constraint); - - columnDefinitionStrings.push_back(std::move(columnDefinitionString)); - } - - for (const TableConstraint &constraint : m_tableConstraints) { - Utils::SmallString columnDefinitionString; - - TableContraintsVisiter visiter{columnDefinitionString}; - Utils::visit(visiter, constraint); - - columnDefinitionStrings.push_back(std::move(columnDefinitionString)); - } - - m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings); -} - -void CreateTableSqlStatementBuilder::bindAll() const -{ - m_sqlStatementBuilder.bind("$table", m_tableName.clone()); - - bindTemporary(); - bindIfNotExists(); - bindColumnDefinitionsAndTableConstraints(); - bindWithoutRowId(); -} - -void CreateTableSqlStatementBuilder::bindWithoutRowId() const -{ - if (m_useWithoutRowId) - m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID"); - else - m_sqlStatementBuilder.bindEmptyText("$withoutRowId"); -} - -void CreateTableSqlStatementBuilder::bindIfNotExists() const -{ - if (m_useIfNotExits) - m_sqlStatementBuilder.bind("$ifNotExits", "IF NOT EXISTS "); - else - m_sqlStatementBuilder.bindEmptyText("$ifNotExits"); -} - -void CreateTableSqlStatementBuilder::bindTemporary() const -{ - if (m_useTemporaryTable) - m_sqlStatementBuilder.bind("$temporary", "TEMPORARY "); - else - m_sqlStatementBuilder.bindEmptyText("$temporary"); -} - -} // namespace Sqlite diff --git a/src/libs/sqlite/createtablesqlstatementbuilder.h b/src/libs/sqlite/createtablesqlstatementbuilder.h index 3e3743e9da0..fb53e68a426 100644 --- a/src/libs/sqlite/createtablesqlstatementbuilder.h +++ b/src/libs/sqlite/createtablesqlstatementbuilder.h @@ -29,43 +29,326 @@ #include "sqlstatementbuilder.h" #include "tableconstraints.h" +#include + namespace Sqlite { +template class SQLITE_EXPORT CreateTableSqlStatementBuilder { public: - CreateTableSqlStatementBuilder(); + CreateTableSqlStatementBuilder() + : m_sqlStatementBuilder(templateText()) + {} - void setTableName(Utils::SmallString &&tableName); + void setTableName(Utils::SmallString &&tableName) + { + m_sqlStatementBuilder.clear(); + + this->m_tableName = std::move(tableName); + } void addColumn(Utils::SmallStringView columnName, ColumnType columnType, - Constraints &&constraints = {}); - void addConstraint(TableConstraint &&constraint); - void setConstraints(TableConstraints constraints); - void setColumns(SqliteColumns columns); - void setUseWithoutRowId(bool useWithoutRowId); - void setUseIfNotExists(bool useIfNotExists); - void setUseTemporaryTable(bool useTemporaryTable); + Constraints &&constraints = {}) + { + m_sqlStatementBuilder.clear(); - void clear(); - void clearColumns(); + m_columns.emplace_back(Utils::SmallStringView{}, columnName, columnType, std::move(constraints)); + } + void addConstraint(TableConstraint &&constraint) + { + m_tableConstraints.push_back(std::move(constraint)); + } + void setConstraints(TableConstraints constraints) + { + m_tableConstraints = std::move(constraints); + } + void setColumns(BasicColumns columns) + { + m_sqlStatementBuilder.clear(); - Utils::SmallStringView sqlStatement() const; + m_columns = std::move(columns); + } - bool isValid() const; + void setUseWithoutRowId(bool useWithoutRowId) { m_useWithoutRowId = useWithoutRowId; } -protected: - void bindColumnDefinitionsAndTableConstraints() const; - void bindAll() const; - void bindWithoutRowId() const; - void bindIfNotExists() const; - void bindTemporary() const; + void setUseIfNotExists(bool useIfNotExists) { m_useIfNotExits = useIfNotExists; } + + void setUseTemporaryTable(bool useTemporaryTable) { m_useTemporaryTable = useTemporaryTable; } + + void clear() + { + m_sqlStatementBuilder.clear(); + m_columns.clear(); + m_tableName.clear(); + m_useWithoutRowId = false; + } + + void clearColumns() + { + m_sqlStatementBuilder.clear(); + m_columns.clear(); + } + + Utils::SmallStringView sqlStatement() const + { + if (!m_sqlStatementBuilder.isBuild()) + bindAll(); + + return m_sqlStatementBuilder.sqlStatement(); + } + + bool isValid() const { return m_tableName.hasContent() && !m_columns.empty(); } + +private: + static Utils::SmallStringView templateText() + { + if constexpr (std::is_same_v) { + return "CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId"; + } + + return "CREATE $temporaryTABLE $ifNotExits$table($columnDefinitions)$withoutRowId STRICT"; + } + + static Utils::SmallString columnTypeToString(ColumnType columnType) + { + if constexpr (std::is_same_v) { + switch (columnType) { + case ColumnType::Numeric: + return " NUMERIC"; + case ColumnType::Integer: + return " INTEGER"; + case ColumnType::Real: + return " REAL"; + case ColumnType::Text: + return " TEXT"; + case ColumnType::Blob: + return " BLOB"; + case ColumnType::None: + return {}; + } + } else { + switch (columnType) { + case ColumnType::Any: + return " ANY"; + case ColumnType::Int: + return " INT"; + case ColumnType::Integer: + return " INTEGER"; + case ColumnType::Real: + return " REAL"; + case ColumnType::Text: + return " TEXT"; + case ColumnType::Blob: + return " BLOB"; + } + } + + return ""; + } + + static Utils::SmallStringView actionToText(ForeignKeyAction action) + { + switch (action) { + case ForeignKeyAction::NoAction: + return "NO ACTION"; + case ForeignKeyAction::Restrict: + return "RESTRICT"; + case ForeignKeyAction::SetNull: + return "SET NULL"; + case ForeignKeyAction::SetDefault: + return "SET DEFAULT"; + case ForeignKeyAction::Cascade: + return "CASCADE"; + } + + return ""; + } + + class ContraintsVisiter + { + public: + ContraintsVisiter(Utils::SmallString &columnDefinitionString) + : columnDefinitionString(columnDefinitionString) + {} + + void operator()(const Unique &) { columnDefinitionString.append(" UNIQUE"); } + + void operator()(const PrimaryKey &primaryKey) + { + columnDefinitionString.append(" PRIMARY KEY"); + if (primaryKey.autoincrement == AutoIncrement::Yes) + columnDefinitionString.append(" AUTOINCREMENT"); + } + + void operator()(const ForeignKey &foreignKey) + { + columnDefinitionString.append(" REFERENCES "); + columnDefinitionString.append(foreignKey.table); + + if (foreignKey.column.hasContent()) { + columnDefinitionString.append("("); + columnDefinitionString.append(foreignKey.column); + columnDefinitionString.append(")"); + } + + if (foreignKey.updateAction != ForeignKeyAction::NoAction) { + columnDefinitionString.append(" ON UPDATE "); + columnDefinitionString.append(actionToText(foreignKey.updateAction)); + } + + if (foreignKey.deleteAction != ForeignKeyAction::NoAction) { + columnDefinitionString.append(" ON DELETE "); + columnDefinitionString.append(actionToText(foreignKey.deleteAction)); + } + + if (foreignKey.enforcement == Enforment::Deferred) + columnDefinitionString.append(" DEFERRABLE INITIALLY DEFERRED"); + } + + void operator()(const NotNull &) { columnDefinitionString.append(" NOT NULL"); } + + void operator()(const Check &check) + { + columnDefinitionString.append(" CHECK ("); + columnDefinitionString.append(check.expression); + columnDefinitionString.append(")"); + } + + void operator()(const DefaultValue &defaultValue) + { + columnDefinitionString.append(" DEFAULT "); + switch (defaultValue.value.type()) { + case Sqlite::ValueType::Integer: + columnDefinitionString.append( + Utils::SmallString::number(defaultValue.value.toInteger())); + break; + case Sqlite::ValueType::Float: + columnDefinitionString.append(Utils::SmallString::number(defaultValue.value.toFloat())); + break; + case Sqlite::ValueType::String: + columnDefinitionString.append("'"); + columnDefinitionString.append(defaultValue.value.toStringView()); + columnDefinitionString.append("'"); + break; + default: + break; + } + } + + void operator()(const DefaultExpression &defaultexpression) + { + columnDefinitionString.append(" DEFAULT ("); + columnDefinitionString.append(defaultexpression.expression); + columnDefinitionString.append(")"); + } + + void operator()(const Collate &collate) + { + columnDefinitionString.append(" COLLATE "); + columnDefinitionString.append(collate.collation); + } + + void operator()(const GeneratedAlways &generatedAlways) + { + columnDefinitionString.append(" GENERATED ALWAYS AS ("); + columnDefinitionString.append(generatedAlways.expression); + columnDefinitionString.append(")"); + + if (generatedAlways.storage == Sqlite::GeneratedAlwaysStorage::Virtual) + columnDefinitionString.append(" VIRTUAL"); + else + columnDefinitionString.append(" STORED"); + } + + Utils::SmallString &columnDefinitionString; + }; + + class TableContraintsVisiter + { + public: + TableContraintsVisiter(Utils::SmallString &columnDefinitionString) + : columnDefinitionString(columnDefinitionString) + {} + + void operator()(const TablePrimaryKey &primaryKey) + { + columnDefinitionString.append("PRIMARY KEY("); + columnDefinitionString.append(primaryKey.columns.join(", ")); + columnDefinitionString.append(")"); + } + + Utils::SmallString &columnDefinitionString; + }; + + void bindColumnDefinitionsAndTableConstraints() const + { + Utils::SmallStringVector columnDefinitionStrings; + columnDefinitionStrings.reserve(m_columns.size()); + + for (const BasicColumn &column : m_columns) { + auto columnDefinitionString = Utils::SmallString::join( + {column.name, columnTypeToString(column.type)}); + + ContraintsVisiter visiter{columnDefinitionString}; + + for (const Constraint &constraint : column.constraints) + Utils::visit(visiter, constraint); + + columnDefinitionStrings.push_back(std::move(columnDefinitionString)); + } + + for (const TableConstraint &constraint : m_tableConstraints) { + Utils::SmallString columnDefinitionString; + + TableContraintsVisiter visiter{columnDefinitionString}; + Utils::visit(visiter, constraint); + + columnDefinitionStrings.push_back(std::move(columnDefinitionString)); + } + + m_sqlStatementBuilder.bind("$columnDefinitions", columnDefinitionStrings); + } + + void bindAll() const + { + m_sqlStatementBuilder.bind("$table", m_tableName.clone()); + + bindTemporary(); + bindIfNotExists(); + bindColumnDefinitionsAndTableConstraints(); + bindWithoutRowId(); + } + + void bindWithoutRowId() const + { + if (m_useWithoutRowId) + m_sqlStatementBuilder.bind("$withoutRowId", " WITHOUT ROWID"); + else + m_sqlStatementBuilder.bindEmptyText("$withoutRowId"); + } + + void bindIfNotExists() const + { + if (m_useIfNotExits) + m_sqlStatementBuilder.bind("$ifNotExits", "IF NOT EXISTS "); + else + m_sqlStatementBuilder.bindEmptyText("$ifNotExits"); + } + + void bindTemporary() const + { + if (m_useTemporaryTable) + m_sqlStatementBuilder.bind("$temporary", "TEMPORARY "); + else + m_sqlStatementBuilder.bindEmptyText("$temporary"); + } private: mutable SqlStatementBuilder m_sqlStatementBuilder; Utils::SmallString m_tableName; - SqliteColumns m_columns; + BasicColumns m_columns; TableConstraints m_tableConstraints; bool m_useWithoutRowId = false; bool m_useIfNotExits = false; diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp index 459913060f4..932828a625f 100644 --- a/src/libs/sqlite/sqlitebasestatement.cpp +++ b/src/libs/sqlite/sqlitebasestatement.cpp @@ -51,12 +51,8 @@ namespace Sqlite { BaseStatement::BaseStatement(Utils::SmallStringView sqlStatement, Database &database) : m_compiledStatement(nullptr, deleteCompiledStatement) , m_database(database) - , m_bindingParameterCount(0) - , m_columnCount(0) { prepare(sqlStatement); - setBindingParameterCount(); - setColumnCount(); } void BaseStatement::deleteCompiledStatement(sqlite3_stmt *compiledStatement) @@ -141,11 +137,6 @@ void BaseStatement::step() const next(); } -int BaseStatement::columnCount() const -{ - return m_columnCount; -} - void BaseStatement::bind(int index, NullValue) { int resultCode = sqlite3_bind_null(m_compiledStatement.get(), index); @@ -512,34 +503,16 @@ void BaseStatement::checkForBindingError(int resultCode) const 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!"}; +} + void BaseStatement::checkColumnCount(int columnCount) const { - if (columnCount != m_columnCount) - throw ColumnCountDoesNotMatch("SqliteStatement::values: column count does not match!"); -} - -void BaseStatement::checkBindingName(int index) const -{ - if (index <= 0 || index > m_bindingParameterCount) - throwWrongBingingName("SqliteStatement::bind: binding name are not exists in this statement!"); -} - -void BaseStatement::setBindingParameterCount() -{ - m_bindingParameterCount = sqlite3_bind_parameter_count(m_compiledStatement.get()); -} - -Utils::SmallStringView chopFirstLetter(const char *rawBindingName) -{ - if (rawBindingName != nullptr) - return Utils::SmallStringView(++rawBindingName); - - return Utils::SmallStringView(""); -} - -void BaseStatement::setColumnCount() -{ - m_columnCount = sqlite3_column_count(m_compiledStatement.get()); + if (columnCount != sqlite3_column_count(m_compiledStatement.get())) + throw WrongColumnCount{"Sqlite: wrong column count!"}; } bool BaseStatement::isReadOnlyStatement() const @@ -582,11 +555,6 @@ void BaseStatement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) c throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); } -void BaseStatement::throwWrongBingingName(const char *whatHasHappened) const -{ - throw WrongBindingName(whatHasHappened); -} - void BaseStatement::throwUnknowError(const char *whatHasHappened) const { if (sqliteDatabaseHandle()) diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 8ba9de09e89..ef098d42244 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -59,6 +59,8 @@ enum class Type : char { Invalid, Integer, Float, Text, Blob, Null }; class SQLITE_EXPORT BaseStatement { public: + using Database = ::Sqlite::Database; + explicit BaseStatement(Utils::SmallStringView sqlStatement, Database &database); BaseStatement(const BaseStatement &) = delete; @@ -80,7 +82,6 @@ public: BlobView fetchBlobValue(int column) const; template Type fetchValue(int column) const; - int columnCount() const; void bind(int index, NullValue); void bind(int index, int value); @@ -112,10 +113,9 @@ public: [[noreturn]] void checkForPrepareError(int resultCode) const; [[noreturn]] void checkForBindingError(int resultCode) const; void setIfIsReadyToFetchValues(int resultCode) const; - void checkColumnCount(int columnCount) const; void checkBindingName(int index) const; - void setBindingParameterCount(); - void setColumnCount(); + 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; @@ -149,8 +149,6 @@ protected: private: std::unique_ptr m_compiledStatement; Database &m_database; - int m_bindingParameterCount; - int m_columnCount; }; template <> SQLITE_EXPORT int BaseStatement::fetchValue(int column) const; @@ -161,7 +159,7 @@ extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue(int column) const; extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue(int column) const; -template +template class StatementImplementation : public BaseStatement { struct Resetter; @@ -175,11 +173,11 @@ public: BaseStatement::next(); } - void bindValues() {} - template - void bindValues(const ValueType&... values) + void bindValues(const ValueType &...values) { + static_assert(BindParameterCount == sizeof...(values), "Wrong binding parameter count!"); + int index = 0; (BaseStatement::bind(++index, values), ...); } @@ -344,10 +342,9 @@ public: using const_iterator = iterator; template - BaseSqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues) + BaseSqliteResultRange(StatementImplementation &statement) : m_statement{statement} { - statement.bindValues(queryValues...); } BaseSqliteResultRange(BaseSqliteResultRange &) = delete; @@ -376,7 +373,6 @@ public: SqliteResultRange(StatementImplementation &statement, const QueryTypes &...queryValues) : BaseSqliteResultRange{statement} , resetter{&statement} - { statement.bindValues(queryValues...); } @@ -409,7 +405,7 @@ public: } private: - DeferredTransaction m_transaction; + DeferredTransaction m_transaction; Resetter resetter; }; diff --git a/src/libs/sqlite/sqlitecolumn.h b/src/libs/sqlite/sqlitecolumn.h index 35a5e0f25c9..ecca1805590 100644 --- a/src/libs/sqlite/sqlitecolumn.h +++ b/src/libs/sqlite/sqlitecolumn.h @@ -28,19 +28,20 @@ #include "constraints.h" #include +#include namespace Sqlite { - -class Column +template +class BasicColumn { public: - Column() = default; + BasicColumn() = default; - Column(Utils::SmallStringView tableName, - Utils::SmallStringView name, - ColumnType type = ColumnType::None, - Constraints &&constraints = {}) + BasicColumn(Utils::SmallStringView tableName, + Utils::SmallStringView name, + ColumnType type = {}, + Constraints &&constraints = {}) : constraints(std::move(constraints)) , name(name) , tableName(tableName) @@ -50,31 +51,46 @@ public: void clear() { name.clear(); - type = ColumnType::Numeric; + type = {}; constraints = {}; } Utils::SmallString typeString() const { - switch (type) { - case ColumnType::None: - return {}; - case ColumnType::Numeric: - return "NUMERIC"; - case ColumnType::Integer: - return "INTEGER"; - case ColumnType::Real: - return "REAL"; - case ColumnType::Text: - return "TEXT"; - case ColumnType::Blob: - return "BLOB"; + if constexpr (std::is_same_v) { + switch (type) { + case ColumnType::None: + return {}; + case ColumnType::Numeric: + return "NUMERIC"; + case ColumnType::Integer: + return "INTEGER"; + case ColumnType::Real: + return "REAL"; + case ColumnType::Text: + return "TEXT"; + case ColumnType::Blob: + return "BLOB"; + } + } else { + switch (type) { + case ColumnType::Any: + return "ANY"; + case ColumnType::Int: + return "INT"; + case ColumnType::Integer: + return "INTEGER"; + case ColumnType::Real: + return "REAL"; + case ColumnType::Text: + return "TEXT"; + case ColumnType::Blob: + return "BLOB"; + } } - - Q_UNREACHABLE(); } - friend bool operator==(const Column &first, const Column &second) + friend bool operator==(const BasicColumn &first, const BasicColumn &second) { return first.name == second.name && first.type == second.type && first.constraints == second.constraints && first.tableName == second.tableName; @@ -84,11 +100,24 @@ public: Constraints constraints; Utils::SmallString name; Utils::SmallString tableName; - ColumnType type = ColumnType::Numeric; + ColumnType type = {}; }; // namespace Sqlite -using SqliteColumns = std::vector; -using SqliteColumnConstReference = std::reference_wrapper; -using SqliteColumnConstReferences = std::vector; +using Column = BasicColumn; +using StrictColumn = BasicColumn; + +using Columns = std::vector; +using StrictColumns = std::vector; +using ColumnConstReference = std::reference_wrapper; +using StrictColumnConstReference = std::reference_wrapper; +using ColumnConstReferences = std::vector; +using StrictColumnConstReferences = std::vector; + +template +using BasicColumns = std::vector>; +template +using BasicColumnConstReference = std::reference_wrapper>; +template +using BasicColumnConstReferences = std::vector>; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 588cabf3749..3804d6c7a30 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -45,10 +45,11 @@ namespace Sqlite { using namespace std::chrono_literals; -template +template class ReadStatement; +template class WriteStatement; -template +template class ReadWriteStatement; class SQLITE_EXPORT Database final : public TransactionInterface, public DatabaseInterface @@ -59,11 +60,12 @@ class SQLITE_EXPORT Database final : public TransactionInterface, public Databas public: using MutexType = std::mutex; - template - using ReadStatement = Sqlite::ReadStatement; - using WriteStatement = Sqlite::WriteStatement; - template - using ReadWriteStatement = Sqlite::ReadWriteStatement; + template + using ReadStatement = Sqlite::ReadStatement; + template + using WriteStatement = Sqlite::WriteStatement; + template + using ReadWriteStatement = Sqlite::ReadWriteStatement; using BusyHandler = DatabaseBackend::BusyHandler; Database(); @@ -161,7 +163,6 @@ public: void lock() override; void unlock() override; -private: void deferredBegin() override; void immediateBegin() override; void exclusiveBegin() override; @@ -171,6 +172,7 @@ private: void sessionCommit() override; void sessionRollback() override; +private: void initializeTables(); void registerTransactionStatements(); void deleteTransactionStatements(); diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp index 956a3ee2cdd..f7d819bb99f 100644 --- a/src/libs/sqlite/sqlitedatabasebackend.cpp +++ b/src/libs/sqlite/sqlitedatabasebackend.cpp @@ -297,7 +297,7 @@ void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode) return; default: closeWithoutException(); - throw Exception( + throw UnknowError( "SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", sqlite3_errmsg(sqliteDatabaseHandle())); } @@ -473,7 +473,7 @@ void DatabaseBackend::throwExceptionStatic(const char *whatHasHappens) void DatabaseBackend::throwException(const char *whatHasHappens) const { if (m_databaseHandle) - throw Exception(whatHasHappens, sqlite3_errmsg(m_databaseHandle)); + throw ExceptionWithMessage(whatHasHappens, sqlite3_errmsg(m_databaseHandle)); else throw Exception(whatHasHappens); } diff --git a/src/libs/sqlite/sqliteexception.cpp b/src/libs/sqlite/sqliteexception.cpp index d760ff2b7f9..c95bc7f323f 100644 --- a/src/libs/sqlite/sqliteexception.cpp +++ b/src/libs/sqlite/sqliteexception.cpp @@ -31,12 +31,9 @@ namespace Sqlite { -void Exception::printWarning() const +void ExceptionWithMessage::printWarning() const { - if (!m_sqliteErrorMessage.isEmpty()) - qWarning() << m_whatErrorHasHappen << m_sqliteErrorMessage; - else - qWarning() << m_whatErrorHasHappen; + qWarning() << what() << m_sqliteErrorMessage; } } // namespace Sqlite diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h index 12da835eace..44f7806662f 100644 --- a/src/libs/sqlite/sqliteexception.h +++ b/src/libs/sqlite/sqliteexception.h @@ -37,385 +37,293 @@ namespace Sqlite { class SQLITE_EXPORT Exception : public std::exception { public: - Exception(const char *whatErrorHasHappen, Utils::SmallString &&sqliteErrorMessage) - : m_whatErrorHasHappen(whatErrorHasHappen) - , m_sqliteErrorMessage(std::move(sqliteErrorMessage)) - {} - Exception(const char *whatErrorHasHappen) : m_whatErrorHasHappen(whatErrorHasHappen) {} const char *what() const noexcept override { return m_whatErrorHasHappen; } +private: + const char *m_whatErrorHasHappen; +}; + +class SQLITE_EXPORT ExceptionWithMessage : public Exception +{ +public: + ExceptionWithMessage(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString{}) + : Exception{whatErrorHasHappen} + , m_sqliteErrorMessage(std::move(sqliteErrorMessage)) + {} + void printWarning() const; private: - const char *m_whatErrorHasHappen; Utils::SmallString m_sqliteErrorMessage; }; -class StatementIsBusy : public Exception +class StatementIsBusy : public ExceptionWithMessage { public: - StatementIsBusy(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class DatabaseIsBusy : public Exception { public: - DatabaseIsBusy(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class StatementHasError : public Exception +class StatementHasError : public ExceptionWithMessage { public: - StatementHasError(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class StatementIsMisused : public Exception +class StatementIsMisused : public ExceptionWithMessage { public: - StatementIsMisused(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class InputOutputError : public Exception { public: - InputOutputError(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class ConstraintPreventsModification : public Exception +class ConstraintPreventsModification : public ExceptionWithMessage { public: - ConstraintPreventsModification(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class NoValuesToFetch : public Exception { public: - NoValuesToFetch(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class ColumnCountDoesNotMatch : public Exception +class BindingIndexIsOutOfRange : public ExceptionWithMessage { public: - ColumnCountDoesNotMatch(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} -}; - -class BindingIndexIsOutOfRange : public Exception -{ -public: - BindingIndexIsOutOfRange(const char *whatErrorHasHappen, - Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class WrongBindingName : public Exception { public: - WrongBindingName(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class DatabaseIsNotOpen : public Exception { public: - DatabaseIsNotOpen(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class DatabaseCannotBeOpened : public Exception +class DatabaseCannotBeOpened : public ExceptionWithMessage { public: - DatabaseCannotBeOpened(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened { public: - DatabaseFilePathIsEmpty(const char *whatErrorHasHappen) - : DatabaseCannotBeOpened(whatErrorHasHappen) - {} + using DatabaseCannotBeOpened::DatabaseCannotBeOpened; }; class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened { public: - DatabaseIsAlreadyOpen(const char *whatErrorHasHappen) - : DatabaseCannotBeOpened(whatErrorHasHappen) - {} + using DatabaseCannotBeOpened::DatabaseCannotBeOpened; }; class DatabaseCannotBeClosed : public Exception { public: - DatabaseCannotBeClosed(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed { public: - DatabaseIsAlreadyClosed(const char *whatErrorHasHappen) - : DatabaseCannotBeClosed(whatErrorHasHappen) - {} + using DatabaseCannotBeClosed::DatabaseCannotBeClosed; }; -class WrongFilePath : public DatabaseCannotBeOpened +class WrongFilePath : public ExceptionWithMessage { public: - WrongFilePath(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : DatabaseCannotBeOpened(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class PragmaValueNotSet : public Exception { public: - PragmaValueNotSet(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class NotReadOnlySqlStatement : public Exception { public: - NotReadOnlySqlStatement(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class NotWriteSqlStatement : public Exception { public: - NotWriteSqlStatement(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class DeadLock : public Exception { public: - DeadLock(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class UnknowError : public Exception +class UnknowError : public ExceptionWithMessage { public: - UnknowError(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class BindingTooBig : public Exception +class BindingTooBig : public ExceptionWithMessage { public: - BindingTooBig(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class TooBig : public Exception +class TooBig : public ExceptionWithMessage { public: - TooBig(const char *whatErrorHasHappen, Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class CannotConvert : public Exception { public: - CannotConvert(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class ForeignKeyColumnIsNotUnique : public Exception { public: - ForeignKeyColumnIsNotUnique(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class CannotApplyChangeSet : public Exception { public: - CannotApplyChangeSet(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class ChangeSetIsMisused : public Exception { public: - ChangeSetIsMisused(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; -class SchemeChangeError : public Exception +class SchemeChangeError : public ExceptionWithMessage { public: - SchemeChangeError(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class CannotWriteToReadOnlyConnection : public Exception +class CannotWriteToReadOnlyConnection : public ExceptionWithMessage { public: - CannotWriteToReadOnlyConnection(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class ProtocolError : public Exception +class ProtocolError : public ExceptionWithMessage { public: - ProtocolError(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class DatabaseExceedsMaximumFileSize : public Exception +class DatabaseExceedsMaximumFileSize : public ExceptionWithMessage { public: - DatabaseExceedsMaximumFileSize(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class DataTypeMismatch : public Exception +class DataTypeMismatch : public ExceptionWithMessage { public: - DataTypeMismatch(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class ConnectionIsLocked : public Exception +class ConnectionIsLocked : public ExceptionWithMessage { public: - ConnectionIsLocked(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class ExecutionInterrupted : public Exception +class ExecutionInterrupted : public ExceptionWithMessage { public: - ExecutionInterrupted(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class DatabaseIsCorrupt : public Exception +class DatabaseIsCorrupt : public ExceptionWithMessage { public: - DatabaseIsCorrupt(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; -class CannotOpen : public Exception +class CannotOpen : public ExceptionWithMessage { public: - CannotOpen(const char *whatErrorHasHappen, - Utils::SmallString &&errorMessage = Utils::SmallString()) - : Exception(whatErrorHasHappen, std::move(errorMessage)) - {} + using ExceptionWithMessage::ExceptionWithMessage; }; class CannotCreateChangeSetIterator : public Exception { public: - CannotCreateChangeSetIterator(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class CannotGetChangeSetOperation : public Exception { public: - CannotGetChangeSetOperation(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class ChangeSetTupleIsOutOfRange : public Exception { public: - ChangeSetTupleIsOutOfRange(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class ChangeSetTupleIsMisused : public Exception { public: - ChangeSetTupleIsMisused(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - - {} + using Exception::Exception; }; class UnknownError : public Exception { public: - UnknownError(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; }; class DatabaseIsNotLocked : public Exception { public: - DatabaseIsNotLocked(const char *whatErrorHasHappen) - : Exception(whatErrorHasHappen) - {} + using Exception::Exception; +}; + +class WrongBindingParameterCount : public Exception +{ +public: + using Exception::Exception; +}; + +class WrongColumnCount : public Exception +{ +public: + using Exception::Exception; }; } // namespace Sqlite diff --git a/src/libs/sqlite/sqliteglobal.h b/src/libs/sqlite/sqliteglobal.h index b910a05a819..f8a13e0a972 100644 --- a/src/libs/sqlite/sqliteglobal.h +++ b/src/libs/sqlite/sqliteglobal.h @@ -40,6 +40,7 @@ namespace Sqlite { enum class ColumnType : char { None, Numeric, Integer, Real, Text, Blob }; +enum class StrictColumnType : char { Any, Integer, Int, Real, Text, Blob }; enum class ConstraintType : char { NoConstraint, PrimaryKey, Unique, ForeignKey }; diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index 09906a3d902..58eafc3e424 100644 --- a/src/libs/sqlite/sqlitereadstatement.h +++ b/src/libs/sqlite/sqlitereadstatement.h @@ -29,16 +29,18 @@ namespace Sqlite { -template -class ReadStatement final : protected StatementImplementation +template +class ReadStatement final + : protected StatementImplementation { - using Base = StatementImplementation; + using Base = StatementImplementation; public: ReadStatement(Utils::SmallStringView sqlStatement, Database &database) : Base{sqlStatement, database} { checkIsReadOnlyStatement(); + Base::checkBindingParameterCount(BindParameterCount); Base::checkColumnCount(ResultCount); } diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h index e33b247f077..4ac9617996b 100644 --- a/src/libs/sqlite/sqlitereadwritestatement.h +++ b/src/libs/sqlite/sqlitereadwritestatement.h @@ -29,16 +29,18 @@ namespace Sqlite { -template -class ReadWriteStatement final : protected StatementImplementation +template +class ReadWriteStatement final + : protected StatementImplementation { friend class DatabaseBackend; - using Base = StatementImplementation; + using Base = StatementImplementation; public: ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database) : Base{sqlStatement, database} { + Base::checkBindingParameterCount(BindParameterCount); Base::checkColumnCount(ResultCount); } diff --git a/src/libs/sqlite/sqlitesessions.cpp b/src/libs/sqlite/sqlitesessions.cpp index 5f2da020cf0..45fe527a86b 100644 --- a/src/libs/sqlite/sqlitesessions.cpp +++ b/src/libs/sqlite/sqlitesessions.cpp @@ -182,7 +182,7 @@ void Sessions::applyAndUpdateSessions() void Sessions::deleteAll() { - WriteStatement{Utils::SmallString::join({"DELETE FROM ", sessionsTableName}), database}.execute(); + WriteStatement<0>{Utils::SmallString::join({"DELETE FROM ", sessionsTableName}), database}.execute(); } SessionChangeSets Sessions::changeSets() const diff --git a/src/libs/sqlite/sqlitesessions.h b/src/libs/sqlite/sqlitesessions.h index da5fe336df6..0d1baeec477 100644 --- a/src/libs/sqlite/sqlitesessions.h +++ b/src/libs/sqlite/sqlitesessions.h @@ -88,7 +88,7 @@ private: public: Database &database; - WriteStatement insertSession; + WriteStatement<1> insertSession; Utils::SmallString databaseName; Utils::SmallStringVector tableNames; std::unique_ptr session; diff --git a/src/libs/sqlite/sqlitetable.h b/src/libs/sqlite/sqlitetable.h index 1c1f6869757..d0bb850656f 100644 --- a/src/libs/sqlite/sqlitetable.h +++ b/src/libs/sqlite/sqlitetable.h @@ -35,10 +35,15 @@ namespace Sqlite { class Database; -class Table +template +class BasicTable { public: - Table(std::size_t reserve = 10) + using Column = ::Sqlite::BasicColumn; + using ColumnConstReferences = ::Sqlite::BasicColumnConstReferences; + using Columns = ::Sqlite::BasicColumns; + + BasicTable(std::size_t reserve = 10) { m_sqliteColumns.reserve(reserve); m_sqliteIndices.reserve(reserve); @@ -71,9 +76,7 @@ public: m_useTemporaryTable = useTemporaryTable; } - Column &addColumn(Utils::SmallStringView name, - ColumnType type = ColumnType::None, - Constraints &&constraints = {}) + Column &addColumn(Utils::SmallStringView name, ColumnType type = {}, Constraints &&constraints = {}) { m_sqliteColumns.emplace_back(m_tableName, name, type, std::move(constraints)); @@ -81,7 +84,7 @@ public: } Column &addForeignKeyColumn(Utils::SmallStringView name, - const Table &referencedTable, + const BasicTable &referencedTable, ForeignKeyAction foreignKeyupdateAction = {}, ForeignKeyAction foreignKeyDeleteAction = {}, Enforment foreignKeyEnforcement = {}, @@ -123,18 +126,19 @@ public: return m_sqliteColumns.back(); } - void addPrimaryKeyContraint(const SqliteColumnConstReferences &columns) + void addPrimaryKeyContraint(const BasicColumnConstReferences &columns) { Utils::SmallStringVector columnNames; columnNames.reserve(columns.size()); for (const auto &column : columns) - columnNames.emplace_back(column.get().name); + columnNames.emplace_back(column.name); m_tableConstraints.emplace_back(TablePrimaryKey{std::move(columnNames)}); } - Index &addIndex(const SqliteColumnConstReferences &columns, Utils::SmallStringView condition = {}) + Index &addIndex(const BasicColumnConstReferences &columns, + Utils::SmallStringView condition = {}) { return m_sqliteIndices.emplace_back(m_tableName, sqliteColumnNames(columns), @@ -142,7 +146,7 @@ public: condition); } - Index &addUniqueIndex(const SqliteColumnConstReferences &columns, + Index &addUniqueIndex(const BasicColumnConstReferences &columns, Utils::SmallStringView condition = {}) { return m_sqliteIndices.emplace_back(m_tableName, @@ -151,10 +155,7 @@ public: condition); } - const SqliteColumns &columns() const - { - return m_sqliteColumns; - } + const Columns &columns() const { return m_sqliteColumns; } bool isReady() const { @@ -164,7 +165,7 @@ public: template void initialize(Database &database) { - CreateTableSqlStatementBuilder builder; + CreateTableSqlStatementBuilder builder; builder.setTableName(m_tableName.clone()); builder.setUseWithoutRowId(m_withoutRowId); @@ -186,7 +187,7 @@ public: database.execute(index.sqlStatement()); } - friend bool operator==(const Table &first, const Table &second) + friend bool operator==(const BasicTable &first, const BasicTable &second) { return first.m_tableName == second.m_tableName && first.m_withoutRowId == second.m_withoutRowId @@ -207,7 +208,7 @@ public: } private: - Utils::SmallStringVector sqliteColumnNames(const SqliteColumnConstReferences &columns) + Utils::SmallStringVector sqliteColumnNames(const ColumnConstReferences &columns) { Utils::SmallStringVector columnNames; @@ -219,7 +220,7 @@ private: private: Utils::SmallString m_tableName; - SqliteColumns m_sqliteColumns; + Columns m_sqliteColumns; SqliteIndices m_sqliteIndices; TableConstraints m_tableConstraints; bool m_withoutRowId = false; @@ -228,4 +229,7 @@ private: bool m_isReady = false; }; +using Table = BasicTable; +using StrictTable = BasicTable; + } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetransaction.h b/src/libs/sqlite/sqlitetransaction.h index 09a60446d26..1941548877b 100644 --- a/src/libs/sqlite/sqlitetransaction.h +++ b/src/libs/sqlite/sqlitetransaction.h @@ -59,9 +59,12 @@ protected: ~TransactionInterface() = default; }; +template class AbstractTransaction { public: + using Transaction = TransactionInterface; + AbstractTransaction(const AbstractTransaction &) = delete; AbstractTransaction &operator=(const AbstractTransaction &) = delete; @@ -87,11 +90,14 @@ protected: bool m_rollback = false; }; +template class AbstractThrowingSessionTransaction { public: - AbstractThrowingSessionTransaction(const AbstractTransaction &) = delete; - AbstractThrowingSessionTransaction &operator=(const AbstractTransaction &) = delete; + using Transaction = TransactionInterface; + + AbstractThrowingSessionTransaction(const AbstractThrowingSessionTransaction &) = delete; + AbstractThrowingSessionTransaction &operator=(const AbstractThrowingSessionTransaction &) = delete; void commit() { @@ -123,16 +129,19 @@ protected: bool m_rollback = false; }; -class AbstractThrowingTransaction : public AbstractTransaction +template +class AbstractThrowingTransaction : public AbstractTransaction { + using Base = AbstractTransaction; + public: AbstractThrowingTransaction(const AbstractThrowingTransaction &) = delete; AbstractThrowingTransaction &operator=(const AbstractThrowingTransaction &) = delete; ~AbstractThrowingTransaction() noexcept(false) { try { - if (m_rollback) - m_interface.rollback(); + if (Base::m_rollback) + Base::m_interface.rollback(); } catch (...) { if (!std::uncaught_exceptions()) throw; @@ -141,37 +150,40 @@ public: protected: AbstractThrowingTransaction(TransactionInterface &transactionInterface) - : AbstractTransaction(transactionInterface) + : AbstractTransaction(transactionInterface) { } }; -class AbstractNonThrowingDestructorTransaction : public AbstractTransaction +template +class AbstractNonThrowingDestructorTransaction : public AbstractTransaction { + using Base = AbstractTransaction; + public: AbstractNonThrowingDestructorTransaction(const AbstractNonThrowingDestructorTransaction &) = delete; AbstractNonThrowingDestructorTransaction &operator=(const AbstractNonThrowingDestructorTransaction &) = delete; ~AbstractNonThrowingDestructorTransaction() { try { - if (m_rollback) - m_interface.rollback(); + if (Base::m_rollback) + Base::m_interface.rollback(); } catch (...) { } } protected: AbstractNonThrowingDestructorTransaction(TransactionInterface &transactionInterface) - : AbstractTransaction(transactionInterface) + : AbstractTransaction(transactionInterface) { } }; -template -class BasicDeferredTransaction final : public BaseTransaction +template +class BasicDeferredTransaction : public BaseTransaction { public: - BasicDeferredTransaction(TransactionInterface &transactionInterface) + BasicDeferredTransaction(typename BaseTransaction::Transaction &transactionInterface) : BaseTransaction(transactionInterface) { transactionInterface.deferredBegin(); @@ -183,14 +195,38 @@ public: } }; -using DeferredTransaction = BasicDeferredTransaction; -using DeferredNonThrowingDestructorTransaction = BasicDeferredTransaction; +template +class DeferredTransaction final + : public BasicDeferredTransaction> +{ + using Base = BasicDeferredTransaction>; -template -class BasicImmediateTransaction final : public BaseTransaction +public: + using Base::Base; +}; + +template +DeferredTransaction(TransactionInterface &) -> DeferredTransaction; + +template +class DeferredNonThrowingDestructorTransaction final + : public BasicDeferredTransaction> +{ + using Base = BasicDeferredTransaction>; + +public: + using Base::Base; +}; + +template +DeferredNonThrowingDestructorTransaction(TransactionInterface &) + -> DeferredNonThrowingDestructorTransaction; + +template +class BasicImmediateTransaction : public BaseTransaction { public: - BasicImmediateTransaction(TransactionInterface &transactionInterface) + BasicImmediateTransaction(typename BaseTransaction::Transaction &transactionInterface) : BaseTransaction(transactionInterface) { transactionInterface.immediateBegin(); @@ -202,14 +238,38 @@ public: } }; -using ImmediateTransaction = BasicImmediateTransaction; -using ImmediateNonThrowingDestructorTransaction = BasicImmediateTransaction; +template +class ImmediateTransaction final + : public BasicImmediateTransaction> +{ + using Base = BasicImmediateTransaction>; -template -class BasicExclusiveTransaction final : public BaseTransaction +public: + using Base::Base; +}; + +template +ImmediateTransaction(TransactionInterface &) -> ImmediateTransaction; + +template +class ImmediateNonThrowingDestructorTransaction final + : public BasicImmediateTransaction> +{ + using Base = BasicImmediateTransaction>; + +public: + using Base::Base; +}; + +template +ImmediateNonThrowingDestructorTransaction(TransactionInterface &) + -> ImmediateNonThrowingDestructorTransaction; + +template +class BasicExclusiveTransaction : public BaseTransaction { public: - BasicExclusiveTransaction(TransactionInterface &transactionInterface) + BasicExclusiveTransaction(typename BaseTransaction::Transaction &transactionInterface) : BaseTransaction(transactionInterface) { transactionInterface.exclusiveBegin(); @@ -221,24 +281,51 @@ public: } }; -using ExclusiveTransaction = BasicExclusiveTransaction; -using ExclusiveNonThrowingDestructorTransaction - = BasicExclusiveTransaction; - -class ImmediateSessionTransaction final : public AbstractThrowingSessionTransaction +template +class ExclusiveTransaction final + : public BasicExclusiveTransaction> { + using Base = BasicExclusiveTransaction>; + public: - ImmediateSessionTransaction(TransactionInterface &transactionInterface) - : AbstractThrowingSessionTransaction(transactionInterface) + using Base::Base; +}; + +template +ExclusiveTransaction(TransactionInterface &) -> ExclusiveTransaction; + +template +class ExclusiveNonThrowingDestructorTransaction final + : public BasicExclusiveTransaction> +{ + using Base = BasicExclusiveTransaction>; + +public: + using Base::Base; +}; + +template +ExclusiveNonThrowingDestructorTransaction(TransactionInterface &) + -> ExclusiveNonThrowingDestructorTransaction; + +template +class ImmediateSessionTransaction final + : public AbstractThrowingSessionTransaction +{ + using Base = AbstractThrowingSessionTransaction; + +public: + ImmediateSessionTransaction(typename Base::Transaction &transactionInterface) + : AbstractThrowingSessionTransaction(transactionInterface) { transactionInterface.immediateSessionBegin(); } - ~ImmediateSessionTransaction() - { - AbstractThrowingSessionTransaction::m_rollback - = !AbstractThrowingSessionTransaction::m_isAlreadyCommited; - } + ~ImmediateSessionTransaction() { Base::m_rollback = !Base::m_isAlreadyCommited; } }; +template +ImmediateSessionTransaction(TransactionInterface &) + -> ImmediateSessionTransaction; + } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitewritestatement.h b/src/libs/sqlite/sqlitewritestatement.h index 1a0bb5832ca..cbea0d5b3fd 100644 --- a/src/libs/sqlite/sqlitewritestatement.h +++ b/src/libs/sqlite/sqlitewritestatement.h @@ -28,21 +28,23 @@ #include "sqlitebasestatement.h" namespace Sqlite { - -class WriteStatement : protected StatementImplementation +template +class WriteStatement : protected StatementImplementation { - using Base = StatementImplementation; + using Base = StatementImplementation; public: WriteStatement(Utils::SmallStringView sqlStatement, Database &database) - : StatementImplementation(sqlStatement, database) + : Base(sqlStatement, database) { checkIsWritableStatement(); + Base::checkBindingParameterCount(BindParameterCount); + Base::checkColumnCount(0); } - using StatementImplementation::database; - using StatementImplementation::execute; - using StatementImplementation::write; + using Base::database; + using Base::execute; + using Base::write; protected: void checkIsWritableStatement() diff --git a/src/libs/sqlite/sqlstatementbuilder.cpp b/src/libs/sqlite/sqlstatementbuilder.cpp index 7a6cc1a81a3..b72d1d03281 100644 --- a/src/libs/sqlite/sqlstatementbuilder.cpp +++ b/src/libs/sqlite/sqlstatementbuilder.cpp @@ -176,26 +176,6 @@ bool SqlStatementBuilder::isBuild() const return m_sqlStatement.hasContent(); } -Utils::SmallString SqlStatementBuilder::columnTypeToString(ColumnType columnType) -{ - switch (columnType) { - case ColumnType::Numeric: - return " NUMERIC"; - case ColumnType::Integer: - return " INTEGER"; - case ColumnType::Real: - return " REAL"; - case ColumnType::Text: - return " TEXT"; - case ColumnType::Blob: - return " BLOB"; - case ColumnType::None: - return {}; - } - - Q_UNREACHABLE(); -} - void SqlStatementBuilder::generateSqlStatement() const { m_sqlStatement = m_sqlTemplate; diff --git a/src/libs/sqlite/sqlstatementbuilder.h b/src/libs/sqlite/sqlstatementbuilder.h index 670455dc41a..d93f8893e3e 100644 --- a/src/libs/sqlite/sqlstatementbuilder.h +++ b/src/libs/sqlite/sqlstatementbuilder.h @@ -57,8 +57,6 @@ public: bool isBuild() const; - static Utils::SmallString columnTypeToString(ColumnType columnType); - protected: static Utils::SmallString insertTemplateParameters(const Utils::SmallStringVector &columns); static Utils::SmallString updateTemplateParameters(const Utils::SmallStringVector &columns); diff --git a/src/libs/sqlite/sqlstatementbuilderexception.h b/src/libs/sqlite/sqlstatementbuilderexception.h index 05d07c25a97..e741acabe39 100644 --- a/src/libs/sqlite/sqlstatementbuilderexception.h +++ b/src/libs/sqlite/sqlstatementbuilderexception.h @@ -29,10 +29,10 @@ namespace Sqlite { -class SQLITE_EXPORT SqlStatementBuilderException : public Exception +class SQLITE_EXPORT SqlStatementBuilderException : public ExceptionWithMessage { public: - using Exception::Exception; + using ExceptionWithMessage::ExceptionWithMessage; }; } // namespace Sqlite diff --git a/src/libs/utils/process_ctrlc_stub.cpp b/src/libs/utils/process_ctrlc_stub.cpp index 1c37adec3c6..33694d64487 100644 --- a/src/libs/utils/process_ctrlc_stub.cpp +++ b/src/libs/utils/process_ctrlc_stub.cpp @@ -50,6 +50,40 @@ #define CALLBACK WINAPI #endif +/// Class that ensures that when the parent process cancels, the child +/// process will also be cancelled by the operating system. +/// +/// This allows handling of GUI applications that do not react to Ctrl+C +/// or console applications that ignore Ctrl+C. +class JobKillOnClose +{ + HANDLE m_job = nullptr; +public: + JobKillOnClose() + { + m_job = CreateJobObject(nullptr, nullptr); + if (!m_job) { + fwprintf(stderr, L"qtcreator_ctrlc_stub: CreateJobObject failed: 0x%x.\n", GetLastError()); + return; + } + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {0}; + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(m_job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { + fwprintf(stderr, L"qtcreator_ctrlc_stub: SetInformationJobObject failed: 0x%x.\n", GetLastError()); + } + } + + BOOL AssignProcessToJob(HANDLE process) const + { + return AssignProcessToJobObject(m_job, process); + } + + ~JobKillOnClose() + { + CloseHandle(m_job); + } +}; + const wchar_t szTitle[] = L"qtcctrlcstub"; const wchar_t szWindowClass[] = L"wcqtcctrlcstub"; const wchar_t szNice[] = L"-nice "; @@ -61,7 +95,7 @@ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL WINAPI shutdownHandler(DWORD dwCtrlType); BOOL WINAPI interruptHandler(DWORD dwCtrlType); bool isSpaceOrTab(const wchar_t c); -bool startProcess(wchar_t pCommandLine[], bool lowerPriority); +bool startProcess(wchar_t pCommandLine[], bool lowerPriority, const JobKillOnClose& job); int main(int argc, char **) { @@ -108,7 +142,9 @@ int main(int argc, char **) while (isSpaceOrTab(strCommandLine[++pos])) ; } - bool bSuccess = startProcess(strCommandLine + pos, lowerPriority); + + JobKillOnClose job; + bool bSuccess = startProcess(strCommandLine + pos, lowerPriority, job); free(strCommandLine); if (!bSuccess) @@ -181,7 +217,7 @@ DWORD WINAPI processWatcherThread(LPVOID lpParameter) return 0; } -bool startProcess(wchar_t *pCommandLine, bool lowerPriority) +bool startProcess(wchar_t *pCommandLine, bool lowerPriority, const JobKillOnClose& job) { SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(sa); @@ -199,6 +235,11 @@ bool startProcess(wchar_t *pCommandLine, bool lowerPriority) } CloseHandle(pi.hThread); + if (!job.AssignProcessToJob(pi.hProcess)) { + fwprintf(stderr, L"qtcreator_ctrlc_stub: AssignProcessToJobObject failed: 0x%x.\n", GetLastError()); + return false; + } + HANDLE hThread = CreateThread(NULL, 0, processWatcherThread, reinterpret_cast(pi.hProcess), 0, NULL); if (!hThread) { fwprintf(stderr, L"qtcreator_ctrlc_stub: The watch dog thread cannot be started.\n"); diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 95ccb37de89..875bd874a7a 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -72,7 +72,7 @@ static void startFlashingWizard() { const FilePath filePath = flashWizardFilePath(); if (HostOsInfo::isWindowsHost()) { - if (QtcProcess::startDetached({"explorer.exe", {filePath.toString()}})) + if (QtcProcess::startDetached({"explorer.exe", {filePath.toUserOutput()}})) return; } else if (QtcProcess::startDetached({filePath, {}})) { return; diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index ee5bc7540fc..1e8b9a53e95 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -78,7 +78,7 @@ elseif(MSVC) set(big_obj_compile_option "/bigobj") endif() -extend_qtc_plugin(ClangCodeModel - CONDITION DEFINED big_obj_compile_option - PROPERTIES COMPILE_OPTIONS ${big_obj_compile_option} -) +if(big_obj_compile_option AND TARGET ClangCodeModel) + set_property(TARGET ClangCodeModel + APPEND PROPERTY COMPILE_OPTIONS ${big_obj_compile_option}) +endif() diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index a8a1fbe5a90..b8170cf12be 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -2781,6 +2781,7 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, << version << q->documentVersion(doc->filePath()); return; } + force = force || isTesting; const auto previous = previousTokens.find(doc); if (previous != previousTokens.end()) { if (!force && previous->first == tokens && previous->second == version) { diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp index 593615ec1f8..45b2ea8e2cc 100644 --- a/src/plugins/clangtools/executableinfo.cpp +++ b/src/plugins/clangtools/executableinfo.cpp @@ -228,8 +228,9 @@ QString queryVersion(const FilePath &clangToolPath, QueryFailMode failMode) static const QStringList versionPrefixes{"LLVM version ", "clang version: "}; const QString line = stream.readLine().simplified(); for (const QString &prefix : versionPrefixes) { - if (line.startsWith(prefix)) - return line.mid(prefix.length()); + auto idx = line.indexOf(prefix); + if (idx >= 0) + return line.mid(idx + prefix.length()); } } return {}; diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index e96483b8b20..e2091ffe7fa 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -1245,10 +1245,6 @@ void EditorManagerPrivate::saveSettings() qsettings->setValueWithDefault(maxRecentFilesKey, d->m_settings.maxRecentFiles, def.maxRecentFiles); - - qsettings->setValueWithDefault(fileSystemCaseSensitivityKey, - HostOsInfo::fileNameCaseSensitivity(), - OsSpecificAspects::fileNameCaseSensitivity(HostOsInfo::hostOs())); qsettings->setValueWithDefault(preferredEditorFactoriesKey, toMap(userPreferredEditorTypes())); } @@ -1266,26 +1262,14 @@ void EditorManagerPrivate::readSettings() if (maxRecentFiles > 0) d->m_settings.maxRecentFiles = maxRecentFiles; - if (qs->contains(fileSystemCaseSensitivityKey)) { - Qt::CaseSensitivity defaultSensitivity - = OsSpecificAspects::fileNameCaseSensitivity(HostOsInfo::hostOs()); - bool ok = false; - Qt::CaseSensitivity sensitivity = defaultSensitivity; - int sensitivitySetting = qs->value(fileSystemCaseSensitivityKey).toInt(&ok); - if (ok) { - switch (Qt::CaseSensitivity(sensitivitySetting)) { - case Qt::CaseSensitive: - sensitivity = Qt::CaseSensitive; - break; - case Qt::CaseInsensitive: - sensitivity = Qt::CaseInsensitive; - } - } - if (sensitivity == defaultSensitivity) - HostOsInfo::unsetOverrideFileNameCaseSensitivity(); - else - HostOsInfo::setOverrideFileNameCaseSensitivity(sensitivity); - } + const Qt::CaseSensitivity defaultSensitivity = OsSpecificAspects::fileNameCaseSensitivity( + HostOsInfo::hostOs()); + const Qt::CaseSensitivity sensitivity = readFileSystemSensitivity(qs); + if (sensitivity == defaultSensitivity) + HostOsInfo::unsetOverrideFileNameCaseSensitivity(); + else + HostOsInfo::setOverrideFileNameCaseSensitivity(sensitivity); + const QHash preferredEditorFactories = fromMap( qs->value(preferredEditorFactoriesKey).toMap()); setUserPreferredEditorTypes(preferredEditorFactories); @@ -1312,6 +1296,34 @@ void EditorManagerPrivate::readSettings() updateAutoSave(); } +Qt::CaseSensitivity EditorManagerPrivate::readFileSystemSensitivity(QSettings *settings) +{ + const Qt::CaseSensitivity defaultSensitivity = OsSpecificAspects::fileNameCaseSensitivity( + HostOsInfo::hostOs()); + if (!settings->contains(fileSystemCaseSensitivityKey)) + return defaultSensitivity; + bool ok = false; + const int sensitivitySetting = settings->value(fileSystemCaseSensitivityKey).toInt(&ok); + if (ok) { + switch (Qt::CaseSensitivity(sensitivitySetting)) { + case Qt::CaseSensitive: + return Qt::CaseSensitive; + case Qt::CaseInsensitive: + return Qt::CaseInsensitive; + } + } + return defaultSensitivity; +} + +void EditorManagerPrivate::writeFileSystemSensitivity(Utils::QtcSettings *settings, + Qt::CaseSensitivity sensitivity) +{ + settings->setValueWithDefault(fileSystemCaseSensitivityKey, + int(sensitivity), + int(OsSpecificAspects::fileNameCaseSensitivity( + HostOsInfo::hostOs()))); +} + void EditorManagerPrivate::setAutoSaveEnabled(bool enabled) { d->m_settings.autoSaveEnabled = enabled; diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h index 76f7f5c379a..bbbc345c04c 100644 --- a/src/plugins/coreplugin/editormanager/editormanager_p.h +++ b/src/plugins/coreplugin/editormanager/editormanager_p.h @@ -43,9 +43,14 @@ QT_BEGIN_NAMESPACE class QAction; +class QSettings; class QTimer; QT_END_NAMESPACE +namespace Utils { +class QtcSettings; +} + namespace Core { class EditorManager; @@ -112,6 +117,9 @@ public: static void saveSettings(); static void readSettings(); + static Qt::CaseSensitivity readFileSystemSensitivity(QSettings *settings); + static void writeFileSystemSensitivity(Utils::QtcSettings *settings, + Qt::CaseSensitivity sensitivity); static void setAutoSaveEnabled(bool enabled); static bool autoSaveEnabled(); static void setAutoSaveInterval(int interval); diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 637e87acb52..8ec4945082f 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -212,7 +212,9 @@ public: m_ui.fileSystemCaseSensitivityChooser->addItem(tr("Case Insensitive"), Qt::CaseInsensitive); } - if (HostOsInfo::fileNameCaseSensitivity() == Qt::CaseSensitive) + const Qt::CaseSensitivity sensitivity = EditorManagerPrivate::readFileSystemSensitivity( + ICore::settings()); + if (sensitivity == Qt::CaseSensitive) m_ui.fileSystemCaseSensitivityChooser->setCurrentIndex(0); else m_ui.fileSystemCaseSensitivityChooser->setCurrentIndex(1); @@ -260,15 +262,15 @@ private: void SystemSettingsWidget::apply() { + QtcSettings *settings = ICore::settings(); EditorManager::setReloadSetting(IDocument::ReloadSetting(m_ui.reloadBehavior->currentIndex())); if (HostOsInfo::isAnyUnixHost()) { - ConsoleProcess::setTerminalEmulator(ICore::settings(), + ConsoleProcess::setTerminalEmulator(settings, {m_ui.terminalComboBox->lineEdit()->text(), m_ui.terminalOpenArgs->text(), m_ui.terminalExecuteArgs->text()}); if (!HostOsInfo::isMacHost()) { - UnixUtils::setFileBrowser(ICore::settings(), - m_ui.externalFileBrowserEdit->text()); + UnixUtils::setFileBrowser(settings, m_ui.externalFileBrowserEdit->text()); } } PatchTool::setPatchCommand(m_ui.patchChooser->filePath()); @@ -291,14 +293,17 @@ void SystemSettingsWidget::apply() m_ui.askBeforeExitCheckBox->isChecked()); if (HostOsInfo::isMacHost()) { - Qt::CaseSensitivity defaultSensitivity - = OsSpecificAspects::fileNameCaseSensitivity(HostOsInfo::hostOs()); - Qt::CaseSensitivity selectedSensitivity = Qt::CaseSensitivity( - m_ui.fileSystemCaseSensitivityChooser->currentData().toInt()); - if (defaultSensitivity == selectedSensitivity) - HostOsInfo::unsetOverrideFileNameCaseSensitivity(); - else - HostOsInfo::setOverrideFileNameCaseSensitivity(selectedSensitivity); + const Qt::CaseSensitivity sensitivity = EditorManagerPrivate::readFileSystemSensitivity( + settings); + const Qt::CaseSensitivity selectedSensitivity = Qt::CaseSensitivity( + m_ui.fileSystemCaseSensitivityChooser->currentData().toInt()); + if (selectedSensitivity != sensitivity) { + EditorManagerPrivate::writeFileSystemSensitivity(settings, selectedSensitivity); + RestartDialog dialog( + ICore::dialogParent(), + tr("The file system case sensitivity change will take effect after restart.")); + dialog.exec(); + } } CorePlugin::setEnvironmentChanges(m_environmentChanges); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d16e7269836..6aa84a68350 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4066,6 +4066,8 @@ void GdbEngine::setEnvironmentVariables() || item.operation == EnvironmentItem::SetDisabled) { runCommand({"unset environment " + name}); } else { + if (name != item.name) + runCommand({"unset environment " + item.name}); runCommand({"-gdb-set environment " + name + '=' + item.value}); } } diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index b2c49af5015..0e9d453db9d 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -360,6 +360,7 @@ QList LanguageClientSettingsPage::changedSettings() const void LanguageClientSettingsPage::addSettings(BaseSettings *settings) { m_model.insertSettings(settings); + m_changedSettings << settings->m_id; } void LanguageClientSettingsPage::enableSettings(const QString &id) diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp index af4a900946d..171ab499b91 100644 --- a/src/plugins/projectexplorer/kitinformation.cpp +++ b/src/plugins/projectexplorer/kitinformation.cpp @@ -900,8 +900,10 @@ public: m_comboBox(createSubWidget()), m_model(new DeviceManagerModel(DeviceManager::instance())) { - m_comboBox->setSizePolicy(QSizePolicy::Ignored, m_comboBox->sizePolicy().verticalPolicy()); + m_comboBox->setSizePolicy(QSizePolicy::Preferred, + m_comboBox->sizePolicy().verticalPolicy()); m_comboBox->setModel(m_model); + m_comboBox->setMinimumContentsLength(16); // Don't stretch too much for Kit Page m_manageButton = createManageButton(Constants::DEVICE_SETTINGS_PAGE_ID); refresh(); m_comboBox->setToolTip(ki->description()); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index 4bc3e0ca7b2..314b3dc3ad5 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -436,7 +436,9 @@ static void addPythonsFromPath(QList &pythons) static QString idForPythonFromPath(QList pythons) { - const FilePath &pythonFromPath = Environment::systemEnvironment().searchInPath("python"); + FilePath pythonFromPath = Environment::systemEnvironment().searchInPath("python3"); + if (pythonFromPath.isEmpty()) + pythonFromPath = Environment::systemEnvironment().searchInPath("python"); if (pythonFromPath.isEmpty()) return {}; const Interpreter &defaultInterpreter diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index b570b26a1ae..4174702c1f9 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -116,7 +116,7 @@ FilePath getPylsModulePath(CommandLine pylsCommand) static const QString pylsInitPattern = "(.*)" + QRegularExpression::escape( - QDir::toNativeSeparators("/pyls/__init__.py")) + QDir::toNativeSeparators("/pylsp/__init__.py")) + '$'; static const QRegularExpression regexCached(" matches " + pylsInitPattern, QRegularExpression::MultilineOption); @@ -149,7 +149,7 @@ QList configuredPythonLanguageServer() static PythonLanguageServerState checkPythonLanguageServer(const FilePath &python) { using namespace LanguageClient; - const CommandLine pythonLShelpCommand(python, {"-m", "pyls", "-h"}); + const CommandLine pythonLShelpCommand(python, {"-m", "pylsp", "-h"}); const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand); for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) { if (modulePath == getPylsModulePath(serverSetting->command())) { @@ -217,7 +217,7 @@ const StdIOSettings *PyLSConfigureAssistant::languageServerForPython(const FileP { return findOrDefault(configuredPythonLanguageServer(), [pythonModulePath = getPylsModulePath( - CommandLine(python, {"-m", "pyls"}))](const StdIOSettings *setting) { + CommandLine(python, {"-m", "pylsp"}))](const StdIOSettings *setting) { return getPylsModulePath(setting->command()) == pythonModulePath; }); } @@ -226,7 +226,7 @@ static Client *registerLanguageServer(const FilePath &python) { auto *settings = new StdIOSettings(); settings->m_executable = python; - settings->m_arguments = "-m pyls"; + settings->m_arguments = "-m pylsp"; settings->m_name = PyLSConfigureAssistant::tr("Python Language Server (%1)") .arg(pythonName(python)); settings->m_languageFilter.mimeTypes = QStringList(Constants::C_PY_MIMETYPE); @@ -266,7 +266,7 @@ public: connect(&m_killTimer, &QTimer::timeout, this, &PythonLSInstallHelper::cancel); connect(&m_watcher, &QFutureWatcher::canceled, this, &PythonLSInstallHelper::cancel); - QStringList arguments = {"-m", "pip", "install", "python-language-server[all]"}; + QStringList arguments = {"-m", "pip", "install", "python-lsp-server[all]"}; // add --user to global pythons, but skip it for venv pythons if (!QDir(m_python.parentDir().toString()).exists("activate")) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 2bb563ded3a..955f04a7ac3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -334,7 +334,10 @@ QList ItemLibraryWidget::createToolBarWidgets() void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText) { - m_filterText = filterText; + if (filterText != m_filterText) { + m_filterText = filterText; + emit searchActiveChanged(); + } updateSearch(); } @@ -366,11 +369,6 @@ void ItemLibraryWidget::handleAddImport(int index) updateSearch(); } -bool ItemLibraryWidget::isSearchActive() const -{ - return !m_filterText.isEmpty(); -} - void ItemLibraryWidget::handleFilesDrop(const QStringList &filesPaths) { addResources(filesPaths); @@ -568,6 +566,11 @@ bool ItemLibraryWidget::subCompEditMode() const return m_subCompEditMode; } +bool ItemLibraryWidget::searchActive() const +{ + return !m_filterText.isEmpty(); +} + void ItemLibraryWidget::setFlowMode(bool b) { m_itemLibraryModel->setFlowMode(b); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index cd00a18fc23..d67c3df71db 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -72,6 +72,7 @@ class ItemLibraryWidget : public QFrame public: Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged) + Q_PROPERTY(bool searchActive READ searchActive NOTIFY searchActiveChanged) ItemLibraryWidget(AsynchronousImageCache &imageCache, AsynchronousImageCache &asynchronousFontImageCache, @@ -97,6 +98,7 @@ public: inline static bool isHorizontalLayout = false; bool subCompEditMode() const; + bool searchActive() const; Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); @@ -107,13 +109,13 @@ public: Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); Q_INVOKABLE void handleAddImport(int index); - Q_INVOKABLE bool isSearchActive() const; Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths); Q_INVOKABLE QSet supportedDropSuffixes(); signals: void itemActivated(const QString &itemName); void subCompEditModeChanged(); + void searchActiveChanged(); protected: bool eventFilter(QObject *obj, QEvent *event) override; diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp index e6e10a017c1..f3e95f0ef4c 100644 --- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp +++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp @@ -270,7 +270,7 @@ void ListModelEditorModel::addColumn(const QString &columnName) auto found = std::lower_bound(m_propertyNames.begin(), m_propertyNames.end(), propertyName); - if (found != m_propertyNames.end() && *found == columnName) + if (found != m_propertyNames.end() && *found == propertyName) return; int newIndex = static_cast(std::distance(m_propertyNames.begin(), found)); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index a647b653581..3bdfb903c84 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -165,9 +165,9 @@ void PropertyEditorView::changeValue(const QString &name) m_locked = false; QString errMsg = QmlDesigner::ModelNode::getIdValidityErrorMessage(newId); if (!errMsg.isEmpty()) - Core::AsynchronousMessageBox::warning(tr("Invalid ID"), errMsg); + Core::AsynchronousMessageBox::warning(tr("Invalid ID"), errMsg); else - Core::AsynchronousMessageBox::warning(tr("Invalid ID"), tr("%1 already exists.").arg(newId)); + Core::AsynchronousMessageBox::warning(tr("Invalid ID"), tr("%1 already exists.").arg(newId)); } return; } @@ -176,24 +176,24 @@ void PropertyEditorView::changeValue(const QString &name) underscoreName.replace('.', '_'); PropertyEditorValue *value = m_qmlBackEndForCurrentType->propertyValueForName(QString::fromLatin1(underscoreName)); - if (value ==nullptr) + if (value == nullptr) return; - if (propertyName.endsWith( "__AUX")) { + if (propertyName.endsWith("__AUX")) { commitAuxValueToModel(propertyName, value->value()); return; } - QmlObjectNode qmlObjectNode(m_selectedNode); + const NodeMetaInfo metaInfo = QmlObjectNode(m_selectedNode).modelNode().metaInfo(); QVariant castedValue; - if (qmlObjectNode.modelNode().metaInfo().isValid() && qmlObjectNode.modelNode().metaInfo().hasProperty(propertyName)) { - castedValue = qmlObjectNode.modelNode().metaInfo().propertyCastedValue(propertyName, value->value()); + if (metaInfo.isValid() && metaInfo.hasProperty(propertyName)) { + castedValue = metaInfo.propertyCastedValue(propertyName, value->value()); } else if (propertyIsAttachedLayoutProperty(propertyName)) { castedValue = value->value(); } else { - qWarning() << "PropertyEditor:" <fileUrl().toLocalFile()).absolutePath()); @@ -224,7 +228,8 @@ void PropertyEditorView::changeValue(const QString &name) castedValue = QVariant(newColor); } - if (!value->value().isValid()) { //reset + if (!value->value().isValid() + || (propertyTypeUrl && value->value().toString().isEmpty())) { // reset removePropertyFromModel(propertyName); } else { // QVector*D(0, 0, 0) detects as null variant though it is valid value diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp index a8742fc201f..f53aaa5ea4e 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp @@ -145,13 +145,6 @@ void AsynchronousImageCache::clean() m_generator.clean(); } -void AsynchronousImageCache::waitForFinished() -{ - wait(); - - m_generator.waitForFinished(); -} - std::tuple AsynchronousImageCache::getEntry() { std::unique_lock lock{m_mutex}; diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h index 3b320634da0..c245f31d545 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h @@ -43,9 +43,10 @@ template class ImageCacheStorage : public ImageCacheStorageInterface { public: - template - using ReadStatement = typename DatabaseType::template ReadStatement; - using WriteStatement = typename DatabaseType::WriteStatement; + template + using ReadStatement = typename DatabaseType::template ReadStatement; + template + using WriteStatement = typename DatabaseType::template WriteStatement; ImageCacheStorage(DatabaseType &database) : database(database) @@ -272,19 +273,19 @@ private: public: DatabaseType &database; Initializer initializer{database}; - Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database}; - mutable ReadStatement<1> selectImageStatement{ + Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database}; + mutable ReadStatement<1, 2> selectImageStatement{ "SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database}; - mutable ReadStatement<1> selectSmallImageStatement{ + mutable ReadStatement<1, 2> selectSmallImageStatement{ "SELECT smallImage FROM images WHERE name=?1 AND mtime >= ?2", database}; - mutable ReadStatement<1> selectIconStatement{ + mutable ReadStatement<1, 2> selectIconStatement{ "SELECT icon FROM icons WHERE name=?1 AND mtime >= ?2", database}; - WriteStatement upsertImageStatement{ + 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", database}; - WriteStatement upsertIconStatement{ + WriteStatement<3> upsertIconStatement{ "INSERT INTO icons(name, mtime, icon) VALUES (?1, ?2, ?3) ON " "CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, icon=excluded.icon", database}; diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h index f1356c64a03..66dd5601413 100644 --- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h +++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h @@ -62,7 +62,7 @@ public: ImageCache::AuxiliaryData auxiliaryData = {}) override; void clean(); - void waitForFinished(); + // void waitForFinished(); private: enum class RequestType { Image, SmallImage, Icon }; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index 1d9fe437d26..e77ba16bad3 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -47,11 +47,12 @@ template class ProjectStorage final : public ProjectStorageInterface { public: - template - using ReadStatement = typename Database::template ReadStatement; - template - using ReadWriteStatement = typename Database::template ReadWriteStatement; - using WriteStatement = typename Database::WriteStatement; + template + using ReadStatement = typename Database::template ReadStatement; + template + using ReadWriteStatement = typename Database::template ReadWriteStatement; + template + using WriteStatement = typename Database::template WriteStatement; ProjectStorage(Database &database, bool isInitialized) : database{database} @@ -501,6 +502,33 @@ private: }; }; + SourceIds filterSourceIdsWithoutType(const SourceIds &updatedSourceIds, SourceIds &sourceIdsOfTypes) + { + std::sort(sourceIdsOfTypes.begin(), sourceIdsOfTypes.end()); + + SourceIds sourceIdsWithoutTypeSourceIds; + sourceIdsWithoutTypeSourceIds.reserve(updatedSourceIds.size()); + std::set_difference(updatedSourceIds.begin(), + updatedSourceIds.end(), + sourceIdsOfTypes.begin(), + sourceIdsOfTypes.end(), + std::back_inserter(sourceIdsWithoutTypeSourceIds)); + + return sourceIdsWithoutTypeSourceIds; + } + + TypeIds fetchTypeIds(const SourceIds &sourceIds) + { + return selectTypeIdsForSourceIdsStatement.template values(128, toIntegers(sourceIds)); + } + + void unique(SourceIds &sourceIds) + { + std::sort(sourceIds.begin(), sourceIds.end()); + auto newEnd = std::unique(sourceIds.begin(), sourceIds.end()); + sourceIds.erase(newEnd, sourceIds.end()); + } + void synchronizeTypes(Storage::Types &types, TypeIds &updatedTypeIds, AliasPropertyDeclarations &insertedAliasPropertyDeclarations, @@ -512,18 +540,35 @@ private: { Storage::ExportedTypes exportedTypes; exportedTypes.reserve(types.size() * 3); + SourceIds sourceIdsOfTypes; + sourceIdsOfTypes.reserve(updatedSourceIds.size()); + SourceIds notUpdatedExportedSourceIds; + notUpdatedExportedSourceIds.reserve(updatedSourceIds.size()); + SourceIds exportedSourceIds; + exportedSourceIds.reserve(types.size()); for (auto &&type : types) { if (!type.sourceId) throw TypeHasInvalidSourceId{}; TypeId typeId = declareType(type); + sourceIdsOfTypes.push_back(type.sourceId); updatedTypeIds.push_back(typeId); - extractExportedTypes(typeId, type, exportedTypes); + if (type.changeLevel != Storage::ChangeLevel::ExcludeExportedTypes) { + exportedSourceIds.push_back(type.sourceId); + extractExportedTypes(typeId, type, exportedTypes); + } } - synchronizeExportedTypes(updatedSourceIds, - updatedTypeIds, + unique(exportedSourceIds); + + SourceIds sourceIdsWithoutType = filterSourceIdsWithoutType(updatedSourceIds, + sourceIdsOfTypes); + exportedSourceIds.insert(exportedSourceIds.end(), + sourceIdsWithoutType.begin(), + sourceIdsWithoutType.end()); + TypeIds exportedTypeIds = fetchTypeIds(exportedSourceIds); + synchronizeExportedTypes(exportedTypeIds, exportedTypes, relinkableAliasPropertyDeclarations, relinkablePropertyDeclarations, @@ -921,8 +966,7 @@ private: updateAliasPropertyDeclarationValues(updatedAliasPropertyDeclarations); } - void synchronizeExportedTypes(const SourceIds &exportedSourceIds, - const TypeIds &updatedTypeIds, + void synchronizeExportedTypes(const TypeIds &updatedTypeIds, Storage::ExportedTypes &exportedTypes, AliasPropertyDeclarations &relinkableAliasPropertyDeclarations, PropertyDeclarations &relinkablePropertyDeclarations, @@ -933,9 +977,8 @@ private: < std::tie(second.moduleId, second.name, second.version); }); - auto range = selectExportedTypesForSourceIdsStatement - .template range(toIntegers(exportedSourceIds), - toIntegers(updatedTypeIds)); + auto range = selectExportedTypesForSourceIdsStatement.template range( + toIntegers(updatedTypeIds)); auto compareKey = [](const Storage::ExportedTypeView &view, const Storage::ExportedType &type) -> long long { @@ -2102,18 +2145,18 @@ public: Database &database; Initializer initializer; ModuleCache moduleCache{ModuleStorageAdapter{*this}}; - ReadWriteStatement<1> upsertTypeStatement{ + ReadWriteStatement<1, 3> upsertTypeStatement{ "INSERT INTO types(sourceId, name, accessSemantics) VALUES(?1, ?2, ?3) ON CONFLICT DO " "UPDATE SET accessSemantics=excluded.accessSemantics WHERE accessSemantics IS NOT " "excluded.accessSemantics RETURNING typeId", database}; - WriteStatement updatePrototypeStatement{ + WriteStatement<3> updatePrototypeStatement{ "UPDATE types SET prototypeId=?2, prototypeNameId=?3 WHERE typeId=?1 AND (prototypeId IS " "NOT ?2 OR prototypeNameId IS NOT ?3)", database}; - mutable ReadStatement<1> selectTypeIdByExportedNameStatement{ + mutable ReadStatement<1, 1> selectTypeIdByExportedNameStatement{ "SELECT typeId FROM exportedTypeNames WHERE name=?1", database}; - mutable ReadStatement<1> selectPrototypeIdStatement{ + mutable ReadStatement<1, 2> selectPrototypeIdStatement{ "WITH RECURSIVE " " typeSelection(typeId) AS (" " VALUES(?1) " @@ -2122,7 +2165,7 @@ public: " IS NOT NULL)" "SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1", database}; - mutable ReadStatement<1> selectPropertyDeclarationIdByTypeIdAndNameStatement{ + mutable ReadStatement<1, 2> selectPropertyDeclarationIdByTypeIdAndNameStatement{ "WITH RECURSIVE " " typeSelection(typeId, level) AS (" " VALUES(?1, 0) " @@ -2132,7 +2175,7 @@ public: "SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) " " WHERE name=?2 ORDER BY level LIMIT 1", database}; - mutable ReadStatement<3> selectPropertyDeclarationByTypeIdAndNameStatement{ + mutable ReadStatement<3, 2> selectPropertyDeclarationByTypeIdAndNameStatement{ "WITH RECURSIVE " " typeSelection(typeId, level) AS (" " VALUES(?1, 0) " @@ -2143,7 +2186,7 @@ public: " FROM propertyDeclarations JOIN typeSelection USING(typeId) " " WHERE name=?2 ORDER BY level LIMIT 1", database}; - mutable ReadStatement<1> selectPrototypeIdsStatement{ + mutable ReadStatement<1, 1> selectPrototypeIdsStatement{ "WITH RECURSIVE " " typeSelection(typeId, level) AS (" " VALUES(?1, 0) " @@ -2152,68 +2195,69 @@ public: " USING(typeId) WHERE prototypeId IS NOT NULL) " "SELECT typeId FROM typeSelection ORDER BY level DESC", database}; - mutable ReadStatement<1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{ + mutable ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{ "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database}; - mutable ReadStatement<1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{ + mutable ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{ "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database}; mutable ReadStatement<2> selectAllSourceContextsStatement{ "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database}; - WriteStatement insertIntoSourceContextsStatement{ + WriteStatement<1> insertIntoSourceContextsStatement{ "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database}; - mutable ReadStatement<1> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{ + mutable ReadStatement<1, 2> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{ "SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database}; - mutable ReadStatement<2> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{ + mutable ReadStatement<2, 1> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{ "SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database}; - mutable ReadStatement<1> selectSourceContextIdFromSourcesBySourceIdStatement{ + mutable ReadStatement<1, 1> selectSourceContextIdFromSourcesBySourceIdStatement{ "SELECT sourceContextId FROM sources WHERE sourceId = ?", database}; - WriteStatement insertIntoSourcesStatement{ + WriteStatement<2> insertIntoSourcesStatement{ "INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database}; mutable ReadStatement<3> selectAllSourcesStatement{ "SELECT sourceName, sourceContextId, sourceId FROM sources", database}; - mutable ReadStatement<4> selectTypeByTypeIdStatement{ + mutable ReadStatement<4, 1> selectTypeByTypeIdStatement{ "SELECT sourceId, name, prototypeId, accessSemantics FROM types WHERE typeId=?", database}; - mutable ReadStatement<4> selectExportedTypesByTypeIdStatement{ + mutable ReadStatement<4, 1> selectExportedTypesByTypeIdStatement{ "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1) FROM " "exportedTypeNames WHERE typeId=?", database}; mutable ReadStatement<5> selectTypesStatement{ "SELECT sourceId, name, typeId, ifnull(prototypeId, -1), accessSemantics FROM types", database}; - ReadStatement<1> selectNotUpdatedTypesInSourcesStatement{ - "SELECT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN carray(?2))", + ReadStatement<1, 2> selectNotUpdatedTypesInSourcesStatement{ + "SELECT DISTINCT typeId FROM types WHERE (sourceId IN carray(?1) AND typeId NOT IN " + "carray(?2))", database}; - WriteStatement deleteTypeNamesByTypeIdStatement{"DELETE FROM exportedTypeNames WHERE typeId=?", - database}; - WriteStatement deleteEnumerationDeclarationByTypeIdStatement{ + WriteStatement<1> deleteTypeNamesByTypeIdStatement{ + "DELETE FROM exportedTypeNames WHERE typeId=?", database}; + WriteStatement<1> deleteEnumerationDeclarationByTypeIdStatement{ "DELETE FROM enumerationDeclarations WHERE typeId=?", database}; - WriteStatement deletePropertyDeclarationByTypeIdStatement{ + WriteStatement<1> deletePropertyDeclarationByTypeIdStatement{ "DELETE FROM propertyDeclarations WHERE typeId=?", database}; - WriteStatement deleteFunctionDeclarationByTypeIdStatement{ + WriteStatement<1> deleteFunctionDeclarationByTypeIdStatement{ "DELETE FROM functionDeclarations WHERE typeId=?", database}; - WriteStatement deleteSignalDeclarationByTypeIdStatement{ + WriteStatement<1> deleteSignalDeclarationByTypeIdStatement{ "DELETE FROM signalDeclarations WHERE typeId=?", database}; - WriteStatement deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; - mutable ReadStatement<4> selectPropertyDeclarationsByTypeIdStatement{ + WriteStatement<1> deleteTypeStatement{"DELETE FROM types WHERE typeId=?", database}; + mutable ReadStatement<4, 1> selectPropertyDeclarationsByTypeIdStatement{ "SELECT name, nullif(propertyTypeId, -1), propertyTraits, (SELECT name FROM " "propertyDeclarations WHERE propertyDeclarationId=pd.aliasPropertyDeclarationId) FROM " "propertyDeclarations AS pd WHERE typeId=?", database}; - ReadStatement<6> selectPropertyDeclarationsForTypeIdStatement{ + ReadStatement<6, 1> selectPropertyDeclarationsForTypeIdStatement{ "SELECT name, propertyTraits, propertyTypeId, propertyImportedTypeNameId, " "propertyDeclarationId, ifnull(aliasPropertyDeclarationId, -1) FROM propertyDeclarations " "WHERE typeId=? ORDER BY name", database}; - ReadWriteStatement<1> insertPropertyDeclarationStatement{ + ReadWriteStatement<1, 5> insertPropertyDeclarationStatement{ "INSERT INTO propertyDeclarations(typeId, name, propertyTypeId, propertyTraits, " "propertyImportedTypeNameId, aliasPropertyDeclarationId) VALUES(?1, ?2, ?3, ?4, ?5, NULL) " "RETURNING propertyDeclarationId", database}; - WriteStatement updatePropertyDeclarationStatement{ + WriteStatement<4> updatePropertyDeclarationStatement{ "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=NULL WHERE " "propertyDeclarationId=?1", database}; - WriteStatement updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{ + WriteStatement<3> updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement{ "WITH RECURSIVE " " properties(aliasPropertyDeclarationId) AS ( " " SELECT propertyDeclarationId FROM propertyDeclarations WHERE " @@ -2226,7 +2270,7 @@ public: "FROM properties AS p " "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", database}; - WriteStatement updatePropertyAliasDeclarationRecursivelyStatement{ + WriteStatement<1> updatePropertyAliasDeclarationRecursivelyStatement{ "WITH RECURSIVE " " propertyValues(propertyTypeId, propertyTraits) AS (" " SELECT propertyTypeId, propertyTraits FROM propertyDeclarations " @@ -2242,120 +2286,120 @@ public: "FROM properties AS p, propertyValues AS pv " "WHERE pd.propertyDeclarationId=p.aliasPropertyDeclarationId", database}; - WriteStatement deletePropertyDeclarationStatement{ + WriteStatement<1> deletePropertyDeclarationStatement{ "DELETE FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; - ReadStatement<3> selectPropertyDeclarationsWithAliasForTypeIdStatement{ + ReadStatement<3, 1> selectPropertyDeclarationsWithAliasForTypeIdStatement{ "SELECT name, propertyDeclarationId, aliasPropertyDeclarationId FROM propertyDeclarations " "WHERE typeId=? AND aliasPropertyDeclarationId IS NOT NULL ORDER BY name", database}; - WriteStatement updatePropertyDeclarationWithAliasAndTypeStatement{ + WriteStatement<5> updatePropertyDeclarationWithAliasAndTypeStatement{ "UPDATE propertyDeclarations SET propertyTypeId=?2, propertyTraits=?3, " "propertyImportedTypeNameId=?4, aliasPropertyDeclarationId=?5 WHERE " "propertyDeclarationId=?1", database}; - ReadWriteStatement<1> insertAliasPropertyDeclarationStatement{ + ReadWriteStatement<1, 2> insertAliasPropertyDeclarationStatement{ "INSERT INTO propertyDeclarations(typeId, name) VALUES(?1, ?2) RETURNING " "propertyDeclarationId", database}; - mutable ReadStatement<4> selectFunctionDeclarationsForTypeIdStatement{ + mutable ReadStatement<4, 1> selectFunctionDeclarationsForTypeIdStatement{ "SELECT name, returnTypeName, signature, functionDeclarationId FROM " "functionDeclarations WHERE typeId=? ORDER BY name", database}; - mutable ReadStatement<3> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{ + mutable ReadStatement<3, 1> selectFunctionDeclarationsForTypeIdWithoutSignatureStatement{ "SELECT name, returnTypeName, functionDeclarationId FROM " "functionDeclarations WHERE typeId=? ORDER BY name", database}; - mutable ReadStatement<3> selectFunctionParameterDeclarationsStatement{ + mutable ReadStatement<3, 1> selectFunctionParameterDeclarationsStatement{ "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " "json_extract(json_each.value, '$.tr') FROM functionDeclarations, " "json_each(functionDeclarations.signature) WHERE functionDeclarationId=?", database}; - WriteStatement insertFunctionDeclarationStatement{ + WriteStatement<4> insertFunctionDeclarationStatement{ "INSERT INTO functionDeclarations(typeId, name, returnTypeName, signature) VALUES(?1, ?2, " "?3, ?4)", database}; - WriteStatement updateFunctionDeclarationStatement{ + WriteStatement<3> updateFunctionDeclarationStatement{ "UPDATE functionDeclarations SET returnTypeName=?2, signature=?3 WHERE " "functionDeclarationId=?1", database}; - WriteStatement deleteFunctionDeclarationStatement{ + WriteStatement<1> deleteFunctionDeclarationStatement{ "DELETE FROM functionDeclarations WHERE functionDeclarationId=?", database}; - mutable ReadStatement<3> selectSignalDeclarationsForTypeIdStatement{ + mutable ReadStatement<3, 1> selectSignalDeclarationsForTypeIdStatement{ "SELECT name, signature, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER " "BY name", database}; - mutable ReadStatement<2> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{ + mutable ReadStatement<2, 1> selectSignalDeclarationsForTypeIdWithoutSignatureStatement{ "SELECT name, signalDeclarationId FROM signalDeclarations WHERE typeId=? ORDER BY name", database}; - mutable ReadStatement<3> selectSignalParameterDeclarationsStatement{ + mutable ReadStatement<3, 1> selectSignalParameterDeclarationsStatement{ "SELECT json_extract(json_each.value, '$.n'), json_extract(json_each.value, '$.tn'), " "json_extract(json_each.value, '$.tr') FROM signalDeclarations, " "json_each(signalDeclarations.signature) WHERE signalDeclarationId=?", database}; - WriteStatement insertSignalDeclarationStatement{ + WriteStatement<3> insertSignalDeclarationStatement{ "INSERT INTO signalDeclarations(typeId, name, signature) VALUES(?1, ?2, ?3)", database}; - WriteStatement updateSignalDeclarationStatement{ + WriteStatement<2> updateSignalDeclarationStatement{ "UPDATE signalDeclarations SET signature=?2 WHERE signalDeclarationId=?1", database}; - WriteStatement deleteSignalDeclarationStatement{ + WriteStatement<1> deleteSignalDeclarationStatement{ "DELETE FROM signalDeclarations WHERE signalDeclarationId=?", database}; - mutable ReadStatement<3> selectEnumerationDeclarationsForTypeIdStatement{ + mutable ReadStatement<3, 1> selectEnumerationDeclarationsForTypeIdStatement{ "SELECT name, enumeratorDeclarations, enumerationDeclarationId FROM " "enumerationDeclarations WHERE typeId=? ORDER BY name", database}; - mutable ReadStatement<2> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{ + mutable ReadStatement<2, 1> selectEnumerationDeclarationsForTypeIdWithoutEnumeratorDeclarationsStatement{ "SELECT name, enumerationDeclarationId FROM enumerationDeclarations WHERE typeId=? ORDER " "BY name", database}; - mutable ReadStatement<3> selectEnumeratorDeclarationStatement{ + mutable ReadStatement<3, 1> selectEnumeratorDeclarationStatement{ "SELECT json_each.key, json_each.value, json_each.type!='null' FROM " "enumerationDeclarations, json_each(enumerationDeclarations.enumeratorDeclarations) WHERE " "enumerationDeclarationId=?", database}; - WriteStatement insertEnumerationDeclarationStatement{ + WriteStatement<3> insertEnumerationDeclarationStatement{ "INSERT INTO enumerationDeclarations(typeId, name, enumeratorDeclarations) VALUES(?1, ?2, " "?3)", database}; - WriteStatement updateEnumerationDeclarationStatement{ + WriteStatement<2> updateEnumerationDeclarationStatement{ "UPDATE enumerationDeclarations SET enumeratorDeclarations=?2 WHERE " "enumerationDeclarationId=?1", database}; - WriteStatement deleteEnumerationDeclarationStatement{ + WriteStatement<1> deleteEnumerationDeclarationStatement{ "DELETE FROM enumerationDeclarations WHERE enumerationDeclarationId=?", database}; - mutable ReadStatement<1> selectModuleIdByNameStatement{ + mutable ReadStatement<1, 1> selectModuleIdByNameStatement{ "SELECT moduleId FROM modules WHERE name=? LIMIT 1", database}; - mutable ReadWriteStatement<1> insertModuleNameStatement{ + mutable ReadWriteStatement<1, 1> insertModuleNameStatement{ "INSERT INTO modules(name) VALUES(?1) RETURNING moduleId", database}; - mutable ReadStatement<1> selectModuleNameStatement{ + mutable ReadStatement<1, 1> selectModuleNameStatement{ "SELECT name FROM modules WHERE moduleId =?1", database}; mutable ReadStatement<2> selectAllModulesStatement{"SELECT name, moduleId FROM modules", database}; - mutable ReadStatement<1> selectTypeIdBySourceIdAndNameStatement{ + mutable ReadStatement<1, 2> selectTypeIdBySourceIdAndNameStatement{ "SELECT typeId FROM types WHERE sourceId=?1 and name=?2", database}; - mutable ReadStatement<1> selectTypeIdByModuleIdsAndExportedNameStatement{ + mutable ReadStatement<1, 3> selectTypeIdByModuleIdsAndExportedNameStatement{ "SELECT typeId FROM exportedTypeNames WHERE moduleId IN carray(?1, ?2, 'int32') AND " "name=?3", database}; - mutable ReadStatement<5> selectDocumentImportForSourceIdStatement{ + mutable ReadStatement<5, 1> selectDocumentImportForSourceIdStatement{ "SELECT importId, sourceId, moduleId, ifnull(majorVersion, -1), ifnull(minorVersion, -1) " "FROM documentImports WHERE sourceId IN carray(?1) ORDER BY sourceId, moduleId, " "majorVersion, minorVersion", database}; - WriteStatement insertDocumentImportWithoutVersionStatement{ + WriteStatement<2> insertDocumentImportWithoutVersionStatement{ "INSERT INTO documentImports(sourceId, moduleId) " "VALUES (?1, ?2)", database}; - WriteStatement insertDocumentImportWithMajorVersionStatement{ + WriteStatement<3> insertDocumentImportWithMajorVersionStatement{ "INSERT INTO documentImports(sourceId, moduleId, majorVersion) " "VALUES (?1, ?2, ?3)", database}; - WriteStatement insertDocumentImportWithVersionStatement{ + WriteStatement<4> insertDocumentImportWithVersionStatement{ "INSERT INTO documentImports(sourceId, moduleId, majorVersion, minorVersion) " "VALUES (?1, ?2, ?3, ?4)", database}; - WriteStatement deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1", - database}; - WriteStatement deleteDocumentImportsWithSourceIdsStatement{ + WriteStatement<1> deleteDocumentImportStatement{"DELETE FROM documentImports WHERE importId=?1", + database}; + WriteStatement<1> deleteDocumentImportsWithSourceIdsStatement{ "DELETE FROM documentImports WHERE sourceId IN carray(?1)", database}; - ReadStatement<1> selectPropertyDeclarationIdPrototypeChainDownStatement{ + ReadStatement<1, 2> selectPropertyDeclarationIdPrototypeChainDownStatement{ "WITH RECURSIVE " " typeSelection(typeId, level) AS (" " SELECT prototypeId, 0 FROM types WHERE typeId=?1 AND prototypeId IS NOT NULL" @@ -2365,22 +2409,22 @@ public: "SELECT propertyDeclarationId FROM typeSelection JOIN propertyDeclarations " " USING(typeId) WHERE name=?2 ORDER BY level LIMIT 1", database}; - WriteStatement updateAliasIdPropertyDeclarationStatement{ + WriteStatement<2> updateAliasIdPropertyDeclarationStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2 WHERE " "aliasPropertyDeclarationId=?1", database}; - WriteStatement updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{ + WriteStatement<2> updateAliasPropertyDeclarationByAliasPropertyDeclarationIdStatement{ "UPDATE propertyDeclarations SET propertyTypeId=new.propertyTypeId, " "propertyTraits=new.propertyTraits, aliasPropertyDeclarationId=?1 FROM (SELECT " "propertyTypeId, propertyTraits FROM propertyDeclarations WHERE propertyDeclarationId=?1) " "AS new WHERE aliasPropertyDeclarationId=?2", database}; - WriteStatement updateAliasPropertyDeclarationToNullStatement{ + WriteStatement<1> updateAliasPropertyDeclarationToNullStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL, propertyTypeId=NULL, " "propertyTraits=NULL WHERE propertyDeclarationId=? AND (aliasPropertyDeclarationId IS NOT " "NULL OR propertyTypeId IS NOT NULL OR propertyTraits IS NOT NULL)", database}; - ReadStatement<4> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ + ReadStatement<4, 1> selectAliasPropertiesDeclarationForPropertiesWithTypeIdStatement{ "SELECT alias.typeId, alias.propertyDeclarationId, alias.propertyImportedTypeNameId, " "target.propertyDeclarationId FROM propertyDeclarations AS alias JOIN propertyDeclarations " "AS target ON alias.aliasPropertyDeclarationId=target.propertyDeclarationId WHERE " @@ -2388,7 +2432,7 @@ public: "(SELECT importedTypeNameId FROM exportedTypeNames JOIN importedTypeNames USING(name) " "WHERE typeId=?1)", database}; - ReadStatement<3> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{ + ReadStatement<3, 1> selectAliasPropertiesDeclarationForPropertiesWithAliasIdStatement{ "WITH RECURSIVE " " properties(propertyDeclarationId, propertyImportedTypeNameId, typeId, " " aliasPropertyDeclarationId) AS (" @@ -2402,22 +2446,22 @@ public: "SELECT propertyDeclarationId, propertyImportedTypeNameId, aliasPropertyDeclarationId " " FROM properties", database}; - ReadWriteStatement<3> updatesPropertyDeclarationPropertyTypeToNullStatement{ + ReadWriteStatement<3, 1> updatesPropertyDeclarationPropertyTypeToNullStatement{ "UPDATE propertyDeclarations SET propertyTypeId=NULL WHERE propertyTypeId=?1 AND " "aliasPropertyDeclarationId IS NULL RETURNING typeId, propertyDeclarationId, " "propertyImportedTypeNameId", database}; - ReadStatement<1> selectPropertyNameStatement{ + ReadStatement<1, 1> selectPropertyNameStatement{ "SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database}; - WriteStatement updatePropertyDeclarationTypeStatement{ + WriteStatement<2> updatePropertyDeclarationTypeStatement{ "UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database}; - ReadWriteStatement<2> updatePrototypeIdToNullStatement{ + ReadWriteStatement<2, 1> updatePrototypeIdToNullStatement{ "UPDATE types SET prototypeId=NULL WHERE prototypeId=?1 RETURNING " "typeId, prototypeNameId", database}; - WriteStatement updateTypePrototypeStatement{"UPDATE types SET prototypeId=?2 WHERE typeId=?1", - database}; - mutable ReadStatement<1> selectTypeIdsForPrototypeChainIdStatement{ + WriteStatement<2> updateTypePrototypeStatement{ + "UPDATE types SET prototypeId=?2 WHERE typeId=?1", database}; + mutable ReadStatement<1, 1> selectTypeIdsForPrototypeChainIdStatement{ "WITH RECURSIVE " " prototypes(typeId) AS (" " SELECT prototypeId FROM types WHERE typeId=? AND prototypeId IS NOT NULL" @@ -2426,12 +2470,12 @@ public: " IS NOT NULL)" "SELECT typeId FROM prototypes", database}; - WriteStatement updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ + WriteStatement<3> updatePropertyDeclarationAliasIdAndTypeNameIdStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=?2, " "propertyImportedTypeNameId=?3 WHERE propertyDeclarationId=?1 AND " "(aliasPropertyDeclarationId IS NOT ?2 OR propertyImportedTypeNameId IS NOT ?3)", database}; - WriteStatement updatetPropertiesDeclarationValuesOfAliasStatement{ + WriteStatement<1> updatetPropertiesDeclarationValuesOfAliasStatement{ "WITH RECURSIVE " " properties(propertyDeclarationId, propertyTypeId, propertyTraits) AS ( " " SELECT aliasPropertyDeclarationId, propertyTypeId, propertyTraits FROM " @@ -2446,11 +2490,11 @@ public: " (pd.propertyTypeId IS NOT p.propertyTypeId OR pd.propertyTraits IS NOT " " p.propertyTraits)", database}; - WriteStatement updatePropertyDeclarationAliasIdToNullStatement{ + WriteStatement<1> updatePropertyDeclarationAliasIdToNullStatement{ "UPDATE propertyDeclarations SET aliasPropertyDeclarationId=NULL WHERE " "propertyDeclarationId=?1", database}; - mutable ReadStatement<1> selectPropertyDeclarationIdsForAliasChainStatement{ + mutable ReadStatement<1, 1> selectPropertyDeclarationIdsForAliasChainStatement{ "WITH RECURSIVE " " properties(propertyDeclarationId) AS ( " " SELECT aliasPropertyDeclarationId FROM propertyDeclarations WHERE " @@ -2462,43 +2506,44 @@ public: database}; mutable ReadStatement<3> selectAllFileStatusesStatement{ "SELECT sourceId, size, lastModified FROM fileStatuses ORDER BY sourceId", database}; - mutable ReadStatement<3> selectFileStatusesForSourceIdsStatement{ + mutable ReadStatement<3, 1> selectFileStatusesForSourceIdsStatement{ "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId IN carray(?1) ORDER " "BY sourceId", database}; - mutable ReadStatement<3> selectFileStatusesForSourceIdStatement{ + mutable ReadStatement<3, 1> selectFileStatusesForSourceIdStatement{ "SELECT sourceId, size, lastModified FROM fileStatuses WHERE sourceId=?1 ORDER BY sourceId", database}; - WriteStatement insertFileStatusStatement{ + WriteStatement<3> insertFileStatusStatement{ "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES(?1, ?2, ?3)", database}; - WriteStatement deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1", database}; - WriteStatement updateFileStatusStatement{ + WriteStatement<1> deleteFileStatusStatement{"DELETE FROM fileStatuses WHERE sourceId=?1", + database}; + WriteStatement<3> updateFileStatusStatement{ "UPDATE fileStatuses SET size=?2, lastModified=?3 WHERE sourceId=?1", database}; - ReadStatement<1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?", - database}; - mutable ReadStatement<1> selectImportedTypeNameIdStatement{ + ReadStatement<1, 1> selectTypeIdBySourceIdStatement{"SELECT typeId FROM types WHERE sourceId=?", + database}; + mutable ReadStatement<1, 3> selectImportedTypeNameIdStatement{ "SELECT importedTypeNameId FROM importedTypeNames WHERE kind=?1 AND importOrSourceId=?2 " "AND name=?3 LIMIT 1", database}; - mutable ReadWriteStatement<1> insertImportedTypeNameIdStatement{ + mutable ReadWriteStatement<1, 3> insertImportedTypeNameIdStatement{ "INSERT INTO importedTypeNames(kind, importOrSourceId, name) VALUES (?1, ?2, ?3) " "RETURNING importedTypeNameId", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdStatement{ + mutable ReadStatement<1, 2> selectImportIdBySourceIdAndModuleIdStatement{ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND majorVersion " "IS NULL AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ + mutable ReadStatement<1, 3> selectImportIdBySourceIdAndModuleIdAndMajorVersionStatement{ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " "majorVersion=?3 AND minorVersion IS NULL LIMIT 1", database}; - mutable ReadStatement<1> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ + mutable ReadStatement<1, 4> selectImportIdBySourceIdAndModuleIdAndVersionStatement{ "SELECT importId FROM documentImports WHERE sourceId=?1 AND moduleId=?2 AND " "majorVersion=?3 AND minorVersion=?4 LIMIT 1", database}; - mutable ReadStatement<1> selectKindFromImportedTypeNamesStatement{ + mutable ReadStatement<1, 1> selectKindFromImportedTypeNamesStatement{ "SELECT kind FROM importedTypeNames WHERE importedTypeNameId=?1", database}; - mutable ReadStatement<1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ + mutable ReadStatement<1, 1> selectTypeIdForQualifiedImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=importId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " "itn.kind=2 AND importedTypeNameId=?1 AND itn.name=etn.name AND " @@ -2506,7 +2551,7 @@ public: "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", database}; - mutable ReadStatement<1> selectTypeIdForImportedTypeNameNamesStatement{ + mutable ReadStatement<1, 1> selectTypeIdForImportedTypeNameNamesStatement{ "SELECT typeId FROM importedTypeNames AS itn JOIN documentImports AS di ON " "importOrSourceId=sourceId JOIN exportedTypeNames AS etn USING(moduleId) WHERE " "itn.kind=1 AND importedTypeNameId=?1 AND itn.name=etn.name AND " @@ -2514,44 +2559,46 @@ public: "NULL OR di.minorVersion>=etn.minorVersion))) ORDER BY etn.majorVersion DESC NULLS FIRST, " "etn.minorVersion DESC NULLS FIRST LIMIT 1", database}; - WriteStatement deleteAllSourcesStatement{"DELETE FROM sources", database}; - WriteStatement deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; - mutable ReadStatement<6> selectExportedTypesForSourceIdsStatement{ - "SELECT moduleId, etn.name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " - "exportedTypeNameId FROM exportedTypeNames AS etn JOIN types USING(typeId) WHERE sourceId " - "IN carray(?1) OR typeId in carray(?2) ORDER BY moduleId, etn.name, majorVersion, " - "minorVersion", + WriteStatement<0> deleteAllSourcesStatement{"DELETE FROM sources", database}; + WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; + mutable ReadStatement<6, 1> selectExportedTypesForSourceIdsStatement{ + "SELECT moduleId, name, ifnull(majorVersion, -1), ifnull(minorVersion, -1), typeId, " + "exportedTypeNameId FROM exportedTypeNames WHERE typeId in carray(?1) ORDER BY moduleId, " + "name, majorVersion, minorVersion", database}; - WriteStatement insertExportedTypeNamesWithVersionStatement{ + WriteStatement<5> insertExportedTypeNamesWithVersionStatement{ "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, minorVersion, typeId) " "VALUES(?1, ?2, ?3, ?4, ?5)", database}; - WriteStatement insertExportedTypeNamesWithMajorVersionStatement{ + WriteStatement<4> insertExportedTypeNamesWithMajorVersionStatement{ "INSERT INTO exportedTypeNames(moduleId, name, majorVersion, typeId) " "VALUES(?1, ?2, ?3, ?4)", database}; - WriteStatement insertExportedTypeNamesWithoutVersionStatement{ + WriteStatement<3> insertExportedTypeNamesWithoutVersionStatement{ "INSERT INTO exportedTypeNames(moduleId, name, typeId) VALUES(?1, ?2, ?3)", database}; - WriteStatement deleteExportedTypeNameStatement{ + WriteStatement<1> deleteExportedTypeNameStatement{ "DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database}; - WriteStatement updateExportedTypeNameTypeIdStatement{ + WriteStatement<2> updateExportedTypeNameTypeIdStatement{ "UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database}; - mutable ReadStatement<4> selectProjectDatasForModuleIdsStatement{ + mutable ReadStatement<4, 1> selectProjectDatasForModuleIdsStatement{ "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " "projectSourceId IN carray(?1) ORDER BY projectSourceId, sourceId", database}; - WriteStatement insertProjectDataStatement{"INSERT INTO projectDatas(projectSourceId, sourceId, " - "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)", - database}; - WriteStatement deleteProjectDataStatement{ + WriteStatement<4> insertProjectDataStatement{ + "INSERT INTO projectDatas(projectSourceId, sourceId, " + "moduleId, fileType) VALUES(?1, ?2, ?3, ?4)", + database}; + WriteStatement<2> deleteProjectDataStatement{ "DELETE FROM projectDatas WHERE projectSourceId=?1 AND sourceId=?2", database}; - WriteStatement updateProjectDataStatement{ + WriteStatement<4> updateProjectDataStatement{ "UPDATE projectDatas SET moduleId=?3, fileType=?4 WHERE projectSourceId=?1 AND sourceId=?2", database}; - mutable ReadStatement<4> selectProjectDatasForModuleIdStatement{ + mutable ReadStatement<4, 1> selectProjectDatasForModuleIdStatement{ "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE " "projectSourceId=?1", database}; + ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{ + "SELECT typeId FROM types WHERE sourceId IN carray(?1)", database}; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index 1e49ed39093..247d2f3e93d 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -548,7 +548,7 @@ bool generateMainCpp(const FilePath &dir) QString modulesAsPlugins; for (const QString &moduleName : GenerateCmakeLists::moduleNames) modulesAsPlugins.append( - QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "plugin")); + QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "Plugin")); QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH) .arg(modulesAsPlugins); diff --git a/tests/system/suite_QMLS/tst_QMLS05/test.py b/tests/system/suite_QMLS/tst_QMLS05/test.py index 9f78d8b8c4f..376c8bfd501 100644 --- a/tests/system/suite_QMLS/tst_QMLS05/test.py +++ b/tests/system/suite_QMLS/tst_QMLS05/test.py @@ -55,7 +55,5 @@ def main(): for line in ["Item {", "x: 10;", "y: 20;", "width: 10", "}"]: verifyCurrentLine(editorArea, line, verifyMessage) type(editorArea, "") - #save and exit - invokeMenuItem("File", "Save All") invokeMenuItem("File", "Exit") diff --git a/tests/system/suite_QMLS/tst_QMLS06/test.py b/tests/system/suite_QMLS/tst_QMLS06/test.py index 9c61188e1f3..c2c0fe07462 100644 --- a/tests/system/suite_QMLS/tst_QMLS06/test.py +++ b/tests/system/suite_QMLS/tst_QMLS06/test.py @@ -70,6 +70,4 @@ def main(): verifyCurrentLine(editorArea, "sourceComponent: component_Item", verifyMessage) type(editorArea, "") verifyCurrentLine(editorArea, "}", verifyMessage) - # save and exit - invokeMenuItem("File", "Save All") invokeMenuItem("File", "Exit") diff --git a/tests/system/suite_QMLS/tst_QMLS07/test.py b/tests/system/suite_QMLS/tst_QMLS07/test.py index 054332e5213..b8e5d66e627 100644 --- a/tests/system/suite_QMLS/tst_QMLS07/test.py +++ b/tests/system/suite_QMLS/tst_QMLS07/test.py @@ -47,6 +47,4 @@ def main(): type(editorArea, "") test.compare(str(lineUnderCursor(editorArea)).strip(), "// @disable-check M16", "Verifying 'Add comment to suppress message' refactoring") - # save and exit - invokeMenuItem("File", "Save All") invokeMenuItem("File", "Exit") diff --git a/tests/unit/unittest/asynchronousimagecache-test.cpp b/tests/unit/unittest/asynchronousimagecache-test.cpp index d179c51b918..9184a00ac4f 100644 --- a/tests/unit/unittest/asynchronousimagecache-test.cpp +++ b/tests/unit/unittest/asynchronousimagecache-test.cpp @@ -324,34 +324,6 @@ TEST_F(AsynchronousImageCache, AfterCleanNewJobsWorks) notification.wait(); } -TEST_F(AsynchronousImageCache, WaitForFinished) -{ - ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component1.qml"), _)).WillByDefault([&](auto, auto) { - waitInThread.notify(); - return QmlDesigner::ImageCacheStorageInterface::ImageEntry{image1, true}; - }); - ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component2.qml"), _)) - .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image1, true})); - cache.requestImage("/path/to/Component1.qml", - mockCaptureCallback.AsStdFunction(), - mockAbortCallback.AsStdFunction()); - cache.requestImage("/path/to/Component2.qml", - mockCaptureCallback.AsStdFunction(), - mockAbortCallback.AsStdFunction()); - - EXPECT_CALL(mockCaptureCallback, Call(_)).Times(2); - - waitInThread.wait(); - cache.waitForFinished(); -} - -TEST_F(AsynchronousImageCache, WaitForFinishedInGenerator) -{ - EXPECT_CALL(mockGenerator, waitForFinished()); - - cache.waitForFinished(); -} - TEST_F(AsynchronousImageCache, RequestImageWithExtraIdFetchesImageFromStorage) { EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml+extraId1"), _)) diff --git a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp index 0e92b068974..130a2e30427 100644 --- a/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/createtablesqlstatementbuilder-test.cpp @@ -39,13 +39,15 @@ using Sqlite::ForeignKeyAction; using Sqlite::JournalMode; using Sqlite::OpenMode; using Sqlite::PrimaryKey; -using Sqlite::SqliteColumns; using Sqlite::SqlStatementBuilderException; +using Sqlite::StrictColumnType; using Sqlite::Unique; class CreateTableSqlStatementBuilder : public ::testing::Test { protected: + using Columns = ::Sqlite::Columns; + using Builder = Sqlite::CreateTableSqlStatementBuilder; void bindValues() { builder.clear(); @@ -55,9 +57,9 @@ protected: builder.addColumn("number", ColumnType::Numeric); } - static SqliteColumns createColumns() + static Columns createColumns() { - SqliteColumns columns; + Columns columns; columns.emplace_back("", "id", ColumnType::Integer, Sqlite::Constraints{PrimaryKey{}}); columns.emplace_back("", "name", ColumnType::Text); columns.emplace_back("", "number", ColumnType::Numeric); @@ -66,7 +68,7 @@ protected: } protected: - Sqlite::CreateTableSqlStatementBuilder builder; + Builder builder; }; TEST_F(CreateTableSqlStatementBuilder, IsNotValidAfterCreation) @@ -125,8 +127,7 @@ TEST_F(CreateTableSqlStatementBuilder, ChangeTable) builder.setTableName("test2"); ASSERT_THAT(builder.sqlStatement(), - "CREATE TABLE test2(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)" - ); + "CREATE TABLE test2(id INTEGER PRIMARY KEY, name TEXT, number NUMERIC)"); } TEST_F(CreateTableSqlStatementBuilder, IsInvalidAfterClearColumsOnly) @@ -163,7 +164,6 @@ TEST_F(CreateTableSqlStatementBuilder, SetWitoutRowId) TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions) { - builder.clear(); builder.setTableName("test"); builder.setColumns(createColumns()); @@ -174,7 +174,6 @@ TEST_F(CreateTableSqlStatementBuilder, SetColumnDefinitions) TEST_F(CreateTableSqlStatementBuilder, UniqueContraint) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {Unique{}}); @@ -185,7 +184,6 @@ TEST_F(CreateTableSqlStatementBuilder, UniqueContraint) TEST_F(CreateTableSqlStatementBuilder, IfNotExitsModifier) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {}); @@ -197,7 +195,6 @@ TEST_F(CreateTableSqlStatementBuilder, IfNotExitsModifier) TEST_F(CreateTableSqlStatementBuilder, TemporaryTable) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {}); @@ -209,7 +206,6 @@ TEST_F(CreateTableSqlStatementBuilder, TemporaryTable) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", ""}}); @@ -219,7 +215,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithoutColumn) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); @@ -230,7 +225,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyWithColumn) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); @@ -241,7 +235,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateNoAction) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -255,7 +248,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateRestrict) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -269,7 +261,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetNull) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -283,7 +274,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateSetDefault) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -297,7 +287,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyUpdateCascade) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); @@ -308,7 +297,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteNoAction) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -322,7 +310,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteRestrict) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -336,7 +323,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetNull) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -350,7 +336,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteSetDefault) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -364,7 +349,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteCascade) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -381,7 +365,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction) TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -399,7 +382,6 @@ TEST_F(CreateTableSqlStatementBuilder, ForeignKeyDeferred) TEST_F(CreateTableSqlStatementBuilder, NotNullConstraint) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {Sqlite::NotNull{}}); @@ -409,7 +391,6 @@ TEST_F(CreateTableSqlStatementBuilder, NotNullConstraint) TEST_F(CreateTableSqlStatementBuilder, NotNullAndUniqueConstraint) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {Sqlite::Unique{}, Sqlite::NotNull{}}); @@ -419,7 +400,6 @@ TEST_F(CreateTableSqlStatementBuilder, NotNullAndUniqueConstraint) TEST_F(CreateTableSqlStatementBuilder, Check) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Text, {Sqlite::Check{"id != ''"}}); @@ -429,7 +409,6 @@ TEST_F(CreateTableSqlStatementBuilder, Check) TEST_F(CreateTableSqlStatementBuilder, DefaultValueInt) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {Sqlite::DefaultValue{1LL}}); @@ -439,7 +418,6 @@ TEST_F(CreateTableSqlStatementBuilder, DefaultValueInt) TEST_F(CreateTableSqlStatementBuilder, DefaultValueFloat) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Real, {Sqlite::DefaultValue{1.1}}); @@ -449,7 +427,6 @@ TEST_F(CreateTableSqlStatementBuilder, DefaultValueFloat) TEST_F(CreateTableSqlStatementBuilder, DefaultValueString) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Text, {Sqlite::DefaultValue{"foo"}}); @@ -459,7 +436,6 @@ TEST_F(CreateTableSqlStatementBuilder, DefaultValueString) TEST_F(CreateTableSqlStatementBuilder, DefaultExpression) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -472,7 +448,6 @@ TEST_F(CreateTableSqlStatementBuilder, DefaultExpression) TEST_F(CreateTableSqlStatementBuilder, Collation) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Text, {Sqlite::Collate{"unicode"}}); @@ -482,7 +457,6 @@ TEST_F(CreateTableSqlStatementBuilder, Collation) TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysStored) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -497,7 +471,6 @@ TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysStored) TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysVirtual) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", @@ -512,7 +485,6 @@ TEST_F(CreateTableSqlStatementBuilder, GeneratedAlwaysVirtual) TEST_F(CreateTableSqlStatementBuilder, PrimaryKeyAutoincrement) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer, {Sqlite::PrimaryKey{Sqlite::AutoIncrement::Yes}}); @@ -522,7 +494,6 @@ TEST_F(CreateTableSqlStatementBuilder, PrimaryKeyAutoincrement) TEST_F(CreateTableSqlStatementBuilder, BlobType) { - builder.clear(); builder.setTableName("test"); builder.addColumn("data", ColumnType::Blob); @@ -532,7 +503,6 @@ TEST_F(CreateTableSqlStatementBuilder, BlobType) TEST_F(CreateTableSqlStatementBuilder, TablePrimaryKeyConstaint) { - builder.clear(); builder.setTableName("test"); builder.addColumn("id", ColumnType::Integer); builder.addColumn("text", ColumnType::Text); @@ -543,4 +513,595 @@ TEST_F(CreateTableSqlStatementBuilder, TablePrimaryKeyConstaint) ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER, text TEXT, PRIMARY KEY(id, text))"); } +TEST_F(CreateTableSqlStatementBuilder, NoneColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::None); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id)"); +} + +TEST_F(CreateTableSqlStatementBuilder, NumericColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Numeric); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id NUMERIC)"); +} + +TEST_F(CreateTableSqlStatementBuilder, IntegerColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Integer); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER)"); +} + +TEST_F(CreateTableSqlStatementBuilder, RealColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Real); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id REAL)"); +} + +TEST_F(CreateTableSqlStatementBuilder, TextColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Text); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id TEXT)"); +} + +TEST_F(CreateTableSqlStatementBuilder, BlobColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", ColumnType::Blob); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id BLOB)"); +} + +class CreateStrictTableSqlStatementBuilder : public ::testing::Test +{ +protected: + using Columns = ::Sqlite::StrictColumns; + + void bindValues() + { + builder.clear(); + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Integer, {PrimaryKey{}}); + builder.addColumn("name", StrictColumnType::Text); + builder.addColumn("number", StrictColumnType::Any); + } + + static Columns createColumns() + { + Columns columns; + columns.emplace_back("", "id", StrictColumnType::Integer, Sqlite::Constraints{PrimaryKey{}}); + columns.emplace_back("", "name", StrictColumnType::Text); + columns.emplace_back("", "number", StrictColumnType::Any); + + return columns; + } + +protected: + Sqlite::CreateTableSqlStatementBuilder builder; +}; + +TEST_F(CreateStrictTableSqlStatementBuilder, IsNotValidAfterCreation) +{ + ASSERT_FALSE(builder.isValid()); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, IsValidAfterBinding) +{ + bindValues(); + + ASSERT_TRUE(builder.isValid()); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, InvalidAfterClear) +{ + bindValues(); + + builder.clear(); + + ASSERT_TRUE(!builder.isValid()); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, NoSqlStatementAfterClear) +{ + bindValues(); + builder.sqlStatement(); + + builder.clear(); + + ASSERT_THROW(builder.sqlStatement(), SqlStatementBuilderException); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, SqlStatement) +{ + bindValues(); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number ANY) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, AddColumnToExistingColumns) +{ + bindValues(); + + builder.addColumn("number2", StrictColumnType::Real); + + ASSERT_THAT( + builder.sqlStatement(), + "CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number ANY, number2 REAL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ChangeTable) +{ + bindValues(); + + builder.setTableName("test2"); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test2(id INTEGER PRIMARY KEY, name TEXT, number ANY) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, IsInvalidAfterClearColumsOnly) +{ + bindValues(); + builder.sqlStatement(); + + builder.clearColumns(); + + ASSERT_THROW(builder.sqlStatement(), SqlStatementBuilderException); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ClearColumnsAndAddColumnNewColumns) +{ + bindValues(); + builder.clearColumns(); + + builder.addColumn("name3", StrictColumnType::Text); + builder.addColumn("number3", StrictColumnType::Real); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(name3 TEXT, number3 REAL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, SetWitoutRowId) +{ + bindValues(); + + builder.setUseWithoutRowId(true); + + ASSERT_THAT( + builder.sqlStatement(), + "CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number ANY) WITHOUT ROWID STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, SetColumnDefinitions) +{ + builder.setTableName("test"); + + builder.setColumns(createColumns()); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER PRIMARY KEY, name TEXT, number ANY) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, UniqueContraint) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {Unique{}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER UNIQUE) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, IfNotExitsModifier) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Integer, {}); + + builder.setUseIfNotExists(true); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE IF NOT EXISTS test(id INTEGER) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, TemporaryTable) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Integer, {}); + + builder.setUseTemporaryTable(true); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TEMPORARY TABLE test(id INTEGER) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyWithoutColumn) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {ForeignKey{"otherTable", ""}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER REFERENCES otherTable) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyWithColumn) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn)) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyUpdateNoAction) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn)) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyUpdateRestrict) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Restrict}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE " + "RESTRICT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyUpdateSetNull) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetNull}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " + "NULL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyUpdateSetDefault) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::SetDefault}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " + "DEFAULT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyUpdateCascade) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", ForeignKeyAction::Cascade}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE " + "CASCADE) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteNoAction) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {ForeignKey{"otherTable", "otherColumn"}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn)) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteRestrict) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Restrict}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE " + "RESTRICT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteSetNull) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetNull}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET " + "NULL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteSetDefault) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::SetDefault}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE SET " + "DEFAULT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteCascade) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", "otherColumn", {}, ForeignKeyAction::Cascade}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON DELETE " + "CASCADE) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeleteAndUpdateAction) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", + "otherColumn", + ForeignKeyAction::SetDefault, + ForeignKeyAction::Cascade}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " + "DEFAULT ON DELETE CASCADE) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, ForeignKeyDeferred) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {ForeignKey{"otherTable", + "otherColumn", + ForeignKeyAction::SetDefault, + ForeignKeyAction::Cascade, + Enforment::Deferred}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER REFERENCES otherTable(otherColumn) ON UPDATE SET " + "DEFAULT ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, NotNullConstraint) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {Sqlite::NotNull{}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER NOT NULL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, NotNullAndUniqueConstraint) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {Sqlite::Unique{}, Sqlite::NotNull{}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER UNIQUE NOT NULL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, Check) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Text, {Sqlite::Check{"id != ''"}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT CHECK (id != '')) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, DefaultValueInt) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Integer, {Sqlite::DefaultValue{1LL}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id INTEGER DEFAULT 1) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, DefaultValueFloat) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Real, {Sqlite::DefaultValue{1.1}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id REAL DEFAULT 1.100000) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, DefaultValueString) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Text, {Sqlite::DefaultValue{"foo"}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT DEFAULT 'foo') STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, DefaultExpression) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {Sqlite::DefaultExpression{"SELECT name FROM foo WHERE id=?"}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER DEFAULT (SELECT name FROM foo WHERE id=?)) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, Collation) +{ + builder.setTableName("test"); + + builder.addColumn("id", StrictColumnType::Text, {Sqlite::Collate{"unicode"}}); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(id TEXT COLLATE unicode) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, GeneratedAlwaysStored) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Text, + {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?", + Sqlite::GeneratedAlwaysStorage::Stored}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) " + "STORED) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, GeneratedAlwaysVirtual) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Text, + {Sqlite::GeneratedAlways{"SELECT name FROM foo WHERE id=?", + Sqlite::GeneratedAlwaysStorage::Virtual}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id TEXT GENERATED ALWAYS AS (SELECT name FROM foo WHERE id=?) " + "VIRTUAL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, PrimaryKeyAutoincrement) +{ + builder.setTableName("test"); + + builder.addColumn("id", + StrictColumnType::Integer, + {Sqlite::PrimaryKey{Sqlite::AutoIncrement::Yes}}); + + ASSERT_THAT(builder.sqlStatement(), + "CREATE TABLE test(id INTEGER PRIMARY KEY AUTOINCREMENT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, BlobType) +{ + builder.setTableName("test"); + + builder.addColumn("data", StrictColumnType::Blob); + + ASSERT_THAT(builder.sqlStatement(), "CREATE TABLE test(data BLOB) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, TablePrimaryKeyConstaint) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Integer); + builder.addColumn("text", StrictColumnType::Text); + + builder.addConstraint(Sqlite::TablePrimaryKey{{"id, text"}}); + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER, text TEXT, PRIMARY KEY(id, text)) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, AnyColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Any); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id ANY) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, IntColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Int); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id INT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, IntegerColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Integer); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id INTEGER) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, RealColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Real); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id REAL) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, TextColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Text); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id TEXT) STRICT"); +} + +TEST_F(CreateStrictTableSqlStatementBuilder, BlobColumnTypeStringConversion) +{ + builder.setTableName("test"); + builder.addColumn("id", StrictColumnType::Blob); + + auto statement = builder.sqlStatement(); + + ASSERT_THAT(statement, "CREATE TABLE test(id BLOB) STRICT"); +} + } // namespace diff --git a/tests/unit/unittest/imagecachestorage-test.cpp b/tests/unit/unittest/imagecachestorage-test.cpp index 50995e6c407..73098c8cd5b 100644 --- a/tests/unit/unittest/imagecachestorage-test.cpp +++ b/tests/unit/unittest/imagecachestorage-test.cpp @@ -55,17 +55,19 @@ MATCHER_P2(IsIconEntry, class ImageCacheStorageTest : public testing::Test { protected: - template - using ReadStatement = QmlDesigner::ImageCacheStorage::ReadStatement; - using WriteStatement = QmlDesigner::ImageCacheStorage::WriteStatement; + template + using ReadStatement = QmlDesigner::ImageCacheStorage< + SqliteDatabaseMock>::ReadStatement; + template + using WriteStatement = QmlDesigner::ImageCacheStorage::WriteStatement; NiceMock databaseMock; QmlDesigner::ImageCacheStorage storage{databaseMock}; - ReadStatement<1> &selectImageStatement = storage.selectImageStatement; - ReadStatement<1> &selectSmallImageStatement = storage.selectSmallImageStatement; - ReadStatement<1> &selectIconStatement = storage.selectIconStatement; - WriteStatement &upsertImageStatement = storage.upsertImageStatement; - WriteStatement &upsertIconStatement = storage.upsertIconStatement; + ReadStatement<1, 2> &selectImageStatement = storage.selectImageStatement; + ReadStatement<1, 2> &selectSmallImageStatement = storage.selectSmallImageStatement; + ReadStatement<1, 2> &selectIconStatement = storage.selectIconStatement; + WriteStatement<4> &upsertImageStatement = storage.upsertImageStatement; + WriteStatement<3> &upsertIconStatement = storage.upsertIconStatement; QImage image1{10, 10, QImage::Format_ARGB32}; QImage smallImage1{10, 10, QImage::Format_ARGB32}; QIcon icon1{QPixmap::fromImage(image1)}; diff --git a/tests/unit/unittest/listmodeleditor-test.cpp b/tests/unit/unittest/listmodeleditor-test.cpp index 370472d11ed..350944e612a 100644 --- a/tests/unit/unittest/listmodeleditor-test.cpp +++ b/tests/unit/unittest/listmodeleditor-test.cpp @@ -1347,8 +1347,8 @@ TEST_F(ListModelEditor, AddBooleanProperties) model.setValue(0, 1, true); ASSERT_THAT(properties(), - ElementsAre(UnorderedElementsAre(IsVariantProperty("name", "foo"), - IsVariantProperty("value", true), + ElementsAre(UnorderedElementsAre(IsVariantProperty("name", true), + IsVariantProperty("value", 1), IsVariantProperty("value2", 42)), UnorderedElementsAre(IsVariantProperty("image", "pic.png"), IsVariantProperty("name", "bar"), diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h index a05c160371f..82ddc187a5f 100644 --- a/tests/unit/unittest/mocksqlitestatement.h +++ b/tests/unit/unittest/mocksqlitestatement.h @@ -34,6 +34,8 @@ class BaseMockSqliteStatement { public: + using Database = SqliteDatabaseMock; + BaseMockSqliteStatement() = default; BaseMockSqliteStatement(SqliteDatabaseMock &databaseMock) : m_databaseMock{&databaseMock} @@ -64,6 +66,7 @@ public: MOCK_METHOD1(prepare, void(Utils::SmallStringView sqlStatement)); MOCK_METHOD1(checkColumnCount, void(int)); + MOCK_METHOD1(checkBindingParameterCount, void(int)); MOCK_CONST_METHOD0(isReadOnlyStatement, bool()); @@ -109,11 +112,11 @@ Utils::PathString BaseMockSqliteStatement::fetchValue(int col return fetchPathStringValue(column); } -template +template class MockSqliteStatement - : public Sqlite::StatementImplementation, ResultCount> + : public Sqlite::StatementImplementation { - using Base = Sqlite::StatementImplementation, ResultCount>; + using Base = Sqlite::StatementImplementation; public: explicit MockSqliteStatement(SqliteDatabaseMock &databaseMock) diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp index 1e2cc0bd068..58a9886b7f7 100644 --- a/tests/unit/unittest/projectstorage-test.cpp +++ b/tests/unit/unittest/projectstorage-test.cpp @@ -3843,4 +3843,30 @@ TEST_F(ProjectStorage, FetchProjectDatasByModuleId) ASSERT_THAT(projectData, UnorderedElementsAre(projectData1, projectData2)); } +TEST_F(ProjectStorage, ExcludeExportedTypes) +{ + auto package{createSimpleSynchronizationPackage()}; + storage.synchronize(package); + package.types[0].exportedTypes.clear(); + package.types[0].changeLevel = Storage::ChangeLevel::ExcludeExportedTypes; + + storage.synchronize(std::move(package)); + + ASSERT_THAT( + storage.fetchTypes(), + UnorderedElementsAre( + AllOf(IsStorageType(sourceId2, "QObject", TypeId{}, TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qmlModuleId, "Object"), + IsExportedType(qmlModuleId, "Obj"), + IsExportedType(qmlNativeModuleId, "QObject")))), + AllOf(IsStorageType(sourceId1, + "QQuickItem", + fetchTypeId(sourceId2, "QObject"), + TypeAccessSemantics::Reference), + Field(&Storage::Type::exportedTypes, + UnorderedElementsAre(IsExportedType(qtQuickModuleId, "Item"), + IsExportedType(qtQuickNativeModuleId, "QQuickItem")))))); +} + } // namespace diff --git a/tests/unit/unittest/sqlitealgorithms-test.cpp b/tests/unit/unittest/sqlitealgorithms-test.cpp index 462814a67df..6a494696615 100644 --- a/tests/unit/unittest/sqlitealgorithms-test.cpp +++ b/tests/unit/unittest/sqlitealgorithms-test.cpp @@ -115,15 +115,16 @@ public: protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; - Sqlite::ImmediateTransaction transaction{database}; + Sqlite::ImmediateTransaction transaction{database}; Initializer initializer{database}; Sqlite::ReadStatement<2> selectViewsStatement{"SELECT key, value FROM data ORDER BY key", database}; Sqlite::ReadStatement<2> selectValuesStatement{"SELECT key, value FROM data ORDER BY key", database}; - Sqlite::WriteStatement insertStatement{"INSERT INTO data(key, value) VALUES (?1, ?2)", database}; - Sqlite::WriteStatement updateStatement{"UPDATE data SET value = ?2 WHERE key=?1", database}; - Sqlite::WriteStatement deleteStatement{"DELETE FROM data WHERE key=?", database}; + Sqlite::WriteStatement<2> insertStatement{"INSERT INTO data(key, value) VALUES (?1, ?2)", + database}; + Sqlite::WriteStatement<2> updateStatement{"UPDATE data SET value = ?2 WHERE key=?1", database}; + Sqlite::WriteStatement<1> deleteStatement{"DELETE FROM data WHERE key=?", database}; std::function insert{ [&](const KeyValue &keyValue) { insertStatement.write(keyValue.key, keyValue.value); }}; std::function update{ diff --git a/tests/unit/unittest/sqlitecolumn-test.cpp b/tests/unit/unittest/sqlitecolumn-test.cpp index 9753457c947..865726d54f7 100644 --- a/tests/unit/unittest/sqlitecolumn-test.cpp +++ b/tests/unit/unittest/sqlitecolumn-test.cpp @@ -31,18 +31,19 @@ namespace { using Sqlite::ColumnType; using Sqlite::ConstraintType; -using Sqlite::JournalMode; -using Sqlite::OpenMode; -using Column = Sqlite::Column; using Sqlite::Enforment; using Sqlite::ForeignKey; using Sqlite::ForeignKeyAction; -using Sqlite::SqliteColumns; +using Sqlite::JournalMode; +using Sqlite::OpenMode; +using Sqlite::StrictColumnType; class SqliteColumn : public ::testing::Test { protected: - Sqlite::Column column; + using Column = Sqlite::Column; + + Column column; }; TEST_F(SqliteColumn, DefaultConstruct) @@ -50,7 +51,7 @@ TEST_F(SqliteColumn, DefaultConstruct) ASSERT_THAT(column, AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), - Field(&Column::type, ColumnType::Numeric), + Field(&Column::type, ColumnType::None), Field(&Column::constraints, IsEmpty()))); } @@ -66,20 +67,20 @@ TEST_F(SqliteColumn, Clear) ASSERT_THAT(column, AllOf(Field(&Column::name, IsEmpty()), Field(&Column::tableName, IsEmpty()), - Field(&Column::type, ColumnType::Numeric), + Field(&Column::type, ColumnType::None), Field(&Column::constraints, IsEmpty()))); } TEST_F(SqliteColumn, Constructor) { - column = Sqlite::Column{"table", - "column", - ColumnType::Text, - {ForeignKey{"referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}}}; + column = Column{"table", + "column", + ColumnType::Text, + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), @@ -96,14 +97,14 @@ TEST_F(SqliteColumn, Constructor) TEST_F(SqliteColumn, FlatConstructor) { - column = Sqlite::Column{"table", - "column", - ColumnType::Text, - {ForeignKey{"referencedTable", - "referencedColumn", - ForeignKeyAction::SetNull, - ForeignKeyAction::Cascade, - Enforment::Deferred}}}; + column = Column{"table", + "column", + ColumnType::Text, + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; ASSERT_THAT(column, AllOf(Field(&Column::name, Eq("column")), @@ -118,4 +119,85 @@ TEST_F(SqliteColumn, FlatConstructor) Field(&ForeignKey::enforcement, Enforment::Deferred))))))); } +class SqliteStrictColumn : public ::testing::Test +{ +protected: + using Column = Sqlite::StrictColumn; + + Column column; +}; + +TEST_F(SqliteStrictColumn, DefaultConstruct) +{ + ASSERT_THAT(column, + AllOf(Field(&Column::name, IsEmpty()), + Field(&Column::tableName, IsEmpty()), + Field(&Column::type, StrictColumnType::Any), + Field(&Column::constraints, IsEmpty()))); +} + +TEST_F(SqliteStrictColumn, Clear) +{ + column.name = "foo"; + column.name = "foo"; + column.type = StrictColumnType::Text; + column.constraints = {Sqlite::PrimaryKey{}}; + + column.clear(); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, IsEmpty()), + Field(&Column::tableName, IsEmpty()), + Field(&Column::type, StrictColumnType::Any), + Field(&Column::constraints, IsEmpty()))); +} + +TEST_F(SqliteStrictColumn, Constructor) +{ + column = Column{"table", + "column", + StrictColumnType::Text, + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("column")), + Field(&Column::tableName, Eq("table")), + Field(&Column::type, StrictColumnType::Text), + Field(&Column::constraints, + ElementsAre(VariantWith( + AllOf(Field(&ForeignKey::table, Eq("referencedTable")), + Field(&ForeignKey::column, Eq("referencedColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); +} + +TEST_F(SqliteStrictColumn, FlatConstructor) +{ + column = Column{"table", + "column", + StrictColumnType::Text, + {ForeignKey{"referencedTable", + "referencedColumn", + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred}}}; + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("column")), + Field(&Column::tableName, Eq("table")), + Field(&Column::type, StrictColumnType::Text), + Field(&Column::constraints, + ElementsAre(VariantWith( + AllOf(Field(&ForeignKey::table, Eq("referencedTable")), + Field(&ForeignKey::column, Eq("referencedColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); +} + } // namespace diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index 4c05fcd9b07..92cdf01961c 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -196,7 +196,7 @@ TEST_F(SqliteDatabase, DatabaseIsNotInitializedIfDatabasePathDoesNotExistAtOpeni TEST_F(SqliteDatabase, GetChangesCount) { - Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database); statement.write(42); ASSERT_THAT(database.changesCount(), 1); @@ -204,7 +204,7 @@ TEST_F(SqliteDatabase, GetChangesCount) TEST_F(SqliteDatabase, GetTotalChangesCount) { - Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database); statement.write(42); ASSERT_THAT(database.lastInsertedRowId(), 1); @@ -212,7 +212,7 @@ TEST_F(SqliteDatabase, GetTotalChangesCount) TEST_F(SqliteDatabase, GetLastInsertedRowId) { - Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + Sqlite::WriteStatement<1> statement("INSERT INTO test(name) VALUES (?)", database); statement.write(42); ASSERT_THAT(database.lastInsertedRowId(), 1); @@ -265,7 +265,7 @@ TEST_F(SqliteDatabase, SetUpdateHookSet) database.setUpdateHook(this, updateHookCallback); EXPECT_CALL(callbackMock, Call(_, _, _, _)); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, SetNullUpdateHook) @@ -275,7 +275,7 @@ TEST_F(SqliteDatabase, SetNullUpdateHook) database.setUpdateHook(nullptr, nullptr); EXPECT_CALL(callbackMock, Call(_, _, _, _)).Times(0); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, ResetUpdateHook) @@ -285,12 +285,12 @@ TEST_F(SqliteDatabase, ResetUpdateHook) database.resetUpdateHook(); EXPECT_CALL(callbackMock, Call(_, _, _, _)).Times(0); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, DeleteUpdateHookCall) { - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); database.setUpdateHook(this, updateHookCallback); EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Delete), _, _, _)); @@ -304,7 +304,7 @@ TEST_F(SqliteDatabase, InsertUpdateHookCall) EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Insert), _, _, _)); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, UpdateUpdateHookCall) @@ -313,7 +313,7 @@ TEST_F(SqliteDatabase, UpdateUpdateHookCall) EXPECT_CALL(callbackMock, Call(Eq(Sqlite::ChangeType::Insert), _, _, _)); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, RowIdUpdateHookCall) @@ -322,7 +322,7 @@ TEST_F(SqliteDatabase, RowIdUpdateHookCall) EXPECT_CALL(callbackMock, Call(_, _, _, Eq(42))); - Sqlite::WriteStatement("INSERT INTO test(rowid, name) VALUES (?,?)", database).write(42, "foo"); + Sqlite::WriteStatement<2>("INSERT INTO test(rowid, name) VALUES (?,?)", database).write(42, "foo"); } TEST_F(SqliteDatabase, DatabaseUpdateHookCall) @@ -331,7 +331,7 @@ TEST_F(SqliteDatabase, DatabaseUpdateHookCall) EXPECT_CALL(callbackMock, Call(_, StrEq("main"), _, _)); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, TableUpdateHookCall) @@ -340,20 +340,21 @@ TEST_F(SqliteDatabase, TableUpdateHookCall) EXPECT_CALL(callbackMock, Call(_, _, StrEq("test"), _)); - Sqlite::WriteStatement("INSERT INTO test(name) VALUES (?)", database).write(42); + Sqlite::WriteStatement<1>("INSERT INTO test(name) VALUES (?)", database).write(42); } TEST_F(SqliteDatabase, SessionsCommit) { database.setAttachedTables({"test"}); - Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo"); + Sqlite::WriteStatement<2>("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo"); database.unlock(); Sqlite::ImmediateSessionTransaction transaction{database}; - Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar"); + Sqlite::WriteStatement<2>("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar"); transaction.commit(); database.lock(); - Sqlite::WriteStatement("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database).write(2, "hoo"); + Sqlite::WriteStatement<2>("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database) + .write(2, "hoo"); database.applyAndUpdateSessions(); ASSERT_THAT(names(), ElementsAre("foo", "bar")); @@ -362,15 +363,16 @@ TEST_F(SqliteDatabase, SessionsCommit) TEST_F(SqliteDatabase, SessionsRollback) { database.setAttachedTables({"test"}); - Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo"); + Sqlite::WriteStatement<2>("INSERT INTO test(id, name) VALUES (?,?)", database).write(1, "foo"); database.unlock(); { Sqlite::ImmediateSessionTransaction transaction{database}; - Sqlite::WriteStatement("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar"); + Sqlite::WriteStatement<2>("INSERT INTO test(id, name) VALUES (?,?)", database).write(2, "bar"); } database.lock(); - Sqlite::WriteStatement("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database).write(2, "hoo"); + Sqlite::WriteStatement<2>("INSERT OR REPLACE INTO test(id, name) VALUES (?,?)", database) + .write(2, "hoo"); database.applyAndUpdateSessions(); ASSERT_THAT(names(), ElementsAre("foo", "hoo")); diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h index 3314dd3a651..4ea83a46b40 100644 --- a/tests/unit/unittest/sqlitedatabasemock.h +++ b/tests/unit/unittest/sqlitedatabasemock.h @@ -41,11 +41,12 @@ class SqliteDatabaseMock : public SqliteTransactionBackendMock, public Sqlite::DatabaseInterface { public: - template - using ReadStatement = NiceMock>; - using WriteStatement = NiceMock; - template - using ReadWriteStatement = NiceMock>; + template + using ReadStatement = NiceMock>; + template + using WriteStatement = NiceMock>; + template + using ReadWriteStatement = NiceMock>; MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement), ()); diff --git a/tests/unit/unittest/sqlitereadstatementmock.h b/tests/unit/unittest/sqlitereadstatementmock.h index 9bde954ac91..225c83d5c95 100644 --- a/tests/unit/unittest/sqlitereadstatementmock.h +++ b/tests/unit/unittest/sqlitereadstatementmock.h @@ -273,7 +273,7 @@ public: Utils::SmallString sqlStatement; }; -template +template class SqliteReadStatementMock : public SqliteReadStatementMockBase { public: diff --git a/tests/unit/unittest/sqlitereadwritestatementmock.h b/tests/unit/unittest/sqlitereadwritestatementmock.h index 563731c02d4..5b85a67b681 100644 --- a/tests/unit/unittest/sqlitereadwritestatementmock.h +++ b/tests/unit/unittest/sqlitereadwritestatementmock.h @@ -87,7 +87,7 @@ public: Utils::SmallString sqlStatement; }; -template +template class SqliteReadWriteStatementMock : public SqliteReadWriteStatementMockBase { public: diff --git a/tests/unit/unittest/sqlitesessions-test.cpp b/tests/unit/unittest/sqlitesessions-test.cpp index 296dd0cb743..9288f3a2a3b 100644 --- a/tests/unit/unittest/sqlitesessions-test.cpp +++ b/tests/unit/unittest/sqlitesessions-test.cpp @@ -138,18 +138,19 @@ protected: "INITIALLY DEFERRED, tag NUMERIC)", database}; Sqlite::Sessions sessions{database, "main", "testsessions"}; - Sqlite::WriteStatement insertData{"INSERT INTO data(name, number, value) VALUES (?1, ?2, ?3) " - "ON CONFLICT (name) DO UPDATE SET (number, value) = (?2, ?3)", - database}; - Sqlite::WriteStatement insertOneDatum{"INSERT INTO data(value, name) VALUES (?1, ?2) " - "ON CONFLICT (name) DO UPDATE SET (value) = (?2)", - database}; - Sqlite::WriteStatement updateNumber{"UPDATE data SET number = ?002 WHERE name=?001", database}; - Sqlite::WriteStatement updateValue{"UPDATE data SET value = ?002 WHERE name=?001", database}; - Sqlite::WriteStatement deleteData{"DELETE FROM data WHERE name=?", database}; - Sqlite::WriteStatement deleteTag{ + Sqlite::WriteStatement<3> insertData{ + "INSERT INTO data(name, number, value) VALUES (?1, ?2, ?3) " + "ON CONFLICT (name) DO UPDATE SET (number, value) = (?2, ?3)", + database}; + Sqlite::WriteStatement<2> insertOneDatum{"INSERT INTO data(value, name) VALUES (?1, ?2) " + "ON CONFLICT (name) DO UPDATE SET (value) = (?2)", + database}; + Sqlite::WriteStatement<2> updateNumber{"UPDATE data SET number = ?2 WHERE name=?1", database}; + Sqlite::WriteStatement<2> updateValue{"UPDATE data SET value = ?2 WHERE name=?1", database}; + Sqlite::WriteStatement<1> deleteData{"DELETE FROM data WHERE name=?", database}; + Sqlite::WriteStatement<1> deleteTag{ "DELETE FROM tags WHERE dataId=(SELECT id FROM data WHERE name=?)", database}; - Sqlite::WriteStatement insertTag{ + Sqlite::WriteStatement<2> insertTag{ "INSERT INTO tags(dataId, tag) VALUES ((SELECT id FROM data WHERE name=?1), ?2) ", database}; Sqlite::ReadStatement<3> selectData{"SELECT name, number, value FROM data", database}; Sqlite::ReadStatement<2> selectTags{ @@ -599,7 +600,7 @@ TEST_F(SqliteSessions, ConvertAllValueTypesInChangeSet) TEST_F(SqliteSessions, InsertOneValueChangeSet) { sessions.create(); - insertOneDatum.write("foo"); + insertOneDatum.write("foo", Sqlite::NullValue{}); sessions.commit(); auto changeSets = sessions.changeSets(); auto &&changeSet = changeSets.front(); @@ -669,7 +670,7 @@ TEST_F(SqliteSessions, EmptyChangeSet) TEST_F(SqliteSessions, AccessInsertOneValueChangeSet) { sessions.create(); - insertOneDatum.write("foo"); + insertOneDatum.write("foo", Sqlite::NullValue{}); sessions.commit(); auto changeSets = sessions.changeSets(); auto &&changeSet = changeSets.front(); diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index ea37b502221..ff5348585a4 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -54,7 +54,7 @@ using Sqlite::Value; using Sqlite::WriteStatement; template -bool compareValue(SqliteTestStatement &statement, Type value, int column) +bool compareValue(SqliteTestStatement<2, 1> &statement, Type value, int column) { if constexpr (std::is_convertible_v && !std::is_same_v) return statement.fetchLongLongValue(column) == value; @@ -77,7 +77,7 @@ MATCHER_P3(HasValues, value1, value2, rowid, { Database &database = arg.database(); - SqliteTestStatement statement("SELECT name, number FROM test WHERE rowid=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE rowid=?", database); statement.bind(1, rowid); statement.next(); @@ -89,7 +89,7 @@ MATCHER_P(HasNullValues, rowid, std::string(negation ? "isn't null" : "is null") { Database &database = arg.database(); - SqliteTestStatement statement("SELECT name, number FROM test WHERE rowid=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE rowid=?", database); statement.bind(1, rowid); statement.next(); @@ -172,7 +172,7 @@ TEST_F(SqliteStatement, ThrowsNotReadonlySqlStatementForWritableSqlStatementInRe TEST_F(SqliteStatement, CountRows) { - SqliteTestStatement statement("SELECT * FROM test", database); + SqliteTestStatement<3> statement("SELECT * FROM test", database); int nextCount = 0; while (statement.next()) ++nextCount; @@ -184,7 +184,7 @@ TEST_F(SqliteStatement, CountRows) TEST_F(SqliteStatement, Value) { - SqliteTestStatement statement("SELECT name, number, value FROM test ORDER BY name", database); + SqliteTestStatement<3> statement("SELECT name, number, value FROM test ORDER BY name", database); statement.next(); statement.next(); @@ -235,7 +235,7 @@ TEST_F(SqliteStatement, ToStringValue) TEST_F(SqliteStatement, BindNull) { database.execute("INSERT INTO test VALUES (NULL, 323, 344)"); - SqliteTestStatement statement("SELECT name, number FROM test WHERE name IS ?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE name IS ?", database); statement.bind(1, Sqlite::NullValue{}); statement.next(); @@ -246,8 +246,7 @@ TEST_F(SqliteStatement, BindNull) TEST_F(SqliteStatement, BindString) { - - SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE name=?", database); statement.bind(1, Utils::SmallStringView("foo")); statement.next(); @@ -258,7 +257,7 @@ TEST_F(SqliteStatement, BindString) TEST_F(SqliteStatement, BindInteger) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, 40); statement.next(); @@ -268,7 +267,7 @@ TEST_F(SqliteStatement, BindInteger) TEST_F(SqliteStatement, BindLongInteger) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, int64_t(40)); statement.next(); @@ -278,7 +277,7 @@ TEST_F(SqliteStatement, BindLongInteger) TEST_F(SqliteStatement, BindDouble) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, 23.3); statement.next(); @@ -288,7 +287,7 @@ TEST_F(SqliteStatement, BindDouble) TEST_F(SqliteStatement, BindPointer) { - SqliteTestStatement statement("SELECT value FROM carray(?, 5, 'int64')", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?, 5, 'int64')", database); std::vector values{1, 1, 2, 3, 5}; statement.bind(1, values.data()); @@ -299,7 +298,7 @@ TEST_F(SqliteStatement, BindPointer) TEST_F(SqliteStatement, BindIntCarray) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3, 10, 20, 33, 55}; statement.bind(1, values); @@ -313,7 +312,7 @@ TEST_F(SqliteStatement, BindIntCarray) TEST_F(SqliteStatement, BindLongLongCarray) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3, 10, 20, 33, 55}; statement.bind(1, values); @@ -327,7 +326,7 @@ TEST_F(SqliteStatement, BindLongLongCarray) TEST_F(SqliteStatement, BindDoubleCarray) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3.3, 10.2, 20.54, 33.21, 55}; statement.bind(1, values); @@ -341,7 +340,7 @@ TEST_F(SqliteStatement, BindDoubleCarray) TEST_F(SqliteStatement, BindTextCarray) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{"yi", "er", "san", "se", "wu"}; statement.bind(1, values); @@ -355,7 +354,7 @@ TEST_F(SqliteStatement, BindTextCarray) TEST_F(SqliteStatement, BindBlob) { - SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + SqliteTestStatement<1, 1> statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); const unsigned char chars[] = "aaafdfdlll"; auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; @@ -368,7 +367,7 @@ TEST_F(SqliteStatement, BindBlob) TEST_F(SqliteStatement, BindEmptyBlob) { - SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + SqliteTestStatement<1, 1> statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); Sqlite::BlobView bytes; statement.bind(1, bytes); @@ -379,56 +378,56 @@ TEST_F(SqliteStatement, BindEmptyBlob) TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundInt) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(0, 40), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBoundNull) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(0, Sqlite::NullValue{}), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundLongLong) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, 40LL), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringView) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, "foo"), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundStringFloat) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, 2.), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundPointer) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, nullptr), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundValue) { - SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + SqliteTestStatement<2, 1> statement("SELECT name, number FROM test WHERE number=$1", database); ASSERT_THROW(statement.bind(2, Sqlite::Value{1}), Sqlite::BindingIndexIsOutOfRange); } TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob) { - SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + SqliteTestStatement<1, 1> statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); Sqlite::BlobView bytes{QByteArray{"XXX"}}; ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange); @@ -436,7 +435,7 @@ TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob TEST_F(SqliteStatement, BindValues) { - SqliteTestStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + SqliteTestStatement<0, 3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.bindValues("see", 7.23, 1); statement.execute(); @@ -446,7 +445,7 @@ TEST_F(SqliteStatement, BindValues) TEST_F(SqliteStatement, BindNullValues) { - SqliteTestStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + SqliteTestStatement<0, 3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.bindValues(Sqlite::NullValue{}, Sqlite::Value{}, 1); statement.execute(); @@ -456,7 +455,7 @@ TEST_F(SqliteStatement, BindNullValues) TEST_F(SqliteStatement, WriteValues) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write("see", 7.23, 1); @@ -465,58 +464,57 @@ TEST_F(SqliteStatement, WriteValues) TEST_F(SqliteStatement, WritePointerValues) { - SqliteTestStatement statement("SELECT value FROM carray(?, ?, 'int64')", database); + SqliteTestStatement<1, 2> statement("SELECT value FROM carray(?, ?, 'int64')", database); std::vector values{1, 1, 2, 3, 5}; - statement.write(values.data(), int(values.size())); + auto results = statement.values(5, values.data(), int(values.size())); - ASSERT_THAT(statement.template values(5), ElementsAre(1, 1, 2, 3, 5)); + ASSERT_THAT(results, ElementsAre(1, 1, 2, 3, 5)); } TEST_F(SqliteStatement, WriteIntCarrayValues) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3, 10, 20, 33, 55}; - statement.write(Utils::span(values)); + auto results = statement.values(5, Utils::span(values)); - ASSERT_THAT(statement.template values(5), ElementsAre(3, 10, 20, 33, 55)); + ASSERT_THAT(results, ElementsAre(3, 10, 20, 33, 55)); } TEST_F(SqliteStatement, WriteLongLongCarrayValues) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3, 10, 20, 33, 55}; - statement.write(Utils::span(values)); + auto results = statement.values(5, Utils::span(values)); - ASSERT_THAT(statement.template values(5), ElementsAre(3, 10, 20, 33, 55)); + ASSERT_THAT(results, ElementsAre(3, 10, 20, 33, 55)); } TEST_F(SqliteStatement, WriteDoubleCarrayValues) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{3.3, 10.2, 20.54, 33.21, 55}; - statement.write(Utils::span(values)); + auto results = statement.values(5, Utils::span(values)); - ASSERT_THAT(statement.template values(5), ElementsAre(3.3, 10.2, 20.54, 33.21, 55)); + ASSERT_THAT(results, ElementsAre(3.3, 10.2, 20.54, 33.21, 55)); } TEST_F(SqliteStatement, WriteTextCarrayValues) { - SqliteTestStatement statement("SELECT value FROM carray(?)", database); + SqliteTestStatement<1, 1> statement("SELECT value FROM carray(?)", database); std::vector values{"yi", "er", "san", "se", "wu"}; - statement.write(Utils::span(values)); + auto results = statement.values(5, Utils::span(values)); - ASSERT_THAT(statement.template values(5), - ElementsAre("yi", "er", "san", "se", "wu")); + ASSERT_THAT(results, ElementsAre("yi", "er", "san", "se", "wu")); } TEST_F(SqliteStatement, WriteNullValues) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write(1, 1, 1); statement.write(Sqlite::NullValue{}, Sqlite::Value{}, 1); @@ -526,7 +524,7 @@ TEST_F(SqliteStatement, WriteNullValues) TEST_F(SqliteStatement, WriteSqliteIntegerValue) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write(1, 1, 1); statement.write("see", Sqlite::Value{33}, 1); @@ -536,7 +534,7 @@ TEST_F(SqliteStatement, WriteSqliteIntegerValue) TEST_F(SqliteStatement, WriteSqliteDoubeValue) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write("see", Value{7.23}, Value{1}); @@ -545,7 +543,7 @@ TEST_F(SqliteStatement, WriteSqliteDoubeValue) TEST_F(SqliteStatement, WriteSqliteStringValue) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write("see", Value{"foo"}, Value{1}); @@ -554,8 +552,8 @@ TEST_F(SqliteStatement, WriteSqliteStringValue) TEST_F(SqliteStatement, WriteSqliteBlobValue) { - SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); - SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); + SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('blob', 40, ?)", database); + SqliteTestStatement<1, 0> readStatement("SELECT value FROM test WHERE name = 'blob'", database); const unsigned char chars[] = "aaafdfdlll"; auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; @@ -568,7 +566,7 @@ TEST_F(SqliteStatement, WriteSqliteBlobValue) TEST_F(SqliteStatement, WriteNullValueView) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write(1, 1, 1); statement.write(Sqlite::NullValue{}, Sqlite::ValueView::create(Sqlite::NullValue{}), 1); @@ -578,7 +576,7 @@ TEST_F(SqliteStatement, WriteNullValueView) TEST_F(SqliteStatement, WriteSqliteIntegerValueView) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write(1, 1, 1); statement.write("see", Sqlite::ValueView::create(33), 1); @@ -588,7 +586,7 @@ TEST_F(SqliteStatement, WriteSqliteIntegerValueView) TEST_F(SqliteStatement, WriteSqliteDoubeValueView) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write("see", Sqlite::ValueView::create(7.23), 1); @@ -597,7 +595,7 @@ TEST_F(SqliteStatement, WriteSqliteDoubeValueView) TEST_F(SqliteStatement, WriteSqliteStringValueView) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + WriteStatement<3> statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.write("see", Sqlite::ValueView::create("foo"), 1); @@ -606,8 +604,8 @@ TEST_F(SqliteStatement, WriteSqliteStringValueView) TEST_F(SqliteStatement, WriteSqliteBlobValueView) { - SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); - SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); + SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('blob', 40, ?)", database); + SqliteTestStatement<1, 0> readStatement("SELECT value FROM test WHERE name = 'blob'", database); const unsigned char chars[] = "aaafdfdlll"; auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; @@ -620,7 +618,7 @@ TEST_F(SqliteStatement, WriteSqliteBlobValueView) TEST_F(SqliteStatement, WriteEmptyBlobs) { - SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); + SqliteTestStatement<1, 1> statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); Sqlite::BlobView bytes; @@ -631,8 +629,8 @@ TEST_F(SqliteStatement, WriteEmptyBlobs) TEST_F(SqliteStatement, EmptyBlobsAreNull) { - SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT ifnull(blob, 1) FROM T", - database); + SqliteTestStatement<1, 1> statement( + "WITH T(blob) AS (VALUES (?)) SELECT ifnull(blob, 1) FROM T", database); Sqlite::BlobView bytes; @@ -643,8 +641,8 @@ TEST_F(SqliteStatement, EmptyBlobsAreNull) TEST_F(SqliteStatement, WriteBlobs) { - SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); - SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); + SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('blob', 40, ?)", database); + SqliteTestStatement<1, 0> readStatement("SELECT value FROM test WHERE name = 'blob'", database); const unsigned char chars[] = "aaafdfdlll"; auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; @@ -918,7 +916,7 @@ TEST_F(SqliteStatement, GetStructRangeWithTransactionWithoutArguments) TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes) { - ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database); + ReadStatement<1, 1> statement("SELECT name FROM test WHERE number=?", database); statement.values(3, 40); std::vector values = statement.values(3, 40); @@ -928,7 +926,7 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes) TEST_F(SqliteStatement, GetRangeForSingleOutputWithBindingMultipleTimes) { - ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database); + ReadStatement<1, 1> statement("SELECT name FROM test WHERE number=?", database); statement.values(3, 40); auto range = statement.range(40); @@ -939,7 +937,7 @@ TEST_F(SqliteStatement, GetRangeForSingleOutputWithBindingMultipleTimes) TEST_F(SqliteStatement, GetRangeWithTransactionForSingleOutputWithBindingMultipleTimes) { - ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database); + ReadStatement<1, 1> statement("SELECT name FROM test WHERE number=?", database); statement.values(3, 40); database.unlock(); @@ -953,7 +951,7 @@ TEST_F(SqliteStatement, GetRangeWithTransactionForSingleOutputWithBindingMultipl TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto values = statement.values(3, "bar", "blah", 1); @@ -964,7 +962,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) TEST_F(SqliteStatement, GetRangeForMultipleOutputValuesAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto range = statement.range("bar", "blah", 1); @@ -976,7 +974,7 @@ TEST_F(SqliteStatement, GetRangeForMultipleOutputValuesAndMultipleQueryValue) TEST_F(SqliteStatement, GetRangeWithTransactionForMultipleOutputValuesAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); database.unlock(); @@ -989,8 +987,8 @@ TEST_F(SqliteStatement, GetRangeWithTransactionForMultipleOutputValuesAndMultipl TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValueMultipleTimes) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); statement.values(3, "bar", "blah"); auto values = statement.values(3, "bar", "blah"); @@ -1001,8 +999,8 @@ TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValu TEST_F(SqliteStatement, CallGetRangeForMultipleOutputValuesAndMultipleQueryValueMultipleTimes) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); { auto range = statement.range("bar", "blah"); std::vector values1{range.begin(), range.end()}; @@ -1018,8 +1016,8 @@ TEST_F(SqliteStatement, CallGetRangeWithTransactionForMultipleOutputValuesAndMultipleQueryValueMultipleTimes) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); database.unlock(); std::vector values1 = toValues(statement.rangeWithTransaction("bar", "blah")); @@ -1031,7 +1029,7 @@ TEST_F(SqliteStatement, TEST_F(SqliteStatement, GetStructOutputValuesAndMultipleQueryValue) { - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto values = statement.values(3, "bar", "blah", 1); @@ -1081,8 +1079,8 @@ TEST_F(SqliteStatement, GetEmptyOptionalBlobValueForText) TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) { - ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", - database); + ReadStatement<1, 3> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", + database); auto value = statement.optionalValue("bar", "blah", 1); @@ -1091,7 +1089,7 @@ TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue) { - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto value = statement.optionalValue("bar", "blah", 1); @@ -1102,7 +1100,7 @@ TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOptionalTupleValueAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto value = statement.optionalValue("bar", "blah", 1); @@ -1112,7 +1110,7 @@ TEST_F(SqliteStatement, GetOptionalTupleValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOptionalValueCallsReset) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 1> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, reset()); @@ -1121,7 +1119,7 @@ TEST_F(SqliteStatement, GetOptionalValueCallsReset) TEST_F(SqliteStatement, GetOptionalValueCallsResetIfExceptionIsThrown) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 1> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(mockStatement, reset()); @@ -1131,8 +1129,8 @@ TEST_F(SqliteStatement, GetOptionalValueCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, GetSingleValueAndMultipleQueryValue) { - ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", - database); + ReadStatement<1, 3> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", + database); auto value = statement.value("bar", "blah", 1); @@ -1141,7 +1139,7 @@ TEST_F(SqliteStatement, GetSingleValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOutputValueAndMultipleQueryValue) { - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto value = statement.value("bar", "blah", 1); @@ -1152,7 +1150,7 @@ TEST_F(SqliteStatement, GetOutputValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetTupleValueAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement<3> statement( + ReadStatement<3, 3> statement( "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); auto value = statement.value("bar", "blah", 1); @@ -1166,7 +1164,7 @@ TEST_F(SqliteStatement, GetValueCallsReset) { int x = 0; }; - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 1> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, reset()); @@ -1179,7 +1177,7 @@ TEST_F(SqliteStatement, GetValueCallsResetIfExceptionIsThrown) { int x = 0; }; - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 1> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(mockStatement, reset()); @@ -1189,7 +1187,7 @@ TEST_F(SqliteStatement, GetValueCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsReset) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, reset()); @@ -1198,7 +1196,7 @@ TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsReset) TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsReset) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, reset()); @@ -1208,7 +1206,7 @@ TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsReset) TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCalls) { InSequence s; - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; EXPECT_CALL(databaseMock, lock()); EXPECT_CALL(databaseMock, deferredBegin()); @@ -1221,7 +1219,7 @@ TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCalls) TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsResetIfExceptionIsThrown) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(mockStatement, reset()); @@ -1231,7 +1229,7 @@ TEST_F(SqliteStatement, GetValuesWithoutArgumentsCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsResetIfExceptionIsThrown) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); auto range = mockStatement.range(); @@ -1243,7 +1241,7 @@ TEST_F(SqliteStatement, GetRangeWithoutArgumentsCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCallsResetIfExceptionIsThrown) { InSequence s; - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(databaseMock, lock()); @@ -1262,7 +1260,7 @@ TEST_F(SqliteStatement, GetRangeWithTransactionWithoutArgumentsCallsResetIfExcep TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsReset) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 2> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, reset()); @@ -1271,7 +1269,7 @@ TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsReset) TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsResetIfExceptionIsThrown) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 2> mockStatement{databaseMock}; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(mockStatement, reset()); @@ -1281,7 +1279,7 @@ TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsResetIfExceptionIsThrow TEST_F(SqliteStatement, ResetIfWriteIsThrowingException) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 1> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, bind(1, TypedEq("bar"))) .WillOnce(Throw(Sqlite::StatementIsBusy(""))); @@ -1292,7 +1290,7 @@ TEST_F(SqliteStatement, ResetIfWriteIsThrowingException) TEST_F(SqliteStatement, ResetIfExecuteThrowsException) { - MockSqliteStatement mockStatement{databaseMock}; + MockSqliteStatement<1, 0> mockStatement{databaseMock}; EXPECT_CALL(mockStatement, next()).WillOnce(Throw(Sqlite::StatementIsBusy(""))); EXPECT_CALL(mockStatement, reset()); @@ -1300,20 +1298,34 @@ TEST_F(SqliteStatement, ResetIfExecuteThrowsException) ASSERT_ANY_THROW(mockStatement.execute()); } -TEST_F(SqliteStatement, ReadStatementThrowsColumnCountDoesNotMatch) +TEST_F(SqliteStatement, ReadStatementThrowsWrongColumnCount) { - MockFunction callbackMock; - ASSERT_THROW(ReadStatement<1> statement("SELECT name, number FROM test", database), - Sqlite::ColumnCountDoesNotMatch); + Sqlite::WrongColumnCount); } -TEST_F(SqliteStatement, ReadWriteStatementThrowsColumnCountDoesNotMatch) +TEST_F(SqliteStatement, ReadWriteStatementThrowsWrongColumnCount) { - MockFunction callbackMock; - ASSERT_THROW(ReadWriteStatement<1> statement("SELECT name, number FROM test", database), - Sqlite::ColumnCountDoesNotMatch); + Sqlite::WrongColumnCount); +} + +TEST_F(SqliteStatement, WriteStatementThrowsWrongBindingParameterCount) +{ + ASSERT_THROW(WriteStatement<1>("INSERT INTO test(name, number) VALUES(?1, ?2)", database), + Sqlite::WrongBindingParameterCount); +} + +TEST_F(SqliteStatement, ReadWriteStatementThrowsWrongBindingParameterCount) +{ + ASSERT_THROW((ReadWriteStatement<0, 1>("INSERT INTO test(name, number) VALUES(?1, ?2)", database)), + Sqlite::WrongBindingParameterCount); +} + +TEST_F(SqliteStatement, ReadStatementThrowsWrongBindingParameterCount) +{ + ASSERT_THROW((ReadStatement<2, 0>("SELECT name, number FROM test WHERE name=?", database)), + Sqlite::WrongBindingParameterCount); } TEST_F(SqliteStatement, ReadCallback) @@ -1331,7 +1343,7 @@ TEST_F(SqliteStatement, ReadCallback) TEST_F(SqliteStatement, ReadCallbackCalledWithArguments) { MockFunction callbackMock; - ReadStatement<2> statement("SELECT name, value FROM test WHERE value=?", database); + ReadStatement<2, 1> statement("SELECT name, value FROM test WHERE value=?", database); EXPECT_CALL(callbackMock, Call(Eq("foo"), Eq(2))); @@ -1404,7 +1416,7 @@ TEST_F(SqliteStatement, ReadToContainer) TEST_F(SqliteStatement, ReadToContainerCallCallbackWithArguments) { std::deque values; - ReadStatement<1> statement("SELECT number FROM test WHERE value=?", database); + ReadStatement<1, 1> statement("SELECT number FROM test WHERE value=?", database); statement.readTo(values, 2); @@ -1444,8 +1456,8 @@ TEST_F(SqliteStatement, ReadToCallsResetIfExceptionIsThrown) TEST_F(SqliteStatement, ReadStatementValuesWithTransactions) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); database.unlock(); std::vector values = statement.valuesWithTransaction(1024, "bar", "blah"); @@ -1457,8 +1469,8 @@ TEST_F(SqliteStatement, ReadStatementValuesWithTransactions) TEST_F(SqliteStatement, ReadStatementValueWithTransactions) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); database.unlock(); auto value = statement.valueWithTransaction("bar", "blah"); @@ -1470,8 +1482,8 @@ TEST_F(SqliteStatement, ReadStatementValueWithTransactions) TEST_F(SqliteStatement, ReadStatementOptionalValueWithTransactions) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); database.unlock(); auto value = statement.optionalValueWithTransaction("bar", "blah"); @@ -1483,8 +1495,8 @@ TEST_F(SqliteStatement, ReadStatementOptionalValueWithTransactions) TEST_F(SqliteStatement, ReadStatementReadCallbackWithTransactions) { MockFunction callbackMock; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); database.unlock(); EXPECT_CALL(callbackMock, Call(Eq("bar"), Eq("blah"), Eq(1))); @@ -1496,8 +1508,8 @@ TEST_F(SqliteStatement, ReadStatementReadCallbackWithTransactions) TEST_F(SqliteStatement, ReadStatementReadToWithTransactions) { using Tuple = std::tuple; - ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", - database); + ReadStatement<3, 2> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); std::vector values; database.unlock(); @@ -1510,7 +1522,7 @@ TEST_F(SqliteStatement, ReadStatementReadToWithTransactions) TEST_F(SqliteStatement, ReadWriteStatementValuesWithTransactions) { using Tuple = std::tuple; - ReadWriteStatement<3> statement( + ReadWriteStatement<3, 2> statement( "SELECT name, number, value FROM test WHERE name=? AND number=?", database); database.unlock(); @@ -1523,7 +1535,7 @@ TEST_F(SqliteStatement, ReadWriteStatementValuesWithTransactions) TEST_F(SqliteStatement, ReadWriteStatementValueWithTransactions) { using Tuple = std::tuple; - ReadWriteStatement<3> statement( + ReadWriteStatement<3, 2> statement( "SELECT name, number, value FROM test WHERE name=? AND number=?", database); database.unlock(); @@ -1536,7 +1548,7 @@ TEST_F(SqliteStatement, ReadWriteStatementValueWithTransactions) TEST_F(SqliteStatement, ReadWriteStatementOptionalValueWithTransactions) { using Tuple = std::tuple; - ReadWriteStatement<3> statement( + ReadWriteStatement<3, 2> statement( "SELECT name, number, value FROM test WHERE name=? AND number=?", database); database.unlock(); @@ -1549,7 +1561,7 @@ TEST_F(SqliteStatement, ReadWriteStatementOptionalValueWithTransactions) TEST_F(SqliteStatement, ReadWriteStatementReadCallbackWithTransactions) { MockFunction callbackMock; - ReadWriteStatement<3> statement( + ReadWriteStatement<3, 2> statement( "SELECT name, number, value FROM test WHERE name=? AND number=?", database); database.unlock(); @@ -1562,7 +1574,7 @@ TEST_F(SqliteStatement, ReadWriteStatementReadCallbackWithTransactions) TEST_F(SqliteStatement, ReadWriteStatementReadToWithTransactions) { using Tuple = std::tuple; - ReadWriteStatement<3> statement( + ReadWriteStatement<3, 2> statement( "SELECT name, number, value FROM test WHERE name=? AND number=?", database); std::vector values; database.unlock(); diff --git a/tests/unit/unittest/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index 20aa0680be9..24be87cca41 100644 --- a/tests/unit/unittest/sqlitetable-test.cpp +++ b/tests/unit/unittest/sqlitetable-test.cpp @@ -32,7 +32,6 @@ namespace { -using Sqlite::Column; using Sqlite::ColumnType; using Sqlite::ConstraintType; using Sqlite::Database; @@ -41,10 +40,13 @@ using Sqlite::ForeignKey; using Sqlite::ForeignKeyAction; using Sqlite::JournalMode; using Sqlite::OpenMode; +using Sqlite::StrictColumnType; class SqliteTable : public ::testing::Test { protected: + using Column = Sqlite::Column; + NiceMock databaseMock; Sqlite::Table table; Utils::SmallString tableName = "testTable"; @@ -328,4 +330,302 @@ TEST_F(SqliteTable, AddPrimaryTableContraint) table.initialize(databaseMock); } + +class StrictSqliteTable : public ::testing::Test +{ +protected: + using Column = Sqlite::StrictColumn; + + NiceMock databaseMock; + Sqlite::StrictTable table; + Utils::SmallString tableName = "testTable"; +}; + +TEST_F(StrictSqliteTable, ColumnIsAddedToTable) +{ + table.setUseWithoutRowId(true); + + ASSERT_TRUE(table.useWithoutRowId()); +} + +TEST_F(StrictSqliteTable, SetTableName) +{ + table.setName(tableName.clone()); + + ASSERT_THAT(table.name(), tableName); +} + +TEST_F(StrictSqliteTable, SetUseWithoutRowid) +{ + table.setUseWithoutRowId(true); + + ASSERT_TRUE(table.useWithoutRowId()); +} + +TEST_F(StrictSqliteTable, AddIndex) +{ + table.setName(tableName.clone()); + auto &column = table.addColumn("name"); + auto &column2 = table.addColumn("value"); + + auto index = table.addIndex({column, column2}); + + ASSERT_THAT(Utils::SmallStringView(index.sqlStatement()), + Eq("CREATE INDEX IF NOT EXISTS index_testTable_name_value ON testTable(name, " + "value)")); +} + +TEST_F(StrictSqliteTable, InitializeTable) +{ + table.setName(tableName.clone()); + table.setUseIfNotExists(true); + table.setUseTemporaryTable(true); + table.setUseWithoutRowId(true); + table.addColumn("name"); + table.addColumn("value"); + + EXPECT_CALL(databaseMock, + execute(Eq("CREATE TEMPORARY TABLE IF NOT EXISTS testTable(name ANY, value ANY) " + "WITHOUT ROWID STRICT"))); + + table.initialize(databaseMock); +} + +TEST_F(StrictSqliteTable, InitializeTableWithIndex) +{ + InSequence sequence; + table.setName(tableName.clone()); + auto &column = table.addColumn("name"); + auto &column2 = table.addColumn("value"); + table.addIndex({column}); + table.addIndex({column2}, "value IS NOT NULL"); + + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE testTable(name ANY, value ANY) STRICT"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_value ON testTable(value) " + "WHERE value IS NOT NULL"))); + + table.initialize(databaseMock); +} + +TEST_F(StrictSqliteTable, InitializeTableWithUniqueIndex) +{ + InSequence sequence; + table.setName(tableName.clone()); + auto &column = table.addColumn("name"); + auto &column2 = table.addColumn("value"); + table.addUniqueIndex({column}); + table.addUniqueIndex({column2}, "value IS NOT NULL"); + + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE testTable(name ANY, value ANY) STRICT"))); + EXPECT_CALL(databaseMock, + execute(Eq( + "CREATE UNIQUE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)"))); + EXPECT_CALL(databaseMock, + execute(Eq( + "CREATE UNIQUE INDEX IF NOT EXISTS index_testTable_value ON testTable(value) " + "WHERE value IS NOT NULL"))); + + table.initialize(databaseMock); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithTableCalls) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + table.setName(tableName); + table.addForeignKeyColumn("name", + foreignTable, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred); + + EXPECT_CALL(databaseMock, + execute(Eq("CREATE TABLE testTable(name INTEGER REFERENCES foreignTable ON UPDATE " + "SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED) STRICT"))); + + table.initialize(databaseMock); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithColumnCalls) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", + StrictColumnType::Text, + {Sqlite::Unique{}}); + table.setName(tableName); + table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetDefault, + ForeignKeyAction::Restrict, + Enforment::Deferred); + + EXPECT_CALL( + databaseMock, + execute( + Eq("CREATE TABLE testTable(name TEXT REFERENCES foreignTable(foreignColumn) ON UPDATE " + "SET DEFAULT ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED) STRICT"))); + + table.initialize(databaseMock); +} + +TEST_F(StrictSqliteTable, AddColumn) +{ + table.setName(tableName); + + auto &column = table.addColumn("name", StrictColumnType::Text, {Sqlite::Unique{}}); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, StrictColumnType::Text), + Field(&Column::constraints, + ElementsAre(VariantWith(Eq(Sqlite::Unique{})))))); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithTable) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignTable, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, StrictColumnType::Integer), + Field(&Column::constraints, + ElementsAre(VariantWith( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithColumn) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", + StrictColumnType::Text, + {Sqlite::Unique{}}); + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, StrictColumnType::Text), + Field(&Column::constraints, + ElementsAre(VariantWith( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, Eq("foreignColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))))))); +} + +TEST_F(StrictSqliteTable, AddForeignKeyWhichIsNotUniqueThrowsAnExceptions) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", StrictColumnType::Text); + table.setName(tableName); + + ASSERT_THROW(table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred), + Sqlite::ForeignKeyColumnIsNotUnique); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithTableAndNotNull) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignTable, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred, + {Sqlite::NotNull{}}); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, StrictColumnType::Integer), + Field(&Column::constraints, + UnorderedElementsAre( + VariantWith( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, IsEmpty()), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))), + VariantWith(Eq(Sqlite::NotNull{})))))); +} + +TEST_F(StrictSqliteTable, AddForeignKeyColumnWithColumnAndNotNull) +{ + Sqlite::StrictTable foreignTable; + foreignTable.setName("foreignTable"); + auto &foreignColumn = foreignTable.addColumn("foreignColumn", + StrictColumnType::Text, + {Sqlite::Unique{}}); + table.setName(tableName); + + auto &column = table.addForeignKeyColumn("name", + foreignColumn, + ForeignKeyAction::SetNull, + ForeignKeyAction::Cascade, + Enforment::Deferred, + {Sqlite::NotNull{}}); + + ASSERT_THAT(column, + AllOf(Field(&Column::name, Eq("name")), + Field(&Column::tableName, Eq(tableName)), + Field(&Column::type, StrictColumnType::Text), + Field(&Column::constraints, + UnorderedElementsAre( + VariantWith( + AllOf(Field(&ForeignKey::table, Eq("foreignTable")), + Field(&ForeignKey::column, Eq("foreignColumn")), + Field(&ForeignKey::updateAction, ForeignKeyAction::SetNull), + Field(&ForeignKey::deleteAction, ForeignKeyAction::Cascade), + Field(&ForeignKey::enforcement, Enforment::Deferred))), + VariantWith(Eq(Sqlite::NotNull{})))))); +} + +TEST_F(StrictSqliteTable, AddPrimaryTableContraint) +{ + table.setName(tableName.clone()); + const auto &idColumn = table.addColumn("id"); + const auto &nameColumn = table.addColumn("name"); + table.addPrimaryKeyContraint({idColumn, nameColumn}); + + EXPECT_CALL(databaseMock, + execute( + Eq("CREATE TABLE testTable(id ANY, name ANY, PRIMARY KEY(id, name)) STRICT"))); + + table.initialize(databaseMock); +} } // namespace diff --git a/tests/unit/unittest/sqliteteststatement.h b/tests/unit/unittest/sqliteteststatement.h index f2fe6ba2959..f90f319824c 100644 --- a/tests/unit/unittest/sqliteteststatement.h +++ b/tests/unit/unittest/sqliteteststatement.h @@ -26,10 +26,11 @@ #pragma once #include - -class SqliteTestStatement : public Sqlite::StatementImplementation +template +class SqliteTestStatement + : public Sqlite::StatementImplementation { - using Base = Sqlite::StatementImplementation; + using Base = Sqlite::StatementImplementation; public: explicit SqliteTestStatement(Utils::SmallStringView sqlStatement, Sqlite::Database &database) diff --git a/tests/unit/unittest/sqlitewritestatementmock.cpp b/tests/unit/unittest/sqlitewritestatementmock.cpp index a3612833b2e..0cfb6a677f2 100644 --- a/tests/unit/unittest/sqlitewritestatementmock.cpp +++ b/tests/unit/unittest/sqlitewritestatementmock.cpp @@ -27,8 +27,8 @@ #include "sqlitedatabasemock.h" -SqliteWriteStatementMock::SqliteWriteStatementMock(Utils::SmallStringView sqlStatement, - SqliteDatabaseMock &database) +SqliteWriteStatementMockBase::SqliteWriteStatementMockBase(Utils::SmallStringView sqlStatement, + SqliteDatabaseMock &database) : sqlStatement(sqlStatement) { database.prepare(sqlStatement); diff --git a/tests/unit/unittest/sqlitewritestatementmock.h b/tests/unit/unittest/sqlitewritestatementmock.h index 9031da67bbe..5dd939e7448 100644 --- a/tests/unit/unittest/sqlitewritestatementmock.h +++ b/tests/unit/unittest/sqlitewritestatementmock.h @@ -32,11 +32,11 @@ class SqliteDatabaseMock; -class SqliteWriteStatementMock +class SqliteWriteStatementMockBase { public: - SqliteWriteStatementMock() = default; - SqliteWriteStatementMock(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &database); + SqliteWriteStatementMockBase() = default; + SqliteWriteStatementMockBase(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &database); MOCK_METHOD(void, execute, (), ()); @@ -119,3 +119,10 @@ public: Utils::SmallString sqlStatement; }; + +template +class SqliteWriteStatementMock : public SqliteWriteStatementMockBase +{ +public: + using SqliteWriteStatementMockBase::SqliteWriteStatementMockBase; +}; diff --git a/tests/unit/unittest/sqlstatementbuilder-test.cpp b/tests/unit/unittest/sqlstatementbuilder-test.cpp index 1e24faeded1..806939fcdb6 100644 --- a/tests/unit/unittest/sqlstatementbuilder-test.cpp +++ b/tests/unit/unittest/sqlstatementbuilder-test.cpp @@ -135,16 +135,6 @@ TEST(SqlStatementBuilder, ClearBinding) ASSERT_THROW(sqlStatementBuilder.sqlStatement(), SqlStatementBuilderException); } -TEST(SqlStatementBuilder, ColumnType) -{ - ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Numeric), " NUMERIC"); - ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Integer), " INTEGER"); - ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Real), " REAL"); - ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Text), " TEXT"); - ASSERT_THAT(SqlStatementBuilder::columnTypeToString(ColumnType::Blob), " BLOB"); - ASSERT_TRUE(SqlStatementBuilder::columnTypeToString(ColumnType::None).isEmpty()); -} - TEST(SqlStatementBuilder, SqlStatementFailure) { SqlStatementBuilder sqlStatementBuilder("SELECT $columns FROM $table");