summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/CMakeLists.txt1
-rw-r--r--src/corelib/configure.cmake2
-rw-r--r--src/corelib/doc/images/modelview-begin-append-columns.svg80
-rw-r--r--src/corelib/doc/images/modelview-begin-append-rows.svg66
-rw-r--r--src/corelib/doc/images/modelview-begin-insert-columns.svg91
-rw-r--r--src/corelib/doc/images/modelview-begin-insert-rows.svg82
-rw-r--r--src/corelib/doc/images/modelview-begin-remove-columns.svg91
-rw-r--r--src/corelib/doc/images/modelview-begin-remove-rows.svg76
-rw-r--r--src/corelib/doc/images/modelview-move-rows-1.svg169
-rw-r--r--src/corelib/doc/images/modelview-move-rows-2.svg169
-rw-r--r--src/corelib/doc/images/modelview-move-rows-3.svg108
-rw-r--r--src/corelib/doc/images/modelview-move-rows-4.svg108
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp20
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp12
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm_p.h2
-rw-r--r--src/corelib/platform/wasm/qwasmlocalfileengine.cpp422
-rw-r--r--src/corelib/platform/wasm/qwasmlocalfileengine_p.h102
-rw-r--r--src/corelib/platform/wasm/qwasmsuspendresumecontrol.cpp7
-rw-r--r--src/corelib/platform/wasm/qwasmsuspendresumecontrol_p.h10
-rw-r--r--src/corelib/text/qstringconverter_p.h1
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp38
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess_p.h7
-rw-r--r--src/network/kernel/qauthenticator.cpp2
-rw-r--r--src/network/kernel/qauthenticator.h2
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp79
-rw-r--r--src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp157
-rw-r--r--src/plugins/platforms/wasm/qwasmfiledialoghelper.h49
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp13
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h3
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/tools/bootstrap/CMakeLists.txt4
-rw-r--r--src/widgets/widgets/qlcdnumber.cpp14
34 files changed, 1931 insertions, 61 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 539ad753ca6..e50838730cb 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -1533,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/configure.cmake b/src/corelib/configure.cmake
index 7274b51cc0a..0f717ff2ae0 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -812,7 +812,7 @@ qt_feature("winsdkicu" 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
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/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index c960e11f6bb..58a057009ff 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -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/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/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/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
index 051e2b1a04e..8d06821d4c1 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
@@ -285,6 +285,44 @@ void saveFile(const char *content, size_t size, const std::string &fileNameHint)
});
}
+void showOpenFileDialog(const std::string &accept,
+ const std::function<void (bool accepted, std::vector<qstdweb::File> files)> fileDialogClosed)
+{
+ FileDialog::showOpen(makeFilterList(accept), FileSelectMode::MultipleFiles, {
+ .thenFunc = [=](emscripten::val result) {
+ if (result.isUndefined() || result.isNull()) {
+ fileDialogClosed(false, std::vector<qstdweb::File>());
+ } else {
+ std::vector<qstdweb::File> files;
+ int length = result["length"].as<int>();
+ files.reserve(length);
+ for (int i = 0; i < length; ++i) {
+ emscripten::val fileVal = result[i];
+ if (!fileVal.isUndefined() && !fileVal.isNull()) {
+ files.push_back(qstdweb::File(fileVal));
+ }
+ }
+ fileDialogClosed(true, files);
+ }
+ },
+ .catchFunc = [=](emscripten::val) {
+ fileDialogClosed(false, std::vector<qstdweb::File>());
+ }
+ });
+}
+
+void showSaveFileDialog(const std::string &fileNameHint, const std::function<void (bool accepted, qstdweb::FileSystemFileHandle fileHandle)> fileDialogClosed)
+{
+ FileDialog::showSave(fileNameHint, {
+ .thenFunc = [=](emscripten::val result) {
+ fileDialogClosed(true, qstdweb::FileSystemFileHandle(result));
+ },
+ .catchFunc = [=](emscripten::val) {
+ fileDialogClosed(false, qstdweb::FileSystemFileHandle());
+ }
+ });
+}
+
} // namespace QWasmLocalFileAccess
QT_END_NAMESPACE
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
index 77b14577f7e..5597746a5f3 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
@@ -16,6 +16,7 @@
//
#include <private/qglobal_p.h>
+#include <private/qstdweb_p.h>
#include <cstdint>
#include <functional>
@@ -38,6 +39,12 @@ Q_CORE_EXPORT void openFile(const std::string &accept,
Q_CORE_EXPORT void saveFile(const QByteArray &data, const std::string &fileNameHint);
Q_CORE_EXPORT void saveFile(const char *content, size_t size, const std::string &fileNameHint);
+Q_CORE_EXPORT void showOpenFileDialog(const std::string &accept,
+ const std::function<void (bool accepted, std::vector<qstdweb::File> files)> fileDialogClosed);
+Q_CORE_EXPORT void showSaveFileDialog(const std::string &fileNameHint,
+ const std::function<void (bool accepted, qstdweb::FileSystemFileHandle fileHandle)> fileDialogClosed);
+
+
} // namespace QWasmLocalFileAccess
QT_END_NAMESPACE
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 2ef1c31ce1c..7be1d7fe3aa 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -365,7 +365,7 @@ bool QAuthenticator::isNull() const
state.
*/
-void QAuthenticator::clear() noexcept
+void QAuthenticator::clear()
{
*d = QAuthenticatorPrivate();
d->phase = QAuthenticatorPrivate::Done;
diff --git a/src/network/kernel/qauthenticator.h b/src/network/kernel/qauthenticator.h
index db309fb87ad..c4993ff0fc7 100644
--- a/src/network/kernel/qauthenticator.h
+++ b/src/network/kernel/qauthenticator.h
@@ -44,7 +44,7 @@ public:
bool isNull() const;
void detach();
- void clear() noexcept;
+ void clear();
private:
friend class QAuthenticatorPrivate;
QAuthenticatorPrivate *d;
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 03cb0d52ca1..7e9beb7e832 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -33,6 +33,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
qwasminputcontext.cpp qwasminputcontext.h
qwasmwindowstack.h
+ qwasmfiledialoghelper.cpp qwasmfiledialoghelper.h
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
index 71efcee7887..eefd18154aa 100644
--- a/src/plugins/platforms/wasm/qwasmdom.cpp
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -10,6 +10,7 @@
#include <QtCore/qrect.h>
#include <QtGui/qimage.h>
#include <private/qstdweb_p.h>
+#include <private/qwasmlocalfileengine_p.h>
#include <QtCore/qurl.h>
#include <utility>
@@ -112,11 +113,14 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
m_callback(mimeData);
- // Delete files; we expect that the user callback reads/copies
- // file content before returning.
- // Fixme: tie file lifetime to lifetime of the QMimeData?
- for (QUrl fileUrl: fileUrls)
- QFile(fileUrl.toLocalFile()).remove();
+ // Delete temporary files; we expect that the user callback reads/copies
+ // file content before returning.// Fixme: tie file lifetime to lifetime of the QMimeData?
+ // Note: QWasmFileEngine files (weblocalfile://) are managed by QWasmFileEngine
+ // and are not deleted here
+ for (QUrl fileUrl: fileUrls) {
+ if (!QWasmFileEngineHandler::isWasmFileName(fileUrl.toString()))
+ QFile(fileUrl.toLocalFile()).remove();
+ }
delete this;
}
@@ -144,49 +148,56 @@ void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
case ItemKind::File: {
qstdweb::File webfile(item.call<emscripten::val>("getAsFile"));
- if (webfile.size() > 1e+9) { // limit file size to 1 GB
- qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ // Add a file access url for the local file. If asyncify is available,
+ // add a QWasmFileEngine managed url. Else fall back to placing a copy
+ // of the file at /tmp on Emsripten's in-memory file system.
+ if (qstdweb::haveAsyncify()) {
+ QUrl fileUrl(QWasmFileEngineHandler::addFile(webfile));
+ mimeContext->fileUrls.append(fileUrl);
mimeContext->deref();
- continue;
- }
+ } else {
+ // Limit in-memory file size to 1 GB
+ if (webfile.size() > 1e+9) {
+ qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ mimeContext->deref();
+ continue;
+ }
- QString mimeFormat = QString::fromStdString(webfile.type());
- QString fileName = QString::fromStdString(webfile.name());
+ // Read file content
+ QByteArray fileContent(webfile.size(), Qt::Uninitialized);
+ webfile.stream(fileContent.data(), [=]() {
+ QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
+ qtTmpDir.mkpath(qtTmpDir.path());
+
+ QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
+ mimeContext->fileUrls.append(fileUrl);
+
+ QFile file(fileUrl.toLocalFile());
+ if (!file.open(QFile::WriteOnly)) {
+ qWarning() << "File was not opened";
+ mimeContext->deref();
+ return;
+ }
+ if (file.write(fileContent) < 0)
+ qWarning() << "Write failed";
+ file.close();
+ mimeContext->deref();
+ });
- // there's a file, now read it
- QByteArray fileContent(webfile.size(), Qt::Uninitialized);
- webfile.stream(fileContent.data(), [=]() {
-
// If we get a single file, and that file is an image, then
// try to decode the image data. This handles the case where
// image data (i.e. not an image file) is pasted. The browsers
// will then create a fake "image.png" file which has the image
- // data. As a side effect Qt will also decode the image for
+ // data. As a side effect Qt will also decode the image for
// single-image-file drops, since there is no way to differentiate
// the fake "image.png" from a real one.
+ QString mimeFormat = QString::fromStdString(webfile.type());
if (fileCount == 1 && mimeFormat.contains("image/")) {
QImage image;
if (image.loadFromData(fileContent))
mimeContext->mimeData->setImageData(image);
}
-
- QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
- qtTmpDir.mkpath(qtTmpDir.path());
-
- QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
- mimeContext->fileUrls.append(fileUrl);
-
- QFile file(fileUrl.toLocalFile());
- if (!file.open(QFile::WriteOnly)) {
- qWarning() << "File was not opened";
- mimeContext->deref();
- return;
- }
- if (file.write(fileContent) < 0)
- qWarning() << "Write failed";
- file.close();
- mimeContext->deref();
- });
+ }
break;
}
case ItemKind::String:
diff --git a/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp b/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp
new file mode 100644
index 00000000000..1e6e2b1f644
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfiledialoghelper.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmfiledialoghelper.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QUrl>
+#include <QtGui/private/qwasmlocalfileaccess_p.h>
+#include <QtCore/private/qwasmlocalfileengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QWasmFileDialogHelper::QWasmFileDialogHelper()
+ : m_eventLoop(nullptr)
+{
+
+}
+
+QWasmFileDialogHelper::~QWasmFileDialogHelper()
+{
+
+}
+
+bool QWasmFileDialogHelper::defaultNameFilterDisables() const
+{
+ return false;
+}
+
+void QWasmFileDialogHelper::setDirectory(const QUrl &directory)
+{
+ Q_UNUSED(directory)
+}
+
+QUrl QWasmFileDialogHelper::directory() const
+{
+ return QUrl();
+}
+
+void QWasmFileDialogHelper::selectFile(const QUrl &file)
+{
+ m_selectedFiles.clear();
+ m_selectedFiles.append(file);
+}
+
+QList<QUrl> QWasmFileDialogHelper::selectedFiles() const
+{
+ return m_selectedFiles;
+}
+
+void QWasmFileDialogHelper::setFilter()
+{
+
+}
+
+void QWasmFileDialogHelper::selectNameFilter(const QString &filter)
+{
+ Q_UNUSED(filter);
+ // TODO
+}
+
+QString QWasmFileDialogHelper::selectedNameFilter() const
+{
+ return QString();
+}
+
+void QWasmFileDialogHelper::exec()
+{
+ QEventLoop eventLoop;
+ m_eventLoop = &eventLoop;
+ eventLoop.exec();
+ m_eventLoop = nullptr;
+}
+
+bool QWasmFileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ Q_UNUSED(flags)
+ Q_UNUSED(modality)
+ Q_UNUSED(parent)
+ showFileDialog();
+ return true;
+}
+
+void QWasmFileDialogHelper::hide()
+{
+
+}
+
+void QWasmFileDialogHelper::showFileDialog()
+{
+ if (options()->acceptMode() == QFileDialogOptions::AcceptOpen) {
+ // Use name filters from options
+ QString nameFilter = options()->nameFilters().join(";;");
+ if (nameFilter.isEmpty())
+ nameFilter = "*";
+
+ QWasmLocalFileAccess::showOpenFileDialog(nameFilter.toStdString(), [this](bool accepted, std::vector<qstdweb::File> files) {
+ onOpenDialogClosed(accepted, files);
+ });
+ } else if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
+ QString suggestion = m_selectedFiles.isEmpty() ? QString() : QUrl(m_selectedFiles.first()).fileName();
+ m_selectedFiles.clear();
+
+ QWasmLocalFileAccess::showSaveFileDialog(suggestion.toStdString(), [this](bool accepted, qstdweb::FileSystemFileHandle file){
+ onSaveDialogClosed(accepted, file);
+ });
+ }
+}
+
+void QWasmFileDialogHelper::onOpenDialogClosed(bool accepted, std::vector<qstdweb::File> files)
+{
+ m_selectedFiles.clear();
+
+ if (!accepted) {
+ emit reject();
+ return;
+ }
+
+ // Track opened files
+ for (const auto &file : files) {
+ QString wasmFileName = QWasmFileEngineHandler::addFile(file);
+ QUrl fileUrl(wasmFileName);
+ m_selectedFiles.append(fileUrl);
+ }
+
+ // Emit signals
+ if (m_selectedFiles.size() > 0) {
+ emit fileSelected(m_selectedFiles.first());
+ emit filesSelected(m_selectedFiles);
+ }
+ emit accept();
+
+ // exit exec() if in exec()
+ if (m_eventLoop)
+ m_eventLoop->quit();
+}
+
+void QWasmFileDialogHelper::onSaveDialogClosed(bool accepted, qstdweb::FileSystemFileHandle file)
+{
+ if (!accepted) {
+ emit reject();
+ return;
+ }
+
+ // Track save file
+ QString wasmFileName = QWasmFileEngineHandler::addFile(file);
+ QUrl fileUrl(wasmFileName);
+ m_selectedFiles.append(fileUrl);
+
+ // Emit signals
+ emit fileSelected(m_selectedFiles.first());
+ emit accept();
+
+ if (m_eventLoop)
+ m_eventLoop->quit();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfiledialoghelper.h b/src/plugins/platforms/wasm/qwasmfiledialoghelper.h
new file mode 100644
index 00000000000..c5a5b57e518
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmfiledialoghelper.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMFILEDIALOGHELPER_H
+#define QWASMFILEDIALOGHELPER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QUrl>
+#include <QtCore/QEventLoop>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtGui/private/qwasmlocalfileaccess_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmFileDialogHelper : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+public:
+ QWasmFileDialogHelper();
+ ~QWasmFileDialogHelper();
+public:
+ virtual void exec() override;
+ virtual bool show(Qt::WindowFlags windowFlags,
+ Qt::WindowModality windowModality,
+ QWindow *parent) override;
+ virtual void hide() override;
+ virtual bool defaultNameFilterDisables() const override;
+ virtual void setDirectory(const QUrl &directory) override;
+ virtual QUrl directory() const override;
+ virtual void selectFile(const QUrl &filename) override;
+ virtual QList<QUrl> selectedFiles() const override;
+ virtual void setFilter() override;
+ virtual void selectNameFilter(const QString &filter) override;
+ virtual QString selectedNameFilter() const override;
+ static QStringList cleanFilterList(const QString &filter);
+signals:
+ void fileDone(const QUrl &);
+private:
+ void showFileDialog();
+ void onOpenDialogClosed(bool accepted, std::vector<qstdweb::File> files);
+ void onSaveDialogClosed(bool accepted, qstdweb::FileSystemFileHandle file);
+
+ QList<QUrl> m_selectedFiles;
+ QEventLoop *m_eventLoop;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMFILEDIALOGHELPER_H
diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp
index b9340f31275..b1e5c208c6c 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.cpp
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmtheme.h"
+#include "qwasmfiledialoghelper.h"
#include <QtCore/qvariant.h>
#include <QFontDatabase>
#include <QList>
@@ -127,6 +128,18 @@ const QFont *QWasmTheme::font(Font type) const
return nullptr;
}
+bool QWasmTheme::usePlatformNativeDialog(DialogType type) const
+{
+ return (type == DialogType::FileDialog);
+}
+
+QPlatformDialogHelper *QWasmTheme::createPlatformDialogHelper(DialogType type) const
+{
+ if (type == DialogType::FileDialog)
+ return new QWasmFileDialogHelper();
+ return nullptr;
+}
+
void QWasmTheme::onColorSchemeChange()
{
auto colorScheme = getColorSchemeFromMedia();
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
index 4eaad874c76..8b8dd6ebd97 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.h
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -57,6 +57,9 @@ public:
Qt::ContrastPreference contrastPreference() const override;
QVariant themeHint(ThemeHint hint) const override;
const QFont *font(Font type) const override;
+ bool usePlatformNativeDialog(DialogType type) const override;
+ QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+
QFont *fixedFont = nullptr;
void onColorSchemeChange();
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index 6e8bd46ca58..7f1dd7eb34c 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -925,7 +925,7 @@ bool QWasmWindow::deliverPointerEvent(const PointerEvent &event)
std::back_inserter(touchPointList),
[](const QWindowSystemInterface::TouchPoint &val) { return val; });
- if (event.type == EventType::PointerUp)
+ if (event.type == EventType::PointerUp || event.type == EventType::PointerCancel)
m_pointerIdToTouchPoints.remove(event.pointerId);
return event.type == EventType::PointerCancel
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 2816982b1a8..9459e8bdfd3 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -848,7 +848,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
// make mouse events fall through this window
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
if (flagsIn & Qt::WindowTransparentForInput)
- exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
+ exStyle |= WS_EX_TRANSPARENT;
// Currently only compatible with D3D surfaces, use it with care.
if (qEnvironmentVariableIntValue("QT_QPA_DISABLE_REDIRECTION_SURFACE"))
diff --git a/src/tools/bootstrap/CMakeLists.txt b/src/tools/bootstrap/CMakeLists.txt
index e6f920dcf32..c12475d69af 100644
--- a/src/tools/bootstrap/CMakeLists.txt
+++ b/src/tools/bootstrap/CMakeLists.txt
@@ -220,6 +220,10 @@ target_link_libraries(Bootstrap PRIVATE PlatformCommonInternal)
qt_internal_apply_gc_binaries(Bootstrap PUBLIC)
set_target_properties(Bootstrap PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF)
qt_internal_add_target_aliases(Bootstrap)
+qt_internal_add_target_optimized_flags_for_debug_config_in_current_scope(Bootstrap)
+qt_internal_enable_optimized_tools_lto(Bootstrap)
+qt_internal_workaround_static_lib_gcc_lto_issue(Bootstrap)
+
qt_set_msvc_cplusplus_options(Bootstrap PUBLIC)
qt_set_common_target_properties(Bootstrap)
qt_internal_apply_intel_cet(Bootstrap PUBLIC)
diff --git a/src/widgets/widgets/qlcdnumber.cpp b/src/widgets/widgets/qlcdnumber.cpp
index 2c4b4e334d5..ac8e00af95e 100644
--- a/src/widgets/widgets/qlcdnumber.cpp
+++ b/src/widgets/widgets/qlcdnumber.cpp
@@ -5,6 +5,7 @@
#include "qlcdnumber.h"
#include "qbitarray.h"
+#include "qnumeric.h"
#include "qpainter.h"
#include "private/qframe_p.h"
@@ -110,22 +111,17 @@ public:
*/
-static QString int2string(int num, int base, int ndigits, bool *oflow)
+static QString int2string(int number, int base, int ndigits, bool *oflow)
{
QString s;
- bool negative;
- if (num < 0) {
- negative = true;
- num = -num;
- } else {
- negative = false;
- }
+ const bool negative = number < 0;
+ const uint num = QtPrivate::qUnsignedAbs(number);
switch(base) {
case QLCDNumber::Hex:
s = QString::asprintf("%*x", ndigits, num);
break;
case QLCDNumber::Dec:
- s = QString::asprintf("%*i", ndigits, num);
+ s = QString::asprintf("%*u", ndigits, num);
break;
case QLCDNumber::Oct:
s = QString::asprintf("%*o", ndigits, num);