diff options
Diffstat (limited to 'src/corelib')
47 files changed, 2352 insertions, 320 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index ea8cf7b9c8e..e50838730cb 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -590,17 +590,14 @@ if(QT_FEATURE_async_io) DEFINES QT_RANDOMACCESSASYNCFILE_QIORING ) - elseif(QT_FEATURE_thread AND QT_FEATURE_future) - # TODO: This should become the last (fallback) condition later. - # We migth also want to rewrite it so that it does not depend on - # QT_FEATURE_future. - qt_internal_extend_target(Core - SOURCES - io/qrandomaccessasyncfile_threadpool.cpp - DEFINES - QT_RANDOMACCESSASYNCFILE_THREAD - ) endif() + # This is the fallback condition that should be always available. + # TODO: try to rewrite it so that it does not depend on + # QT_FEATURE_future. + qt_internal_extend_target(Core + SOURCES + io/qrandomaccessasyncfile_threadpool.cpp + ) endif() # This needs to be done before one below adds kernel32 because the symbols we use @@ -1536,6 +1533,7 @@ qt_internal_extend_target(Core CONDITION WASM platform/wasm/qstdweb.cpp platform/wasm/qstdweb_p.h platform/wasm/qwasmsocket.cpp platform/wasm/qwasmsocket_p.h platform/wasm/qwasmsuspendresumecontrol.cpp platform/wasm/qwasmsuspendresumecontrol_p.h + platform/wasm/qwasmlocalfileengine.cpp platform/wasm/qwasmlocalfileengine_p.h kernel/qeventdispatcher_wasm.cpp kernel/qeventdispatcher_wasm_p.h ) diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake index f71bac4e08a..fc8e009b9da 100644 --- a/src/corelib/Qt6AndroidGradleHelpers.cmake +++ b/src/corelib/Qt6AndroidGradleHelpers.cmake @@ -193,7 +193,7 @@ function(_qt_internal_android_generate_target_build_gradle target) QT_ANDROID_MIN_SDK_VERSION "28") _qt_internal_android_get_gradle_property(target_sdk_version ${target} - QT_ANDROID_TARGET_SDK_VERSION "34") + QT_ANDROID_TARGET_SDK_VERSION "36") set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>") set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>") diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index 90a0e359c9f..0f717ff2ae0 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -620,6 +620,10 @@ int main(void) HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, 1, 1, &ioRingHandle); if (hr == IORING_E_SUBMISSION_QUEUE_FULL) // not valid, but test that this #define exists return 0; + IORING_HANDLE_REF ref(HANDLE(nullptr)); + IORING_BUFFER_REF bufRef(nullptr); + // The newest API addition that we require: + BuildIoRingWriteFile(ioRingHandle, ref, bufRef, -1, 0, FILE_WRITE_FLAGS_NONE, 0, IOSQE_FLAGS_NONE); /* END TEST: */ return 0; } @@ -806,9 +810,9 @@ qt_feature("winsdkicu" PRIVATE CONDITION TEST_winsdkicu DISABLE QT_FEATURE_icu ) -qt_feature("windows_ioring" PRIVATE +qt_feature("windows-ioring" PRIVATE LABEL "Windows I/O Ring" - AUTODETECT WIN32 AND CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 10.0.22000 + AUTODETECT WIN32 CONDITION TEST_windows_ioring ) qt_feature("inotify" PUBLIC PRIVATE @@ -1284,7 +1288,7 @@ qt_feature("openssl-hash" PRIVATE qt_feature("async-io" PRIVATE LABEL "Async File I/O" PURPOSE "Provides support for asynchronous file I/O." - CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE OR (LINUX AND QT_FEATURE_liburing) OR (WIN32 AND QT_FEATURE_windows_ioring) + CONDITION QT_FEATURE_thread AND QT_FEATURE_future ) qt_configure_add_summary_section(NAME "Qt Core") @@ -1297,7 +1301,7 @@ qt_configure_add_summary_entry(ARGS "glib") qt_configure_add_summary_entry(ARGS "icu") qt_configure_add_summary_entry(ARGS "jemalloc") qt_configure_add_summary_entry(ARGS "liburing") -qt_configure_add_summary_entry(ARGS "windows_ioring") +qt_configure_add_summary_entry(ARGS "windows-ioring") qt_configure_add_summary_entry(ARGS "timezone_tzdb") qt_configure_add_summary_entry(ARGS "system-libb2") qt_configure_add_summary_entry(ARGS "mimetype-database") diff --git a/src/corelib/doc/images/javaiterators1.svg b/src/corelib/doc/images/javaiterators1.svg index 468dbe5371c..c10329ab480 100644 --- a/src/corelib/doc/images/javaiterators1.svg +++ b/src/corelib/doc/images/javaiterators1.svg @@ -12,6 +12,11 @@ svg .text-style { font: 20px arial; fill: black } svg .fill-style { stroke: none; fill: red } + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .line-style { stroke: red; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .fill-style { stroke: none; fill: red } + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } [data-theme="dark"] svg .line-style { stroke: red; fill: none } [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } @@ -24,36 +29,53 @@ </style> <g transform="translate(10.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">A</text> -<path d="M 0,60 v 30" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">A</text> +<path d="M 0,60 v 30" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red" + class="fill-style" /> </g> <g transform="translate(90.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">B</text> -<path d="M 0,60 v 30" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">B</text> +<path d="M 0,60 v 30" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red" + class="fill-style" /> </g> <g transform="translate(170.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">C</text> -<path d="M 0,60 v 30" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">C</text> +<path d="M 0,60 v 30" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red" + class="fill-style" /> </g> <g transform="translate(250.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">D</text> -<path d="M 0,60 v 30" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">D</text> +<path d="M 0,60 v 30" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red" + class="fill-style" /> </g> <g transform="translate(330.5, 10.5)"> -<path d="M 0,60 v 30" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<path d="M 0,60 v 30" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="red" fill="red" + class="fill-style" /> </g> - </svg> diff --git a/src/corelib/doc/images/javaiterators2.svg b/src/corelib/doc/images/javaiterators2.svg index df4c6b352a6..3b41b3f8730 100644 --- a/src/corelib/doc/images/javaiterators2.svg +++ b/src/corelib/doc/images/javaiterators2.svg @@ -15,6 +15,14 @@ svg .text-style { font: 20px arial; fill: black } svg .small-text-style { font: 12px monospace; fill: black } + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .line-style { stroke: red; fill: none } + svg.dark .fill-style { stroke: none; fill: red } + svg.dark .np-line-style { stroke: #4080ff; fill: none; stroke-width: 1.5 } + svg.dark .np-fill-style { stroke: none; fill: #4080ff } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .small-text-style { font: 12px monospace; fill: #f2f2f2 } + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } [data-theme="dark"] svg .line-style { stroke: red; fill: none } [data-theme="dark"] svg .fill-style { stroke: none; fill: red } @@ -33,31 +41,46 @@ </style> <g transform="translate(10.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">A</text> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">A</text> </g> <g transform="translate(90.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">B</text> -<path d="M 0,60 c 0,30 50,40 80,30" class="np-line-style" /> -<path d="M 0,60 l -2,14 l 11,-4 z" class="np-fill-style" /> -<text x="-15" y="110" class="small-text-style">previous()</text> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">B</text> +<path d="M 0,60 c 0,30 50,40 80,30" stroke="blue" fill="none" + class="np-line-style" /> +<path d="M 0,60 l -2,14 l 11,-4 z" stroke="none" fill="blue" + class="np-fill-style" /> +<text x="-15" y="110" + class="small-text-style">previous()</text> </g> <g transform="translate(170.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">C</text> -<path d="M 0,60 v 50" class="line-style" /> -<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> -<text x="30" y="110" class="small-text-style">next()</text> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">C</text> +<path d="M 0,60 v 50" stroke="red" + class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +<text x="30" y="110" + class="small-text-style">next()</text> </g> <g transform="translate(250.5, 10.5)"> -<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> -<text x="35" y="36" class="text-style">D</text> -<path d="M 0,60 c 0,30 -50,40 -80,30" class="np-line-style" /> -<path d="M 0,60 l 2,14 l -11,-4 z" class="np-fill-style" /> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">D</text> +<path d="M 0,60 c 0,30 -50,40 -80,30" stroke="blue" fill="none" + class="np-line-style" /> +<path d="M 0,60 l 2,14 l -11,-4 z" stroke="none" fill="blue" + class="np-fill-style" /> </g> - </svg> diff --git a/src/corelib/doc/images/modelindex-no-parent.svg b/src/corelib/doc/images/modelindex-no-parent.svg new file mode 100644 index 00000000000..4ce4b86b1f2 --- /dev/null +++ b/src/corelib/doc/images/modelindex-no-parent.svg @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="300" + height="160" + version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .line-style { stroke: black; fill: none } + svg .fill-style { stroke: black; fill: #c0c0c0 } + svg .text-style { font: 12px arial; fill: black } + svg .italic-style { font: 12px arial; fill: black; font-style: italic } + svg .bold-style { font: 12px arial; fill: black; font-weight: bold } + + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .fill-style { stroke: #f2f2f2; fill: #606060 } + svg.dark .text-style { font: 12px arial; fill: #f2f2f2 } + svg.dark .italic-style { font: 12px arial; fill: #f2f2f2; font-style: italic } + svg.dark .bold-style { font: 12px arial; fill: #f2f2f2; font-weight: bold } + + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .fill-style { stroke: #f2f2f2; fill: #606060 } + [data-theme="dark"] svg .text-style { font: 12px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .italic-style { font: 12px arial; fill: #f2f2f2; font-style: italic } + [data-theme="dark"] svg .bold-style { font: 12px arial; fill: #f2f2f2; font-weight: bold } + + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .fill-style { stroke: black; fill: #c0c0c0 } + [data-theme="light"] svg .text-style { font: 12px arial; fill: black } + [data-theme="light"] svg .italic-style { font: 12px arial; fill: black; font-style: italic } + [data-theme="light"] svg .bold-style { font: 12px arial; fill: black; font-weight: bold } +</style> + +<text x="25" y="49" font-family="arial" font-size="12px" + class="text-style">0</text> +<text x="25" y="79" font-family="arial" font-size="12px" + class="text-style">1</text> +<text x="25" y="109" font-family="arial" font-size="12px" + class="text-style">2</text> +<g transform="translate(30,139)"> +<text x="0" y="0" font-family="arial" font-size="12px" + class="text-style" transform="rotate(270)">...</text> +</g> + +<path d="m 40.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 70.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 100.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 130.5,30.5 h 30 v 30" stroke="black" fill="none" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 40.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 70.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 100.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0c0c0" + class="fill-style" /> +<path d="m 130.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 40.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 70.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 100.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" /> +<path d="m 70.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 40.5,120.5 v 30 h 30" stroke="black" fill="none" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 100.5,150.5 h 30" stroke="black" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 130.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="none" + class="line-style" stroke-dasharray="3, 3" /> +<path d="m 160.5,90.5 v 30" stroke="black" + class="line-style" stroke-dasharray="3, 3" /> + +<text x="50" y="20" font-family="arial" font-size="12px" + class="text-style">0</text> +<text x="80" y="20" font-family="arial" font-size="12px" + class="text-style">1</text> +<text x="110" y="20" font-family="arial" font-size="12px" + class="text-style">2</text> +<text x="140" y="20" font-family="arial" font-size="12px" + class="text-style">...</text> + +<text x="190" y="55" font-family="arial" font-size="12px" font-weight="bold" + class="bold-style">Model index</text> +<rect x="185.5" y="60.5" width="77" height="37" stroke="black" fill="none" + class="line-style" /> +<text x="190" y="75" font-family="arial" font-size="12px" + class="text-style">row = 1</text> +<text x="190" y="92" font-family="arial" font-size="12px" + class="text-style">column = 2</text> + +<path d="m 185.5,85.5 c -35,0 -35,-10 -70,-10" stroke="black" fill="none" + stroke-dasharray="2, 2" class="line-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-begin-append-columns.svg b/src/corelib/doc/images/modelview-begin-append-columns.svg new file mode 100644 index 00000000000..937a2c03206 --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-append-columns.svg @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="291" + height="166" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } +</style> + +<path d="m 10.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="50" y="32" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="80" y="32" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="110" y="32" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="140" y="32" font-family="arial" font-size="20px" class="text-style">4</text> +<path d="m 160.5,10.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="170" y="32" font-family="arial" font-size="20px" class="text-style">5</text> + +<path d="m 190.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="200" y="90" font-family="arial" font-size="20px" class="high-text-style">6</text> +<path d="m 220.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="230" y="90" font-family="arial" font-size="20px" class="high-text-style">7</text> +<path d="m 250.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="260" y="90" font-family="arial" font-size="20px" class="high-text-style">8</text> + +<path d="m 10.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="20" y="147" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="50" y="147" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="80" y="147" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="110" y="147" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="140" y="147" font-family="arial" font-size="20px" class="text-style">4</text> +<path d="m 160.5,125.5 h 30 v 30 h -30 v -30" class="box-style" /> +<text x="170" y="147" font-family="arial" font-size="20px" class="text-style">5</text> +<path d="m 190.5,125.5 h 30 v 30 h -30 v -30" class="highlighted-style" /> +<text x="200" y="147" font-family="arial" font-size="20px" class="high-text-style">6</text> +<path d="m 220.5,125.5 h 30 v 30 h -30 v -30" class="highlighted-style" /> +<text x="230" y="147" font-family="arial" font-size="20px" class="high-text-style">7</text> +<path d="m 250.5,125.5 h 30 v 30 h -30 v -30" class="highlighted-style" /> +<text x="260" y="147" font-family="arial" font-size="20px" class="high-text-style">8</text> + +<path d="m 190.5,65.5 v -20" class="line-style" /> +<path d="M 190.5 42.5 l 5,10 l -10,0 z" class="fill-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-begin-append-rows.svg b/src/corelib/doc/images/modelview-begin-append-rows.svg new file mode 100644 index 00000000000..7e66d0d8756 --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-append-rows.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="165" + height="200" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } +</style> + +<path d="m 10.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 10.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 10.5,70.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="92" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 10.5,100.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="122" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 68.5,130.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="152" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 68.5,160.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="182" font-family="arial" font-size="20px" class="high-text-style">5</text> + +<path d="m 125.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 125.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 125.5,70.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="92" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 125.5,100.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="122" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 125.5,130.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="135" y="152" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 125.5,160.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="135" y="182" font-family="arial" font-size="20px" class="high-text-style">5</text> + +<path d="m 65.5,130.5 h -20" class="line-style" /> +<path d="M 42.5,130.5 l 10,-5 l 0,10 z" class="fill-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-begin-insert-columns.svg b/src/corelib/doc/images/modelview-begin-insert-columns.svg new file mode 100644 index 00000000000..51664b80568 --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-insert-columns.svg @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="290" + height="165" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<path d="m 10.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="50" y="32" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="80" y="32" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="110" y="32" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="140" y="32" font-family="arial" font-size="20px" class="text-style">4</text> +<path d="m 160.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="170" y="32" font-family="arial" font-size="20px" class="text-style">5</text> +<path d="m 190.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="200" y="32" font-family="arial" font-size="20px" class="text-style">6</text> +<path d="m 220.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="230" y="32" font-family="arial" font-size="20px" class="text-style">7</text> +<path d="m 250.5,10.5 h 30 v 30 h -30 z" class="line-style" + stroke-dasharray="5, 5" /> + +<path d="m 130.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="140" y="90" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 160.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="170" y="90" font-family="arial" font-size="20px" class="high-text-style">5</text> +<path d="m 190.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="200" y="90" font-family="arial" font-size="20px" class="high-text-style">6</text> + +<path d="m 10.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="147" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="50" y="147" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="80" y="147" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="110" y="147" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,125.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="140" y="147" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 160.5,125.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="170" y="147" font-family="arial" font-size="20px" class="high-text-style">5</text> +<path d="m 190.5,125.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="200" y="147" font-family="arial" font-size="20px" class="high-text-style">6</text> +<path d="m 220.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="230" y="147" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">4</text> +<path d="m 250.5,125.5 h 30 v 30 h -30 z" class="line-style" + stroke-dasharray="5, 5" /> + + +<path d="m 130.5,65.5 v -20" class="line-style" /> +<path d="M 130.5,42.5 l 5,10 l -10,0 z" class="fill-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-begin-insert-rows.svg b/src/corelib/doc/images/modelview-begin-insert-rows.svg new file mode 100644 index 00000000000..fd6641218ed --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-insert-rows.svg @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="165" + height="230" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<path d="m 10.5,190.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> +<path d="m 125.5,190.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> +<path d="m 10.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 10.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 10.5,70.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="92" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 10.5,100.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="122" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 10.5,130.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="152" font-family="arial" font-size="20px" class="text-style">4</text> +<path d="m 10.5,160.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="182" font-family="arial" font-size="20px" class="text-style">5</text> + +<path d="m 68.5,70.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="92" font-family="arial" font-size="20px" class="high-text-style">2</text> +<path d="m 68.5,100.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="122" font-family="arial" font-size="20px" class="high-text-style">3</text> +<path d="m 68.5,130.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="152" font-family="arial" font-size="20px" class="high-text-style">4</text> + +<path d="m 125.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 125.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 125.5,70.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="135" y="92" font-family="arial" font-size="20px" class="high-text-style">2</text> +<path d="m 125.5,100.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="135" y="122" font-family="arial" font-size="20px" class="high-text-style">3</text> +<path d="m 125.5,130.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="135" y="152" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 125.5,160.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="182" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">2</text> + +<path d="m 65.5,70.5 h -20" class="line-style" /> +<path d="M 42.5,70.5 l 10,-5 l 0,10 z" class="fill-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-begin-remove-columns.svg b/src/corelib/doc/images/modelview-begin-remove-columns.svg new file mode 100644 index 00000000000..a221bfda9fc --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-remove-columns.svg @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="290" + height="165" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<path d="m 10.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="50" y="32" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="80" y="32" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="110" y="32" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,10.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="140" y="32" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 160.5,10.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="170" y="32" font-family="arial" font-size="20px" class="high-text-style">5</text> +<path d="m 190.5,10.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="200" y="32" font-family="arial" font-size="20px" class="high-text-style">6</text> +<path d="m 220.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="230" y="32" font-family="arial" font-size="20px" class="text-style">7</text> +<path d="m 250.5,10.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> + +<path d="m 130.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="140" y="89" font-family="arial" font-size="20px" class="high-text-style">4</text> +<path d="m 160.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="170" y="89" font-family="arial" font-size="20px" class="high-text-style">5</text> +<path d="m 190.5,68.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="200" y="89" font-family="arial" font-size="20px" class="high-text-style">6</text> + +<path d="m 10.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="147" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 40.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="50" y="147" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 70.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="80" y="147" font-family="arial" font-size="20px" class="text-style">2</text> +<path d="m 100.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="110" y="147" font-family="arial" font-size="20px" class="text-style">3</text> +<path d="m 130.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="140" y="147" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">7</text> +<path d="m 160.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="170" y="147" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">8</text> +<path d="m 190.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="200" y="147" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">9</text> +<path d="m 220.5,125.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="224" y="147" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">10</text> +<path d="m 250.5,125.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> + +<path d="M 130.5,63 V 43" class="line-style" /> +<path d="M 130.5,66 l -5,-10 l 10,0 z" class="fill-style" /> + +</svg> diff --git a/src/corelib/doc/images/modelview-begin-remove-rows.svg b/src/corelib/doc/images/modelview-begin-remove-rows.svg new file mode 100644 index 00000000000..0c67b1b6404 --- /dev/null +++ b/src/corelib/doc/images/modelview-begin-remove-rows.svg @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="165" + height="230" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<path d="m 10.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 10.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 10.5,70.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="20" y="92" font-family="arial" font-size="20px" class="high-text-style">2</text> +<path d="m 10.5,100.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="20" y="122" font-family="arial" font-size="20px" class="high-text-style">3</text> +<path d="m 10.5,130.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="152" font-family="arial" font-size="20px" class="text-style">4</text> +<path d="m 10.5,160.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="20" y="182" font-family="arial" font-size="20px" class="text-style">5</text> +<path d="m 10.5,190.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> + +<path d="m 125.5,10.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="32" font-family="arial" font-size="20px" class="text-style">0</text> +<path d="m 125.5,40.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="62" font-family="arial" font-size="20px" class="text-style">1</text> +<path d="m 125.5,70.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="92" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">4</text> +<path d="m 125.5,100.5 h 30 v 30 h -30 z" class="box-style" /> +<text x="135" y="122" font-family="arial" font-size="20px" fill="#808080" class="faded-text-style">5</text> +<path d="m 125.5,130.5 h 30 v 30 h -30 z" class="box-style" + stroke-dasharray="5, 5" /> + +<path d="m 68.5,70.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="92" font-family="arial" font-size="20px" class="high-text-style">2</text> +<path d="m 68.5,100.5 h 30 v 30 h -30 z" class="highlighted-style" /> +<text x="77" y="122" font-family="arial" font-size="20px" class="high-text-style">3</text> + +<path d="M 63,70.5 H 43" class="line-style" /> +<path d="M 66,70.5 l -10,-5 l 0,10 z" class="fill-style" /> +</svg> diff --git a/src/corelib/doc/images/modelview-move-rows-1.svg b/src/corelib/doc/images/modelview-move-rows-1.svg new file mode 100644 index 00000000000..1c90c42f730 --- /dev/null +++ b/src/corelib/doc/images/modelview-move-rows-1.svg @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="200" + height="440" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<g transform="translate(10,10)"> +<path d="m 0.5,0.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="82" font-family="arial" font-size="20px" + class="text-style">2</text> +<path d="m 0.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 0.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 0.5,180.5 h 30 v 30 h -30 z" stroke="black" fill="white" + stroke-dasharray="5, 5" + class="box-style" /> +<path d="m 0.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 0.5,240.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="262" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,270.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="292" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,300.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="322" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 0.5,330.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="352" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 0.5,360.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="382" font-family="arial" font-size="20px" + class="high-text-style">4</text> +<path d="m 0.5,390.5 h 30 V 420.5 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="412" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 58.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="82" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 58.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="112" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 58.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="142" font-family="arial" font-size="20px" + class="high-text-style">4</text> + +<path d="m 145.5,0.5 h 30 v 30.956 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 145.5,31.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 145.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="82" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 145.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="112" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 145.5,180.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="202" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">3</text> +<path d="m 145.5,210.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="232" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">4</text> +<path d="m 145.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="142" font-family="arial" font-size="20px" + class="high-text-style">4</text> +<path d="m 145.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="172" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">2</text> +<path d="m 145.5,240.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="262" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">5</text> + +<path d="m 145.5,330.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="352" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 145.5,360.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="382" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 145.5,390.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="412" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">5</text> + +<path d="M 58.5,60.5 h -25" stroke="black" + class="line-style" /> +<path d="M 31.5,60.5 l 10,-5 l 0,10 z" stroke="none" fill="black" + class="fill-style" /> +<path d="M 31.5,315.5 h 42 v -163" stroke="black" fill="none" + class="line-style" /> +<path d="M 73.5,151.5 l -5,10 l 10,0 z" stroke="none" fill="black" + class="fill-style" /> +</g> +</svg> diff --git a/src/corelib/doc/images/modelview-move-rows-2.svg b/src/corelib/doc/images/modelview-move-rows-2.svg new file mode 100644 index 00000000000..12ebfc43a16 --- /dev/null +++ b/src/corelib/doc/images/modelview-move-rows-2.svg @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="200" + height="440" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<g transform="translate(10,10)"> +<path d="m 0.5,0.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="82" font-family="arial" font-size="20px" + class="text-style">2</text> +<path d="m 0.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 0.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 0.5,180.5 h 30 v 30 h -30 z" stroke="black" fill="white" + stroke-dasharray="5, 5" + class="box-style" /> +<path d="m 0.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 0.5,240.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="262" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,270.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="292" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,300.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="322" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 0.5,330.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="352" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 0.5,360.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="382" font-family="arial" font-size="20px" + class="high-text-style">4</text> +<path d="m 0.5,390.5 h 30 V 420.5 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="412" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 58.5,180.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="202" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 58.5,210.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="232" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 58.5,240.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="262" font-family="arial" font-size="20px" + class="high-text-style">4</text> + +<path d="m 145.5,0.5 h 30 v 30.956 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 145.5,31.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 145.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="82" font-family="arial" font-size="20px" + class="text-style">2</text> +<path d="m 145.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 145.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 145.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> +<path d="m 145.5,180.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="202" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 145.5,210.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="232" font-family="arial" font-size="20px" + class="high-text-style">3</text> +<path d="m 145.5,240.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="262" font-family="arial" font-size="20px" + class="high-text-style">4</text> + +<path d="m 145.5,330.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="352" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 145.5,360.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="382" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 145.5,390.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="412" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">5</text> + +<path d="M 58.5,180.5 h -25" stroke="black" + class="line-style" /> +<path d="M 31.5,180.5 l 10,-5 l 0,10 z" stroke="none" fill="black" + class="fill-style" /> +<path d="M 31.5,315.5 h 42 v -43" stroke="black" fill="none" + class="line-style" /> +<path d="M 73.5,271.5 l -5,10 l 10,0 z" stroke="none" fill="black" + class="fill-style" /> +</g> +</svg> diff --git a/src/corelib/doc/images/modelview-move-rows-3.svg b/src/corelib/doc/images/modelview-move-rows-3.svg new file mode 100644 index 00000000000..21d9803eb91 --- /dev/null +++ b/src/corelib/doc/images/modelview-move-rows-3.svg @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="200" + height="200" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<g transform="translate(10,10)"> +<path d="m 0.5,0.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="82" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 0.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 0.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 0.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 58.5,0.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="22" font-family="arial" font-size="20px" + class="high-text-style">2</text> + +<path d="m 145.5,0.5 h 30 v 30.956 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="22" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 145.5,31.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="52" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">0</text> +<path d="m 145.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="82" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">1</text> +<path d="m 145.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 145.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 145.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="M 58.5,0.5 h -25" stroke="black" fill="none" + class="line-style" /> +<path d="M 31.5,0.5 l 10,-5 l 0,10 z" stroke="none" fill="black" + class="fill-style" /> +<path d="M 31.5,75.5 h 42 v -43" stroke="black" fill="none" + class="line-style" /> +<path d="M 73.5,31.5 l -5,10 l 10,0 z" stroke="black" fill="black" + class="fill-style" /> +</g> +</svg> diff --git a/src/corelib/doc/images/modelview-move-rows-4.svg b/src/corelib/doc/images/modelview-move-rows-4.svg new file mode 100644 index 00000000000..708eb71f440 --- /dev/null +++ b/src/corelib/doc/images/modelview-move-rows-4.svg @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="200" + height="200" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .highlighted-style { stroke: black; fill: #c0ffc0 } + svg .fill-style { stroke: none; fill: black } + svg .line-style { stroke: black; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .high-text-style { font: 20px arial; fill: black } + svg .faded-text-style { font: 20px arial; fill: #808080 } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + svg.dark .fill-style { stroke: none; fill: #f2f2f2 } + svg.dark .line-style { stroke: #f2f2f2; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .high-text-style { font: 20px arial; fill: black } + svg.dark .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .highlighted-style { stroke: #f2f2f2; fill: #c0ffc0 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: #f2f2f2 } + [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="dark"] svg .faded-text-style { font: 20px arial; fill: #808080 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .highlighted-style { stroke: black; fill: #c0ffc0 } + [data-theme="light"] svg .fill-style { stroke: none; fill: black } + [data-theme="light"] svg .line-style { stroke: black; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .high-text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .faded-text-style { font: 20px arial; fill: #808080 } +</style> + +<g transform="translate(10,10)"> +<path d="m 0.5,0.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 0.5,30.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 0.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="10" y="82" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 0.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="112" font-family="arial" font-size="20px" + class="text-style">3</text> +<path d="m 0.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 0.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="10" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="m 58.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="67" y="142" font-family="arial" font-size="20px" + class="high-text-style">2</text> + +<path d="m 145.5,0.5 h 30 v 30.956 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="22" font-family="arial" font-size="20px" + class="text-style">0</text> +<path d="m 145.5,31.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="52" font-family="arial" font-size="20px" + class="text-style">1</text> +<path d="m 145.5,60.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="82" font-family="arial" font-size="20px" fill="#808080" + class="faded-text-style">3</text> +<path d="m 145.5,90.5 h 30 v 30 h -30 z" stroke="black" fill="#c0ffc0" + class="highlighted-style" /> +<text x="155" y="112" font-family="arial" font-size="20px" + class="high-text-style">2</text> +<path d="m 145.5,120.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="142" font-family="arial" font-size="20px" + class="text-style">4</text> +<path d="m 145.5,150.5 h 30 v 30 h -30 z" stroke="black" fill="white" + class="box-style" /> +<text x="155" y="172" font-family="arial" font-size="20px" + class="text-style">5</text> + +<path d="M 58.5,120.5 h -25" stroke="black" fill="none" + class="line-style" /> +<path d="M 31.5,120.5 l 10,-5 l 0,10 z" stroke="black" fill="black" + class="fill-style" /> +<path d="M 31.5,75.5 h 42 v 43" stroke="black" fill="none" + class="line-style" /> +<path d="M 73.5,119.5 l -5,-10 l 10,0 z" stroke="black" fill="black" + class="fill-style" /> +</g> +</svg> diff --git a/src/corelib/doc/images/stliterators1.svg b/src/corelib/doc/images/stliterators1.svg new file mode 100644 index 00000000000..478211c78d7 --- /dev/null +++ b/src/corelib/doc/images/stliterators1.svg @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="420" + height="110" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .line-style { stroke: red; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .fill-style { stroke: none; fill: red } + svg .fn-text-style { font: 14px monospace; fill: black } + + svg.dark .box-style { stroke: #f2f2f2; fill: black } + svg.dark .line-style { stroke: red; fill: none } + svg.dark .text-style { font: 20px arial; fill: #f2f2f2 } + svg.dark .fill-style { stroke: none; fill: red } + svg.dark .fn-text-style { font: 14px monospace; fill: #f2f2f2 } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .line-style { stroke: red; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: red } + [data-theme="dark"] svg .fn-text-style { font: 14px monospace; fill: #f2f2f2 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .line-style { stroke: red; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .fill-style { stroke: none; fill: red } + [data-theme="light"] svg .fn-text-style { font: 14px monospace; fill: black } +</style> + +<g transform="translate(10.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">A</text> +<path d="M 40,60 v 30" stroke="red" + class="line-style" /> +<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +</g> + +<g transform="translate(90.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">B</text> +<path d="M 40,60 v 30" stroke="red" + class="line-style" /> +<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +</g> + +<g transform="translate(170.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">C</text> +<path d="M 40,60 v 30" stroke="red" + class="line-style" /> +<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +</g> + +<g transform="translate(250.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + class="box-style" /> +<text x="35" y="36" font-family="arial" font-size="20px" + class="text-style">D</text> +<path d="M 40,60 v 30" stroke="red" + class="line-style" /> +<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +</g> + +<g transform="translate(330.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" stroke="black" fill="white" + stroke-dasharray="3,3" + class="box-style" /> +<text x="20" y="36" font-family="monospace" font-size="14px" + class="fn-text-style">end()</text> +<path d="M 40,60 v 30" stroke="red" + class="line-style" /> +<path d="M 40,60 l -5,10 l 10,0 z" stroke="none" fill="red" + class="fill-style" /> +</g> +</svg> diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc index b8e5e038a33..7cd3f91b901 100644 --- a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc +++ b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc @@ -525,7 +525,6 @@ To prevent this, set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to \c TRUE. \summary {Enables verbose mode of deployment tools.} \cmakevariablesince 6.3 -\preliminarycmakevariable Enables verbose mode of the \l androiddeployqt deployment tool when it is called internally at build time, usually during target finalization. @@ -545,7 +544,6 @@ must be set before the first \c{find_package(Qt6)} call to have that effect. \summary {Name of the file to include for setting up deployment support.} \cmakevariablesince 6.3 -\preliminarycmakevariable \note The value of this variable should never be modified by project code. This configure-phase variable is set by the Core package. It is intended to be diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc index 821862494a2..310debf7edc 100644 --- a/src/corelib/doc/src/cmake/cmake-properties.qdoc +++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc @@ -239,7 +239,7 @@ precedence over this CMake property. \badcode set_target_properties(${target} PROPERTIES - QT_ANDROID_COMPILE_SDK_VERSION 35 + QT_ANDROID_COMPILE_SDK_VERSION 36 ) \endcode @@ -247,7 +247,7 @@ The following format also works: \badcode set_target_properties(${target} PROPERTIES - QT_ANDROID_COMPILE_SDK_VERSION "android-35" + QT_ANDROID_COMPILE_SDK_VERSION "android-36" ) \endcode @@ -665,7 +665,6 @@ UTF-8 input). Use the \l QT_NO_CAST_FROM_ASCII and \summary {Specifies the default Qt resource prefix.} \cmakepropertysince 6.0 -\preliminarycmakeproperty When using \l{qt6_add_resources}{qt_add_resources} without a \c PREFIX argument, then the value of this target property will be used as @@ -773,7 +772,6 @@ CMake properties: \brief Sets the FOLDER property for Qt-internal targets. \cmakepropertysince 6.5 -\preliminarycmakeproperty Name of the \l FOLDER for internal targets that are added by Qt's CMake commands. diff --git a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc index 43ff23a35a1..e6d3edbbdc4 100644 --- a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc +++ b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc @@ -17,7 +17,6 @@ can only be called from a deployment script. It cannot be called directly by the project during the configure stage. \cmakecommandsince 6.5 -\preliminarycmakecommand \note This command does not usually need to be called directly. It is used internally by other higher level commands, but projects wishing to implement more customized deployment logic may find it useful. diff --git a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc index 7ec8d90f9b1..24112b1cf87 100644 --- a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc +++ b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc @@ -11,7 +11,6 @@ \summary {Extracts metatypes from a Qt target and generates an associated metatypes.json file.} \cmakecommandsince 6.0 -\preliminarycmakecommand \section1 Synopsis diff --git a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc index 5506712691e..f60b850fcdb 100644 --- a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc +++ b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc @@ -9,7 +9,6 @@ \keyword qt6_finalize_project \summary {Handles various common platform-specific tasks associated with a Qt project.} -\preliminarycmakecommand \include cmake-find-package-core.qdocinc diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc index 874ab807609..38ce2188e13 100644 --- a/src/corelib/doc/src/containers.qdoc +++ b/src/corelib/doc/src/containers.qdoc @@ -275,7 +275,7 @@ The diagram below shows the valid iterator positions as red arrows for a list containing four items: - \image stliterators1.png + \image stliterators1.svg STL-style iterators point to items Iterating backward with an STL-style iterator is done with reverse iterators: diff --git a/src/corelib/doc/src/java-style-iterators.qdoc b/src/corelib/doc/src/java-style-iterators.qdoc index a0e5c53d633..fc1378bb718 100644 --- a/src/corelib/doc/src/java-style-iterators.qdoc +++ b/src/corelib/doc/src/java-style-iterators.qdoc @@ -70,7 +70,7 @@ \l{QListIterator::next()}{next()} and \l{QListIterator::previous()}{previous()} on an iterator: - \image javaiterators2.png Iterating to the next and previous items + \image javaiterators2.svg Iterating to the next and previous items The following table summarizes the QListIterator API: diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 0b42af7686c..b2d79cca603 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -1404,7 +1404,7 @@ static_assert(!std::is_convertible_v<std::nullptr_t, bool>, #if defined(__cplusplus) #ifdef __cpp_constinit -# if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG) +# if defined(Q_CC_MSVC) && _MSC_VER < 1940 && !defined(Q_CC_CLANG) // https://developercommunity.visualstudio.com/t/C:-constinit-for-an-optional-fails-if-/1406069 # define Q_CONSTINIT # else diff --git a/src/corelib/io/qiooperation_p.h b/src/corelib/io/qiooperation_p.h index 56845167ede..1486719a7e8 100644 --- a/src/corelib/io/qiooperation_p.h +++ b/src/corelib/io/qiooperation_p.h @@ -72,6 +72,9 @@ protected: Q_DECLARE_PRIVATE(QIOOperation) friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOReadWriteOperationBase : public QIOOperation @@ -86,6 +89,11 @@ protected: QIOReadWriteOperationBase() = delete; Q_DISABLE_COPY_MOVE(QIOReadWriteOperationBase) explicit QIOReadWriteOperationBase(QIOOperationPrivate &dd, QObject *parent = nullptr); + + friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOReadOperation : public QIOReadWriteOperationBase @@ -101,6 +109,9 @@ protected: explicit QIOReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOWriteOperation : public QIOReadWriteOperationBase @@ -116,6 +127,9 @@ protected: explicit QIOWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOVectoredReadOperation : public QIOReadWriteOperationBase @@ -131,6 +145,9 @@ protected: explicit QIOVectoredReadOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; class Q_CORE_EXPORT QIOVectoredWriteOperation : public QIOReadWriteOperationBase @@ -146,6 +163,9 @@ protected: explicit QIOVectoredWriteOperation(QIOOperationPrivate &dd, QObject *parent = nullptr); friend class QRandomAccessAsyncFilePrivate; + friend class QRandomAccessAsyncFileBackend; + friend class QRandomAccessAsyncFileNativeBackend; + friend class QRandomAccessAsyncFileThreadPoolBackend; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qioring_p.h b/src/corelib/io/qioring_p.h index 0db832bc6bf..8fdaf48f8f6 100644 --- a/src/corelib/io/qioring_p.h +++ b/src/corelib/io/qioring_p.h @@ -91,6 +91,10 @@ enum class Operation : quint8 { // clang-format on Q_ENUM_NS(Operation); #undef DEFINE_ENTRY + +#ifdef Q_OS_WIN +struct IORingApiTable; +#endif }; // namespace QtPrivate template <QtPrivate::Operation Op> @@ -221,9 +225,11 @@ private: std::optional<QWinEventNotifier> notifier; HIORING ioRingHandle = nullptr; HANDLE eventHandle = INVALID_HANDLE_VALUE; + const QtPrivate::IORingApiTable *apiTable; bool initialized = false; bool queueWasFull = false; + [[nodiscard]] RequestPrepResult prepareRequest(GenericRequestType &request); QIORing::ReadWriteStatus handleReadCompletion( diff --git a/src/corelib/io/qioring_win.cpp b/src/corelib/io/qioring_win.cpp index 42c51f428d6..b2f188486d0 100644 --- a/src/corelib/io/qioring_win.cpp +++ b/src/corelib/io/qioring_win.cpp @@ -24,6 +24,59 @@ static_assert(sizeof(qsizetype) > sizeof(UINT32), using namespace Qt::StringLiterals; +namespace QtPrivate { +#define FOREACH_WIN_IORING_FUNCTION(Fn) \ + Fn(BuildIoRingReadFile) \ + Fn(BuildIoRingWriteFile) \ + Fn(BuildIoRingFlushFile) \ + Fn(BuildIoRingCancelRequest) \ + Fn(QueryIoRingCapabilities) \ + Fn(CreateIoRing) \ + Fn(GetIoRingInfo) \ + Fn(SubmitIoRing) \ + Fn(CloseIoRing) \ + Fn(PopIoRingCompletion) \ + Fn(SetIoRingCompletionEvent) \ + /**/ +struct IORingApiTable +{ +#define DefineIORingFunction(Name) \ + using Name##Fn = decltype(&::Name); \ + Name##Fn Name = nullptr; + + FOREACH_WIN_IORING_FUNCTION(DefineIORingFunction) + +#undef DefineIORingFunction +}; + +static const IORingApiTable *getApiTable() +{ + static const IORingApiTable apiTable = []() { + IORingApiTable apiTable; + const HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (Q_UNLIKELY(!kernel32)) // how would this happen + return apiTable; + +#define ResolveFunction(Name) \ + apiTable.Name = IORingApiTable::Name##Fn(QFunctionPointer(GetProcAddress(kernel32, #Name))); + + FOREACH_WIN_IORING_FUNCTION(ResolveFunction) + +#undef ResolveFunction + return apiTable; + }(); + +#define TEST_TABLE_OK(X) \ + apiTable.X && /* chain */ +#define BOOL_CHAIN(...) (__VA_ARGS__ true) + const bool success = BOOL_CHAIN(FOREACH_WIN_IORING_FUNCTION(TEST_TABLE_OK)); +#undef BOOL_CHAIN +#undef TEST_TABLE_OK + + return success ? std::addressof(apiTable) : nullptr; +} +} // namespace QtPrivate + static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan<std::byte> destination, quint64 offset, quintptr userData) { @@ -32,8 +85,10 @@ static HRESULT buildReadOperation(HIORING ioRingHandle, qintptr fd, QSpan<std::b const IORING_BUFFER_REF bufferRef(destination.data()); const auto maxSize = q26::saturate_cast<UINT32>(destination.size()); Q_ASSERT(maxSize == destination.size()); - return BuildIoRingReadFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, userData, - IOSQE_FLAGS_NONE); + const auto *apiTable = QtPrivate::getApiTable(); + Q_ASSERT(apiTable); // If we got this far it needs to be here + return apiTable->BuildIoRingReadFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, + userData, IOSQE_FLAGS_NONE); } static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan<const std::byte> source, @@ -44,16 +99,18 @@ static HRESULT buildWriteOperation(HIORING ioRingHandle, qintptr fd, QSpan<const const IORING_BUFFER_REF bufferRef(const_cast<std::byte *>(source.data())); const auto maxSize = q26::saturate_cast<UINT32>(source.size()); Q_ASSERT(maxSize == source.size()); + const auto *apiTable = QtPrivate::getApiTable(); + Q_ASSERT(apiTable); // If we got this far it needs to be here // @todo: FILE_WRITE_FLAGS can be set to write-through, could be used for Unbuffered mode. - return BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, - FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE); + return apiTable->BuildIoRingWriteFile(ioRingHandle, fileRef, bufferRef, maxSize, offset, + FILE_WRITE_FLAGS_NONE, userData, IOSQE_FLAGS_NONE); } QIORing::~QIORing() { if (initialized) { CloseHandle(eventHandle); - CloseIoRing(ioRingHandle); + apiTable->CloseIoRing(ioRingHandle); } } @@ -62,8 +119,13 @@ bool QIORing::initializeIORing() if (initialized) return true; + if (apiTable = QtPrivate::getApiTable(); !apiTable) { + qCWarning(lcQIORing, "Failed to retrieve API table"); + return false; + } + IORING_CAPABILITIES capabilities; - QueryIoRingCapabilities(&capabilities); + apiTable->QueryIoRingCapabilities(&capabilities); if (capabilities.MaxVersion < IORING_VERSION_3) // 3 adds write, flush and drain return false; if ((capabilities.FeatureFlags & IORING_FEATURE_SET_COMPLETION_EVENT) == 0) @@ -75,7 +137,8 @@ bool QIORing::initializeIORing() IORING_CREATE_FLAGS flags; memset(&flags, 0, sizeof(flags)); - HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, sqEntries, cqEntries, &ioRingHandle); + HRESULT hr = apiTable->CreateIoRing(IORING_VERSION_3, flags, sqEntries, cqEntries, + &ioRingHandle); if (FAILED(hr)) { qErrnoWarning(hr, "failed to initialize QIORing"); return false; @@ -83,7 +146,7 @@ bool QIORing::initializeIORing() auto earlyExitCleanup = qScopeGuard([this]() { if (eventHandle != INVALID_HANDLE_VALUE) CloseHandle(eventHandle); - CloseIoRing(ioRingHandle); + apiTable->CloseIoRing(ioRingHandle); }); eventHandle = CreateEvent(nullptr, TRUE, FALSE, nullptr); if (eventHandle == INVALID_HANDLE_VALUE) { @@ -91,13 +154,13 @@ bool QIORing::initializeIORing() return false; } notifier.emplace(eventHandle); - hr = SetIoRingCompletionEvent(ioRingHandle, eventHandle); + hr = apiTable->SetIoRingCompletionEvent(ioRingHandle, eventHandle); if (FAILED(hr)) { qErrnoWarning(hr, "Failed to assign the event handle to QIORing"); return false; } IORING_INFO info; - if (SUCCEEDED(GetIoRingInfo(ioRingHandle, &info))) { + if (SUCCEEDED(apiTable->GetIoRingInfo(ioRingHandle, &info))) { sqEntries = info.SubmissionQueueSize; cqEntries = info.CompletionQueueSize; qCDebug(lcQIORing) << "QIORing configured with capacity for" << sqEntries @@ -274,7 +337,7 @@ void QIORing::completionReady() { ResetEvent(eventHandle); IORING_CQE entry; - while (PopIoRingCompletion(ioRingHandle, &entry) == S_OK) { + while (apiTable->PopIoRingCompletion(ioRingHandle, &entry) == S_OK) { // NOLINTNEXTLINE(performance-no-int-to-ptr) auto *request = reinterpret_cast<GenericRequestType *>(entry.UserData); if (!addrItMap.contains(request)) { @@ -458,7 +521,8 @@ void QIORing::submitRequests() const bool shouldTryWait = std::exchange(queueWasFull, false); const auto submitToRing = [this, &shouldTryWait] { quint32 submittedEntries = 0; - HRESULT hr = SubmitIoRing(ioRingHandle, shouldTryWait ? 1 : 0, 1, &submittedEntries); + HRESULT hr = apiTable->SubmitIoRing(ioRingHandle, shouldTryWait ? 1 : 0, 1, + &submittedEntries); qCDebug(lcQIORing) << "Submitted" << submittedEntries << "requests"; unstagedRequests -= submittedEntries; if (FAILED(hr)) { @@ -558,9 +622,9 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult auto *closeRequest = request.requestData<Operation::Close>(); // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef(HANDLE(closeRequest->fd)); - hr = BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_MIN_METADATA, - quintptr(std::addressof(request)), - IOSQE_FLAGS_DRAIN_PRECEDING_OPS); + hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_MIN_METADATA, + quintptr(std::addressof(request)), + IOSQE_FLAGS_DRAIN_PRECEDING_OPS); break; } case Operation::Read: { @@ -645,9 +709,9 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult auto *flushRequest = request.requestData<Operation::Flush>(); // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef(HANDLE(flushRequest->fd)); - hr = BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_DEFAULT, - quintptr(std::addressof(request)), - IOSQE_FLAGS_DRAIN_PRECEDING_OPS); + hr = apiTable->BuildIoRingFlushFile(ioRingHandle, fileRef, FILE_FLUSH_DEFAULT, + quintptr(std::addressof(request)), + IOSQE_FLAGS_DRAIN_PRECEDING_OPS); break; } case QtPrivate::Operation::Stat: { @@ -703,8 +767,8 @@ auto QIORing::prepareRequest(GenericRequestType &request) -> RequestPrepResult } // NOLINTNEXTLINE(performance-no-int-to-ptr) const IORING_HANDLE_REF fileRef((HANDLE(fd))); - hr = BuildIoRingCancelRequest(ioRingHandle, fileRef, quintptr(otherOperation), - quintptr(std::addressof(request))); + hr = apiTable->BuildIoRingCancelRequest(ioRingHandle, fileRef, quintptr(otherOperation), + quintptr(std::addressof(request))); break; } case Operation::NumOperations: diff --git a/src/corelib/io/qrandomaccessasyncfile.cpp b/src/corelib/io/qrandomaccessasyncfile.cpp index c544585de9d..34e216efe27 100644 --- a/src/corelib/io/qrandomaccessasyncfile.cpp +++ b/src/corelib/io/qrandomaccessasyncfile.cpp @@ -7,6 +7,31 @@ QT_BEGIN_NAMESPACE +QRandomAccessAsyncFileBackend::QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner) + : m_owner(owner) +{ +} +QRandomAccessAsyncFileBackend::~QRandomAccessAsyncFileBackend() = default; +QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default; + +void QRandomAccessAsyncFilePrivate::init() +{ + Q_Q(QRandomAccessAsyncFile); + +#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN) + m_backend = std::make_unique<QRandomAccessAsyncFileNativeBackend>(q); +#endif + if (!m_backend || !m_backend->init()) { +#if QT_CONFIG(thread) && QT_CONFIG(future) + m_backend = std::make_unique<QRandomAccessAsyncFileThreadPoolBackend>(q); + [[maybe_unused]] + bool result = m_backend->init(); + Q_ASSERT(result); // it always succeeds +#endif + } +} + QRandomAccessAsyncFile::QRandomAccessAsyncFile(QObject *parent) : QObject{*new QRandomAccessAsyncFilePrivate, parent} { diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm index fca225263ba..80c1affa642 100644 --- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm +++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm @@ -27,14 +27,14 @@ static bool isBarrierOperation(QIOOperation::Type type) // only! template <typename Operation, typename ...Args> Operation * -QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args) +QRandomAccessAsyncFileNativeBackend::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args) { auto dataStorage = new QtPrivate::QIOOperationDataStorage(std::forward<Args>(args)...); auto *priv = new QIOOperationPrivate(dataStorage); priv->offset = offset; priv->type = type; - Operation *op = new Operation(*priv, q_ptr); + Operation *op = new Operation(*priv, m_owner); auto opId = getNextId(); m_operations.push_back(OperationInfo(opId, op)); startOperationsUntilBarrier(); @@ -42,19 +42,20 @@ QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offs return op; } -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() - : QObjectPrivate() +QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner) + : QRandomAccessAsyncFileBackend(owner) { } -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() +QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend() = default; -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileNativeBackend::init() { + return true; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op) { auto it = std::find_if(m_operations.cbegin(), m_operations.cend(), [op](const auto &opInfo) { @@ -87,7 +88,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) startOperationsUntilBarrier(); } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileNativeBackend::close() { if (m_fileState == FileState::Closed) return; @@ -125,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fileState = FileState::Closed; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileNativeBackend::size() const { if (m_fileState != FileState::Opened) return -1; @@ -138,7 +139,7 @@ qint64 QRandomAccessAsyncFilePrivate::size() const } QIOOperation * -QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QRandomAccessAsyncFileNativeBackend::open(const QString &path, QIODeviceBase::OpenMode mode) { if (m_fileState == FileState::Closed) { m_filePath = path; @@ -151,44 +152,44 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode return addOperation<QIOOperation>(QIOOperation::Type::Open, 0); } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileNativeBackend::flush() { return addOperation<QIOOperation>(QIOOperation::Type::Flush, 0); } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize) { QByteArray array(maxSize, Qt::Uninitialized); return addOperation<QIOReadOperation>(QIOOperation::Type::Read, offset, std::move(array)); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data) { QByteArray copy = data; return write(offset, std::move(copy)); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data) { return addOperation<QIOWriteOperation>(QIOOperation::Type::Write, offset, std::move(data)); } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { return addOperation<QIOVectoredReadOperation>(QIOOperation::Type::Read, offset, QSpan<const QSpan<std::byte>>{buffer}); } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, QSpan<const QSpan<const std::byte>>{buffer}); } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { // GCD implementation does not have vectored read. Spawning several read // operations (each with an updated offset), is not ideal, because some @@ -202,12 +203,12 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, buffers); } -void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() +void QRandomAccessAsyncFileNativeBackend::notifyIfOperationsAreCompleted() { QMutexLocker locker(&m_mutex); --m_numChannelsToClose; @@ -217,7 +218,7 @@ void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted() } } -dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd) +dispatch_io_t QRandomAccessAsyncFileNativeBackend::createMainChannel(int fd) { auto sharedThis = this; auto channel = @@ -235,7 +236,7 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd) return channel; } -dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId) +dispatch_io_t QRandomAccessAsyncFileNativeBackend::duplicateIoChannel(OperationId opId) { if (!m_ioChannel) return nullptr; @@ -258,13 +259,13 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId return channel; } -void QRandomAccessAsyncFilePrivate::closeIoChannel(dispatch_io_t channel) +void QRandomAccessAsyncFileNativeBackend::closeIoChannel(dispatch_io_t channel) { if (channel) dispatch_io_close(channel, DISPATCH_IO_STOP); } -void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel) +void QRandomAccessAsyncFileNativeBackend::releaseIoChannel(dispatch_io_t channel) { if (channel) { dispatch_release(channel); @@ -272,7 +273,7 @@ void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel) } } -void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResult &opResult) +void QRandomAccessAsyncFileNativeBackend::handleOperationComplete(const OperationResult &opResult) { // try to start next operations on return auto onReturn = qScopeGuard([this] { @@ -379,15 +380,15 @@ void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResul } } -void QRandomAccessAsyncFilePrivate::queueCompletion(OperationId opId, int error) +void QRandomAccessAsyncFileNativeBackend::queueCompletion(OperationId opId, int error) { const OperationResult res = { opId, 0LL, error }; - QMetaObject::invokeMethod(q_ptr, [this, res] { + QMetaObject::invokeMethod(m_owner, [this, res] { handleOperationComplete(res); }, Qt::QueuedConnection); } -void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier() +void QRandomAccessAsyncFileNativeBackend::startOperationsUntilBarrier() { // starts all operations until barrier, or a barrier operation if it's the // first one @@ -421,7 +422,7 @@ void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier() } } -void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeRead(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -452,7 +453,7 @@ void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo) } } -void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeWrite(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -501,7 +502,7 @@ void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo) } } -void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeFlush(OperationInfo &opInfo) { opInfo.channel = duplicateIoChannel(opInfo.opId); if (!opInfo.channel) { @@ -530,7 +531,7 @@ void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo) } } } else { - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, 0LL, err }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { sharedThis->handleOperationComplete(r); @@ -562,7 +563,7 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode) return oflags; } -void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) +void QRandomAccessAsyncFileNativeBackend::executeOpen(OperationInfo &opInfo) { if (m_fileState != FileState::OpenPending) { queueCompletion(opInfo.opId, EINVAL); @@ -603,7 +604,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) Q_ASSERT(sharedThis->m_numChannelsToClose == 0); sharedThis->m_cancellationCondition.wakeOne(); } else { - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, qint64(fd), err }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { @@ -613,7 +614,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo) }); } -void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bufferIdx, +void QRandomAccessAsyncFileNativeBackend::readOneBuffer(OperationId opId, qsizetype bufferIdx, qint64 alreadyRead) { // we need to lookup the operation again, because it could have beed removed @@ -650,7 +651,7 @@ void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bu readBuffers.size(), alreadyRead); } -void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispatch_io_t channel, +void QRandomAccessAsyncFileNativeBackend::readOneBufferHelper(OperationId opId, dispatch_io_t channel, qint64 offset, void *bytesPtr, qint64 maxSize, qsizetype currentBufferIdx, qsizetype totalBuffers, qint64 alreadyRead) @@ -698,7 +699,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat } } else { sharedThis->m_runningOps.remove(opId); - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; // if error, or last buffer, or read less than expected, // report operation completion qint64 totalRead = qint64(readFromBuffer) + alreadyRead; @@ -721,7 +722,7 @@ void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispat }); } -void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t channel, +void QRandomAccessAsyncFileNativeBackend::writeHelper(OperationId opId, dispatch_io_t channel, qint64 offset, dispatch_data_t dataToWrite, qint64 dataSize) { @@ -760,7 +761,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t const size_t written = dataSize - toBeWritten; [dataToWrite release]; - auto context = sharedThis->q_ptr; + auto context = sharedThis->m_owner; const OperationResult res = { opId, qint64(written), error }; QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) { @@ -770,7 +771,7 @@ void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t }); } -QRandomAccessAsyncFilePrivate::OperationId QRandomAccessAsyncFilePrivate::getNextId() +QRandomAccessAsyncFileNativeBackend::OperationId QRandomAccessAsyncFileNativeBackend::getNextId() { // never return reserved values static OperationId opId = kInvalidOperationId; diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h index 11ad788c884..2eb53058780 100644 --- a/src/corelib/io/qrandomaccessasyncfile_p_p.h +++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h @@ -22,7 +22,7 @@ #include <QtCore/qstring.h> -#ifdef QT_RANDOMACCESSASYNCFILE_THREAD +#if QT_CONFIG(future) && QT_CONFIG(thread) #include <QtCore/private/qfsfileengine_p.h> @@ -30,7 +30,7 @@ #include <QtCore/qmutex.h> #include <QtCore/qqueue.h> -#endif // QT_RANDOMACCESSASYNCFILE_THREAD +#endif // future && thread #ifdef Q_OS_DARWIN @@ -50,41 +50,36 @@ QT_BEGIN_NAMESPACE -class QRandomAccessAsyncFilePrivate : public QObjectPrivate +class QRandomAccessAsyncFileBackend { - Q_DECLARE_PUBLIC(QRandomAccessAsyncFile) - Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate) + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileBackend) public: - QRandomAccessAsyncFilePrivate(); - ~QRandomAccessAsyncFilePrivate() override; - - static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file) - { return file->d_func(); } + explicit QRandomAccessAsyncFileBackend(QRandomAccessAsyncFile *owner); + virtual ~QRandomAccessAsyncFileBackend(); - void init(); - void cancelAndWait(QIOOperation *op); + virtual bool init() = 0; + virtual void cancelAndWait(QIOOperation *op) = 0; - void close(); - qint64 size() const; + virtual void close() = 0; + virtual qint64 size() const = 0; - [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode); - [[nodiscard]] QIOOperation *flush(); + [[nodiscard]] virtual QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) = 0; + [[nodiscard]] virtual QIOOperation *flush() = 0; - [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize); - [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data); - [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data); + [[nodiscard]] virtual QIOReadOperation *read(qint64 offset, qint64 maxSize) = 0; + [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, const QByteArray &data) = 0; + [[nodiscard]] virtual QIOWriteOperation *write(qint64 offset, QByteArray &&data) = 0; - [[nodiscard]] QIOVectoredReadOperation * - readInto(qint64 offset, QSpan<std::byte> buffer); - [[nodiscard]] QIOVectoredWriteOperation * - writeFrom(qint64 offset, QSpan<const std::byte> buffer); - - [[nodiscard]] QIOVectoredReadOperation * - readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers); - [[nodiscard]] QIOVectoredWriteOperation * - writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers); + [[nodiscard]] virtual QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) = 0; + [[nodiscard]] virtual QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) = 0; -private: + [[nodiscard]] virtual QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) = 0; + [[nodiscard]] virtual QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) = 0; +protected: // common for all backends enum class FileState : quint8 { @@ -94,32 +89,131 @@ private: }; QString m_filePath; + QRandomAccessAsyncFile *m_owner = nullptr; QIODeviceBase::OpenMode m_openMode; FileState m_fileState = FileState::Closed; +}; -#ifdef QT_RANDOMACCESSASYNCFILE_THREAD +class QRandomAccessAsyncFilePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QRandomAccessAsyncFile) + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFilePrivate) public: - struct OperationResult + QRandomAccessAsyncFilePrivate(); + ~QRandomAccessAsyncFilePrivate() override; + + static QRandomAccessAsyncFilePrivate *get(QRandomAccessAsyncFile *file) + { return file->d_func(); } + + void init(); + void cancelAndWait(QIOOperation *op) { - qint64 bytesProcessed; // either read or written - QIOOperation::Error error; - }; + checkValid(); + m_backend->cancelAndWait(op); + } + + void close() + { + checkValid(); + m_backend->close(); + } + qint64 size() const + { + checkValid(); + return m_backend->size(); + } + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) + { + checkValid(); + return m_backend->open(path, mode); + } + [[nodiscard]] QIOOperation *flush() + { + checkValid(); + return m_backend->flush(); + } + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) + { + checkValid(); + return m_backend->read(offset, maxSize); + } + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) + { + checkValid(); + return m_backend->write(offset, data); + } + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) + { + checkValid(); + return m_backend->write(offset, std::move(data)); + } + + [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset, QSpan<std::byte> buffer) + { + checkValid(); + return m_backend->readInto(offset, buffer); + } + [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset, QSpan<const std::byte> buffer) + { + checkValid(); + return m_backend->writeFrom(offset, buffer); + } + + [[nodiscard]] QIOVectoredReadOperation *readInto(qint64 offset, + QSpan<const QSpan<std::byte>> buffers) + { + checkValid(); + return m_backend->readInto(offset, buffers); + } + [[nodiscard]] QIOVectoredWriteOperation *writeFrom(qint64 offset, + QSpan<const QSpan<const std::byte>> buffers) + { + checkValid(); + return m_backend->writeFrom(offset, buffers); + } private: - mutable QBasicMutex m_engineMutex; - std::unique_ptr<QFSFileEngine> m_engine; - QFutureWatcher<OperationResult> m_watcher; + void checkValid() const { Q_ASSERT(m_backend); } + std::unique_ptr<QRandomAccessAsyncFileBackend> m_backend; - QQueue<QPointer<QIOOperation>> m_operations; - QPointer<QIOOperation> m_currentOperation; - qsizetype numProcessedBuffers = 0; +}; - void executeNextOperation(); - void processBufferAt(qsizetype idx); - void processFlush(); - void processOpen(); - void operationComplete(); -#elif defined(QT_RANDOMACCESSASYNCFILE_QIORING) + +#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) || defined(Q_OS_DARWIN) +class QRandomAccessAsyncFileNativeBackend final : public QRandomAccessAsyncFileBackend +{ + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileNativeBackend) +public: + explicit QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner); + ~QRandomAccessAsyncFileNativeBackend(); + + bool init() override; + void cancelAndWait(QIOOperation *op) override; + + void close() override; + qint64 size() const override; + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override; + [[nodiscard]] QIOOperation *flush() override; + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override; + +private: +#if defined(QT_RANDOMACCESSASYNCFILE_QIORING) void queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error); void startReadIntoSingle(QIOOperation *op, const QSpan<std::byte> &to); void startWriteFromSingle(QIOOperation *op, const QSpan<const std::byte> &from); @@ -210,6 +304,61 @@ private: dispatch_data_t dataToWrite, qint64 dataSize); #endif }; +#endif // QIORing || macOS + +#if QT_CONFIG(future) && QT_CONFIG(thread) +class QRandomAccessAsyncFileThreadPoolBackend : public QRandomAccessAsyncFileBackend +{ + Q_DISABLE_COPY_MOVE(QRandomAccessAsyncFileThreadPoolBackend) +public: + explicit QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner); + ~QRandomAccessAsyncFileThreadPoolBackend(); + + bool init() override; + void cancelAndWait(QIOOperation *op) override; + + void close() override; + qint64 size() const override; + + [[nodiscard]] QIOOperation *open(const QString &path, QIODeviceBase::OpenMode mode) override; + [[nodiscard]] QIOOperation *flush() override; + + [[nodiscard]] QIOReadOperation *read(qint64 offset, qint64 maxSize) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, const QByteArray &data) override; + [[nodiscard]] QIOWriteOperation *write(qint64 offset, QByteArray &&data) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<std::byte> buffer) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const std::byte> buffer) override; + + [[nodiscard]] QIOVectoredReadOperation * + readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) override; + [[nodiscard]] QIOVectoredWriteOperation * + writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) override; + + struct OperationResult + { + qint64 bytesProcessed; // either read or written + QIOOperation::Error error; + }; +private: + + mutable QBasicMutex m_engineMutex; + std::unique_ptr<QFSFileEngine> m_engine; + QFutureWatcher<OperationResult> m_watcher; + + QQueue<QPointer<QIOOperation>> m_operations; + QPointer<QIOOperation> m_currentOperation; + qsizetype numProcessedBuffers = 0; + + void executeNextOperation(); + void processBufferAt(qsizetype idx); + void processFlush(); + void processOpen(); + void operationComplete(); +}; +#endif // future && thread QT_END_NAMESPACE diff --git a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp index c9783ea2856..8e1145325d8 100644 --- a/src/corelib/io/qrandomaccessasyncfile_qioring.cpp +++ b/src/corelib/io/qrandomaccessasyncfile_qioring.cpp @@ -18,18 +18,21 @@ QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcQRandomAccessIORing, "qt.core.qrandomaccessasyncfile.ioring", QtCriticalMsg); -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFileNativeBackend::QRandomAccessAsyncFileNativeBackend(QRandomAccessAsyncFile *owner) + : QRandomAccessAsyncFileBackend(owner) +{} -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() = default; +QRandomAccessAsyncFileNativeBackend::~QRandomAccessAsyncFileNativeBackend() = default; -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileNativeBackend::init() { m_ioring = QIORing::sharedInstance(); if (!m_ioring) - qCCritical(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize"); + qCWarning(lcQRandomAccessIORing, "QRandomAccessAsyncFile: ioring failed to initialize"); + return m_ioring != nullptr; } -QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHandle handle) +QIORing::RequestHandle QRandomAccessAsyncFileNativeBackend::cancel(QIORing::RequestHandle handle) { if (handle) { QIORingRequest<QIORing::Operation::Cancel> cancelRequest; @@ -39,7 +42,7 @@ QIORing::RequestHandle QRandomAccessAsyncFilePrivate::cancel(QIORing::RequestHan return nullptr; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileNativeBackend::cancelAndWait(QIOOperation *op) { auto *opHandle = m_opHandleMap.value(op); if (auto *handle = cancel(opHandle)) { @@ -48,7 +51,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) } } -void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error) +void QRandomAccessAsyncFileNativeBackend::queueCompletion(QIOOperationPrivate *priv, QIOOperation::Error error) { // Remove the handle now in case the user cancels or deletes the io-operation // before operationComplete is called - the null-handle will protect from @@ -61,14 +64,14 @@ void QRandomAccessAsyncFilePrivate::queueCompletion(QIOOperationPrivate *priv, Q }, Qt::QueuedConnection); } -QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QIOOperation *QRandomAccessAsyncFileNativeBackend::open(const QString &path, QIODeviceBase::OpenMode mode) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Open; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); if (m_fileState != FileState::Closed) { queueCompletion(priv, QIOOperation::Error::Open); return op; @@ -115,7 +118,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::open(const QString &path, QIODevice return op; } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileNativeBackend::close() { // all the operations should be aborted const auto ops = std::exchange(m_operations, {}); @@ -123,7 +126,7 @@ void QRandomAccessAsyncFilePrivate::close() // Request to cancel all of the in-flight operations: for (const auto &op : ops) { if (op) { - op->d_func()->error = QIOOperation::Error::Aborted; + QIOOperationPrivate::get(op)->error = QIOOperation::Error::Aborted; if (auto *opHandle = m_opHandleMap.value(op)) { tasksToAwait.append(cancel(opHandle)); tasksToAwait.append(opHandle); @@ -142,7 +145,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fd = -1; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileNativeBackend::size() const { QIORingRequest<QIORing::Operation::Stat> statRequest; statRequest.fd = m_fd; @@ -161,14 +164,14 @@ qint64 QRandomAccessAsyncFilePrivate::size() const return finalSize; } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileNativeBackend::flush() { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Flush; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); QIORingRequest<QIORing::Operation::Flush> flushRequest; @@ -192,7 +195,7 @@ QIOOperation *QRandomAccessAsyncFilePrivate::flush() return op; } -void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op, +void QRandomAccessAsyncFileNativeBackend::startReadIntoSingle(QIOOperation *op, const QSpan<std::byte> &to) { QIORingRequest<QIORing::Operation::Read> readRequest; @@ -231,7 +234,7 @@ void QRandomAccessAsyncFilePrivate::startReadIntoSingle(QIOOperation *op, m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(readRequest))); } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileNativeBackend::read(qint64 offset, qint64 maxSize) { QByteArray array; array.resizeForOverwrite(maxSize); @@ -241,7 +244,7 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOReadOperation(*priv, q_ptr); + auto *op = new QIOReadOperation(*priv, m_owner); m_operations.append(op); startReadIntoSingle(op, as_writable_bytes(QSpan(dataStorage->getByteArray()))); @@ -249,12 +252,12 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS return op; } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, const QByteArray &data) { return write(offset, QByteArray(data)); } -void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op, +void QRandomAccessAsyncFileNativeBackend::startWriteFromSingle(QIOOperation *op, const QSpan<const std::byte> &from) { QIORingRequest<QIORing::Operation::Write> writeRequest; @@ -288,7 +291,7 @@ void QRandomAccessAsyncFilePrivate::startWriteFromSingle(QIOOperation *op, m_opHandleMap.insert(priv->q_func(), m_ioring->queueRequest(std::move(writeRequest))); } -QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QIOWriteOperation *QRandomAccessAsyncFileNativeBackend::write(qint64 offset, QByteArray &&data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data)); @@ -296,7 +299,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); startWriteFromSingle(op, as_bytes(QSpan(dataStorage->getByteArray()))); @@ -304,7 +307,7 @@ QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArra return op; } -QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, +QIOVectoredReadOperation *QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage( @@ -314,7 +317,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); startReadIntoSingle(op, dataStorage->getReadSpans().first()); @@ -322,7 +325,7 @@ QIOVectoredReadOperation *QRandomAccessAsyncFilePrivate::readInto(qint64 offset, return op; } -QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, +QIOVectoredWriteOperation *QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage( @@ -332,7 +335,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); startWriteFromSingle(op, dataStorage->getWriteSpans().first()); @@ -341,7 +344,7 @@ QIOVectoredWriteOperation *QRandomAccessAsyncFilePrivate::writeFrom(qint64 offse } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredRead)) return nullptr; @@ -351,7 +354,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now queueCompletion(priv, QIOOperation::Error::IncorrectOffset); return op; @@ -393,7 +396,7 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileNativeBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { if (!QIORing::supportsOperation(QtPrivate::Operation::VectoredWrite)) return nullptr; @@ -403,7 +406,7 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); if (priv->offset < 0) { // The QIORing offset is unsigned, so error out now queueCompletion(priv, QIOOperation::Error::IncorrectOffset); return op; diff --git a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp index 4ebcf554655..774fbadc5ad 100644 --- a/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp +++ b/src/corelib/io/qrandomaccessasyncfile_threadpool.cpp @@ -64,28 +64,29 @@ static SharedThreadPool asyncFileThreadPool; } // anonymous namespace -QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate() : - QObjectPrivate() +QRandomAccessAsyncFileThreadPoolBackend::QRandomAccessAsyncFileThreadPoolBackend(QRandomAccessAsyncFile *owner) : + QRandomAccessAsyncFileBackend(owner) { asyncFileThreadPool.ref(); } -QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate() +QRandomAccessAsyncFileThreadPoolBackend::~QRandomAccessAsyncFileThreadPoolBackend() { asyncFileThreadPool.deref(); } -void QRandomAccessAsyncFilePrivate::init() +bool QRandomAccessAsyncFileThreadPoolBackend::init() { - QObject::connect(&m_watcher, &QFutureWatcherBase::finished, q_ptr, [this]{ + QObject::connect(&m_watcher, &QFutureWatcherBase::finished, m_owner, [this]{ operationComplete(); }); - QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, q_ptr, [this]{ + QObject::connect(&m_watcher, &QFutureWatcherBase::canceled, m_owner, [this]{ operationComplete(); }); + return true; } -void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) +void QRandomAccessAsyncFileThreadPoolBackend::cancelAndWait(QIOOperation *op) { if (op == m_currentOperation) { m_currentOperation = nullptr; // to discard the result @@ -97,7 +98,7 @@ void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op) } QIOOperation * -QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode) +QRandomAccessAsyncFileThreadPoolBackend::open(const QString &path, QIODeviceBase::OpenMode mode) { // We generate the command in any case. But if the file is already opened, // it will finish with an error @@ -112,14 +113,14 @@ QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Open; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -void QRandomAccessAsyncFilePrivate::close() +void QRandomAccessAsyncFileThreadPoolBackend::close() { // all the operations should be aborted for (const auto &op : std::as_const(m_operations)) { @@ -148,7 +149,7 @@ void QRandomAccessAsyncFilePrivate::close() m_fileState = FileState::Closed; } -qint64 QRandomAccessAsyncFilePrivate::size() const +qint64 QRandomAccessAsyncFileThreadPoolBackend::size() const { QMutexLocker locker(&m_engineMutex); if (m_engine) @@ -156,20 +157,20 @@ qint64 QRandomAccessAsyncFilePrivate::size() const return -1; } -QIOOperation *QRandomAccessAsyncFilePrivate::flush() +QIOOperation *QRandomAccessAsyncFileThreadPoolBackend::flush() { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(); auto *priv = new QIOOperationPrivate(dataStorage); priv->type = QIOOperation::Type::Flush; - auto *op = new QIOOperation(*priv, q_ptr); + auto *op = new QIOOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize) +QIOReadOperation *QRandomAccessAsyncFileThreadPoolBackend::read(qint64 offset, qint64 maxSize) { QByteArray array; array.resizeForOverwrite(maxSize); @@ -179,14 +180,14 @@ QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxS priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOReadOperation(*priv, q_ptr); + auto *op = new QIOReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOWriteOperation * -QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) +QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, const QByteArray &data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(data); @@ -194,14 +195,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data) priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOWriteOperation * -QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) +QRandomAccessAsyncFileThreadPoolBackend::write(qint64 offset, QByteArray &&data) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(std::move(data)); @@ -209,14 +210,14 @@ QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data) priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOWriteOperation(*priv, q_ptr); + auto *op = new QIOWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) +QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<std::byte>>{buffer}); @@ -225,14 +226,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer) priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer) +QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const std::byte> buffer) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(QSpan<const QSpan<const std::byte>>{buffer}); @@ -241,14 +242,14 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> b priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredReadOperation * -QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) +QRandomAccessAsyncFileThreadPoolBackend::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); @@ -256,14 +257,14 @@ QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::by priv->offset = offset; priv->type = QIOOperation::Type::Read; - auto *op = new QIOVectoredReadOperation(*priv, q_ptr); + auto *op = new QIOVectoredReadOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } QIOVectoredWriteOperation * -QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) +QRandomAccessAsyncFileThreadPoolBackend::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers) { auto *dataStorage = new QtPrivate::QIOOperationDataStorage(buffers); @@ -271,16 +272,16 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const priv->offset = offset; priv->type = QIOOperation::Type::Write; - auto *op = new QIOVectoredWriteOperation(*priv, q_ptr); + auto *op = new QIOVectoredWriteOperation(*priv, m_owner); m_operations.append(op); executeNextOperation(); return op; } -static QRandomAccessAsyncFilePrivate::OperationResult +static QRandomAccessAsyncFileThreadPoolBackend::OperationResult executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buffer, qint64 maxSize) { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutex); if (engine) { @@ -299,11 +300,11 @@ executeRead(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, char *buff return result; } -static QRandomAccessAsyncFilePrivate::OperationResult +static QRandomAccessAsyncFileThreadPoolBackend::OperationResult executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, const char *buffer, qint64 size) { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutex); if (engine) { @@ -322,7 +323,7 @@ executeWrite(QFSFileEngine *engine, QBasicMutex *mutex, qint64 offset, return result; } -void QRandomAccessAsyncFilePrivate::executeNextOperation() +void QRandomAccessAsyncFileThreadPoolBackend::executeNextOperation() { if (m_currentOperation.isNull()) { // start next @@ -351,7 +352,7 @@ void QRandomAccessAsyncFilePrivate::executeNextOperation() } } -void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx) +void QRandomAccessAsyncFileThreadPoolBackend::processBufferAt(qsizetype idx) { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -417,7 +418,7 @@ void QRandomAccessAsyncFilePrivate::processBufferAt(qsizetype idx) } } -void QRandomAccessAsyncFilePrivate::processFlush() +void QRandomAccessAsyncFileThreadPoolBackend::processFlush() { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -427,7 +428,7 @@ void QRandomAccessAsyncFilePrivate::processFlush() QBasicMutex *mutexPtr = &m_engineMutex; auto op = [engine = m_engine.get(), mutexPtr] { QMutexLocker locker(mutexPtr); - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; if (engine) { if (!engine->flush()) result.error = QIOOperation::Error::Flush; @@ -442,7 +443,7 @@ void QRandomAccessAsyncFilePrivate::processFlush() m_watcher.setFuture(f); } -void QRandomAccessAsyncFilePrivate::processOpen() +void QRandomAccessAsyncFileThreadPoolBackend::processOpen() { Q_ASSERT(!m_currentOperation.isNull()); auto *priv = QIOOperationPrivate::get(m_currentOperation.get()); @@ -457,7 +458,7 @@ void QRandomAccessAsyncFilePrivate::processOpen() m_engineMutex.unlock(); QBasicMutex *mutexPtr = &m_engineMutex; auto op = [engine = m_engine.get(), mutexPtr, mode = m_openMode] { - QRandomAccessAsyncFilePrivate::OperationResult result{0, QIOOperation::Error::None}; + QRandomAccessAsyncFileThreadPoolBackend::OperationResult result{0, QIOOperation::Error::None}; QMutexLocker locker(mutexPtr); const bool res = engine && engine->open(mode | QIODeviceBase::Unbuffered, std::nullopt); @@ -468,13 +469,13 @@ void QRandomAccessAsyncFilePrivate::processOpen() f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), op); } else { f = QtFuture::makeReadyVoidFuture().then(asyncFileThreadPool(), [] { - return QRandomAccessAsyncFilePrivate::OperationResult{0, QIOOperation::Error::Open}; + return QRandomAccessAsyncFileThreadPoolBackend::OperationResult{0, QIOOperation::Error::Open}; }); } m_watcher.setFuture(f); } -void QRandomAccessAsyncFilePrivate::operationComplete() +void QRandomAccessAsyncFileThreadPoolBackend::operationComplete() { // TODO: if one of the buffers was read/written with an error, // stop processing immediately diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index c960e11f6bb..8b0a05ee6ed 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1390,7 +1390,7 @@ void QAbstractItemModel::resetInternalData() simple table of rows and columns. Each item has a unique index specified by a QModelIndex. - \image modelindex-no-parent.png {Screenshot showing a 3x3 grid with numbered + \image modelindex-no-parent.svg {Diagram showing a 3x3 grid with numbered rows and columns that shows the cell at row 1, column 2 highlighted.} Every item of data that can be accessed via a model has an associated model @@ -2867,7 +2867,7 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare \table 80% \row - \li \inlineimage modelview-begin-insert-rows.png Inserting rows + \li \inlineimage modelview-begin-insert-rows.svg Inserting rows \li Specify the first and last row numbers for the span of rows you want to insert into an item in a model. @@ -2878,7 +2878,7 @@ bool QAbstractItemModel::decodeData(int row, int column, const QModelIndex &pare This inserts the three new rows as rows 2, 3, and 4. \row - \li \inlineimage modelview-begin-append-rows.png Appending rows + \li \inlineimage modelview-begin-append-rows.svg Appending rows \li To append rows, insert them after the last row. For example, as shown in the diagram, we append two rows to a @@ -2934,7 +2934,7 @@ void QAbstractItemModel::endInsertRows() \table 80% \row - \li \inlineimage modelview-begin-remove-rows.png Removing rows + \li \inlineimage modelview-begin-remove-rows.svg Removing rows \li Specify the first and last row numbers for the span of rows you want to remove from an item in a model. @@ -3055,7 +3055,7 @@ void QAbstractItemModelPrivate::executePendingOperations() const { } \table 80% \row - \li \inlineimage modelview-move-rows-1.png Moving rows to another parent + \li \inlineimage modelview-move-rows-1.svg Moving rows to another parent \li Specify the first and last row numbers for the span of rows in the source parent you want to move in the model. Also specify the row in the destination parent to move the span to. @@ -3069,7 +3069,7 @@ void QAbstractItemModelPrivate::executePendingOperations() const { } This moves the three rows rows 2, 3, and 4 in the source to become 2, 3 and 4 in the destination. Other affected siblings are displaced accordingly. \row - \li \inlineimage modelview-move-rows-2.png Moving rows to append to another parent + \li \inlineimage modelview-move-rows-2.svg Moving rows to append to another parent \li To append rows to another parent, move them to after the last row. For example, as shown in the diagram, we move three rows to a @@ -3079,7 +3079,7 @@ void QAbstractItemModelPrivate::executePendingOperations() const { } This moves the target rows to the end of the target parent as 6, 7 and 8. \row - \li \inlineimage modelview-move-rows-3.png Moving rows in the same parent up + \li \inlineimage modelview-move-rows-3.svg Moving rows in the same parent up \li To move rows within the same parent, specify the row to move them to. For example, as shown in the diagram, we move one item from row 2 to row 0, @@ -3094,7 +3094,7 @@ void QAbstractItemModelPrivate::executePendingOperations() const { } it is already) \row - \li \inlineimage modelview-move-rows-4.png Moving rows in the same parent down + \li \inlineimage modelview-move-rows-4.svg Moving rows in the same parent down \li To move rows within the same parent, specify the row to move them to. For example, as shown in the diagram, we move one item from row 2 to row 4, @@ -3176,7 +3176,7 @@ void QAbstractItemModel::endMoveRows() \table 80% \row - \li \inlineimage modelview-begin-insert-columns.png Inserting columns + \li \inlineimage modelview-begin-insert-columns.svg Inserting columns \li Specify the first and last column numbers for the span of columns you want to insert into an item in a model. @@ -3187,7 +3187,7 @@ void QAbstractItemModel::endMoveRows() This inserts the three new columns as columns 4, 5, and 6. \row - \li \inlineimage modelview-begin-append-columns.png Appending columns + \li \inlineimage modelview-begin-append-columns.svg Appending columns \li To append columns, insert them after the last column. For example, as shown in the diagram, we append three columns to a @@ -3245,7 +3245,7 @@ void QAbstractItemModel::endInsertColumns() \table 80% \row - \li \inlineimage modelview-begin-remove-columns.png Removing columns + \li \inlineimage modelview-begin-remove-columns.svg Removing columns \li Specify the first and last column numbers for the span of columns you want to remove from an item in a model. diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp index f7edf3285f8..25a27a0c22b 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm.cpp +++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp @@ -150,6 +150,18 @@ bool QEventDispatcherWasm::isValidEventDispatcherPointer(QEventDispatcherWasm *e bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags) { + // Accept the current event if event handling recurses / event loop is reentered, + // to prevent the browser from propagating it to other event handlers. + if (useAsyncify() && isMainThreadEventDispatcher()) { + auto control = QWasmSuspendResumeControl::get(); + auto currentEvent = control->currentEvent(); + if (!currentEvent.isUndefined() && currentEvent.instanceof(emscripten::val::global("Event"))) { + currentEvent.call<void>("preventDefault"); + currentEvent.call<void>("stopPropagation"); + control->setCurrentEvent(emscripten::val::undefined()); + } + } + emit awake(); if (!useAsyncify() && isMainThreadEventDispatcher()) diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h index 674af85dac2..1946bf63ede 100644 --- a/src/corelib/kernel/qeventdispatcher_wasm_p.h +++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h @@ -40,7 +40,6 @@ public: ~QEventDispatcherWasm(); bool processEvents(QEventLoop::ProcessEventsFlags flags) override; - bool sendAllEvents(QEventLoop::ProcessEventsFlags flag); void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) override final; @@ -69,6 +68,7 @@ protected: virtual bool sendPostedEvents(); private: + bool sendAllEvents(QEventLoop::ProcessEventsFlags flag); bool isMainThreadEventDispatcher(); bool isSecondaryThreadEventDispatcher(); bool isValidEventDispatcher(); diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h index c9d3a6bf9c6..66047afefd4 100644 --- a/src/corelib/kernel/qmetacontainer.h +++ b/src/corelib/kernel/qmetacontainer.h @@ -971,18 +971,11 @@ public: Iterator mutableEnd(); QVariant at(qsizetype idx) const; - void set(qsizetype idx, const QVariant &value); + void setAt(qsizetype idx, const QVariant &value); void append(const QVariant &value); void prepend(const QVariant &value); void removeLast(); void removeFirst(); - -#if QT_DEPRECATED_SINCE(6, 11) - enum Position: quint8 { Unspecified, AtBegin, AtEnd }; - void addValue(const QVariant &value, Position position = Unspecified); - void removeValue(Position position = Unspecified); - QMetaType valueMetaType() const; -#endif // QT_DEPRECATED_SINCE(6, 11) }; #else using Iterable = QtMetaContainerPrivate::Sequence; diff --git a/src/corelib/kernel/qmetasequence.cpp b/src/corelib/kernel/qmetasequence.cpp index 2a3a923d5ca..018dd610146 100644 --- a/src/corelib/kernel/qmetasequence.cpp +++ b/src/corelib/kernel/qmetasequence.cpp @@ -531,39 +531,6 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con */ /*! - \enum QMetaSequence::Iterable::Position - \deprecated [6.11] Use append(), prepend(), removeFirst(), or removeLast() - - Specifies the position at which an element shall be added to or removed from - the iterable. - - \value AtBegin - Add or remove at the beginning of the iterable. - \value AtEnd - Add or remove at the end of the iterable. - \value Unspecified - Add or remove at an unspecified position in the iterable. - */ - -/*! - \fn void QMetaSequence::Iterable::addValue(const QVariant &value, Position position) - \deprecated [6.11] Use append() or prepend() - Adds \a value to the container, at \a position, if possible. - */ - -/*! - \deprecated [6.11] Use removeFirst() or removeLast() - \fn void QMetaSequence::Iterable::removeValue(Position position) - Removes a value from the container, at \a position, if possible. - */ - -/*! - \deprecated [6.11] Use QMetaSequence::valueMetaType() - \fn QMetaType QMetaSequence::Iterable::valueMetaType() const - Returns the meta type for values stored in the underlying container. - */ - -/*! \fn QVariant QMetaSequence::Iterable::at(qsizetype idx) const Returns the value at position \a idx in the container. @@ -574,13 +541,8 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con */ /*! - \fn void QMetaSequence::Iterable::set(qsizetype idx, const QVariant &value) + \fn void QMetaSequence::Iterable::setAt(qsizetype idx, const QVariant &value) Sets the element at position \a idx in the container to \a value. - - \note If the underlying container does not provide a native way to assign - an element at an index, this method will synthesize the assignment - using iterators. This behavior is deprecated and will be removed in a - future version of Qt. */ /*! diff --git a/src/corelib/kernel/qmetasequence.h b/src/corelib/kernel/qmetasequence.h index 26156e7924f..f8052476d79 100644 --- a/src/corelib/kernel/qmetasequence.h +++ b/src/corelib/kernel/qmetasequence.h @@ -196,25 +196,11 @@ public: }); } - void set(qsizetype idx, const QVariant &value) + void setAt(qsizetype idx, const QVariant &value) { const QMetaSequence meta = metaContainer(); QtPrivate::QVariantTypeCoercer coercer; - const void *dataPtr = coercer.coerce(value, meta.valueMetaType()); - if (meta.canSetValueAtIndex()) { - meta.setValueAtIndex(mutableIterable(), idx, dataPtr); - return; - } - -#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) - // We shouldn't second-guess the underlying container - QtPrivate::warnSynthesizedAccess( - "set() called on an iterable without native indexed accessors. This is slow"); - void *it = meta.begin(m_iterable.mutablePointer()); - meta.advanceIterator(it, idx); - meta.setValueAtIterator(it, dataPtr); - meta.destroyIterator(it); -#endif + meta.setValueAtIndex(mutableIterable(), idx, coercer.coerce(value, meta.valueMetaType())); } void append(const QVariant &value) @@ -261,6 +247,9 @@ public: QMetaType valueMetaType() const Q_DECL_EQ_DELETE_X("Use QMetaSequence::valueMetaType() instead."); + void set(qsizetype idx, const QVariant &value) + Q_DECL_EQ_DELETE_X("Use setAt() instead."); + QT_WARNING_POP #endif // QT_DEPRECATED_SINCE(6, 11) }; diff --git a/src/corelib/platform/wasm/qwasmlocalfileengine.cpp b/src/corelib/platform/wasm/qwasmlocalfileengine.cpp new file mode 100644 index 00000000000..58e662d5fde --- /dev/null +++ b/src/corelib/platform/wasm/qwasmlocalfileengine.cpp @@ -0,0 +1,422 @@ +// Copyright (C) 2025 Qt Group +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "qwasmlocalfileengine_p.h" +#include <QtCore/QDebug> +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +using namespace Qt::StringLiterals; + +// Custom URL scheme for files handled by this file engine. A complete file URL can +// look like +// +// "weblocalfile:/n/file.ext" +// +// where n is a counter to ensure uniqueness, needed since web platform gives us the file name only +// and does not provide the file path. +// +// The scheme may be visible to end users if the application displays it, so +// we avoid using "wasm" and instead say "web", which should be more recognizable. +static constexpr QLatin1StringView wasmlocalfileScheme = "weblocalfile"_L1; + +// Instantiate the engine, the system will pick it up automatically +// Never destroy it to avoid problems with static destruction. +// The OS will reclaim the memory anyway, +// TODO: cleanup on QApplication destruction and re-init on QApplication re-creation. +static QWasmFileEngineHandler *singleton = new QWasmFileEngineHandler(); + +QWasmFileEngineHandler::QWasmFileEngineHandler() +{ +} + +QWasmFileEngineHandler::~QWasmFileEngineHandler() +{ +} + +std::unique_ptr<QAbstractFileEngine> QWasmFileEngineHandler::create(const QString &fileName) const +{ + if (!QWasmFileEngineHandler::isWasmFileName(fileName)) + return {}; + + // Check if it's a File or FileSystemFileHandle + if (singleton->m_files.contains(fileName)) { + qstdweb::File file = singleton->m_files.value(fileName); + return std::make_unique<QWasmFileEngine>(fileName, file); + } else if (singleton->m_fileSystemFiles.contains(fileName)) { + qstdweb::FileSystemFileHandle file = singleton->m_fileSystemFiles.value(fileName); + return std::make_unique<QWasmFileEngine>(fileName, file); + } + + // Not an error, this function will be called with partial paths like "weblocalfile:/1/" + return {}; +} + +// Check if this is a wasm filename by checking the URL scheme. +bool QWasmFileEngineHandler::isWasmFileName(const QString& fileName) +{ + return QUrl(fileName).scheme() == wasmlocalfileScheme; +} + +// Creates a wasm filename using the custom URL scheme and a counter. +QString QWasmFileEngineHandler::makeWasmFileName(const QString &nativeFileName) +{ + static std::atomic<uint64_t> sid = 0; + const uint64_t id = ++sid; + return wasmlocalfileScheme + QStringLiteral(":/%1/%2").arg(id).arg(nativeFileName); +} + +// Extracts the native filename from the custom URL (removes scheme and counter). +QString QWasmFileEngineHandler::nativeFileName(const QString &wasmFileName) +{ + QUrl url(wasmFileName); + if (url.scheme() == wasmlocalfileScheme) { + QString path = url.path(); + // Path is "/n/filename", find the second '/' and extract the filename + const qsizetype idx = path.indexOf(u'/', 1); + if (idx != -1) + return path.mid(idx + 1); + } + return wasmFileName; +} + +// Adds a File to the set of open files. Returns a prefixed wasm file name. +QString QWasmFileEngineHandler::addFile(qstdweb::File file) +{ + QString nativeFileName = QString::fromStdString(file.name()); + QString wasmFileName = makeWasmFileName(nativeFileName); + singleton->m_files.insert(wasmFileName, file); + return wasmFileName; +} + +// Adds a FileSystemFileHandle to the set of open files. Returns a prefixed wasm file name. +QString QWasmFileEngineHandler::addFile(qstdweb::FileSystemFileHandle file) +{ + QString nativeFileName = QString::fromStdString(file.name()); + QString wasmFileName = makeWasmFileName(nativeFileName); + singleton->m_fileSystemFiles.insert(wasmFileName, file); + return wasmFileName; +} + +// Removes a File or FileSystemFileHandle from the set of open file handlers +void QWasmFileEngineHandler::removeFile(const QString fileName) +{ + singleton->m_files.remove(fileName); + singleton->m_fileSystemFiles.remove(fileName); +} + +qstdweb::File QWasmFileEngineHandler::getFile(const QString fileName) +{ + return singleton->m_files.value(fileName); +} + +qstdweb::FileSystemFileHandle QWasmFileEngineHandler::getFileSystemFile(const QString fileName) +{ + return singleton->m_fileSystemFiles.value(fileName); +} + +/*! + \class QWasmFileEngine + \brief The QWasmFileEngine class provides a QAbstractFileEngine + for files that has the prefix ':weblocalfile/'. +*/ + +// Constructs a QWasmFileEngine with a File for read-only access +QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::File file) + : m_fileName(fileName), + m_blobDevice(std::make_unique<qstdweb::BlobIODevice>(file.slice(0, file.size()))) +{ + // TODO use m_blobDevice in unbuffered mode? if there is already a buffer higher up. +} + +// Constructs a QWasmFileEngine with a FileSystemFileHandle for read-write access +QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::FileSystemFileHandle file) + : m_fileName(fileName), + m_fileDevice(std::make_unique<qstdweb::FileSystemFileIODevice>(file)) +{ + +} + +QWasmFileEngine::~QWasmFileEngine() +{ + close(); +} + +bool QWasmFileEngine::open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) +{ + Q_UNUSED(permissions); + m_openMode = openMode; + + if (m_fileDevice) + return m_fileDevice->open(openMode); + else if (m_blobDevice) + return m_blobDevice->open(openMode); + + return false; +} + +bool QWasmFileEngine::close() +{ + if (m_openMode == QIODevice::NotOpen) + return false; + + bool success = true; + if (m_fileDevice) { + m_fileDevice->close(); + } + if (m_blobDevice) { + m_blobDevice->close(); + } + + m_openMode = QIODevice::NotOpen; + return success; +} + +bool QWasmFileEngine::flush() +{ + return true; +} + +bool QWasmFileEngine::syncToDisk() +{ + return true; +} + +qint64 QWasmFileEngine::size() const +{ + if (m_fileDevice) + return m_fileDevice->size(); + if (m_blobDevice) + return m_blobDevice->size(); + return 0; +} + +qint64 QWasmFileEngine::pos() const +{ + if (m_fileDevice) + return m_fileDevice->pos(); + if (m_blobDevice) + return m_blobDevice->pos(); + return 0; +} + +bool QWasmFileEngine::seek(qint64 pos) +{ + if (m_fileDevice) + return m_fileDevice->seek(pos); + if (m_blobDevice) + return m_blobDevice->seek(pos); + return false; +} + +bool QWasmFileEngine::isSequential() const +{ + return false; +} + +bool QWasmFileEngine::remove() +{ + return false; +} + +bool QWasmFileEngine::copy(const QString &newName) +{ + Q_UNUSED(newName); + return false; +} + +bool QWasmFileEngine::rename(const QString &newName) +{ + Q_UNUSED(newName); + return false; +} + +bool QWasmFileEngine::renameOverwrite(const QString &newName) +{ + Q_UNUSED(newName); + return false; +} + +bool QWasmFileEngine::link(const QString &newName) +{ + Q_UNUSED(newName); + return false; +} + +bool QWasmFileEngine::mkdir(const QString &dirName, bool createParentDirectories, + std::optional<QFile::Permissions> permissions) const +{ + Q_UNUSED(dirName); + Q_UNUSED(createParentDirectories); + Q_UNUSED(permissions); + return false; +} + +bool QWasmFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const +{ + Q_UNUSED(dirName); + Q_UNUSED(recurseParentDirectories); + return false; +} + +bool QWasmFileEngine::setSize(qint64 size) +{ + Q_UNUSED(size); + return false; +} + +bool QWasmFileEngine::caseSensitive() const +{ + return true; +} + +bool QWasmFileEngine::isRelativePath() const +{ + return false; +} + + +QAbstractFileEngine::FileFlags QWasmFileEngine::fileFlags(FileFlags type) const +{ + return type & (QAbstractFileEngine::FileFlag::ExistsFlag | + QAbstractFileEngine::FileFlag::FileType | + QAbstractFileEngine::FileFlag::ReadOwnerPerm | + QAbstractFileEngine::FileFlag::WriteOwnerPerm); +} + +bool QWasmFileEngine::setPermissions(uint perms) +{ + Q_UNUSED(perms); + return false; +} + +QByteArray QWasmFileEngine::id() const +{ + return {}; +} + +QString QWasmFileEngine::fileName(FileName file) const +{ + switch (file) { + case DefaultName: + case AbsoluteName: + case CanonicalName: + return m_fileName; + case BaseName: { + QString native = QWasmFileEngineHandler::nativeFileName(m_fileName); + QFileInfo info(native); + return info.fileName(); + } + case PathName: + case AbsolutePathName: + case CanonicalPathName: { + QString native = QWasmFileEngineHandler::nativeFileName(m_fileName); + QFileInfo info(native); + QString path = info.path(); + return path.isEmpty() ? "."_L1 : path; + } + default: + return QString(); + } +} + +uint QWasmFileEngine::ownerId(FileOwner) const +{ + return 0; +} + +QString QWasmFileEngine::owner(FileOwner) const +{ + return {}; +} + +bool QWasmFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time) +{ + Q_UNUSED(newDate); + Q_UNUSED(time); + return false; +} + +QDateTime QWasmFileEngine::fileTime(QFile::FileTime time) const +{ + Q_UNUSED(time); + return {}; +} + +void QWasmFileEngine::setFileName(const QString &file) +{ + if (m_fileName == file) + return; + close(); + m_fileName = file; +} + +int QWasmFileEngine::handle() const +{ + return -1; +} + +QAbstractFileEngine::TriStateResult QWasmFileEngine::cloneTo(QAbstractFileEngine *target) +{ + Q_UNUSED(target); + return QAbstractFileEngine::TriStateResult::NotSupported; +} + +QAbstractFileEngine::IteratorUniquePtr QWasmFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) +{ + Q_UNUSED(path); + Q_UNUSED(filters); + Q_UNUSED(filterNames); + return nullptr; +} + +qint64 QWasmFileEngine::read(char *data, qint64 maxlen) +{ + if (!(m_openMode & QIODevice::ReadOnly)) + return -1; + + if (m_fileDevice) + return m_fileDevice->read(data, maxlen); + if (m_blobDevice) + return m_blobDevice->read(data, maxlen); + return -1; +} + +qint64 QWasmFileEngine::readLine(char *data, qint64 maxlen) +{ + if (!(m_openMode & QIODevice::ReadOnly)) + return -1; + + if (m_fileDevice) + return m_fileDevice->readLine(data, maxlen); + if (m_blobDevice) + return m_blobDevice->readLine(data, maxlen); + return -1; +} + +qint64 QWasmFileEngine::write(const char *data, qint64 len) +{ + if (!(m_openMode & QIODevice::WriteOnly)) + return -1; + + if (m_fileDevice) + return m_fileDevice->write(data, len); + return -1; +} + +bool QWasmFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) +{ + Q_UNUSED(extension); + Q_UNUSED(option); + Q_UNUSED(output); + return false; +} + +bool QWasmFileEngine::supportsExtension(Extension extension) const +{ + Q_UNUSED(extension); + return false; +} + +QT_END_NAMESPACE diff --git a/src/corelib/platform/wasm/qwasmlocalfileengine_p.h b/src/corelib/platform/wasm/qwasmlocalfileengine_p.h new file mode 100644 index 00000000000..dd82788dd90 --- /dev/null +++ b/src/corelib/platform/wasm/qwasmlocalfileengine_p.h @@ -0,0 +1,102 @@ +// Copyright (C) 2024 Qt Group +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#ifndef QWASMLOCALFILEENGINE_P_H +#define QWASMLOCALFILEENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/private/qabstractfileengine_p.h> +#include <QtCore/private/qstdweb_p.h> + +QT_BEGIN_NAMESPACE + +class QWasmFileEngine; + +class QWasmFileEngineHandler: public QAbstractFileEngineHandler +{ +public: + Q_DISABLE_COPY_MOVE(QWasmFileEngineHandler) + + QWasmFileEngineHandler(); + virtual ~QWasmFileEngineHandler() override; + virtual std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override; + + static bool isWasmFileName(const QString& fileName); + static QString makeWasmFileName(const QString &fileName); + static QString nativeFileName(const QString &wasmFileName); + + static QString addFile(qstdweb::File file); + static QString addFile(qstdweb::FileSystemFileHandle file); + static void removeFile(const QString fileName); + qstdweb::File getFile(const QString fileName); + qstdweb::FileSystemFileHandle getFileSystemFile(const QString fileName); + +private: + QHash<QString, qstdweb::File> m_files; + QHash<QString, qstdweb::FileSystemFileHandle> m_fileSystemFiles; +}; + +class QWasmFileEngine: public QAbstractFileEngine +{ +public: + explicit QWasmFileEngine(const QString &fileName, qstdweb::File file); + explicit QWasmFileEngine(const QString &fileName, qstdweb::FileSystemFileHandle file); + ~QWasmFileEngine() override; + + virtual bool open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions) override; + virtual bool close() override; + virtual bool flush() override; + virtual bool syncToDisk() override; + virtual qint64 size() const override; + virtual qint64 pos() const override; + virtual bool seek(qint64 pos) override; + virtual bool isSequential() const override; + virtual bool remove() override; + virtual bool copy(const QString &newName) override; + virtual bool rename(const QString &newName) override; + virtual bool renameOverwrite(const QString &newName) override; + virtual bool link(const QString &newName) override; + virtual bool mkdir(const QString &dirName, bool createParentDirectories, + std::optional<QFile::Permissions> permissions = std::nullopt) const override; + virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const override; + virtual bool setSize(qint64 size) override; + virtual bool caseSensitive() const override; + virtual bool isRelativePath() const override; + virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const override; + virtual bool setPermissions(uint perms) override; + virtual QByteArray id() const override; + virtual QString fileName(FileName file = DefaultName) const override; + virtual uint ownerId(FileOwner) const override; + virtual QString owner(FileOwner) const override; + virtual bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override; + virtual QDateTime fileTime(QFile::FileTime time) const override; + virtual void setFileName(const QString &file) override; + virtual int handle() const override; + virtual TriStateResult cloneTo(QAbstractFileEngine *target) override; + virtual IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, + const QStringList &filterNames) override; + virtual qint64 read(char *data, qint64 maxlen) override; + virtual qint64 readLine(char *data, qint64 maxlen) override; + virtual qint64 write(const char *data, qint64 len) override; + virtual bool extension(Extension extension, const ExtensionOption *option = nullptr, + ExtensionReturn *output = nullptr) override; + virtual bool supportsExtension(Extension extension) const override; + +private: + QString m_fileName; + QIODevice::OpenMode m_openMode = QIODevice::NotOpen; + std::unique_ptr<qstdweb::BlobIODevice> m_blobDevice; + std::unique_ptr<qstdweb::FileSystemFileIODevice> m_fileDevice; +}; + +QT_END_NAMESPACE +#endif // QWASMFILEENGINEHANDLER_H diff --git a/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp b/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp index a4bc7843380..85358d1daf4 100644 --- a/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp +++ b/src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp @@ -225,8 +225,11 @@ int QWasmSuspendResumeControl::sendPendingEvents() pendingEvents.call<void>("splice", i, 1); auto it = m_eventHandlers.find(event["index"].as<int>()); - if (it != m_eventHandlers.end()) - it->second(event["arg"]); + if (it != m_eventHandlers.end()) { + setCurrentEvent(event["arg"]); + it->second(currentEvent()); + setCurrentEvent(emscripten::val::undefined()); + } ++count; } } diff --git a/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h b/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h index ff97ff3d7ea..4e75d5674be 100644 --- a/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h +++ b/src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h @@ -42,12 +42,22 @@ public: void suspendExclusive(QList<uint32_t> eventHandlerIndices); int sendPendingEvents(); + emscripten::val currentEvent() const + { + return m_currentEvent; + } + void setCurrentEvent(emscripten::val currentEvent) + { + m_currentEvent = currentEvent; + } + private: friend void qtSendPendingEvents(); static QWasmSuspendResumeControl *s_suspendResumeControl; std::map<int, std::function<void(emscripten::val)>> m_eventHandlers; std::function<bool(int)> m_eventFilter = [](int) { return true; }; + emscripten::val m_currentEvent = emscripten::val::undefined(); }; class Q_CORE_EXPORT QWasmEventHandler diff --git a/src/corelib/text/qregularexpression.cpp b/src/corelib/text/qregularexpression.cpp index 5cc8e8681bb..0c65e18ec10 100644 --- a/src/corelib/text/qregularexpression.cpp +++ b/src/corelib/text/qregularexpression.cpp @@ -952,7 +952,7 @@ void QRegularExpressionPrivate::getPatternInfo() namespace { struct PcreJitStackFree { - void operator()(pcre2_jit_stack_16 *stack) + void operator()(pcre2_jit_stack_16 *stack) const { if (stack) pcre2_jit_stack_free_16(stack); diff --git a/src/corelib/text/qstringconverter_p.h b/src/corelib/text/qstringconverter_p.h index 3ac60ce8c70..3923c2f302f 100644 --- a/src/corelib/text/qstringconverter_p.h +++ b/src/corelib/text/qstringconverter_p.h @@ -334,6 +334,7 @@ struct QUtf8 static char16_t *convertToUnicode(char16_t *dst, QByteArrayView in, QStringConverter::State *state); + Q_CORE_EXPORT static char *convertFromUnicode(char *dst, QStringView in) noexcept; Q_CORE_EXPORT static QByteArray convertFromUnicode(QStringView in); Q_CORE_EXPORT static QByteArray convertFromUnicode(QStringView in, QStringConverter::State *state); diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index f3f32e20adc..5e97086694b 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -786,7 +786,7 @@ between the second and third result, and returns the second result; and so on. - \image javaiterators1.png + \image javaiterators1.svg Here's how to iterate over the elements in reverse order: diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index ce35e8ccffe..1e647a83dc0 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -333,12 +333,12 @@ struct TCBPoint qreal _b; - bool operator==(const TCBPoint &other) const + friend bool operator==(const TCBPoint &lhs, const TCBPoint &rhs) noexcept { - return _point == other._point && - qFuzzyCompare(_t, other._t) && - qFuzzyCompare(_c, other._c) && - qFuzzyCompare(_b, other._b); + return qFuzzyCompare(lhs._point, rhs._point) + && QtPrivate::fuzzyCompare(lhs._t, rhs._t) + && QtPrivate::fuzzyCompare(lhs._c, rhs._c) + && QtPrivate::fuzzyCompare(lhs._b, rhs._b); } }; Q_DECLARE_TYPEINFO(TCBPoint, Q_PRIMITIVE_TYPE); |
