changeset 32535:dd5ece3664ed stable

update Qt and Qsci sources for scanning text for translation * libgui/languages/build_ts/octave-qsci/*: updated source files from Qscintilla * libgui/languages/build_ts/octave-qt/*.: updated source files from Qt * libgui/languages/build_ts/update_external_sources: script for updating above mentioned source files from user defined directories
author Torsten Lilge <ttl-octave@mailbox.org>
date Mon, 04 Dec 2023 19:55:32 +0100
parents 97e55a21cd20
children 189360f2a7e0 f3df7a95ff16
files libgui/languages/build_ts/octave-qsci/Qsci/qsciabstractapis.h libgui/languages/build_ts/octave-qsci/Qsci/qsciapis.h libgui/languages/build_ts/octave-qsci/Qsci/qscicommand.h libgui/languages/build_ts/octave-qsci/Qsci/qscicommandset.h libgui/languages/build_ts/octave-qsci/Qsci/qscidocument.h libgui/languages/build_ts/octave-qsci/Qsci/qsciglobal.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexer.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexeravs.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbash.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbatch.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercmake.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercoffeescript.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercpp.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercsharp.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercss.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexercustom.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerd.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerdiff.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexeredifact.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran77.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerhtml.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexeridl.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjava.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjavascript.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjson.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerlua.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexermakefile.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexermarkdown.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexermatlab.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexeroctave.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpascal.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerperl.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpo.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpostscript.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpov.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerproperties.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpython.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerruby.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerspice.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexersql.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexertcl.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexertex.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerverilog.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexervhdl.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexerxml.h libgui/languages/build_ts/octave-qsci/Qsci/qscilexeryaml.h libgui/languages/build_ts/octave-qsci/Qsci/qscimacro.h libgui/languages/build_ts/octave-qsci/Qsci/qsciprinter.h libgui/languages/build_ts/octave-qsci/Qsci/qsciscintilla.h libgui/languages/build_ts/octave-qsci/Qsci/qsciscintillabase.h libgui/languages/build_ts/octave-qsci/Qsci/qscistyle.h libgui/languages/build_ts/octave-qsci/Qsci/qscistyledtext.h libgui/languages/build_ts/octave-qsci/qscilexer.cpp libgui/languages/build_ts/octave-qsci/qscilexerbash.cpp libgui/languages/build_ts/octave-qsci/qscilexerbatch.cpp libgui/languages/build_ts/octave-qsci/qscilexercpp.cpp libgui/languages/build_ts/octave-qsci/qscilexerdiff.cpp libgui/languages/build_ts/octave-qsci/qscilexermatlab.cpp libgui/languages/build_ts/octave-qsci/qscilexeroctave.cpp libgui/languages/build_ts/octave-qsci/qscilexerperl.cpp libgui/languages/build_ts/octave-qsci/qsciscintilla.cpp libgui/languages/build_ts/octave-qsci/qsciscintillabase.cpp libgui/languages/build_ts/octave-qt/qabstractprintdialog.cpp libgui/languages/build_ts/octave-qt/qcolordialog.cpp libgui/languages/build_ts/octave-qt/qdialog.cpp libgui/languages/build_ts/octave-qt/qdialogbuttonbox.cpp libgui/languages/build_ts/octave-qt/qerrormessage.cpp libgui/languages/build_ts/octave-qt/qfiledialog.cpp libgui/languages/build_ts/octave-qt/qfileinfogatherer.cpp libgui/languages/build_ts/octave-qt/qfilesystemmodel.cpp libgui/languages/build_ts/octave-qt/qfontdialog.cpp libgui/languages/build_ts/octave-qt/qhelpsearchquerywidget.cpp libgui/languages/build_ts/octave-qt/qinputdialog.cpp libgui/languages/build_ts/octave-qt/qmessagebox.cpp libgui/languages/build_ts/octave-qt/qpagesetupdialog.cpp libgui/languages/build_ts/octave-qt/qpagesetupdialog_unix.cpp libgui/languages/build_ts/octave-qt/qpagesetupdialog_win.cpp libgui/languages/build_ts/octave-qt/qplatformtheme.cpp libgui/languages/build_ts/octave-qt/qprintdialog_unix.cpp libgui/languages/build_ts/octave-qt/qprintdialog_win.cpp libgui/languages/build_ts/update_external_sources
diffstat 82 files changed, 8050 insertions(+), 6942 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciabstractapis.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciabstractapis.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines interface to the QsciAbstractAPIs class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciapis.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciapis.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines interface to the QsciAPIs class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscicommand.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscicommand.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciCommand class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscicommandset.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscicommandset.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciCommandSet class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscidocument.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscidocument.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciDocument class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciglobal.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciglobal.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines various things common to all of the Scintilla Qt port.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -24,8 +24,14 @@
 #include <qglobal.h>
 
 
-#define QSCINTILLA_VERSION      0x020b04
-#define QSCINTILLA_VERSION_STR  "2.11.4"
+#define QSCINTILLA_VERSION      0x020e00
+#define QSCINTILLA_VERSION_STR  "2.14.0"
+
+
+// We only support Qt v5.11 and later.
+#if QT_VERSION < 0x050b00
+#error "Qt v5.11.0 or later is required"
+#endif
 
 
 // Define QSCINTILLA_MAKE_DLL to create a QScintilla shared library, or
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexer.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexer.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexer class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -318,6 +318,12 @@
     //!
     virtual bool writeProperties(QSettings &qs,const QString &prefix) const;
 
+    //! \internal Convert a QString to encoded bytes.
+    QByteArray textAsBytes(const QString &text) const;
+
+    //! \internal Convert encoded bytes to a QString.
+    QString bytesAsText(const char *bytes, int size) const;
+
 private:
     struct StyleData {
         QFont font;
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeravs.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeravs.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerAVS class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbash.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbash.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerBash class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbatch.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerbatch.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerBatch class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercmake.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercmake.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCMake class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercoffeescript.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercoffeescript.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCoffeeScript class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercpp.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercpp.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCPP class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercsharp.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercsharp.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCSharp class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercss.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercss.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCSS class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercustom.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexercustom.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCustom class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerd.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerd.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerD class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerdiff.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerdiff.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerDiff class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeredifact.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeredifact.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerEDIFACT class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerFortran class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran77.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerfortran77.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerFortran77 class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerhtml.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerhtml.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerHTML class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeridl.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeridl.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerIDL class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjava.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjava.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJava class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjavascript.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjavascript.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJavaScript class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjson.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerjson.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJSON class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerlua.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerlua.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerLua class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermakefile.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermakefile.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerMakefile class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermarkdown.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermarkdown.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerMarkdown class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermatlab.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexermatlab.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerMatlab class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeroctave.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeroctave.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerOctave class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpascal.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpascal.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPascal class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerperl.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerperl.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPerl class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpo.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpo.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPO class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpostscript.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpostscript.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPostScript class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpov.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpov.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPOV class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerproperties.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerproperties.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerProperties class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpython.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerpython.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPython class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerruby.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerruby.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerRuby class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerspice.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerspice.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerSpice class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexersql.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexersql.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerSQL class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexertcl.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexertcl.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerTCL class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexertex.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexertex.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerTeX class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerverilog.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerverilog.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerVerilog class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexervhdl.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexervhdl.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerVHDL class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerxml.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexerxml.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerXML class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeryaml.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscilexeryaml.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerYAML class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscimacro.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscimacro.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This defines the interface to the QsciMacro class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciprinter.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciprinter.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines interface to the QsciPrinter class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -64,7 +64,7 @@
     //! area of the page that will be used to draw the text.  This should be
     //! modified if it is necessary to reserve space for any customised text or
     //! graphics.  By default the area is relative to the printable area of the
-    //! page.  Use QPrinter::setFullPage() because calling printRange() if you
+    //! page.  Use QPrinter::setFullPage() before calling printRange() if you
     //! want to try and print over the whole page.  \a pagenr is the number of
     //! the page.  The first page is numbered 1.
     virtual void formatPage(QPainter &painter, bool drawing, QRect &area,
@@ -81,11 +81,19 @@
     //! \sa magnification()
     virtual void setMagnification(int magnification);
 
-    //! Print a range of lines from the Scintilla instance \a qsb.  \a from is
-    //! the first line to print and a negative value signifies the first line
-    //! of text.  \a to is the last line to print and a negative value
-    //! signifies the last line of text.  true is returned if there was no
-    //! error.
+    //! Print a range of lines from the Scintilla instance \a qsb using the
+    //! supplied QPainter \a painter.  \a from is the first line to print and a
+    //! negative value signifies the first line of text.  \a to is the last
+    //! line to print and a negative value signifies the last line of text.
+    //! true is returned if there was no error.
+    virtual int printRange(QsciScintillaBase *qsb, QPainter &painter,
+            int from = -1, int to = -1);
+
+    //! Print a range of lines from the Scintilla instance \a qsb using a
+    //! default QPainter.  \a from is the first line to print and a negative
+    //! value signifies the first line of text.  \a to is the last line to
+    //! print and a negative value signifies the last line of text.  true is
+    //! returned if there was no error.
     virtual int printRange(QsciScintillaBase *qsb, int from = -1, int to = -1);
 
     //! Return the line wrap mode used when printing.  The default is
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciscintilla.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciscintilla.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,7 +1,7 @@
 // This module defines the "official" high-level API of the Qt port of
 // Scintilla.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -2242,7 +2242,7 @@
 
     QString wordAtPosition(int position) const;
 
-    ScintillaBytes styleText(const QList<QsciStyledText> &styled_text,
+    QByteArray styleText(const QList<QsciStyledText> &styled_text,
             char **styles, int style_offset = 0);
 
     struct FindState
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qsciscintillabase.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qsciscintillabase.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This class defines the "official" low-level API.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -3845,16 +3845,15 @@
     //! \internal This helps to work around some Scintilla bugs.
     void setScrollBars();
 
-    //! \internal Qt4, Qt5 portability.
-    typedef QByteArray ScintillaBytes;
-
-#define ScintillaBytesConstData(b)  (b).constData()
-
     //! \internal Convert a QString to encoded bytes.
-    ScintillaBytes textAsBytes(const QString &text) const;
+    QByteArray textAsBytes(const QString &text) const;
 
     //! \internal Convert encoded bytes to a QString.
-    QString bytesAsText(const char *bytes) const;
+    QString bytesAsText(const char *bytes, int size) const;
+
+    //! Give access to the text convertors.
+    friend class QsciAccessibleScintillaBase;
+    friend class QsciLexer;
 
     //! \internal A helper for QsciScintilla::contextMenuEvent().
     bool contextMenuNeeded(int x, int y) const;
@@ -3873,9 +3872,7 @@
     int preeditPos;
     int preeditNrBytes;
     QString preeditString;
-#if QT_VERSION >= 0x050000
     bool clickCausedFocus;
-#endif
 
     void connectHorizontalScrollBar();
     void connectVerticalScrollBar();
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscistyle.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscistyle.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines interface to the QsciStyle class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/Qsci/qscistyledtext.h	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/Qsci/qscistyledtext.h	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module defines interface to the QsciStyledText class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexer.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexer.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexer class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -367,7 +367,7 @@
         if (description(i).isEmpty())
             continue;
 
-        key.sprintf("%s/%s/style%d/",prefix,language(),i);
+        key = QString("%1/%2/style%3/").arg(prefix).arg(language()).arg(i);
 
         // Read the foreground colour.
         full_key = key + "color";
@@ -454,7 +454,7 @@
     }
 
     // Read the properties.
-    key.sprintf("%s/%s/properties/",prefix,language());
+    key = QString("%1/%2/properties/").arg(prefix).arg(language());
 
     if (!readProperties(qs,key))
         rc = false;
@@ -462,7 +462,7 @@
     refreshProperties();
 
     // Read the rest.
-    key.sprintf("%s/%s/",prefix,language());
+    key = QString("%1/%2/").arg(prefix).arg(language());
 
     // Read the default foreground colour.
     full_key = key + "defaultcolor";
@@ -569,7 +569,7 @@
 
         QColor c;
 
-        key.sprintf("%s/%s/style%d/",prefix,language(),i);
+        key = QString("%1/%2/style%3/").arg(prefix).arg(language()).arg(i);
 
         // Write the foreground colour.
         c = color(i);
@@ -607,13 +607,13 @@
     }
 
     // Write the properties.
-    key.sprintf("%s/%s/properties/",prefix,language());
+    key = QString("%1/%2/properties/").arg(prefix).arg(language());
 
     if (!writeProperties(qs,key))
         rc = false;
 
     // Write the rest.
-    key.sprintf("%s/%s/",prefix,language());
+    key = QString("%1/%2/").arg(prefix).arg(language());
 
     // Write the default foreground colour.
     num = (defColor.red() << 16) | (defColor.green() << 8) | defColor.blue();
@@ -729,3 +729,21 @@
         emit paperChanged(c, QsciScintillaBase::STYLE_DEFAULT);
     }
 }
+
+
+// Encode a QString as bytes.
+QByteArray QsciLexer::textAsBytes(const QString &text) const
+{
+    Q_ASSERT(attached_editor);
+
+    return attached_editor->textAsBytes(text);
+}
+
+
+// Decode bytes as a QString.
+QString QsciLexer::bytesAsText(const char *bytes, int size) const
+{
+    Q_ASSERT(attached_editor);
+
+    return attached_editor->bytesAsText(bytes, size);
+}
--- a/libgui/languages/build_ts/octave-qsci/qscilexerbash.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexerbash.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerBash class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexerbatch.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexerbatch.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerBatch class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexercpp.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexercpp.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerCPP class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexerdiff.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexerdiff.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerDiff class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexermatlab.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexermatlab.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerMatlab class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexeroctave.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexeroctave.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerOctave class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qscilexerperl.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qscilexerperl.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the QsciLexerPerl class.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
--- a/libgui/languages/build_ts/octave-qsci/qsciscintilla.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qsciscintilla.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -2,7 +2,7 @@
 // Scintilla.  It is modelled on QTextEdit - a method of the same name should
 // behave in the same way.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -390,8 +390,8 @@
         ct = ct_entries.join("\n");
     }
 
-    ScintillaBytes ct_bytes = textAsBytes(ct);
-    const char *cts = ScintillaBytesConstData(ct_bytes);
+    QByteArray ct_bytes = textAsBytes(ct);
+    const char *cts = ct_bytes.constData();
 
     SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), cts);
 
@@ -470,7 +470,8 @@
     if (ct_cursor > 0)
         ct.prepend('\001');
 
-    SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift), ct.toLatin1().data());
+    SendScintilla(SCI_CALLTIPSHOW, adjustedCallTipPosition(shift),
+            textAsBytes(ct).constData());
 }
 
 
@@ -673,8 +674,8 @@
         return;
 
     // Get the last word's raw data and length.
-    ScintillaBytes s = textAsBytes(context.last());
-    const char *last_data = ScintillaBytesConstData(s);
+    QByteArray s = textAsBytes(context.last());
+    const char *last_data = s.constData();
     int last_len = s.length();
 
     if (checkThresh && last_len < acThresh)
@@ -774,8 +775,8 @@
     SendScintilla(SCI_AUTOCSETCHOOSESINGLE, choose_single);
     SendScintilla(SCI_AUTOCSETSEPARATOR, acSeparator);
 
-    ScintillaBytes wlist_s = textAsBytes(wlist.join(QChar(acSeparator)));
-    SendScintilla(SCI_AUTOCSHOW, last_len, ScintillaBytesConstData(wlist_s));
+    SendScintilla(SCI_AUTOCSHOW, last_len,
+            textAsBytes(wlist.join(QChar(acSeparator))).constData());
 }
 
 
@@ -1880,10 +1881,9 @@
     SendScintilla(SCI_SETTARGETSTART, findState.startpos);
     SendScintilla(SCI_SETTARGETEND, findState.endpos);
 
-    ScintillaBytes s = textAsBytes(findState.expr);
-
-    return SendScintilla(SCI_SEARCHINTARGET, s.length(),
-            ScintillaBytesConstData(s));
+    QByteArray s = textAsBytes(findState.expr);
+
+    return SendScintilla(SCI_SEARCHINTARGET, s.length(), s.constData());
 }
 
 
@@ -1900,8 +1900,7 @@
 
     int cmd = (findState.flags & SCFIND_REGEXP) ? SCI_REPLACETARGETRE : SCI_REPLACETARGET;
 
-    ScintillaBytes s = textAsBytes(replaceStr);
-    long len = SendScintilla(cmd, -1, ScintillaBytesConstData(s));
+    long len = SendScintilla(cmd, -1, textAsBytes(replaceStr).constData());
 
     // Reset the selection.
     SendScintilla(SCI_SETSELECTIONSTART, start);
@@ -1911,7 +1910,10 @@
     findState.endpos_orig += (len - orig_len);
 
     if (findState.forward)
+    {
         findState.startpos = start + len;
+        findState.endpos += (len - orig_len);
+    }
 }
 
 
@@ -2180,8 +2182,8 @@
 {
     bool ro = ensureRW();
 
-    ScintillaBytes s = textAsBytes(text);
-    SendScintilla(SCI_APPENDTEXT, s.length(), ScintillaBytesConstData(s));
+    QByteArray s = textAsBytes(text);
+    SendScintilla(SCI_APPENDTEXT, s.length(), s.constData());
 
     SendScintilla(SCI_EMPTYUNDOBUFFER);
 
@@ -2209,8 +2211,7 @@
     bool ro = ensureRW();
 
     SendScintilla(SCI_BEGINUNDOACTION);
-    SendScintilla(SCI_INSERTTEXT, pos,
-            ScintillaBytesConstData(textAsBytes(text)));
+    SendScintilla(SCI_INSERTTEXT, pos, textAsBytes(text).constData());
     SendScintilla(SCI_ENDUNDOACTION);
 
     setReadOnly(ro);
@@ -2305,7 +2306,7 @@
 // Replace any selected text.
 void QsciScintilla::replaceSelectedText(const QString &text)
 {
-    SendScintilla(SCI_REPLACESEL, ScintillaBytesConstData(textAsBytes(text)));
+    SendScintilla(SCI_REPLACESEL, textAsBytes(text).constData());
 }
 
 
@@ -2315,11 +2316,12 @@
     if (!selText)
         return QString();
 
-    char *buf = new char[SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART) + 1];
+    int size = SendScintilla(SCI_GETSELECTIONEND) - SendScintilla(SCI_GETSELECTIONSTART);
+    char *buf = new char[size + 1];
 
     SendScintilla(SCI_GETSELTEXT, buf);
 
-    QString qs = bytesAsText(buf);
+    QString qs = bytesAsText(buf, size);
     delete[] buf;
 
     return qs;
@@ -2329,12 +2331,14 @@
 // Return the current text.
 QString QsciScintilla::text() const
 {
-    int buflen = length() + 1;
-    char *buf = new char[buflen];
-
-    SendScintilla(SCI_GETTEXT, buflen, buf);
-
-    QString qs = bytesAsText(buf);
+    int size = length();
+    char *buf = new char[size + 1];
+
+    // Note that the docs seem to be wrong and we need to ask for the length
+    // plus the '\0'.
+    SendScintilla(SCI_GETTEXT, size + 1, buf);
+
+    QString qs = bytesAsText(buf, size);
     delete[] buf;
 
     return qs;
@@ -2344,17 +2348,16 @@
 // Return the text of a line.
 QString QsciScintilla::text(int line) const
 {
-    int line_len = lineLength(line);
-
-    if (line_len < 1)
+    int size = lineLength(line);
+
+    if (size < 1)
         return QString();
 
-    char *buf = new char[line_len + 1];
+    char *buf = new char[size];
 
     SendScintilla(SCI_GETLINE, line, buf);
-    buf[line_len] = '\0';
-
-    QString qs = bytesAsText(buf);
+
+    QString qs = bytesAsText(buf, size);
     delete[] buf;
 
     return qs;
@@ -2364,9 +2367,10 @@
 // Return the text between two positions.
 QString QsciScintilla::text(int start, int end) const
 {
-    char *buf = new char[end - start + 1];
+    int size = end - start;
+    char *buf = new char[size + 1];
     SendScintilla(SCI_GETTEXTRANGE, start, end, buf);
-    QString text = bytesAsText(buf);
+    QString text = bytesAsText(buf, size);
     delete[] buf;
 
     return text;
@@ -2389,7 +2393,9 @@
 {
     bool ro = ensureRW();
 
-    SendScintilla(SCI_SETTEXT, ScintillaBytesConstData(textAsBytes(text)));
+    SendScintilla(SCI_CLEARALL);
+    QByteArray bytes = textAsBytes(text);
+    SendScintilla(SCI_ADDTEXT, bytes.size(), bytes.constData());
     SendScintilla(SCI_EMPTYUNDOBUFFER);
 
     setReadOnly(ro);
@@ -2700,9 +2706,7 @@
 {
     int style_offset = SendScintilla(SCI_MARGINGETSTYLEOFFSET);
 
-    SendScintilla(SCI_MARGINSETTEXT, line,
-            ScintillaBytesConstData(textAsBytes(text)));
-
+    SendScintilla(SCI_MARGINSETTEXT, line, textAsBytes(text).constData());
     SendScintilla(SCI_MARGINSETSTYLE, line, style - style_offset);
 }
 
@@ -2729,11 +2733,10 @@
 void QsciScintilla::setMarginText(int line, const QList<QsciStyledText> &text)
 {
     char *styles;
-    ScintillaBytes styled_text = styleText(text, &styles,
+    QByteArray styled_text = styleText(text, &styles,
             SendScintilla(SCI_MARGINGETSTYLEOFFSET));
 
-    SendScintilla(SCI_MARGINSETTEXT, line,
-            ScintillaBytesConstData(styled_text));
+    SendScintilla(SCI_MARGINSETTEXT, line, styled_text.constData());
     SendScintilla(SCI_MARGINSETSTYLES, line, styles);
 
     delete[] styles;
@@ -2801,7 +2804,7 @@
 void QsciScintilla::setMarginWidth(int margin, const QString &s)
 {
     int width = SendScintilla(SCI_TEXTWIDTH, STYLE_LINENUMBER,
-            ScintillaBytesConstData(textAsBytes(s)));
+            textAsBytes(s).constData());
 
     setMarginWidth(margin, width);
 }
@@ -4052,8 +4055,8 @@
 
     SendScintilla(SCI_AUTOCSETSEPARATOR, userSeparator);
 
-    ScintillaBytes s = textAsBytes(list.join(QChar(userSeparator)));
-    SendScintilla(SCI_USERLISTSHOW, id, ScintillaBytesConstData(s));
+    SendScintilla(SCI_USERLISTSHOW, id,
+            textAsBytes(list.join(QChar(userSeparator))).constData());
 }
 
 
@@ -4223,9 +4226,7 @@
 {
     int style_offset = SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET);
 
-    ScintillaBytes s = textAsBytes(text);
-
-    SendScintilla(SCI_ANNOTATIONSETTEXT, line, ScintillaBytesConstData(s));
+    SendScintilla(SCI_ANNOTATIONSETTEXT, line, textAsBytes(text).constData());
     SendScintilla(SCI_ANNOTATIONSETSTYLE, line, style - style_offset);
 
     setScrollBars();
@@ -4254,11 +4255,10 @@
 void QsciScintilla::annotate(int line, const QList<QsciStyledText> &text)
 {
     char *styles;
-    ScintillaBytes styled_text = styleText(text, &styles,
+    QByteArray styled_text = styleText(text, &styles,
             SendScintilla(SCI_ANNOTATIONGETSTYLEOFFSET));
 
-    SendScintilla(SCI_ANNOTATIONSETTEXT, line,
-            ScintillaBytesConstData(styled_text));
+    SendScintilla(SCI_ANNOTATIONSETTEXT, line, styled_text.constData());
     SendScintilla(SCI_ANNOTATIONSETSTYLES, line, styles);
 
     delete[] styles;
@@ -4268,11 +4268,10 @@
 // Get the annotation for a line, if any.
 QString QsciScintilla::annotation(int line) const
 {
-    char *buf = new char[SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0) + 1];
-
-    buf[SendScintilla(SCI_ANNOTATIONGETTEXT, line, buf)] = '\0';
-
-    QString qs = bytesAsText(buf);
+    int size = SendScintilla(SCI_ANNOTATIONGETTEXT, line, (const char *)0);
+    char *buf = new char[size + 1];
+
+    QString qs = bytesAsText(buf, size);
     delete[] buf;
 
     return qs;
@@ -4280,7 +4279,8 @@
 
 
 // Convert a list of styled text to the low-level arrays.
-QsciScintillaBase::ScintillaBytes QsciScintilla::styleText(const QList<QsciStyledText> &styled_text, char **styles, int style_offset)
+QByteArray QsciScintilla::styleText(const QList<QsciStyledText> &styled_text,
+        char **styles, int style_offset)
 {
     QString text;
     int i;
@@ -4295,7 +4295,7 @@
         text.append(st.text());
     }
 
-    ScintillaBytes s = textAsBytes(text);
+    QByteArray s = textAsBytes(text);
 
     // There is a style byte for every byte.
     char *sp = *styles = new char[s.length()];
@@ -4303,7 +4303,7 @@
     for (i = 0; i < styled_text.count(); ++i)
     {
         const QsciStyledText &st = styled_text[i];
-        ScintillaBytes part = textAsBytes(st.text());
+        QByteArray part = textAsBytes(st.text());
         int part_length = part.length();
 
         for (int c = 0; c < part_length; ++c)
@@ -4377,7 +4377,10 @@
 
    if ((e->modifiers() & zoom_modifier) != 0)
    {
-       if (e->delta() > 0)
+       QPoint ad = e->angleDelta();
+       int delta = (qAbs(ad.x()) > qAbs(ad.y())) ? ad.x() : ad.y();
+
+       if (delta > 0)
            zoomIn();
        else
            zoomOut();
--- a/libgui/languages/build_ts/octave-qsci/qsciscintillabase.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qsci/qsciscintillabase.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,6 +1,6 @@
 // This module implements the "official" low-level API.
 //
-// Copyright (c) 2019 Riverbank Computing Limited <info@riverbankcomputing.com>
+// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
 // 
 // This file is part of QScintilla.
 // 
@@ -36,7 +36,6 @@
 #include <QPaintEvent>
 #include <QScrollBar>
 #include <QStyle>
-#include <QTextCodec>
 
 #include "SciAccessibility.h"
 #include "ScintillaQt.h"
@@ -80,17 +79,15 @@
 static const QLatin1String mimeRectangularWin("MSDEVColumnSelect");
 static const QLatin1String mimeRectangular("text/x-qscintilla-rectangular");
 
-#if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX))
+#if QT_VERSION < 0x060000 && defined(Q_OS_OSX)
 extern void initialiseRectangularPasteboardMime();
 #endif
 
 
 // The ctor.
 QsciScintillaBase::QsciScintillaBase(QWidget *parent)
-    : QAbstractScrollArea(parent), preeditPos(-1), preeditNrBytes(0)
-#if QT_VERSION >= 0x050000
-        , clickCausedFocus(false)
-#endif
+    : QAbstractScrollArea(parent), preeditPos(-1), preeditNrBytes(0),
+            clickCausedFocus(false)
 {
 #if !defined(QT_NO_ACCESSIBILITY)
     QsciAccessibleScintillaBase::initialise();
@@ -103,12 +100,8 @@
     setFocusPolicy(Qt::WheelFocus);
     setAttribute(Qt::WA_KeyCompression);
     setAttribute(Qt::WA_InputMethodEnabled);
-#if QT_VERSION >= 0x050100
     setInputMethodHints(
             Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhMultiLine);
-#elif QT_VERSION >= 0x040600
-    setInputMethodHints(Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText);
-#endif
 
     viewport()->setBackgroundRole(QPalette::Base);
     viewport()->setMouseTracking(true);
@@ -116,7 +109,7 @@
 
     triple_click.setSingleShot(true);
 
-#if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX))
+#if QT_VERSION < 0x060000 && defined(Q_OS_OSX)
     initialiseRectangularPasteboardMime();
 #endif
 
@@ -321,11 +314,7 @@
 void QsciScintillaBase::focusInEvent(QFocusEvent *e)
 {
     sci->SetFocusState(true);
-
-#if QT_VERSION >= 0x050000
     clickCausedFocus = (e->reason() == Qt::MouseFocusReason);
-#endif
-
     QAbstractScrollArea::focusInEvent(e);
 }
 
@@ -400,7 +389,7 @@
 
     if (!text.isEmpty() && text[0].isPrint())
     {
-        ScintillaBytes bytes = textAsBytes(text);
+        QByteArray bytes = textAsBytes(text);
         sci->AddCharUTF(bytes.data(), bytes.length());
         e->accept();
     }
@@ -503,7 +492,7 @@
 
 
 // Encode a QString as bytes.
-QsciScintillaBase::ScintillaBytes QsciScintillaBase::textAsBytes(const QString &text) const
+QByteArray QsciScintillaBase::textAsBytes(const QString &text) const
 {
     if (sci->IsUnicodeMode())
         return text.toUtf8();
@@ -513,12 +502,12 @@
 
 
 // Decode bytes as a QString.
-QString QsciScintillaBase::bytesAsText(const char *bytes) const
+QString QsciScintillaBase::bytesAsText(const char *bytes, int size) const
 {
     if (sci->IsUnicodeMode())
-        return QString::fromUtf8(bytes);
+        return QString::fromUtf8(bytes, size);
 
-    return QString::fromLatin1(bytes);
+    return QString::fromLatin1(bytes, size);
 }
 
 
@@ -595,7 +584,7 @@
             sci->RightButtonDownWithModifiers(pt, clickTime,
                     QsciScintillaQt::ModifierFlags(shift, ctrl, alt));
     }
-    else if (e->button() == Qt::MidButton)
+    else if (e->button() == Qt::MiddleButton)
     {
         QClipboard *cb = QApplication::clipboard();
 
@@ -628,7 +617,6 @@
                 QsciScintillaQt::ModifierFlags(false, ctrl, false));
     }
 
-#if QT_VERSION >= 0x050000
     if (!sci->pdoc->IsReadOnly() && !sci->PointInSelMargin(pt) && qApp->autoSipEnabled())
     {
         QStyle::RequestSoftwareInputPanel rsip = QStyle::RequestSoftwareInputPanel(style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
@@ -638,7 +626,6 @@
     }
 
     clickCausedFocus = false;
-#endif
 }
 
 
--- a/libgui/languages/build_ts/octave-qt/qabstractprintdialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qabstractprintdialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,43 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qabstractprintdialog_p.h"
 #include "qcoreapplication.h"
@@ -45,30 +7,21 @@
 #include "qprinter.h"
 #include "private/qprinter_p.h"
 
-#ifndef QT_NO_PRINTDIALOG
-
 QT_BEGIN_NAMESPACE
 
-// hack
-class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
-{
-};
-
 /*!
     \class QAbstractPrintDialog
     \brief The QAbstractPrintDialog class provides a base implementation for
     print dialogs used to configure printers.
 
     \ingroup printing
+    \inmodule QtPrintSupport
 
     This class implements getter and setter functions that are used to
     customize settings shown in print dialogs, but it is not used directly.
     Use QPrintDialog to display a print dialog in your application.
 
-    In Symbian, there is no support for printing. Hence, this dialog should not
-    be used in Symbian.
-
-    \sa QPrintDialog, QPrinter, {Printing with Qt}
+    \sa QPrintDialog, QPrinter
 */
 
 /*!
@@ -79,7 +32,7 @@
     \value AllPages All pages should be printed.
     \value Selection Only the selection should be printed.
     \value PageRange The specified page range should be printed.
-    \value CurrentPage Only the currently visible page should be printed. (This value was introduced in 4.7.)
+    \value CurrentPage Only the currently visible page should be printed.
 
     \sa QPrinter::PrintRange
 */
@@ -89,20 +42,12 @@
 
     Used to specify which parts of the print dialog should be visible.
 
-    \value None None of the options are enabled.
     \value PrintToFile The print to file option is enabled.
     \value PrintSelection The print selection option is enabled.
     \value PrintPageRange The page range selection option is enabled.
     \value PrintShowPageSize  Show the page size + margins page only if this is enabled.
     \value PrintCollateCopies The collate copies option is enabled
-    \value PrintCurrentPage The print current page option is enabled (This value was introduced in 4.7.)
-
-    This value is obsolete and does nothing since Qt 4.5:
-
-    \value DontUseSheet In previous versions of Qt, exec() the print dialog
-    would create a sheet by default the dialog was given a parent.
-    This is no longer supported in Qt 4.5.  If you want to use sheets, use
-    QPrintDialog::open() instead.
+    \value PrintCurrentPage The print current page option is enabled
 */
 
 /*!
@@ -115,6 +60,9 @@
     Q_D(QAbstractPrintDialog);
     setWindowTitle(QCoreApplication::translate("QPrintDialog", "Print"));
     d->setPrinter(printer);
+    d->minPage = printer->fromPage();
+    int to = printer->toPage();
+    d->maxPage = to > 0 ? to : INT_MAX;
 }
 
 /*!
@@ -148,21 +96,21 @@
 */
 void QPrintDialog::setOption(PrintDialogOption option, bool on)
 {
-    Q_D(QPrintDialog);
-    if (!(d->pd->options & option) != !on)
-        setOptions(d->pd->options ^ option);
+    auto *d = static_cast<QAbstractPrintDialogPrivate *>(d_ptr.data());
+    if (!(d->options & option) != !on)
+        setOptions(d->options ^ option);
 }
 
 /*!
-    Returns true if the given \a option is enabled; otherwise, returns
+    Returns \c true if the given \a option is enabled; otherwise, returns
     false.
 
     \sa options, setOption()
 */
 bool QPrintDialog::testOption(PrintDialogOption option) const
 {
-    Q_D(const QPrintDialog);
-    return (d->pd->options & option) != 0;
+    auto *d = static_cast<const QAbstractPrintDialogPrivate *>(d_ptr.data());
+    return (d->options & option) != 0;
 }
 
 /*!
@@ -180,63 +128,19 @@
 */
 void QPrintDialog::setOptions(PrintDialogOptions options)
 {
-    Q_D(QPrintDialog);
+    auto *d = static_cast<QAbstractPrintDialogPrivate *>(d_ptr.data());
 
-    PrintDialogOptions changed = (options ^ d->pd->options);
+    PrintDialogOptions changed = (options ^ d->options);
     if (!changed)
         return;
 
-    d->pd->options = options;
+    d->options = options;
 }
 
 QPrintDialog::PrintDialogOptions QPrintDialog::options() const
 {
-    Q_D(const QPrintDialog);
-    return d->pd->options;
-}
-
-/*!
-    \obsolete
-
-    Use QPrintDialog::setOptions() instead.
-*/
-void QAbstractPrintDialog::setEnabledOptions(PrintDialogOptions options)
-{
-    Q_D(QAbstractPrintDialog);
-    d->pd->options = options;
-}
-
-/*!
-    \obsolete
-
-    Use QPrintDialog::setOption(\a option, true) instead.
-*/
-void QAbstractPrintDialog::addEnabledOption(PrintDialogOption option)
-{
-    Q_D(QAbstractPrintDialog);
-    d->pd->options |= option;
-}
-
-/*!
-    \obsolete
-
-    Use QPrintDialog::options() instead.
-*/
-QAbstractPrintDialog::PrintDialogOptions QAbstractPrintDialog::enabledOptions() const
-{
-    Q_D(const QAbstractPrintDialog);
-    return d->pd->options;
-}
-
-/*!
-    \obsolete
-
-    Use QPrintDialog::testOption(\a option) instead.
-*/
-bool QAbstractPrintDialog::isOptionEnabled(PrintDialogOption option) const
-{
-    Q_D(const QAbstractPrintDialog);
-    return d->pd->options & option;
+    auto *d = static_cast<const QAbstractPrintDialogPrivate *>(d_ptr.data());
+    return d->options;
 }
 
 /*!
@@ -245,7 +149,7 @@
 void QAbstractPrintDialog::setPrintRange(PrintRange range)
 {
     Q_D(QAbstractPrintDialog);
-    d->pd->printRange = range;
+    d->printer->setPrintRange(QPrinter::PrintRange(range));
 }
 
 /*!
@@ -254,7 +158,7 @@
 QAbstractPrintDialog::PrintRange QAbstractPrintDialog::printRange() const
 {
     Q_D(const QAbstractPrintDialog);
-    return d->pd->printRange;
+    return QAbstractPrintDialog::PrintRange(d->pd->printRange);
 }
 
 /*!
@@ -266,9 +170,9 @@
     Q_D(QAbstractPrintDialog);
     Q_ASSERT_X(min <= max, "QAbstractPrintDialog::setMinMax",
                "'min' must be less than or equal to 'max'");
-    d->pd->minPage = min;
-    d->pd->maxPage = max;
-    d->pd->options |= PrintPageRange;
+    d->minPage = min;
+    d->maxPage = max;
+    d->options |= PrintPageRange;
 }
 
 /*!
@@ -278,7 +182,7 @@
 int QAbstractPrintDialog::minPage() const
 {
     Q_D(const QAbstractPrintDialog);
-    return d->pd->minPage;
+    return d->minPage;
 }
 
 /*!
@@ -289,7 +193,7 @@
 int QAbstractPrintDialog::maxPage() const
 {
     Q_D(const QAbstractPrintDialog);
-    return d->pd->maxPage;
+    return d->maxPage;
 }
 
 /*!
@@ -300,10 +204,9 @@
     Q_D(QAbstractPrintDialog);
     Q_ASSERT_X(from <= to, "QAbstractPrintDialog::setFromTo",
                "'from' must be less than or equal to 'to'");
-    d->pd->fromPage = from;
-    d->pd->toPage = to;
+    d->printer->setFromTo(from, to);
 
-    if (d->pd->minPage == 0 && d->pd->maxPage == 0)
+    if (d->minPage == 0 && d->maxPage == 0)
         setMinMax(1, to);
 }
 
@@ -314,7 +217,7 @@
 int QAbstractPrintDialog::fromPage() const
 {
     Q_D(const QAbstractPrintDialog);
-    return d->pd->fromPage;
+    return d->printer->fromPage();
 }
 
 /*!
@@ -324,7 +227,7 @@
 int QAbstractPrintDialog::toPage() const
 {
     Q_D(const QAbstractPrintDialog);
-    return d->pd->toPage;
+    return d->printer->toPage();
 }
 
 
@@ -343,6 +246,8 @@
     if (newPrinter) {
         printer = newPrinter;
         ownsPrinter = false;
+        if (printer->fromPage() || printer->toPage())
+            options |= QAbstractPrintDialog::PrintPageRange;
     } else {
         printer = new QPrinter;
         ownsPrinter = true;
@@ -351,13 +256,6 @@
 }
 
 /*!
-    \fn int QAbstractPrintDialog::exec()
-
-    This virtual function is called to pop up the dialog. It must be
-    reimplemented in subclasses.
-*/
-
-/*!
     \class QPrintDialog
 
     \brief The QPrintDialog class provides a dialog for specifying
@@ -365,6 +263,7 @@
 
     \ingroup standard-dialogs
     \ingroup printing
+    \inmodule QtPrintSupport
 
     The dialog allows users to change document-related settings, such
     as the paper size and orientation, type of print (color or
@@ -376,33 +275,32 @@
     Typically, QPrintDialog objects are constructed with a QPrinter
     object, and executed using the exec() function.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qabstractprintdialog.cpp 0
+    \snippet code/src_gui_dialogs_qabstractprintdialog.cpp 0
 
     If the dialog is accepted by the user, the QPrinter object is
     correctly configured for printing.
 
     \table
     \row
-    \o \inlineimage plastique-printdialog.png
-    \o \inlineimage plastique-printdialog-properties.png
+    \li \inlineimage plastique-printdialog.png
+    \li \inlineimage plastique-printdialog-properties.png
     \endtable
 
     The printer dialog (shown above in Plastique style) enables access to common
     printing properties. On X11 platforms that use the CUPS printing system, the
     settings for each available printer can be modified via the dialog's
-    \gui{Properties} push button.
+    \uicontrol{Properties} push button.
 
-    On Windows and Mac OS X, the native print dialog is used, which means that
+    On Windows and \macos, the native print dialog is used, which means that
     some QWidget and QDialog properties set on the dialog won't be respected.
-    The native print dialog on Mac OS X does not support setting printer options,
+    The native print dialog on \macos does not support setting printer options,
     i.e. setOptions() and setOption() have no effect.
 
     In Qt 4.4, it was possible to use the static functions to show a sheet on
-    Mac OS X. This is no longer supported in Qt 4.5. If you want this
+    \macos. This is no longer supported in Qt 4.5. If you want this
     functionality, use QPrintDialog::open().
 
-    \sa QPageSetupDialog, QPrinter, {Pixelator Example}, {Order Form Example},
-        {Image Viewer Example}, {Scribble Example}
+    \sa QPageSetupDialog, QPrinter
 */
 
 /*!
@@ -459,21 +357,21 @@
   and exec() to return \a result.
 
   \note This function does not apply to the Native Print Dialog on the Mac
-  OS X and Windows platforms, because the dialog is required to be modal
+  \macos and Windows platforms, because the dialog is required to be modal
   and only the user can close it.
 
   \sa QDialog::done()
 */
 void QPrintDialog::done(int result)
 {
-    Q_D(QPrintDialog);
+    auto *d = static_cast<QAbstractPrintDialogPrivate *>(d_ptr.data());
     QDialog::done(result);
     if (result == Accepted)
         emit accepted(printer());
     if (d->receiverToDisconnectOnClose) {
         disconnect(this, SIGNAL(accepted(QPrinter*)),
                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
-        d->receiverToDisconnectOnClose = 0;
+        d->receiverToDisconnectOnClose = nullptr;
     }
     d->memberToDisconnectOnClose.clear();
 }
@@ -489,7 +387,7 @@
 */
 void QPrintDialog::open(QObject *receiver, const char *member)
 {
-    Q_D(QPrintDialog);
+    auto *d = static_cast<QAbstractPrintDialogPrivate *>(d_ptr.data());
     connect(this, SIGNAL(accepted(QPrinter*)), receiver, member);
     d->receiverToDisconnectOnClose = receiver;
     d->memberToDisconnectOnClose = member;
@@ -498,4 +396,4 @@
 
 QT_END_NAMESPACE
 
-#endif // QT_NO_PRINTDIALOG
+#include "moc_qabstractprintdialog.cpp"
--- a/libgui/languages/build_ts/octave-qt/qcolordialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qcolordialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,82 +1,165 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-#include "qcolordialog_p.h"
-
-#ifndef QT_NO_COLORDIALOG
+#include "qcolordialog.h"
 
 #include "qapplication.h"
-#include "qdesktopwidget.h"
 #include "qdrawutil.h"
 #include "qevent.h"
 #include "qimage.h"
+#if QT_CONFIG(draganddrop)
+#include <qdrag.h>
+#endif
 #include "qlabel.h"
 #include "qlayout.h"
 #include "qlineedit.h"
+#if QT_CONFIG(menu)
 #include "qmenu.h"
+#endif
 #include "qpainter.h"
 #include "qpixmap.h"
 #include "qpushbutton.h"
+#if QT_CONFIG(regularexpression)
+#include <qregularexpression.h>
+#endif
+#if QT_CONFIG(settings)
 #include "qsettings.h"
+#endif
+#include "qsharedpointer.h"
 #include "qstyle.h"
 #include "qstyleoption.h"
 #include "qvalidator.h"
-#include "qmime.h"
+#include "qmimedata.h"
 #include "qspinbox.h"
 #include "qdialogbuttonbox.h"
-#include "private/qguiplatformplugin_p.h"
+#include "qscreen.h"
+#include "qcursor.h"
+#include "qtimer.h"
+#include "qwindow.h"
 
-#ifdef Q_WS_S60
-#include "private/qt_s60_p.h"
-#endif
+#include "private/qdialog_p.h"
 
-#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
-#  define QT_SMALL_COLORDIALOG
-#endif
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformservices.h>
+#include <private/qguiapplication_p.h>
+
+#include <algorithm>
 
 QT_BEGIN_NAMESPACE
 
+using namespace Qt::StringLiterals;
+
+namespace QtPrivate {
+class QColorLuminancePicker;
+class QColorPicker;
+class QColorShower;
+class QWellArray;
+class QColorWell;
+class QColorPickingEventFilter;
+} // namespace QtPrivate
+
+using QColorLuminancePicker = QtPrivate::QColorLuminancePicker;
+using QColorPicker = QtPrivate::QColorPicker;
+using QColorShower = QtPrivate::QColorShower;
+using QWellArray = QtPrivate::QWellArray;
+using QColorWell = QtPrivate::QColorWell;
+using QColorPickingEventFilter = QtPrivate::QColorPickingEventFilter;
+
+class QColorDialogPrivate : public QDialogPrivate
+{
+    Q_DECLARE_PUBLIC(QColorDialog)
+
+public:
+    enum SetColorMode {
+        ShowColor = 0x1,
+        SelectColor = 0x2,
+        SetColorAll = ShowColor | SelectColor
+    };
+
+    QColorDialogPrivate() : options(QColorDialogOptions::create())
+#ifdef Q_OS_WIN32
+        , updateTimer(0)
+#endif
+    {}
+
+    QPlatformColorDialogHelper *platformColorDialogHelper() const
+        { return static_cast<QPlatformColorDialogHelper *>(platformHelper()); }
+
+    void init(const QColor &initial);
+    void initWidgets();
+    QRgb currentColor() const;
+    QColor currentQColor() const;
+    void setCurrentColor(const QColor &color, SetColorMode setColorMode = SetColorAll);
+    void setCurrentRgbColor(QRgb rgb);
+    void setCurrentQColor(const QColor &color);
+    bool selectColor(const QColor &color);
+    QColor grabScreenColor(const QPoint &p);
+
+    int currentAlpha() const;
+    void setCurrentAlpha(int a);
+    void showAlpha(bool b);
+    bool isAlphaVisible() const;
+    void retranslateStrings();
+    bool supportsColorPicking() const;
+
+    void _q_addCustom();
+    void _q_setCustom(int index, QRgb color);
+
+    void _q_newHsv(int h, int s, int v);
+    void _q_newColorTypedIn(QRgb rgb);
+    void _q_nextCustom(int, int);
+    void _q_newCustom(int, int);
+    void _q_newStandard(int, int);
+    void _q_pickScreenColor();
+    void _q_updateColorPicking();
+    void updateColorLabelText(const QPoint &);
+    void updateColorPicking(const QPoint &pos);
+    void releaseColorPicking();
+    bool handleColorPickingMouseMove(QMouseEvent *e);
+    bool handleColorPickingMouseButtonRelease(QMouseEvent *e);
+    bool handleColorPickingKeyPress(QKeyEvent *e);
+
+    bool canBeNativeDialog() const override;
+    void setVisible(bool visible) override;
+
+    QWellArray *custom;
+    QWellArray *standard;
+
+    QDialogButtonBox *buttons;
+    QVBoxLayout *leftLay;
+    QColorPicker *cp;
+    QColorLuminancePicker *lp;
+    QColorShower *cs;
+    QLabel *lblBasicColors;
+    QLabel *lblCustomColors;
+    QLabel *lblScreenColorInfo;
+    QPushButton *ok;
+    QPushButton *cancel;
+    QPushButton *addCusBt;
+    QPushButton *screenColorPickerButton;
+    QColor selectedQColor;
+    int nextCust;
+    bool smallDisplay;
+    bool screenColorPicking;
+    QColorPickingEventFilter *colorPickingEventFilter;
+    QRgb beforeScreenColorPicking;
+    QSharedPointer<QColorDialogOptions> options;
+
+    QPointer<QObject> receiverToDisconnectOnClose;
+    QByteArray memberToDisconnectOnClose;
+#ifdef Q_OS_WIN32
+    QTimer *updateTimer;
+    QWindow dummyTransparentWindow;
+#endif
+
+private:
+    virtual void initHelper(QPlatformDialogHelper *h) override;
+    virtual void helperPrepareShow(QPlatformDialogHelper *h) override;
+};
+
 //////////// QWellArray BEGIN
 
-struct QWellArrayData;
+namespace QtPrivate {
 
 class QWellArray : public QWidget
 {
@@ -85,7 +168,7 @@
     Q_PROPERTY(int selectedRow READ selectedRow)
 
 public:
-    QWellArray(int rows, int cols, QWidget* parent=0);
+    QWellArray(int rows, int cols, QWidget* parent=nullptr);
     ~QWellArray() {}
     QString cellContent(int row, int col) const;
 
@@ -95,10 +178,7 @@
     virtual void setCurrent(int row, int col);
     virtual void setSelected(int row, int col);
 
-    QSize sizeHint() const;
-
-    virtual void setCellBrush(int row, int col, const QBrush &);
-    QBrush cellBrush(int row, int col);
+    QSize sizeHint() const override;
 
     inline int cellWidth() const
         { return cellw; }
@@ -142,17 +222,19 @@
 
 signals:
     void selected(int row, int col);
+    void currentChanged(int row, int col);
+    void colorChanged(int index, QRgb color);
 
 protected:
     virtual void paintCell(QPainter *, int row, int col, const QRect&);
     virtual void paintCellContents(QPainter *, int row, int col, const QRect&);
 
-    void mousePressEvent(QMouseEvent*);
-    void mouseReleaseEvent(QMouseEvent*);
-    void keyPressEvent(QKeyEvent*);
-    void focusInEvent(QFocusEvent*);
-    void focusOutEvent(QFocusEvent*);
-    void paintEvent(QPaintEvent *);
+    void mousePressEvent(QMouseEvent*) override;
+    void mouseReleaseEvent(QMouseEvent*) override;
+    void keyPressEvent(QKeyEvent*) override;
+    void focusInEvent(QFocusEvent*) override;
+    void focusOutEvent(QFocusEvent*) override;
+    void paintEvent(QPaintEvent *) override;
 
 private:
     Q_DISABLE_COPY(QWellArray)
@@ -165,7 +247,6 @@
     int curCol;
     int selRow;
     int selCol;
-    QWellArrayData *d;
 };
 
 void QWellArray::paintEvent(QPaintEvent *e)
@@ -215,15 +296,10 @@
     }
 }
 
-struct QWellArrayData {
-    QBrush *brush;
-};
-
 QWellArray::QWellArray(int rows, int cols, QWidget *parent)
     : QWidget(parent)
         ,nrows(rows), ncols(cols)
 {
-    d = 0;
     setFocusPolicy(Qt::StrongFocus);
     cellw = 28;
     cellh = 24;
@@ -246,7 +322,8 @@
 
     const QPalette & g = palette();
     QStyleOptionFrame opt;
-    int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+    opt.initFrom(this);
+    int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt);
     opt.lineWidth = dfw;
     opt.midLineWidth = 1;
     opt.rect = rect.adjusted(b, b, -b, -b);
@@ -267,25 +344,23 @@
     paintCellContents(p, row, col, opt.rect.adjusted(dfw, dfw, -dfw, -dfw));
 }
 
-/*!
+/*
   Reimplement this function to change the contents of the well array.
  */
 void QWellArray::paintCellContents(QPainter *p, int row, int col, const QRect &r)
 {
-    if (d) {
-        p->fillRect(r, d->brush[row*numCols()+col]);
-    } else {
-        p->fillRect(r, Qt::white);
-        p->setPen(Qt::black);
-        p->drawLine(r.topLeft(), r.bottomRight());
-        p->drawLine(r.topRight(), r.bottomLeft());
-    }
+    Q_UNUSED(row);
+    Q_UNUSED(col);
+    p->fillRect(r, Qt::white);
+    p->setPen(Qt::black);
+    p->drawLine(r.topLeft(), r.bottomRight());
+    p->drawLine(r.topRight(), r.bottomLeft());
 }
 
 void QWellArray::mousePressEvent(QMouseEvent *e)
 {
     // The current cell marker is set to the cell the mouse is pressed in
-    QPoint pos = e->pos();
+    QPoint pos = e->position().toPoint();
     setCurrent(rowAt(pos.y()), columnAt(pos.x()));
 }
 
@@ -317,6 +392,8 @@
 
     updateCell(oldRow, oldCol);
     updateCell(curRow, curCol);
+
+    emit currentChanged(curRow, curCol);
 }
 
 /*
@@ -341,7 +418,7 @@
     if (row >= 0)
         emit selected(row, col);
 
-#ifndef QT_NO_MENU
+#if QT_CONFIG(menu)
     if (isVisible() && qobject_cast<QMenu*>(parentWidget()))
         parentWidget()->close();
 #endif
@@ -350,62 +427,45 @@
 void QWellArray::focusInEvent(QFocusEvent*)
 {
     updateCell(curRow, curCol);
-}
-
-void QWellArray::setCellBrush(int row, int col, const QBrush &b)
-{
-    if (!d) {
-        d = new QWellArrayData;
-        int i = numRows()*numCols();
-        d->brush = new QBrush[i];
-    }
-    if (row >= 0 && row < numRows() && col >= 0 && col < numCols())
-        d->brush[row*numCols()+col] = b;
+    emit currentChanged(curRow, curCol);
 }
 
-/*
-  Returns the brush set for the cell at \a row, \a column. If no brush is
-  set, Qt::NoBrush is returned.
-*/
-
-QBrush QWellArray::cellBrush(int row, int col)
-{
-    if (d && row >= 0 && row < numRows() && col >= 0 && col < numCols())
-        return d->brush[row*numCols()+col];
-    return Qt::NoBrush;
-}
-
-
-
-/*!\reimp
-*/
 
 void QWellArray::focusOutEvent(QFocusEvent*)
 {
     updateCell(curRow, curCol);
 }
 
-/*\reimp
-*/
 void QWellArray::keyPressEvent(QKeyEvent* e)
 {
     switch(e->key()) {                        // Look at the key code
     case Qt::Key_Left:                                // If 'left arrow'-key,
-        if(curCol > 0)                        // and cr't not in leftmost col
+        if (curCol > 0)                        // and cr't not in leftmost col
             setCurrent(curRow, curCol - 1);        // set cr't to next left column
         break;
     case Qt::Key_Right:                                // Correspondingly...
-        if(curCol < numCols()-1)
+        if (curCol < numCols()-1)
             setCurrent(curRow, curCol + 1);
         break;
     case Qt::Key_Up:
-        if(curRow > 0)
+        if (curRow > 0)
             setCurrent(curRow - 1, curCol);
         break;
     case Qt::Key_Down:
-        if(curRow < numRows()-1)
+        if (curRow < numRows()-1)
             setCurrent(curRow + 1, curCol);
         break;
+#if 0
+    // bad idea that shouldn't have been implemented; very counterintuitive
+    case Qt::Key_Return:
+    case Qt::Key_Enter:
+        /*
+          ignore the key, so that the dialog get it, but still select
+          the current row/col
+        */
+        e->ignore();
+        // fallthrough intended
+#endif
     case Qt::Key_Space:
         setSelected(curRow, curCol);
         break;
@@ -414,30 +474,35 @@
         return;
     }
 
-}
+} // namespace QtPrivate
 
 //////////// QWellArray END
 
-static bool initrgb = false;
-static QRgb stdrgb[6*8];
-static QRgb cusrgb[2*8];
-static bool customSet = false;
-
+// Event filter to be installed on the dialog while in color-picking mode.
+class QColorPickingEventFilter : public QObject {
+public:
+    explicit QColorPickingEventFilter(QColorDialogPrivate *dp, QObject *parent) : QObject(parent), m_dp(dp) {}
 
-static void initRGB()
-{
-    if (initrgb)
-        return;
-    initrgb = true;
-    int i = 0;
-    for (int g = 0; g < 4; g++)
-        for (int r = 0;  r < 4; r++)
-            for (int b = 0; b < 3; b++)
-                stdrgb[i++] = qRgb(r * 255 / 3, g * 255 / 3, b * 255 / 2);
+    bool eventFilter(QObject *, QEvent *event) override
+    {
+        switch (event->type()) {
+        case QEvent::MouseMove:
+            return m_dp->handleColorPickingMouseMove(static_cast<QMouseEvent *>(event));
+        case QEvent::MouseButtonRelease:
+            return m_dp->handleColorPickingMouseButtonRelease(static_cast<QMouseEvent *>(event));
+        case QEvent::KeyPress:
+            return m_dp->handleColorPickingKeyPress(static_cast<QKeyEvent *>(event));
+        default:
+            break;
+        }
+        return false;
+    }
 
-    for (i = 0; i < 2*8; i++)
-        cusrgb[i] = 0xffffffff;
-}
+private:
+    QColorDialogPrivate *m_dp;
+};
+
+} // unnamed namespace
 
 /*!
     Returns the number of custom colors supported by QColorDialog. All
@@ -445,52 +510,51 @@
 */
 int QColorDialog::customCount()
 {
-    return 2 * 8;
+    return QColorDialogOptions::customColorCount();
 }
 
 /*!
     \since 4.5
 
-    Returns the custom color at the given \a index as a QRgb value.
+    Returns the custom color at the given \a index as a QColor value.
 */
-QRgb QColorDialog::customColor(int index)
+QColor QColorDialog::customColor(int index)
 {
-    if (uint(index) >= uint(customCount()))
-        return qRgb(255, 255, 255);
-    initRGB();
-    return cusrgb[index];
+    return QColor(QColorDialogOptions::customColor(index));
+}
+
+/*!
+    Sets the custom color at \a index to the QColor \a color value.
+
+    \note This function does not apply to the Native Color Dialog on the
+    \macos platform. If you still require this function, use the
+    QColorDialog::DontUseNativeDialog option.
+*/
+void QColorDialog::setCustomColor(int index, QColor color)
+{
+    QColorDialogOptions::setCustomColor(index, color.rgba());
 }
 
 /*!
-    Sets the custom color at \a index to the QRgb \a color value.
+    \since 5.0
 
-    \note This function does not apply to the Native Color Dialog on the Mac
-    OS X platform. If you still require this function, use the
-    QColorDialog::DontUseNativeDialog option.
+    Returns the standard color at the given \a index as a QColor value.
 */
-void QColorDialog::setCustomColor(int index, QRgb color)
+QColor QColorDialog::standardColor(int index)
 {
-    if (uint(index) >= uint(customCount()))
-        return;
-    initRGB();
-    customSet = true;
-    cusrgb[index] = color;
+    return QColor(QColorDialogOptions::standardColor(index));
 }
 
 /*!
-    Sets the standard color at \a  index to the QRgb \a color value.
+    Sets the standard color at \a index to the QColor \a color value.
 
-    \note This function does not apply to the Native Color Dialog on the Mac
-    OS X platform. If you still require this function, use the
+    \note This function does not apply to the Native Color Dialog on the
+    \macos platform. If you still require this function, use the
     QColorDialog::DontUseNativeDialog option.
 */
-
-void QColorDialog::setStandardColor(int index, QRgb color)
+void QColorDialog::setStandardColor(int index, QColor color)
 {
-    if (uint(index) >= uint(6 * 8))
-        return;
-    initRGB();
-    stdrgb[index] = color;
+    QColorDialogOptions::setStandardColor(index, color.rgba());
 }
 
 static inline void rgb2hsv(QRgb rgb, int &h, int &s, int &v)
@@ -500,27 +564,29 @@
     c.getHsv(&h, &s, &v);
 }
 
+namespace QtPrivate {
+
 class QColorWell : public QWellArray
 {
 public:
-    QColorWell(QWidget *parent, int r, int c, QRgb *vals)
+    QColorWell(QWidget *parent, int r, int c, const QRgb *vals)
         :QWellArray(r, c, parent), values(vals), mousePressed(false), oldCurrent(-1, -1)
     { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); }
 
 protected:
-    void paintCellContents(QPainter *, int row, int col, const QRect&);
-    void mousePressEvent(QMouseEvent *e);
-    void mouseMoveEvent(QMouseEvent *e);
-    void mouseReleaseEvent(QMouseEvent *e);
-#ifndef QT_NO_DRAGANDDROP
-    void dragEnterEvent(QDragEnterEvent *e);
-    void dragLeaveEvent(QDragLeaveEvent *e);
-    void dragMoveEvent(QDragMoveEvent *e);
-    void dropEvent(QDropEvent *e);
+    void paintCellContents(QPainter *, int row, int col, const QRect&) override;
+    void mousePressEvent(QMouseEvent *e) override;
+    void mouseMoveEvent(QMouseEvent *e) override;
+    void mouseReleaseEvent(QMouseEvent *e) override;
+#if QT_CONFIG(draganddrop)
+    void dragEnterEvent(QDragEnterEvent *e) override;
+    void dragLeaveEvent(QDragLeaveEvent *e) override;
+    void dragMoveEvent(QDragMoveEvent *e) override;
+    void dropEvent(QDropEvent *e) override;
 #endif
 
 private:
-    QRgb *values;
+    const QRgb *values;
     bool mousePressed;
     QPoint pressPos;
     QPoint oldCurrent;
@@ -538,16 +604,16 @@
     oldCurrent = QPoint(selectedRow(), selectedColumn());
     QWellArray::mousePressEvent(e);
     mousePressed = true;
-    pressPos = e->pos();
+    pressPos = e->position().toPoint();
 }
 
 void QColorWell::mouseMoveEvent(QMouseEvent *e)
 {
     QWellArray::mouseMoveEvent(e);
-#ifndef QT_NO_DRAGANDDROP
+#if QT_CONFIG(draganddrop)
     if (!mousePressed)
         return;
-    if ((pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+    if ((pressPos - e->position().toPoint()).manhattanLength() > QApplication::startDragDistance()) {
         setCurrent(oldCurrent.x(), oldCurrent.y());
         int i = rowAt(pressPos.y()) + columnAt(pressPos.x()) * numRows();
         QColor col(values[i]);
@@ -562,12 +628,12 @@
         drg->setMimeData(mime);
         drg->setPixmap(pix);
         mousePressed = false;
-        drg->start();
+        drg->exec(Qt::CopyAction);
     }
 #endif
 }
 
-#ifndef QT_NO_DRAGANDDROP
+#if QT_CONFIG(draganddrop)
 void QColorWell::dragEnterEvent(QDragEnterEvent *e)
 {
     if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid())
@@ -585,7 +651,7 @@
 void QColorWell::dragMoveEvent(QDragMoveEvent *e)
 {
     if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid()) {
-        setCurrent(rowAt(e->pos().y()), columnAt(e->pos().x()));
+        setCurrent(rowAt(e->position().toPoint().y()), columnAt(e->position().toPoint().x()));
         e->accept();
     } else {
         e->ignore();
@@ -596,16 +662,15 @@
 {
     QColor col = qvariant_cast<QColor>(e->mimeData()->colorData());
     if (col.isValid()) {
-        int i = rowAt(e->pos().y()) + columnAt(e->pos().x()) * numRows();
-        values[i] = col.rgb();
-        update();
+        int i = rowAt(e->position().toPoint().y()) + columnAt(e->position().toPoint().x()) * numRows();
+        emit colorChanged(i, col.rgb());
         e->accept();
     } else {
         e->ignore();
     }
 }
 
-#endif // QT_NO_DRAGANDDROP
+#endif // QT_CONFIG(draganddrop)
 
 void QColorWell::mouseReleaseEvent(QMouseEvent *e)
 {
@@ -622,6 +687,7 @@
     QColorPicker(QWidget* parent);
     ~QColorPicker();
 
+    void setCrossVisible(bool visible);
 public slots:
     void setCol(int h, int s);
 
@@ -629,11 +695,11 @@
     void newCol(int h, int s);
 
 protected:
-    QSize sizeHint() const;
-    void paintEvent(QPaintEvent*);
-    void mouseMoveEvent(QMouseEvent *);
-    void mousePressEvent(QMouseEvent *);
-    void resizeEvent(QResizeEvent *);
+    QSize sizeHint() const override;
+    void paintEvent(QPaintEvent*) override;
+    void mouseMoveEvent(QMouseEvent *) override;
+    void mousePressEvent(QMouseEvent *) override;
+    void resizeEvent(QResizeEvent *) override;
 
 private:
     int hue;
@@ -645,16 +711,21 @@
     void setCol(const QPoint &pt);
 
     QPixmap pix;
+    bool crossVisible;
 };
 
+} // namespace QtPrivate
+
 static int pWidth = 220;
 static int pHeight = 200;
 
+namespace QtPrivate {
+
 class QColorLuminancePicker : public QWidget
 {
     Q_OBJECT
 public:
-    QColorLuminancePicker(QWidget* parent=0);
+    QColorLuminancePicker(QWidget* parent=nullptr);
     ~QColorLuminancePicker();
 
 public slots:
@@ -665,9 +736,9 @@
     void newHsv(int h, int s, int v);
 
 protected:
-    void paintEvent(QPaintEvent*);
-    void mouseMoveEvent(QMouseEvent *);
-    void mousePressEvent(QMouseEvent *);
+    void paintEvent(QPaintEvent*) override;
+    void mouseMoveEvent(QMouseEvent *) override;
+    void mousePressEvent(QMouseEvent *) override;
 
 private:
     enum { foff = 3, coff = 4 }; //frame and contents offset
@@ -699,7 +770,7 @@
     :QWidget(parent)
 {
     hue = 100; val = 100; sat = 100;
-    pix = 0;
+    pix = nullptr;
     //    setAttribute(WA_NoErase, true);
 }
 
@@ -710,11 +781,15 @@
 
 void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
 {
-    setVal(y2val(m->y()));
+    if (m->buttons() == Qt::NoButton) {
+        m->ignore();
+        return;
+    }
+    setVal(y2val(m->position().toPoint().y()));
 }
 void QColorLuminancePicker::mousePressEvent(QMouseEvent *m)
 {
-    setVal(y2val(m->y()));
+    setVal(y2val(m->position().toPoint().y()));
 }
 
 void QColorLuminancePicker::setVal(int v)
@@ -722,7 +797,7 @@
     if (val == v)
         return;
     val = qMax(0, qMin(v,255));
-    delete pix; pix=0;
+    delete pix; pix=nullptr;
     repaint();
     emit newHsv(hue, sat, val);
 }
@@ -747,13 +822,9 @@
         int y;
         uint *pixel = (uint *) img.scanLine(0);
         for (y = 0; y < hi; y++) {
-            const uint *end = pixel + wi;
-            while (pixel < end) {
-                QColor c;
-                c.setHsv(hue, sat, y2val(y+coff));
-                *pixel = c.rgb();
-                ++pixel;
-            }
+            uint *end = pixel + wi;
+            std::fill(pixel, end, QColor::fromHsv(hue, sat, y2val(y + coff)).rgb());
+            pixel = end;
         }
         pix = new QPixmap(QPixmap::fromImage(img));
     }
@@ -761,8 +832,8 @@
     p.drawPixmap(1, coff, *pix);
     const QPalette &g = palette();
     qDrawShadePanel(&p, r, g, true);
-    p.setPen(g.foreground().color());
-    p.setBrush(g.foreground());
+    p.setPen(g.windowText().color());
+    p.setBrush(g.windowText());
     QPolygon a;
     int y = val2y(val);
     a.setPoints(3, w, y, w+5, y+5, w+5, y-5);
@@ -775,7 +846,7 @@
     val = v;
     hue = h;
     sat = s;
-    delete pix; pix=0;
+    delete pix; pix=nullptr;
     repaint();
 }
 
@@ -804,6 +875,7 @@
 
 QColorPicker::QColorPicker(QWidget* parent)
     : QFrame(parent)
+    , crossVisible(true)
 {
     hue = 0; sat = 0;
     setCol(150, 255);
@@ -816,6 +888,14 @@
 {
 }
 
+void QColorPicker::setCrossVisible(bool visible)
+{
+    if (crossVisible != visible) {
+        crossVisible = visible;
+        update();
+    }
+}
+
 QSize QColorPicker::sizeHint() const
 {
     return QSize(pWidth + 2*frameWidth(), pHeight + 2*frameWidth());
@@ -838,14 +918,18 @@
 
 void QColorPicker::mouseMoveEvent(QMouseEvent *m)
 {
-    QPoint p = m->pos() - contentsRect().topLeft();
+    QPoint p = m->position().toPoint() - contentsRect().topLeft();
+    if (m->buttons() == Qt::NoButton) {
+        m->ignore();
+        return;
+    }
     setCol(p);
     emit newCol(hue, sat);
 }
 
 void QColorPicker::mousePressEvent(QMouseEvent *m)
 {
-    QPoint p = m->pos() - contentsRect().topLeft();
+    QPoint p = m->position().toPoint() - contentsRect().topLeft();
     setCol(p);
     emit newCol(hue, sat);
 }
@@ -857,12 +941,13 @@
     QRect r = contentsRect();
 
     p.drawPixmap(r.topLeft(), pix);
-    QPoint pt = colPt() + r.topLeft();
-    p.setPen(Qt::black);
 
-    p.fillRect(pt.x()-9, pt.y(), 20, 2, Qt::black);
-    p.fillRect(pt.x(), pt.y()-9, 2, 20, Qt::black);
-
+    if (crossVisible) {
+        QPoint pt = colPt() + r.topLeft();
+        p.setPen(Qt::black);
+        p.fillRect(pt.x()-9, pt.y(), 20, 2, Qt::black);
+        p.fillRect(pt.x(), pt.y()-9, 2, 20, Qt::black);
+    }
 }
 
 void QColorPicker::resizeEvent(QResizeEvent *ev)
@@ -896,10 +981,8 @@
     QColSpinBox(QWidget *parent)
         : QSpinBox(parent) { setRange(0, 255); }
     void setValue(int i) {
-        bool block = signalsBlocked();
-        blockSignals(true);
+        const QSignalBlocker blocker(this);
         QSpinBox::setValue(i);
-        blockSignals(block);
     }
 };
 
@@ -935,6 +1018,8 @@
 private slots:
     void rgbEd();
     void hsvEd();
+    void htmlEd();
+
 private:
     void showCurrentColor();
     int hue, sat, val;
@@ -946,6 +1031,7 @@
     QLabel *lblRed;
     QLabel *lblGreen;
     QLabel *lblBlue;
+    QLabel *lblHtml;
     QColSpinBox *hEd;
     QColSpinBox *sEd;
     QColSpinBox *vEd;
@@ -954,12 +1040,14 @@
     QColSpinBox *bEd;
     QColSpinBox *alphaEd;
     QLabel *alphaLab;
+    QLineEdit *htEd;
     QColorShowLabel *lab;
     bool rgbOriginal;
     QColorDialog *colorDialog;
+    QGridLayout *gl;
 
-    friend class QColorDialog;
-    friend class QColorDialogPrivate;
+    friend class QT_PREPEND_NAMESPACE(QColorDialog);
+    friend class QT_PREPEND_NAMESPACE(QColorDialogPrivate);
 };
 
 class QColorShowLabel : public QFrame
@@ -978,14 +1066,14 @@
     void colorDropped(QRgb);
 
 protected:
-    void paintEvent(QPaintEvent *);
-    void mousePressEvent(QMouseEvent *e);
-    void mouseMoveEvent(QMouseEvent *e);
-    void mouseReleaseEvent(QMouseEvent *e);
-#ifndef QT_NO_DRAGANDDROP
-    void dragEnterEvent(QDragEnterEvent *e);
-    void dragLeaveEvent(QDragLeaveEvent *e);
-    void dropEvent(QDropEvent *e);
+    void paintEvent(QPaintEvent *) override;
+    void mousePressEvent(QMouseEvent *e) override;
+    void mouseMoveEvent(QMouseEvent *e) override;
+    void mouseReleaseEvent(QMouseEvent *e) override;
+#if QT_CONFIG(draganddrop)
+    void dragEnterEvent(QDragEnterEvent *e) override;
+    void dragLeaveEvent(QDragLeaveEvent *e) override;
+    void dropEvent(QDropEvent *e) override;
 #endif
 
 private:
@@ -1015,17 +1103,17 @@
 void QColorShowLabel::mousePressEvent(QMouseEvent *e)
 {
     mousePressed = true;
-    pressPos = e->pos();
+    pressPos = e->position().toPoint();
 }
 
 void QColorShowLabel::mouseMoveEvent(QMouseEvent *e)
 {
-#ifdef QT_NO_DRAGANDDROP
+#if !QT_CONFIG(draganddrop)
     Q_UNUSED(e);
 #else
     if (!mousePressed)
         return;
-    if ((pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+    if ((pressPos - e->position().toPoint()).manhattanLength() > QApplication::startDragDistance()) {
         QMimeData *mime = new QMimeData;
         mime->setColorData(col);
         QPixmap pix(30, 20);
@@ -1037,12 +1125,12 @@
         drg->setMimeData(mime);
         drg->setPixmap(pix);
         mousePressed = false;
-        drg->start();
+        drg->exec(Qt::CopyAction);
     }
 #endif
 }
 
-#ifndef QT_NO_DRAGANDDROP
+#if QT_CONFIG(draganddrop)
 void QColorShowLabel::dragEnterEvent(QDragEnterEvent *e)
 {
     if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid())
@@ -1067,7 +1155,7 @@
         e->ignore();
     }
 }
-#endif // QT_NO_DRAGANDDROP
+#endif // QT_CONFIG(draganddrop)
 
 void QColorShowLabel::mouseReleaseEvent(QMouseEvent *)
 {
@@ -1084,40 +1172,25 @@
     curCol = qRgb(255, 255, 255);
     curQColor = Qt::white;
 
-    QGridLayout *gl = new QGridLayout(this);
-    gl->setMargin(gl->spacing());
+    gl = new QGridLayout(this);
+    const int s = gl->spacing();
+    gl->setContentsMargins(s, s, s, s);
     lab = new QColorShowLabel(this);
 
 #ifdef QT_SMALL_COLORDIALOG
-#  ifdef Q_WS_S60
-    const bool nonTouchUI = !S60->hasTouchscreen;
-#  elif defined Q_WS_MAEMO_5
-    const bool nonTouchUI = false;
-#  endif
-#endif
-
-#ifndef Q_WS_WINCE
-#ifdef QT_SMALL_COLORDIALOG
     lab->setMinimumHeight(60);
 #endif
     lab->setMinimumWidth(60);
-#else
-    lab->setMinimumWidth(20);
-#endif
 
-// In S60, due to small screen and different screen layouts need to re-arrange the widgets.
 // For QVGA screens only the comboboxes and color label are visible.
 // For nHD screens only color and luminence pickers and color label are visible.
 #if !defined(QT_SMALL_COLORDIALOG)
     gl->addWidget(lab, 0, 0, -1, 1);
 #else
-    if (nonTouchUI)
-        gl->addWidget(lab, 0, 0, 1, -1);
-    else
-        gl->addWidget(lab, 0, 0, -1, 1);
+    gl->addWidget(lab, 0, 0, 1, -1);
 #endif
-    connect(lab, SIGNAL(colorDropped(QRgb)), this, SIGNAL(newCol(QRgb)));
-    connect(lab, SIGNAL(colorDropped(QRgb)), this, SLOT(setRgb(QRgb)));
+    connect(lab, &QColorShowLabel::colorDropped, this, &QColorShower::newCol);
+    connect(lab, &QColorShowLabel::colorDropped, this, &QColorShower::setRgb);
 
     hEd = new QColSpinBox(this);
     hEd->setRange(0, 359);
@@ -1130,13 +1203,8 @@
     gl->addWidget(lblHue, 0, 1);
     gl->addWidget(hEd, 0, 2);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblHue, 1, 0);
-        gl->addWidget(hEd, 2, 0);
-    } else {
-        lblHue->hide();
-        hEd->hide();
-    }
+    gl->addWidget(lblHue, 1, 0);
+    gl->addWidget(hEd, 2, 0);
 #endif
 
     sEd = new QColSpinBox(this);
@@ -1149,13 +1217,8 @@
     gl->addWidget(lblSat, 1, 1);
     gl->addWidget(sEd, 1, 2);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblSat, 1, 1);
-        gl->addWidget(sEd, 2, 1);
-    } else {
-        lblSat->hide();
-        sEd->hide();
-    }
+    gl->addWidget(lblSat, 1, 1);
+    gl->addWidget(sEd, 2, 1);
 #endif
 
     vEd = new QColSpinBox(this);
@@ -1168,13 +1231,8 @@
     gl->addWidget(lblVal, 2, 1);
     gl->addWidget(vEd, 2, 2);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblVal, 1, 2);
-        gl->addWidget(vEd, 2, 2);
-    } else {
-        lblVal->hide();
-        vEd->hide();
-    }
+    gl->addWidget(lblVal, 1, 2);
+    gl->addWidget(vEd, 2, 2);
 #endif
 
     rEd = new QColSpinBox(this);
@@ -1187,13 +1245,8 @@
     gl->addWidget(lblRed, 0, 3);
     gl->addWidget(rEd, 0, 4);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblRed, 3, 0);
-        gl->addWidget(rEd, 4, 0);
-    } else {
-        lblRed->hide();
-        rEd->hide();
-    }
+    gl->addWidget(lblRed, 3, 0);
+    gl->addWidget(rEd, 4, 0);
 #endif
 
     gEd = new QColSpinBox(this);
@@ -1206,13 +1259,8 @@
     gl->addWidget(lblGreen, 1, 3);
     gl->addWidget(gEd, 1, 4);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblGreen, 3, 1);
-        gl->addWidget(gEd, 4, 1);
-    } else {
-        lblGreen->hide();
-        gEd->hide();
-    }
+    gl->addWidget(lblGreen, 3, 1);
+    gl->addWidget(gEd, 4, 1);
 #endif
 
     bEd = new QColSpinBox(this);
@@ -1225,13 +1273,8 @@
     gl->addWidget(lblBlue, 2, 3);
     gl->addWidget(bEd, 2, 4);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(lblBlue, 3, 2);
-        gl->addWidget(bEd, 4, 2);
-    } else {
-        lblBlue->hide();
-        bEd->hide();
-    }
+    gl->addWidget(lblBlue, 3, 2);
+    gl->addWidget(bEd, 4, 2);
 #endif
 
     alphaEd = new QColSpinBox(this);
@@ -1244,29 +1287,51 @@
     gl->addWidget(alphaLab, 3, 1, 1, 3);
     gl->addWidget(alphaEd, 3, 4);
 #else
-    if (nonTouchUI) {
-        gl->addWidget(alphaLab, 1, 3, 3, 1);
-        gl->addWidget(alphaEd, 4, 3);
-    } else {
-        alphaLab->hide();
-        alphaEd->hide();
-    }
+    gl->addWidget(alphaLab, 1, 3, 3, 1);
+    gl->addWidget(alphaEd, 4, 3);
 #endif
     alphaEd->hide();
     alphaLab->hide();
+    lblHtml = new QLabel(this);
+    htEd = new QLineEdit(this);
+    htEd->setObjectName("qt_colorname_lineedit");
+#ifndef QT_NO_SHORTCUT
+    lblHtml->setBuddy(htEd);
+#endif
 
-    connect(hEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
-    connect(sEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
-    connect(vEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
+#if QT_CONFIG(regularexpression)
+    QRegularExpression regExp(QStringLiteral("#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"));
+    QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
+    htEd->setValidator(validator);
+#else
+    htEd->setReadOnly(true);
+#endif
+    htEd->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
 
-    connect(rEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
-    connect(gEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
-    connect(bEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
-    connect(alphaEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
+    lblHtml->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if defined(QT_SMALL_COLORDIALOG)
+    gl->addWidget(lblHtml, 5, 0);
+    gl->addWidget(htEd, 5, 1, 1, /*colspan=*/ 2);
+#else
+    gl->addWidget(lblHtml, 5, 1);
+    gl->addWidget(htEd, 5, 2, 1, /*colspan=*/ 3);
+#endif
+
+    connect(hEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
+    connect(sEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
+    connect(vEd, &QSpinBox::valueChanged, this, &QColorShower::hsvEd);
+
+    connect(rEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
+    connect(gEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
+    connect(bEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
+    connect(alphaEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
+    connect(htEd, &QLineEdit::textEdited, this, &QColorShower::htmlEd);
 
     retranslateStrings();
 }
 
+} // namespace QtPrivate
+
 inline QRgb QColorDialogPrivate::currentColor() const { return cs->currentColor(); }
 inline int QColorDialogPrivate::currentAlpha() const { return cs->currentAlpha(); }
 inline void QColorDialogPrivate::setCurrentAlpha(int a) { cs->setCurrentAlpha(a); }
@@ -1275,6 +1340,8 @@
 
 QColor QColorDialogPrivate::currentQColor() const
 {
+    if (nativeDialogInUse)
+        return platformColorDialogHelper()->currentColor();
     return cs->currentQColor();
 }
 
@@ -1295,6 +1362,8 @@
     sEd->setValue(sat);
     vEd->setValue(val);
 
+    htEd->setText(QColor(curCol).name());
+
     showCurrentColor();
     emit newCol(currentColor());
     updateQColor();
@@ -1315,6 +1384,40 @@
     gEd->setValue(qGreen(currentColor()));
     bEd->setValue(qBlue(currentColor()));
 
+    htEd->setText(c.name());
+
+    showCurrentColor();
+    emit newCol(currentColor());
+    updateQColor();
+}
+
+void QColorShower::htmlEd()
+{
+    QString t = htEd->text();
+    if (t.isEmpty())
+        return;
+
+    if (!t.startsWith(QStringLiteral("#"))) {
+        t = QStringLiteral("#") + t;
+        QSignalBlocker blocker(htEd);
+        htEd->setText(t);
+    }
+
+    QColor c = QColor::fromString(t);
+    if (!c.isValid())
+        return;
+
+    curCol = qRgba(c.red(), c.green(), c.blue(), currentAlpha());
+    rgb2hsv(curCol, hue, sat, val);
+
+    hEd->setValue(hue);
+    sEd->setValue(sat);
+    vEd->setValue(val);
+
+    rEd->setValue(qRed(currentColor()));
+    gEd->setValue(qGreen(currentColor()));
+    bEd->setValue(qBlue(currentColor()));
+
     showCurrentColor();
     emit newCol(currentColor());
     updateQColor();
@@ -1335,6 +1438,8 @@
     gEd->setValue(qGreen(currentColor()));
     bEd->setValue(qBlue(currentColor()));
 
+    htEd->setText(QColor(rgb).name());
+
     showCurrentColor();
     updateQColor();
 }
@@ -1342,7 +1447,7 @@
 void QColorShower::setHsv(int h, int s, int v)
 {
     if (h < -1 || (uint)s > 255 || (uint)v > 255)
-	    return;
+        return;
 
     rgbOriginal = false;
     hue = h; val = v; sat = s;
@@ -1358,6 +1463,8 @@
     gEd->setValue(qGreen(currentColor()));
     bEd->setValue(qBlue(currentColor()));
 
+    htEd->setText(c.name());
+
     showCurrentColor();
     updateQColor();
 }
@@ -1371,6 +1478,7 @@
     lblGreen->setText(QColorDialog::tr("&Green:"));
     lblBlue->setText(QColorDialog::tr("Bl&ue:"));
     alphaLab->setText(QColorDialog::tr("A&lpha channel:"));
+    lblHtml->setText(QColorDialog::tr("&HTML:"));
 }
 
 void QColorShower::updateQColor()
@@ -1384,16 +1492,20 @@
 //sets all widgets to display h,s,v
 void QColorDialogPrivate::_q_newHsv(int h, int s, int v)
 {
-    cs->setHsv(h, s, v);
-    cp->setCol(h, s);
-    lp->setCol(h, s, v);
+    if (!nativeDialogInUse) {
+        cs->setHsv(h, s, v);
+        cp->setCol(h, s);
+        lp->setCol(h, s, v);
+    }
 }
 
 //sets all widgets to display rgb
-void QColorDialogPrivate::setCurrentColor(QRgb rgb)
+void QColorDialogPrivate::setCurrentRgbColor(QRgb rgb)
 {
-    cs->setRgb(rgb);
-    _q_newColorTypedIn(rgb);
+    if (!nativeDialogInUse) {
+        cs->setRgb(rgb);
+        _q_newColorTypedIn(rgb);
+    }
 }
 
 // hack; doesn't keep curCol in sync, so use with care
@@ -1406,66 +1518,173 @@
     }
 }
 
+// size of standard and custom color selector
+enum {
+    colorColumns = 8,
+    standardColorRows = 6,
+    customColorRows = 2
+};
+
 bool QColorDialogPrivate::selectColor(const QColor &col)
 {
     QRgb color = col.rgb();
-    int i = 0, j = 0;
     // Check standard colors
     if (standard) {
-        for (i = 0; i < 6; i++) {
-            for (j = 0; j < 8; j++) {
-                if (color == stdrgb[i + j*6]) {
-                    _q_newStandard(i, j);
-                    standard->setCurrent(i, j);
-                    standard->setSelected(i, j);
-                    standard->setFocus();
-                    return true;
-                }
-            }
+        const QRgb *standardColors = QColorDialogOptions::standardColors();
+        const QRgb *standardColorsEnd = standardColors + standardColorRows * colorColumns;
+        const QRgb *match = std::find(standardColors, standardColorsEnd, color);
+        if (match != standardColorsEnd) {
+            const int index = int(match - standardColors);
+            const int column = index / standardColorRows;
+            const int row = index % standardColorRows;
+            _q_newStandard(row, column);
+            standard->setCurrent(row, column);
+            standard->setSelected(row, column);
+            standard->setFocus();
+            return true;
         }
     }
     // Check custom colors
     if (custom) {
-        for (i = 0; i < 2; i++) {
-            for (j = 0; j < 8; j++) {
-                if (color == cusrgb[i + j*2]) {
-                    _q_newCustom(i, j);
-                    custom->setCurrent(i, j);
-                    custom->setSelected(i, j);
-                    custom->setFocus();
-                    return true;
-                }
-            }
+        const QRgb *customColors = QColorDialogOptions::customColors();
+        const QRgb *customColorsEnd = customColors + customColorRows * colorColumns;
+        const QRgb *match = std::find(customColors, customColorsEnd, color);
+        if (match != customColorsEnd) {
+            const int index = int(match - customColors);
+            const int column = index / customColorRows;
+            const int row = index % customColorRows;
+            _q_newCustom(row, column);
+            custom->setCurrent(row, column);
+            custom->setSelected(row, column);
+            custom->setFocus();
+            return true;
         }
     }
     return false;
 }
 
+QColor QColorDialogPrivate::grabScreenColor(const QPoint &p)
+{
+    QScreen *screen = QGuiApplication::screenAt(p);
+    if (!screen)
+        screen = QGuiApplication::primaryScreen();
+    const QRect screenRect = screen->geometry();
+    const QPixmap pixmap =
+            screen->grabWindow(0, p.x() - screenRect.x(), p.y() - screenRect.y(), 1, 1);
+    const QImage i = pixmap.toImage();
+    return i.pixel(0, 0);
+}
+
 //sets all widgets except cs to display rgb
 void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb)
 {
-    int h, s, v;
-    rgb2hsv(rgb, h, s, v);
-    cp->setCol(h, s);
-    lp->setCol(h, s, v);
+    if (!nativeDialogInUse) {
+        int h, s, v;
+        rgb2hsv(rgb, h, s, v);
+        cp->setCol(h, s);
+        lp->setCol(h, s, v);
+    }
+}
+
+void QColorDialogPrivate::_q_nextCustom(int r, int c)
+{
+    nextCust = r + customColorRows * c;
 }
 
 void QColorDialogPrivate::_q_newCustom(int r, int c)
 {
-    int i = r+2*c;
-    setCurrentColor(cusrgb[i]);
-    nextCust = i;
+    const int i = r + customColorRows * c;
+    setCurrentRgbColor(QColorDialogOptions::customColor(i));
     if (standard)
         standard->setSelected(-1,-1);
 }
 
 void QColorDialogPrivate::_q_newStandard(int r, int c)
 {
-    setCurrentColor(stdrgb[r+c*6]);
+    setCurrentRgbColor(QColorDialogOptions::standardColor(r + c * 6));
     if (custom)
         custom->setSelected(-1,-1);
 }
 
+void QColorDialogPrivate::_q_pickScreenColor()
+{
+    Q_Q(QColorDialog);
+
+    auto *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
+    if (platformServices->hasCapability(QPlatformServices::Capability::ColorPicking)) {
+        if (auto *colorPicker = platformServices->colorPicker(q->windowHandle())) {
+            q->connect(colorPicker, &QPlatformServiceColorPicker::colorPicked, q,
+                       [q, colorPicker](const QColor &color) {
+                           colorPicker->deleteLater();
+                           q->setCurrentColor(color);
+                       });
+            colorPicker->pickColor();
+            return;
+        }
+    }
+
+    if (!colorPickingEventFilter)
+        colorPickingEventFilter = new QColorPickingEventFilter(this, q);
+    q->installEventFilter(colorPickingEventFilter);
+    // If user pushes Escape, the last color before picking will be restored.
+    beforeScreenColorPicking = cs->currentColor();
+#ifndef QT_NO_CURSOR
+    q->grabMouse(Qt::CrossCursor);
+#else
+    q->grabMouse();
+#endif
+
+#ifdef Q_OS_WIN32
+    // On Windows mouse tracking doesn't work over other processes's windows
+    updateTimer->start(30);
+
+    // HACK: Because mouse grabbing doesn't work across processes, we have to have a dummy,
+    // invisible window to catch the mouse click, otherwise we will click whatever we clicked
+    // and loose focus.
+    dummyTransparentWindow.show();
+#endif
+    q->grabKeyboard();
+    /* With setMouseTracking(true) the desired color can be more precisely picked up,
+     * and continuously pushing the mouse button is not necessary.
+     */
+    q->setMouseTracking(true);
+
+    addCusBt->setDisabled(true);
+    buttons->setDisabled(true);
+    if (screenColorPickerButton) {
+        screenColorPickerButton->setDisabled(true);
+        const QPoint globalPos = QCursor::pos();
+        q->setCurrentColor(grabScreenColor(globalPos));
+        updateColorLabelText(globalPos);
+    }
+}
+
+void QColorDialogPrivate::updateColorLabelText(const QPoint &globalPos)
+{
+    if (lblScreenColorInfo)
+        lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2\nPress ESC to cancel")
+                                .arg(globalPos.x())
+                                .arg(globalPos.y()));
+}
+
+void QColorDialogPrivate::releaseColorPicking()
+{
+    Q_Q(QColorDialog);
+    cp->setCrossVisible(true);
+    q->removeEventFilter(colorPickingEventFilter);
+    q->releaseMouse();
+#ifdef Q_OS_WIN32
+    updateTimer->stop();
+    dummyTransparentWindow.setVisible(false);
+#endif
+    q->releaseKeyboard();
+    q->setMouseTracking(false);
+    lblScreenColorInfo->setText("\n"_L1);
+    addCusBt->setDisabled(false);
+    buttons->setDisabled(false);
+    screenColorPickerButton->setDisabled(false);
+}
+
 void QColorDialogPrivate::init(const QColor &initial)
 {
     Q_Q(QColorDialog);
@@ -1473,9 +1692,25 @@
     q->setSizeGripEnabled(false);
     q->setWindowTitle(QColorDialog::tr("Select Color"));
 
-    nativeDialogInUse = false;
+    // default: use the native dialog if possible.  Can be overridden in setOptions()
+    nativeDialogInUse = (platformColorDialogHelper() != nullptr);
+    colorPickingEventFilter = nullptr;
+    nextCust = 0;
+
+    if (!nativeDialogInUse)
+        initWidgets();
 
-    nextCust = 0;
+#ifdef Q_OS_WIN32
+    dummyTransparentWindow.resize(1, 1);
+    dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint);
+#endif
+
+    q->setCurrentColor(initial);
+}
+
+void QColorDialogPrivate::initWidgets()
+{
+    Q_Q(QColorDialog);
     QVBoxLayout *mainLay = new QVBoxLayout(q);
     // there's nothing in this dialog that benefits from sizing up
     mainLay->setSizeConstraint(QLayout::SetFixedSize);
@@ -1483,48 +1718,23 @@
     QHBoxLayout *topLay = new QHBoxLayout();
     mainLay->addLayout(topLay);
 
-    leftLay = 0;
+    leftLay = nullptr;
 
-#if defined(Q_WS_WINCE) || defined(QT_SMALL_COLORDIALOG)
+#if defined(QT_SMALL_COLORDIALOG)
     smallDisplay = true;
     const int lumSpace = 20;
 #else
     // small displays (e.g. PDAs) cannot fit the full color dialog,
     // so just use the color picker.
-    smallDisplay = (QApplication::desktop()->width() < 480 || QApplication::desktop()->height() < 350);
+    smallDisplay = (QGuiApplication::primaryScreen()->virtualGeometry().width() < 480 || QGuiApplication::primaryScreen()->virtualGeometry().height() < 350);
     const int lumSpace = topLay->spacing() / 2;
 #endif
 
     if (!smallDisplay) {
         leftLay = new QVBoxLayout;
         topLay->addLayout(leftLay);
-    }
 
-    initRGB();
-
-#ifndef QT_NO_SETTINGS
-    if (!customSet) {
-        QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
-        for (int i = 0; i < 2*8; ++i) {
-            QVariant v = settings.value(QLatin1String("Qt/customColors/") + QString::number(i));
-            if (v.isValid()) {
-                QRgb rgb = v.toUInt();
-                cusrgb[i] = rgb;
-            }
-        }
-    }
-#endif
-
-#if defined(QT_SMALL_COLORDIALOG)
-#  if defined(Q_WS_S60)
-    const bool nonTouchUI = !S60->hasTouchscreen;
-#  elif defined(Q_WS_MAEMO_5)
-    const bool nonTouchUI = false;
-#  endif
-#endif
-
-    if (!smallDisplay) {
-        standard = new QColorWell(q, 6, 8, stdrgb);
+        standard = new QColorWell(q, standardColorRows, colorColumns, QColorDialogOptions::standardColors());
         lblBasicColors = new QLabel(q);
 #ifndef QT_NO_SHORTCUT
         lblBasicColors->setBuddy(standard);
@@ -1533,14 +1743,33 @@
         leftLay->addWidget(lblBasicColors);
         leftLay->addWidget(standard);
 
-#if !defined(Q_WS_WINCE)
-        leftLay->addStretch();
+#if !defined(QT_SMALL_COLORDIALOG)
+        if (supportsColorPicking()) {
+            screenColorPickerButton = new QPushButton();
+            leftLay->addWidget(screenColorPickerButton);
+            lblScreenColorInfo = new QLabel("\n"_L1);
+            leftLay->addWidget(lblScreenColorInfo);
+            q->connect(screenColorPickerButton, SIGNAL(clicked()), SLOT(_q_pickScreenColor()));
+        } else {
+            screenColorPickerButton = nullptr;
+            lblScreenColorInfo = nullptr;
+        }
 #endif
 
-        custom = new QColorWell(q, 2, 8, cusrgb);
+        leftLay->addStretch();
+
+        custom = new QColorWell(q, customColorRows, colorColumns, QColorDialogOptions::customColors());
         custom->setAcceptDrops(true);
 
         q->connect(custom, SIGNAL(selected(int,int)), SLOT(_q_newCustom(int,int)));
+        q->connect(custom, SIGNAL(currentChanged(int,int)), SLOT(_q_nextCustom(int,int)));
+
+        q->connect(custom, &QWellArray::colorChanged, [this] (int index, QRgb color) {
+            QColorDialogOptions::setCustomColor(index, color);
+            if (custom)
+                custom->update();
+        });
+
         lblCustomColors = new QLabel(q);
 #ifndef QT_NO_SHORTCUT
         lblCustomColors->setBuddy(custom);
@@ -1554,17 +1783,17 @@
     } else {
         // better color picker size for small displays
 #if defined(QT_SMALL_COLORDIALOG)
-        QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
+        QSize screenSize = QGuiApplication::screenAt(QCursor::pos())->availableGeometry().size();
         pWidth = pHeight = qMin(screenSize.width(), screenSize.height());
         pHeight -= 20;
-        if(screenSize.height() > screenSize.width())
+        if (screenSize.height() > screenSize.width())
             pWidth -= 20;
 #else
         pWidth = 150;
         pHeight = 100;
 #endif
-        custom = 0;
-        standard = 0;
+        custom = nullptr;
+        standard = nullptr;
     }
 
     QVBoxLayout *rightLay = new QVBoxLayout;
@@ -1577,15 +1806,10 @@
     pickLay->addLayout(cLay);
     cp = new QColorPicker(q);
 
-    cp->setFrameStyle(QFrame::Panel + QFrame::Sunken);
+    cp->setFrameStyle(QFrame::Panel | QFrame::Sunken);
 
 #if defined(QT_SMALL_COLORDIALOG)
-    if (!nonTouchUI) {
-        pickLay->addWidget(cp);
-        cLay->addSpacing(lumSpace);
-    } else {
-        cp->hide();
-    }
+    cp->hide();
 #else
     cLay->addSpacing(lumSpace);
     cLay->addWidget(cp);
@@ -1594,18 +1818,12 @@
 
     lp = new QColorLuminancePicker(q);
 #if defined(QT_SMALL_COLORDIALOG)
-    QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
-    const int minDimension = qMin(screenSize.height(), screenSize.width());
-    //set picker to be finger-usable
-    int pickerWidth = !nonTouchUI ? minDimension/9 : minDimension/12;
-    lp->setFixedWidth(pickerWidth);
-    if (!nonTouchUI)
-        pickLay->addWidget(lp);
-    else
-        lp->hide();
+    lp->hide();
 #else
     lp->setFixedWidth(20);
+    pickLay->addSpacing(10);
     pickLay->addWidget(lp);
+    pickLay->addStretch();
 #endif
 
     QObject::connect(cp, SIGNAL(newCol(int,int)), lp, SLOT(setCol(int,int)));
@@ -1614,15 +1832,16 @@
     rightLay->addStretch();
 
     cs = new QColorShower(q);
+    pickLay->setContentsMargins(cs->gl->contentsMargins());
     QObject::connect(cs, SIGNAL(newCol(QRgb)), q, SLOT(_q_newColorTypedIn(QRgb)));
     QObject::connect(cs, SIGNAL(currentColorChanged(QColor)),
                      q, SIGNAL(currentColorChanged(QColor)));
 #if defined(QT_SMALL_COLORDIALOG)
-    if (!nonTouchUI)
-        pWidth -= cp->size().width();
     topLay->addWidget(cs);
 #else
     rightLay->addWidget(cs);
+    if (leftLay)
+        leftLay->addSpacing(cs->gl->contentsMargins().right());
 #endif
 
     buttons = new QDialogButtonBox(q);
@@ -1634,36 +1853,77 @@
     cancel = buttons->addButton(QDialogButtonBox::Cancel);
     QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject()));
 
+#ifdef Q_OS_WIN32
+    updateTimer = new QTimer(q);
+    QObject::connect(updateTimer, SIGNAL(timeout()), q, SLOT(_q_updateColorPicking()));
+#endif
     retranslateStrings();
+}
 
-#ifdef Q_WS_MAC
-    delegate = 0;
-#endif
+void QColorDialogPrivate::initHelper(QPlatformDialogHelper *h)
+{
+    QColorDialog *d = q_func();
+    QObject::connect(h, SIGNAL(currentColorChanged(QColor)), d, SIGNAL(currentColorChanged(QColor)));
+    QObject::connect(h, SIGNAL(colorSelected(QColor)), d, SIGNAL(colorSelected(QColor)));
+    static_cast<QPlatformColorDialogHelper *>(h)->setOptions(options);
+}
 
-    q->setCurrentColor(initial);
+void QColorDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
+{
+    options->setWindowTitle(q_func()->windowTitle());
 }
 
 void QColorDialogPrivate::_q_addCustom()
 {
-    cusrgb[nextCust] = cs->currentColor();
+    QColorDialogOptions::setCustomColor(nextCust, cs->currentColor());
     if (custom)
         custom->update();
-    nextCust = (nextCust+1) % 16;
+    nextCust = (nextCust+1) % QColorDialogOptions::customColorCount();
 }
 
 void QColorDialogPrivate::retranslateStrings()
 {
+    if (nativeDialogInUse)
+        return;
+
     if (!smallDisplay) {
         lblBasicColors->setText(QColorDialog::tr("&Basic colors"));
         lblCustomColors->setText(QColorDialog::tr("&Custom colors"));
         addCusBt->setText(QColorDialog::tr("&Add to Custom Colors"));
+#if !defined(QT_SMALL_COLORDIALOG)
+        if (screenColorPickerButton)
+            screenColorPickerButton->setText(QColorDialog::tr("&Pick Screen Color"));
+#endif
     }
 
     cs->retranslateStrings();
 }
 
-static const Qt::WindowFlags DefaultWindowFlags =
-        Qt::Dialog | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint
+bool QColorDialogPrivate::supportsColorPicking() const
+{
+    const auto integration = QGuiApplicationPrivate::platformIntegration();
+    return integration->hasCapability(QPlatformIntegration::ScreenWindowGrabbing)
+            || integration->services()->hasCapability(QPlatformServices::Capability::ColorPicking);
+}
+
+bool QColorDialogPrivate::canBeNativeDialog() const
+{
+    // Don't use Q_Q here! This function is called from ~QDialog,
+    // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
+    const QDialog * const q = static_cast<const QDialog*>(q_ptr);
+    if (nativeDialogInUse)
+        return true;
+    if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+        || q->testAttribute(Qt::WA_DontShowOnScreen)
+        || (options->options() & QColorDialog::DontUseNativeDialog)) {
+        return false;
+    }
+
+    return strcmp(QColorDialog::staticMetaObject.className(), q->metaObject()->className()) == 0;
+}
+
+static const Qt::WindowFlags qcd_DefaultWindowFlags =
+        Qt::Dialog | Qt::WindowTitleHint
         | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
 
 /*!
@@ -1671,6 +1931,7 @@
     \brief The QColorDialog class provides a dialog widget for specifying colors.
 
     \ingroup standard-dialogs
+    \inmodule QtWidgets
 
     The color dialog's function is to allow users to choose colors.
     For example, you might use this in a drawing program to allow the
@@ -1691,12 +1952,17 @@
     during the execution of the program. Use setCustomColor() to set
     the custom colors, and use customColor() to get them.
 
+    When pressing the "Pick Screen Color" button, the cursor changes to a haircross
+    and the colors on the screen are scanned. The user can pick up one by clicking
+    the mouse or the Enter button. Pressing Escape restores the last color selected
+    before entering this mode.
+
     The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
     how to use QColorDialog as well as other built-in Qt dialogs.
 
-    \image plastique-colordialog.png A color dialog in the Plastique widget style.
+    \image fusion-colordialog.png A color dialog in the Fusion widget style.
 
-    \sa QColor, QFileDialog, QPrintDialog, QFontDialog, {Standard Dialogs Example}
+    \sa QColor, QFileDialog, QFontDialog, {Standard Dialogs Example}
 */
 
 /*!
@@ -1705,10 +1971,8 @@
     Constructs a color dialog with the given \a parent.
 */
 QColorDialog::QColorDialog(QWidget *parent)
-    : QDialog(*new QColorDialogPrivate, parent, DefaultWindowFlags)
+    : QColorDialog(QColor(Qt::white), parent)
 {
-    Q_D(QColorDialog);
-    d->init(Qt::white);
 }
 
 /*!
@@ -1718,12 +1982,27 @@
     \a initial color.
 */
 QColorDialog::QColorDialog(const QColor &initial, QWidget *parent)
-    : QDialog(*new QColorDialogPrivate, parent, DefaultWindowFlags)
+    : QDialog(*new QColorDialogPrivate, parent, qcd_DefaultWindowFlags)
 {
     Q_D(QColorDialog);
     d->init(initial);
 }
 
+void QColorDialogPrivate::setCurrentColor(const QColor &color,  SetColorMode setColorMode)
+{
+    if (nativeDialogInUse) {
+        platformColorDialogHelper()->setCurrentColor(color);
+        return;
+    }
+
+    if (setColorMode & ShowColor) {
+        setCurrentRgbColor(color.rgb());
+        setCurrentAlpha(color.alpha());
+    }
+    if (setColorMode & SelectColor)
+        selectColor(color);
+}
+
 /*!
     \property QColorDialog::currentColor
     \brief the currently selected color in the dialog
@@ -1732,16 +2011,7 @@
 void QColorDialog::setCurrentColor(const QColor &color)
 {
     Q_D(QColorDialog);
-    d->setCurrentColor(color.rgb());
-    d->selectColor(color);
-    d->setCurrentAlpha(color.alpha());
-
-#ifdef Q_WS_MAC
-    d->setCurrentQColor(color);
-    d->setCocoaPanelColor(color);
-#endif
-    if (d->nativeDialogInUse)
-        qt_guiPlatformPlugin()->colorDialogSetCurrentColor(this, color);
+    d->setCurrentColor(color);
 }
 
 QColor QColorDialog::currentColor() const
@@ -1750,9 +2020,8 @@
     return d->currentQColor();
 }
 
-
 /*!
-    Returns the color that the user selected by clicking the \gui{OK}
+    Returns the color that the user selected by clicking the \uicontrol{OK}
     or equivalent button.
 
     \note This color is not always the same as the color held by the
@@ -1773,15 +2042,15 @@
 */
 void QColorDialog::setOption(ColorDialogOption option, bool on)
 {
-    Q_D(QColorDialog);
-    if (!(d->opts & option) != !on)
-        setOptions(d->opts ^ option);
+    const QColorDialog::ColorDialogOptions previousOptions = options();
+    if (!(previousOptions & option) != !on)
+        setOptions(previousOptions ^ option);
 }
 
 /*!
     \since 4.5
 
-    Returns true if the given \a option is enabled; otherwise, returns
+    Returns \c true if the given \a option is enabled; otherwise, returns
     false.
 
     \sa options, setOption()
@@ -1789,7 +2058,7 @@
 bool QColorDialog::testOption(ColorDialogOption option) const
 {
     Q_D(const QColorDialog);
-    return (d->opts & option) != 0;
+    return d->options->testOption(static_cast<QColorDialogOptions::ColorDialogOption>(option));
 }
 
 /*!
@@ -1808,19 +2077,24 @@
 {
     Q_D(QColorDialog);
 
-    ColorDialogOptions changed = (options ^ d->opts);
-    if (!changed)
+    if (QColorDialog::options() == options)
         return;
 
-    d->opts = options;
-    d->buttons->setVisible(!(options & NoButtons));
-    d->showAlpha(options & ShowAlphaChannel);
+    d->options->setOptions(QColorDialogOptions::ColorDialogOptions(int(options)));
+    if ((options & DontUseNativeDialog) && d->nativeDialogInUse) {
+        d->nativeDialogInUse = false;
+        d->initWidgets();
+    }
+    if (!d->nativeDialogInUse) {
+        d->buttons->setVisible(!(options & NoButtons));
+        d->showAlpha(options & ShowAlphaChannel);
+    }
 }
 
 QColorDialog::ColorDialogOptions QColorDialog::options() const
 {
     Q_D(const QColorDialog);
-    return d->opts;
+    return QColorDialog::ColorDialogOptions(int(d->options->options()));
 }
 
 /*!
@@ -1832,9 +2106,9 @@
     of a color dialog.
 
     \value ShowAlphaChannel Allow the user to select the alpha component of a color.
-    \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
-    \value DontUseNativeDialog Use Qt's standard color dialog on the Mac instead of the operating system
-                               native color dialog.
+    \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
+    \value DontUseNativeDialog  Use Qt's standard color dialog instead of the operating system
+                                native color dialog.
 
     \sa options, setOption(), testOption(), windowModality()
 */
@@ -1848,15 +2122,10 @@
     \sa color, colorSelected()
 */
 
-#ifdef Q_WS_MAC
-// can only have one Cocoa color panel active
-bool QColorDialogPrivate::sharedColorPanelAvailable = true;
-#endif
-
 /*!
     \fn void QColorDialog::colorSelected(const QColor &color);
 
-    This signal is emitted just after the user has clicked \gui{OK} to
+    This signal is emitted just after the user has clicked \uicontrol{OK} to
     select a color to use. The chosen color is specified by \a color.
 
     \sa color, currentColorChanged()
@@ -1868,51 +2137,45 @@
 */
 void QColorDialog::setVisible(bool visible)
 {
-    Q_D(QColorDialog);
-
-    if (visible){
-        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
-            return;
-    } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
-        return;
-
-    if (visible)
-        d->selectedQColor = QColor();
-
-#if defined(Q_WS_MAC)
-    if (visible) {
-        if (d->delegate || (QColorDialogPrivate::sharedColorPanelAvailable &&
-                !(testAttribute(Qt::WA_DontShowOnScreen) || (d->opts & DontUseNativeDialog)))){
-            d->openCocoaColorPanel(currentColor(), parentWidget(), windowTitle(), options());
-            QColorDialogPrivate::sharedColorPanelAvailable = false;
-            setAttribute(Qt::WA_DontShowOnScreen);
-        }
-        setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags);
-    } else {
-        if (d->delegate) {
-            d->closeCocoaColorPanel();
-            QColorDialogPrivate::sharedColorPanelAvailable = true;
-            setAttribute(Qt::WA_DontShowOnScreen, false);
-        }
-    }
-#else
-
-    if (!(d->opts & DontUseNativeDialog) && qt_guiPlatformPlugin()->colorDialogSetVisible(this, visible)) {
-        d->nativeDialogInUse = true;
-        // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
-        // updates the state correctly, but skips showing the non-native version:
-        setAttribute(Qt::WA_DontShowOnScreen);
-    } else {
-        d->nativeDialogInUse = false;
-        setAttribute(Qt::WA_DontShowOnScreen, false);
-    }
-#endif
-
+    // will call QColorDialogPrivate::setVisible override
     QDialog::setVisible(visible);
 }
 
 /*!
-    \overload
+    \internal
+
+    The implementation of QColorDialog::setVisible() has to live here so that the call
+    to hide() in ~QDialog calls this function; it wouldn't call the override of
+    QDialog::setVisible().
+*/
+void QColorDialogPrivate::setVisible(bool visible)
+{
+    Q_Q(QColorDialog);
+    if (visible){
+        if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden))
+            return;
+    } else if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden))
+        return;
+
+    if (visible)
+        selectedQColor = QColor();
+
+    if (nativeDialogInUse) {
+        if (setNativeDialogVisible(visible)) {
+            // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+            // updates the state correctly, but skips showing the non-native version:
+            q->setAttribute(Qt::WA_DontShowOnScreen);
+        } else {
+            initWidgets();
+        }
+    } else {
+        q->setAttribute(Qt::WA_DontShowOnScreen, false);
+    }
+
+    QDialogPrivate::setVisible(visible);
+}
+
+/*!
     \since 4.5
 
     Opens the dialog and connects its colorSelected() signal to the slot specified
@@ -1930,22 +2193,6 @@
 }
 
 /*!
-    \fn QColorDialog::open()
-
-    \since 4.5
-    Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
-    returning immediately.
-
-    \sa QDialog::open()
-*/
-
-/*
-    For Symbian color dialogs
-*/
-#ifdef Q_WS_S60
-extern QColor qtSymbianGetColor(const QColor &initial);
-#endif
-/*!
     \since 4.5
 
     Pops up a modal color dialog with the given window \a title (or "Select Color" if none is
@@ -1954,19 +2201,10 @@
     QColor::isValid()) color if the user cancels the dialog.
 
     The \a options argument allows you to customize the dialog.
-
-    On Symbian, this static function will use the native color dialog and not a QColorDialog.
-    On Symbian the parameters \a title and \a parent has no relevance and the
-    \a options parameter is only used to define if the native color dialog is
-    used or not.
 */
 QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QString &title,
                               ColorDialogOptions options)
 {
-#ifdef Q_WS_S60
-    if (!(options & DontUseNativeDialog))
-        return qtSymbianGetColor(initial);
-#endif
     QColorDialog dlg(parent);
     if (!title.isEmpty())
         dlg.setWindowTitle(title);
@@ -1977,76 +2215,13 @@
 }
 
 /*!
-    Pops up a modal color dialog, lets the user choose a color, and
-    returns that color. The color is initially set to \a initial. The
-    dialog is a child of \a parent. It returns an invalid (see
-    QColor::isValid()) color if the user cancels the dialog.
-
-    On Symbian, this static function will use the native
-    color dialog and not a QColorDialog.
-*/
-
-QColor QColorDialog::getColor(const QColor &initial, QWidget *parent)
-{
-#ifdef Q_WS_S60
-    return qtSymbianGetColor(initial);
-#endif
-    return getColor(initial, parent, QString(), ColorDialogOptions(0));
-}
-
-
-/*!
-    \obsolete
-
-    Pops up a modal color dialog to allow the user to choose a color
-    and an alpha channel (transparency) value. The color+alpha is
-    initially set to \a initial. The dialog is a child of \a parent.
-
-    If \a ok is non-null, \e *\a ok is set to true if the user clicked
-    \gui{OK}, and to false if the user clicked Cancel.
-
-    If the user clicks Cancel, the \a initial value is returned.
-
-    Use QColorDialog::getColor() instead, passing the
-    QColorDialog::ShowAlphaChannel option.
-*/
-
-QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent)
-{
-    QColor color(getColor(QColor(initial), parent, QString(), ShowAlphaChannel));
-    QRgb result = color.isValid() ? color.rgba() : initial;
-    if (ok)
-        *ok = color.isValid();
-    return result;
-}
-
-/*!
     Destroys the color dialog.
 */
 
 QColorDialog::~QColorDialog()
 {
-    Q_D(QColorDialog);
-#if defined(Q_WS_MAC)
-    if (d->delegate) {
-        d->releaseCocoaColorPanelDelegate();
-        QColorDialogPrivate::sharedColorPanelAvailable = true;
-    }
-#endif
-
-#ifndef QT_NO_SETTINGS
-    if (!customSet) {
-        QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
-        for (int i = 0; i < 2*8; ++i)
-            settings.setValue(QLatin1String("Qt/customColors/") + QString::number(i), cusrgb[i]);
-    }
-#endif
-    if (d->nativeDialogInUse)
-        qt_guiPlatformPlugin()->colorDialogDelete(this);
-
 }
 
-
 /*!
     \reimp
 */
@@ -2058,6 +2233,67 @@
     QDialog::changeEvent(e);
 }
 
+void QColorDialogPrivate::_q_updateColorPicking()
+{
+#ifndef QT_NO_CURSOR
+    Q_Q(QColorDialog);
+    static QPoint lastGlobalPos;
+    QPoint newGlobalPos = QCursor::pos();
+    if (lastGlobalPos == newGlobalPos)
+        return;
+    lastGlobalPos = newGlobalPos;
+
+    if (!q->rect().contains(q->mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called
+        updateColorPicking(newGlobalPos);
+#ifdef Q_OS_WIN32
+        dummyTransparentWindow.setPosition(newGlobalPos);
+#endif
+    }
+#endif // ! QT_NO_CURSOR
+}
+
+void QColorDialogPrivate::updateColorPicking(const QPoint &globalPos)
+{
+    const QColor color = grabScreenColor(globalPos);
+    // QTBUG-39792, do not change standard, custom color selectors while moving as
+    // otherwise it is not possible to pre-select a custom cell for assignment.
+    setCurrentColor(color, ShowColor);
+    updateColorLabelText(globalPos);
+}
+
+bool QColorDialogPrivate::handleColorPickingMouseMove(QMouseEvent *e)
+{
+    // If the cross is visible the grabbed color will be black most of the times
+    cp->setCrossVisible(!cp->geometry().contains(e->position().toPoint()));
+
+    updateColorPicking(e->globalPosition().toPoint());
+    return true;
+}
+
+bool QColorDialogPrivate::handleColorPickingMouseButtonRelease(QMouseEvent *e)
+{
+    setCurrentColor(grabScreenColor(e->globalPosition().toPoint()), SetColorAll);
+    releaseColorPicking();
+    return true;
+}
+
+bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e)
+{
+    Q_Q(QColorDialog);
+#if QT_CONFIG(shortcut)
+    if (e->matches(QKeySequence::Cancel)) {
+        releaseColorPicking();
+        q->setCurrentColor(beforeScreenColorPicking);
+    } else
+#endif
+      if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
+        q->setCurrentColor(grabScreenColor(QCursor::pos()));
+        releaseColorPicking();
+    }
+    e->accept();
+    return true;
+}
+
 /*!
   Closes the dialog and sets its result code to \a result. If this dialog
   is shown with exec(), done() causes the local event loop to finish,
@@ -2068,17 +2304,17 @@
 void QColorDialog::done(int result)
 {
     Q_D(QColorDialog);
-    QDialog::done(result);
     if (result == Accepted) {
         d->selectedQColor = d->currentQColor();
         emit colorSelected(d->selectedQColor);
     } else {
         d->selectedQColor = QColor();
     }
+    QDialog::done(result);
     if (d->receiverToDisconnectOnClose) {
         disconnect(this, SIGNAL(colorSelected(QColor)),
                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
-        d->receiverToDisconnectOnClose = 0;
+        d->receiverToDisconnectOnClose = nullptr;
     }
     d->memberToDisconnectOnClose.clear();
 }
@@ -2087,15 +2323,3 @@
 
 #include "qcolordialog.moc"
 #include "moc_qcolordialog.cpp"
-
-#endif // QT_NO_COLORDIALOG
-
-/*!
-    \fn QColor QColorDialog::getColor(const QColor &init, QWidget *parent, const char *name)
-    \compat
-*/
-
-/*!
-    \fn QRgb QColorDialog::getRgba(QRgb rgba, bool *ok, QWidget *parent, const char *name)
-    \compat
-*/
--- a/libgui/languages/build_ts/octave-qt/qdialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qdialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,110 +1,204 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-#include "qdialog.h"
-
+#include <QtWidgets/qtwidgetsglobal.h>
+#if QT_CONFIG(colordialog)
+#include "qcolordialog.h"
+#endif
+#if QT_CONFIG(fontdialog)
+#include "qfontdialog.h"
+#endif
+#if QT_CONFIG(filedialog)
+#include "qfiledialog.h"
+#endif
 
 #include "qevent.h"
-#include "qdesktopwidget.h"
-#include "qpushbutton.h"
 #include "qapplication.h"
 #include "qlayout.h"
+#if QT_CONFIG(sizegrip)
 #include "qsizegrip.h"
+#endif
+#if QT_CONFIG(whatsthis)
 #include "qwhatsthis.h"
+#endif
+#if QT_CONFIG(menu)
 #include "qmenu.h"
-#include "qcursor.h"
-#include "private/qdialog_p.h"
-#ifndef QT_NO_ACCESSIBILITY
-#include "qaccessible.h"
 #endif
-#if defined(Q_WS_WINCE)
-#include "qt_windows.h"
-#include "qmenubar.h"
-#include "qpointer.h"
-#include "qguifunctions_wince.h"
-extern bool qt_wince_is_mobile();     //defined in qguifunctions_wce.cpp
-extern bool qt_wince_is_smartphone(); //is defined in qguifunctions_wce.cpp
-#elif defined(Q_WS_X11)
-#  include "../kernel/qt_x11_p.h"
-#elif defined(Q_OS_SYMBIAN)
-#   include "qfiledialog.h"
-#   include "qfontdialog.h"
-#   include "qwizard.h"
-#   include "private/qt_s60_p.h"
-#elif defined(Q_OS_BLACKBERRY)
-#   include "qmessagebox.h"
+#include "qcursor.h"
+#if QT_CONFIG(messagebox)
+#include "qmessagebox.h"
 #endif
-
-#if defined(Q_WS_S60)
-#include <AknUtils.h>               // AknLayoutUtils
+#if QT_CONFIG(errormessage)
+#include "qerrormessage.h"
 #endif
-
-#ifndef SPI_GETSNAPTODEFBUTTON
-#   define SPI_GETSNAPTODEFBUTTON  95
+#include <qpa/qplatformtheme.h>
+#include "private/qdialog_p.h"
+#include "private/qguiapplication_p.h"
+#if QT_CONFIG(accessibility)
+#include "qaccessible.h"
 #endif
 
 QT_BEGIN_NAMESPACE
 
+static inline int themeDialogType(const QDialog *dialog)
+{
+#if QT_CONFIG(filedialog)
+    if (qobject_cast<const QFileDialog *>(dialog))
+        return QPlatformTheme::FileDialog;
+#endif
+#if QT_CONFIG(colordialog)
+    if (qobject_cast<const QColorDialog *>(dialog))
+        return QPlatformTheme::ColorDialog;
+#endif
+#if QT_CONFIG(fontdialog)
+    if (qobject_cast<const QFontDialog *>(dialog))
+        return QPlatformTheme::FontDialog;
+#endif
+#if QT_CONFIG(messagebox)
+    if (qobject_cast<const QMessageBox *>(dialog))
+        return QPlatformTheme::MessageDialog;
+#endif
+#if QT_CONFIG(errormessage)
+    if (qobject_cast<const QErrorMessage *>(dialog))
+        return QPlatformTheme::MessageDialog;
+#endif
+#if !QT_CONFIG(filedialog) && !QT_CONFIG(colordialog) && !QT_CONFIG(fontdialog) && \
+    !QT_CONFIG(messagebox) && !QT_CONFIG(errormessage)
+    Q_UNUSED(dialog);
+#endif
+    return -1;
+}
+
+QDialogPrivate::~QDialogPrivate()
+{
+    delete m_platformHelper;
+}
+
+QPlatformDialogHelper *QDialogPrivate::platformHelper() const
+{
+    // Delayed creation of the platform, ensuring that
+    // that qobject_cast<> on the dialog works in the plugin.
+    if (!m_platformHelperCreated && canBeNativeDialog()) {
+        m_platformHelperCreated = true;
+        QDialogPrivate *ncThis = const_cast<QDialogPrivate *>(this);
+        QDialog *dialog = ncThis->q_func();
+        const int type = themeDialogType(dialog);
+        if (type >= 0) {
+            m_platformHelper = QGuiApplicationPrivate::platformTheme()
+                    ->createPlatformDialogHelper(static_cast<QPlatformTheme::DialogType>(type));
+            if (m_platformHelper) {
+                QObject::connect(m_platformHelper, SIGNAL(accept()), dialog, SLOT(accept()));
+                QObject::connect(m_platformHelper, SIGNAL(reject()), dialog, SLOT(reject()));
+                ncThis->initHelper(m_platformHelper);
+            }
+        }
+    }
+    return m_platformHelper;
+}
+
+bool QDialogPrivate::canBeNativeDialog() const
+{
+    if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs))
+        return false;
+
+    QDialogPrivate *ncThis = const_cast<QDialogPrivate *>(this);
+    QDialog *dialog = ncThis->q_func();
+    const int type = themeDialogType(dialog);
+    if (type >= 0)
+        return QGuiApplicationPrivate::platformTheme()
+                ->usePlatformNativeDialog(static_cast<QPlatformTheme::DialogType>(type));
+    return false;
+}
+
+/*!
+    \internal
+
+    Properly closes dialog and sets the \a resultCode.
+ */
+void QDialogPrivate::close(int resultCode)
+{
+    Q_Q(QDialog);
+
+    q->setResult(resultCode);
+
+    if (!data.is_closing) {
+        // Until Qt 6.3 we didn't close dialogs, so they didn't receive a QCloseEvent.
+        // It is likely that subclasses implement closeEvent and handle them as rejection
+        // (like QMessageBox and QProgressDialog do), so eat those events.
+        struct CloseEventEater : QObject
+        {
+            using QObject::QObject;
+        protected:
+            bool eventFilter(QObject *o, QEvent *e) override
+            {
+                if (e->type() == QEvent::Close)
+                    return true;
+                return QObject::eventFilter(o, e);
+            }
+        } closeEventEater;
+        q->installEventFilter(&closeEventEater);
+        QWidgetPrivate::close();
+    } else {
+        // If the close was initiated outside of QDialog we will end up
+        // here via QDialog::closeEvent calling reject(), in which case
+        // we need to hide the dialog to ensure QDialog::closeEvent does
+        // not ignore the close event. FIXME: Why is QDialog doing this?
+        q->hide();
+    }
+
+    resetModalitySetByOpen();
+}
+
+QWindow *QDialogPrivate::transientParentWindow() const
+{
+    Q_Q(const QDialog);
+    if (const QWidget *parent = q->nativeParentWidget())
+        return parent->windowHandle();
+    else if (q->windowHandle())
+        return q->windowHandle()->transientParent();
+    return nullptr;
+}
+
+bool QDialogPrivate::setNativeDialogVisible(bool visible)
+{
+    if (QPlatformDialogHelper *helper = platformHelper()) {
+        if (visible) {
+            Q_Q(QDialog);
+            helperPrepareShow(helper);
+            nativeDialogInUse = helper->show(q->windowFlags(), q->windowModality(), transientParentWindow());
+        } else if (nativeDialogInUse) {
+            helper->hide();
+        }
+    }
+    return nativeDialogInUse;
+}
+
+QVariant QDialogPrivate::styleHint(QPlatformDialogHelper::StyleHint hint) const
+{
+    if (const QPlatformDialogHelper *helper = platformHelper())
+        return helper->styleHint(hint);
+    return QPlatformDialogHelper::defaultStyleHint(hint);
+}
+
 /*!
     \class QDialog
     \brief The QDialog class is the base class of dialog windows.
 
     \ingroup dialog-classes
     \ingroup abstractwidgets
-
+    \inmodule QtWidgets
 
     A dialog window is a top-level window mostly used for short-term
     tasks and brief communications with the user. QDialogs may be
     modal or modeless. QDialogs can
-    provide a \link #return return
-    value\endlink, and they can have \link #default default
-    buttons\endlink. QDialogs can also have a QSizeGrip in their
+    provide a \l{#return}{return value}, and they can have \l{#default}{default buttons}. QDialogs can also have a QSizeGrip in their
     lower-right corner, using setSizeGripEnabled().
 
     Note that QDialog (and any other widget that has type \c Qt::Dialog) uses
-    the parent widget slightly differently from other classes in Qt. A
-    dialog is always a top-level widget, but if it has a parent, its
-    default location is centered on top of the parent's top-level widget
-    (if it is not top-level itself). It will also share the parent's
-    taskbar entry.
+    the parent widget slightly differently from other classes in Qt. A dialog is
+    always a top-level widget, but if it has a parent, its default location is
+    centered on top of the parent's top-level widget (if it is not top-level
+    itself). It will also share the parent's taskbar entry.
 
     Use the overload of the QWidget::setParent() function to change
     the ownership of a QDialog widget. This function allows you to
@@ -113,9 +207,16 @@
     window-system properties for the widget (in particular it will
     reset the Qt::Dialog flag).
 
+    \note The parent relationship of the dialog does \e{not} imply
+    that the dialog will always be stacked on top of the parent
+    window. To ensure that the dialog is always on top, make the
+    dialog modal. This also applies for child windows of the dialog
+    itself. To ensure that child windows of the dialog stay on top
+    of the dialog, make the child windows modal as well.
+
     \section1 Modal Dialogs
 
-    A \bold{modal} dialog is a dialog that blocks input to other
+    A \b{modal} dialog is a dialog that blocks input to other
     visible windows in the same application. Dialogs that are used to
     request a file name from the user or that are used to set
     application preferences are usually modal. Dialogs can be
@@ -130,12 +231,11 @@
 
     The most common way to display a modal dialog is to call its
     exec() function. When the user closes the dialog, exec() will
-    provide a useful \link #return return value\endlink. Typically,
-    to get the dialog to close and return the appropriate value, we
-    connect a default button, e.g. \gui OK, to the accept() slot and a
-    \gui Cancel button to the reject() slot.
-    Alternatively you can call the done() slot with \c Accepted or
-    \c Rejected.
+    provide a useful \l{#return}{return value}. To close the dialog
+    and return the appropriate value, you must connect a default button,
+    e.g. an \uicontrol OK button to the accept() slot and a
+    \uicontrol Cancel button to the reject() slot. Alternatively, you
+    can call the done() slot with \c Accepted or \c Rejected.
 
     An alternative is to call setModal(true) or setWindowModality(),
     then show(). Unlike exec(), show() returns control to the caller
@@ -143,13 +243,13 @@
     progress dialogs, where the user must have the ability to interact
     with the dialog, e.g.  to cancel a long running operation. If you
     use show() and setModal(true) together to perform a long operation,
-    you must call QApplication::processEvents() periodically during
+    you must call QCoreApplication::processEvents() periodically during
     processing to enable the user to interact with the dialog. (See
     QProgressDialog.)
 
     \section1 Modeless Dialogs
 
-    A \bold{modeless} dialog is a dialog that operates
+    A \b{modeless} dialog is a dialog that operates
     independently of other windows in the same application. Find and
     replace dialogs in word-processors are often modeless to allow the
     user to interact with both the application's main window and with
@@ -180,9 +280,8 @@
     \section1 Escape Key
 
     If the user presses the Esc key in a dialog, QDialog::reject()
-    will be called. This will cause the window to close: The \link
-    QCloseEvent close event \endlink cannot be \link
-    QCloseEvent::ignore() ignored \endlink.
+    will be called. This will cause the window to close:
+    The \l{QCloseEvent}{close event} cannot be \l{QEvent::ignore()}{ignored}.
 
     \section1 Extensibility
 
@@ -190,16 +289,15 @@
     partial dialog that shows the most commonly used options, and a
     full dialog that shows all the options. Typically an extensible
     dialog will initially appear as a partial dialog, but with a
-    \gui More toggle button. If the user presses the \gui More button down,
-    the dialog is expanded. The \l{Extension Example} shows how to achieve
-    extensible dialogs using Qt.
+    \uicontrol More toggle button. If the user presses the
+    \uicontrol More button down, the dialog is expanded.
 
     \target return
     \section1 Return Value (Modal Dialogs)
 
     Modal dialogs are often used in situations where a return value is
-    required, e.g. to indicate whether the user pressed \gui OK or
-    \gui Cancel. A dialog can be closed by calling the accept() or the
+    required, e.g. to indicate whether the user pressed \uicontrol OK or
+    \uicontrol Cancel. A dialog can be closed by calling the accept() or the
     reject() slots, and exec() will return \c Accepted or \c Rejected
     as appropriate. The exec() call returns the result of the dialog.
     The result is also available from result() if the dialog has not
@@ -216,14 +314,17 @@
 
     A modal dialog:
 
-    \snippet doc/src/snippets/dialogs/dialogs.cpp 1
+    \snippet dialogs/dialogs.cpp 1
 
     A modeless dialog:
 
-    \snippet doc/src/snippets/dialogs/dialogs.cpp 0
+    \snippet dialogs/dialogs.cpp 0
+
+    A dialog with an extension:
+
+    \snippet dialogs/dialogs.cpp extension
 
     \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog,
-        {fowler}{GUI Design Handbook: Dialogs, Standard}, {Extension Example},
         {Standard Dialogs Example}
 */
 
@@ -262,36 +363,8 @@
     : QWidget(*new QDialogPrivate, parent,
               f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
 {
-#ifdef Q_WS_WINCE
-    if (!qt_wince_is_smartphone())
-        setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
-#endif
-
-#ifdef Q_WS_S60
-    if (S60->avkonComponentsSupportTransparency) {
-        bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
-        setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
-        setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
-    }
-#endif
 }
 
-#ifdef QT3_SUPPORT
-/*!
-    \overload
-    \obsolete
-*/
-QDialog::QDialog(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f)
-    : QWidget(*new QDialogPrivate, parent,
-              f
-              | QFlag(modal ? Qt::WShowModal : Qt::WindowType(0))
-              | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0))
-        )
-{
-    setObjectName(QString::fromAscii(name));
-}
-#endif
-
 /*!
   \overload
   \internal
@@ -299,18 +372,6 @@
 QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f)
     : QWidget(dd, parent, f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
 {
-#ifdef Q_WS_WINCE
-    if (!qt_wince_is_smartphone())
-        setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
-#endif
-
-#ifdef Q_WS_S60
-    if (S60->avkonComponentsSupportTransparency) {
-        bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
-        setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
-        setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
-    }
-#endif
 }
 
 /*!
@@ -331,10 +392,11 @@
 /*!
   \internal
   This function is called by the push button \a pushButton when it
-  becomes the default button. If \a pushButton is 0, the dialogs
+  becomes the default button. If \a pushButton is \nullptr, the dialogs
   default default button becomes the default button. This is what a
   push button calls when it loses focus.
 */
+#if QT_CONFIG(pushbutton)
 void QDialogPrivate::setDefault(QPushButton *pushButton)
 {
     Q_Q(QDialog);
@@ -362,7 +424,7 @@
 */
 void QDialogPrivate::setMainDefault(QPushButton *pushButton)
 {
-    mainDef = 0;
+    mainDef = nullptr;
     setDefault(pushButton);
 }
 
@@ -379,6 +441,7 @@
         list.at(i)->setDefault(false);
     }
 }
+#endif
 
 void QDialogPrivate::resetModalitySetByOpen()
 {
@@ -387,7 +450,7 @@
         // open() changed the window modality and the user didn't touch it afterwards; restore it
         q->setWindowModality(Qt::WindowModality(resetModalityTo));
         q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
         Q_ASSERT(resetModalityTo != Qt::WindowModal);
         q->setParent(q->parentWidget(), Qt::Dialog);
 #endif
@@ -395,46 +458,12 @@
     resetModalityTo = -1;
 }
 
-#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
-#ifdef Q_WS_WINCE_WM
-void QDialogPrivate::_q_doneAction()
-{
-    //Done...
-    QApplication::postEvent(q_func(), new QEvent(QEvent::OkRequest));
-}
-#endif
+/*!
+  In general returns the modal dialog's result code, \c Accepted or
+  \c Rejected.
 
-/*!
-    \reimp
-*/
-bool QDialog::event(QEvent *e)
-{
-    bool result = QWidget::event(e);
-#ifdef Q_WS_WINCE
-    if (e->type() == QEvent::OkRequest) {
-        accept();
-        result = true;
-     }
-#elif defined(Q_WS_S60)
-    if ((e->type() == QEvent::StyleChange) || (e->type() == QEvent::Resize )) {
-        if (!testAttribute(Qt::WA_Moved)) {
-            Qt::WindowStates state = windowState();
-            adjustPosition(parentWidget());
-            setAttribute(Qt::WA_Moved, false); // not really an explicit position
-            if (state != windowState())
-                setWindowState(state);
-        }
-    }
-    // TODO is Symbian, non-S60 behaviour required?
-#endif
-    return result;
-}
-#endif
-
-/*!
-  In general returns the modal dialog's result code, \c Accepted or \c Rejected.
-
-  \note When used from QMessageBox instance the result code type is \l QMessageBox::StandardButton
+  \note When called on a QMessageBox instance, the returned value is a
+  value of the \l QMessageBox::StandardButton enum.
 
   Do not call this function if the dialog was constructed with the
   Qt::WA_DeleteOnClose attribute.
@@ -477,7 +506,7 @@
         d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
         setWindowModality(Qt::WindowModal);
         setAttribute(Qt::WA_SetWindowModality, false);
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
         setParent(parentWidget(), Qt::Sheet);
 #endif
     }
@@ -497,6 +526,13 @@
     interaction with the parent window is blocked while the dialog is open.
     By default, the dialog is application modal.
 
+    \note Avoid using this function; instead, use \c{open()}. Unlike exec(),
+    open() is asynchronous, and does not spin an additional event loop. This
+    prevents a series of dangerous bugs from happening (e.g. deleting the
+    dialog's parent while the dialog is open via exec()). When using open() you
+    can connect to the finished() signal of QDialog to be notified when the
+    dialog is closed.
+
     \sa open(), show(), result(), setWindowModality()
 */
 
@@ -504,7 +540,7 @@
 {
     Q_D(QDialog);
 
-    if (d->eventLoop) {
+    if (Q_UNLIKELY(d->eventLoop)) {
         qWarning("QDialog::exec: Recursive call detected");
         return -1;
     }
@@ -518,101 +554,71 @@
     setAttribute(Qt::WA_ShowModal, true);
     setResult(0);
 
-//On Windows Mobile we create an empty menu to hide the current menu
-#ifdef Q_WS_WINCE_WM
-#ifndef QT_NO_MENUBAR
-    QMenuBar *menuBar = 0;
-    if (!findChild<QMenuBar *>())
-        menuBar = new QMenuBar(this);
-    if (qt_wince_is_smartphone()) {
-        QAction *doneAction = new QAction(tr("Done"), this);
-        menuBar->setDefaultAction(doneAction);
-        connect(doneAction, SIGNAL(triggered()), this, SLOT(_q_doneAction()));
-    }
-#endif //QT_NO_MENUBAR
-#endif //Q_WS_WINCE_WM
-
-    bool showSystemDialogFullScreen = false;
-
-#ifdef Q_OS_SYMBIAN
-    if (qobject_cast<QFileDialog *>(this) || qobject_cast<QFontDialog *>(this) ||
-        qobject_cast<QWizard *>(this)) {
-        showSystemDialogFullScreen = true;
-    }
-#endif // Q_OS_SYMBIAN
-
-#ifdef Q_OS_BLACKBERRY
-    if (!qobject_cast<QMessageBox *>(this))
-        showSystemDialogFullScreen = true;
-#endif // Q_OS_BLACKBERRY
-
-    if (showSystemDialogFullScreen) {
-        setWindowFlags(windowFlags() | Qt::WindowSoftkeysVisibleHint);
-        setWindowState(Qt::WindowFullScreen);
-    }
     show();
 
-#ifdef Q_WS_MAC
-    d->mac_nativeDialogModalHelp();
-#endif
-
-    QEventLoop eventLoop;
-    d->eventLoop = &eventLoop;
     QPointer<QDialog> guard = this;
-    () eventLoop.exec(QEventLoop::DialogExec);
+    if (d->nativeDialogInUse) {
+        d->platformHelper()->exec();
+    } else {
+        QEventLoop eventLoop;
+        d->eventLoop = &eventLoop;
+        (void) eventLoop.exec(QEventLoop::DialogExec);
+    }
     if (guard.isNull())
         return QDialog::Rejected;
-    d->eventLoop = 0;
+    d->eventLoop = nullptr;
 
     setAttribute(Qt::WA_ShowModal, wasShowModal);
 
     int res = result();
+    if (d->nativeDialogInUse)
+        d->helperDone(static_cast<QDialog::DialogCode>(res), d->platformHelper());
     if (deleteOnClose)
         delete this;
-#ifdef Q_WS_WINCE_WM
-#ifndef QT_NO_MENUBAR
-    else if (menuBar)
-        delete menuBar;
-#endif //QT_NO_MENUBAR
-#endif //Q_WS_WINCE_WM
     return res;
 }
 
+/*!
+  Closes the dialog and sets its result code to \a r. The finished() signal
+  will emit \a r; if \a r is QDialog::Accepted or QDialog::Rejected, the
+  accepted() or the rejected() signals will also be emitted, respectively.
 
-/*!
-  Closes the dialog and sets its result code to \a r. If this dialog
-  is shown with exec(), done() causes the local event loop to finish,
-  and exec() to return \a r.
+  If this dialog is shown with exec(), done() also causes the local event loop
+  to finish, and exec() to return \a r.
 
   As with QWidget::close(), done() deletes the dialog if the
   Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
   main widget, the application terminates. If the dialog is the
-  last window closed, the QApplication::lastWindowClosed() signal is
+  last window closed, the QGuiApplication::lastWindowClosed() signal is
   emitted.
 
-  \sa accept(), reject(), QApplication::activeWindow(), QApplication::quit()
+  \sa accept(), reject(), QApplication::activeWindow(), QCoreApplication::quit()
 */
 
 void QDialog::done(int r)
 {
+    QPointer<QDialog> guard(this);
+
     Q_D(QDialog);
-    hide();
-    setResult(r);
+    d->close(r);
+
+    if (!guard)
+        return;
 
-    d->close_helper(QWidgetPrivate::CloseNoEvent);
-    d->resetModalitySetByOpen();
+    int dialogCode = d->dialogCode();
+    if (dialogCode == QDialog::Accepted)
+        emit accepted();
+    else if (dialogCode == QDialog::Rejected)
+        emit rejected();
 
-    emit finished(r);
-    if (r == Accepted)
-        emit accepted();
-    else if (r == Rejected)
-        emit rejected();
+    if (guard)
+        emit finished(r);
 }
 
 /*!
   Hides the modal dialog and sets the result code to \c Accepted.
 
-  \sa reject() done()
+  \sa reject(), done()
 */
 
 void QDialog::accept()
@@ -623,7 +629,7 @@
 /*!
   Hides the modal dialog and sets the result code to \c Rejected.
 
-  \sa accept() done()
+  \sa accept(), done()
 */
 
 void QDialog::reject()
@@ -645,24 +651,24 @@
 /*! \reimp */
 void QDialog::contextMenuEvent(QContextMenuEvent *e)
 {
-#if defined(QT_NO_WHATSTHIS) || defined(QT_NO_MENU)
+#if !QT_CONFIG(whatsthis) || !QT_CONFIG(menu)
     Q_UNUSED(e);
 #else
     QWidget *w = childAt(e->pos());
     if (!w) {
-        w = rect().contains(e->pos()) ? this : 0;
+        w = rect().contains(e->pos()) ? this : nullptr;
         if (!w)
             return;
     }
     while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
-        w = w->isWindow() ? 0 : w->parentWidget();
+        w = w->isWindow() ? nullptr : w->parentWidget();
     if (w) {
-        QWeakPointer<QMenu> p = new QMenu(this);
+        QPointer<QMenu> p = new QMenu(this);
         QAction *wt = p.data()->addAction(tr("What's This?"));
         if (p.data()->exec(e->globalPos()) == wt) {
             QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
                          w->mapToGlobal(w->rect().center()));
-            QApplication::sendEvent(w, &e);
+            QCoreApplication::sendEvent(w, &e);
         }
         delete p.data();
     }
@@ -673,16 +679,17 @@
 /*! \reimp */
 void QDialog::keyPressEvent(QKeyEvent *e)
 {
+#ifndef QT_NO_SHORTCUT
     //   Calls reject() if Escape is pressed. Simulates a button
     //   click for the default button if Enter is pressed. Move focus
     //   for the arrow keys. Ignore the rest.
-#ifdef Q_WS_MAC
-    if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
+    if (e->matches(QKeySequence::Cancel)) {
         reject();
     } else
 #endif
     if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
         switch (e->key()) {
+#if QT_CONFIG(pushbutton)
         case Qt::Key_Enter:
         case Qt::Key_Return: {
             QList<QPushButton*> list = findChildren<QPushButton*>();
@@ -696,9 +703,7 @@
             }
         }
         break;
-        case Qt::Key_Escape:
-            reject();
-            break;
+#endif
         default:
             e->ignore();
             return;
@@ -711,7 +716,7 @@
 /*! \reimp */
 void QDialog::closeEvent(QCloseEvent *e)
 {
-#ifndef QT_NO_WHATSTHIS
+#if QT_CONFIG(whatsthis)
     if (isModal() && QWhatsThis::inWhatsThisMode())
         QWhatsThis::leaveWhatsThisMode();
 #endif
@@ -735,81 +740,109 @@
 void QDialog::setVisible(bool visible)
 {
     Q_D(QDialog);
+    d->setVisible(visible);
+}
+
+void QDialogPrivate::setVisible(bool visible)
+{
+    Q_Q(QDialog);
+    if (!q->testAttribute(Qt::WA_DontShowOnScreen) && canBeNativeDialog() && setNativeDialogVisible(visible))
+        return;
+
+    // We should not block windows by the invisible modal dialog
+    // if a platform-specific dialog is implemented as an in-process
+    // Qt window, because in this case it will also be blocked.
+    const bool dontBlockWindows = q->testAttribute(Qt::WA_DontShowOnScreen)
+            && styleHint(QPlatformDialogHelper::DialogIsQtWindow).toBool();
+    Qt::WindowModality oldModality;
+    bool wasModalitySet;
+
+    if (dontBlockWindows) {
+        oldModality = q->windowModality();
+        wasModalitySet = q->testAttribute(Qt::WA_SetWindowModality);
+        q->setWindowModality(Qt::NonModal);
+    }
+
     if (visible) {
-        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
+        if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden))
             return;
 
-        if (!testAttribute(Qt::WA_Moved)) {
-            Qt::WindowStates state = windowState();
-            adjustPosition(parentWidget());
-            setAttribute(Qt::WA_Moved, false); // not really an explicit position
-            if (state != windowState())
-                setWindowState(state);
-        }
-        QWidget::setVisible(visible);
-        showExtension(d->doShowExtension);
-        QWidget *fw = window()->focusWidget();
-        if (!fw)
-            fw = this;
+        q->QWidget::setVisible(visible);
+
+        // Window activation might be prevented. We can't test isActiveWindow here,
+        // as the window will be activated asynchronously by the window manager.
+        if (!q->testAttribute(Qt::WA_ShowWithoutActivating)) {
+            QWidget *fw = q->window()->focusWidget();
+            if (!fw)
+                fw = q;
 
-        /*
-          The following block is to handle a special case, and does not
-          really follow propper logic in concern of autoDefault and TAB
-          order. However, it's here to ease usage for the users. If a
-          dialog has a default QPushButton, and first widget in the TAB
-          order also is a QPushButton, then we give focus to the main
-          default QPushButton. This simplifies code for the developers,
-          and actually catches most cases... If not, then they simply
-          have to use [widget*]->setFocus() themselves...
-        */
-        if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
-            QWidget *first = fw;
-            while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
-                ;
-            if (first != d->mainDef && qobject_cast<QPushButton*>(first))
-                d->mainDef->setFocus();
-        }
-        if (!d->mainDef && isWindow()) {
-            QWidget *w = fw;
-            while ((w = w->nextInFocusChain()) != fw) {
-                QPushButton *pb = qobject_cast<QPushButton *>(w);
-                if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
-                    pb->setDefault(true);
-                    break;
+            /*
+            The following block is to handle a special case, and does not
+            really follow proper logic in concern of autoDefault and TAB
+            order. However, it's here to ease usage for the users. If a
+            dialog has a default QPushButton, and first widget in the TAB
+            order also is a QPushButton, then we give focus to the main
+            default QPushButton. This simplifies code for the developers,
+            and actually catches most cases... If not, then they simply
+            have to use [widget*]->setFocus() themselves...
+            */
+#if QT_CONFIG(pushbutton)
+            if (mainDef && fw->focusPolicy() == Qt::NoFocus) {
+                QWidget *first = fw;
+                while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
+                    ;
+                if (first != mainDef && qobject_cast<QPushButton*>(first))
+                    mainDef->setFocus();
+            }
+            if (!mainDef && q->isWindow()) {
+                QWidget *w = fw;
+                while ((w = w->nextInFocusChain()) != fw) {
+                    QPushButton *pb = qobject_cast<QPushButton *>(w);
+                    if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
+                        pb->setDefault(true);
+                        break;
+                    }
                 }
             }
-        }
-        if (fw && !fw->hasFocus()) {
-            QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
-            QApplication::sendEvent(fw, &e);
+#endif
+            if (fw && !fw->hasFocus()) {
+                QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
+                QCoreApplication::sendEvent(fw, &e);
+            }
         }
 
-#ifndef QT_NO_ACCESSIBILITY
-        QAccessible::updateAccessibility(this, 0, QAccessible::DialogStart);
+#if QT_CONFIG(accessibility)
+        QAccessibleEvent event(q, QAccessible::DialogStart);
+        QAccessible::updateAccessibility(&event);
 #endif
 
     } else {
-        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+        if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden))
             return;
 
-#ifndef QT_NO_ACCESSIBILITY
-        if (isVisible())
-            QAccessible::updateAccessibility(this, 0, QAccessible::DialogEnd);
+#if QT_CONFIG(accessibility)
+        if (q->isVisible()) {
+            QAccessibleEvent event(q, QAccessible::DialogEnd);
+            QAccessible::updateAccessibility(&event);
+        }
 #endif
 
         // Reimplemented to exit a modal event loop when the dialog is hidden.
-        QWidget::setVisible(visible);
-        if (d->eventLoop)
-            d->eventLoop->exit();
+        q->QWidget::setVisible(visible);
+        if (eventLoop)
+            eventLoop->exit();
     }
-#ifdef Q_WS_WIN
-    if (d->mainDef && isActiveWindow()) {
-        BOOL snapToDefault = false;
-        if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) {
-            if (snapToDefault)
-                QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
-        }
+
+    if (dontBlockWindows) {
+        q->setWindowModality(oldModality);
+        q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
     }
+
+#if QT_CONFIG(pushbutton)
+    const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
+    if (mainDef && q->isActiveWindow()
+        && theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
+        QCursor::setPos(mainDef->mapToGlobal(mainDef->rect().center()));
 #endif
 }
 
@@ -828,31 +861,31 @@
 /*! \internal */
 void QDialog::adjustPosition(QWidget* w)
 {
-#ifdef Q_WS_X11
-    // if the WM advertises that it will place the windows properly for us, let it do it :)
-    if (X11->isSupportedByWM(ATOM(_NET_WM_FULL_PLACEMENT)))
-        return;
-#endif
+    Q_D(QDialog);
 
-#ifdef Q_OS_SYMBIAN
-    if (symbianAdjustedPosition())
-        //dialog has already been positioned
-        return;
-#endif
-
+    if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+        if (theme->themeHint(QPlatformTheme::WindowAutoPlacement).toBool())
+            return;
     QPoint p(0, 0);
-    int extraw = 0, extrah = 0, scrn = 0;
-    if (w)
-        w = w->window();
-    QRect desk;
+    int extraw = 0, extrah = 0;
+    const QWindow *parentWindow = nullptr;
     if (w) {
-        scrn = QApplication::desktop()->screenNumber(w);
-    } else if (QApplication::desktop()->isVirtualDesktop()) {
-        scrn = QApplication::desktop()->screenNumber(QCursor::pos());
+        w = w->window();
     } else {
-        scrn = QApplication::desktop()->screenNumber(this);
+        parentWindow = d->transientParentWindow();
     }
-    desk = QApplication::desktop()->availableGeometry(scrn);
+    QRect desk;
+    QScreen *scrn = nullptr;
+    if (w)
+        scrn = w->screen();
+    else if (parentWindow)
+        scrn = parentWindow->screen();
+    else if (QGuiApplication::primaryScreen()->virtualSiblings().size() > 1)
+        scrn = QGuiApplication::screenAt(QCursor::pos());
+    else
+        scrn = screen();
+    if (scrn)
+        desk = scrn->availableGeometry();
 
     QWidgetList list = QApplication::topLevelWidgets();
     for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
@@ -875,11 +908,19 @@
 
 
     if (w) {
-        // Use mapToGlobal rather than geometry() in case w might
-        // be embedded in another application
-        QPoint pp = w->mapToGlobal(QPoint(0,0));
+        // Use pos() if the widget is embedded into a native window
+        QPoint pp;
+        if (w->windowHandle() && qvariant_cast<WId>(w->windowHandle()->property("_q_embedded_native_parent_handle")))
+            pp = w->pos();
+        else
+            pp = w->mapToGlobal(QPoint(0,0));
         p = QPoint(pp.x() + w->width()/2,
                     pp.y() + w->height()/ 2);
+    } else if (parentWindow) {
+        // QTBUG-63406: Widget-based dialog in QML, which has no Widget parent
+        // but a transient parent window.
+        QPoint pp = parentWindow->mapToGlobal(QPoint(0, 0));
+        p = QPoint(pp.x() + parentWindow->width() / 2, pp.y() + parentWindow->height() / 2);
     } else {
         // p = middle of the desktop
         p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
@@ -900,226 +941,17 @@
     if (p.y() < desk.y())
         p.setY(desk.y());
 
+    // QTBUG-52735: Manually set the correct target screen since scaling in a
+    // subsequent call to QWindow::resize() may otherwise use the wrong factor
+    // if the screen changed notification is still in an event queue.
+    if (scrn) {
+        if (QWindow *window = windowHandle())
+            window->setScreen(scrn);
+    }
+
     move(p);
 }
 
-#if defined(Q_OS_SYMBIAN)
-/*! \internal */
-bool QDialog::symbianAdjustedPosition()
-{
-#if defined(Q_WS_S60)
-    QPoint p;
-    QPoint oldPos = pos();
-    if (isFullScreen()) {
-        p.setX(0);
-        p.setY(0);
-    } else if (isMaximized()) {
-        TRect statusPaneRect = TRect();
-        if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
-            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
-        } else {
-            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, statusPaneRect);
-            // In some native layouts, StaCon is not used. Try to fetch the status pane
-            // height from StatusPane component.
-            if (statusPaneRect.IsEmpty())
-                AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
-        }
-
-        p.setX(0);
-        p.setY(statusPaneRect.Height());
-    } else {
-        // naive way to deduce screen orientation
-        if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
-            int cbaHeight;
-            TRect rect;
-            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, rect);
-            cbaHeight = rect.Height();
-            p.setY(S60->screenHeightInPixels - height() - cbaHeight);
-            p.setX(0);
-        } else {
-            const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
-            TRect staConTopRect = TRect();
-            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
-            if (staConTopRect.IsEmpty()) {
-                TRect cbaRect = TRect();
-                AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect);
-                AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation();
-                switch (cbaLocation) {
-                case AknLayoutUtils::EAknCbaLocationBottom:
-                    p.setY(S60->screenHeightInPixels - height() - cbaRect.Height());
-                    p.setX((S60->screenWidthInPixels - width()) >> 1);
-                    break;
-                case AknLayoutUtils::EAknCbaLocationRight:
-                    p.setY((S60->screenHeightInPixels - height()) >> 1);
-                    p.setX(qMax(0,S60->screenWidthInPixels - width() - scrollbarWidth - cbaRect.Width()));
-                    break;
-                case AknLayoutUtils::EAknCbaLocationLeft:
-                    p.setY((S60->screenHeightInPixels - height()) >> 1);
-                    p.setX(qMax(0,scrollbarWidth + cbaRect.Width()));
-                    break;
-                }
-            } else {
-                p.setY((S60->screenHeightInPixels - height()) >> 1);
-                p.setX(qMax(0,S60->screenWidthInPixels - width()));
-            }
-        }
-    }
-    if (oldPos != p || p.y() < 0)
-        move(p);
-    return true;
-#else
-    // TODO - check positioning requirement for Symbian, non-s60
-    return false;
-#endif
-}
-#endif
-
-/*!
-    \obsolete
-
-    If \a orientation is Qt::Horizontal, the extension will be displayed
-    to the right of the dialog's main area. If \a orientation is
-    Qt::Vertical, the extension will be displayed below the dialog's main
-    area.
-
-    Instead of using this functionality, we recommend that you simply call
-    show() or hide() on the part of the dialog that you want to use as an
-    extension. See the \l{Extension Example} for details.
-
-    \sa setExtension()
-*/
-void QDialog::setOrientation(Qt::Orientation orientation)
-{
-    Q_D(QDialog);
-    d->orientation = orientation;
-}
-
-/*!
-    \obsolete
-
-    Returns the dialog's extension orientation.
-
-    Instead of using this functionality, we recommend that you simply call
-    show() or hide() on the part of the dialog that you want to use as an
-    extension. See the \l{Extension Example} for details.
-
-    \sa extension()
-*/
-Qt::Orientation QDialog::orientation() const
-{
-    Q_D(const QDialog);
-    return d->orientation;
-}
-
-/*!
-    \obsolete
-
-    Sets the widget, \a extension, to be the dialog's extension,
-    deleting any previous extension. The dialog takes ownership of the
-    extension. Note that if 0 is passed any existing extension will be
-    deleted. This function must only be called while the dialog is hidden.
-
-    Instead of using this functionality, we recommend that you simply call
-    show() or hide() on the part of the dialog that you want to use as an
-    extension. See the \l{Extension Example} for details.
-
-    \sa showExtension(), setOrientation()
-*/
-void QDialog::setExtension(QWidget* extension)
-{
-    Q_D(QDialog);
-    delete d->extension;
-    d->extension = extension;
-
-    if (!extension)
-        return;
-
-    if (extension->parentWidget() != this)
-        extension->setParent(this);
-    extension->hide();
-}
-
-/*!
-    \obsolete
-
-    Returns the dialog's extension or 0 if no extension has been
-    defined.
-
-    Instead of using this functionality, we recommend that you simply call
-    show() or hide() on the part of the dialog that you want to use as an
-    extension. See the \l{Extension Example} for details.
-
-    \sa showExtension(), setOrientation()
-*/
-QWidget* QDialog::extension() const
-{
-    Q_D(const QDialog);
-    return d->extension;
-}
-
-
-/*!
-    \obsolete
-
-    If \a showIt is true, the dialog's extension is shown; otherwise the
-    extension is hidden.
-
-    Instead of using this functionality, we recommend that you simply call
-    show() or hide() on the part of the dialog that you want to use as an
-    extension. See the \l{Extension Example} for details.
-
-    \sa show(), setExtension(), setOrientation()
-*/
-void QDialog::showExtension(bool showIt)
-{
-    Q_D(QDialog);
-    d->doShowExtension = showIt;
-    if (!d->extension)
-        return;
-    if (!testAttribute(Qt::WA_WState_Visible))
-        return;
-    if (d->extension->isVisible() == showIt)
-        return;
-
-    if (showIt) {
-        d->size = size();
-        d->min = minimumSize();
-        d->max = maximumSize();
-        if (layout())
-            layout()->setEnabled(false);
-        QSize s(d->extension->sizeHint()
-                 .expandedTo(d->extension->minimumSize())
-                 .boundedTo(d->extension->maximumSize()));
-        if (d->orientation == Qt::Horizontal) {
-            int h = qMax(height(), s.height());
-            d->extension->setGeometry(width(), 0, s.width(), h);
-            setFixedSize(width() + s.width(), h);
-        } else {
-            int w = qMax(width(), s.width());
-            d->extension->setGeometry(0, height(), w, s.height());
-            setFixedSize(w, height() + s.height());
-        }
-        d->extension->show();
-#ifndef QT_NO_SIZEGRIP
-        const bool sizeGripEnabled = isSizeGripEnabled();
-        setSizeGripEnabled(false);
-        d->sizeGripEnabled = sizeGripEnabled;
-#endif
-    } else {
-        d->extension->hide();
-        // workaround for CDE window manager that won't shrink with (-1,-1)
-        setMinimumSize(d->min.expandedTo(QSize(1, 1)));
-        setMaximumSize(d->max);
-        resize(d->size);
-        if (layout())
-            layout()->setEnabled(true);
-#ifndef QT_NO_SIZEGRIP
-        setSizeGripEnabled(d->sizeGripEnabled);
-#endif
-    }
-}
-
-
 /*! \reimp */
 QSize QDialog::sizeHint() const
 {
@@ -1132,17 +964,7 @@
             return QSize(qMax(QWidget::sizeHint().width(), d->extension->sizeHint().width()),
                         QWidget::sizeHint().height());
     }
-#if defined(Q_WS_S60)
-    // if size is not fixed, try to adjust it according to S60 layoutting
-    if (minimumSize() != maximumSize()) {
-        // In S60, dialogs are always the width of screen (in portrait, regardless of current layout)
-        return QSize(qMin(S60->screenHeightInPixels, S60->screenWidthInPixels), QWidget::sizeHint().height());
-    } else {
-        return QWidget::sizeHint();
-    }
-#else
     return QWidget::sizeHint();
-#endif //Q_WS_S60
 }
 
 
@@ -1166,8 +988,8 @@
     \property QDialog::modal
     \brief whether show() should pop up the dialog as modal or modeless
 
-    By default, this property is false and show() pops up the dialog
-    as modeless. Setting his property to true is equivalent to setting
+    By default, this property is \c false and show() pops up the dialog
+    as modeless. Setting this property to true is equivalent to setting
     QWidget::windowModality to Qt::ApplicationModal.
 
     exec() ignores the value of this property and always pops up the
@@ -1184,7 +1006,7 @@
 
 bool QDialog::isSizeGripEnabled() const
 {
-#ifndef QT_NO_SIZEGRIP
+#if QT_CONFIG(sizegrip)
     Q_D(const QDialog);
     return !!d->resizer;
 #else
@@ -1195,11 +1017,11 @@
 
 void QDialog::setSizeGripEnabled(bool enabled)
 {
-#ifdef QT_NO_SIZEGRIP
+#if !QT_CONFIG(sizegrip)
     Q_UNUSED(enabled);
 #else
     Q_D(QDialog);
-#ifndef QT_NO_SIZEGRIP
+#if QT_CONFIG(sizegrip)
     d->sizeGripEnabled = enabled;
     if (enabled && d->doShowExtension)
         return;
@@ -1217,10 +1039,10 @@
             d->resizer->show();
         } else {
             delete d->resizer;
-            d->resizer = 0;
+            d->resizer = nullptr;
         }
     }
-#endif //QT_NO_SIZEGRIP
+#endif // QT_CONFIG(sizegrip)
 }
 
 
@@ -1228,7 +1050,7 @@
 /*! \reimp */
 void QDialog::resizeEvent(QResizeEvent *)
 {
-#ifndef QT_NO_SIZEGRIP
+#if QT_CONFIG(sizegrip)
     Q_D(QDialog);
     if (d->resizer) {
         if (isRightToLeft())
--- a/libgui/languages/build_ts/octave-qt/qdialogbuttonbox.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qdialogbuttonbox.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include <QtCore/qhash.h>
 #include <QtWidgets/qpushbutton.h>
@@ -47,9 +11,10 @@
 #include <private/qguiapplication_p.h>
 #include <QtGui/qpa/qplatformdialoghelper.h>
 #include <QtGui/qpa/qplatformtheme.h>
-#include <QtWidgets/qaction.h>
+#include <QtGui/qaction.h>
 
 #include "qdialogbuttonbox.h"
+#include "qdialogbuttonbox_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -89,7 +54,7 @@
     the buttons (or button texts) yourself and add them to the button box,
     specifying their role.
 
-    \snippet dialogs/extension/finddialog.cpp 1
+    \snippet dialogs/dialogs.cpp buttonbox
 
     Alternatively, QDialogButtonBox provides several standard buttons (e.g. OK, Cancel, Save)
     that you can use. They exist as flags so you can OR them together in the constructor.
@@ -147,39 +112,25 @@
 
     \sa QMessageBox, QPushButton, QDialog
 */
-
-class QDialogButtonBoxPrivate : public QWidgetPrivate
+QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
+    : orientation(orient), buttonLayout(nullptr), center(false)
 {
-    Q_DECLARE_PUBLIC(QDialogButtonBox)
-
-public:
-    QDialogButtonBoxPrivate(Qt::Orientation orient);
-
-    QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
-    QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
-
-    Qt::Orientation orientation;
-    QDialogButtonBox::ButtonLayout layoutPolicy;
-    QBoxLayout *buttonLayout;
-    bool internalRemove;
-    bool center;
+    struct EventFilter : public QObject
+    {
+        EventFilter(QDialogButtonBoxPrivate *d) : d(d) {};
 
-    void createStandardButtons(QDialogButtonBox::StandardButtons buttons);
+        bool eventFilter(QObject *obj, QEvent *event) override
+        {
+            QAbstractButton *button = qobject_cast<QAbstractButton *>(obj);
+            return button ? d->handleButtonShowAndHide(button, event) : false;
+        }
 
-    void layoutButtons();
-    void initLayout();
-    void resetLayout();
-    QPushButton *createButton(QDialogButtonBox::StandardButton button, bool doLayout = true);
-    void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, bool doLayout = true);
-    void _q_handleButtonDestroyed();
-    void _q_handleButtonClicked();
-    void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse);
-    void retranslateStrings();
-};
+    private:
+        QDialogButtonBoxPrivate *d;
 
-QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
-    : orientation(orient), buttonLayout(nullptr), internalRemove(false), center(false)
-{
+    };
+
+    filter.reset(new EventFilter(this));
 }
 
 void QDialogButtonBoxPrivate::initLayout()
@@ -213,7 +164,6 @@
 
 void QDialogButtonBoxPrivate::resetLayout()
 {
-    //delete buttonLayout;
     initLayout();
     layoutButtons();
 }
@@ -221,8 +171,8 @@
 void QDialogButtonBoxPrivate::addButtonsToLayout(const QList<QAbstractButton *> &buttonList,
                                                  bool reverse)
 {
-    int start = reverse ? buttonList.count() - 1 : 0;
-    int end = reverse ? -1 : buttonList.count();
+    int start = reverse ? buttonList.size() - 1 : 0;
+    int end = reverse ? -1 : buttonList.size();
     int step = reverse ? -1 : 1;
 
     for (int i = start; i != end; i += step) {
@@ -237,6 +187,7 @@
     Q_Q(QDialogButtonBox);
     const int MacGap = 36 - 8;    // 8 is the default gap between a widget and a spacer item
 
+    QBoolBlocker blocker(ignoreShowAndHide);
     for (int i = buttonLayout->count() - 1; i >= 0; --i) {
         QLayoutItem *item = buttonLayout->takeAt(i);
         if (QWidget *widget = item->widget())
@@ -347,7 +298,7 @@
 }
 
 QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton,
-                                                   bool doLayout)
+                                                   LayoutRule layoutRule)
 {
     Q_Q(QDialogButtonBox);
     int icon = 0;
@@ -422,7 +373,7 @@
     if (Q_UNLIKELY(role == QPlatformDialogHelper::InvalidRole))
         qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
     else
-        addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role), doLayout);
+        addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role), layoutRule);
 #if QT_CONFIG(shortcut)
     const QKeySequence standardShortcut = QGuiApplicationPrivate::platformTheme()->standardButtonShortcut(sbutton);
     if (!standardShortcut.isEmpty())
@@ -432,23 +383,36 @@
 }
 
 void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
-                                        bool doLayout)
+                                        LayoutRule layoutRule, AddRule addRule)
 {
-    Q_Q(QDialogButtonBox);
-    QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_handleButtonClicked()));
-    QObject::connect(button, SIGNAL(destroyed()), q, SLOT(_q_handleButtonDestroyed()));
     buttonLists[role].append(button);
-    if (doLayout)
+    switch (addRule) {
+    case AddRule::Connect:
+        QObjectPrivate::connect(button, &QAbstractButton::clicked,
+                               this, &QDialogButtonBoxPrivate::handleButtonClicked);
+        QObjectPrivate::connect(button, &QAbstractButton::destroyed,
+                               this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
+        button->installEventFilter(filter.get());
+        break;
+    case AddRule::SkipConnect:
+        break;
+    }
+
+    switch (layoutRule) {
+    case LayoutRule::DoLayout:
         layoutButtons();
+        break;
+    case LayoutRule::SkipLayout:
+        break;
+    }
 }
 
 void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardButtons buttons)
 {
     uint i = QDialogButtonBox::FirstButton;
     while (i <= QDialogButtonBox::LastButton) {
-        if (i & buttons) {
-            createButton(QDialogButtonBox::StandardButton(i), false);
-        }
+        if (i & buttons)
+            createButton(QDialogButtonBox::StandardButton(i), LayoutRule::SkipLayout);
         i = i << 1;
     }
     layoutButtons();
@@ -456,13 +420,10 @@
 
 void QDialogButtonBoxPrivate::retranslateStrings()
 {
-    typedef QHash<QPushButton *, QDialogButtonBox::StandardButton>::iterator Iterator;
-
-    const Iterator end = standardButtonHash.end();
-    for (Iterator it = standardButtonHash.begin(); it != end; ++it) {
-        const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(it.value());
+    for (auto &&[key, value] : std::as_const(standardButtonHash).asKeyValueRange()) {
+        const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(value);
         if (!text.isEmpty())
-            it.key()->setText(text);
+            key->setText(text);
     }
 }
 
@@ -518,12 +479,20 @@
 */
 QDialogButtonBox::~QDialogButtonBox()
 {
+    Q_D(QDialogButtonBox);
+
+    d->ignoreShowAndHide = true;
+
+    // QObjectPrivate::connect requires explicit disconnect in destructor
+    // otherwise the connection may kick in on child destruction and reach
+    // the parent's destroyed private object
+    d->disconnectAll();
 }
 
 /*!
     \enum QDialogButtonBox::ButtonRole
-    \enum QMessageBox::ButtonRole
 
+//! [buttonrole-enum]
     This enum describes the roles that can be used to describe buttons in
     the button box. Combinations of these roles are as flags used to
     describe different aspects of their behavior.
@@ -546,6 +515,7 @@
     \omitvalue NRoles
 
     \sa StandardButton
+//! [buttonrole-enum]
 */
 
 /*!
@@ -671,34 +641,45 @@
     d->standardButtonHash.clear();
     for (int i = 0; i < NRoles; ++i) {
         QList<QAbstractButton *> &list = d->buttonLists[i];
-        while (list.count()) {
+        while (list.size()) {
             QAbstractButton *button = list.takeAt(0);
-            QObject::disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
+            QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
+                                       d, &QDialogButtonBoxPrivate::handleButtonDestroyed);
             delete button;
         }
     }
 }
 
 /*!
-    Returns a list of all the buttons that have been added to the button box.
+    Returns a list of all buttons that have been added to the button box.
 
     \sa buttonRole(), addButton(), removeButton()
 */
 QList<QAbstractButton *> QDialogButtonBox::buttons() const
 {
     Q_D(const QDialogButtonBox);
+    return d->allButtons();
+}
+
+QList<QAbstractButton *> QDialogButtonBoxPrivate::visibleButtons() const
+{
     QList<QAbstractButton *> finalList;
-    for (int i = 0; i < NRoles; ++i) {
-        const QList<QAbstractButton *> &list = d->buttonLists[i];
-        for (int j = 0; j < list.count(); ++j)
+    for (int i = 0; i < QDialogButtonBox::NRoles; ++i) {
+        const QList<QAbstractButton *> &list = buttonLists[i];
+        for (int j = 0; j < list.size(); ++j)
             finalList.append(list.at(j));
     }
     return finalList;
 }
 
+QList<QAbstractButton *> QDialogButtonBoxPrivate::allButtons() const
+{
+    return visibleButtons() << hiddenButtons.keys();
+}
+
 /*!
     Returns the button role for the specified \a button. This function returns
-    \l InvalidRole if \a button is 0 or has not been added to the button box.
+    \l InvalidRole if \a button is \nullptr or has not been added to the button box.
 
     \sa buttons(), addButton()
 */
@@ -707,12 +688,12 @@
     Q_D(const QDialogButtonBox);
     for (int i = 0; i < NRoles; ++i) {
         const QList<QAbstractButton *> &list = d->buttonLists[i];
-        for (int j = 0; j < list.count(); ++j) {
+        for (int j = 0; j < list.size(); ++j) {
             if (list.at(j) == button)
                 return ButtonRole(i);
         }
     }
-    return InvalidRole;
+    return d->hiddenButtons.value(button, InvalidRole);
 }
 
 /*!
@@ -723,27 +704,45 @@
 void QDialogButtonBox::removeButton(QAbstractButton *button)
 {
     Q_D(QDialogButtonBox);
+    d->removeButton(button, QDialogButtonBoxPrivate::RemoveReason::ManualRemove);
+}
 
+/*!
+   \internal
+   Removes \param button.
+   \param reason determines the behavior following the removal:
+   \list
+   \li \c ManualRemove disconnects all signals and removes the button from standardButtonHash.
+   \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonHash.
+   \li \c Destroyed removes the button from standardButtonHash. Signals remain untouched, because
+          the button might already be only a QObject, the destructor of which handles disconnecting.
+   \endlist
+ */
+void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveReason reason)
+{
     if (!button)
         return;
 
-    // Remove it from the standard button hash first and then from the roles
-    d->standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
-    for (int i = 0; i < NRoles; ++i) {
-        QList<QAbstractButton *> &list = d->buttonLists[i];
-        for (int j = 0; j < list.count(); ++j) {
-            if (list.at(j) == button) {
-                list.takeAt(j);
-                if (!d->internalRemove) {
-                    disconnect(button, SIGNAL(clicked()), this, SLOT(_q_handleButtonClicked()));
-                    disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
-                }
-                break;
-            }
-        }
+    // Remove button from hidden buttons and roles
+    hiddenButtons.remove(button);
+    for (int i = 0; i < QDialogButtonBox::NRoles; ++i)
+        buttonLists[i].removeOne(button);
+
+    switch (reason) {
+    case RemoveReason::ManualRemove:
+        button->setParent(nullptr);
+        QObjectPrivate::disconnect(button, &QAbstractButton::clicked,
+                                   this, &QDialogButtonBoxPrivate::handleButtonClicked);
+        QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
+                                   this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
+        button->removeEventFilter(filter.get());
+        Q_FALLTHROUGH();
+    case RemoveReason::Destroyed:
+        standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
+        break;
+    case RemoveReason::HideEvent:
+        break;
     }
-    if (!d->internalRemove)
-        button->setParent(nullptr);
 }
 
 /*!
@@ -813,7 +812,7 @@
 {
     Q_D(QDialogButtonBox);
     // Clear out all the old standard buttons, then recreate them.
-    qDeleteAll(d->standardButtonHash.keys());
+    qDeleteAll(d->standardButtonHash.keyBegin(), d->standardButtonHash.keyEnd());
     d->standardButtonHash.clear();
 
     d->createStandardButtons(buttons);
@@ -855,7 +854,7 @@
     return d->standardButtonHash.value(static_cast<QPushButton *>(button));
 }
 
-void QDialogButtonBoxPrivate::_q_handleButtonClicked()
+void QDialogButtonBoxPrivate::handleButtonClicked()
 {
     Q_Q(QDialogButtonBox);
     if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) {
@@ -889,20 +888,51 @@
     }
 }
 
-void QDialogButtonBoxPrivate::_q_handleButtonDestroyed()
+void QDialogButtonBoxPrivate::handleButtonDestroyed()
+{
+    Q_Q(QDialogButtonBox);
+    if (QObject *object = q->sender())
+        removeButton(reinterpret_cast<QAbstractButton *>(object), RemoveReason::Destroyed);
+}
+
+bool QDialogButtonBoxPrivate::handleButtonShowAndHide(QAbstractButton *button, QEvent *event)
 {
     Q_Q(QDialogButtonBox);
-    if (QObject *object = q->sender()) {
-        QBoolBlocker skippy(internalRemove);
-        q->removeButton(reinterpret_cast<QAbstractButton *>(object));
+
+    const QEvent::Type type = event->type();
+
+    if ((type != QEvent::HideToParent && type != QEvent::ShowToParent) || ignoreShowAndHide)
+        return false;
+
+    switch (type) {
+    case QEvent::HideToParent: {
+        const QDialogButtonBox::ButtonRole role = q->buttonRole(button);
+        if (role != QDialogButtonBox::ButtonRole::InvalidRole) {
+            removeButton(button, RemoveReason::HideEvent);
+            hiddenButtons.insert(button, role);
+            layoutButtons();
+        }
+        break;
     }
+    case QEvent::ShowToParent:
+        if (hiddenButtons.contains(button)) {
+            const auto role = hiddenButtons.take(button);
+            addButton(button, role, LayoutRule::DoLayout, AddRule::SkipConnect);
+            if (role == QDialogButtonBox::AcceptRole)
+                ensureFirstAcceptIsDefault();
+        }
+        break;
+    default: break;
+    }
+
+    return false;
 }
 
 /*!
     \property QDialogButtonBox::centerButtons
     \brief whether the buttons in the button box are centered
 
-    By default, this property is \c false. This behavior is appopriate
+    By default, this property is \c false. This behavior is appropriate
     for most types of dialogs. A notable exception is message boxes
     on most platforms (e.g. Windows), where the button box is
     centered horizontally.
@@ -953,36 +983,78 @@
     }
 }
 
+void QDialogButtonBoxPrivate::ensureFirstAcceptIsDefault()
+{
+    Q_Q(QDialogButtonBox);
+    const QList<QAbstractButton *> &acceptRoleList = buttonLists[QDialogButtonBox::AcceptRole];
+    QPushButton *firstAcceptButton = acceptRoleList.isEmpty()
+                                   ? nullptr
+                                   : qobject_cast<QPushButton *>(acceptRoleList.at(0));
+
+    if (!firstAcceptButton)
+        return;
+
+    bool hasDefault = false;
+    QWidget *dialog = nullptr;
+    QWidget *p = q;
+    while (p && !p->isWindow()) {
+        p = p->parentWidget();
+        if ((dialog = qobject_cast<QDialog *>(p)))
+            break;
+    }
+
+    QWidget *parent = dialog ? dialog : q;
+    Q_ASSERT(parent);
+
+    const auto pushButtons = parent->findChildren<QPushButton *>();
+    for (QPushButton *pushButton : pushButtons) {
+        if (pushButton->isDefault() && pushButton != firstAcceptButton) {
+            hasDefault = true;
+            break;
+        }
+    }
+    if (!hasDefault && firstAcceptButton) {
+        firstAcceptButton->setDefault(true);
+        // When the QDialogButtonBox is focused, and it doesn't have an
+        // explicit focus widget, it will transfer focus to its focus
+        // proxy, which is the first button in the layout. This behavior,
+        // combined with the behavior that QPushButtons in a QDialog will
+        // by default have their autoDefault set to true, results in the
+        // focus proxy/first button stealing the default button status
+        // immediately when the button box is focused, which is not what
+        // we want. Account for this by explicitly making the firstAcceptButton
+        // focused as well, unless an explicit focus widget has been set.
+        if (dialog && !dialog->focusWidget())
+            firstAcceptButton->setFocus();
+    }
+}
+
+void QDialogButtonBoxPrivate::disconnectAll()
+{
+    Q_Q(QDialogButtonBox);
+    const auto buttons = q->findChildren<QAbstractButton *>();
+    for (auto *button : buttons)
+        button->disconnect(q);
+}
+
 /*!
     \reimp
 */
 bool QDialogButtonBox::event(QEvent *event)
 {
     Q_D(QDialogButtonBox);
-    if (event->type() == QEvent::Show) {
-        QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole];
-        QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0));
-        bool hasDefault = false;
-        QWidget *dialog = nullptr;
-        QWidget *p = this;
-        while (p && !p->isWindow()) {
-            p = p->parentWidget();
-            if ((dialog = qobject_cast<QDialog *>(p)))
-                break;
-        }
+    switch (event->type()) {
+    case QEvent::Show:
+        d->ensureFirstAcceptIsDefault();
+        break;
 
-        const auto pbs = (dialog ? dialog : this)->findChildren<QPushButton *>();
-        for (QPushButton *pb : pbs) {
-            if (pb->isDefault() && pb != firstAcceptButton) {
-                hasDefault = true;
-                break;
-            }
-        }
-        if (!hasDefault && firstAcceptButton)
-            firstAcceptButton->setDefault(true);
-    }else if (event->type() == QEvent::LanguageChange) {
+    case QEvent::LanguageChange:
         d->retranslateStrings();
+        break;
+
+    default: break;
     }
+
     return QWidget::event(event);
 }
 
--- a/libgui/languages/build_ts/octave-qt/qerrormessage.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qerrormessage.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,53 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qerrormessage.h"
 
-#ifndef QT_NO_ERRORMESSAGE
-
 #include "qapplication.h"
 #include "qcheckbox.h"
 #include "qlabel.h"
 #include "qlayout.h"
+#if QT_CONFIG(messagebox)
 #include "qmessagebox.h"
+#endif
 #include "qpushbutton.h"
 #include "qstringlist.h"
 #include "qtextedit.h"
@@ -55,94 +17,99 @@
 #include "qpixmap.h"
 #include "qmetaobject.h"
 #include "qthread.h"
-#include "qqueue.h"
 #include "qset.h"
 
+#include <queue>
+
 #include <stdio.h>
 #include <stdlib.h>
 
-#ifdef Q_WS_WINCE
-extern bool qt_wince_is_mobile();    //defined in qguifunctions_wince.cpp
-extern bool qt_wince_is_high_dpi();  //defined in qguifunctions_wince.cpp
-
-#include "qguifunctions_wince.h"
-#endif
+QT_BEGIN_NAMESPACE
 
-#if defined(QT_SOFTKEYS_ENABLED)
-#include <qaction.h>
-#endif
-#ifdef Q_WS_S60
-#include "private/qt_s60_p.h"
-#endif
-
-QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
 
 class QErrorMessagePrivate : public QDialogPrivate
 {
     Q_DECLARE_PUBLIC(QErrorMessage)
 public:
+    struct Message {
+        QString content;
+        QString type;
+    };
+
     QPushButton * ok;
     QCheckBox * again;
     QTextEdit * errors;
     QLabel * icon;
-#ifdef QT_SOFTKEYS_ENABLED
-    QAction *okAction;
-#endif
-    QQueue<QPair<QString, QString> > pending;
+    std::queue<Message> pending;
     QSet<QString> doNotShow;
     QSet<QString> doNotShowType;
     QString currentMessage;
     QString currentType;
 
+    bool isMessageToBeShown(const QString &message, const QString &type) const;
     bool nextPending();
     void retranslateStrings();
+
+    void setVisible(bool) override;
+
+private:
+    void initHelper(QPlatformDialogHelper *) override;
+    void helperPrepareShow(QPlatformDialogHelper *) override;
 };
 
+
+void QErrorMessagePrivate::initHelper(QPlatformDialogHelper *helper)
+{
+    Q_Q(QErrorMessage);
+    auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
+    QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged, q,
+        [this](Qt::CheckState state) {
+            again->setCheckState(state);
+        }
+    );
+    QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked, q,
+        [this](QPlatformDialogHelper::StandardButton, QPlatformDialogHelper::ButtonRole) {
+            Q_Q(QErrorMessage);
+            q->accept();
+        }
+    );
+}
+
+void QErrorMessagePrivate::helperPrepareShow(QPlatformDialogHelper *helper)
+{
+    Q_Q(QErrorMessage);
+    auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(helper);
+    QSharedPointer<QMessageDialogOptions> options = QMessageDialogOptions::create();
+    options->setText(currentMessage);
+    options->setWindowTitle(q->windowTitle());
+    options->setText(QErrorMessage::tr("An error occurred"));
+    options->setInformativeText(currentMessage);
+    options->setStandardIcon(QMessageDialogOptions::Critical);
+    options->setCheckBox(again->text(), again->checkState());
+    messageDialogHelper->setOptions(options);
+}
+
+namespace {
 class QErrorMessageTextView : public QTextEdit
 {
 public:
     QErrorMessageTextView(QWidget *parent)
         : QTextEdit(parent) { setReadOnly(true); }
 
-    virtual QSize minimumSizeHint() const;
-    virtual QSize sizeHint() const;
+    virtual QSize minimumSizeHint() const override;
+    virtual QSize sizeHint() const override;
 };
+} // unnamed namespace
 
 QSize QErrorMessageTextView::minimumSizeHint() const
 {
-#ifdef Q_WS_WINCE
-    if (qt_wince_is_mobile())
-         if (qt_wince_is_high_dpi())
-            return QSize(200, 200);
-         else
-             return QSize(100, 100);
-    else
-      return QSize(70, 70);
-#else
     return QSize(50, 50);
-#endif
 }
 
 QSize QErrorMessageTextView::sizeHint() const
 {
-#ifdef Q_WS_WINCE
-    if (qt_wince_is_mobile())
-         if (qt_wince_is_high_dpi())
-            return QSize(400, 200);
-         else
-             return QSize(320, 120);
-    else
-      return QSize(300, 100);
-#else
-
-#ifdef Q_WS_S60
-    const int smallerDimension = qMin(S60->screenHeightInPixels, S60->screenWidthInPixels);
-    // In S60 layout data, error messages seem to be one third of the screen height (in portrait) minus two.
-    return QSize(smallerDimension, smallerDimension/3-2);
-#else
     return QSize(250, 75);
-#endif //Q_WS_S60
-#endif //Q_WS_WINCE
 }
 
 /*!
@@ -151,6 +118,7 @@
     \brief The QErrorMessage class provides an error message display dialog.
 
     \ingroup standard-dialog
+    \inmodule QtWidgets
 
     An error message widget consists of a text label and a checkbox. The
     checkbox lets the user control whether the same error message will be
@@ -164,7 +132,7 @@
     connecting signals to it.
 
     The static qtHandler() function installs a message handler
-    using qInstallMsgHandler() and creates a QErrorMessage that displays
+    using qInstallMessageHandler() and creates a QErrorMessage that displays
     qDebug(), qWarning() and qFatal() messages. This is most useful in
     environments where no console is available to display warnings and
     error messages.
@@ -178,46 +146,67 @@
     The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
     how to use QErrorMessage as well as other built-in Qt dialogs.
 
-    \img qerrormessage.png
+    \image qerrormessage.png
 
     \sa QMessageBox, QStatusBar::showMessage(), {Standard Dialogs Example}
 */
 
-static QErrorMessage * qtMessageHandler = 0;
+static QErrorMessage * qtMessageHandler = nullptr;
 
 static void deleteStaticcQErrorMessage() // post-routine
 {
     if (qtMessageHandler) {
         delete qtMessageHandler;
-        qtMessageHandler = 0;
+        qtMessageHandler = nullptr;
     }
 }
 
 static bool metFatal = false;
 
-static void jump(QtMsgType t, const char * m)
+static QString msgType2i18nString(QtMsgType t)
 {
+    static_assert(QtDebugMsg == 0);
+    static_assert(QtWarningMsg == 1);
+    static_assert(QtCriticalMsg == 2);
+    static_assert(QtFatalMsg == 3);
+    static_assert(QtInfoMsg == 4);
+
+    // adjust the array below if any of the above fire...
+
+    const char * const messages[] = {
+        QT_TRANSLATE_NOOP("QErrorMessage", "Debug Message:"),
+        QT_TRANSLATE_NOOP("QErrorMessage", "Warning:"),
+        QT_TRANSLATE_NOOP("QErrorMessage", "Critical Error:"),
+        QT_TRANSLATE_NOOP("QErrorMessage", "Fatal Error:"),
+        QT_TRANSLATE_NOOP("QErrorMessage", "Information:"),
+    };
+    Q_ASSERT(size_t(t) < sizeof messages / sizeof *messages);
+
+    return QCoreApplication::translate("QErrorMessage", messages[t]);
+}
+
+static QtMessageHandler originalMessageHandler = nullptr;
+
+static void jump(QtMsgType t, const QMessageLogContext &context, const QString &m)
+{
+    const auto forwardToOriginalHandler = qScopeGuard([&] {
+       if (originalMessageHandler)
+            originalMessageHandler(t, context, m);
+    });
+
     if (!qtMessageHandler)
         return;
 
-    QString rich;
+    auto *defaultCategory = QLoggingCategory::defaultCategory();
+    if (context.category && defaultCategory
+        && qstrcmp(context.category, defaultCategory->categoryName()) != 0)
+        return;
 
-    switch (t) {
-    case QtDebugMsg:
-    default:
-        rich = QErrorMessage::tr("Debug Message:");
-        break;
-    case QtWarningMsg:
-        rich = QErrorMessage::tr("Warning:");
-        break;
-    case QtFatalMsg:
-        rich = QErrorMessage::tr("Fatal Error:");
-    }
-    rich = QString::fromLatin1("<p><b>%1</b></p>").arg(rich);
-    rich += Qt::convertFromPlainText(QLatin1String(m), Qt::WhiteSpaceNormal);
+    QString rich = "<p><b>"_L1 + msgType2i18nString(t) + "</b></p>"_L1
+                   + Qt::convertFromPlainText(m, Qt::WhiteSpaceNormal);
 
     // ### work around text engine quirk
-    if (rich.endsWith(QLatin1String("</p>")))
+    if (rich.endsWith("</p>"_L1))
         rich.chop(4);
 
     if (!metFatal) {
@@ -237,49 +226,43 @@
 /*!
     Constructs and installs an error handler window with the given \a
     parent.
+
+    The default \l{Qt::WindowModality} {window modality} of the dialog
+    depends on the platform. The window modality can be overridden via
+    setWindowModality() before calling showMessage().
 */
 
 QErrorMessage::QErrorMessage(QWidget * parent)
     : QDialog(*new QErrorMessagePrivate, parent)
 {
     Q_D(QErrorMessage);
-    QGridLayout * grid = new QGridLayout(this);
+
+#if defined(Q_OS_MACOS)
+    setWindowModality(parent ? Qt::WindowModal : Qt::ApplicationModal);
+#endif
+
     d->icon = new QLabel(this);
-#ifndef QT_NO_MESSAGEBOX
-    d->icon->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+    d->errors = new QErrorMessageTextView(this);
+    d->again = new QCheckBox(this);
+    d->ok = new QPushButton(this);
+    QGridLayout * grid = new QGridLayout(this);
+
+    connect(d->ok, SIGNAL(clicked()), this, SLOT(accept()));
+
+    grid->addWidget(d->icon,   0, 0, Qt::AlignTop);
+    grid->addWidget(d->errors, 0, 1);
+    grid->addWidget(d->again,  1, 1, Qt::AlignTop);
+    grid->addWidget(d->ok,     2, 0, 1, 2, Qt::AlignCenter);
+    grid->setColumnStretch(1, 42);
+    grid->setRowStretch(0, 42);
+
+#if QT_CONFIG(messagebox)
+    d->icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxInformation));
     d->icon->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
 #endif
-#ifdef Q_WS_S60
-    //In Symbian, messagebox icons are in LtR UIs on right. Thus, layout needs to switch icon and text columns.
-    const int preferredIconColumn = (QApplication::layoutDirection() == Qt::LeftToRight) ? 1 : 0;
-    const int preferredTextColumn = (QApplication::layoutDirection() == Qt::LeftToRight) ? 0 : 1;
-#else
-    const int preferredIconColumn = 0;
-    const int preferredTextColumn = 1;
-#endif
-    grid->addWidget(d->icon, 0, preferredIconColumn, Qt::AlignTop);
-    d->errors = new QErrorMessageTextView(this);
-    grid->addWidget(d->errors, 0, preferredTextColumn);
-    d->again = new QCheckBox(this);
     d->again->setChecked(true);
-    grid->addWidget(d->again, 1, preferredTextColumn, Qt::AlignTop);
-    d->ok = new QPushButton(this);
-#ifdef QT_SOFTKEYS_ENABLED
-    d->okAction = new QAction(d->ok);
-    d->okAction->setSoftKeyRole(QAction::PositiveSoftKey);
-    connect(d->okAction, SIGNAL(triggered()), this, SLOT(accept()));
-    addAction(d->okAction);
-#endif
+    d->ok->setFocus();
 
-
-#if defined(Q_WS_WINCE) || defined(Q_WS_S60)
-    d->ok->setFixedSize(0,0);
-#endif
-    connect(d->ok, SIGNAL(clicked()), this, SLOT(accept()));
-    d->ok->setFocus();
-    grid->addWidget(d->ok, 2, 0, 1, 2, Qt::AlignCenter);
-    grid->setColumnStretch(preferredTextColumn, 42);
-    grid->setRowStretch(0, 42);
     d->retranslateStrings();
 }
 
@@ -291,11 +274,13 @@
 QErrorMessage::~QErrorMessage()
 {
     if (this == qtMessageHandler) {
-        qtMessageHandler = 0;
-        QtMsgHandler tmp = qInstallMsgHandler(0);
-        // in case someone else has later stuck in another...
-        if (tmp != jump)
-            qInstallMsgHandler(tmp);
+        qtMessageHandler = nullptr;
+        QtMessageHandler currentMessagHandler = qInstallMessageHandler(nullptr);
+        if (currentMessagHandler != jump)
+            qInstallMessageHandler(currentMessagHandler);
+        else
+            qInstallMessageHandler(originalMessageHandler);
+        originalMessageHandler = nullptr;
     }
 }
 
@@ -305,16 +290,22 @@
 void QErrorMessage::done(int a)
 {
     Q_D(QErrorMessage);
-    if (!d->again->isChecked() && !d->currentMessage.isEmpty() && d->currentType.isEmpty()) {
-        d->doNotShow.insert(d->currentMessage);
-    }
-    if (!d->again->isChecked() && !d->currentType.isEmpty()) {
-        d->doNotShowType.insert(d->currentType);
+    if (!d->again->isChecked()) {
+        if (d->currentType.isEmpty()) {
+            if (!d->currentMessage.isEmpty())
+                d->doNotShow.insert(d->currentMessage);
+        } else {
+            d->doNotShowType.insert(d->currentType);
+        }
     }
     d->currentMessage.clear();
     d->currentType.clear();
-    if (!d->nextPending()) {
-        QDialog::done(a);
+
+    QDialog::done(a);
+
+    if (d->nextPending()) {
+        show();
+    } else {
         if (this == qtMessageHandler && metFatal)
             exit(1);
     }
@@ -325,15 +316,21 @@
     Returns a pointer to a QErrorMessage object that outputs the
     default Qt messages. This function creates such an object, if there
     isn't one already.
+
+    The object will only output log messages of QLoggingCategory::defaultCategory().
+
+    The object will forward all messages to the original message handler.
+
+    \sa qInstallMessageHandler
 */
 
 QErrorMessage * QErrorMessage::qtHandler()
 {
     if (!qtMessageHandler) {
-        qtMessageHandler = new QErrorMessage(0);
+        qtMessageHandler = new QErrorMessage(nullptr);
         qAddPostRoutine(deleteStaticcQErrorMessage); // clean up
-        qtMessageHandler->setWindowTitle(QApplication::applicationName());
-        qInstallMsgHandler(jump);
+        qtMessageHandler->setWindowTitle(QCoreApplication::applicationName());
+        originalMessageHandler = qInstallMessageHandler(jump);
     }
     return qtMessageHandler;
 }
@@ -341,20 +338,27 @@
 
 /*! \internal */
 
+bool QErrorMessagePrivate::isMessageToBeShown(const QString &message, const QString &type) const
+{
+    return !message.isEmpty()
+        && (type.isEmpty() ? !doNotShow.contains(message) : !doNotShowType.contains(type));
+}
+
 bool QErrorMessagePrivate::nextPending()
 {
-    while (!pending.isEmpty()) {
-        QPair<QString,QString> pendingMessage = pending.dequeue();
-        QString message = pendingMessage.first;
-        QString type = pendingMessage.second;
-        if (!message.isEmpty() && ((type.isEmpty() && !doNotShow.contains(message)) || (!type.isEmpty() && !doNotShowType.contains(type)))) {
+    while (!pending.empty()) {
+        QString message = std::move(pending.front().content);
+        QString type = std::move(pending.front().type);
+        pending.pop();
+        if (isMessageToBeShown(message, type)) {
 #ifndef QT_NO_TEXTHTMLPARSER
             errors->setHtml(message);
 #else
             errors->setPlainText(message);
 #endif
-            currentMessage = message;
-            currentType = type;
+            currentMessage = std::move(message);
+            currentType = std::move(type);
+            again->setChecked(true);
             return true;
         }
     }
@@ -373,12 +377,7 @@
 
 void QErrorMessage::showMessage(const QString &message)
 {
-    Q_D(QErrorMessage);
-    if (d->doNotShow.contains(message))
-        return;
-    d->pending.enqueue(qMakePair(message,QString()));
-    if (!isVisible() && d->nextPending())
-        show();
+    showMessage(message, QString());
 }
 
 /*!
@@ -398,13 +397,30 @@
 void QErrorMessage::showMessage(const QString &message, const QString &type)
 {
     Q_D(QErrorMessage);
-    if (d->doNotShow.contains(message) && d->doNotShowType.contains(type))
+    if (!d->isMessageToBeShown(message, type))
         return;
-     d->pending.push_back(qMakePair(message,type));
+    d->pending.push({message, type});
     if (!isVisible() && d->nextPending())
         show();
 }
 
+void QErrorMessagePrivate::setVisible(bool visible)
+{
+    Q_Q(QErrorMessage);
+    if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
+        return;
+
+    if (canBeNativeDialog())
+        setNativeDialogVisible(visible);
+
+    // Update WA_DontShowOnScreen based on whether the native dialog was shown,
+    // so that QDialog::setVisible(visible) below updates the QWidget state correctly,
+    // but skips showing the non-native version.
+    q->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
+
+    QDialogPrivate::setVisible(visible);
+}
+
 /*!
     \reimp
 */
@@ -421,17 +437,8 @@
 {
     again->setText(QErrorMessage::tr("&Show this message again"));
     ok->setText(QErrorMessage::tr("&OK"));
-#ifdef QT_SOFTKEYS_ENABLED
-    okAction->setText(ok->text());
-#endif
 }
 
-/*!
-    \fn void QErrorMessage::message(const QString & message)
-
-    Use showMessage(\a message) instead.
-*/
-
 QT_END_NAMESPACE
 
-#endif // QT_NO_ERRORMESSAGE
+#include "moc_qerrormessage.cpp"
--- a/libgui/languages/build_ts/octave-qt/qfiledialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qfiledialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,112 +1,73 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_NO_URL_CAST_FROM_STRING
 
 #include <qvariant.h>
 #include <private/qwidgetitemdata_p.h>
 #include "qfiledialog.h"
 
-#ifndef QT_NO_FILEDIALOG
 #include "qfiledialog_p.h"
+#include <private/qapplication_p.h>
+#include <private/qguiapplication_p.h>
 #include <qfontmetrics.h>
 #include <qaction.h>
+#include <qactiongroup.h>
 #include <qheaderview.h>
-#include <qshortcut.h>
+#if QT_CONFIG(shortcut)
+#  include <qshortcut.h>
+#endif
 #include <qgridlayout.h>
+#if QT_CONFIG(menu)
 #include <qmenu.h>
+#endif
+#if QT_CONFIG(messagebox)
 #include <qmessagebox.h>
-#include <qinputdialog.h>
+#endif
 #include <stdlib.h>
+#if QT_CONFIG(settings)
 #include <qsettings.h>
+#endif
 #include <qdebug.h>
+#if QT_CONFIG(mimetype)
+#include <qmimedatabase.h>
+#endif
+#if QT_CONFIG(regularexpression)
+#include <qregularexpression.h>
+#endif
 #include <qapplication.h>
 #include <qstylepainter.h>
-#include <private/qfileiconprovider_p.h>
-#if !defined(Q_WS_WINCE) && !defined(Q_OS_SYMBIAN)
 #include "ui_qfiledialog.h"
-#else
-#define Q_EMBEDDED_SMALLSCREEN
-#include "ui_qfiledialog_embedded.h"
-#if defined(Q_OS_WINCE)
-extern bool qt_priv_ptr_valid;
-#endif
 #if defined(Q_OS_UNIX)
 #include <pwd.h>
+#include <unistd.h> // for pathconf() on OS X
+#elif defined(Q_OS_WIN)
+#  include <QtCore/qt_windows.h>
 #endif
+#if defined(Q_OS_WASM)
+#include <private/qwasmlocalfileaccess_p.h>
 #endif
 
+#include <algorithm>
+
 QT_BEGIN_NAMESPACE
 
-Q_GLOBAL_STATIC(QString, lastVisitedDir)
-
-/*
-    \internal
-
-    Exported hooks that can be used to customize the static functions.
- */
-typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options);
-Q_GUI_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook = 0;
-
-typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
-Q_GUI_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook = 0;
-
-typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
-Q_GUI_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook = 0;
-
-typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
-Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook = 0;
+using namespace Qt::StringLiterals;
+
+Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
 
 /*!
   \class QFileDialog
   \brief The QFileDialog class provides a dialog that allow users to select files or directories.
   \ingroup standard-dialogs
-
+  \inmodule QtWidgets
 
   The QFileDialog class enables a user to traverse the file system in
   order to select one or many files or a directory.
 
-  The easiest way to create a QFileDialog is to use the static
-  functions. On Windows, Mac OS X, KDE and GNOME, these static functions will
-  call the native file dialog when possible.
-
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 0
+  The easiest way to create a QFileDialog is to use the static functions.
+
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 0
 
   In the above example, a modal QFileDialog is created using a static
   function. The dialog initially displays the contents of the "/home/jana"
@@ -117,13 +78,13 @@
   If you want to use multiple filters, separate each one with
   \e two semicolons. For example:
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 1
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 1
 
   You can create your own QFileDialog without using the static
   functions. By calling setFileMode(), you can specify what the user must
   select in the dialog:
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 2
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 2
 
   In the above example, the mode of the file dialog is set to
   AnyFile, meaning that the user can select any file, or even specify a
@@ -136,7 +97,7 @@
   this indicates what types of objects the user is expected to select.
   Use setNameFilter() to set the dialog's file filter. For example:
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 3
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 3
 
   In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"},
   this means that only files with the extension \c png, \c xpm,
@@ -152,12 +113,12 @@
   information alongside each name, such as the file size and modification
   date. Set the mode with setViewMode():
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 4
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 4
 
   The last important function you will need to use when creating your
   own file dialog is selectedFiles().
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 5
+  \snippet code/src_gui_dialogs_qfiledialog.cpp 5
 
   In the above example, a modal file dialog is created and shown. If
   the user clicked OK, the file they selected is put in \c fileName.
@@ -169,8 +130,15 @@
   The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
   how to use QFileDialog as well as other built-in Qt dialogs.
 
-  \sa QDir, QFileInfo, QFile, QPrintDialog, QColorDialog, QFontDialog, {Standard Dialogs Example},
-      {Application Example}
+  By default, a platform-native file dialog will be used if the platform has
+  one. In that case, the widgets which would otherwise be used to construct the
+  dialog will not be instantiated, so related accessors such as layout() and
+  itemDelegate() will return null. Also, not all platforms show file dialogs
+  with a title bar, so be aware that the caption text might not be visible to
+  the user. You can set the \l DontUseNativeDialog option to ensure that the
+  widget-based implementation will be used instead of the native dialog.
+
+  \sa QDir, QFileInfo, QFile, QColorDialog, QFontDialog, {Standard Dialogs Example}
 */
 
 /*!
@@ -203,13 +171,11 @@
     \value AnyFile        The name of a file, whether it exists or not.
     \value ExistingFile   The name of a single existing file.
     \value Directory      The name of a directory. Both files and
-                          directories are displayed.
+                          directories are displayed. However, the native Windows
+                          file dialog does not support displaying files in the
+                          directory chooser.
     \value ExistingFiles  The names of zero or more existing files.
 
-    This value is obsolete since Qt 4.5:
-
-    \value DirectoryOnly  Use \c Directory and setOption(ShowDirsOnly, true) instead.
-
     \sa setFileMode()
 */
 
@@ -226,25 +192,27 @@
     \value DontConfirmOverwrite Don't ask for confirmation if an
     existing file is selected.  By default confirmation is requested.
 
+    Note: This option is not supported on macOS when using the
+    native file dialog.
+
     \value DontUseNativeDialog Don't use the native file dialog. By
     default, the native file dialog is used unless you use a subclass
-    of QFileDialog that contains the Q_OBJECT macro.
+    of QFileDialog that contains the Q_OBJECT macro, or the platform
+    does not have a native dialog of the type that you require.
+
+    \b{Note:} This option must be set before changing dialog properties
+    or showing the dialog.
 
     \value ReadOnly Indicates that the model is readonly.
 
     \value HideNameFilterDetails Indicates if the file name filter details are
     hidden or not.
 
-    \value DontUseSheet In previous versions of Qt, the static
-    functions would create a sheet by default if the static function
-    was given a parent. This is no longer supported and does nothing in Qt 4.5, The
-    static functions will always be an application modal dialog. If
-    you want to use sheets, use QFileDialog::open() instead.
-
     \value DontUseCustomDirectoryIcons Always use the default directory icon.
     Some platforms allow the user to set a different icon. Custom icon lookup
-    cause a big performance impact over network or removable drives. Setting this
-    will affect the behavior of the icon provider. This enum value was added in Qt 4.8.6.
+    cause a big performance impact over network or removable drives.
+    Setting this will enable the QFileIconProvider::DontUseCustomDirectoryIcons
+    option in the icon provider. This enum value was added in Qt 5.2.
 */
 
 /*!
@@ -260,37 +228,76 @@
 /*!
     \fn void QFileDialog::filesSelected(const QStringList &selected)
 
-    When the selection changes and the dialog is accepted, this signal is
-    emitted with the (possibly empty) list of \a selected files.
+    When the selection changes for local operations and the dialog is
+    accepted, this signal is emitted with the (possibly empty) list
+    of \a selected files.
 
     \sa currentChanged(), QDialog::Accepted
 */
 
+/*!
+    \fn void QFileDialog::urlsSelected(const QList<QUrl> &urls)
+
+    When the selection changes and the dialog is accepted, this signal is
+    emitted with the (possibly empty) list of selected \a urls.
+
+    \sa currentUrlChanged(), QDialog::Accepted
+    \since 5.2
+*/
 
 /*!
     \fn void QFileDialog::fileSelected(const QString &file)
 
-    When the selection changes and the dialog is accepted, this signal is
-    emitted with the (possibly empty) selected \a file.
+    When the selection changes for local operations and the dialog is
+    accepted, this signal is emitted with the (possibly empty)
+    selected \a file.
 
     \sa currentChanged(), QDialog::Accepted
 */
 
+/*!
+    \fn void QFileDialog::urlSelected(const QUrl &url)
+
+    When the selection changes and the dialog is accepted, this signal is
+    emitted with the (possibly empty) selected \a url.
+
+    \sa currentUrlChanged(), QDialog::Accepted
+    \since 5.2
+*/
 
 /*!
     \fn void QFileDialog::currentChanged(const QString &path)
 
-    When the current file changes, this signal is emitted with the
-    new file name as the \a path parameter.
+    When the current file changes for local operations, this signal is
+    emitted with the new file name as the \a path parameter.
 
     \sa filesSelected()
 */
 
 /*!
+    \fn void QFileDialog::currentUrlChanged(const QUrl &url)
+
+    When the current file changes, this signal is emitted with the
+    new file URL as the \a url parameter.
+
+    \sa urlsSelected()
+    \since 5.2
+*/
+
+/*!
   \fn void QFileDialog::directoryEntered(const QString &directory)
   \since 4.3
 
+  This signal is emitted for local operations when the user enters
+  a \a directory.
+*/
+
+/*!
+  \fn void QFileDialog::directoryUrlEntered(const QUrl &directory)
+
   This signal is emitted when the user enters a \a directory.
+
+  \since 5.2
 */
 
 /*!
@@ -300,17 +307,10 @@
   This signal is emitted when the user selects a \a filter.
 */
 
-#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
-bool Q_GUI_EXPORT qt_use_native_dialogs = true; // for the benefit of testing tools, until we have a proper API
-#endif
-
 QT_BEGIN_INCLUDE_NAMESPACE
-#ifdef Q_WS_WIN
-#include <qwindowsstyle.h>
-#endif
-#include <qshortcut.h>
-#ifdef Q_WS_MAC
-#include <qmacstyle_mac.h>
+#include <QMetaEnum>
+#if QT_CONFIG(shortcut)
+#  include <qshortcut.h>
 #endif
 QT_END_INCLUDE_NAMESPACE
 
@@ -323,8 +323,8 @@
     : QDialog(*new QFileDialogPrivate, parent, f)
 {
     Q_D(QFileDialog);
-    d->init();
-    d->lineEdit()->selectAll();
+    QFileDialogArgs args;
+    d->init(args);
 }
 
 /*!
@@ -338,25 +338,26 @@
                      const QString &caption,
                      const QString &directory,
                      const QString &filter)
-    : QDialog(*new QFileDialogPrivate, parent, 0)
+    : QDialog(*new QFileDialogPrivate, parent, { })
 {
     Q_D(QFileDialog);
-    d->init(directory, filter, caption);
-    d->lineEdit()->selectAll();
+    QFileDialogArgs args(QUrl::fromLocalFile(directory));
+    args.filter = filter;
+    args.caption = caption;
+    d->init(args);
 }
 
 /*!
     \internal
 */
 QFileDialog::QFileDialog(const QFileDialogArgs &args)
-    : QDialog(*new QFileDialogPrivate, args.parent, 0)
+    : QDialog(*new QFileDialogPrivate, args.parent, { })
 {
     Q_D(QFileDialog);
-    d->init(args.directory, args.filter, args.caption);
+    d->init(args);
     setFileMode(args.mode);
     setOptions(args.options);
     selectFile(args.selection);
-    d->lineEdit()->selectAll();
 }
 
 /*!
@@ -364,13 +365,10 @@
 */
 QFileDialog::~QFileDialog()
 {
+#if QT_CONFIG(settings)
     Q_D(QFileDialog);
-#ifndef QT_NO_SETTINGS
-    QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
-    settings.beginGroup(QLatin1String("Qt"));
-    settings.setValue(QLatin1String("filedialog"), saveState());
+    d->saveSettings();
 #endif
-    d->deleteNativeDialog_sys();
 }
 
 /*!
@@ -379,7 +377,7 @@
 
     For instance:
 
-    \snippet doc/src/snippets/filedialogurls.cpp 0
+    \snippet filedialogurls/filedialogurls.cpp 0
 
     The file dialog will then look like this:
 
@@ -390,7 +388,8 @@
 void QFileDialog::setSidebarUrls(const QList<QUrl> &urls)
 {
     Q_D(QFileDialog);
-    d->qFileDialogUi->sidebar->setUrls(urls);
+    if (!d->nativeDialogInUse)
+        d->qFileDialogUi->sidebar->setUrls(urls);
 }
 
 /*!
@@ -400,14 +399,11 @@
 QList<QUrl> QFileDialog::sidebarUrls() const
 {
     Q_D(const QFileDialog);
-    return d->qFileDialogUi->sidebar->urls();
+    return (d->nativeDialogInUse ? QList<QUrl>() : d->qFileDialogUi->sidebar->urls());
 }
 
 static const qint32 QFileDialogMagic = 0xbe;
 
-const char *qt_file_dialog_filter_reg_exp =
-"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
-
 /*!
     \since 4.3
     Saves the state of the dialog's layout, history and current directory.
@@ -418,17 +414,26 @@
 QByteArray QFileDialog::saveState() const
 {
     Q_D(const QFileDialog);
-    int version = 3;
+    int version = 4;
     QByteArray data;
     QDataStream stream(&data, QIODevice::WriteOnly);
+    stream.setVersion(QDataStream::Qt_5_0);
 
     stream << qint32(QFileDialogMagic);
     stream << qint32(version);
-    stream << d->qFileDialogUi->splitter->saveState();
-    stream << d->qFileDialogUi->sidebar->urls();
+    if (d->usingWidgets()) {
+        stream << d->qFileDialogUi->splitter->saveState();
+        stream << d->qFileDialogUi->sidebar->urls();
+    } else {
+        stream << d->splitterState;
+        stream << d->sidebarUrls;
+    }
     stream << history();
     stream << *lastVisitedDir();
-    stream << d->qFileDialogUi->treeView->header()->saveState();
+    if (d->usingWidgets())
+        stream << d->qFileDialogUi->treeView->header()->saveState();
+    else
+        stream << d->headerData;
     stream << qint32(viewMode());
     return data;
 }
@@ -440,66 +445,47 @@
     Typically this is used in conjunction with QSettings to restore the size
     from a past session.
 
-    Returns false if there are errors
+    Returns \c false if there are errors
 */
 bool QFileDialog::restoreState(const QByteArray &state)
 {
     Q_D(QFileDialog);
-    int version = 3;
     QByteArray sd = state;
     QDataStream stream(&sd, QIODevice::ReadOnly);
+    stream.setVersion(QDataStream::Qt_5_0);
     if (stream.atEnd())
         return false;
-    QByteArray splitterState;
-    QByteArray headerData;
-    QList<QUrl> bookmarks;
     QStringList history;
-    QString currentDirectory;
+    QUrl currentDirectory;
     qint32 marker;
     qint32 v;
     qint32 viewMode;
     stream >> marker;
     stream >> v;
-    if (marker != QFileDialogMagic || v != version)
+    // the code below only supports versions 3 and 4
+    if (marker != QFileDialogMagic || (v != 3 && v != 4))
         return false;
 
-    stream >> splitterState
-           >> bookmarks
-           >> history
-           >> currentDirectory
-           >> headerData
-           >> viewMode;
-
-    if (!d->qFileDialogUi->splitter->restoreState(splitterState))
-        return false;
-    QList<int> list = d->qFileDialogUi->splitter->sizes();
-    if (list.count() >= 2 && list.at(0) == 0 && list.at(1) == 0) {
-        for (int i = 0; i < list.count(); ++i)
-            list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width();
-        d->qFileDialogUi->splitter->setSizes(list);
+    stream >> d->splitterState
+           >> d->sidebarUrls
+           >> history;
+    if (v == 3) {
+        QString currentDirectoryString;
+        stream >> currentDirectoryString;
+        currentDirectory = QUrl::fromLocalFile(currentDirectoryString);
+    } else {
+        stream >> currentDirectory;
     }
-
-    d->qFileDialogUi->sidebar->setUrls(bookmarks);
-    while (history.count() > 5)
-        history.pop_front();
-    setHistory(history);
-    setDirectory(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
-    QHeaderView *headerView = d->qFileDialogUi->treeView->header();
-    if (!headerView->restoreState(headerData))
-        return false;
-
-    QList<QAction*> actions = headerView->actions();
-    QAbstractItemModel *abstractModel = d->model;
-#ifndef QT_NO_PROXYMODEL
-    if (d->proxyModel)
-        abstractModel = d->proxyModel;
-#endif
-    int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1);
-    for (int i = 1; i < total; ++i)
-        actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
-
-    setViewMode(ViewMode(viewMode));
-    return true;
+    stream >> d->headerData
+           >> viewMode;
+
+    setDirectoryUrl(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
+    setViewMode(static_cast<QFileDialog::ViewMode>(viewMode));
+
+    if (!d->usingWidgets())
+        return true;
+
+    return d->restoreWidgetState(history, -1);
 }
 
 /*!
@@ -517,29 +503,17 @@
 
 QFileDialogPrivate::QFileDialogPrivate()
     :
-#ifndef QT_NO_PROXYMODEL
-        proxyModel(0),
+#if QT_CONFIG(proxymodel)
+        proxyModel(nullptr),
 #endif
-        model(0),
-        fileMode(QFileDialog::AnyFile),
-        acceptMode(QFileDialog::AcceptOpen),
+        model(nullptr),
         currentHistoryLocation(-1),
-        renameAction(0),
-        deleteAction(0),
-        showHiddenAction(0),
+        renameAction(nullptr),
+        deleteAction(nullptr),
+        showHiddenAction(nullptr),
         useDefaultCaption(true),
-        defaultFileTypes(true),
-        fileNameLabelExplicitlySat(false),
-        nativeDialogInUse(false),
-#ifdef Q_WS_MAC
-        mDelegate(0),
-#ifndef QT_MAC_USE_COCOA
-        mDialog(0),
-        mDialogStarted(false),
-        mDialogClosed(true),
-#endif
-#endif
-        qFileDialogUi(0)
+        qFileDialogUi(nullptr),
+        options(QFileDialogOptions::create())
 {
 }
 
@@ -547,13 +521,48 @@
 {
 }
 
+void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h)
+{
+    QFileDialog *d = q_func();
+    QObject::connect(h, SIGNAL(fileSelected(QUrl)), d, SLOT(_q_emitUrlSelected(QUrl)));
+    QObject::connect(h, SIGNAL(filesSelected(QList<QUrl>)), d, SLOT(_q_emitUrlsSelected(QList<QUrl>)));
+    QObject::connect(h, SIGNAL(currentChanged(QUrl)), d, SLOT(_q_nativeCurrentChanged(QUrl)));
+    QObject::connect(h, SIGNAL(directoryEntered(QUrl)), d, SLOT(_q_nativeEnterDirectory(QUrl)));
+    QObject::connect(h, SIGNAL(filterSelected(QString)), d, SIGNAL(filterSelected(QString)));
+    static_cast<QPlatformFileDialogHelper *>(h)->setOptions(options);
+}
+
+void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
+{
+    Q_Q(QFileDialog);
+    options->setWindowTitle(q->windowTitle());
+    options->setHistory(q->history());
+    if (usingWidgets())
+        options->setSidebarUrls(qFileDialogUi->sidebar->urls());
+    if (options->initiallySelectedNameFilter().isEmpty())
+        options->setInitiallySelectedNameFilter(q->selectedNameFilter());
+    if (options->initiallySelectedFiles().isEmpty())
+        options->setInitiallySelectedFiles(userSelectedFiles());
+}
+
+void QFileDialogPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
+{
+    if (code == QDialog::Accepted) {
+        Q_Q(QFileDialog);
+        q->setViewMode(static_cast<QFileDialog::ViewMode>(options->viewMode()));
+        q->setSidebarUrls(options->sidebarUrls());
+        q->setHistory(options->history());
+    }
+}
+
 void QFileDialogPrivate::retranslateWindowTitle()
 {
     Q_Q(QFileDialog);
     if (!useDefaultCaption || setWindowTitle != q->windowTitle())
         return;
-    if (acceptMode == QFileDialog::AcceptOpen) {
-        if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory)
+    if (q->acceptMode() == QFileDialog::AcceptOpen) {
+        const QFileDialog::FileMode fileMode = q->fileMode();
+        if (fileMode == QFileDialog::Directory)
             q->setWindowTitle(QFileDialog::tr("Find Directory"));
         else
             q->setWindowTitle(QFileDialog::tr("Open"));
@@ -563,25 +572,85 @@
     setWindowTitle = q->windowTitle();
 }
 
-void QFileDialogPrivate::setLastVisitedDirectory(const QString &dir)
+void QFileDialogPrivate::setLastVisitedDirectory(const QUrl &dir)
 {
     *lastVisitedDir() = dir;
 }
 
+void QFileDialogPrivate::updateLookInLabel()
+{
+    if (options->isLabelExplicitlySet(QFileDialogOptions::LookIn))
+        setLabelTextControl(QFileDialog::LookIn, options->labelText(QFileDialogOptions::LookIn));
+}
+
+void QFileDialogPrivate::updateFileNameLabel()
+{
+    if (options->isLabelExplicitlySet(QFileDialogOptions::FileName)) {
+        setLabelTextControl(QFileDialog::FileName, options->labelText(QFileDialogOptions::FileName));
+    } else {
+        switch (q_func()->fileMode()) {
+        case QFileDialog::Directory:
+            setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("Directory:"));
+            break;
+        default:
+            setLabelTextControl(QFileDialog::FileName, QFileDialog::tr("File &name:"));
+            break;
+        }
+    }
+}
+
+void QFileDialogPrivate::updateFileTypeLabel()
+{
+    if (options->isLabelExplicitlySet(QFileDialogOptions::FileType))
+        setLabelTextControl(QFileDialog::FileType, options->labelText(QFileDialogOptions::FileType));
+}
+
+void QFileDialogPrivate::updateOkButtonText(bool saveAsOnFolder)
+{
+    Q_Q(QFileDialog);
+    // 'Save as' at a folder: Temporarily change to "Open".
+    if (saveAsOnFolder) {
+        setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Open"));
+    } else if (options->isLabelExplicitlySet(QFileDialogOptions::Accept)) {
+        setLabelTextControl(QFileDialog::Accept, options->labelText(QFileDialogOptions::Accept));
+        return;
+    } else {
+        switch (q->fileMode()) {
+        case QFileDialog::Directory:
+            setLabelTextControl(QFileDialog::Accept, QFileDialog::tr("&Choose"));
+            break;
+        default:
+            setLabelTextControl(QFileDialog::Accept,
+                                q->acceptMode() == QFileDialog::AcceptOpen ?
+                                    QFileDialog::tr("&Open")  :
+                                    QFileDialog::tr("&Save"));
+            break;
+        }
+    }
+}
+
+void QFileDialogPrivate::updateCancelButtonText()
+{
+    if (options->isLabelExplicitlySet(QFileDialogOptions::Reject))
+        setLabelTextControl(QFileDialog::Reject, options->labelText(QFileDialogOptions::Reject));
+}
+
 void QFileDialogPrivate::retranslateStrings()
 {
     Q_Q(QFileDialog);
     /* WIDGETS */
-    if (defaultFileTypes)
-        q->setNameFilter(QFileDialog::tr("All Files (*)"));
+    if (options->useDefaultNameFilters())
+        q->setNameFilter(QFileDialogOptions::defaultNameFilterString());
+    if (!usingWidgets())
+        return;
 
     QList<QAction*> actions = qFileDialogUi->treeView->header()->actions();
     QAbstractItemModel *abstractModel = model;
-#ifndef QT_NO_PROXYMODEL
+#if QT_CONFIG(proxymodel)
     if (proxyModel)
         abstractModel = proxyModel;
 #endif
-    int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1);
+    const int total = qMin(abstractModel->columnCount(QModelIndex()), int(actions.size() + 1));
     for (int i = 1; i < total; ++i) {
         actions.at(i - 1)->setText(QFileDialog::tr("Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
     }
@@ -592,38 +661,39 @@
     showHiddenAction->setText(QFileDialog::tr("Show &hidden files"));
     newFolderAction->setText(QFileDialog::tr("&New Folder"));
     qFileDialogUi->retranslateUi(q);
-
-    if (!fileNameLabelExplicitlySat){
-        if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
-            q->setLabelText(QFileDialog::FileName, QFileDialog::tr("Directory:"));
-        } else {
-            q->setLabelText(QFileDialog::FileName, QFileDialog::tr("File &name:"));
-        }
-        fileNameLabelExplicitlySat = false;
-    }
+    updateLookInLabel();
+    updateFileNameLabel();
+    updateFileTypeLabel();
+    updateCancelButtonText();
 }
 
 void QFileDialogPrivate::emitFilesSelected(const QStringList &files)
 {
     Q_Q(QFileDialog);
     emit q->filesSelected(files);
-    if (files.count() == 1)
+    if (files.size() == 1)
         emit q->fileSelected(files.first());
 }
 
-bool QFileDialogPrivate::canBeNativeDialog()
+bool QFileDialogPrivate::canBeNativeDialog() const
 {
-    Q_Q(QFileDialog);
+    // Don't use Q_Q here! This function is called from ~QDialog,
+    // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
+    const QDialog * const q = static_cast<const QDialog*>(q_ptr);
     if (nativeDialogInUse)
         return true;
-    if (q->testAttribute(Qt::WA_DontShowOnScreen))
-        return false;
-    if (opts & QFileDialog::DontUseNativeDialog)
+    if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+        || q->testAttribute(Qt::WA_DontShowOnScreen)
+        || (options->options() & QFileDialog::DontUseNativeDialog)) {
         return false;
-
-    QLatin1String staticName(QFileDialog::staticMetaObject.className());
-    QLatin1String dynamicName(q->metaObject()->className());
-    return (staticName == dynamicName);
+    }
+
+    return strcmp(QFileDialog::staticMetaObject.className(), q->metaObject()->className()) == 0;
+}
+
+bool QFileDialogPrivate::usingWidgets() const
+{
+    return !nativeDialogInUse && qFileDialogUi;
 }
 
 /*!
@@ -631,19 +701,29 @@
     Sets the given \a option to be enabled if \a on is true; otherwise,
     clears the given \a option.
 
+    Options (particularly the DontUseNativeDialogs option) should be set
+    before changing dialog properties or showing the dialog.
+
+    Setting options while the dialog is visible is not guaranteed to have
+    an immediate effect on the dialog (depending on the option and on the
+    platform).
+
+    Setting options after changing other properties may cause these
+    values to have no effect.
+
     \sa options, testOption()
 */
 void QFileDialog::setOption(Option option, bool on)
 {
-    Q_D(QFileDialog);
-    if (!(d->opts & option) != !on)
-        setOptions(d->opts ^ option);
+    const QFileDialog::Options previousOptions = options();
+    if (!(previousOptions & option) != !on)
+        setOptions(previousOptions ^ option);
 }
 
 /*!
     \since 4.5
 
-    Returns true if the given \a option is enabled; otherwise, returns
+    Returns \c true if the given \a option is enabled; otherwise, returns
     false.
 
     \sa options, setOption()
@@ -651,7 +731,7 @@
 bool QFileDialog::testOption(Option option) const
 {
     Q_D(const QFileDialog);
-    return (d->opts & option) != 0;
+    return d->options->testOption(static_cast<QFileDialogOptions::FileDialogOption>(option));
 }
 
 /*!
@@ -661,9 +741,15 @@
 
     By default, all options are disabled.
 
-    Options should be set before showing the dialog. Setting them while the
-    dialog is visible is not guaranteed to have an immediate effect on the
-    dialog (depending on the option and on the platform).
+    Options (particularly the DontUseNativeDialogs option) should be set
+    before changing dialog properties or showing the dialog.
+
+    Setting options while the dialog is visible is not guaranteed to have
+    an immediate effect on the dialog (depending on the option and on the
+    platform).
+
+    Setting options after changing other properties may cause these
+    values to have no effect.
 
     \sa setOption(), testOption()
 */
@@ -671,39 +757,57 @@
 {
     Q_D(QFileDialog);
 
-    Options changed = (options ^ d->opts);
+    Options changed = (options ^ QFileDialog::options());
     if (!changed)
         return;
 
-    d->opts = options;
-    if (changed & DontResolveSymlinks)
-        d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
-    if (changed & ReadOnly) {
-        bool ro = (options & ReadOnly);
-        d->model->setReadOnly(ro);
-        d->qFileDialogUi->newFolderButton->setEnabled(!ro);
-        d->renameAction->setEnabled(!ro);
-        d->deleteAction->setEnabled(!ro);
+    d->options->setOptions(QFileDialogOptions::FileDialogOptions(int(options)));
+
+    if (options & DontUseNativeDialog) {
+        d->nativeDialogInUse = false;
+        d->createWidgets();
     }
+
+    if (d->usingWidgets()) {
+        if (changed & DontResolveSymlinks)
+            d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
+        if (changed & ReadOnly) {
+            bool ro = (options & ReadOnly);
+            d->model->setReadOnly(ro);
+            d->qFileDialogUi->newFolderButton->setEnabled(!ro);
+            d->renameAction->setEnabled(!ro);
+            d->deleteAction->setEnabled(!ro);
+        }
+
+        if (changed & DontUseCustomDirectoryIcons) {
+            QFileIconProvider::Options providerOptions = iconProvider()->options();
+            providerOptions.setFlag(QFileIconProvider::DontUseCustomDirectoryIcons,
+                                    options & DontUseCustomDirectoryIcons);
+            iconProvider()->setOptions(providerOptions);
+        }
+    }
+
     if (changed & HideNameFilterDetails)
-        setNameFilters(d->nameFilters);
+        setNameFilters(d->options->nameFilters());
 
     if (changed & ShowDirsOnly)
         setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files);
-
-    if (changed & DontUseCustomDirectoryIcons)
-        iconProvider()->d_ptr->setUseCustomDirectoryIcons(!(options & DontUseCustomDirectoryIcons));
 }
 
 QFileDialog::Options QFileDialog::options() const
 {
     Q_D(const QFileDialog);
-    return d->opts;
+    static_assert((int)QFileDialog::ShowDirsOnly == (int)QFileDialogOptions::ShowDirsOnly);
+    static_assert((int)QFileDialog::DontResolveSymlinks == (int)QFileDialogOptions::DontResolveSymlinks);
+    static_assert((int)QFileDialog::DontConfirmOverwrite == (int)QFileDialogOptions::DontConfirmOverwrite);
+    static_assert((int)QFileDialog::DontUseNativeDialog == (int)QFileDialogOptions::DontUseNativeDialog);
+    static_assert((int)QFileDialog::ReadOnly == (int)QFileDialogOptions::ReadOnly);
+    static_assert((int)QFileDialog::HideNameFilterDetails == (int)QFileDialogOptions::HideNameFilterDetails);
+    static_assert((int)QFileDialog::DontUseCustomDirectoryIcons == (int)QFileDialogOptions::DontUseCustomDirectoryIcons);
+    return QFileDialog::Options(int(d->options->options()));
 }
 
 /*!
-    \overload
-
     \since 4.5
 
     This function connects one of its signals to the slot specified by \a receiver
@@ -731,39 +835,53 @@
 */
 void QFileDialog::setVisible(bool visible)
 {
-    Q_D(QFileDialog);
+    // will call QFileDialogPrivate::setVisible override
+    QDialog::setVisible(visible);
+}
+
+/*!
+    \internal
+
+    The logic has to live here so that the call to hide() in ~QDialog calls
+    this function; it wouldn't call an override of QDialog::setVisible().
+*/
+void QFileDialogPrivate::setVisible(bool visible)
+{
+    Q_Q(QFileDialog);
     if (visible){
-        if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
+        if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden))
             return;
-    } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+    } else if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden))
         return;
 
-    if (d->canBeNativeDialog()){
-        if (d->setVisible_sys(visible)){
-            d->nativeDialogInUse = true;
-            // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+    if (canBeNativeDialog()){
+        if (setNativeDialogVisible(visible)){
+            // Set WA_DontShowOnScreen so that QDialogPrivate::setVisible(visible) below
             // updates the state correctly, but skips showing the non-native version:
-            setAttribute(Qt::WA_DontShowOnScreen);
-#ifndef QT_NO_FSCOMPLETER
-            //So the completer don't try to complete and therefore to show a popup
-            d->completer->setModel(0);
+            q->setAttribute(Qt::WA_DontShowOnScreen);
+#if QT_CONFIG(fscompleter)
+            // So the completer doesn't try to complete and therefore show a popup
+            if (!nativeDialogInUse)
+                completer->setModel(nullptr);
 #endif
         } else {
-            d->nativeDialogInUse = false;
-            setAttribute(Qt::WA_DontShowOnScreen, false);
-#ifndef QT_NO_FSCOMPLETER
-            if (d->proxyModel != 0)
-                d->completer->setModel(d->proxyModel);
-            else
-                d->completer->setModel(d->model);
+            createWidgets();
+            q->setAttribute(Qt::WA_DontShowOnScreen, false);
+#if QT_CONFIG(fscompleter)
+            if (!nativeDialogInUse) {
+                if (proxyModel != nullptr)
+                    completer->setModel(proxyModel);
+                else
+                    completer->setModel(model);
+            }
 #endif
         }
     }
 
-    if (!d->nativeDialogInUse)
-        d->qFileDialogUi->fileNameEdit->setFocus();
-
-    QDialog::setVisible(visible);
+    if (visible && usingWidgets())
+        qFileDialogUi->fileNameEdit->setFocus();
+
+    QDialogPrivate::setVisible(visible);
 }
 
 /*!
@@ -787,12 +905,20 @@
 
 /*!
     Sets the file dialog's current \a directory.
+
+    \note On iOS, if you set \a directory to \l{QStandardPaths::standardLocations()}
+        {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()},
+        a native image picker dialog will be used for accessing the user's photo album.
+        The filename returned can be loaded using QFile and related APIs.
+        For this to be enabled, the Info.plist assigned to QMAKE_INFO_PLIST in the
+        project file must contain the key \c NSPhotoLibraryUsageDescription. See
+        Info.plist documentation from Apple for more information regarding this key.
+        This feature was added in Qt 5.5.
 */
 void QFileDialog::setDirectory(const QString &directory)
 {
     Q_D(QFileDialog);
     QString newDirectory = directory;
-    QFileInfo info(directory);
     //we remove .. and . from the given path if exist
     if (!directory.isEmpty())
         newDirectory = QDir::cleanPath(directory);
@@ -800,26 +926,30 @@
     if (!directory.isEmpty() && newDirectory.isEmpty())
         return;
 
-    d->setLastVisitedDirectory(newDirectory);
-
-    if (d->nativeDialogInUse){
-        d->setDirectory_sys(newDirectory);
+    QUrl newDirUrl = QUrl::fromLocalFile(newDirectory);
+    QFileDialogPrivate::setLastVisitedDirectory(newDirUrl);
+
+    d->options->setInitialDirectory(QUrl::fromLocalFile(directory));
+    if (!d->usingWidgets()) {
+        d->setDirectory_sys(newDirUrl);
         return;
     }
     if (d->rootPath() == newDirectory)
         return;
     QModelIndex root = d->model->setRootPath(newDirectory);
-    d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
-    if (root != d->rootIndex()) {
-#ifndef QT_NO_FSCOMPLETER
-    if (directory.endsWith(QLatin1Char('/')))
-        d->completer->setCompletionPrefix(newDirectory);
-    else
-        d->completer->setCompletionPrefix(newDirectory + QLatin1Char('/'));
+    if (!d->nativeDialogInUse) {
+        d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
+        if (root != d->rootIndex()) {
+#if QT_CONFIG(fscompleter)
+            if (directory.endsWith(u'/'))
+                d->completer->setCompletionPrefix(newDirectory);
+            else
+                d->completer->setCompletionPrefix(newDirectory + u'/');
 #endif
-        d->setRootIndex(root);
+            d->setRootIndex(root);
+        }
+        d->qFileDialogUi->listView->selectionModel()->clear();
     }
-    d->qFileDialogUi->listView->selectionModel()->clear();
 }
 
 /*!
@@ -828,7 +958,97 @@
 QDir QFileDialog::directory() const
 {
     Q_D(const QFileDialog);
-    return QDir(d->nativeDialogInUse ? d->directory_sys() : d->rootPath());
+    if (d->nativeDialogInUse) {
+        QString dir = d->directory_sys().toLocalFile();
+        return QDir(dir.isEmpty() ? d->options->initialDirectory().toLocalFile() : dir);
+    }
+    return d->rootPath();
+}
+
+/*!
+    Sets the file dialog's current \a directory url.
+
+    \note The non-native QFileDialog supports only local files.
+
+    \note On Windows, it is possible to pass URLs representing
+    one of the \e {virtual folders}, such as "Computer" or "Network".
+    This is done by passing a QUrl using the scheme \c clsid followed
+    by the CLSID value with the curly braces removed. For example the URL
+    \c clsid:374DE290-123F-4565-9164-39C4925E467B denotes the download
+    location. For a complete list of possible values, see the MSDN documentation on
+    \l{https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid}{KNOWNFOLDERID}.
+    This feature was added in Qt 5.5.
+
+    \sa QUuid
+    \since 5.2
+*/
+void QFileDialog::setDirectoryUrl(const QUrl &directory)
+{
+    Q_D(QFileDialog);
+    if (!directory.isValid())
+        return;
+
+    QFileDialogPrivate::setLastVisitedDirectory(directory);
+    d->options->setInitialDirectory(directory);
+
+    if (d->nativeDialogInUse)
+        d->setDirectory_sys(directory);
+    else if (directory.isLocalFile())
+        setDirectory(directory.toLocalFile());
+    else if (Q_UNLIKELY(d->usingWidgets()))
+        qWarning("Non-native QFileDialog supports only local files");
+}
+
+/*!
+    Returns the url of the directory currently being displayed in the dialog.
+
+    \since 5.2
+*/
+QUrl QFileDialog::directoryUrl() const
+{
+    Q_D(const QFileDialog);
+    if (d->nativeDialogInUse)
+        return d->directory_sys();
+    else
+        return QUrl::fromLocalFile(directory().absolutePath());
+}
+
+// FIXME Qt 5.4: Use upcoming QVolumeInfo class to determine this information?
+static inline bool isCaseSensitiveFileSystem(const QString &path)
+{
+    Q_UNUSED(path);
+#if defined(Q_OS_WIN)
+    // Return case insensitive unconditionally, even if someone has a case sensitive
+    // file system mounted, wrongly capitalized drive letters will cause mismatches.
+    return false;
+#elif defined(Q_OS_MACOS)
+    return pathconf(QFile::encodeName(path).constData(), _PC_CASE_SENSITIVE);
+#else
+    return true;
+#endif
+}
+
+// Determine the file name to be set on the line edit from the path
+// passed to selectFile() in mode QFileDialog::AcceptSave.
+static inline QString fileFromPath(const QString &rootPath, QString path)
+{
+    if (!QFileInfo(path).isAbsolute())
+        return path;
+    if (path.startsWith(rootPath, isCaseSensitiveFileSystem(rootPath) ? Qt::CaseSensitive : Qt::CaseInsensitive))
+        path.remove(0, rootPath.size());
+
+    if (path.isEmpty())
+        return path;
+
+    if (path.at(0) == QDir::separator()
+#ifdef Q_OS_WIN
+            //On Windows both cases can happen
+            || path.at(0) == u'/'
+#endif
+            ) {
+            path.remove(0, 1);
+    }
+    return path;
 }
 
 /*!
@@ -842,8 +1062,19 @@
     if (filename.isEmpty())
         return;
 
-    if (d->nativeDialogInUse){
-        d->selectFile_sys(filename);
+    if (!d->usingWidgets()) {
+        QUrl url;
+        if (QFileInfo(filename).isRelative()) {
+            url = d->options->initialDirectory();
+            QString path = url.path();
+            if (!path.endsWith(u'/'))
+                path += u'/';
+            url.setPath(path + filename);
+        } else {
+            url = QUrl::fromLocalFile(filename);
+        }
+        d->selectFile_sys(url);
+        d->options->setInitiallySelectedFiles(QList<QUrl>() << url);
         return;
     }
 
@@ -856,73 +1087,71 @@
     }
 
     QModelIndex index = d->model->index(filename);
-    QString file;
-    if (!index.isValid()) {
-        // save as dialog where we want to input a default value
-        QString text = filename;
-        if (QFileInfo(filename).isAbsolute()) {
-            QString current = d->rootPath();
-            text.remove(current);
-            if (text.at(0) == QDir::separator()
-#ifdef Q_OS_WIN
-                //On Windows both cases can happen
-                || text.at(0) == QLatin1Char('/')
-#endif
-                )
-                text = text.remove(0,1);
-        }
-        file = text;
-    } else {
-        file = index.data().toString();
-    }
     d->qFileDialogUi->listView->selectionModel()->clear();
     if (!isVisible() || !d->lineEdit()->hasFocus())
-        d->lineEdit()->setText(file);
+        d->lineEdit()->setText(index.isValid() ? index.data().toString() : fileFromPath(d->rootPath(), filename));
+}
+
+/*!
+    Selects the given \a url in the file dialog.
+
+    \note The non-native QFileDialog supports only local files.
+
+    \sa selectedUrls()
+    \since 5.2
+*/
+void QFileDialog::selectUrl(const QUrl &url)
+{
+    Q_D(QFileDialog);
+    if (!url.isValid())
+        return;
+
+    if (d->nativeDialogInUse)
+        d->selectFile_sys(url);
+    else if (url.isLocalFile())
+        selectFile(url.toLocalFile());
+    else
+        qWarning("Non-native QFileDialog supports only local files");
 }
 
 #ifdef Q_OS_UNIX
-Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0)
+Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path)
 {
-    if (expanded != 0)
-        *expanded = false;
-    if (!path.startsWith(QLatin1Char('~')))
+    if (!path.startsWith(u'~'))
         return path;
-    QString ret = path;
-#if !defined(Q_OS_INTEGRITY)
-    QStringList tokens = ret.split(QDir::separator());
-    if (tokens.first() == QLatin1String("~")) {
-        ret.replace(0, 1, QDir::homePath());
+    int separatorPosition = path.indexOf(QDir::separator());
+    if (separatorPosition < 0)
+        separatorPosition = path.size();
+    if (separatorPosition == 1) {
+        return QDir::homePath() + QStringView{path}.mid(1);
     } else {
-        QString userName = tokens.first();
-        userName.remove(0, 1);
-#if defined(Q_OS_VXWORKS)
+#if defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY)
         const QString homePath = QDir::homePath();
-#elif defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+#else
+        const QByteArray userName = QStringView{path}.mid(1, separatorPosition - 1).toLocal8Bit();
+# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
         passwd pw;
         passwd *tmpPw;
         char buf[200];
         const int bufSize = sizeof(buf);
         int err = 0;
-#if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L)
-        tmpPw = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize);
-#else
-        err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw);
-#endif
+#  if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L)
+        tmpPw = getpwnam_r(userName.constData(), &pw, buf, bufSize);
+#  else
+        err = getpwnam_r(userName.constData(), &pw, buf, bufSize, &tmpPw);
+#  endif
         if (err || !tmpPw)
-            return ret;
+            return path;
         const QString homePath = QString::fromLocal8Bit(pw.pw_dir);
-#else
-        passwd *pw = getpwnam(userName.toLocal8Bit().constData());
+# else
+        passwd *pw = getpwnam(userName.constData());
         if (!pw)
-            return ret;
+            return path;
         const QString homePath = QString::fromLocal8Bit(pw->pw_dir);
+# endif
 #endif
-        ret.replace(0, tokens.first().length(), homePath);
+        return homePath + QStringView{path}.mid(separatorPosition);
     }
-    if (expanded != 0)
-        *expanded = true;
-#endif
-    return ret;
 }
 #endif
 
@@ -931,12 +1160,10 @@
   */
 QStringList QFileDialogPrivate::typedFiles() const
 {
-#ifdef Q_OS_UNIX
     Q_Q(const QFileDialog);
-#endif
     QStringList files;
     QString editText = lineEdit()->text();
-    if (!editText.contains(QLatin1Char('"'))) {
+    if (!editText.contains(u'"')) {
 #ifdef Q_OS_UNIX
         const QString prefix = q->directory().absolutePath() + QDir::separator();
         if (QFile::exists(prefix + editText))
@@ -945,11 +1172,12 @@
             files << qt_tildeExpansion(editText);
 #else
         files << editText;
+        Q_UNUSED(q);
 #endif
     } else {
         // " is used to separate files like so: "file1" "file2" "file3" ...
         // ### need escape character for filenames with quotes (")
-        QStringList tokens = editText.split(QLatin1Char('\"'));
+        QStringList tokens = editText.split(u'\"');
         for (int i=0; i<tokens.size(); ++i) {
             if ((i % 2) == 0)
                 continue; // Every even token is a separator
@@ -968,15 +1196,42 @@
     return addDefaultSuffixToFiles(files);
 }
 
-QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesToFix) const
+// Return selected files without defaulting to the root of the file system model
+// used for initializing QFileDialogOptions for native dialogs. The default is
+// not suitable for native dialogs since it mostly equals directory().
+QList<QUrl> QFileDialogPrivate::userSelectedFiles() const
+{
+    QList<QUrl> files;
+
+    if (!usingWidgets())
+        return addDefaultSuffixToUrls(selectedFiles_sys());
+
+    const QModelIndexList selectedRows = qFileDialogUi->listView->selectionModel()->selectedRows();
+    files.reserve(selectedRows.size());
+    for (const QModelIndex &index : selectedRows)
+        files.append(QUrl::fromLocalFile(index.data(QFileSystemModel::FilePathRole).toString()));
+
+    if (files.isEmpty() && !lineEdit()->text().isEmpty()) {
+        const QStringList typedFilesList = typedFiles();
+        files.reserve(typedFilesList.size());
+        for (const QString &path : typedFilesList)
+            files.append(QUrl::fromLocalFile(path));
+    }
+
+    return files;
+}
+
+QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList &filesToFix) const
 {
     QStringList files;
     for (int i=0; i<filesToFix.size(); ++i) {
         QString name = toInternal(filesToFix.at(i));
         QFileInfo info(name);
         // if the filename has no suffix, add the default suffix
-        if (!defaultSuffix.isEmpty() && !info.isDir() && name.lastIndexOf(QLatin1Char('.')) == -1)
-            name += QLatin1Char('.') + defaultSuffix;
+        const QString defaultSuffix = options->defaultSuffix();
+        if (!defaultSuffix.isEmpty() && !info.isDir() && !info.fileName().contains(u'.'))
+            name += u'.' + defaultSuffix;
+
         if (info.isAbsolute()) {
             files.append(name);
         } else {
@@ -984,8 +1239,8 @@
             // This check is needed since we might be at the root directory
             // and on Windows it already ends with slash.
             QString path = rootPath();
-            if (!path.endsWith(QLatin1Char('/')))
-                path += QLatin1Char('/');
+            if (!path.endsWith(u'/'))
+                path += u'/';
             path += name;
             files.append(path);
         }
@@ -993,6 +1248,24 @@
     return files;
 }
 
+QList<QUrl> QFileDialogPrivate::addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const
+{
+    QList<QUrl> urls;
+    urls.reserve(urlsToFix.size());
+    // if the filename has no suffix, add the default suffix
+    const QString defaultSuffix = options->defaultSuffix();
+    for (QUrl url : urlsToFix) {
+        if (!defaultSuffix.isEmpty()) {
+            const QString urlPath = url.path();
+            const auto idx = urlPath.lastIndexOf(u'/');
+            if (idx != (urlPath.size() - 1) && !QStringView{urlPath}.mid(idx + 1).contains(u'.'))
+                url.setPath(urlPath + u'.' + defaultSuffix);
+        }
+        urls.append(url);
+    }
+    return urls;
+}
+
 
 /*!
     Returns a list of strings containing the absolute paths of the
@@ -1004,43 +1277,58 @@
 QStringList QFileDialog::selectedFiles() const
 {
     Q_D(const QFileDialog);
-    if (d->nativeDialogInUse)
-        return d->addDefaultSuffixToFiles(d->selectedFiles_sys());
-
-    QModelIndexList indexes = d->qFileDialogUi->listView->selectionModel()->selectedRows();
+
     QStringList files;
-    for (int i = 0; i < indexes.count(); ++i)
-        files.append(indexes.at(i).data(QFileSystemModel::FilePathRole).toString());
-
-    if (files.isEmpty() && !d->lineEdit()->text().isEmpty())
-        files = d->typedFiles();
-
-    if (files.isEmpty() && !(d->fileMode == ExistingFile || d->fileMode == ExistingFiles))
-        files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
+    const QList<QUrl> userSelectedFiles = d->userSelectedFiles();
+    files.reserve(userSelectedFiles.size());
+    for (const QUrl &file : userSelectedFiles)
+        files.append(file.toString(QUrl::PreferLocalFile));
+
+    if (files.isEmpty() && d->usingWidgets()) {
+        const FileMode fm = fileMode();
+        if (fm != ExistingFile && fm != ExistingFiles)
+            files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
+    }
     return files;
 }
 
+/*!
+    Returns a list of urls containing the selected files in the dialog.
+    If no files are selected, or the mode is not ExistingFiles or
+    ExistingFile, selectedUrls() contains the current path in the viewport.
+
+    \sa selectedNameFilter(), selectUrl()
+    \since 5.2
+*/
+QList<QUrl> QFileDialog::selectedUrls() const
+{
+    Q_D(const QFileDialog);
+    if (d->nativeDialogInUse) {
+        return d->userSelectedFiles();
+    } else {
+        QList<QUrl> urls;
+        const QStringList selectedFileList = selectedFiles();
+        urls.reserve(selectedFileList.size());
+        for (const QString &file : selectedFileList)
+            urls.append(QUrl::fromLocalFile(file));
+        return urls;
+    }
+}
+
 /*
     Makes a list of filters from ;;-separated text.
     Used by the mac and windows implementations
 */
 QStringList qt_make_filter_list(const QString &filter)
 {
-    QString f(filter);
-
-    if (f.isEmpty())
+    if (filter.isEmpty())
         return QStringList();
 
-    QString sep(QLatin1String(";;"));
-    int i = f.indexOf(sep, 0);
-    if (i == -1) {
-        if (f.indexOf(QLatin1Char('\n'), 0) != -1) {
-            sep = QLatin1Char('\n');
-            i = f.indexOf(sep, 0);
-        }
-    }
-
-    return f.split(sep);
+    auto sep = ";;"_L1;
+    if (!filter.contains(sep) && filter.contains(u'\n'))
+        sep = "\n"_L1;
+
+    return filter.split(sep);
 }
 
 /*!
@@ -1049,67 +1337,43 @@
     Sets the filter used in the file dialog to the given \a filter.
 
     If \a filter contains a pair of parentheses containing one or more
-    of \bold{anything*something}, separated by spaces, then only the
+    filename-wildcard patterns, separated by spaces, then only the
     text contained in the parentheses is used as the filter. This means
     that these calls are all equivalent:
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 6
-
-    \sa setNameFilters()
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 6
+
+    \note With Android's native file dialog, the mime type matching the given
+        name filter is used because only mime types are supported.
+
+    \sa setMimeTypeFilters(), setNameFilters()
 */
 void QFileDialog::setNameFilter(const QString &filter)
 {
     setNameFilters(qt_make_filter_list(filter));
 }
 
-/*!
-  \obsolete
-
-  Use setNameFilter() instead.
-*/
-void QFileDialog::setFilter(const QString &filter)
-{
-    setNameFilter(filter);
-}
-
-/*!
-    \property QFileDialog::nameFilterDetailsVisible
-    \obsolete
-    \brief This property holds whether the filter details is shown or not.
-    \since 4.4
-
-    When this property is true (the default), the filter details are shown
-    in the combo box.  When the property is set to false, these are hidden.
-
-    Use setOption(HideNameFilterDetails, !\e enabled) or
-    !testOption(HideNameFilterDetails).
-*/
-void QFileDialog::setNameFilterDetailsVisible(bool enabled)
-{
-    setOption(HideNameFilterDetails, !enabled);
-}
-
-bool QFileDialog::isNameFilterDetailsVisible() const
-{
-    return !testOption(HideNameFilterDetails);
-}
-
 
 /*
     Strip the filters by removing the details, e.g. (*.*).
 */
 QStringList qt_strip_filters(const QStringList &filters)
 {
+#if QT_CONFIG(regularexpression)
     QStringList strippedFilters;
-    QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
-    for (int i = 0; i < filters.count(); ++i) {
+    static const QRegularExpression r(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
+    strippedFilters.reserve(filters.size());
+    for (const QString &filter : filters) {
         QString filterName;
-        int index = r.indexIn(filters[i]);
-        if (index >= 0)
-            filterName = r.cap(1);
+        auto match = r.match(filter);
+        if (match.hasMatch())
+            filterName = match.captured(1);
         strippedFilters.append(filterName.simplified());
     }
     return strippedFilters;
+#else
+    return filters;
+#endif
 }
 
 
@@ -1118,22 +1382,32 @@
 
     Sets the \a filters used in the file dialog.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 7
+    Note that the filter \b{*.*} is not portable, because the historical
+    assumption that the file extension determines the file type is not
+    consistent on every operating system. It is possible to have a file with no
+    dot in its name (for example, \c Makefile). In a native Windows file
+    dialog, \b{*.*} will match such files, while in other types of file dialogs
+    it may not. So it is better to use \b{*} if you mean to select any file.
+
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 7
+
+    \l setMimeTypeFilters() has the advantage of providing all possible name
+    filters for each file type. For example, JPEG images have three possible
+    extensions; if your application can open such files, selecting the
+    \c image/jpeg mime type as a filter will allow you to open all of them.
 */
 void QFileDialog::setNameFilters(const QStringList &filters)
 {
     Q_D(QFileDialog);
-    d->defaultFileTypes = (filters == QStringList(QFileDialog::tr("All Files (*)")));
     QStringList cleanedFilters;
-    for (int i = 0; i < filters.count(); ++i) {
-        cleanedFilters << filters[i].simplified();
-    }
-    d->nameFilters = cleanedFilters;
-
-    if (d->nativeDialogInUse){
-        d->setNameFilters_sys(cleanedFilters);
+    cleanedFilters.reserve(filters.size());
+    for (const QString &filter : filters)
+        cleanedFilters << filter.simplified();
+
+    d->options->setNameFilters(cleanedFilters);
+
+    if (!d->usingWidgets())
         return;
-    }
 
     d->qFileDialogUi->fileTypeCombo->clear();
     if (cleanedFilters.isEmpty())
@@ -1148,16 +1422,6 @@
 }
 
 /*!
-    \obsolete
-
-    Use setNameFilters() instead.
-*/
-void QFileDialog::setFilters(const QStringList &filters)
-{
-    setNameFilters(filters);
-}
-
-/*!
     \since 4.4
 
     Returns the file type filters that are in operation on this file
@@ -1165,18 +1429,7 @@
 */
 QStringList QFileDialog::nameFilters() const
 {
-    return d_func()->nameFilters;
-}
-
-/*!
-    \obsolete
-
-    Use nameFilters() instead.
-*/
-
-QStringList QFileDialog::filters() const
-{
-    return nameFilters();
+    return d_func()->options->nameFilters();
 }
 
 /*!
@@ -1190,7 +1443,8 @@
 void QFileDialog::selectNameFilter(const QString &filter)
 {
     Q_D(QFileDialog);
-    if (d->nativeDialogInUse) {
+    d->options->setInitiallySelectedNameFilter(filter);
+    if (!d->usingWidgets()) {
         d->selectNameFilter_sys(filter);
         return;
     }
@@ -1209,17 +1463,6 @@
 }
 
 /*!
-    \obsolete
-
-    Use selectNameFilter() instead.
-*/
-
-void QFileDialog::selectFilter(const QString &filter)
-{
-    selectNameFilter(filter);
-}
-
-/*!
     \since 4.4
 
     Returns the filter that the user selected in the file dialog.
@@ -1229,23 +1472,13 @@
 QString QFileDialog::selectedNameFilter() const
 {
     Q_D(const QFileDialog);
-    if (d->nativeDialogInUse)
+    if (!d->usingWidgets())
         return d->selectedNameFilter_sys();
 
     return d->qFileDialogUi->fileTypeCombo->currentText();
 }
 
 /*!
-    \obsolete
-
-    Use selectedNameFilter() instead.
-*/
-QString QFileDialog::selectedFilter() const
-{
-    return selectedNameFilter();
-}
-
-/*!
     \since 4.4
 
     Returns the filter that is used when displaying files.
@@ -1255,7 +1488,9 @@
 QDir::Filters QFileDialog::filter() const
 {
     Q_D(const QFileDialog);
-    return d->model->filter();
+    if (d->usingWidgets())
+        return d->model->filter();
+    return d->options->filter();
 }
 
 /*!
@@ -1270,15 +1505,129 @@
 void QFileDialog::setFilter(QDir::Filters filters)
 {
     Q_D(QFileDialog);
-    d->model->setFilter(filters);
-    if (d->nativeDialogInUse){
+    d->options->setFilter(filters);
+    if (!d->usingWidgets()) {
         d->setFilter_sys();
         return;
     }
 
+    d->model->setFilter(filters);
     d->showHiddenAction->setChecked((filters & QDir::Hidden));
 }
 
+#if QT_CONFIG(mimetype)
+
+static QString nameFilterForMime(const QString &mimeType)
+{
+    QMimeDatabase db;
+    QMimeType mime(db.mimeTypeForName(mimeType));
+    if (mime.isValid()) {
+        if (mime.isDefault()) {
+            return QFileDialog::tr("All files (*)");
+        } else {
+            const QString patterns = mime.globPatterns().join(u' ');
+            return mime.comment() + " ("_L1 + patterns + u')';
+        }
+    }
+    return QString();
+}
+
+/*!
+    \since 5.2
+
+    Sets the \a filters used in the file dialog, from a list of MIME types.
+
+    Convenience method for setNameFilters().
+    Uses QMimeType to create a name filter from the glob patterns and description
+    defined in each MIME type.
+
+    Use application/octet-stream for the "All files (*)" filter, since that
+    is the base MIME type for all files.
+
+    Calling setMimeTypeFilters overrides any previously set name filters,
+    and changes the return value of nameFilters().
+
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 13
+*/
+void QFileDialog::setMimeTypeFilters(const QStringList &filters)
+{
+    Q_D(QFileDialog);
+    QStringList nameFilters;
+    for (const QString &mimeType : filters) {
+        const QString text = nameFilterForMime(mimeType);
+        if (!text.isEmpty())
+            nameFilters.append(text);
+    }
+    setNameFilters(nameFilters);
+    d->options->setMimeTypeFilters(filters);
+}
+
+/*!
+    \since 5.2
+
+    Returns the MIME type filters that are in operation on this file
+    dialog.
+*/
+QStringList QFileDialog::mimeTypeFilters() const
+{
+    return d_func()->options->mimeTypeFilters();
+}
+
+/*!
+    \since 5.2
+
+    Sets the current MIME type \a filter.
+
+*/
+void QFileDialog::selectMimeTypeFilter(const QString &filter)
+{
+    Q_D(QFileDialog);
+    d->options->setInitiallySelectedMimeTypeFilter(filter);
+
+    const QString filterForMime = nameFilterForMime(filter);
+
+    if (!d->usingWidgets()) {
+        d->selectMimeTypeFilter_sys(filter);
+        if (d->selectedMimeTypeFilter_sys().isEmpty() && !filterForMime.isEmpty()) {
+            selectNameFilter(filterForMime);
+        }
+    } else if (!filterForMime.isEmpty()) {
+        selectNameFilter(filterForMime);
+    }
+}
+
+#endif // mimetype
+
+/*!
+ * \since 5.9
+ * \return The mimetype of the file that the user selected in the file dialog.
+ */
+QString QFileDialog::selectedMimeTypeFilter() const
+{
+    Q_D(const QFileDialog);
+    QString mimeTypeFilter;
+    if (!d->usingWidgets())
+        mimeTypeFilter = d->selectedMimeTypeFilter_sys();
+
+#if QT_CONFIG(mimetype)
+    if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) {
+        const auto nameFilter = selectedNameFilter();
+        const auto mimeTypes = d->options->mimeTypeFilters();
+        for (const auto &mimeType: mimeTypes) {
+            QString filter = nameFilterForMime(mimeType);
+            if (testOption(HideNameFilterDetails))
+                filter = qt_strip_filters({ filter }).first();
+            if (filter == nameFilter) {
+                mimeTypeFilter = mimeType;
+                break;
+            }
+        }
+    }
+#endif
+
+    return mimeTypeFilter;
+}
+
 /*!
     \property QFileDialog::viewMode
     \brief the way files and directories are displayed in the dialog
@@ -1291,6 +1640,9 @@
 void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
 {
     Q_D(QFileDialog);
+    d->options->setViewMode(static_cast<QFileDialogOptions::ViewMode>(mode));
+    if (!d->usingWidgets())
+        return;
     if (mode == Detail)
         d->_q_showDetailsView();
     else
@@ -1300,6 +1652,8 @@
 QFileDialog::ViewMode QFileDialog::viewMode() const
 {
     Q_D(const QFileDialog);
+    if (!d->usingWidgets())
+        return static_cast<QFileDialog::ViewMode>(d->options->viewMode());
     return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail);
 }
 
@@ -1321,12 +1675,12 @@
 void QFileDialog::setFileMode(QFileDialog::FileMode mode)
 {
     Q_D(QFileDialog);
-    d->fileMode = mode;
+    d->options->setFileMode(static_cast<QFileDialogOptions::FileMode>(mode));
+    if (!d->usingWidgets())
+        return;
+
     d->retranslateWindowTitle();
 
-    // keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete)
-    setOption(ShowDirsOnly, mode == DirectoryOnly);
-
     // set selection mode and behavior
     QAbstractItemView::SelectionMode selectionMode;
     if (mode == QFileDialog::ExistingFiles)
@@ -1338,29 +1692,13 @@
     // set filter
     d->model->setFilter(d->filterForMode(filter()));
     // setup file type for directory
-    QString buttonText = (d->acceptMode == AcceptOpen ? tr("&Open") : tr("&Save"));
-    if (mode == DirectoryOnly || mode == Directory) {
+    if (mode == Directory) {
         d->qFileDialogUi->fileTypeCombo->clear();
         d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories"));
         d->qFileDialogUi->fileTypeCombo->setEnabled(false);
-
-        if (!d->fileNameLabelExplicitlySat){
-            setLabelText(FileName, tr("Directory:"));
-            d->fileNameLabelExplicitlySat = false;
-        }
-        buttonText = tr("&Choose");
-    } else {
-        if (!d->fileNameLabelExplicitlySat){
-            setLabelText(FileName, tr("File &name:"));
-            d->fileNameLabelExplicitlySat = false;
-        }
     }
-    setLabelText(Accept, buttonText);
-    if (d->nativeDialogInUse){
-        d->setFilter_sys();
-        return;
-    }
-
+    d->updateFileNameLabel();
+    d->updateOkButtonText();
     d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
     d->_q_updateOkButton();
 }
@@ -1368,7 +1706,7 @@
 QFileDialog::FileMode QFileDialog::fileMode() const
 {
     Q_D(const QFileDialog);
-    return d->fileMode;
+    return static_cast<FileMode>(d->options->fileMode());
 }
 
 /*!
@@ -1384,24 +1722,43 @@
 void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
 {
     Q_D(QFileDialog);
-    d->acceptMode = mode;
-    bool directoryMode = (d->fileMode == Directory || d->fileMode == DirectoryOnly);
+    d->options->setAcceptMode(static_cast<QFileDialogOptions::AcceptMode>(mode));
+    // clear WA_DontShowOnScreen so that d->canBeNativeDialog() doesn't return false incorrectly
+    setAttribute(Qt::WA_DontShowOnScreen, false);
+    if (!d->usingWidgets())
+        return;
     QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
     d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
     d->qFileDialogUi->buttonBox->button(button)->setEnabled(false);
     d->_q_updateOkButton();
-    if (mode == AcceptOpen && directoryMode)
-        setLabelText(Accept, tr("&Choose"));
-    else
-        setLabelText(Accept, (mode == AcceptOpen ? tr("&Open") : tr("&Save")));
     if (mode == AcceptSave) {
         d->qFileDialogUi->lookInCombo->setEditable(false);
     }
     d->retranslateWindowTitle();
-#if defined(Q_WS_MAC)
-    d->deleteNativeDialog_sys();
-    setAttribute(Qt::WA_DontShowOnScreen, false);
-#endif
+}
+
+/*!
+    \property QFileDialog::supportedSchemes
+    \brief the URL schemes that the file dialog should allow navigating to.
+    \since 5.6
+
+    Setting this property allows to restrict the type of URLs the
+    user will be able to select. It is a way for the application to declare
+    the protocols it will support to fetch the file content. An empty list
+    means that no restriction is applied (the default).
+    Supported for local files ("file" scheme) is implicit and always enabled;
+    it is not necessary to include it in the restriction.
+*/
+
+void QFileDialog::setSupportedSchemes(const QStringList &schemes)
+{
+    Q_D(QFileDialog);
+    d->options->setSupportedSchemes(schemes);
+}
+
+QStringList QFileDialog::supportedSchemes() const
+{
+    return d_func()->options->supportedSchemes();
 }
 
 /*
@@ -1414,7 +1771,7 @@
 
 QAbstractItemView *QFileDialogPrivate::currentView() const {
     if (!qFileDialogUi->stackedWidget)
-        return 0;
+        return nullptr;
     if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent())
         return qFileDialogUi->listView;
     return qFileDialogUi->treeView;
@@ -1424,6 +1781,22 @@
     return (QLineEdit*)qFileDialogUi->fileNameEdit;
 }
 
+long QFileDialogPrivate::maxNameLength(const QString &path)
+{
+#if defined(Q_OS_UNIX)
+    return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
+#elif defined(Q_OS_WIN)
+    DWORD maxLength;
+    const QString drive = path.left(3);
+    if (::GetVolumeInformation(reinterpret_cast<const wchar_t *>(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) == false)
+        return -1;
+    return maxLength;
+#else
+    Q_UNUSED(path);
+#endif
+    return -1;
+}
+
 /*
     Sets the view root index to be the file system model index
 */
@@ -1450,67 +1823,7 @@
 QFileDialog::AcceptMode QFileDialog::acceptMode() const
 {
     Q_D(const QFileDialog);
-    return d->acceptMode;
-}
-
-/*!
-    \property QFileDialog::readOnly
-    \obsolete
-    \brief Whether the filedialog is read-only
-
-    If this property is set to false, the file dialog will allow renaming,
-    and deleting of files and directories and creating directories.
-
-    Use setOption(ReadOnly, \e enabled) or testOption(ReadOnly) instead.
-*/
-void QFileDialog::setReadOnly(bool enabled)
-{
-    setOption(ReadOnly, enabled);
-}
-
-bool QFileDialog::isReadOnly() const
-{
-    return testOption(ReadOnly);
-}
-
-/*!
-    \property QFileDialog::resolveSymlinks
-    \obsolete
-    \brief whether the filedialog should resolve shortcuts
-
-    If this property is set to true, the file dialog will resolve
-    shortcuts or symbolic links.
-
-    Use setOption(DontResolveSymlinks, !\a enabled) or
-    !testOption(DontResolveSymlinks).
-*/
-void QFileDialog::setResolveSymlinks(bool enabled)
-{
-    setOption(DontResolveSymlinks, !enabled);
-}
-
-bool QFileDialog::resolveSymlinks() const
-{
-    return !testOption(DontResolveSymlinks);
-}
-
-/*!
-    \property QFileDialog::confirmOverwrite
-    \obsolete
-    \brief whether the filedialog should ask before accepting a selected file,
-    when the accept mode is AcceptSave
-
-    Use setOption(DontConfirmOverwrite, !\e enabled) or
-    !testOption(DontConfirmOverwrite) instead.
-*/
-void QFileDialog::setConfirmOverwrite(bool enabled)
-{
-    setOption(DontConfirmOverwrite, !enabled);
-}
-
-bool QFileDialog::confirmOverwrite() const
-{
-    return !testOption(DontConfirmOverwrite);
+    return static_cast<AcceptMode>(d->options->acceptMode());
 }
 
 /*!
@@ -1521,17 +1834,19 @@
     filename if it has no suffix already. The suffix is typically
     used to indicate the file type (e.g. "txt" indicates a text
     file).
+
+    If the first character is a dot ('.'), it is removed.
 */
 void QFileDialog::setDefaultSuffix(const QString &suffix)
 {
     Q_D(QFileDialog);
-    d->defaultSuffix = suffix;
+    d->options->setDefaultSuffix(suffix);
 }
 
 QString QFileDialog::defaultSuffix() const
 {
     Q_D(const QFileDialog);
-    return d->defaultSuffix;
+    return d->options->defaultSuffix();
 }
 
 /*!
@@ -1541,7 +1856,8 @@
 void QFileDialog::setHistory(const QStringList &paths)
 {
     Q_D(QFileDialog);
-    d->qFileDialogUi->lookInCombo->setHistory(paths);
+    if (d->usingWidgets())
+        d->qFileDialogUi->lookInCombo->setHistory(paths);
 }
 
 void QFileDialogComboBox::setHistory(const QStringList &paths)
@@ -1549,9 +1865,11 @@
     m_history = paths;
     // Only populate the first item, showPopup will populate the rest if needed
     QList<QUrl> list;
-    QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
+    const QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
     //On windows the popup display the "C:\", convert to nativeSeparators
-    QUrl url = QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()));
+    const QUrl url = idx.isValid()
+                   ? QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()))
+                   : QUrl("file:"_L1);
     if (url.isValid())
         list.append(url);
     urlModel->setUrls(list);
@@ -1563,6 +1881,8 @@
 QStringList QFileDialog::history() const
 {
     Q_D(const QFileDialog);
+    if (!d->usingWidgets())
+        return QStringList();
     QStringList currentHistory = d->qFileDialogUi->lookInCombo->history();
     //On windows the popup display the "C:\", convert to nativeSeparators
     QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
@@ -1575,6 +1895,9 @@
     Sets the item delegate used to render items in the views in the
     file dialog to the given \a delegate.
 
+    Any existing delegate will be removed, but not deleted. QFileDialog
+    does not take ownership of \a delegate.
+
     \warning You should not share the same instance of a delegate between views.
     Doing so can cause incorrect or unintuitive editing behavior since each
     view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
@@ -1589,6 +1912,8 @@
 void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate)
 {
     Q_D(QFileDialog);
+    if (!d->usingWidgets())
+        return;
     d->qFileDialogUi->listView->setItemDelegate(delegate);
     d->qFileDialogUi->treeView->setItemDelegate(delegate);
 }
@@ -1599,15 +1924,19 @@
 QAbstractItemDelegate *QFileDialog::itemDelegate() const
 {
     Q_D(const QFileDialog);
+    if (!d->usingWidgets())
+        return nullptr;
     return d->qFileDialogUi->listView->itemDelegate();
 }
 
 /*!
     Sets the icon provider used by the filedialog to the specified \a provider.
 */
-void QFileDialog::setIconProvider(QFileIconProvider *provider)
+void QFileDialog::setIconProvider(QAbstractFileIconProvider *provider)
 {
     Q_D(QFileDialog);
+    if (!d->usingWidgets())
+        return;
     d->model->setIconProvider(provider);
     //It forces the refresh of all entries in the side bar, then we can get new icons
     d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls());
@@ -1616,45 +1945,53 @@
 /*!
     Returns the icon provider used by the filedialog.
 */
-QFileIconProvider *QFileDialog::iconProvider() const
+QAbstractFileIconProvider *QFileDialog::iconProvider() const
 {
     Q_D(const QFileDialog);
+    if (!d->model)
+        return nullptr;
     return d->model->iconProvider();
 }
 
+void QFileDialogPrivate::setLabelTextControl(QFileDialog::DialogLabel label, const QString &text)
+{
+    if (!qFileDialogUi)
+        return;
+    switch (label) {
+    case QFileDialog::LookIn:
+        qFileDialogUi->lookInLabel->setText(text);
+        break;
+    case QFileDialog::FileName:
+        qFileDialogUi->fileNameLabel->setText(text);
+        break;
+    case QFileDialog::FileType:
+        qFileDialogUi->fileTypeLabel->setText(text);
+        break;
+    case QFileDialog::Accept:
+        if (q_func()->acceptMode() == QFileDialog::AcceptOpen) {
+            if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Open))
+                button->setText(text);
+        } else {
+            if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Save))
+                button->setText(text);
+        }
+        break;
+    case QFileDialog::Reject:
+        if (QPushButton *button = qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel))
+            button->setText(text);
+        break;
+    }
+}
+
 /*!
     Sets the \a text shown in the filedialog in the specified \a label.
 */
+
 void QFileDialog::setLabelText(DialogLabel label, const QString &text)
 {
     Q_D(QFileDialog);
-    QPushButton *button;
-    switch (label) {
-    case LookIn:
-        d->qFileDialogUi->lookInLabel->setText(text);
-        break;
-    case FileName:
-        d->qFileDialogUi->fileNameLabel->setText(text);
-        d->fileNameLabelExplicitlySat = true;
-        break;
-    case FileType:
-        d->qFileDialogUi->fileTypeLabel->setText(text);
-        break;
-    case Accept:
-        d->acceptLabel = text;
-        if (acceptMode() == AcceptOpen)
-            button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
-        else
-            button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
-        if (button)
-            button->setText(text);
-        break;
-    case Reject:
-        button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
-        if (button)
-            button->setText(text);
-        break;
-    }
+    d->options->setLabelText(static_cast<QFileDialogOptions::DialogLabel>(label), text);
+    d->setLabelTextControl(label, text);
 }
 
 /*!
@@ -1662,8 +1999,10 @@
 */
 QString QFileDialog::labelText(DialogLabel label) const
 {
+    Q_D(const QFileDialog);
+    if (!d->usingWidgets())
+        return d->options->labelText(static_cast<QFileDialogOptions::DialogLabel>(label));
     QPushButton *button;
-    Q_D(const QFileDialog);
     switch (label) {
     case LookIn:
         return d->qFileDialogUi->lookInLabel->text();
@@ -1678,62 +2017,25 @@
             button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
         if (button)
             return button->text();
+        break;
     case Reject:
         button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
         if (button)
             return button->text();
+        break;
     }
     return QString();
 }
 
-/*
-    For the native file dialogs
-*/
-
-#if defined(Q_WS_WIN)
-extern QString qt_win_get_open_file_name(const QFileDialogArgs &args,
-                                         QString *initialDirectory,
-                                         QString *selectedFilter);
-
-extern QString qt_win_get_save_file_name(const QFileDialogArgs &args,
-                                         QString *initialDirectory,
-                                         QString *selectedFilter);
-
-extern QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
-                                              QString *initialDirectory,
-                                              QString *selectedFilter);
-
-extern QString qt_win_get_existing_directory(const QFileDialogArgs &args);
-#endif
-
-/*
-    For Symbian file dialogs
-*/
-#if defined(Q_WS_S60)
-extern QString qtSymbianGetOpenFileName(const QString &caption,
-                                        const QString &dir,
-                                        const QString &filter);
-
-extern QStringList qtSymbianGetOpenFileNames(const QString &caption,
-                                             const QString &dir,
-                                             const QString &filter);
-
-extern QString qtSymbianGetSaveFileName(const QString &caption,
-                                        const QString &dir);
-
-extern QString qtSymbianGetExistingDirectory(const QString &caption,
-                                             const QString &dir);
-#endif
-
 /*!
     This is a convenience static function that returns an existing file
     selected by the user. If the user presses Cancel, it returns a null string.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 8
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 8
 
     The function creates a modal file dialog with the given \a parent widget.
-    If \a parent is not 0, the dialog will be shown centered over the parent
-    widget.
+    If \a parent is not \nullptr, the dialog will be shown centered over the
+    parent widget.
 
     The file dialog's working directory will be set to \a dir. If \a dir
     includes a file name, the file will be selected. Only files that match the
@@ -1742,9 +2044,7 @@
     strings. If you want multiple filters, separate them with ';;', for
     example:
 
-    \code
-    "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
-    \endcode
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 14
 
     The \a options argument holds various options about how to run the dialog,
     see the QFileDialog::Option enum for more information on the flags you can
@@ -1753,12 +2053,13 @@
     The dialog's caption is set to \a caption. If \a caption is not specified
     then a default caption will be used.
 
-    On Windows, Mac OS X and Symbian^3, this static function will use the
-    native file dialog and not a QFileDialog.
+    On Windows, and \macos, this static function will use the
+    native file dialog and not a QFileDialog. Note that the \macos native file
+    dialog does not show a title bar.
 
     On Windows the dialog will spin a blocking modal event loop that will not
-    dispatch any QTimers, and if \a parent is not 0 then it will position the
-    dialog just below the parent's title bar.
+    dispatch any QTimers, and if \a parent is not \nullptr then it will position
+    the dialog just below the parent's title bar.
 
     On Unix/X11, the normal behavior of the file dialog is to resolve and
     follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
@@ -1766,10 +2067,6 @@
     \a options includes DontResolveSymlinks, the file dialog will treat
     symlinks as regular directories.
 
-    On Symbian^3 the parameter \a selectedFilter has no meaning and the
-    \a options parameter is only used to define if the native file dialog is
-    used.
-
     \warning Do not delete \a parent during the execution of the dialog. If you
     want to do this, you should create the dialog yourself using one of the
     QFileDialog constructors.
@@ -1783,47 +2080,78 @@
                                QString *selectedFilter,
                                Options options)
 {
-    if (qt_filedialog_open_filename_hook && !(options & DontUseNativeDialog))
-        return qt_filedialog_open_filename_hook(parent, caption, dir, filter, selectedFilter, options);
-#if defined(Q_WS_S60)
-    if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
-        return qtSymbianGetOpenFileName(caption, dir, filter);
-#endif
-    QFileDialogArgs args;
+    const QStringList schemes = QStringList(QStringLiteral("file"));
+    const QUrl selectedUrl = getOpenFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
+                                            selectedFilter, options, schemes);
+    if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
+        return selectedUrl.toLocalFile();
+    else
+        return selectedUrl.toString();
+}
+
+/*!
+    This is a convenience static function that returns an existing file
+    selected by the user. If the user presses Cancel, it returns an
+    empty url.
+
+    The function is used similarly to QFileDialog::getOpenFileName(). In
+    particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
+    and \a options are used in the exact same way.
+
+    The main difference with QFileDialog::getOpenFileName() comes from
+    the ability offered to the user to select a remote file. That's why
+    the return type and the type of \a dir is QUrl.
+
+    The \a supportedSchemes argument allows to restrict the type of URLs the
+    user will be able to select. It is a way for the application to declare
+    the protocols it will support to fetch the file content. An empty list
+    means that no restriction is applied (the default).
+    Supported for local files ("file" scheme) is implicit and always enabled;
+    it is not necessary to include it in the restriction.
+
+    When possible, this static function will use the native file dialog and
+    not a QFileDialog. On platforms which don't support selecting remote
+    files, Qt will allow to select only local files.
+
+    \sa getOpenFileName(), getOpenFileUrls(), getSaveFileUrl(), getExistingDirectoryUrl()
+    \since 5.2
+*/
+QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
+                                 const QString &caption,
+                                 const QUrl &dir,
+                                 const QString &filter,
+                                 QString *selectedFilter,
+                                 Options options,
+                                 const QStringList &supportedSchemes)
+{
+    QFileDialogArgs args(dir);
     args.parent = parent;
     args.caption = caption;
-    args.directory = QFileDialogPrivate::workingDirectory(dir);
-    args.selection = QFileDialogPrivate::initialSelection(dir);
     args.filter = filter;
     args.mode = ExistingFile;
     args.options = options;
-#if defined(Q_WS_WIN)
-    if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
-        return qt_win_get_open_file_name(args, &(args.directory), selectedFilter);
-    }
-#endif
-
-    // create a qt dialog
+
     QFileDialog dialog(args);
+    dialog.setSupportedSchemes(supportedSchemes);
     if (selectedFilter && !selectedFilter->isEmpty())
         dialog.selectNameFilter(*selectedFilter);
     if (dialog.exec() == QDialog::Accepted) {
         if (selectedFilter)
-            *selectedFilter = dialog.selectedFilter();
-        return dialog.selectedFiles().value(0);
+            *selectedFilter = dialog.selectedNameFilter();
+        return dialog.selectedUrls().value(0);
     }
-    return QString();
+    return QUrl();
 }
 
 /*!
     This is a convenience static function that will return one or more existing
     files selected by the user.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 9
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 9
 
     This function creates a modal file dialog with the given \a parent widget.
-    If \a parent is not 0, the dialog will be shown centered over the parent
-    widget.
+    If \a parent is not \nullptr, the dialog will be shown centered over the
+    parent widget.
 
     The file dialog's working directory will be set to \a dir. If \a dir
     includes a file name, the file will be selected. The filter is set to
@@ -1832,19 +2160,18 @@
     \a selectedFilter and \a filter may be empty strings. If you need multiple
     filters, separate them with ';;', for instance:
 
-    \code
-    "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
-    \endcode
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 14
 
     The dialog's caption is set to \a caption. If \a caption is not specified
     then a default caption will be used.
 
-    On Windows, Mac OS X and Symbian^3, this static function will use the
-    native file dialog and not a QFileDialog.
+    On Windows, and \macos, this static function will use the
+    native file dialog and not a QFileDialog. Note that the \macos native file
+    dialog does not show a title bar.
 
     On Windows the dialog will spin a blocking modal event loop that will not
-    dispatch any QTimers, and if \a parent is not 0 then it will position the
-    dialog just below the parent's title bar.
+    dispatch any QTimers, and if \a parent is not \nullptr then it will position
+    the dialog just below the parent's title bar.
 
     On Unix/X11, the normal behavior of the file dialog is to resolve and
     follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
@@ -1853,15 +2180,6 @@
     see the QFileDialog::Option enum for more information on the flags you can
     pass.
 
-    \note If you want to iterate over the list of files, you should iterate
-    over a copy. For example:
-
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 10
-
-    On Symbian^3 the parameter \a selectedFilter has no meaning and the
-    \a options parameter is only used to define if the native file dialog is
-    used. On Symbian^3, this function can only return a single filename.
-
     \warning Do not delete \a parent during the execution of the dialog. If you
     want to do this, you should create the dialog yourself using one of the
     QFileDialog constructors.
@@ -1875,37 +2193,179 @@
                                           QString *selectedFilter,
                                           Options options)
 {
-    if (qt_filedialog_open_filenames_hook && !(options & DontUseNativeDialog))
-        return qt_filedialog_open_filenames_hook(parent, caption, dir, filter, selectedFilter, options);
-#if defined(Q_WS_S60)
-    if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
-        return qtSymbianGetOpenFileNames(caption, dir, filter);
-#endif
-    QFileDialogArgs args;
+    const QStringList schemes = QStringList(QStringLiteral("file"));
+    const QList<QUrl> selectedUrls = getOpenFileUrls(parent, caption, QUrl::fromLocalFile(dir),
+                                                     filter, selectedFilter, options, schemes);
+    QStringList fileNames;
+    fileNames.reserve(selectedUrls.size());
+    for (const QUrl &url : selectedUrls)
+        fileNames.append(url.toString(QUrl::PreferLocalFile));
+    return fileNames;
+}
+
+/*!
+    This is a convenience static function that will return one or more existing
+    files selected by the user. If the user presses Cancel, it returns an
+    empty list.
+
+    The function is used similarly to QFileDialog::getOpenFileNames(). In
+    particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
+    and \a options are used in the exact same way.
+
+    The main difference with QFileDialog::getOpenFileNames() comes from
+    the ability offered to the user to select remote files. That's why
+    the return type and the type of \a dir are respectively QList<QUrl>
+    and QUrl.
+
+    The \a supportedSchemes argument allows to restrict the type of URLs the
+    user will be able to select. It is a way for the application to declare
+    the protocols it will support to fetch the file content. An empty list
+    means that no restriction is applied (the default).
+    Supported for local files ("file" scheme) is implicit and always enabled;
+    it is not necessary to include it in the restriction.
+
+    When possible, this static function will use the native file dialog and
+    not a QFileDialog. On platforms which don't support selecting remote
+    files, Qt will allow to select only local files.
+
+    \sa getOpenFileNames(), getOpenFileUrl(), getSaveFileUrl(), getExistingDirectoryUrl()
+    \since 5.2
+*/
+QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
+                                         const QString &caption,
+                                         const QUrl &dir,
+                                         const QString &filter,
+                                         QString *selectedFilter,
+                                         Options options,
+                                         const QStringList &supportedSchemes)
+{
+    QFileDialogArgs args(dir);
     args.parent = parent;
     args.caption = caption;
-    args.directory = QFileDialogPrivate::workingDirectory(dir);
-    args.selection = QFileDialogPrivate::initialSelection(dir);
     args.filter = filter;
     args.mode = ExistingFiles;
     args.options = options;
 
-#if defined(Q_WS_WIN)
-    if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
-        return qt_win_get_open_file_names(args, &(args.directory), selectedFilter);
-    }
-#endif
-
-    // create a qt dialog
     QFileDialog dialog(args);
+    dialog.setSupportedSchemes(supportedSchemes);
     if (selectedFilter && !selectedFilter->isEmpty())
         dialog.selectNameFilter(*selectedFilter);
     if (dialog.exec() == QDialog::Accepted) {
         if (selectedFilter)
-            *selectedFilter = dialog.selectedFilter();
-        return dialog.selectedFiles();
+            *selectedFilter = dialog.selectedNameFilter();
+        return dialog.selectedUrls();
     }
-    return QStringList();
+    return QList<QUrl>();
+}
+
+/*!
+    This is a convenience static function that will return the content of a file
+    selected by the user.
+
+    This function is used to access local files on Qt for WebAssembly, where the web
+    sandbox places restrictions on how such access may happen. Its implementation will
+    make the browser display a native file dialog, where the user makes the file selection
+    based on the parameter \a nameFilter.
+
+    It can also be used on other platforms, where it will fall back to using QFileDialog.
+
+    The function is asynchronous and returns immediately. The \a fileOpenCompleted
+    callback will be called when a file has been selected and its contents have been
+    read into memory.
+
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 15
+    \since 5.13
+*/
+void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::function<void(const QString &, const QByteArray &)> &fileOpenCompleted)
+{
+#ifdef Q_OS_WASM
+    auto openFileImpl = std::make_shared<std::function<void(void)>>();
+    QString fileName;
+    QByteArray fileContent;
+    *openFileImpl = [=]() mutable {
+        auto fileDialogClosed = [&](bool fileSelected) {
+            if (!fileSelected) {
+                fileOpenCompleted(fileName, fileContent);
+                openFileImpl.reset();
+            }
+        };
+        auto acceptFile = [&](uint64_t size, const std::string name) -> char * {
+            const uint64_t twoGB = 1ULL << 31; // QByteArray limit
+            if (size > twoGB)
+                return nullptr;
+
+            fileName = QString::fromStdString(name);
+            fileContent.resize(size);
+            return fileContent.data();
+        };
+        auto fileContentReady = [&]() mutable {
+            fileOpenCompleted(fileName, fileContent);
+            openFileImpl.reset();
+        };
+
+        QWasmLocalFileAccess::openFile(nameFilter.toStdString(), fileDialogClosed, acceptFile, fileContentReady);
+    };
+
+    (*openFileImpl)();
+#else
+    QFileDialog *dialog = new QFileDialog();
+    dialog->setFileMode(QFileDialog::ExistingFile);
+    dialog->setNameFilter(nameFilter);
+
+    auto fileSelected = [=](const QString &fileName) {
+        QByteArray fileContent;
+        if (!fileName.isNull()) {
+            QFile selectedFile(fileName);
+            if (selectedFile.open(QIODevice::ReadOnly))
+                fileContent = selectedFile.readAll();
+        }
+        fileOpenCompleted(fileName, fileContent);
+    };
+
+    connect(dialog, &QFileDialog::fileSelected, fileSelected);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+#endif
+}
+
+/*!
+    This is a convenience static function that saves \a fileContent to a file, using
+    a file name and location chosen by the user. \a fileNameHint can be provided to
+    suggest a file name to the user.
+
+    This function is used to save files to the local file system on Qt for WebAssembly, where
+    the web sandbox places restrictions on how such access may happen. Its implementation will
+    make the browser display a native file dialog, where the user makes the file selection.
+
+    It can also be used on other platforms, where it will fall back to using QFileDialog.
+
+    The function is asynchronous and returns immediately.
+
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 16
+    \since 5.14
+*/
+void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint)
+{
+#ifdef Q_OS_WASM
+    QWasmLocalFileAccess::saveFile(fileContent, fileNameHint.toStdString());
+#else
+    QFileDialog *dialog = new QFileDialog();
+    dialog->setAcceptMode(QFileDialog::AcceptSave);
+    dialog->setFileMode(QFileDialog::AnyFile);
+    dialog->selectFile(fileNameHint);
+
+    auto fileSelected = [=](const QString &fileName) {
+        if (!fileName.isNull()) {
+            QFile selectedFile(fileName);
+            if (selectedFile.open(QIODevice::WriteOnly))
+                selectedFile.write(fileContent);
+        }
+    };
+
+    connect(dialog, &QFileDialog::fileSelected, fileSelected);
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->show();
+#endif
 }
 
 /*!
@@ -1913,10 +2373,10 @@
     by the user. The file does not have to exist.
 
     It creates a modal file dialog with the given \a parent widget. If
-    \a parent is not 0, the dialog will be shown centered over the parent
-    widget.
-
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 11
+    \a parent is not \nullptr, the dialog will be shown centered over the
+    parent widget.
+
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 11
 
     The file dialog's working directory will be set to \a dir. If \a dir
     includes a file name, the file will be selected. Only files that match the
@@ -1924,9 +2384,7 @@
     parameters \a dir, \a selectedFilter, and \a filter may be empty strings.
     Multiple filters are separated with ';;'. For instance:
 
-    \code
-    "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
-    \endcode
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 14
 
     The \a options argument holds various options about how to run the dialog,
     see the QFileDialog::Option enum for more information on the flags you can
@@ -1938,13 +2396,13 @@
     The dialog's caption is set to \a caption. If \a caption is not specified,
     a default caption will be used.
 
-    On Windows, Mac OS X and Symbian^3, this static function will use the
+    On Windows, and \macos, this static function will use the
     native file dialog and not a QFileDialog.
 
     On Windows the dialog will spin a blocking modal event loop that will not
-    dispatch any QTimers, and if \a parent is not 0 then it will position the
-    dialog just below the parent's title bar. On Mac OS X, with its native file
-    dialog, the filter argument is ignored.
+    dispatch any QTimers, and if \a parent is not \nullptr then it will
+    position the  dialog just below the parent's title bar. On \macos, with its
+    native file dialog, the filter argument is ignored.
 
     On Unix/X11, the normal behavior of the file dialog is to resolve and
     follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
@@ -1952,10 +2410,6 @@
     \a options includes DontResolveSymlinks the file dialog will treat symlinks
     as regular directories.
 
-    On Symbian^3 the parameters \a filter and \a selectedFilter have no
-    meaning. The \a options parameter is only used to define if the native file
-    dialog is used.
-
     \warning Do not delete \a parent during the execution of the dialog. If you
     want to do this, you should create the dialog yourself using one of the
     QFileDialog constructors.
@@ -1969,50 +2423,79 @@
                                      QString *selectedFilter,
                                      Options options)
 {
-    if (qt_filedialog_save_filename_hook && !(options & DontUseNativeDialog))
-        return qt_filedialog_save_filename_hook(parent, caption, dir, filter, selectedFilter, options);
-#if defined(Q_WS_S60)
-    if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
-        return qtSymbianGetSaveFileName(caption, dir);
-#endif
-    QFileDialogArgs args;
+    const QStringList schemes = QStringList(QStringLiteral("file"));
+    const QUrl selectedUrl = getSaveFileUrl(parent, caption, QUrl::fromLocalFile(dir), filter,
+                                            selectedFilter, options, schemes);
+    if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
+        return selectedUrl.toLocalFile();
+    else
+        return selectedUrl.toString();
+}
+
+/*!
+    This is a convenience static function that returns a file selected by
+    the user. The file does not have to exist. If the user presses Cancel,
+    it returns an empty url.
+
+    The function is used similarly to QFileDialog::getSaveFileName(). In
+    particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
+    and \a options are used in the exact same way.
+
+    The main difference with QFileDialog::getSaveFileName() comes from
+    the ability offered to the user to select a remote file. That's why
+    the return type and the type of \a dir is QUrl.
+
+    The \a supportedSchemes argument allows to restrict the type of URLs the
+    user will be able to select. It is a way for the application to declare
+    the protocols it will support to save the file content. An empty list
+    means that no restriction is applied (the default).
+    Supported for local files ("file" scheme) is implicit and always enabled;
+    it is not necessary to include it in the restriction.
+
+    When possible, this static function will use the native file dialog and
+    not a QFileDialog. On platforms which don't support selecting remote
+    files, Qt will allow to select only local files.
+
+    \sa getSaveFileName(), getOpenFileUrl(), getOpenFileUrls(), getExistingDirectoryUrl()
+    \since 5.2
+*/
+QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
+                                 const QString &caption,
+                                 const QUrl &dir,
+                                 const QString &filter,
+                                 QString *selectedFilter,
+                                 Options options,
+                                 const QStringList &supportedSchemes)
+{
+    QFileDialogArgs args(dir);
     args.parent = parent;
     args.caption = caption;
-    args.directory = QFileDialogPrivate::workingDirectory(dir);
-    args.selection = QFileDialogPrivate::initialSelection(dir);
     args.filter = filter;
     args.mode = AnyFile;
     args.options = options;
 
-#if defined(Q_WS_WIN)
-    if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
-        return qt_win_get_save_file_name(args, &(args.directory), selectedFilter);
-    }
-#endif
-
-    // create a qt dialog
     QFileDialog dialog(args);
+    dialog.setSupportedSchemes(supportedSchemes);
     dialog.setAcceptMode(AcceptSave);
     if (selectedFilter && !selectedFilter->isEmpty())
         dialog.selectNameFilter(*selectedFilter);
     if (dialog.exec() == QDialog::Accepted) {
         if (selectedFilter)
-            *selectedFilter = dialog.selectedFilter();
-        return dialog.selectedFiles().value(0);
+            *selectedFilter = dialog.selectedNameFilter();
+        return dialog.selectedUrls().value(0);
     }
-
-    return QString();
+    return QUrl();
 }
 
 /*!
     This is a convenience static function that will return an existing
     directory selected by the user.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 12
+    \snippet code/src_gui_dialogs_qfiledialog.cpp 12
 
     This function creates a modal file dialog with the given \a parent widget.
-    If \a parent is not 0, the dialog will be shown centered over the parent
-    widget.
+    If \a parent is not \nullptr, the dialog will be shown centered over the
+    parent widget.
 
     The dialog's working directory is set to \a dir, and the caption is set to
     \a caption. Either of these may be an empty string in which case the
@@ -2023,9 +2506,13 @@
     pass. To ensure a native file dialog, \l{QFileDialog::}{ShowDirsOnly} must
     be set.
 
-    On Windows, Mac OS X and Symbian^3, this static function will use the
-    native file dialog and not a QFileDialog. On Windows CE, if the device has
-    no native file dialog, a QFileDialog will be used.
+    On Windows and \macos, this static function will use the
+    native file dialog and not a QFileDialog. However, the native Windows file
+    dialog does not support displaying files in the directory chooser. You need
+    to pass \l{QFileDialog::}{DontUseNativeDialog} to display files using a
+    QFileDialog.
+
+    Note that the \macos native file dialog does not show a title bar.
 
     On Unix/X11, the normal behavior of the file dialog is to resolve and
     follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
@@ -2033,12 +2520,9 @@
     \a options includes DontResolveSymlinks, the file dialog will treat
     symlinks as regular directories.
 
-    On Windows the dialog will spin a blocking modal event loop that will not
-    dispatch any QTimers, and if \a parent is not 0 then it will position the
-    dialog just below the parent's title bar.
-
-    On Symbian^3 the \a options parameter is only used to define if the native
-    file dialog is used.
+    On Windows, the dialog will spin a blocking modal event loop that will not
+    dispatch any QTimers, and if \a parent is not \nullptr then it will position
+    the dialog just below the parent's title bar.
 
     \warning Do not delete \a parent during the execution of the dialog. If you
     want to do this, you should create the dialog yourself using one of the
@@ -2051,80 +2535,109 @@
                                           const QString &dir,
                                           Options options)
 {
-    if (qt_filedialog_existing_directory_hook && !(options & DontUseNativeDialog))
-        return qt_filedialog_existing_directory_hook(parent, caption, dir, options);
-#if defined(Q_WS_S60)
-    if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
-        return qtSymbianGetExistingDirectory(caption, dir);
-#endif
-    QFileDialogArgs args;
+    const QStringList schemes = QStringList(QStringLiteral("file"));
+    const QUrl selectedUrl =
+            getExistingDirectoryUrl(parent, caption, QUrl::fromLocalFile(dir), options, schemes);
+    if (selectedUrl.isLocalFile() || selectedUrl.isEmpty())
+        return selectedUrl.toLocalFile();
+    else
+        return selectedUrl.toString();
+}
+
+/*!
+    This is a convenience static function that will return an existing
+    directory selected by the user. If the user presses Cancel, it
+    returns an empty url.
+
+    The function is used similarly to QFileDialog::getExistingDirectory().
+    In particular \a parent, \a caption, \a dir and \a options are used
+    in the exact same way.
+
+    The main difference with QFileDialog::getExistingDirectory() comes from
+    the ability offered to the user to select a remote directory. That's why
+    the return type and the type of \a dir is QUrl.
+
+    The \a supportedSchemes argument allows to restrict the type of URLs the
+    user will be able to select. It is a way for the application to declare
+    the protocols it will support to fetch the file content. An empty list
+    means that no restriction is applied (the default).
+    Supported for local files ("file" scheme) is implicit and always enabled;
+    it is not necessary to include it in the restriction.
+
+    When possible, this static function will use the native file dialog and
+    not a QFileDialog. On platforms which don't support selecting remote
+    files, Qt will allow to select only local files.
+
+    \sa getExistingDirectory(), getOpenFileUrl(), getOpenFileUrls(), getSaveFileUrl()
+    \since 5.2
+*/
+QUrl QFileDialog::getExistingDirectoryUrl(QWidget *parent,
+                                          const QString &caption,
+                                          const QUrl &dir,
+                                          Options options,
+                                          const QStringList &supportedSchemes)
+{
+    QFileDialogArgs args(dir);
     args.parent = parent;
     args.caption = caption;
-    args.directory = QFileDialogPrivate::workingDirectory(dir);
-    args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory);
+    args.mode = Directory;
     args.options = options;
 
-#if defined(Q_WS_WIN)
-    if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog) && (options & ShowDirsOnly)
-#if defined(Q_WS_WINCE)
-        && qt_priv_ptr_valid
-#endif
-        ) {
-        return qt_win_get_existing_directory(args);
-    }
-#endif
-
-    // create a qt dialog
     QFileDialog dialog(args);
-    if (dialog.exec() == QDialog::Accepted) {
-        return dialog.selectedFiles().value(0);
-    }
-    return QString();
+    dialog.setSupportedSchemes(supportedSchemes);
+    if (dialog.exec() == QDialog::Accepted)
+        return dialog.selectedUrls().value(0);
+    return QUrl();
 }
 
-inline static QString _qt_get_directory(const QString &path)
+inline static QUrl _qt_get_directory(const QUrl &url, const QFileInfo &local)
 {
-    QFileInfo info = QFileInfo(QDir::current(), path);
-    if (info.exists() && info.isDir())
-        return QDir::cleanPath(info.absoluteFilePath());
-    info.setFile(info.absolutePath());
-    if (info.exists() && info.isDir())
-        return info.absoluteFilePath();
-    return QString();
-}
-/*
-    Get the initial directory path
-
-    \sa initialSelection()
- */
-QString QFileDialogPrivate::workingDirectory(const QString &path)
-{
-    if (!path.isEmpty()) {
-        QString directory = _qt_get_directory(path);
-        if (!directory.isEmpty())
-            return directory;
+    if (url.isLocalFile()) {
+        QFileInfo info = local;
+        if (!local.isAbsolute())
+            info = QFileInfo(QDir::current(), url.toLocalFile());
+        const QFileInfo pathInfo(info.absolutePath());
+        if (!pathInfo.exists() || !pathInfo.isDir())
+            return QUrl();
+        if (info.exists() && info.isDir())
+            return QUrl::fromLocalFile(QDir::cleanPath(info.absoluteFilePath()));
+        return QUrl::fromLocalFile(pathInfo.absoluteFilePath());
+    } else {
+        return url;
     }
-    QString directory = _qt_get_directory(*lastVisitedDir());
-    if (!directory.isEmpty())
-        return directory;
-    return QDir::currentPath();
 }
 
 /*
-    Get the initial selection given a path.  The initial directory
-    can contain both the initial directory and initial selection
-    /home/user/foo.txt
-
-    \sa workingDirectory()
- */
-QString QFileDialogPrivate::initialSelection(const QString &path)
+    Initialize working directory and selection from \a url.
+*/
+QFileDialogArgs::QFileDialogArgs(const QUrl &url)
 {
-    if (!path.isEmpty()) {
-        QFileInfo info(path);
-        if (!info.isDir())
-            return info.fileName();
+    // default case, re-use QFileInfo to avoid stat'ing
+    const QFileInfo local(url.toLocalFile());
+    // Get the initial directory URL
+    if (!url.isEmpty())
+        directory = _qt_get_directory(url, local);
+    if (directory.isEmpty()) {
+        const QUrl lastVisited = *lastVisitedDir();
+        if (lastVisited != url)
+            directory = _qt_get_directory(lastVisited, QFileInfo());
     }
-    return QString();
+    if (directory.isEmpty())
+        directory = QUrl::fromLocalFile(QDir::currentPath());
+
+    /*
+    The initial directory can contain both the initial directory
+    and initial selection, e.g. /home/user/foo.txt
+    */
+    if (selection.isEmpty() && !url.isEmpty()) {
+        if (url.isLocalFile()) {
+            if (!local.isDir())
+                selection = local.fileName();
+        } else {
+            // With remote URLs we can only assume.
+            selection = url.fileName();
+        }
+    }
 }
 
 /*!
@@ -2139,51 +2652,77 @@
     if (d->receiverToDisconnectOnClose) {
         disconnect(this, d->signalToDisconnectOnClose,
                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
-        d->receiverToDisconnectOnClose = 0;
+        d->receiverToDisconnectOnClose = nullptr;
     }
     d->memberToDisconnectOnClose.clear();
     d->signalToDisconnectOnClose.clear();
 }
 
+bool QFileDialogPrivate::itemAlreadyExists(const QString &fileName)
+{
+#if QT_CONFIG(messagebox)
+    Q_Q(QFileDialog);
+    const QString msg = QFileDialog::tr("%1 already exists.\nDo you want to replace it?").arg(fileName);
+    using B = QMessageBox;
+    const auto res = B::warning(q, q->windowTitle(), msg, B::Yes | B::No, B::No);
+    return res == B::Yes;
+#endif
+    return false;
+}
+
+void QFileDialogPrivate::itemNotFound(const QString &fileName, QFileDialog::FileMode mode)
+{
+#if QT_CONFIG(messagebox)
+    Q_Q(QFileDialog);
+    const QString message = mode == QFileDialog::Directory
+            ? QFileDialog::tr("%1\nDirectory not found.\n"
+                              "Please verify the correct directory name was given.")
+            : QFileDialog::tr("%1\nFile not found.\nPlease verify the "
+                              "correct file name was given.");
+
+    QMessageBox::warning(q, q->windowTitle(), message.arg(fileName));
+#endif // QT_CONFIG(messagebox)
+}
+
 /*!
  \reimp
 */
 void QFileDialog::accept()
 {
     Q_D(QFileDialog);
-    QStringList files = selectedFiles();
-    if (files.isEmpty())
-        return;
-    if (d->nativeDialogInUse){
-        d->emitFilesSelected(files);
+    if (!d->usingWidgets()) {
+        const QList<QUrl> urls = selectedUrls();
+        if (urls.isEmpty())
+            return;
+        d->_q_emitUrlsSelected(urls);
+        if (urls.size() == 1)
+            d->_q_emitUrlSelected(urls.first());
         QDialog::accept();
         return;
     }
 
+    const QStringList files = selectedFiles();
+    if (files.isEmpty())
+        return;
     QString lineEditText = d->lineEdit()->text();
     // "hidden feature" type .. and then enter, and it will move up a dir
     // special case for ".."
-    if (lineEditText == QLatin1String("..")) {
+    if (lineEditText == ".."_L1) {
         d->_q_navigateToParent();
-        bool block = d->qFileDialogUi->fileNameEdit->blockSignals(true);
+        const QSignalBlocker blocker(d->qFileDialogUi->fileNameEdit);
         d->lineEdit()->selectAll();
-        d->qFileDialogUi->fileNameEdit->blockSignals(block);
         return;
     }
 
-    switch (d->fileMode) {
-    case DirectoryOnly:
+    const auto mode = fileMode();
+    switch (mode) {
     case Directory: {
         QString fn = files.first();
         QFileInfo info(fn);
         if (!info.exists())
             info = QFileInfo(d->getEnvironmentVariable(fn));
         if (!info.exists()) {
-#ifndef QT_NO_MESSAGEBOX
-            QString message = tr("%1\nDirectory not found.\nPlease verify the "
-                                          "correct directory name was given.");
-            QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
-#endif // QT_NO_MESSAGEBOX
+            d->itemNotFound(info.fileName(), mode);
             return;
         }
         if (info.isDir()) {
@@ -2202,42 +2741,32 @@
         }
 
         if (!info.exists()) {
-            int maxNameLength = d->maxNameLength(info.path());
-            if (maxNameLength >= 0 && info.fileName().length() > maxNameLength)
+            const long maxNameLength = d->maxNameLength(info.path());
+            if (maxNameLength >= 0 && info.fileName().size() > maxNameLength)
                 return;
         }
 
         // check if we have to ask for permission to overwrite the file
-        if (!info.exists() || !confirmOverwrite() || acceptMode() == AcceptOpen) {
+        if (!info.exists() || testOption(DontConfirmOverwrite) || acceptMode() == AcceptOpen) {
             d->emitFilesSelected(QStringList(fn));
             QDialog::accept();
-#ifndef QT_NO_MESSAGEBOX
         } else {
-            if (QMessageBox::warning(this, windowTitle(),
-                                     tr("%1 already exists.\nDo you want to replace it?")
-                                     .arg(info.fileName()),
-                                     QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
-                    == QMessageBox::Yes) {
+            if (d->itemAlreadyExists(info.fileName())) {
                 d->emitFilesSelected(QStringList(fn));
                 QDialog::accept();
             }
-#endif
         }
         return;
     }
 
     case ExistingFile:
     case ExistingFiles:
-        for (int i = 0; i < files.count(); ++i) {
-            QFileInfo info(files.at(i));
+        for (const auto &file : files) {
+            QFileInfo info(file);
             if (!info.exists())
-                info = QFileInfo(d->getEnvironmentVariable(files.at(i)));
+                info = QFileInfo(d->getEnvironmentVariable(file));
             if (!info.exists()) {
-#ifndef QT_NO_MESSAGEBOX
-                QString message = tr("%1\nFile not found.\nPlease verify the "
-                                     "correct file name was given.");
-                QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
-#endif // QT_NO_MESSAGEBOX
+                d->itemNotFound(info.fileName(), mode);
                 return;
             }
             if (info.isDir()) {
@@ -2252,32 +2781,147 @@
     }
 }
 
+#if QT_CONFIG(settings)
+void QFileDialogPrivate::saveSettings()
+{
+    Q_Q(QFileDialog);
+    QSettings settings(QSettings::UserScope, u"QtProject"_s);
+    settings.beginGroup("FileDialog");
+
+    if (usingWidgets()) {
+        settings.setValue("sidebarWidth", qFileDialogUi->splitter->sizes().constFirst());
+        settings.setValue("shortcuts", QUrl::toStringList(qFileDialogUi->sidebar->urls()));
+        settings.setValue("treeViewHeader", qFileDialogUi->treeView->header()->saveState());
+    }
+    QStringList historyUrls;
+    const QStringList history = q->history();
+    historyUrls.reserve(history.size());
+    for (const QString &path : history)
+        historyUrls << QUrl::fromLocalFile(path).toString();
+    settings.setValue("history", historyUrls);
+    settings.setValue("lastVisited", lastVisitedDir()->toString());
+    const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewMode"));
+    settings.setValue("viewMode", QLatin1StringView(viewModeMeta.key(q->viewMode())));
+    settings.setValue("qtVersion", QT_VERSION_STR ""_L1);
+}
+
+bool QFileDialogPrivate::restoreFromSettings()
+{
+    Q_Q(QFileDialog);
+    QSettings settings(QSettings::UserScope, u"QtProject"_s);
+    if (!settings.childGroups().contains("FileDialog"_L1))
+        return false;
+    settings.beginGroup("FileDialog");
+
+    q->setDirectoryUrl(lastVisitedDir()->isEmpty() ? settings.value("lastVisited").toUrl() : *lastVisitedDir());
+
+    QByteArray viewModeStr = settings.value("viewMode").toString().toLatin1();
+    const QMetaEnum &viewModeMeta = q->metaObject()->enumerator(q->metaObject()->indexOfEnumerator("ViewMode"));
+    bool ok = false;
+    int viewMode = viewModeMeta.keyToValue(viewModeStr.constData(), &ok);
+    if (!ok)
+        viewMode = QFileDialog::List;
+    q->setViewMode(static_cast<QFileDialog::ViewMode>(viewMode));
+
+    sidebarUrls = QUrl::fromStringList(settings.value("shortcuts").toStringList());
+    headerData = settings.value("treeViewHeader").toByteArray();
+
+    if (!usingWidgets())
+        return true;
+
+    QStringList history;
+    const auto urlStrings = settings.value("history").toStringList();
+    for (const QString &urlStr : urlStrings) {
+        QUrl url(urlStr);
+        if (url.isLocalFile())
+            history << url.toLocalFile();
+    }
+
+    return restoreWidgetState(history, settings.value("sidebarWidth", -1).toInt());
+}
+#endif // settings
+
+bool QFileDialogPrivate::restoreWidgetState(QStringList &history, int splitterPosition)
+{
+    Q_Q(QFileDialog);
+    if (splitterPosition >= 0) {
+        QList<int> splitterSizes;
+        splitterSizes.append(splitterPosition);
+        splitterSizes.append(qFileDialogUi->splitter->widget(1)->sizeHint().width());
+        qFileDialogUi->splitter->setSizes(splitterSizes);
+    } else {
+        if (!qFileDialogUi->splitter->restoreState(splitterState))
+            return false;
+        QList<int> list = qFileDialogUi->splitter->sizes();
+        if (list.size() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) {
+            for (int i = 0; i < list.size(); ++i)
+                list[i] = qFileDialogUi->splitter->widget(i)->sizeHint().width();
+            qFileDialogUi->splitter->setSizes(list);
+        }
+    }
+
+    qFileDialogUi->sidebar->setUrls(sidebarUrls);
+
+    static const int MaxHistorySize = 5;
+    if (history.size() > MaxHistorySize)
+        history.erase(history.begin(), history.end() - MaxHistorySize);
+    q->setHistory(history);
+
+    QHeaderView *headerView = qFileDialogUi->treeView->header();
+    if (!headerView->restoreState(headerData))
+        return false;
+
+    QList<QAction*> actions = headerView->actions();
+    QAbstractItemModel *abstractModel = model;
+#if QT_CONFIG(proxymodel)
+    if (proxyModel)
+        abstractModel = proxyModel;
+#endif
+    const int total = qMin(abstractModel->columnCount(QModelIndex()), int(actions.size() + 1));
+    for (int i = 1; i < total; ++i)
+        actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
+
+    return true;
+}
+
 /*!
     \internal
 
     Create widgets, layout and set default values
 */
-void QFileDialogPrivate::init(const QString &directory, const QString &nameFilter,
-                              const QString &caption)
+void QFileDialogPrivate::init(const QFileDialogArgs &args)
 {
     Q_Q(QFileDialog);
-    if (!caption.isEmpty()) {
+    if (!args.caption.isEmpty()) {
         useDefaultCaption = false;
-        setWindowTitle = caption;
-        q->setWindowTitle(caption);
+        setWindowTitle = args.caption;
+        q->setWindowTitle(args.caption);
     }
 
-    createWidgets();
-    createMenuActions();
-    retranslateStrings();
-    q->setFileMode(fileMode);
-
-#ifndef QT_NO_SETTINGS
-    QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
-    settings.beginGroup(QLatin1String("Qt"));
-    if (!directory.isEmpty())
-        setLastVisitedDirectory(workingDirectory(directory));
-    q->restoreState(settings.value(QLatin1String("filedialog")).toByteArray());
+    q->setAcceptMode(QFileDialog::AcceptOpen);
+    nativeDialogInUse = platformFileDialogHelper() != nullptr;
+    if (!nativeDialogInUse)
+        createWidgets();
+    q->setFileMode(QFileDialog::AnyFile);
+    if (!args.filter.isEmpty())
+        q->setNameFilter(args.filter);
+    // QTBUG-70798, prevent the default blocking the restore logic.
+    const bool dontStoreDir = !args.directory.isValid() && !lastVisitedDir()->isValid();
+    q->setDirectoryUrl(args.directory);
+    if (dontStoreDir)
+        lastVisitedDir()->clear();
+    if (args.directory.isLocalFile())
+        q->selectFile(args.selection);
+    else
+        q->selectUrl(args.directory);
+
+#if QT_CONFIG(settings)
+    // Try to restore from the FileDialog settings group; if it fails, fall back
+    // to the pre-5.5 QByteArray serialized settings.
+    if (!restoreFromSettings()) {
+        const QSettings settings(QSettings::UserScope, u"QtProject"_s);
+        q->restoreState(settings.value("Qt/filedialog").toByteArray());
+    }
 #endif
 
 #if defined(Q_EMBEDDED_SMALLSCREEN)
@@ -2286,15 +2930,10 @@
     qFileDialogUi->fileTypeLabel->setVisible(false);
     qFileDialogUi->sidebar->hide();
 #endif
-    // Default case
-    if (!nameFilter.isEmpty())
-        q->setNameFilter(nameFilter);
-    q->setAcceptMode(QFileDialog::AcceptOpen);
-    q->setDirectory(workingDirectory(directory));
-    q->selectFile(initialSelection(directory));
-
-    _q_updateOkButton();
-    q->resize(q->sizeHint());
+
+    const QSize sizeHint = q->sizeHint();
+    if (sizeHint.isValid())
+       q->resize(sizeHint);
 }
 
 /*!
@@ -2304,14 +2943,24 @@
 */
 void QFileDialogPrivate::createWidgets()
 {
+    if (qFileDialogUi)
+        return;
     Q_Q(QFileDialog);
+
+    // This function is sometimes called late (e.g as a fallback from setVisible). In that case we
+    // need to ensure that the following UI code (setupUI in particular) doesn't reset any explicitly
+    // set window state or geometry.
+    QSize preSize = q->testAttribute(Qt::WA_Resized) ? q->size() : QSize();
+    Qt::WindowStates preState = q->windowState();
+
     model = new QFileSystemModel(q);
-    model->setObjectName(QLatin1String("qt_filesystem_model"));
-#ifdef Q_WS_MAC
-    model->setNameFilterDisables(true);
-#else
-    model->setNameFilterDisables(false);
-#endif
+    model->setIconProvider(&defaultIconProvider);
+    model->setFilter(options->filter());
+    model->setObjectName("qt_filesystem_model"_L1);
+    if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
+        model->setNameFilterDisables(helper->defaultNameFilterDisables());
+    else
+        model->setNameFilterDisables(false);
     model->d_func()->disableRecursiveSort = true;
     QFileDialog::connect(model, SIGNAL(fileRenamed(QString,QString,QString)), q, SLOT(_q_fileRenamed(QString,QString,QString)));
     QFileDialog::connect(model, SIGNAL(rootPathChanged(QString)),
@@ -2324,31 +2973,33 @@
     qFileDialogUi->setupUi(q);
 
     QList<QUrl> initialBookmarks;
-    initialBookmarks << QUrl::fromLocalFile(QLatin1String(""))
+    initialBookmarks << QUrl("file:"_L1)
                      << QUrl::fromLocalFile(QDir::homePath());
-    qFileDialogUi->sidebar->init(model, initialBookmarks);
+    qFileDialogUi->sidebar->setModelAndUrls(model, initialBookmarks);
     QFileDialog::connect(qFileDialogUi->sidebar, SIGNAL(goToUrl(QUrl)),
                          q, SLOT(_q_goToUrl(QUrl)));
 
     QObject::connect(qFileDialogUi->buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
     QObject::connect(qFileDialogUi->buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
 
-
-    qFileDialogUi->lookInCombo->init(this);
-    QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(activated(QString)), q, SLOT(_q_goToDirectory(QString)));
+    qFileDialogUi->lookInCombo->setFileDialogPrivate(this);
+    QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(textActivated(QString)), q, SLOT(_q_goToDirectory(QString)));
 
     qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
     qFileDialogUi->lookInCombo->setDuplicatesEnabled(false);
 
     // filename
-    qFileDialogUi->fileNameEdit->init(this);
+    qFileDialogUi->fileNameEdit->setFileDialogPrivate(this);
 #ifndef QT_NO_SHORTCUT
     qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit);
 #endif
-#ifndef QT_NO_FSCOMPLETER
+#if QT_CONFIG(fscompleter)
     completer = new QFSCompleter(model, q);
     qFileDialogUi->fileNameEdit->setCompleter(completer);
-#endif // QT_NO_FSCOMPLETER
+#endif // QT_CONFIG(fscompleter)
+
+    qFileDialogUi->fileNameEdit->setInputMethodHints(Qt::ImhNoPredictiveText);
+
     QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
             q, SLOT(_q_autoCompleteFileName(QString)));
     QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
@@ -2358,42 +3009,41 @@
 
     // filetype
     qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(false);
-    qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
+    qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
     qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
     QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(int)),
                      q, SLOT(_q_useNameFilter(int)));
-    QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(QString)),
+    QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(textActivated(QString)),
                      q, SIGNAL(filterSelected(QString)));
 
-    qFileDialogUi->listView->init(this);
+    qFileDialogUi->listView->setFileDialogPrivate(this);
     qFileDialogUi->listView->setModel(model);
     QObject::connect(qFileDialogUi->listView, SIGNAL(activated(QModelIndex)),
                      q, SLOT(_q_enterDirectory(QModelIndex)));
     QObject::connect(qFileDialogUi->listView, SIGNAL(customContextMenuRequested(QPoint)),
                     q, SLOT(_q_showContextMenu(QPoint)));
 #ifndef QT_NO_SHORTCUT
-    QShortcut *shortcut = new QShortcut(qFileDialogUi->listView);
-    shortcut->setKey(QKeySequence(QLatin1String("Delete")));
+    QShortcut *shortcut = new QShortcut(QKeySequence::Delete, qFileDialogUi->listView);
     QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
 #endif
 
-    qFileDialogUi->treeView->init(this);
+    qFileDialogUi->treeView->setFileDialogPrivate(this);
     qFileDialogUi->treeView->setModel(model);
     QHeaderView *treeHeader = qFileDialogUi->treeView->header();
     QFontMetrics fm(q->font());
-    treeHeader->resizeSection(0, fm.width(QLatin1String("wwwwwwwwwwwwwwwwwwwwwwwwww")));
-    treeHeader->resizeSection(1, fm.width(QLatin1String("128.88 GB")));
-    treeHeader->resizeSection(2, fm.width(QLatin1String("mp3Folder")));
-    treeHeader->resizeSection(3, fm.width(QLatin1String("10/29/81 02:02PM")));
+    treeHeader->resizeSection(0, fm.horizontalAdvance("wwwwwwwwwwwwwwwwwwwwwwwwww"_L1));
+    treeHeader->resizeSection(1, fm.horizontalAdvance("128.88 GB"_L1));
+    treeHeader->resizeSection(2, fm.horizontalAdvance("mp3Folder"_L1));
+    treeHeader->resizeSection(3, fm.horizontalAdvance("10/29/81 02:02PM"_L1));
     treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu);
 
     QActionGroup *showActionGroup = new QActionGroup(q);
     showActionGroup->setExclusive(false);
     QObject::connect(showActionGroup, SIGNAL(triggered(QAction*)),
-                     q, SLOT(_q_showHeader(QAction*)));
+                     q, SLOT(_q_showHeader(QAction*)));;
 
     QAbstractItemModel *abstractModel = model;
-#ifndef QT_NO_PROXYMODEL
+#if QT_CONFIG(proxymodel)
     if (proxyModel)
         abstractModel = proxyModel;
 #endif
@@ -2412,8 +3062,7 @@
     QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)),
                      q, SLOT(_q_showContextMenu(QPoint)));
 #ifndef QT_NO_SHORTCUT
-    shortcut = new QShortcut(qFileDialogUi->treeView);
-    shortcut->setKey(QKeySequence(QLatin1String("Delete")));
+    shortcut = new QShortcut(QKeySequence::Delete, qFileDialogUi->treeView);
     QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
 #endif
 
@@ -2426,16 +3075,56 @@
     qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
 
     createToolButtons();
+    createMenuActions();
+
+#if QT_CONFIG(settings)
+    // Try to restore from the FileDialog settings group; if it fails, fall back
+    // to the pre-5.5 QByteArray serialized settings.
+    if (!restoreFromSettings()) {
+        const QSettings settings(QSettings::UserScope, u"QtProject"_s);
+        q->restoreState(settings.value("Qt/filedialog").toByteArray());
+    }
+#endif
+
+    // Initial widget states from options
+    q->setFileMode(static_cast<QFileDialog::FileMode>(options->fileMode()));
+    q->setAcceptMode(static_cast<QFileDialog::AcceptMode>(options->acceptMode()));
+    q->setViewMode(static_cast<QFileDialog::ViewMode>(options->viewMode()));
+    q->setOptions(static_cast<QFileDialog::Options>(static_cast<int>(options->options())));
+    if (!options->sidebarUrls().isEmpty())
+        q->setSidebarUrls(options->sidebarUrls());
+    q->setDirectoryUrl(options->initialDirectory());
+#if QT_CONFIG(mimetype)
+    if (!options->mimeTypeFilters().isEmpty())
+        q->setMimeTypeFilters(options->mimeTypeFilters());
+    else
+#endif
+    if (!options->nameFilters().isEmpty())
+        q->setNameFilters(options->nameFilters());
+    q->selectNameFilter(options->initiallySelectedNameFilter());
+    q->setDefaultSuffix(options->defaultSuffix());
+    q->setHistory(options->history());
+    const auto initiallySelectedFiles = options->initiallySelectedFiles();
+    if (initiallySelectedFiles.size() == 1)
+        q->selectFile(initiallySelectedFiles.first().fileName());
+    for (const QUrl &url : initiallySelectedFiles)
+        q->selectUrl(url);
+    lineEdit()->selectAll();
+    _q_updateOkButton();
+    retranslateStrings();
+    q->resize(preSize.isValid() ? preSize : q->sizeHint());
+    q->setWindowState(preState);
 }
 
 void QFileDialogPrivate::_q_showHeader(QAction *action)
 {
     Q_Q(QFileDialog);
     QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
-    qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked());
+    qFileDialogUi->treeView->header()->setSectionHidden(int(actionGroup->actions().indexOf(action) + 1),
+                                                        !action->isChecked());
 }
 
-#ifndef QT_NO_PROXYMODEL
+#if QT_CONFIG(proxymodel)
 /*!
     \since 4.3
 
@@ -2451,6 +3140,8 @@
 void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
 {
     Q_D(QFileDialog);
+    if (!d->usingWidgets())
+        return;
     if ((!proxyModel && !d->proxyModel)
         || (proxyModel == d->proxyModel))
         return;
@@ -2464,26 +3155,26 @@
             this, SLOT(_q_rowsInserted(QModelIndex)));
     }
 
-    if (proxyModel != 0) {
+    if (proxyModel != nullptr) {
         proxyModel->setParent(this);
         d->proxyModel = proxyModel;
         proxyModel->setSourceModel(d->model);
         d->qFileDialogUi->listView->setModel(d->proxyModel);
         d->qFileDialogUi->treeView->setModel(d->proxyModel);
-#ifndef QT_NO_FSCOMPLETER
+#if QT_CONFIG(fscompleter)
         d->completer->setModel(d->proxyModel);
         d->completer->proxyModel = d->proxyModel;
 #endif
         connect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
             this, SLOT(_q_rowsInserted(QModelIndex)));
     } else {
-        d->proxyModel = 0;
+        d->proxyModel = nullptr;
         d->qFileDialogUi->listView->setModel(d->model);
         d->qFileDialogUi->treeView->setModel(d->model);
-#ifndef QT_NO_FSCOMPLETER
+#if QT_CONFIG(fscompleter)
         d->completer->setModel(d->model);
         d->completer->sourceModel = d->model;
-        d->completer->proxyModel = 0;
+        d->completer->proxyModel = nullptr;
 #endif
         connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
             this, SLOT(_q_rowsInserted(QModelIndex)));
@@ -2511,7 +3202,7 @@
     Q_D(const QFileDialog);
     return d->proxyModel;
 }
-#endif // QT_NO_PROXYMODEL
+#endif // QT_CONFIG(proxymodel)
 
 /*!
     \internal
@@ -2521,27 +3212,27 @@
 void QFileDialogPrivate::createToolButtons()
 {
     Q_Q(QFileDialog);
-    qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, 0, q));
+    qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, nullptr, q));
     qFileDialogUi->backButton->setAutoRaise(true);
     qFileDialogUi->backButton->setEnabled(false);
     QObject::connect(qFileDialogUi->backButton, SIGNAL(clicked()), q, SLOT(_q_navigateBackward()));
 
-    qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, 0, q));
+    qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, nullptr, q));
     qFileDialogUi->forwardButton->setAutoRaise(true);
     qFileDialogUi->forwardButton->setEnabled(false);
     QObject::connect(qFileDialogUi->forwardButton, SIGNAL(clicked()), q, SLOT(_q_navigateForward()));
 
-    qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, 0, q));
+    qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, nullptr, q));
     qFileDialogUi->toParentButton->setAutoRaise(true);
     qFileDialogUi->toParentButton->setEnabled(false);
     QObject::connect(qFileDialogUi->toParentButton, SIGNAL(clicked()), q, SLOT(_q_navigateToParent()));
 
-    qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, 0, q));
+    qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, nullptr, q));
     qFileDialogUi->listModeButton->setAutoRaise(true);
     qFileDialogUi->listModeButton->setDown(true);
     QObject::connect(qFileDialogUi->listModeButton, SIGNAL(clicked()), q, SLOT(_q_showListView()));
 
-    qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, 0, q));
+    qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, nullptr, q));
     qFileDialogUi->detailModeButton->setAutoRaise(true);
     QObject::connect(qFileDialogUi->detailModeButton, SIGNAL(clicked()), q, SLOT(_q_showDetailsView()));
 
@@ -2552,7 +3243,7 @@
     qFileDialogUi->forwardButton->setFixedSize(toolSize);
     qFileDialogUi->toParentButton->setFixedSize(toolSize);
 
-    qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder, 0, q));
+    qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder, nullptr, q));
     qFileDialogUi->newFolderButton->setFixedSize(toolSize);
     qFileDialogUi->newFolderButton->setAutoRaise(true);
     qFileDialogUi->newFolderButton->setEnabled(false);
@@ -2570,7 +3261,7 @@
 
     QAction *goHomeAction =  new QAction(q);
 #ifndef QT_NO_SHORTCUT
-    goHomeAction->setShortcut(Qt::CTRL + Qt::Key_H + Qt::SHIFT);
+    goHomeAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_H);
 #endif
     QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome()));
     q->addAction(goHomeAction);
@@ -2578,30 +3269,30 @@
     // ### TODO add Desktop & Computer actions
 
     QAction *goToParent =  new QAction(q);
-    goToParent->setObjectName(QLatin1String("qt_goto_parent_action"));
+    goToParent->setObjectName("qt_goto_parent_action"_L1);
 #ifndef QT_NO_SHORTCUT
-    goToParent->setShortcut(Qt::CTRL + Qt::UpArrow);
+    goToParent->setShortcut(Qt::CTRL | Qt::Key_Up);
 #endif
     QObject::connect(goToParent, SIGNAL(triggered()), q, SLOT(_q_navigateToParent()));
     q->addAction(goToParent);
 
     renameAction = new QAction(q);
     renameAction->setEnabled(false);
-    renameAction->setObjectName(QLatin1String("qt_rename_action"));
+    renameAction->setObjectName("qt_rename_action"_L1);
     QObject::connect(renameAction, SIGNAL(triggered()), q, SLOT(_q_renameCurrent()));
 
     deleteAction = new QAction(q);
     deleteAction->setEnabled(false);
-    deleteAction->setObjectName(QLatin1String("qt_delete_action"));
+    deleteAction->setObjectName("qt_delete_action"_L1);
     QObject::connect(deleteAction, SIGNAL(triggered()), q, SLOT(_q_deleteCurrent()));
 
     showHiddenAction = new QAction(q);
-    showHiddenAction->setObjectName(QLatin1String("qt_show_hidden_action"));
+    showHiddenAction->setObjectName("qt_show_hidden_action"_L1);
     showHiddenAction->setCheckable(true);
     QObject::connect(showHiddenAction, SIGNAL(triggered()), q, SLOT(_q_showHidden()));
 
     newFolderAction = new QAction(q);
-    newFolderAction->setObjectName(QLatin1String("qt_new_folder_action"));
+    newFolderAction->setObjectName("qt_new_folder_action"_L1);
     QObject::connect(newFolderAction, SIGNAL(triggered()), q, SLOT(_q_createDirectory()));
 }
 
@@ -2611,6 +3302,18 @@
     q->setDirectory(QDir::homePath());
 }
 
+
+void QFileDialogPrivate::saveHistorySelection()
+{
+    if (qFileDialogUi.isNull() || currentHistoryLocation < 0 || currentHistoryLocation >= currentHistory.size())
+        return;
+    auto &item = currentHistory[currentHistoryLocation];
+    item.selection.clear();
+    const auto selectedIndexes = qFileDialogUi->listView->selectionModel()->selectedRows();
+    for (const auto &index : selectedIndexes)
+        item.selection.append(QPersistentModelIndex(index));
+}
+
 /*!
     \internal
 
@@ -2619,22 +3322,55 @@
 void QFileDialogPrivate::_q_pathChanged(const QString &newPath)
 {
     Q_Q(QFileDialog);
-    QDir dir(model->rootDirectory());
-    qFileDialogUi->toParentButton->setEnabled(dir.exists());
+    qFileDialogUi->toParentButton->setEnabled(QFileInfo::exists(model->rootPath()));
     qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath));
     q->setHistory(qFileDialogUi->lookInCombo->history());
 
-    if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation) != QDir::toNativeSeparators(newPath)) {
-        while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.count()) {
+    const QString newNativePath = QDir::toNativeSeparators(newPath);
+
+    // equal paths indicate this was invoked by _q_navigateBack/Forward()
+    if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation).path != newNativePath) {
+        if (currentHistoryLocation >= 0)
+            saveHistorySelection();
+        while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.size()) {
             currentHistory.removeLast();
         }
-        currentHistory.append(QDir::toNativeSeparators(newPath));
+        currentHistory.append({newNativePath, PersistentModelIndexList()});
         ++currentHistoryLocation;
     }
     qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1);
     qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0);
 }
 
+void QFileDialogPrivate::navigate(HistoryItem &historyItem)
+{
+    Q_Q(QFileDialog);
+    q->setDirectory(historyItem.path);
+    // Restore selection unless something has changed in the file system
+    if (qFileDialogUi.isNull() || historyItem.selection.isEmpty())
+        return;
+    if (std::any_of(historyItem.selection.cbegin(), historyItem.selection.cend(),
+                    [](const QPersistentModelIndex &i) { return !i.isValid(); })) {
+        historyItem.selection.clear();
+        return;
+    }
+
+    QAbstractItemView *view = q->viewMode() == QFileDialog::List
+        ? static_cast<QAbstractItemView *>(qFileDialogUi->listView)
+        : static_cast<QAbstractItemView *>(qFileDialogUi->treeView);
+    auto selectionModel = view->selectionModel();
+    const QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select
+        | QItemSelectionModel::Rows;
+    selectionModel->select(historyItem.selection.constFirst(),
+                           flags | QItemSelectionModel::Clear | QItemSelectionModel::Current);
+    auto it = historyItem.selection.cbegin() + 1;
+    const auto end = historyItem.selection.cend();
+    for (; it != end; ++it)
+        selectionModel->select(*it, flags);
+
+    view->scrollTo(historyItem.selection.constFirst());
+}
+
 /*!
     \internal
 
@@ -2642,11 +3378,9 @@
 */
 void QFileDialogPrivate::_q_navigateBackward()
 {
-    Q_Q(QFileDialog);
     if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
-        --currentHistoryLocation;
-        QString previousHistory = currentHistory.at(currentHistoryLocation);
-        q->setDirectory(previousHistory);
+        saveHistorySelection();
+        navigate(currentHistory[--currentHistoryLocation]);
     }
 }
 
@@ -2657,11 +3391,9 @@
 */
 void QFileDialogPrivate::_q_navigateForward()
 {
-    Q_Q(QFileDialog);
     if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
-        ++currentHistoryLocation;
-        QString nextHistory = currentHistory.at(currentHistoryLocation);
-        q->setDirectory(nextHistory);
+        saveHistorySelection();
+        navigate(currentHistory[++currentHistoryLocation]);
     }
 }
 
@@ -2745,11 +3477,11 @@
 */
 void QFileDialogPrivate::_q_showContextMenu(const QPoint &position)
 {
-#ifdef QT_NO_MENU
+#if !QT_CONFIG(menu)
     Q_UNUSED(position);
 #else
     Q_Q(QFileDialog);
-    QAbstractItemView *view = 0;
+    QAbstractItemView *view = nullptr;
     if (q->viewMode() == QFileDialog::Detail)
         view = qFileDialogUi->treeView;
     else
@@ -2757,23 +3489,27 @@
     QModelIndex index = view->indexAt(position);
     index = mapToSource(index.sibling(index.row(), 0));
 
-    QMenu menu(view);
+    QMenu *menu = new QMenu(view);
+    menu->setAttribute(Qt::WA_DeleteOnClose);
+
     if (index.isValid()) {
         // file context menu
+        const bool ro = model && model->isReadOnly();
         QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
-        renameAction->setEnabled(p & QFile::WriteUser);
-        menu.addAction(renameAction);
-        deleteAction->setEnabled(p & QFile::WriteUser);
-        menu.addAction(deleteAction);
-        menu.addSeparator();
+        renameAction->setEnabled(!ro && p & QFile::WriteUser);
+        menu->addAction(renameAction);
+        deleteAction->setEnabled(!ro && p & QFile::WriteUser);
+        menu->addAction(deleteAction);
+        menu->addSeparator();
     }
-    menu.addAction(showHiddenAction);
+    menu->addAction(showHiddenAction);
     if (qFileDialogUi->newFolderButton->isVisible()) {
         newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled());
-        menu.addAction(newFolderAction);
+        menu->addAction(newFolderAction);
     }
-    menu.exec(view->viewport()->mapToGlobal(position));
-#endif // QT_NO_MENU
+    menu->popup(view->viewport()->mapToGlobal(position));
+
+#endif // QT_CONFIG(menu)
 }
 
 /*!
@@ -2806,9 +3542,9 @@
     if (model->isReadOnly())
         return;
 
-    QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
-    for (int i = list.count() - 1; i >= 0; --i) {
-        QModelIndex index = list.at(i);
+    const QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
+    for (auto it = list.crbegin(), end = list.crend(); it != end; ++it) {
+        QPersistentModelIndex index = *it;
         if (index == qFileDialogUi->listView->rootIndex())
             continue;
 
@@ -2816,33 +3552,35 @@
         if (!index.isValid())
             continue;
 
-    QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
-    QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
-    bool isDir = model->isDir(index);
-
-    QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
-#ifndef QT_NO_MESSAGEBOX
-    Q_Q(QFileDialog);
-    if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), q_func()->windowTitle(),
-                                QFileDialog::tr("'%1' is write protected.\nDo you want to delete it anyway?")
-                                .arg(fileName),
-                                 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
-        return;
-    else if (QMessageBox::warning(q_func(), q_func()->windowTitle(),
-                                  QFileDialog::tr("Are sure you want to delete '%1'?")
-                                  .arg(fileName),
-                                  QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
-        return;
+        QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
+        QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
+
+        QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
+#if QT_CONFIG(messagebox)
+        Q_Q(QFileDialog);
+        if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), QFileDialog::tr("Delete"),
+                                    QFileDialog::tr("'%1' is write protected.\nDo you want to delete it anyway?")
+                                    .arg(fileName),
+                                     QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
+            return;
+        else if (QMessageBox::warning(q_func(), QFileDialog::tr("Delete"),
+                                      QFileDialog::tr("Are you sure you want to delete '%1'?")
+                                      .arg(fileName),
+                                      QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
+            return;
+
+        // the event loop has run, we have to validate if the index is valid because the model might have removed it.
+        if (!index.isValid())
+            return;
 
 #else
-    if (!(p & QFile::WriteUser))
-        return;
-#endif // QT_NO_MESSAGEBOX
-
-        // the event loop has run, we can NOT reuse index because the model might have removed it.
-        if (isDir) {
+        if (!(p & QFile::WriteUser))
+            return;
+#endif // QT_CONFIG(messagebox)
+
+        if (model->isDir(index) && !model->fileInfo(index).isSymLink()) {
             if (!removeDirectory(filePath)) {
-#ifndef QT_NO_MESSAGEBOX
+#if QT_CONFIG(messagebox)
             QMessageBox::warning(q, q->windowTitle(),
                                 QFileDialog::tr("Could not delete directory."));
 #endif
@@ -2855,28 +3593,27 @@
 
 void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text)
 {
-    if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1Char('\\'))) {
+    if (text.startsWith("//"_L1) || text.startsWith(u'\\')) {
         qFileDialogUi->listView->selectionModel()->clearSelection();
         return;
     }
 
-    QStringList multipleFiles = typedFiles();
-    if (multipleFiles.count() > 0) {
+    const QStringList multipleFiles = typedFiles();
+    if (multipleFiles.size() > 0) {
         QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows();
-        QModelIndexList newFiles;
-        for (int i = 0; i < multipleFiles.count(); ++i) {
-            QModelIndex idx = model->index(multipleFiles.at(i));
-            if (oldFiles.contains(idx))
-                oldFiles.removeAll(idx);
-            else
+        QList<QModelIndex> newFiles;
+        for (const auto &file : multipleFiles) {
+            QModelIndex idx = model->index(file);
+            if (oldFiles.removeAll(idx) == 0)
                 newFiles.append(idx);
         }
-        for (int i = 0; i < newFiles.count(); ++i)
-            select(newFiles.at(i));
-        if (lineEdit()->hasFocus())
-            for (int i = 0; i < oldFiles.count(); ++i)
-                qFileDialogUi->listView->selectionModel()->select(oldFiles.at(i),
-                    QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
+        for (const auto &newFile : std::as_const(newFiles))
+            select(newFile);
+        if (lineEdit()->hasFocus()) {
+            auto *sm = qFileDialogUi->listView->selectionModel();
+            for (const auto &oldFile : std::as_const(oldFiles))
+                sm->select(oldFile, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
+        }
     }
 }
 
@@ -2886,31 +3623,30 @@
 void QFileDialogPrivate::_q_updateOkButton()
 {
     Q_Q(QFileDialog);
-    QPushButton *button =  qFileDialogUi->buttonBox->button((acceptMode == QFileDialog::AcceptOpen)
+    QPushButton *button =  qFileDialogUi->buttonBox->button((q->acceptMode() == QFileDialog::AcceptOpen)
                     ? QDialogButtonBox::Open : QDialogButtonBox::Save);
     if (!button)
         return;
+    const QFileDialog::FileMode fileMode = q->fileMode();
 
     bool enableButton = true;
     bool isOpenDirectory = false;
 
-    QStringList files = q->selectedFiles();
+    const QStringList files = q->selectedFiles();
     QString lineEditText = lineEdit()->text();
 
-    if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1Char('\\'))) {
+    if (lineEditText.startsWith("//"_L1) || lineEditText.startsWith(u'\\')) {
         button->setEnabled(true);
-        if (acceptMode == QFileDialog::AcceptSave)
-            button->setText(acceptLabel);
+        updateOkButtonText();
         return;
     }
 
     if (files.isEmpty()) {
         enableButton = false;
-    } else if (lineEditText == QLatin1String("..")) {
+    } else if (lineEditText == ".."_L1) {
         isOpenDirectory = true;
     } else {
         switch (fileMode) {
-        case QFileDialog::DirectoryOnly:
         case QFileDialog::Directory: {
             QString fn = files.first();
             QModelIndex idx = model->index(fn);
@@ -2929,10 +3665,10 @@
             if (info.isDir()) {
                 fileDir = info.canonicalFilePath();
             } else {
-                fileDir = fn.mid(0, fn.lastIndexOf(QLatin1Char('/')));
-                fileName = fn.mid(fileDir.length() + 1);
+                fileDir = fn.mid(0, fn.lastIndexOf(u'/'));
+                fileName = fn.mid(fileDir.size() + 1);
             }
-            if (lineEditText.contains(QLatin1String(".."))) {
+            if (lineEditText.contains(".."_L1)) {
                 fileDir = info.canonicalFilePath();
                 fileName = info.fileName();
             }
@@ -2947,17 +3683,17 @@
                 break;
             }
             if (!idx.isValid()) {
-                int maxLength = maxNameLength(fileDir);
-                enableButton = maxLength < 0 || fileName.length() <= maxLength;
+                const long maxLength = maxNameLength(fileDir);
+                enableButton = maxLength < 0 || fileName.size() <= maxLength;
             }
             break;
         }
         case QFileDialog::ExistingFile:
         case QFileDialog::ExistingFiles:
-            for (int i = 0; i < files.count(); ++i) {
-                QModelIndex idx = model->index(files.at(i));
+            for (const auto &file : files) {
+                QModelIndex idx = model->index(file);
                 if (!idx.isValid())
-                    idx = model->index(getEnvironmentVariable(files.at(i)));
+                    idx = model->index(getEnvironmentVariable(file));
                 if (!idx.isValid()) {
                     enableButton = false;
                     break;
@@ -2974,8 +3710,7 @@
     }
 
     button->setEnabled(enableButton);
-    if (acceptMode == QFileDialog::AcceptSave)
-        button->setText(isOpenDirectory ? QFileDialog::tr("&Open") : acceptLabel);
+    updateOkButtonText(isOpenDirectory);
 }
 
 /*!
@@ -3000,18 +3735,18 @@
     QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
     QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
     if (path.isEmpty() || model->isDir(sourceIndex)) {
+        const QFileDialog::FileMode fileMode = q->fileMode();
         q->setDirectory(path);
         emit q->directoryEntered(path);
-        if (fileMode == QFileDialog::Directory
-                || fileMode == QFileDialog::DirectoryOnly) {
+        if (fileMode == QFileDialog::Directory) {
             // ### find out why you have to do both of these.
             lineEdit()->setText(QString());
             lineEdit()->clear();
         }
     } else {
         // Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE)
-        if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick)
-            || q->fileMode() != QFileDialog::ExistingFiles || !(QApplication::keyboardModifiers() & Qt::CTRL)) {
+        if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, qFileDialogUi->treeView)
+            || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL)) {
             q->accept();
         }
     }
@@ -3025,7 +3760,9 @@
 */
 void QFileDialogPrivate::_q_goToDirectory(const QString &path)
 {
- #ifndef QT_NO_MESSAGEBOX
+    enum { UrlRole = Qt::UserRole + 1 };
+
+ #if QT_CONFIG(messagebox)
     Q_Q(QFileDialog);
 #endif
     QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(),
@@ -3040,30 +3777,19 @@
     }
     QDir dir(path2);
     if (!dir.exists())
-        dir = getEnvironmentVariable(path2);
+        dir.setPath(getEnvironmentVariable(path2));
 
     if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
         _q_enterDirectory(index);
-#ifndef QT_NO_MESSAGEBOX
+#if QT_CONFIG(messagebox)
     } else {
         QString message = QFileDialog::tr("%1\nDirectory not found.\nPlease verify the "
                                           "correct directory name was given.");
         QMessageBox::warning(q, q->windowTitle(), message.arg(path2));
-#endif // QT_NO_MESSAGEBOX
+#endif // QT_CONFIG(messagebox)
     }
 }
 
-// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
-QStringList qt_clean_filter_list(const QString &filter)
-{
-    QRegExp regexp(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
-    QString f = filter;
-    int i = regexp.indexIn(f);
-    if (i >= 0)
-        f = regexp.cap(2);
-    return f.split(QLatin1Char(' '), QString::SkipEmptyParts);
-}
-
 /*!
     \internal
 
@@ -3072,23 +3798,25 @@
 */
 void QFileDialogPrivate::_q_useNameFilter(int index)
 {
+    QStringList nameFilters = options->nameFilters();
     if (index == nameFilters.size()) {
         QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model();
         nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString());
+        options->setNameFilters(nameFilters);
     }
 
     QString nameFilter = nameFilters.at(index);
-    QStringList newNameFilters = qt_clean_filter_list(nameFilter);
-    if (acceptMode == QFileDialog::AcceptSave) {
+    QStringList newNameFilters = QPlatformFileDialogHelper::cleanFilterList(nameFilter);
+    if (q_func()->acceptMode() == QFileDialog::AcceptSave) {
         QString newNameFilterExtension;
-        if (newNameFilters.count() > 0)
+        if (newNameFilters.size() > 0)
             newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix();
 
         QString fileName = lineEdit()->text();
         const QString fileNameExtension = QFileInfo(fileName).suffix();
         if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
-            const int fileNameExtensionLength = fileNameExtension.count();
-            fileName.replace(fileName.count() - fileNameExtensionLength,
+            const qsizetype fileNameExtensionLength = fileNameExtension.size();
+            fileName.replace(fileName.size() - fileNameExtensionLength,
                              fileNameExtensionLength, newNameFilterExtension);
             qFileDialogUi->listView->clearSelection();
             lineEdit()->setText(fileName);
@@ -3106,21 +3834,22 @@
 */
 void QFileDialogPrivate::_q_selectionChanged()
 {
-    QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
-    bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory);
+    const QFileDialog::FileMode fileMode = q_func()->fileMode();
+    const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
+    bool stripDirs = fileMode != QFileDialog::Directory;
 
     QStringList allFiles;
-    for (int i = 0; i < indexes.count(); ++i) {
-        if (stripDirs && model->isDir(mapToSource(indexes.at(i))))
+    for (const auto &index : indexes) {
+        if (stripDirs && model->isDir(mapToSource(index)))
             continue;
-        allFiles.append(indexes.at(i).data().toString());
+        allFiles.append(index.data().toString());
     }
-    if (allFiles.count() > 1)
-        for (int i = 0; i < allFiles.count(); ++i) {
-            allFiles.replace(i, QString(QLatin1Char('"') + allFiles.at(i) + QLatin1Char('"')));
+    if (allFiles.size() > 1)
+        for (qsizetype i = 0; i < allFiles.size(); ++i) {
+            allFiles.replace(i, QString(u'"' + allFiles.at(i) + u'"'));
     }
 
-    QString finalFiles = allFiles.join(QLatin1String(" "));
+    QString finalFiles = allFiles.join(u' ');
     if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
         lineEdit()->setText(finalFiles);
     else
@@ -3136,10 +3865,7 @@
 {
     Q_Q(QFileDialog);
     QDir::Filters dirFilters = q->filter();
-    if (showHiddenAction->isChecked())
-        dirFilters |= QDir::Hidden;
-    else
-        dirFilters &= ~QDir::Hidden;
+    dirFilters.setFlag(QDir::Hidden, showHiddenAction->isChecked());
     q->setFilter(dirFilters);
 }
 
@@ -3159,31 +3885,77 @@
         return;
 }
 
-void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString oldName, const QString newName)
+void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString &oldName, const QString &newName)
 {
-    if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) {
+    const QFileDialog::FileMode fileMode = q_func()->fileMode();
+    if (fileMode == QFileDialog::Directory) {
         if (path == rootPath() && lineEdit()->text() == oldName)
             lineEdit()->setText(newName);
     }
 }
 
+void QFileDialogPrivate::_q_emitUrlSelected(const QUrl &file)
+{
+    Q_Q(QFileDialog);
+    emit q->urlSelected(file);
+    if (file.isLocalFile())
+        emit q->fileSelected(file.toLocalFile());
+}
+
+void QFileDialogPrivate::_q_emitUrlsSelected(const QList<QUrl> &files)
+{
+    Q_Q(QFileDialog);
+    emit q->urlsSelected(files);
+    QStringList localFiles;
+    for (const QUrl &file : files)
+        if (file.isLocalFile())
+            localFiles.append(file.toLocalFile());
+    if (!localFiles.isEmpty())
+        emit q->filesSelected(localFiles);
+}
+
+void QFileDialogPrivate::_q_nativeCurrentChanged(const QUrl &file)
+{
+    Q_Q(QFileDialog);
+    emit q->currentUrlChanged(file);
+    if (file.isLocalFile())
+        emit q->currentChanged(file.toLocalFile());
+}
+
+void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory)
+{
+    Q_Q(QFileDialog);
+    emit q->directoryUrlEntered(directory);
+    if (!directory.isEmpty()) { // Windows native dialogs occasionally emit signals with empty strings.
+        *lastVisitedDir() = directory;
+        if (directory.isLocalFile())
+            emit q->directoryEntered(directory.toLocalFile());
+    }
+}
+
 /*!
     \internal
 
     For the list and tree view watch keys to goto parent and back in the history
 
-    returns true if handled
+    returns \c true if handled
 */
 bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
 
+#if QT_CONFIG(shortcut)
     Q_Q(QFileDialog);
+    if (event->matches(QKeySequence::Cancel)) {
+        q->reject();
+        return true;
+    }
+#endif
     switch (event->key()) {
     case Qt::Key_Backspace:
         _q_navigateToParent();
         return true;
     case Qt::Key_Back:
 #ifdef QT_KEYPAD_NAVIGATION
-        if (QApplication::keypadNavigationEnabled())
+        if (QApplicationPrivate::keypadNavigationEnabled())
             return false;
 #endif
     case Qt::Key_Left:
@@ -3192,9 +3964,6 @@
             return true;
         }
         break;
-    case Qt::Key_Escape:
-        q->hide();
-        return true;
     default:
         break;
     }
@@ -3204,18 +3973,18 @@
 QString QFileDialogPrivate::getEnvironmentVariable(const QString &string)
 {
 #ifdef Q_OS_UNIX
-    if (string.size() > 1 && string.startsWith(QLatin1Char('$'))) {
-        return QString::fromLocal8Bit(getenv(string.mid(1).toLatin1().constData()));
+    if (string.size() > 1 && string.startsWith(u'$')) {
+        return QString::fromLocal8Bit(qgetenv(QStringView{string}.mid(1).toLatin1().constData()));
     }
 #else
-    if (string.size() > 2 && string.startsWith(QLatin1Char('%')) && string.endsWith(QLatin1Char('%'))) {
-        return QString::fromLocal8Bit(qgetenv(string.mid(1, string.size() - 2).toLatin1().constData()));
+    if (string.size() > 2 && string.startsWith(u'%') && string.endsWith(u'%')) {
+        return QString::fromLocal8Bit(qgetenv(QStringView{string}.mid(1, string.size() - 2).toLatin1().constData()));
     }
 #endif
     return string;
 }
 
-void QFileDialogComboBox::init(QFileDialogPrivate *d_pointer) {
+void QFileDialogComboBox::setFileDialogPrivate(QFileDialogPrivate *d_pointer) {
     d_ptr = d_pointer;
     urlModel = new QUrlModel(this);
     urlModel->showFullPath = true;
@@ -3238,18 +4007,18 @@
         idx = idx.parent();
     }
     // add "my computer"
-    list.append(QUrl::fromLocalFile(QLatin1String("")));
+    list.append(QUrl("file:"_L1));
     urlModel->addUrls(list, 0);
     idx = model()->index(model()->rowCount() - 1, 0);
 
     // append history
     QList<QUrl> urls;
-    for (int i = 0; i < m_history.count(); ++i) {
+    for (int i = 0; i < m_history.size(); ++i) {
         QUrl path = QUrl::fromLocalFile(m_history.at(i));
         if (!urls.contains(path))
             urls.prepend(path);
     }
-    if (urls.count() > 0) {
+    if (urls.size() > 0) {
         model()->insertRow(model()->rowCount());
         idx = model()->index(model()->rowCount()-1, 0);
         // ### TODO maybe add a horizontal line before this
@@ -3287,11 +4056,7 @@
     painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
 }
 
-QFileDialogListView::QFileDialogListView(QWidget *parent) : QListView(parent)
-{
-}
-
-void QFileDialogListView::init(QFileDialogPrivate *d_pointer)
+void QFileDialogListView::setFileDialogPrivate(QFileDialogPrivate *d_pointer)
 {
     d_ptr = d_pointer;
     setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -3299,7 +4064,7 @@
     setResizeMode(QListView::Adjust);
     setEditTriggers(QAbstractItemView::EditKeyPressed);
     setContextMenuPolicy(Qt::CustomContextMenu);
-#ifndef QT_NO_DRAGANDDROP
+#if QT_CONFIG(draganddrop)
     setDragDropMode(QAbstractItemView::InternalMove);
 #endif
 }
@@ -3324,11 +4089,7 @@
     e->accept();
 }
 
-QFileDialogTreeView::QFileDialogTreeView(QWidget *parent) : QTreeView(parent)
-{
-}
-
-void QFileDialogTreeView::init(QFileDialogPrivate *d_pointer)
+void QFileDialogTreeView::setFileDialogPrivate(QFileDialogPrivate *d_pointer)
 {
     d_ptr = d_pointer;
     setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -3340,7 +4101,7 @@
     setTextElideMode(Qt::ElideMiddle);
     setEditTriggers(QAbstractItemView::EditKeyPressed);
     setContextMenuPolicy(Qt::CustomContextMenu);
-#ifndef QT_NO_DRAGANDDROP
+#if QT_CONFIG(draganddrop)
     setDragDropMode(QAbstractItemView::InternalMove);
 #endif
 }
@@ -3379,18 +4140,17 @@
     }
 #endif // QT_KEYPAD_NAVIGATION
 
+#if QT_CONFIG(shortcut)
     int key = e->key();
+#endif
     QLineEdit::keyPressEvent(e);
-    if (key != Qt::Key_Escape)
-        e->accept();
-    if (hideOnEsc && (key == Qt::Key_Escape || key == Qt::Key_Return || key == Qt::Key_Enter)) {
+#if QT_CONFIG(shortcut)
+    if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back)
+#endif
         e->accept();
-        hide();
-        d_ptr->currentView()->setFocus(Qt::ShortcutFocusReason);
-    }
 }
 
-#ifndef QT_NO_FSCOMPLETER
+#if QT_CONFIG(fscompleter)
 
 QString QFSCompleter::pathFromIndex(const QModelIndex &index) const
 {
@@ -3402,14 +4162,14 @@
     QString currentLocation = dirModel->rootPath();
     QString path = index.data(QFileSystemModel::FilePathRole).toString();
     if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) {
-#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
+#if defined(Q_OS_UNIX)
         if (currentLocation == QDir::separator())
-            return path.mid(currentLocation.length());
+            return path.remove(0, currentLocation.size());
 #endif
-        if (currentLocation.endsWith(QLatin1Char('/')))
-            return path.mid(currentLocation.length());
+        if (currentLocation.endsWith(u'/'))
+            return path.remove(0, currentLocation.size());
         else
-            return path.mid(currentLocation.length()+1);
+            return path.remove(0, currentLocation.size()+1);
     }
     return index.data(QFileSystemModel::FilePathRole).toString();
 }
@@ -3420,74 +4180,65 @@
         return QStringList(completionPrefix());
 
     QString pathCopy = QDir::toNativeSeparators(path);
-    QString sep = QDir::separator();
-#if defined(Q_OS_SYMBIAN)
-    if (pathCopy == QLatin1String("\\"))
+    QChar sep = QDir::separator();
+#if defined(Q_OS_WIN)
+    if (pathCopy == "\\"_L1 || pathCopy == "\\\\"_L1)
         return QStringList(pathCopy);
-#elif defined(Q_OS_WIN)
-    if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\"))
-        return QStringList(pathCopy);
-    QString doubleSlash(QLatin1String("\\\\"));
+    QString doubleSlash("\\\\"_L1);
     if (pathCopy.startsWith(doubleSlash))
         pathCopy = pathCopy.mid(2);
     else
         doubleSlash.clear();
 #elif defined(Q_OS_UNIX)
-    bool expanded;
-    pathCopy = qt_tildeExpansion(pathCopy, &expanded);
-    if (expanded) {
-        QFileSystemModel *dirModel;
-        if (proxyModel)
-            dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
-        else
-            dirModel = sourceModel;
-        dirModel->fetchMore(dirModel->index(pathCopy));
+    {
+        QString tildeExpanded = qt_tildeExpansion(pathCopy);
+        if (tildeExpanded != pathCopy) {
+            QFileSystemModel *dirModel;
+            if (proxyModel)
+                dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
+            else
+                dirModel = sourceModel;
+            dirModel->fetchMore(dirModel->index(tildeExpanded));
+        }
+        pathCopy = std::move(tildeExpanded);
     }
 #endif
 
-    QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']'));
-
-#if defined(Q_OS_SYMBIAN)
-    QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
-    if (pathCopy.endsWith(sep))
-        parts.append(QString());
-#elif defined(Q_OS_WIN)
-    QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
+#if defined(Q_OS_WIN)
+    QStringList parts = pathCopy.split(sep, Qt::SkipEmptyParts);
     if (!doubleSlash.isEmpty() && !parts.isEmpty())
         parts[0].prepend(doubleSlash);
     if (pathCopy.endsWith(sep))
         parts.append(QString());
 #else
-    QStringList parts = pathCopy.split(re);
-    if (pathCopy[0] == sep[0]) // read the "/" at the beginning as the split removed it
-        parts[0] = sep[0];
+    QStringList parts = pathCopy.split(sep);
+    if (pathCopy[0] == sep) // read the "/" at the beginning as the split removed it
+        parts[0] = sep;
 #endif
 
-#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
-    bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':'));
+#if defined(Q_OS_WIN)
+    bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(u':');
 #else
-    bool startsFromRoot = pathCopy[0] == sep[0];
+    bool startsFromRoot = pathCopy[0] == sep;
 #endif
-    if (parts.count() == 1 || (parts.count() > 1 && !startsFromRoot)) {
+    if (parts.size() == 1 || (parts.size() > 1 && !startsFromRoot)) {
         const QFileSystemModel *dirModel;
         if (proxyModel)
             dirModel = qobject_cast<const QFileSystemModel *>(proxyModel->sourceModel());
         else
             dirModel = sourceModel;
         QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath());
-#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
-        if (currentLocation.endsWith(QLatin1Char(':')))
+#if defined(Q_OS_WIN)
+        if (currentLocation.endsWith(u':'))
             currentLocation.append(sep);
 #endif
         if (currentLocation.contains(sep) && path != currentLocation) {
             QStringList currentLocationList = splitPath(currentLocation);
-            while (!currentLocationList.isEmpty()
-                   && parts.count() > 0
-                   && parts.at(0) == QLatin1String("..")) {
+            while (!currentLocationList.isEmpty() && parts.size() > 0 && parts.at(0) == ".."_L1) {
                 parts.removeFirst();
                 currentLocationList.removeLast();
             }
-            if (!currentLocationList.isEmpty() && currentLocationList.last().isEmpty())
+            if (!currentLocationList.isEmpty() && currentLocationList.constLast().isEmpty())
                 currentLocationList.removeLast();
             return currentLocationList + parts;
         }
@@ -3495,97 +4246,9 @@
     return parts;
 }
 
-#endif // QT_NO_COMPLETER
-
-#ifdef QT3_SUPPORT
-/*!
-    Use selectedFiles() instead.
-
-    \oldcode
-       QString selected = dialog->selectedFile();
-    \newcode
-        QStringList files = dialog->selectedFiles();
-        QString selected;
-        if (!files.isEmpty())
-            selected = files[0];
-    \endcode
-*/
-QString QFileDialog::selectedFile() const
-{
-    QStringList files = selectedFiles();
-    return files.size() ? files.at(0) : QString();
-}
-
-/*!
-    \typedef QFileDialog::Mode
-
-    Use QFileDialog::FileMode instead.
-*/
-
-/*!
-    \fn void QFileDialog::setMode(FileMode m)
-
-    Use setFileMode() instead.
-*/
-
-/*!
-    \fn FileMode QFileDialog::mode() const
-
-    Use fileMode() instead.
-*/
-
-/*!
-    \fn void QFileDialog::setDir(const QString &directory)
-
-    Use setDirectory() instead.
-*/
-
-/*!
-    \fn void QFileDialog::setDir( const QDir &directory )
-
-    Use setDirectory() instead.
-*/
-
-/*!
-    \fn QStringList QFileDialog::getOpenFileNames(const QString &filter,
-        const QString &dir, QWidget *parent, const char* name,
-        const QString &caption, QString *selectedFilter, bool resolveSymlinks)
-
-    Use the getOpenFileNames() overload that takes \a parent as the first
-    argument instead.
-*/
-
-/*!
-    \fn QString QFileDialog::getOpenFileName(const QString &dir,
-        const QString &filter, QWidget *parent = 0, const char *name,
-        const QString &caption, QString *selectedFilter, bool resolveSymlinks)
-
-    Use the getOpenFileName() overload that takes \a parent as the first
-    argument instead.
-*/
-
-/*!
-    \fn QString QFileDialog::getSaveFileName(const QString &dir,
-        const QString &filter, QWidget *parent, const char *name,
-        const QString &caption, QString *selectedFilter, bool resolveSymlinks)
-
-    Use the getSaveFileName() overload that takes \a parent as the first
-    argument instead.
-*/
-
-/*!
-    \fn QString QFileDialog::getExistingDirectory(const QString &dir,
-        QWidget *parent, const char *name, const QString &caption,
-        bool dirOnly, bool resolveSymlinks)
-
-    Use the getExistingDirectory() overload that takes \a parent as
-    the first argument instead.
-*/
-
-#endif // QT3_SUPPORT
+#endif // QT_CONFIG(completer)
+
 
 QT_END_NAMESPACE
 
 #include "moc_qfiledialog.cpp"
-
-#endif // QT_NO_FILEDIALOG
--- a/libgui/languages/build_ts/octave-qt/qfileinfogatherer.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qfileinfogatherer.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,48 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qfileinfogatherer_p.h"
 #include <qdebug.h>
-#include <qfsfileengine.h>
 #include <qdiriterator.h>
+#include <private/qfileinfo_p.h>
 #ifndef Q_OS_WIN
 #  include <unistd.h>
 #  include <sys/types.h>
@@ -53,42 +15,40 @@
 
 QT_BEGIN_NAMESPACE
 
-#ifndef QT_NO_FILESYSTEMMODEL
+using namespace Qt::StringLiterals;
 
 #ifdef QT_BUILD_INTERNAL
-static bool fetchedRoot = false;
+Q_CONSTINIT static QBasicAtomicInt fetchedRoot = Q_BASIC_ATOMIC_INITIALIZER(false);
 Q_AUTOTEST_EXPORT void qt_test_resetFetchedRoot()
 {
-    fetchedRoot = false;
+    fetchedRoot.storeRelaxed(false);
 }
 
 Q_AUTOTEST_EXPORT bool qt_test_isFetchedRoot()
 {
-    return fetchedRoot;
+    return fetchedRoot.loadRelaxed();
 }
 #endif
 
+static QString translateDriveName(const QFileInfo &drive)
+{
+    QString driveName = drive.absoluteFilePath();
+#ifdef Q_OS_WIN
+    if (driveName.startsWith(u'/')) // UNC host
+        return drive.fileName();
+    if (driveName.endsWith(u'/'))
+        driveName.chop(1);
+#endif // Q_OS_WIN
+    return driveName;
+}
+
 /*!
     Creates thread
 */
 QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
-    : QThread(parent), abort(false),
-#ifndef QT_NO_FILESYSTEMWATCHER
-      watcher(0),
-#endif
-      m_resolveSymlinks(false), m_iconProvider(&defaultProvider)
+    : QThread(parent)
+    , m_iconProvider(&defaultProvider)
 {
-#ifdef Q_OS_WIN
-    m_resolveSymlinks = true;
-#elif !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS)
-    userId = getuid();
-    groupId = getgid();
-#endif
-#ifndef QT_NO_FILESYSTEMWATCHER
-    watcher = new QFileSystemWatcher(this);
-    connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(list(QString)));
-    connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
-#endif
     start(LowPriority);
 }
 
@@ -97,9 +57,9 @@
 */
 QFileInfoGatherer::~QFileInfoGatherer()
 {
+    abort.storeRelaxed(true);
     QMutexLocker locker(&mutex);
-    abort = true;
-    condition.wakeOne();
+    condition.wakeAll();
     locker.unlock();
     wait();
 }
@@ -108,23 +68,39 @@
 {
     Q_UNUSED(enable);
 #ifdef Q_OS_WIN
-    QMutexLocker locker(&mutex);
     m_resolveSymlinks = enable;
 #endif
 }
 
+void QFileInfoGatherer::driveAdded()
+{
+    fetchExtendedInformation(QString(), QStringList());
+}
+
+void QFileInfoGatherer::driveRemoved()
+{
+    QStringList drives;
+    const QFileInfoList driveInfoList = QDir::drives();
+    for (const QFileInfo &fi : driveInfoList)
+        drives.append(translateDriveName(fi));
+    emit newListOfFiles(QString(), drives);
+}
+
 bool QFileInfoGatherer::resolveSymlinks() const
 {
+#ifdef Q_OS_WIN
     return m_resolveSymlinks;
+#else
+    return false;
+#endif
 }
 
-void QFileInfoGatherer::setIconProvider(QFileIconProvider *provider)
+void QFileInfoGatherer::setIconProvider(QAbstractFileIconProvider *provider)
 {
-    QMutexLocker locker(&mutex);
     m_iconProvider = provider;
 }
 
-QFileIconProvider *QFileInfoGatherer::iconProvider() const
+QAbstractFileIconProvider *QFileInfoGatherer::iconProvider() const
 {
     return m_iconProvider;
 }
@@ -137,7 +113,7 @@
 void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStringList &files)
 {
     QMutexLocker locker(&mutex);
-    // See if we already have this dir/file in our que
+    // See if we already have this dir/file in our queue
     int loc = this->path.lastIndexOf(path);
     while (loc > 0)  {
         if (this->files.at(loc) == files) {
@@ -145,9 +121,22 @@
         }
         loc = this->path.lastIndexOf(path, loc - 1);
     }
+#if QT_CONFIG(thread)
     this->path.push(path);
     this->files.push(files);
     condition.wakeAll();
+#else // !QT_CONFIG(thread)
+    getFileInfos(path, files);
+#endif // QT_CONFIG(thread)
+
+#if QT_CONFIG(filesystemwatcher)
+    if (files.isEmpty()
+        && !path.isEmpty()
+        && !path.startsWith("//"_L1) /*don't watch UNC path*/) {
+        if (!watchedDirectories().contains(path))
+            watchPaths(QStringList(path));
+    }
+#endif
 }
 
 /*!
@@ -157,11 +146,96 @@
 */
 void QFileInfoGatherer::updateFile(const QString &filePath)
 {
-    QString dir = filePath.mid(0, filePath.lastIndexOf(QDir::separator()));
-    QString fileName = filePath.mid(dir.length() + 1);
+    QString dir = filePath.mid(0, filePath.lastIndexOf(u'/'));
+    QString fileName = filePath.mid(dir.size() + 1);
     fetchExtendedInformation(dir, QStringList(fileName));
 }
 
+QStringList QFileInfoGatherer::watchedFiles() const
+{
+#if QT_CONFIG(filesystemwatcher)
+    if (m_watcher)
+        return m_watcher->files();
+#endif
+    return {};
+}
+
+QStringList QFileInfoGatherer::watchedDirectories() const
+{
+#if QT_CONFIG(filesystemwatcher)
+    if (m_watcher)
+        return m_watcher->directories();
+#endif
+    return {};
+}
+
+void QFileInfoGatherer::createWatcher()
+{
+#if QT_CONFIG(filesystemwatcher)
+    m_watcher = new QFileSystemWatcher(this);
+    connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &QFileInfoGatherer::list);
+    connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &QFileInfoGatherer::updateFile);
+#  if defined(Q_OS_WIN)
+    const QVariant listener = m_watcher->property("_q_driveListener");
+    if (listener.canConvert<QObject *>()) {
+        if (QObject *driveListener = listener.value<QObject *>()) {
+            connect(driveListener, SIGNAL(driveAdded()), this, SLOT(driveAdded()));
+            connect(driveListener, SIGNAL(driveRemoved()), this, SLOT(driveRemoved()));
+        }
+    }
+#  endif // Q_OS_WIN
+#endif
+}
+
+void QFileInfoGatherer::watchPaths(const QStringList &paths)
+{
+#if QT_CONFIG(filesystemwatcher)
+    if (m_watching) {
+        if (m_watcher == nullptr)
+            createWatcher();
+        m_watcher->addPaths(paths);
+    }
+#else
+    Q_UNUSED(paths);
+#endif
+}
+
+void QFileInfoGatherer::unwatchPaths(const QStringList &paths)
+{
+#if QT_CONFIG(filesystemwatcher)
+    if (m_watcher && !paths.isEmpty())
+        m_watcher->removePaths(paths);
+#else
+    Q_UNUSED(paths);
+#endif
+}
+
+bool QFileInfoGatherer::isWatching() const
+{
+    bool result = false;
+#if QT_CONFIG(filesystemwatcher)
+    QMutexLocker locker(&mutex);
+    result = m_watching;
+#endif
+    return result;
+}
+
+void QFileInfoGatherer::setWatching(bool v)
+{
+#if QT_CONFIG(filesystemwatcher)
+    QMutexLocker locker(&mutex);
+    if (v != m_watching) {
+        if (!v) {
+            delete m_watcher;
+            m_watcher = nullptr;
+        }
+        m_watching = v;
+    }
+#else
+    Q_UNUSED(v);
+#endif
+}
+
 /*
     List all files in \a directoryPath
 
@@ -169,10 +243,10 @@
 */
 void QFileInfoGatherer::clear()
 {
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
     QMutexLocker locker(&mutex);
-    watcher->removePaths(watcher->files());
-    watcher->removePaths(watcher->directories());
+    unwatchPaths(watchedFiles());
+    unwatchPaths(watchedDirectories());
 #endif
 }
 
@@ -183,9 +257,11 @@
 */
 void QFileInfoGatherer::removePath(const QString &path)
 {
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
     QMutexLocker locker(&mutex);
-    watcher->removePath(path);
+    unwatchPaths(QStringList(path));
+#else
+    Q_UNUSED(path);
 #endif
 }
 
@@ -205,25 +281,18 @@
 void QFileInfoGatherer::run()
 {
     forever {
-        bool updateFiles = false;
         QMutexLocker locker(&mutex);
-        if (abort) {
-            return;
-        }
-        if (this->path.isEmpty())
+        while (!abort.loadRelaxed() && path.isEmpty())
             condition.wait(&mutex);
-        QString path;
-        QStringList list;
-        if (!this->path.isEmpty()) {
-            path = this->path.first();
-            list = this->files.first();
-            this->path.pop_front();
-            this->files.pop_front();
-            updateFiles = true;
-        }
+        if (abort.loadRelaxed())
+            return;
+        const QString thisPath = std::as_const(path).front();
+        path.pop_front();
+        const QStringList thisList = std::as_const(files).front();
+        files.pop_front();
         locker.unlock();
-        if (updateFiles)
-            getFileInfos(path, list);
+
+        getFileInfos(thisPath, thisList);
     }
 }
 
@@ -232,67 +301,62 @@
     QExtendedInformation info(fileInfo);
     info.icon = m_iconProvider->icon(fileInfo);
     info.displayType = m_iconProvider->type(fileInfo);
-#ifndef QT_NO_FILESYSTEMWATCHER
-    // ### Not ready to listen all modifications
-#endif
+#if QT_CONFIG(filesystemwatcher)
+    // ### Not ready to listen all modifications by default
+    static const bool watchFiles = qEnvironmentVariableIsSet("QT_FILESYSTEMMODEL_WATCH_FILES");
+    if (watchFiles) {
+        if (!fileInfo.exists() && !fileInfo.isSymLink()) {
+            const_cast<QFileInfoGatherer *>(this)->
+                unwatchPaths(QStringList(fileInfo.absoluteFilePath()));
+        } else {
+            const QString path = fileInfo.absoluteFilePath();
+            if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()
+                && !watchedFiles().contains(path)) {
+                const_cast<QFileInfoGatherer *>(this)->watchPaths(QStringList(path));
+            }
+        }
+    }
+#endif // filesystemwatcher
 
+#ifdef Q_OS_WIN
     if (m_resolveSymlinks && info.isSymLink(/* ignoreNtfsSymLinks = */ true)) {
-        QFileInfo resolvedInfo(fileInfo.symLinkTarget());
-        resolvedInfo = resolvedInfo.canonicalFilePath();
+        QFileInfo resolvedInfo(QFileInfo(fileInfo.symLinkTarget()).canonicalFilePath());
         if (resolvedInfo.exists()) {
             emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
         }
     }
+#endif
     return info;
 }
 
-QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const
-{
-    QString driveName = drive.absoluteFilePath();
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
-    if (driveName.startsWith(QLatin1Char('/'))) // UNC host
-        return drive.fileName();
-#endif
-#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
-    if (driveName.endsWith(QLatin1Char('/')))
-        driveName.chop(1);
-#endif
-    return driveName;
-}
-
 /*
     Get specific file info's, batch the files so update when we have 100
     items and every 200ms after that
  */
 void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files)
 {
-#ifndef QT_NO_FILESYSTEMWATCHER
-    if (files.isEmpty()
-        && !watcher->directories().contains(path)
-        && !path.isEmpty()
-        && !path.startsWith(QLatin1String("//")) /*don't watch UNC path*/) {
-        watcher->addPath(path);
-    }
-#endif
-
     // List drives
     if (path.isEmpty()) {
 #ifdef QT_BUILD_INTERNAL
-        fetchedRoot = true;
+        fetchedRoot.storeRelaxed(true);
 #endif
         QFileInfoList infoList;
         if (files.isEmpty()) {
             infoList = QDir::drives();
         } else {
-            for (int i = 0; i < files.count(); ++i)
-                infoList << QFileInfo(files.at(i));
+            infoList.reserve(files.size());
+            for (const auto &file : files)
+                infoList << QFileInfo(file);
         }
-        for (int i = infoList.count() - 1; i >= 0; --i) {
-            QString driveName = translateDriveName(infoList.at(i));
-            QList<QPair<QString,QFileInfo> > updatedFiles;
-            updatedFiles.append(QPair<QString,QFileInfo>(driveName, infoList.at(i)));
-            emit updates(path, updatedFiles);
+        QList<QPair<QString, QFileInfo>> updatedFiles;
+        updatedFiles.reserve(infoList.size());
+        for (int i = infoList.size() - 1; i >= 0; --i) {
+            QFileInfo driveInfo = infoList.at(i);
+            driveInfo.stat();
+            QString driveName = translateDriveName(driveInfo);
+            updatedFiles.append(QPair<QString,QFileInfo>(driveName, driveInfo));
         }
+        emit updates(path, updatedFiles);
         return;
     }
 
@@ -300,25 +364,27 @@
     base.start();
     QFileInfo fileInfo;
     bool firstTime = true;
-    QList<QPair<QString, QFileInfo> > updatedFiles;
+    QList<QPair<QString, QFileInfo>> updatedFiles;
     QStringList filesToCheck = files;
 
-    QString itPath = QDir::fromNativeSeparators(files.isEmpty() ? path : QLatin1String(""));
-    QDirIterator dirIt(itPath, QDir::AllEntries | QDir::System | QDir::Hidden);
     QStringList allFiles;
-    while(!abort && dirIt.hasNext()) {
-        dirIt.next();
-        fileInfo = dirIt.fileInfo();
-        allFiles.append(fileInfo.fileName());
-	fetch(fileInfo, base, firstTime, updatedFiles, path);
+    if (files.isEmpty()) {
+        QDirIterator dirIt(path, QDir::AllEntries | QDir::System | QDir::Hidden);
+        while (!abort.loadRelaxed() && dirIt.hasNext()) {
+            fileInfo = dirIt.nextFileInfo();
+            fileInfo.stat();
+            allFiles.append(fileInfo.fileName());
+            fetch(fileInfo, base, firstTime, updatedFiles, path);
+        }
     }
     if (!allFiles.isEmpty())
         emit newListOfFiles(path, allFiles);
 
     QStringList::const_iterator filesIt = filesToCheck.constBegin();
-    while(!abort && filesIt != filesToCheck.constEnd()) {
+    while (!abort.loadRelaxed() && filesIt != filesToCheck.constEnd()) {
         fileInfo.setFile(path + QDir::separator() + *filesIt);
         ++filesIt;
+        fileInfo.stat();
         fetch(fileInfo, base, firstTime, updatedFiles, path);
     }
     if (!updatedFiles.isEmpty())
@@ -326,11 +392,13 @@
     emit directoryLoaded(path);
 }
 
-void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime, QList<QPair<QString, QFileInfo> > &updatedFiles, const QString &path) {
+void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime,
+                              QList<QPair<QString, QFileInfo>> &updatedFiles, const QString &path)
+{
     updatedFiles.append(QPair<QString, QFileInfo>(fileInfo.fileName(), fileInfo));
     QElapsedTimer current;
     current.start();
-    if ((firstTime && updatedFiles.count() > 100) || base.msecsTo(current) > 1000) {
+    if ((firstTime && updatedFiles.size() > 100) || base.msecsTo(current) > 1000) {
         emit updates(path, updatedFiles);
         updatedFiles.clear();
         base = current;
@@ -338,6 +406,6 @@
     }
 }
 
-#endif // QT_NO_FILESYSTEMMODEL
+QT_END_NAMESPACE
 
-QT_END_NAMESPACE
+#include "moc_qfileinfogatherer_p.cpp"
--- a/libgui/languages/build_ts/octave-qt/qfilesystemmodel.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qfilesystemmodel.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,63 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qfilesystemmodel_p.h"
 #include "qfilesystemmodel.h"
+#include <qabstractfileiconprovider.h>
 #include <qlocale.h>
-#include <qmime.h>
+#include <qmimedata.h>
 #include <qurl.h>
 #include <qdebug.h>
-#include <qmessagebox.h>
-#include <qapplication.h>
+#include <QtCore/qcollator.h>
+#if QT_CONFIG(regularexpression)
+#  include <QtCore/qregularexpression.h>
+#endif
+
+#include <algorithm>
 
 #ifdef Q_OS_WIN
-#include <qt_windows.h>
-#endif
-#ifdef Q_OS_WIN32
-#include <QtCore/QVarLengthArray>
+#  include <QtCore/QVarLengthArray>
+#  include <qt_windows.h>
+#  include <shlobj.h>
 #endif
 
 QT_BEGIN_NAMESPACE
 
-#ifndef QT_NO_FILESYSTEMMODEL
+using namespace Qt::StringLiterals;
 
 /*!
     \enum QFileSystemModel::Roles
@@ -74,6 +40,7 @@
     \brief The QFileSystemModel class provides a data model for the local filesystem.
 
     \ingroup model-view
+    \inmodule QtGui
 
     This class provides access to the local filesystem, providing functions
     for renaming and removing files and directories, and for creating new
@@ -83,30 +50,30 @@
     QFileSystemModel can be accessed using the standard interface provided by
     QAbstractItemModel, but it also provides some convenience functions that are
     specific to a directory model.
-    The fileInfo(), isDir(), name(), and path() functions provide information
+    The fileInfo(), isDir(), fileName() and filePath() functions provide information
     about the underlying files and directories related to items in the model.
     Directories can be created and removed using mkdir(), rmdir().
 
-    \note QFileSystemModel requires an instance of a GUI application.
+    \note QFileSystemModel requires an instance of \l QApplication.
 
     \section1 Example Usage
 
     A directory model that displays the contents of a default directory
     is usually constructed with a parent object:
 
-    \snippet doc/src/snippets/shareddirmodel/main.cpp 2
+    \snippet shareddirmodel/main.cpp 2
 
     A tree view can be used to display the contents of the model
 
-    \snippet doc/src/snippets/shareddirmodel/main.cpp 4
+    \snippet shareddirmodel/main.cpp 4
 
     and the contents of a particular directory can be displayed by
     setting the tree view's root index:
 
-    \snippet doc/src/snippets/shareddirmodel/main.cpp 7
+    \snippet shareddirmodel/main.cpp 7
 
     The view's root index can be used to control how much of a
-    hierarchical model is displayed. QDirModel provides a convenience
+    hierarchical model is displayed. QFileSystemModel provides a convenience
     function that returns a suitable model index for a path to a
     directory within the model.
 
@@ -116,10 +83,9 @@
     is called.  This will prevent any unnecessary querying on the file system
     until that point such as listing the drives on Windows.
 
-    Unlike QDirModel, QFileSystemModel uses a separate thread to populate
-    itself so it will not cause the main thread to hang as the file system
-    is being queried.  Calls to rowCount() will return 0 until the model
-    populates a directory.
+    QFileSystemModel uses a separate thread to populate itself so it will not
+    cause the main thread to hang as the file system is being queried.
+    Calls to rowCount() will return 0 until the model populates a directory.
 
     QFileSystemModel keeps a cache with file information. The cache is
     automatically kept up to date using the QFileSystemWatcher.
@@ -128,21 +94,21 @@
 */
 
 /*!
-    \fn bool QFileSystemModel::rmdir(const QModelIndex &index) const
+    \fn bool QFileSystemModel::rmdir(const QModelIndex &index)
 
     Removes the directory corresponding to the model item \a index in the
-    file system model and \bold{deletes the corresponding directory from the
+    file system model and \b{deletes the corresponding directory from the
     file system}, returning true if successful. If the directory cannot be
     removed, false is returned.
 
     \warning This function deletes directories from the file system; it does
-    \bold{not} move them to a location where they can be recovered.
+    \b{not} move them to a location where they can be recovered.
 
     \sa remove()
 */
 
 /*!
-    \fn QIcon QFileSystemModel::fileName(const QModelIndex &index) const
+    \fn QString QFileSystemModel::fileName(const QModelIndex &index) const
 
     Returns the file name for the item stored in the model under the given
     \a index.
@@ -161,6 +127,11 @@
     Returns the QFileInfo for the item stored in the model under the given
     \a index.
 */
+QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const
+{
+    Q_D(const QFileSystemModel);
+    return d->node(index)->fileInfo();
+}
 
 /*!
     \fn void QFileSystemModel::rootPathChanged(const QString &newPath);
@@ -172,7 +143,7 @@
     \fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
 
     This signal is emitted whenever a file with the \a oldName is successfully
-    renamed to \a newName.  The file is located in in the directory \a path.
+    renamed to \a newName.  The file is located in the directory \a path.
 */
 
 /*!
@@ -184,56 +155,44 @@
 */
 
 /*!
-    \fn bool QFileSystemModel::remove(const QModelIndex &index) const
+    \fn bool QFileSystemModel::remove(const QModelIndex &index)
 
-    Removes the model item \a index from the file system model and \bold{deletes the
+    Removes the model item \a index from the file system model and \b{deletes the
     corresponding file from the file system}, returning true if successful. If the
     item cannot be removed, false is returned.
 
-    \warning This function deletes files from the file system; it does \bold{not}
+    \warning This function deletes files from the file system; it does \b{not}
     move them to a location where they can be recovered.
 
     \sa rmdir()
 */
 
-bool QFileSystemModel::remove(const QModelIndex &aindex) const
+bool QFileSystemModel::remove(const QModelIndex &aindex)
 {
-    //### TODO optim
-    QString path = filePath(aindex);
-    QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
-    d->fileInfoGatherer.removePath(path);
-    QDirIterator it(path,
-            QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot,
-            QDirIterator::Subdirectories);
-    QStringList children;
-    while (it.hasNext())
-        children.prepend(it.next());
-    children.append(path);
+    Q_D(QFileSystemModel);
 
-    bool error = false;
-    for (int i = 0; i < children.count(); ++i) {
-        QFileInfo info(children.at(i));
-        QModelIndex modelIndex = index(children.at(i));
-        if (info.isDir()) {
-            QDir dir;
-            if (children.at(i) != path)
-                error |= remove(modelIndex);
-            error |= rmdir(modelIndex);
-        } else {
-            error |= QFile::remove(filePath(modelIndex));
-        }
-    }
-    return error;
+    const QString path = d->filePath(aindex);
+    const QFileInfo fileInfo(path);
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+    // QTBUG-65683: Remove file system watchers prior to deletion to prevent
+    // failure due to locked files on Windows.
+    const QStringList watchedPaths = d->unwatchPathsAt(aindex);
+#endif // filesystemwatcher && Q_OS_WIN
+    const bool success = (fileInfo.isFile() || fileInfo.isSymLink())
+            ? QFile::remove(path) : QDir(path).removeRecursively();
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+    if (!success)
+        d->watchPaths(watchedPaths);
+#endif // filesystemwatcher && Q_OS_WIN
+    return success;
 }
 
 /*!
   Constructs a file system model with the given \a parent.
 */
-QFileSystemModel::QFileSystemModel(QObject *parent)
-    : QAbstractItemModel(*new QFileSystemModelPrivate, parent)
+QFileSystemModel::QFileSystemModel(QObject *parent) :
+    QFileSystemModel(*new QFileSystemModelPrivate, parent)
 {
-    Q_D(QFileSystemModel);
-    d->init();
 }
 
 /*!
@@ -249,9 +208,7 @@
 /*!
   Destroys this file system model.
 */
-QFileSystemModel::~QFileSystemModel()
-{
-}
+QFileSystemModel::~QFileSystemModel() = default;
 
 /*!
     \reimp
@@ -268,7 +225,10 @@
     Q_ASSERT(parentNode);
 
     // now get the internal pointer for the index
-    QString childName = parentNode->visibleChildren[d->translateVisibleLocation(parentNode, row)];
+    const int i = d->translateVisibleLocation(parentNode, row);
+    if (i >= parentNode->visibleChildren.size())
+        return QModelIndex();
+    const QString &childName = parentNode->visibleChildren.at(i);
     const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName);
     Q_ASSERT(indexNode);
 
@@ -276,6 +236,21 @@
 }
 
 /*!
+    \reimp
+*/
+QModelIndex QFileSystemModel::sibling(int row, int column, const QModelIndex &idx) const
+{
+    if (row == idx.row() && column < columnCount(idx.parent())) {
+        // cheap sibling operation: just adjust the column:
+        return createIndex(row, column, idx.internalPointer());
+    } else {
+        // for anything else: call the default implementation
+        // (this could probably be optimized, too):
+        return QAbstractItemModel::sibling(row, column, idx);
+    }
+}
+
+/*!
     \overload
 
     Returns the model item index for the given \a path and \a column.
@@ -284,10 +259,7 @@
 {
     Q_D(const QFileSystemModel);
     QFileSystemModelPrivate::QFileSystemNode *node = d->node(path, false);
-    QModelIndex idx = d->index(node);
-    if (idx.column() != column)
-        idx = idx.sibling(idx.row(), column);
-    return idx;
+    return d->index(node, column);
 }
 
 /*!
@@ -308,17 +280,17 @@
 static QString qt_GetLongPathName(const QString &strShortPath)
 {
     if (strShortPath.isEmpty()
-        || strShortPath == QLatin1String(".") || strShortPath == QLatin1String(".."))
+        || strShortPath == "."_L1 || strShortPath == ".."_L1)
         return strShortPath;
-    if (strShortPath.length() == 2 && strShortPath.endsWith(QLatin1Char(':')))
+    if (strShortPath.length() == 2 && strShortPath.endsWith(u':'))
         return strShortPath.toUpper();
     const QString absPath = QDir(strShortPath).absolutePath();
-    if (absPath.startsWith(QLatin1String("//"))
-        || absPath.startsWith(QLatin1String("\\\\"))) // unc
+    if (absPath.startsWith("//"_L1)
+        || absPath.startsWith("\\\\"_L1)) // unc
         return QDir::fromNativeSeparators(absPath);
-    if (absPath.startsWith(QLatin1Char('/')))
+    if (absPath.startsWith(u'/'))
         return QString();
-    const QString inputString = QLatin1String("\\\\?\\") + QDir::toNativeSeparators(absPath);
+    const QString inputString = "\\\\?\\"_L1 + QDir::toNativeSeparators(absPath);
     QVarLengthArray<TCHAR, MAX_PATH> buffer(MAX_PATH);
     DWORD result = ::GetLongPathName((wchar_t*)inputString.utf16(),
                                      buffer.data(),
@@ -348,7 +320,7 @@
 {
     Q_Q(const QFileSystemModel);
     Q_UNUSED(q);
-    if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1Char(':')))
+    if (path.isEmpty() || path == myComputer() || path.startsWith(u':'))
         return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
 
     // Construct the nodes up to the new root path if they need to be built
@@ -364,25 +336,33 @@
         absolutePath = QDir(longPath).absolutePath();
 
     // ### TODO can we use bool QAbstractFileEngine::caseSensitive() const?
-    QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
+    QStringList pathElements = absolutePath.split(u'/', Qt::SkipEmptyParts);
     if ((pathElements.isEmpty())
-#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
-        && QDir::fromNativeSeparators(longPath) != QLatin1String("/")
+#if !defined(Q_OS_WIN)
+        && QDir::fromNativeSeparators(longPath) != "/"_L1
 #endif
         )
         return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
     QModelIndex index = QModelIndex(); // start with "My Computer"
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
-    if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path
-        QString host = QLatin1String("\\\\") + pathElements.first();
+    QString elementPath;
+    QChar separator = u'/';
+    QString trailingSeparator;
+#if defined(Q_OS_WIN)
+    if (absolutePath.startsWith("//"_L1)) { // UNC path
+        QString host = "\\\\"_L1 + pathElements.constFirst();
         if (absolutePath == QDir::fromNativeSeparators(host))
-            absolutePath.append(QLatin1Char('/'));
-        if (longPath.endsWith(QLatin1Char('/')) && !absolutePath.endsWith(QLatin1Char('/')))
-            absolutePath.append(QLatin1Char('/'));
+            absolutePath.append(u'/');
+        if (longPath.endsWith(u'/') && !absolutePath.endsWith(u'/'))
+            absolutePath.append(u'/');
+        if (absolutePath.endsWith(u'/'))
+            trailingSeparator = "\\"_L1;
         int r = 0;
-        QFileSystemModelPrivate::QFileSystemNode *rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
-        if (!root.children.contains(host.toLower())) {
-            if (pathElements.count() == 1 && !absolutePath.endsWith(QLatin1Char('/')))
+        auto rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+        auto it = root.children.constFind(host);
+        if (it != root.children.cend()) {
+            host = it.key(); // Normalize case for lookup in visibleLocation()
+        } else {
+            if (pathElements.count() == 1 && !absolutePath.endsWith(u'/'))
                 return rootNode;
             QFileInfo info(host);
             if (!info.exists())
@@ -395,41 +375,52 @@
         r = translateVisibleLocation(rootNode, r);
         index = q->index(r, 0, QModelIndex());
         pathElements.pop_front();
-    } else
-#endif
-
-#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
-    {
-        if (!pathElements.at(0).contains(QLatin1String(":"))) {
-            // The reason we express it like this instead of with anonymous, temporary
-            // variables, is to workaround a compiler crash with Q_CC_NOKIAX86.
+        separator = u'\\';
+        elementPath = host;
+        elementPath.append(separator);
+    } else {
+        if (!pathElements.at(0).contains(u':')) {
             QString rootPath = QDir(longPath).rootPath();
             pathElements.prepend(rootPath);
         }
-        if (pathElements.at(0).endsWith(QLatin1Char('/')))
+        if (pathElements.at(0).endsWith(u'/'))
             pathElements[0].chop(1);
     }
 #else
     // add the "/" item, since it is a valid path element on Unix
-    if (absolutePath[0] == QLatin1Char('/'))
-        pathElements.prepend(QLatin1String("/"));
+    if (absolutePath[0] == u'/')
+        pathElements.prepend("/"_L1);
 #endif
 
     QFileSystemModelPrivate::QFileSystemNode *parent = node(index);
 
-    for (int i = 0; i < pathElements.count(); ++i) {
+    for (int i = 0; i < pathElements.size(); ++i) {
         QString element = pathElements.at(i);
+        if (i != 0)
+            elementPath.append(separator);
+        elementPath.append(element);
+        if (i == pathElements.size() - 1)
+            elementPath.append(trailingSeparator);
 #ifdef Q_OS_WIN
-        // On Windows, "filename......." and "filename" are equivalent Task #133928
-        while (element.endsWith(QLatin1Char('.')))
+        // On Windows, "filename    " and "filename" are equivalent and
+        // "filename  .  " and "filename" are equivalent
+        // "filename......." and "filename" are equivalent Task #133928
+        // whereas "filename  .txt" is still "filename  .txt"
+        // If after stripping the characters there is nothing left then we
+        // just return the parent directory as it is assumed that the path
+        // is referring to the parent
+        while (element.endsWith(u'.') || element.endsWith(u' '))
             element.chop(1);
+        // Only filenames that can't possibly exist will be end up being empty
+        if (element.isEmpty())
+            return parent;
 #endif
         bool alreadyExisted = parent->children.contains(element);
 
         // we couldn't find the path element, we create a new node since we
         // _know_ that the path is valid
         if (alreadyExisted) {
-            if ((parent->children.count() == 0)
+            if ((parent->children.size() == 0)
                 || (parent->caseSensitive()
                     && parent->children.value(element)->fileName != element)
                 || (!parent->caseSensitive()
@@ -441,12 +432,12 @@
         if (!alreadyExisted) {
             // Someone might call ::index("file://cookie/monster/doesn't/like/veggies"),
             // a path that doesn't exists, I.E. don't blindly create directories.
-            QFileInfo info(absolutePath);
+            QFileInfo info(elementPath);
             if (!info.exists())
                 return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
             QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
             node = p->addNode(parent, element,info);
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
             node->populate(fileInfoGatherer.getInfo(info));
 #endif
         } else {
@@ -465,11 +456,8 @@
                 p->bypassFilters[node] = 1;
             QString dir = q->filePath(this->index(parent));
             if (!node->hasInformation() && fetch) {
-                Fetching f;
-                f.dir = dir;
-                f.file = element;
-                f.node = node;
-                p->toFetch.append(f);
+                Fetching f = { std::move(dir), std::move(element), node };
+                p->toFetch.append(std::move(f));
                 p->fetchingTimer.start(0, const_cast<QFileSystemModel*>(q));
             }
         }
@@ -487,14 +475,14 @@
     Q_D(QFileSystemModel);
     if (event->timerId() == d->fetchingTimer.timerId()) {
         d->fetchingTimer.stop();
-#ifndef QT_NO_FILESYSTEMWATCHER
-        for (int i = 0; i < d->toFetch.count(); ++i) {
+#if QT_CONFIG(filesystemwatcher)
+        for (int i = 0; i < d->toFetch.size(); ++i) {
             const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node;
             if (!node->hasInformation()) {
                 d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir,
                                                  QStringList(d->toFetch.at(i).file));
             } else {
-                // qDebug() << "yah!, you saved a little gerbil soul";
+                // qDebug("yah!, you saved a little gerbil soul");
             }
         }
 #endif
@@ -503,8 +491,8 @@
 }
 
 /*!
-    Returns true if the model item \a index represents a directory;
-    otherwise returns false.
+    Returns \c true if the model item \a index represents a directory;
+    otherwise returns \c false.
 */
 bool QFileSystemModel::isDir(const QModelIndex &index) const
 {
@@ -541,14 +529,38 @@
 }
 
 /*!
-    Returns the date and time when \a index was last modified.
+    Returns the date and time (in local time) when \a index was last modified.
+
+    This is an overloaded function, equivalent to calling:
+    \code
+    lastModified(index, QTimeZone::LocalTime);
+    \endcode
+
+    If \a index is invalid, a default constructed QDateTime is returned.
  */
 QDateTime QFileSystemModel::lastModified(const QModelIndex &index) const
 {
+    return lastModified(index, QTimeZone::LocalTime);
+}
+
+/*!
+    \since 6.6
+    Returns the date and time, in the time zone \a tz, when
+    \a index was last modified.
+
+    Typical arguments for \a tz are \c QTimeZone::UTC or \c QTimeZone::LocalTime.
+    UTC does not require any conversion from the time returned by the native file
+    system API, therefore getting the time in UTC is potentially faster. LocalTime
+    is typically chosen if the time is shown to the user.
+
+    If \a index is invalid, a default constructed QDateTime is returned.
+ */
+QDateTime QFileSystemModel::lastModified(const QModelIndex &index, const QTimeZone &tz) const
+{
     Q_D(const QFileSystemModel);
     if (!index.isValid())
         return QDateTime();
-    return d->node(index)->lastModified();
+    return d->node(index)->lastModified(tz);
 }
 
 /*!
@@ -561,9 +573,9 @@
         return QModelIndex();
 
     QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
-    Q_ASSERT(indexNode != 0);
-    QFileSystemModelPrivate::QFileSystemNode *parentNode = (indexNode ? indexNode->parent : 0);
-    if (parentNode == 0 || parentNode == &d->root)
+    Q_ASSERT(indexNode != nullptr);
+    QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent;
+    if (parentNode == nullptr || parentNode == &d->root)
         return QModelIndex();
 
     // get the parent's row
@@ -580,10 +592,10 @@
 
     return the index for node
 */
-QModelIndex QFileSystemModelPrivate::index(const QFileSystemModelPrivate::QFileSystemNode *node) const
+QModelIndex QFileSystemModelPrivate::index(const QFileSystemModelPrivate::QFileSystemNode *node, int column) const
 {
     Q_Q(const QFileSystemModel);
-    QFileSystemModelPrivate::QFileSystemNode *parentNode = (node ? node->parent : 0);
+    QFileSystemModelPrivate::QFileSystemNode *parentNode = (node ? node->parent : nullptr);
     if (node == &root || !parentNode)
         return QModelIndex();
 
@@ -593,7 +605,7 @@
         return QModelIndex();
 
     int visualRow = translateVisibleLocation(parentNode, parentNode->visibleLocation(node->fileName));
-    return q->createIndex(visualRow, 0, const_cast<QFileSystemNode*>(node));
+    return q->createIndex(visualRow, column, const_cast<QFileSystemNode*>(node));
 }
 
 /*!
@@ -619,6 +631,8 @@
 bool QFileSystemModel::canFetchMore(const QModelIndex &parent) const
 {
     Q_D(const QFileSystemModel);
+    if (!d->setRootPath)
+        return false;
     const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
     return (!indexNode->populatedChildren);
 }
@@ -635,7 +649,9 @@
     if (indexNode->populatedChildren)
         return;
     indexNode->populatedChildren = true;
+#if QT_CONFIG(filesystemwatcher)
     d->fileInfoGatherer.list(filePath(parent));
+#endif
 }
 
 /*!
@@ -648,10 +664,10 @@
         return 0;
 
     if (!parent.isValid())
-        return d->root.visibleChildren.count();
+        return d->root.visibleChildren.size();
 
     const QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
-    return parentNode->visibleChildren.count();
+    return parentNode->visibleChildren.size();
 }
 
 /*!
@@ -659,7 +675,7 @@
 */
 int QFileSystemModel::columnCount(const QModelIndex &parent) const
 {
-    return (parent.column() > 0) ? 0 : 4;
+    return (parent.column() > 0) ? 0 : QFileSystemModelPrivate::NumColumns;
 }
 
 /*!
@@ -669,12 +685,16 @@
  */
 QVariant QFileSystemModel::myComputer(int role) const
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_D(const QFileSystemModel);
+#endif
     switch (role) {
     case Qt::DisplayRole:
-        return d->myComputer();
+        return QFileSystemModelPrivate::myComputer();
+#if QT_CONFIG(filesystemwatcher)
     case Qt::DecorationRole:
-        return d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Computer);
+        return d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Computer);
+#endif
     }
     return QVariant();
 }
@@ -690,12 +710,15 @@
 
     switch (role) {
     case Qt::EditRole:
+        if (index.column() == QFileSystemModelPrivate::NameColumn)
+            return d->name(index);
+        Q_FALLTHROUGH();
     case Qt::DisplayRole:
         switch (index.column()) {
-        case 0: return d->displayName(index);
-        case 1: return d->size(index);
-        case 2: return d->type(index);
-        case 3: return d->time(index);
+        case QFileSystemModelPrivate::NameColumn: return d->displayName(index);
+        case QFileSystemModelPrivate::SizeColumn: return d->size(index);
+        case QFileSystemModelPrivate::TypeColumn: return d->type(index);
+        case QFileSystemModelPrivate::TimeColumn: return d->time(index);
         default:
             qWarning("data: invalid display value column %d", index.column());
             break;
@@ -706,20 +729,22 @@
     case FileNameRole:
         return d->name(index);
     case Qt::DecorationRole:
-        if (index.column() == 0) {
+        if (index.column() == QFileSystemModelPrivate::NameColumn) {
             QIcon icon = d->icon(index);
+#if QT_CONFIG(filesystemwatcher)
             if (icon.isNull()) {
                 if (d->node(index)->isDir())
-                    icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
+                    icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Folder);
                 else
-                    icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
+                    icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::File);
             }
+#endif // filesystemwatcher
             return icon;
         }
         break;
     case Qt::TextAlignmentRole:
-        if (index.column() == 1)
-            return Qt::AlignRight;
+        if (index.column() == QFileSystemModelPrivate::SizeColumn)
+            return QVariant(Qt::AlignTrailing | Qt::AlignVCenter);
         break;
     case FilePermissions:
         int p = permissions(index);
@@ -739,9 +764,9 @@
     const QFileSystemNode *n = node(index);
     if (n->isDir()) {
 #ifdef Q_OS_MAC
-        return QLatin1String("--");
+        return "--"_L1;
 #else
-        return QLatin1String("");
+        return ""_L1;
 #endif
     // Windows   - ""
     // OS X      - "--"
@@ -753,21 +778,7 @@
 
 QString QFileSystemModelPrivate::size(qint64 bytes)
 {
-    // According to the Si standard KB is 1000 bytes, KiB is 1024
-    // but on windows sizes are calculated by dividing by 1024 so we do what they do.
-    const qint64 kb = 1024;
-    const qint64 mb = 1024 * kb;
-    const qint64 gb = 1024 * mb;
-    const qint64 tb = 1024 * gb;
-    if (bytes >= tb)
-        return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
-    if (bytes >= gb)
-        return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
-    if (bytes >= mb)
-        return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
-    if (bytes >= kb)
-        return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
-    return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
+    return QLocale::system().formattedDataSize(bytes);
 }
 
 /*!
@@ -777,8 +788,8 @@
 {
     if (!index.isValid())
         return QString();
-#ifndef QT_NO_DATESTRING
-    return node(index)->lastModified().toString(Qt::SystemLocaleDate);
+#if QT_CONFIG(datestring)
+    return QLocale::system().toString(node(index)->lastModified(QTimeZone::LocalTime), QLocale::ShortFormat);
 #else
     Q_UNUSED(index);
     return QString();
@@ -803,11 +814,13 @@
     if (!index.isValid())
         return QString();
     QFileSystemNode *dirNode = node(index);
-    if (fileInfoGatherer.resolveSymlinks() && !resolvedSymLinks.isEmpty() &&
-        dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) {
+    if (
+#if QT_CONFIG(filesystemwatcher)
+        fileInfoGatherer.resolveSymlinks() &&
+#endif
+        !resolvedSymLinks.isEmpty() && dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) {
         QString fullPath = QDir::fromNativeSeparators(filePath(index));
-        if (resolvedSymLinks.contains(fullPath))
-            return resolvedSymLinks[fullPath];
+        return resolvedSymLinks.value(fullPath, dirNode->fileName);
     }
     return dirNode->fileName;
 }
@@ -817,10 +830,10 @@
 */
 QString QFileSystemModelPrivate::displayName(const QModelIndex &index) const
 {
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+#if defined(Q_OS_WIN)
     QFileSystemNode *dirNode = node(index);
-    if (!dirNode->volumeName.isNull())
-        return dirNode->volumeName + QLatin1String(" (") + name(index) + QLatin1Char(')');
+    if (!dirNode->volumeName.isEmpty())
+        return dirNode->volumeName;
 #endif
     return name(index);
 }
@@ -850,25 +863,30 @@
 
     QString newName = value.toString();
     QString oldName = idx.data().toString();
-    if (newName == idx.data().toString())
+    if (newName == oldName)
         return true;
 
-    if (newName.isEmpty()
-        || QDir::toNativeSeparators(newName).contains(QDir::separator())
-        || !QDir(filePath(parent(idx))).rename(oldName, newName)) {
-#ifndef QT_NO_MESSAGEBOX
-        QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
-                                QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
-                                .arg(newName),
-                                 QMessageBox::Ok);
-#endif // QT_NO_MESSAGEBOX
+    const QString parentPath = filePath(parent(idx));
+
+    if (newName.isEmpty() || QDir::toNativeSeparators(newName).contains(QDir::separator()))
+        return false;
+
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+    // QTBUG-65683: Remove file system watchers prior to renaming to prevent
+    // failure due to locked files on Windows.
+    const QStringList watchedPaths = d->unwatchPathsAt(idx);
+#endif // filesystemwatcher && Q_OS_WIN
+    if (!QDir(parentPath).rename(oldName, newName)) {
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+        d->watchPaths(watchedPaths);
+#endif
         return false;
     } else {
         /*
             *After re-naming something we don't want the selection to change*
             - can't remove rows and later insert
             - can't quickly remove and insert
-            - index pointer can't change because treeview doesn't use persistant index's
+            - index pointer can't change because treeview doesn't use persistent index's
 
             - if this get any more complicated think of changing it to just
               use layoutChanged
@@ -878,21 +896,19 @@
         QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent;
         int visibleLocation = parentNode->visibleLocation(parentNode->children.value(indexNode->fileName)->fileName);
 
-        d->addNode(parentNode, newName,indexNode->info->fileInfo());
         parentNode->visibleChildren.removeAt(visibleLocation);
-        QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName);
-        parentNode->children[newName] = oldValue;
-        QFileInfo info(d->rootDir, newName);
-        oldValue->fileName = newName;
-        oldValue->parent = parentNode;
-        oldValue->populate(d->fileInfoGatherer.getInfo(info));
-        oldValue->isVisible = true;
-
-        parentNode->children.remove(oldName);
+        std::unique_ptr<QFileSystemModelPrivate::QFileSystemNode> nodeToRename(parentNode->children.take(oldName));
+        nodeToRename->fileName = newName;
+        nodeToRename->parent = parentNode;
+#if QT_CONFIG(filesystemwatcher)
+        nodeToRename->populate(d->fileInfoGatherer.getInfo(QFileInfo(parentPath, newName)));
+#endif
+        nodeToRename->isVisible = true;
+        parentNode->children[newName] = nodeToRename.release();
         parentNode->visibleChildren.insert(visibleLocation, newName);
 
         d->delayedSort();
-        emit fileRenamed(filePath(idx.parent()), oldName, newName);
+        emit fileRenamed(parentPath, oldName, newName);
     }
     return true;
 }
@@ -907,9 +923,8 @@
         if (section == 0) {
             // ### TODO oh man this is ugly and doesn't even work all the way!
             // it is still 2 pixels off
-            QImage pixmap(16, 1, QImage::Format_Mono);
-            pixmap.fill(0);
-            pixmap.setAlphaChannel(pixmap.createAlphaMask());
+            QImage pixmap(16, 1, QImage::Format_ARGB32_Premultiplied);
+            pixmap.fill(Qt::transparent);
             return pixmap;
         }
         break;
@@ -922,23 +937,27 @@
 
     QString returnValue;
     switch (section) {
-    case 0: returnValue = tr("Name");
-            break;
-    case 1: returnValue = tr("Size");
-            break;
-    case 2: returnValue =
+    case QFileSystemModelPrivate::NameColumn:
+        returnValue = tr("Name");
+        break;
+    case QFileSystemModelPrivate::SizeColumn:
+        returnValue = tr("Size");
+        break;
+    case QFileSystemModelPrivate::TypeColumn:
+        returnValue =
 #ifdef Q_OS_MAC
-                   tr("Kind", "Match OS X Finder");
+                    tr("Kind", "Match OS X Finder");
 #else
-                   tr("Type", "All other platforms");
+                    tr("Type", "All other platforms");
 #endif
-           break;
+        break;
     // Windows   - Type
     // OS X      - Kind
     // Konqueror - File Type
     // Nautilus  - Type
-    case 3: returnValue = tr("Date Modified");
-            break;
+    case QFileSystemModelPrivate::TimeColumn:
+        returnValue = tr("Date Modified");
+        break;
     default: return QVariant();
     }
     return returnValue;
@@ -962,6 +981,9 @@
     }
 
     flags |= Qt::ItemIsDragEnabled;
+
+    if (!indexNode->isDir())
+        flags |= Qt::ItemNeverHasChildren;
     if (d->readOnly)
         return flags;
     if ((index.column() == 0) && indexNode->permissions() & QFile::WriteUser) {
@@ -981,84 +1003,6 @@
     q->sort(sortColumn, sortOrder);
 }
 
-static inline QChar getNextChar(const QString &s, int location)
-{
-    return (location < s.length()) ? s.at(location) : QChar();
-}
-
-/*!
-    Natural number sort, skips spaces.
-
-    Examples:
-    1, 2, 10, 55, 100
-    01.jpg, 2.jpg, 10.jpg
-
-    Note on the algorithm:
-    Only as many characters as necessary are looked at and at most they all
-    are looked at once.
-
-    Slower then QString::compare() (of course)
-  */
-int QFileSystemModelPrivate::naturalCompare(const QString &s1, const QString &s2,  Qt::CaseSensitivity cs)
-{
-    for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) {
-        // skip spaces, tabs and 0's
-        QChar c1 = getNextChar(s1, l1);
-        while (c1.isSpace())
-            c1 = getNextChar(s1, ++l1);
-        QChar c2 = getNextChar(s2, l2);
-        while (c2.isSpace())
-            c2 = getNextChar(s2, ++l2);
-
-        if (c1.isDigit() && c2.isDigit()) {
-            while (c1.digitValue() == 0)
-                c1 = getNextChar(s1, ++l1);
-            while (c2.digitValue() == 0)
-                c2 = getNextChar(s2, ++l2);
-
-            int lookAheadLocation1 = l1;
-            int lookAheadLocation2 = l2;
-            int currentReturnValue = 0;
-            // find the last digit, setting currentReturnValue as we go if it isn't equal
-            for (
-                QChar lookAhead1 = c1, lookAhead2 = c2;
-                (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
-                lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
-                lookAhead2 = getNextChar(s2, ++lookAheadLocation2)
-                ) {
-                bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
-                bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
-                if (!is1ADigit && !is2ADigit)
-                    break;
-                if (!is1ADigit)
-                    return -1;
-                if (!is2ADigit)
-                    return 1;
-                if (currentReturnValue == 0) {
-                    if (lookAhead1 < lookAhead2) {
-                        currentReturnValue = -1;
-                    } else if (lookAhead1 > lookAhead2) {
-                        currentReturnValue = 1;
-                    }
-                }
-            }
-            if (currentReturnValue != 0)
-                return currentReturnValue;
-        }
-
-        if (cs == Qt::CaseInsensitive) {
-            if (!c1.isLower()) c1 = c1.toLower();
-            if (!c2.isLower()) c2 = c2.toLower();
-        }
-        int r = QString::localeAwareCompare(c1, c2);
-        if (r < 0)
-            return -1;
-        if (r > 0)
-            return 1;
-    }
-    // The two strings are the same (02 == 2) so fall back to the normal sort
-    return QString::compare(s1, s2, cs);
-}
 
 /*
     \internal
@@ -1067,13 +1011,17 @@
 class QFileSystemModelSorter
 {
 public:
-    inline QFileSystemModelSorter(int column) : sortColumn(column) {}
+    inline QFileSystemModelSorter(int column) : sortColumn(column)
+    {
+        naturalCompare.setNumericMode(true);
+        naturalCompare.setCaseSensitivity(Qt::CaseInsensitive);
+    }
 
     bool compareNodes(const QFileSystemModelPrivate::QFileSystemNode *l,
                     const QFileSystemModelPrivate::QFileSystemNode *r) const
     {
         switch (sortColumn) {
-        case 0: {
+        case QFileSystemModelPrivate::NameColumn: {
 #ifndef Q_OS_MAC
             // place directories before files
             bool left = l->isDir();
@@ -1081,31 +1029,53 @@
             if (left ^ right)
                 return left;
 #endif
-            return QFileSystemModelPrivate::naturalCompare(l->fileName,
-                                                r->fileName, Qt::CaseInsensitive) < 0;
+            return naturalCompare.compare(l->fileName, r->fileName) < 0;
                 }
-        case 1:
+        case QFileSystemModelPrivate::SizeColumn:
+        {
             // Directories go first
-            if (l->isDir() && !r->isDir())
-                return true;
-            return l->size() < r->size();
-        case 2:
-            return l->type() < r->type();
-        case 3:
-            return l->lastModified() < r->lastModified();
+            bool left = l->isDir();
+            bool right = r->isDir();
+            if (left ^ right)
+                return left;
+
+            qint64 sizeDifference = l->size() - r->size();
+            if (sizeDifference == 0)
+                return naturalCompare.compare(l->fileName, r->fileName) < 0;
+
+            return sizeDifference < 0;
+        }
+        case QFileSystemModelPrivate::TypeColumn:
+        {
+            int compare = naturalCompare.compare(l->type(), r->type());
+            if (compare == 0)
+                return naturalCompare.compare(l->fileName, r->fileName) < 0;
+
+            return compare < 0;
+        }
+        case QFileSystemModelPrivate::TimeColumn:
+        {
+            const QDateTime left = l->lastModified(QTimeZone::UTC);
+            const QDateTime right = r->lastModified(QTimeZone::UTC);
+            if (left == right)
+                return naturalCompare.compare(l->fileName, r->fileName) < 0;
+
+            return left < right;
+        }
         }
         Q_ASSERT(false);
         return false;
     }
 
-    bool operator()(const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &l,
-                           const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &r) const
+    bool operator()(const QFileSystemModelPrivate::QFileSystemNode *l,
+                    const QFileSystemModelPrivate::QFileSystemNode *r) const
     {
-        return compareNodes(l.first, r.first);
+        return compareNodes(l, r);
     }
 
 
 private:
+    QCollator naturalCompare;
     int sortColumn;
 };
 
@@ -1118,29 +1088,28 @@
 {
     Q_Q(QFileSystemModel);
     QFileSystemModelPrivate::QFileSystemNode *indexNode = node(parent);
-    if (indexNode->children.count() == 0)
+    if (indexNode->children.size() == 0)
         return;
 
-    QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > values;
-    QHash<QString, QFileSystemNode *>::const_iterator iterator;
-    int i = 0;
-    for(iterator = indexNode->children.begin() ; iterator != indexNode->children.end() ; ++iterator) {
+    QList<QFileSystemModelPrivate::QFileSystemNode *> values;
+
+    for (auto iterator = indexNode->children.constBegin(), cend = indexNode->children.constEnd(); iterator != cend; ++iterator) {
         if (filtersAcceptsNode(iterator.value())) {
-            values.append(QPair<QFileSystemModelPrivate::QFileSystemNode*, int>((iterator.value()), i));
+            values.append(iterator.value());
         } else {
             iterator.value()->isVisible = false;
         }
-        i++;
     }
     QFileSystemModelSorter ms(column);
-    qStableSort(values.begin(), values.end(), ms);
+    std::sort(values.begin(), values.end(), ms);
     // First update the new visible list
     indexNode->visibleChildren.clear();
     //No more dirty item we reset our internal dirty index
     indexNode->dirtyChildrenIndex = -1;
-    for (int i = 0; i < values.count(); ++i) {
-        indexNode->visibleChildren.append(values.at(i).first->fileName);
-        values.at(i).first->isVisible = true;
+    indexNode->visibleChildren.reserve(values.size());
+    for (QFileSystemNode *node : std::as_const(values)) {
+        indexNode->visibleChildren.append(node->fileName);
+        node->isVisible = true;
     }
 
     if (!disableRecursiveSort) {
@@ -1165,9 +1134,10 @@
 
     emit layoutAboutToBeChanged();
     QModelIndexList oldList = persistentIndexList();
-    QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > oldNodes;
-    for (int i = 0; i < oldList.count(); ++i) {
-        QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldList.at(i)), oldList.at(i).column());
+    QList<QPair<QFileSystemModelPrivate::QFileSystemNode *, int>> oldNodes;
+    oldNodes.reserve(oldList.size());
+    for (const QModelIndex &oldNode : oldList) {
+        QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldNode), oldNode.column());
         oldNodes.append(pair);
     }
 
@@ -1180,11 +1150,10 @@
     d->sortOrder = order;
 
     QModelIndexList newList;
-    for (int i = 0; i < oldNodes.count(); ++i) {
-        QModelIndex idx = d->index(oldNodes.at(i).first);
-        idx = idx.sibling(idx.row(), oldNodes.at(i).second);
-        newList.append(idx);
-    }
+    newList.reserve(oldNodes.size());
+    for (const auto &[node, col]: std::as_const(oldNodes))
+        newList.append(d->index(node, col));
+
     changePersistentIndexList(oldList, newList);
     emit layoutChanged();
 }
@@ -1195,7 +1164,7 @@
 */
 QStringList QFileSystemModel::mimeTypes() const
 {
-    return QStringList(QLatin1String("text/uri-list"));
+    return QStringList("text/uri-list"_L1);
 }
 
 /*!
@@ -1203,15 +1172,15 @@
     \a indexes. The format used to describe the items corresponding to the
     indexes is obtained from the mimeTypes() function.
 
-    If the list of indexes is empty, 0 is returned rather than a serialized
-    empty list.
+    If the list of indexes is empty, \nullptr is returned rather than a
+    serialized empty list.
 */
 QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const
 {
     QList<QUrl> urls;
     QList<QModelIndex>::const_iterator it = indexes.begin();
     for (; it != indexes.end(); ++it)
-        if ((*it).column() == 0)
+        if ((*it).column() == QFileSystemModelPrivate::NameColumn)
             urls << QUrl::fromLocalFile(filePath(*it));
     QMimeData *data = new QMimeData();
     data->setUrls(urls);
@@ -1221,7 +1190,8 @@
 /*!
     Handles the \a data supplied by a drag and drop operation that ended with
     the given \a action over the row in the model specified by the \a row and
-    \a column and by the \a parent index.
+    \a column and by the \a parent index. Returns true if the operation was
+    successful.
 
     \sa supportedDropActions()
 */
@@ -1274,6 +1244,121 @@
 }
 
 /*!
+    \reimp
+*/
+QHash<int, QByteArray> QFileSystemModel::roleNames() const
+{
+    auto ret = QAbstractItemModel::roleNames();
+    ret.insert(QFileSystemModel::FileIconRole,
+               QByteArrayLiteral("fileIcon")); // == Qt::decoration
+    ret.insert(QFileSystemModel::FilePathRole, QByteArrayLiteral("filePath"));
+    ret.insert(QFileSystemModel::FileNameRole, QByteArrayLiteral("fileName"));
+    ret.insert(QFileSystemModel::FilePermissions, QByteArrayLiteral("filePermissions"));
+    return ret;
+}
+
+/*!
+    \enum QFileSystemModel::Option
+    \since 5.14
+
+    \value DontWatchForChanges Do not add file watchers to the paths.
+    This reduces overhead when using the model for simple tasks
+    like line edit completion.
+
+    \value DontResolveSymlinks Don't resolve symlinks in the file
+    system model. By default, symlinks are resolved.
+
+    \value DontUseCustomDirectoryIcons Always use the default directory icon.
+    Some platforms allow the user to set a different icon. Custom icon lookup
+    causes a big performance impact over network or removable drives.
+    This sets the QFileIconProvider::DontUseCustomDirectoryIcons
+    option in the icon provider accordingly.
+
+    \sa resolveSymlinks
+*/
+
+/*!
+    \since 5.14
+    Sets the given \a option to be enabled if \a on is true; otherwise,
+    clears the given \a option.
+
+    Options should be set before changing properties.
+
+    \sa options, testOption()
+*/
+void QFileSystemModel::setOption(Option option, bool on)
+{
+    QFileSystemModel::Options previousOptions = options();
+    setOptions(previousOptions.setFlag(option, on));
+}
+
+/*!
+    \since 5.14
+
+    Returns \c true if the given \a option is enabled; otherwise, returns
+    false.
+
+    \sa options, setOption()
+*/
+bool QFileSystemModel::testOption(Option option) const
+{
+    return options().testFlag(option);
+}
+
+/*!
+    \property QFileSystemModel::options
+    \brief the various options that affect the model
+    \since 5.14
+
+    By default, all options are disabled.
+
+    Options should be set before changing properties.
+
+    \sa setOption(), testOption()
+*/
+void QFileSystemModel::setOptions(Options options)
+{
+    const Options changed = (options ^ QFileSystemModel::options());
+
+    if (changed.testFlag(DontResolveSymlinks))
+        setResolveSymlinks(!options.testFlag(DontResolveSymlinks));
+
+#if QT_CONFIG(filesystemwatcher)
+    Q_D(QFileSystemModel);
+    if (changed.testFlag(DontWatchForChanges))
+        d->fileInfoGatherer.setWatching(!options.testFlag(DontWatchForChanges));
+#endif
+
+    if (changed.testFlag(DontUseCustomDirectoryIcons)) {
+        if (auto provider = iconProvider()) {
+            QAbstractFileIconProvider::Options providerOptions = provider->options();
+            providerOptions.setFlag(QAbstractFileIconProvider::DontUseCustomDirectoryIcons,
+                                    options.testFlag(QFileSystemModel::DontUseCustomDirectoryIcons));
+            provider->setOptions(providerOptions);
+        } else {
+            qWarning("Setting QFileSystemModel::DontUseCustomDirectoryIcons has no effect when no provider is used");
+        }
+    }
+}
+
+QFileSystemModel::Options QFileSystemModel::options() const
+{
+    QFileSystemModel::Options result;
+    result.setFlag(DontResolveSymlinks, !resolveSymlinks());
+#if QT_CONFIG(filesystemwatcher)
+    Q_D(const QFileSystemModel);
+    result.setFlag(DontWatchForChanges, !d->fileInfoGatherer.isWatching());
+#else
+    result.setFlag(DontWatchForChanges);
+#endif
+    if (auto provider = iconProvider()) {
+        result.setFlag(DontUseCustomDirectoryIcons,
+                       provider->options().testFlag(QAbstractFileIconProvider::DontUseCustomDirectoryIcons));
+    }
+    return result;
+}
+
+/*!
     Returns the path of the item stored in the model under the
     \a index given.
 */
@@ -1282,11 +1367,20 @@
     Q_D(const QFileSystemModel);
     QString fullPath = d->filePath(index);
     QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
-    if (dirNode->isSymLink() && d->fileInfoGatherer.resolveSymlinks()
+    if (dirNode->isSymLink()
+#if QT_CONFIG(filesystemwatcher)
+        && d->fileInfoGatherer.resolveSymlinks()
+#endif
         && d->resolvedSymLinks.contains(fullPath)
         && dirNode->isDir()) {
-        QFileInfo resolvedInfo(fullPath);
-        resolvedInfo = resolvedInfo.canonicalFilePath();
+        QFileInfo fullPathInfo(dirNode->fileInfo());
+        if (!dirNode->hasInformation())
+            fullPathInfo = QFileInfo(fullPath);
+        QString canonicalPath = fullPathInfo.canonicalFilePath();
+        auto *canonicalNode = d->node(fullPathInfo.canonicalFilePath(), false);
+        QFileInfo resolvedInfo = canonicalNode->fileInfo();
+        if (!canonicalNode->hasInformation())
+            resolvedInfo = QFileInfo(canonicalPath);
         if (resolvedInfo.exists())
             return resolvedInfo.filePath();
     }
@@ -1310,13 +1404,12 @@
         idx = idx.parent();
     }
     QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator()));
-#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
-    if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/'))
+#if !defined(Q_OS_WIN)
+    if ((fullPath.size() > 2) && fullPath[0] == u'/' && fullPath[1] == u'/')
         fullPath = fullPath.mid(1);
-#endif
-#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
-    if (fullPath.length() == 2 && fullPath.endsWith(QLatin1Char(':')))
-        fullPath.append(QLatin1Char('/'));
+#else
+    if (fullPath.length() == 2 && fullPath.endsWith(u':'))
+        fullPath.append(u'/');
 #endif
     return fullPath;
 }
@@ -1337,7 +1430,9 @@
     d->addNode(parentNode, name, QFileInfo());
     Q_ASSERT(parentNode->children.contains(name));
     QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
+#if QT_CONFIG(filesystemwatcher)
     node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
+#endif
     d->addVisibleFiles(parentNode, QStringList(name));
     return d->index(node);
 }
@@ -1348,12 +1443,7 @@
 QFile::Permissions QFileSystemModel::permissions(const QModelIndex &index) const
 {
     Q_D(const QFileSystemModel);
-    QFile::Permissions p = d->node(index)->permissions();
-    if (d->readOnly) {
-        p ^= (QFile::WriteOwner | QFile::WriteUser
-            | QFile::WriteGroup | QFile::WriteOther);
-    }
-    return p;
+    return d->node(index)->permissions();
 }
 
 /*!
@@ -1381,12 +1471,9 @@
 #else
     QString longNewPath = newPath;
 #endif
-    QDir newPathDir(longNewPath);
     //we remove .. and . from the given path if exist
-    if (!newPath.isEmpty()) {
+    if (!newPath.isEmpty())
         longNewPath = QDir::cleanPath(longNewPath);
-        newPathDir.setPath(longNewPath);
-    }
 
     d->setRootPath = true;
 
@@ -1397,14 +1484,23 @@
     if (d->rootDir.path() == longNewPath)
         return d->index(rootPath());
 
-    bool showDrives = (longNewPath.isEmpty() || longNewPath == d->myComputer());
-    if (!showDrives && !newPathDir.exists())
+    auto node = d->node(longNewPath);
+    QFileInfo newPathInfo;
+    if (node && node->hasInformation())
+        newPathInfo = node->fileInfo();
+    else
+        newPathInfo = QFileInfo(longNewPath);
+
+    bool showDrives = (longNewPath.isEmpty() || longNewPath == QFileSystemModelPrivate::myComputer());
+    if (!showDrives && !newPathInfo.exists())
         return d->index(rootPath());
 
     //We remove the watcher on the previous path
-    if (!rootPath().isEmpty() && rootPath() != QLatin1String(".")) {
+    if (!rootPath().isEmpty() && rootPath() != "."_L1) {
         //This remove the watcher for the old rootPath
+#if QT_CONFIG(filesystemwatcher)
         d->fileInfoGatherer.removePath(rootPath());
+#endif
         //This line "marks" the node as dirty, so the next fetchMore
         //call on the path will ask the gatherer to install a watcher again
         //But it doesn't re-fetch everything
@@ -1412,13 +1508,13 @@
     }
 
     // We have a new valid root path
-    d->rootDir = newPathDir;
+    d->rootDir = QDir(longNewPath);
     QModelIndex newRootIndex;
     if (showDrives) {
         // otherwise dir will become '.'
-        d->rootDir.setPath(QLatin1String(""));
+        d->rootDir.setPath(""_L1);
     } else {
-        newRootIndex = d->index(newPathDir.path());
+        newRootIndex = d->index(d->rootDir.path());
     }
     fetchMore(newRootIndex);
     emit rootPathChanged(longNewPath);
@@ -1455,20 +1551,26 @@
 /*!
     Sets the \a provider of file icons for the directory model.
 */
-void QFileSystemModel::setIconProvider(QFileIconProvider *provider)
+void QFileSystemModel::setIconProvider(QAbstractFileIconProvider *provider)
 {
     Q_D(QFileSystemModel);
+#if QT_CONFIG(filesystemwatcher)
     d->fileInfoGatherer.setIconProvider(provider);
+#endif
     d->root.updateIcon(provider, QString());
 }
 
 /*!
     Returns the file icon provider for this directory model.
 */
-QFileIconProvider *QFileSystemModel::iconProvider() const
+QAbstractFileIconProvider *QFileSystemModel::iconProvider() const
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_D(const QFileSystemModel);
     return d->fileInfoGatherer.iconProvider();
+#else
+    return 0;
+#endif
 }
 
 /*!
@@ -1484,9 +1586,11 @@
     Q_D(QFileSystemModel);
     if (d->filters == filters)
         return;
+    const bool changingCaseSensitivity =
+        filters.testFlag(QDir::CaseSensitive) != d->filters.testFlag(QDir::CaseSensitive);
     d->filters = filters;
-    // CaseSensitivity might have changed
-    setNameFilters(nameFilters());
+    if (changingCaseSensitivity)
+        d->rebuildNameFilterRegexps();
     d->forceSort = true;
     d->delayedSort();
 }
@@ -1509,20 +1613,30 @@
     \property QFileSystemModel::resolveSymlinks
     \brief Whether the directory model should resolve symbolic links
 
-    This is only relevant on operating systems that support symbolic links.
+    This is only relevant on Windows.
 
-    By default, this property is false.
+    By default, this property is \c true.
+
+    \sa QFileSystemModel::Options
 */
 void QFileSystemModel::setResolveSymlinks(bool enable)
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_D(QFileSystemModel);
     d->fileInfoGatherer.setResolveSymlinks(enable);
+#else
+    Q_UNUSED(enable);
+#endif
 }
 
 bool QFileSystemModel::resolveSymlinks() const
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_D(const QFileSystemModel);
     return d->fileInfoGatherer.resolveSymlinks();
+#else
+    return false;
+#endif
 }
 
 /*!
@@ -1532,7 +1646,7 @@
     If this property is set to false, the directory model will allow renaming, copying
     and deleting of files and directories.
 
-    This property is true by default
+    This property is \c true by default
 */
 void QFileSystemModel::setReadOnly(bool enable)
 {
@@ -1550,7 +1664,7 @@
     \property QFileSystemModel::nameFilterDisables
     \brief Whether files that don't pass the name filter are hidden or disabled
 
-    This property is true by default
+    This property is \c true by default
 */
 void QFileSystemModel::setNameFilterDisables(bool enable)
 {
@@ -1573,8 +1687,7 @@
 */
 void QFileSystemModel::setNameFilters(const QStringList &filters)
 {
-    // Prep the regexp's ahead of time
-#ifndef QT_NO_REGEXP
+#if QT_CONFIG(regularexpression)
     Q_D(QFileSystemModel);
 
     if (!d->bypassFilters.isEmpty()) {
@@ -1582,10 +1695,9 @@
         d->bypassFilters.clear();
         // We guarantee that rootPath will stick around
         QPersistentModelIndex root(index(rootPath()));
-        QModelIndexList persistantList = persistentIndexList();
-        for (int i = 0; i < persistantList.count(); ++i) {
-            QFileSystemModelPrivate::QFileSystemNode *node;
-            node = d->node(persistantList.at(i));
+        const QModelIndexList persistentList = persistentIndexList();
+        for (const auto &persistentIndex : persistentList) {
+            QFileSystemModelPrivate::QFileSystemNode *node = d->node(persistentIndex);
             while (node) {
                 if (d->bypassFilters.contains(node))
                     break;
@@ -1596,14 +1708,12 @@
         }
     }
 
-    d->nameFilters.clear();
-    const Qt::CaseSensitivity caseSensitive =
-        (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
-    for (int i = 0; i < filters.size(); ++i) {
-        d->nameFilters << QRegExp(filters.at(i), caseSensitive, QRegExp::Wildcard);
-    }
+    d->nameFilters = filters;
+    d->rebuildNameFilterRegexps();
     d->forceSort = true;
     d->delayedSort();
+#else
+    Q_UNUSED(filters);
 #endif
 }
 
@@ -1612,14 +1722,12 @@
 */
 QStringList QFileSystemModel::nameFilters() const
 {
+#if QT_CONFIG(regularexpression)
     Q_D(const QFileSystemModel);
-    QStringList filters;
-#ifndef QT_NO_REGEXP
-    for (int i = 0; i < d->nameFilters.size(); ++i) {
-         filters << d->nameFilters.at(i).pattern();
-    }
+    return d->nameFilters;
+#else
+    return QStringList();
 #endif
-    return filters;
 }
 
 /*!
@@ -1627,20 +1735,27 @@
 */
 bool QFileSystemModel::event(QEvent *event)
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_D(QFileSystemModel);
     if (event->type() == QEvent::LanguageChange) {
         d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
         return true;
     }
+#endif
     return QAbstractItemModel::event(event);
 }
 
-bool QFileSystemModel::rmdir(const QModelIndex &aindex) const
+bool QFileSystemModel::rmdir(const QModelIndex &aindex)
 {
     QString path = filePath(aindex);
-    QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
-    d->fileInfoGatherer.removePath(path);
-    return QDir().rmdir(path);
+    const bool success = QDir().rmdir(path);
+#if QT_CONFIG(filesystemwatcher)
+    if (success) {
+        QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
+        d->fileInfoGatherer.removePath(path);
+    }
+#endif
+    return success;
 }
 
 /*!
@@ -1652,37 +1767,41 @@
 void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
 {
     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
-    if (parentNode->children.count() == 0)
+    if (parentNode->children.size() == 0)
         return;
     QStringList toRemove;
-#if defined(Q_OS_SYMBIAN)
-    // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names.
-    QStringList newFiles;
-    for(int i = 0; i < files.size(); i++) {
-        newFiles << files.at(i).toLower();
+    QStringList newFiles = files;
+    std::sort(newFiles.begin(), newFiles.end());
+    for (auto i = parentNode->children.constBegin(), cend = parentNode->children.constEnd(); i != cend; ++i) {
+        QStringList::iterator iterator = std::lower_bound(newFiles.begin(), newFiles.end(), i.value()->fileName);
+        if ((iterator == newFiles.end()) || (i.value()->fileName < *iterator))
+            toRemove.append(i.value()->fileName);
     }
-#else
-    QStringList newFiles = files;
-#endif
-    qSort(newFiles.begin(), newFiles.end());
-    QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin();
-    while (i != parentNode->children.constEnd()) {
-        QStringList::iterator iterator;
-        iterator = qBinaryFind(newFiles.begin(), newFiles.end(),
-#if defined(Q_OS_SYMBIAN)
-                    i.value()->fileName.toLower());
-#else
-                    i.value()->fileName);
-#endif
-        if (iterator == newFiles.end()) {
-            toRemove.append(i.value()->fileName);
-        }
-        ++i;
-    }
-    for (int i = 0 ; i < toRemove.count() ; ++i )
+    for (int i = 0 ; i < toRemove.size() ; ++i )
         removeNode(parentNode, toRemove[i]);
 }
 
+#if defined(Q_OS_WIN)
+static QString volumeName(const QString &path)
+{
+    IShellItem *item = nullptr;
+    const QString native = QDir::toNativeSeparators(path);
+    HRESULT hr = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
+                                             nullptr, IID_IShellItem,
+                                             reinterpret_cast<void **>(&item));
+    if (FAILED(hr))
+        return QString();
+    LPWSTR name = nullptr;
+    hr = item->GetDisplayName(SIGDN_NORMALDISPLAY, &name);
+    if (FAILED(hr))
+        return QString();
+    QString result = QString::fromWCharArray(name);
+    CoTaskMemFree(name);
+    item->Release();
+    return result;
+}
+#endif // Q_OS_WIN
+
 /*!
     \internal
 
@@ -1694,21 +1813,17 @@
 {
     // In the common case, itemLocation == count() so check there first
     QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode);
-#ifndef QT_NO_FILESYSTEMWATCHER
+#if QT_CONFIG(filesystemwatcher)
     node->populate(info);
+#else
+    Q_UNUSED(info);
 #endif
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+#if defined(Q_OS_WIN)
     //The parentNode is "" so we are listing the drives
-    if (parentNode->fileName.isEmpty()) {
-        wchar_t name[MAX_PATH + 1];
-        //GetVolumeInformation requires to add trailing backslash
-        const QString nodeName = fileName + QLatin1String("\\");
-        BOOL success = ::GetVolumeInformation((wchar_t *)(nodeName.utf16()),
-                name, MAX_PATH + 1, NULL, 0, NULL, NULL, 0);
-        if (success && name[0])
-            node->volumeName = QString::fromWCharArray(name);
-    }
+    if (parentNode->fileName.isEmpty())
+        node->volumeName = volumeName(fileName);
 #endif
+    Q_ASSERT(!parentNode->children.contains(fileName));
     parentNode->children.insert(fileName, node);
     return node;
 }
@@ -1740,26 +1855,6 @@
         q->endRemoveRows();
 }
 
-/*
-    \internal
-    Helper functor used by addVisibleFiles()
-*/
-class QFileSystemModelVisibleFinder
-{
-public:
-    inline QFileSystemModelVisibleFinder(QFileSystemModelPrivate::QFileSystemNode *node, QFileSystemModelSorter *sorter) : parentNode(node), sorter(sorter) {}
-
-    bool operator()(const QString &, QString r) const
-    {
-        return sorter->compareNodes(parentNode->children.value(name), parentNode->children.value(r));
-    }
-
-    QString name;
-private:
-    QFileSystemModelPrivate::QFileSystemNode *parentNode;
-    QFileSystemModelSorter *sorter;
-};
-
 /*!
     \internal
 
@@ -1774,16 +1869,16 @@
     QModelIndex parent = index(parentNode);
     bool indexHidden = isHiddenByFilter(parentNode, parent);
     if (!indexHidden) {
-        q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1);
+        q->beginInsertRows(parent, parentNode->visibleChildren.size() , parentNode->visibleChildren.size() + newFiles.size() - 1);
     }
 
     if (parentNode->dirtyChildrenIndex == -1)
-        parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count();
+        parentNode->dirtyChildrenIndex = parentNode->visibleChildren.size();
 
-    for (int i = 0; i < newFiles.count(); ++i) {
-            parentNode->visibleChildren.append(newFiles.at(i));
-            parentNode->children[newFiles.at(i)]->isVisible = true;
-        }
+    for (const auto &newFile : newFiles) {
+        parentNode->visibleChildren.append(newFile);
+        parentNode->children.value(newFile)->isVisible = true;
+    }
     if (!indexHidden)
       q->endInsertRows();
 }
@@ -1805,7 +1900,7 @@
     if (!indexHidden)
         q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
                                        translateVisibleLocation(parentNode, vLocation));
-    parentNode->children[parentNode->visibleChildren.at(vLocation)]->isVisible = false;
+    parentNode->children.value(parentNode->visibleChildren.at(vLocation))->isVisible = false;
     parentNode->visibleChildren.removeAt(vLocation);
     if (!indexHidden)
         q->endRemoveRows();
@@ -1817,17 +1912,19 @@
     The thread has received new information about files,
     update and emit dataChanged if it has actually changed.
  */
-void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &updates)
+void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path,
+                                                   const QList<QPair<QString, QFileInfo>> &updates)
 {
+#if QT_CONFIG(filesystemwatcher)
     Q_Q(QFileSystemModel);
-    QVector<QString> rowsToUpdate;
+    QList<QString> rowsToUpdate;
     QStringList newFiles;
     QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false);
     QModelIndex parentIndex = index(parentNode);
-    for (int i = 0; i < updates.count(); ++i) {
-        QString fileName = updates.at(i).first;
+    for (const auto &update : updates) {
+        QString fileName = update.first;
         Q_ASSERT(!fileName.isEmpty());
-        QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second);
+        QExtendedInformation info = fileInfoGatherer.getInfo(update.second);
         bool previouslyHere = parentNode->children.contains(fileName);
         if (!previouslyHere) {
             addNode(parentNode, fileName, info.fileInfo());
@@ -1847,10 +1944,6 @@
             node->fileName = fileName;
         }
 
-        if (info.size() == -1 && !info.isSymLink()) {
-            removeNode(parentNode, fileName);
-            continue;
-        }
         if (*node != info ) {
             node->populate(info);
             bypassFilters.remove(node);
@@ -1873,11 +1966,10 @@
     }
 
     // bundle up all of the changed signals into as few as possible.
-    qSort(rowsToUpdate.begin(), rowsToUpdate.end());
+    std::sort(rowsToUpdate.begin(), rowsToUpdate.end());
     QString min;
     QString max;
-    for (int i = 0; i < rowsToUpdate.count(); ++i) {
-        QString value = rowsToUpdate.at(i);
+    for (const QString &value : std::as_const(rowsToUpdate)) {
         //##TODO is there a way to bundle signals with QString as the content of the list?
         /*if (min.isEmpty()) {
             min = value;
@@ -1895,26 +1987,37 @@
         int visibleMin = parentNode->visibleLocation(min);
         int visibleMax = parentNode->visibleLocation(max);
         if (visibleMin >= 0
-            && visibleMin < parentNode->visibleChildren.count()
+            && visibleMin < parentNode->visibleChildren.size()
             && parentNode->visibleChildren.at(visibleMin) == min
             && visibleMax >= 0) {
-            QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
-            QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
-            emit q->dataChanged(bottom, top);
+            // don't use NumColumns here, a subclass might override columnCount
+            const int lastColumn = q->columnCount(parentIndex) - 1;
+            const QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMin),
+                                             QFileSystemModelPrivate::NameColumn, parentIndex);
+            const QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMax),
+                                                lastColumn, parentIndex);
+            // We document that emitting dataChanged with indexes that don't have the
+            // same parent is undefined behavior.
+            Q_ASSERT(bottom.parent() == top.parent());
+            emit q->dataChanged(top, bottom);
         }
 
         /*min = QString();
         max = QString();*/
     }
 
-    if (newFiles.count() > 0) {
+    if (newFiles.size() > 0) {
         addVisibleFiles(parentNode, newFiles);
     }
 
-    if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) {
+    if (newFiles.size() > 0 || (sortColumn != 0 && rowsToUpdate.size() > 0)) {
         forceSort = true;
         delayedSort();
     }
+#else
+    Q_UNUSED(path);
+    Q_UNUSED(updates);
+#endif // filesystemwatcher
 }
 
 /*!
@@ -1925,35 +2028,77 @@
     resolvedSymLinks[fileName] = resolvedName;
 }
 
+#if QT_CONFIG(filesystemwatcher) && defined(Q_OS_WIN)
+// Remove file system watchers at/below the index and return a list of previously
+// watched files. This should be called prior to operations like rename/remove
+// which might fail due to watchers on platforms like Windows. The watchers
+// should be restored on failure.
+QStringList QFileSystemModelPrivate::unwatchPathsAt(const QModelIndex &index)
+{
+    const QFileSystemModelPrivate::QFileSystemNode *indexNode = node(index);
+    if (indexNode == nullptr)
+        return QStringList();
+    const Qt::CaseSensitivity caseSensitivity = indexNode->caseSensitive()
+        ? Qt::CaseSensitive : Qt::CaseInsensitive;
+    const QString path = indexNode->fileInfo().absoluteFilePath();
+
+    QStringList result;
+    const auto filter = [path, caseSensitivity] (const QString &watchedPath)
+    {
+        const int pathSize = path.size();
+        if (pathSize == watchedPath.size()) {
+            return path.compare(watchedPath, caseSensitivity) == 0;
+        } else if (watchedPath.size() > pathSize) {
+            return watchedPath.at(pathSize) == u'/'
+                && watchedPath.startsWith(path, caseSensitivity);
+        }
+        return false;
+    };
+
+    const QStringList &watchedFiles = fileInfoGatherer.watchedFiles();
+    std::copy_if(watchedFiles.cbegin(), watchedFiles.cend(),
+                 std::back_inserter(result), filter);
+
+    const QStringList &watchedDirectories = fileInfoGatherer.watchedDirectories();
+    std::copy_if(watchedDirectories.cbegin(), watchedDirectories.cend(),
+                 std::back_inserter(result), filter);
+
+    fileInfoGatherer.unwatchPaths(result);
+    return result;
+}
+#endif // filesystemwatcher && Q_OS_WIN
+
+QFileSystemModelPrivate::QFileSystemModelPrivate() = default;
+
+QFileSystemModelPrivate::~QFileSystemModelPrivate() = default;
+
 /*!
     \internal
 */
 void QFileSystemModelPrivate::init()
 {
     Q_Q(QFileSystemModel);
-    qRegisterMetaType<QList<QPair<QString,QFileInfo> > >("QList<QPair<QString,QFileInfo> >");
+
+    delayedSortTimer.setSingleShot(true);
+
+    qRegisterMetaType<QList<QPair<QString, QFileInfo>>>();
+#if QT_CONFIG(filesystemwatcher)
     q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)),
                q, SLOT(_q_directoryChanged(QString,QStringList)));
-    q->connect(&fileInfoGatherer, SIGNAL(updates(QString,QList<QPair<QString,QFileInfo> >)),
-            q, SLOT(_q_fileSystemChanged(QString,QList<QPair<QString,QFileInfo> >)));
+    q->connect(&fileInfoGatherer, SIGNAL(updates(QString,QList<std::pair<QString,QFileInfo>>)), q,
+               SLOT(_q_fileSystemChanged(QString,QList<std::pair<QString,QFileInfo>>)));
     q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)),
             q, SLOT(_q_resolvedName(QString,QString)));
     q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)),
                q, SIGNAL(directoryLoaded(QString)));
+#endif // filesystemwatcher
     q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
-
-    QHash<int, QByteArray> roles = q->roleNames();
-    roles.insertMulti(QFileSystemModel::FileIconRole, "fileIcon"); // == Qt::decoration
-    roles.insert(QFileSystemModel::FilePathRole, "filePath");
-    roles.insert(QFileSystemModel::FileNameRole, "fileName");
-    roles.insert(QFileSystemModel::FilePermissions, "filePermissions");
-    q->setRoleNames(roles);
 }
 
 /*!
     \internal
 
-    Returns false if node doesn't pass the filters otherwise true
+    Returns \c false if node doesn't pass the filters otherwise true
 
     QDir::Modified is not supported
     QDir::Drives is not supported
@@ -1978,13 +2123,12 @@
     const bool hideHidden        = !(filters & QDir::Hidden);
     const bool hideSystem        = !(filters & QDir::System);
     const bool hideSymlinks      = (filters & QDir::NoSymLinks);
-    const bool hideDot           = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
-    const bool hideDotDot        = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
+    const bool hideDot           = (filters & QDir::NoDot);
+    const bool hideDotDot        = (filters & QDir::NoDotDot);
 
-    // Note that we match the behavior of entryList and not QFileInfo on this and this
-    // incompatibility won't be fixed until Qt 5 at least
-    bool isDot    = (node->fileName == QLatin1String("."));
-    bool isDotDot = (node->fileName == QLatin1String(".."));
+    // Note that we match the behavior of entryList and not QFileInfo on this.
+    bool isDot    = (node->fileName == "."_L1);
+    bool isDotDot = (node->fileName == ".."_L1);
     if (   (hideHidden && !(isDot || isDotDot) && node->isHidden())
         || (hideSystem && node->isSystem())
         || (hideDirs && node->isDir())
@@ -2003,28 +2147,47 @@
 /*
     \internal
 
-    Returns true if node passes the name filters and should be visible.
+    Returns \c true if node passes the name filters and should be visible.
  */
 bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const
 {
-#ifndef QT_NO_REGEXP
+#if QT_CONFIG(regularexpression)
     if (nameFilters.isEmpty())
         return true;
 
     // Check the name regularexpression filters
     if (!(node->isDir() && (filters & QDir::AllDirs))) {
-        for (int i = 0; i < nameFilters.size(); ++i) {
-            if (nameFilters.at(i).exactMatch(node->fileName))
-                return true;
-        }
-        return false;
+        const auto matchesNodeFileName = [node](const QRegularExpression &re)
+        {
+            return node->fileName.contains(re);
+        };
+        return std::any_of(nameFiltersRegexps.begin(),
+                           nameFiltersRegexps.end(),
+                           matchesNodeFileName);
     }
+#else
+    Q_UNUSED(node);
 #endif
     return true;
 }
 
+#if QT_CONFIG(regularexpression)
+void QFileSystemModelPrivate::rebuildNameFilterRegexps()
+{
+    nameFiltersRegexps.clear();
+    nameFiltersRegexps.reserve(nameFilters.size());
+    const auto cs = (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+    const auto convertWildcardToRegexp = [cs](const QString &nameFilter)
+    {
+        return QRegularExpression::fromWildcard(nameFilter, cs);
+    };
+    std::transform(nameFilters.constBegin(),
+                   nameFilters.constEnd(),
+                   std::back_inserter(nameFiltersRegexps),
+                   convertWildcardToRegexp);
+}
+#endif
+
 QT_END_NAMESPACE
 
 #include "moc_qfilesystemmodel.cpp"
-
-#endif // QT_NO_FILESYSTEMMODEL
--- a/libgui/languages/build_ts/octave-qt/qfontdialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qfontdialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,56 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qwindowdefs.h"
+#include "qfontdialog.h"
 
-#ifndef QT_NO_FONTDIALOG
-
-#include "qfontdialog.h"
 #include "qfontdialog_p.h"
 
 #include <qapplication.h>
 #include <qcheckbox.h>
 #include <qcombobox.h>
 #include <qevent.h>
-#include <qfontdatabase.h>
 #include <qgroupbox.h>
 #include <qlabel.h>
 #include <qlayout.h>
@@ -62,14 +21,13 @@
 #include <qlistview.h>
 #include <qstringlistmodel.h>
 #include <qvalidator.h>
+#include <private/qfontdatabase_p.h>
 #include <private/qdialog_p.h>
 #include <private/qfont_p.h>
 
-#if defined(Q_WS_S60)
-#include <QtGui/qdesktopwidget.h>
-#endif
+QT_BEGIN_NAMESPACE
 
-QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
 
 class QFontListView : public QListView
 {
@@ -92,7 +50,7 @@
         int row = QListView::currentIndex().row();
         return row < 0 ? QString() : model()->stringList().at(row);
     }
-    void currentChanged(const QModelIndex &current, const QModelIndex &previous) {
+    void currentChanged(const QModelIndex &current, const QModelIndex &previous) override {
         QListView::currentChanged(current, previous);
         if (current.isValid())
             emit highlighted(current.row());
@@ -111,12 +69,23 @@
     setEditTriggers(NoEditTriggers);
 }
 
-static const Qt::WindowFlags DefaultWindowFlags =
-        Qt::Dialog | Qt::WindowSystemMenuHint;
+static const Qt::WindowFlags qfd_DefaultWindowFlags =
+        Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
+
+QFontDialogPrivate::QFontDialogPrivate()
+    : writingSystem(QFontDatabase::Any),
+      options(QFontDialogOptions::create())
+{
+}
+
+QFontDialogPrivate::~QFontDialogPrivate()
+{
+}
 
 /*!
   \class QFontDialog
   \ingroup standard-dialogs
+  \inmodule QtWidgets
 
   \brief The QFontDialog class provides a dialog widget for selecting a font.
 
@@ -125,16 +94,16 @@
 
   Examples:
 
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 0
+  \snippet code/src_gui_dialogs_qfontdialog.cpp 0
 
     The dialog can also be used to set a widget's font directly:
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 1
+  \snippet code/src_gui_dialogs_qfontdialog.cpp 1
   If the user clicks OK the font they chose will be used for myWidget,
   and if they click Cancel the original font is used.
 
-  \image plastique-fontdialog.png A font dialog in the Plastique widget style.
+  \image fusion-fontdialog.png A font dialog in the Fusion widget style.
 
-  \sa QFont, QFontInfo, QFontMetrics, QColorDialog, QFileDialog, QPrintDialog,
+  \sa QFont, QFontInfo, QFontMetrics, QColorDialog, QFileDialog,
       {Standard Dialogs Example}
 */
 
@@ -150,7 +119,7 @@
     \sa getFont()
 */
 QFontDialog::QFontDialog(QWidget *parent)
-    : QDialog(*new QFontDialogPrivate, parent, DefaultWindowFlags)
+    : QDialog(*new QFontDialogPrivate, parent, qfd_DefaultWindowFlags)
 {
     Q_D(QFontDialog);
     d->init();
@@ -163,10 +132,8 @@
     \a initial font.
 */
 QFontDialog::QFontDialog(const QFont &initial, QWidget *parent)
-    : QDialog(*new QFontDialogPrivate, parent, DefaultWindowFlags)
+    : QFontDialog(parent)
 {
-    Q_D(QFontDialog);
-    d->init();
     setCurrentFont(initial);
 }
 
@@ -174,11 +141,6 @@
 {
     Q_Q(QFontDialog);
 
-#ifdef Q_WS_MAC
-    nativeDialogInUse = false;
-    delegate = 0;
-#endif
-
     q->setSizeGripEnabled(true);
     q->setWindowTitle(QFontDialog::tr("Select Font"));
 
@@ -232,7 +194,7 @@
     sampleEdit->setAlignment(Qt::AlignCenter);
     // Note that the sample text is *not* translated with tr(), as the
     // characters used depend on the charset encoding.
-    sampleEdit->setText(QLatin1String("AaBbYyZz"));
+    sampleEdit->setText("AaBbYyZz"_L1);
     hbox->addWidget(sampleEdit);
 
     writingSystemCombo = new QComboBox(q);
@@ -264,8 +226,10 @@
     }
 
     updateFamilies();
-    if (familyList->count() != 0)
+    if (familyList->count() != 0) {
         familyList->setCurrentItem(0);
+        sizeList->setCurrentItem(0);
+    }
 
     // grid layout
     QGridLayout *mainGrid = new QGridLayout(q);
@@ -278,7 +242,7 @@
        mainGrid->setColumnMinimumWidth(3, spacing);
 
        int margin = 0;
-       mainGrid->getContentsMargins(0, 0, 0, &margin);
+       mainGrid->getContentsMargins(nullptr, nullptr, nullptr, &margin);
 
        mainGrid->setRowMinimumHeight(3, margin);
        mainGrid->setRowMinimumHeight(6, 2);
@@ -319,13 +283,7 @@
     buttonBox->addButton(QDialogButtonBox::Cancel);
     QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
 
-#if defined(Q_WS_WINCE)
-    q->resize(180, 120);
-#elif defined(Q_WS_S60)
-    q->resize(QApplication::desktop()->availableGeometry(QCursor::pos()).size());
-#else
     q->resize(500, 360);
-#endif // Q_WS_WINCE
 
     sizeEdit->installEventFilter(q);
     familyList->installEventFilter(q);
@@ -334,6 +292,7 @@
 
     familyList->setFocus();
     retranslateStrings();
+    sampleEdit->setObjectName("qt_fontDialog_sampleEdit"_L1);
 }
 
 /*!
@@ -343,32 +302,25 @@
 
 QFontDialog::~QFontDialog()
 {
-#ifdef Q_WS_MAC
-    Q_D(QFontDialog);
-    if (d->delegate) {
-        d->closeCocoaFontPanel();
-        return;
-    }
-#endif
 }
 
 /*!
   Executes a modal font dialog and returns a font.
 
-  If the user clicks \gui OK, the selected font is returned. If the user
-  clicks \gui Cancel, the \a initial font is returned.
+  If the user clicks \uicontrol OK, the selected font is returned. If the user
+  clicks \uicontrol Cancel, the \a initial font is returned.
 
   The dialog is constructed with the given \a parent and the options specified
   in \a options. \a title is shown as the window title of the dialog and  \a
   initial is the initially selected font. If the \a ok parameter is not-null,
-  the value it refers to is set to true if the user clicks \gui OK, and set to
-  false if the user clicks \gui Cancel.
+  the value it refers to is set to true if the user clicks \uicontrol OK, and set to
+  false if the user clicks \uicontrol Cancel.
 
   Examples:
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 2
+  \snippet code/src_gui_dialogs_qfontdialog.cpp 2
 
     The dialog can also be used to set a widget's font directly:
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 3
+  \snippet code/src_gui_dialogs_qfontdialog.cpp 3
   In this example, if the user clicks OK the font they chose will be
   used, and if they click Cancel the original font is used.
 
@@ -384,36 +336,19 @@
 
 /*!
     \overload
-    \since 4.5
-*/
-QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title)
-{
-    return QFontDialogPrivate::getFont(ok, initial, parent, title, 0);
-}
-
-/*!
-    \overload
-*/
-QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent)
-{
-    return QFontDialogPrivate::getFont(ok, initial, parent, QString(), 0);
-}
-
-/*!
-    \overload
 
   Executes a modal font dialog and returns a font.
 
-  If the user clicks \gui OK, the selected font is returned. If the user
-  clicks \gui Cancel, the Qt default font is returned.
+  If the user clicks \uicontrol OK, the selected font is returned. If the user
+  clicks \uicontrol Cancel, the Qt default font is returned.
 
   The dialog is constructed with the given \a parent.
   If the \a ok parameter is not-null, the value it refers to is set
-  to true if the user clicks \gui OK, and false if the user clicks
-  \gui Cancel.
+  to true if the user clicks \uicontrol OK, and false if the user clicks
+  \uicontrol Cancel.
 
   Example:
-  \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 4
+  \snippet code/src_gui_dialogs_qfontdialog.cpp 4
 
   \warning Do not delete \a parent during the execution of the dialog.
            If you want to do this, you should create the dialog
@@ -422,7 +357,7 @@
 QFont QFontDialog::getFont(bool *ok, QWidget *parent)
 {
     QFont initial;
-    return QFontDialogPrivate::getFont(ok, initial, parent, QString(), 0);
+    return QFontDialogPrivate::getFont(ok, initial, parent, QString(), { });
 }
 
 QFont QFontDialogPrivate::getFont(bool *ok, const QFont &initial, QWidget *parent,
@@ -455,7 +390,7 @@
 {
     Q_D(QFontDialog);
     if (e->type() == QEvent::KeyPress) {
-        QKeyEvent *k = (QKeyEvent *)e;
+        QKeyEvent *k = static_cast<QKeyEvent *>(e);
         if (o == d->sizeEdit &&
         (k->key() == Qt::Key_Up ||
              k->key() == Qt::Key_Down ||
@@ -463,10 +398,10 @@
          k->key() == Qt::Key_PageDown)) {
 
             int ci = d->sizeList->currentItem();
-            ()QApplication::sendEvent(d->sizeList, k);
+            QCoreApplication::sendEvent(d->sizeList, k);
 
             if (ci != d->sizeList->currentItem()
-                    && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, this))
+                    && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, this))
                 d->sizeEdit->selectAll();
             return true;
         } else if ((o == d->familyList || o == d->styleList) &&
@@ -476,7 +411,7 @@
             return true;
         }
     } else if (e->type() == QEvent::FocusIn
-               && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, this)) {
+               && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, this)) {
         if (o == d->familyList)
             d->familyEdit->selectAll();
         else if (o == d->styleList)
@@ -489,6 +424,21 @@
     return QDialog::eventFilter(o, e);
 }
 
+void QFontDialogPrivate::initHelper(QPlatformDialogHelper *h)
+{
+    Q_Q(QFontDialog);
+    auto *fontDialogHelper = static_cast<QPlatformFontDialogHelper *>(h);
+    fontDialogHelper->setOptions(options);
+    fontDialogHelper->setCurrentFont(q->currentFont());
+    QObject::connect(h, SIGNAL(currentFontChanged(QFont)), q, SIGNAL(currentFontChanged(QFont)));
+    QObject::connect(h, SIGNAL(fontSelected(QFont)), q, SIGNAL(fontSelected(QFont)));
+}
+
+void QFontDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
+{
+    options->setWindowTitle(q_func()->windowTitle());
+}
+
 /*
     Updates the contents of the "font family" list box. This
     function can be reimplemented if you have special requirements.
@@ -500,7 +450,26 @@
 
     enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 };
 
-    QStringList familyNames = fdb.families(writingSystem);
+    const QFontDialog::FontDialogOptions scalableMask = (QFontDialog::ScalableFonts | QFontDialog::NonScalableFonts);
+    const QFontDialog::FontDialogOptions spacingMask = (QFontDialog::ProportionalFonts | QFontDialog::MonospacedFonts);
+    const QFontDialog::FontDialogOptions options = q->options();
+
+    QStringList familyNames;
+    const auto families = QFontDatabase::families(writingSystem);
+    for (const QString &family : families) {
+        if (QFontDatabase::isPrivateFamily(family))
+            continue;
+
+        if ((options & scalableMask) && (options & scalableMask) != scalableMask) {
+            if (bool(options & QFontDialog::ScalableFonts) != QFontDatabase::isSmoothlyScalable(family))
+                continue;
+        }
+        if ((options & spacingMask) && (options & spacingMask) != spacingMask) {
+            if (bool(options & QFontDialog::MonospacedFonts) != QFontDatabase::isFixedPitch(family))
+                continue;
+        }
+        familyNames << family;
+    }
 
     familyList->model()->setStringList(familyNames);
 
@@ -511,12 +480,12 @@
     QFont f;
 
     // ##### do the right thing for a list of family names in the font.
-    QFontDatabase::parseFontName(family, foundryName1, familyName1);
+    QFontDatabasePrivate::parseFontName(family, foundryName1, familyName1);
 
     QStringList::const_iterator it = familyNames.constBegin();
     int i = 0;
     for(; it != familyNames.constEnd(); ++it, ++i) {
-        QFontDatabase::parseFontName(*it, foundryName2, familyName2);
+        QFontDatabasePrivate::parseFontName(*it, foundryName2, familyName2);
 
         //try to match...
         if (familyName1 == familyName2) {
@@ -531,9 +500,9 @@
 
         //and try some fall backs
         match_t type = MATCH_NONE;
-        if (bestFamilyType <= MATCH_NONE && familyName2 == f.lastResortFamily())
+        if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica"))
             type = MATCH_LAST_RESORT;
-        if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.family())
+        if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().first())
             type = MATCH_APP;
         // ### add fallback for writingSystem
         if (type != MATCH_NONE) {
@@ -547,7 +516,7 @@
     else
         familyList->setCurrentItem(0);
     familyEdit->setText(familyList->currentText());
-    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
             && familyList->hasFocus())
         familyEdit->selectAll();
 
@@ -561,7 +530,7 @@
 void QFontDialogPrivate::updateStyles()
 {
     Q_Q(QFontDialog);
-    QStringList styles = fdb.styles(familyList->currentText());
+    QStringList styles = QFontDatabase::styles(familyList->currentText());
     styleList->model()->setStringList(styles);
 
     if (styles.isEmpty()) {
@@ -574,7 +543,7 @@
             QString cstyle = style;
 
         redo:
-            for (int i = 0; i < (int)styleList->count(); i++) {
+            for (int i = 0; i < static_cast<int>(styleList->count()); i++) {
                 if (cstyle == styleList->text(i)) {
                      styleList->setCurrentItem(i);
                      found = true;
@@ -582,12 +551,20 @@
                  }
             }
             if (!found && first) {
-                if (cstyle.contains(QLatin1String("Italic"))) {
-                    cstyle.replace(QLatin1String("Italic"), QLatin1String("Oblique"));
+                if (cstyle.contains("Italic"_L1)) {
+                    cstyle.replace("Italic"_L1, "Oblique"_L1);
                     first = false;
                     goto redo;
-                } else if (cstyle.contains(QLatin1String("Oblique"))) {
-                    cstyle.replace(QLatin1String("Oblique"), QLatin1String("Italic"));
+                } else if (cstyle.contains("Oblique"_L1)) {
+                    cstyle.replace("Oblique"_L1, "Italic"_L1);
+                    first = false;
+                    goto redo;
+                } else if (cstyle.contains("Regular"_L1)) {
+                    cstyle.replace("Regular"_L1, "Normal"_L1);
+                    first = false;
+                    goto redo;
+                } else if (cstyle.contains("Normal"_L1)) {
+                    cstyle.replace("Normal"_L1, "Regular"_L1);
                     first = false;
                     goto redo;
                 }
@@ -599,11 +576,11 @@
         }
 
         styleEdit->setText(styleList->currentText());
-        if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+        if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
                 && styleList->hasFocus())
             styleEdit->selectAll();
 
-        smoothScalable = fdb.isSmoothlyScalable(familyList->currentText(), styleList->currentText());
+        smoothScalable = QFontDatabase::isSmoothlyScalable(familyList->currentText(), styleList->currentText());
     }
 
     updateSizes();
@@ -620,30 +597,27 @@
     Q_Q(QFontDialog);
 
     if (!familyList->currentText().isEmpty()) {
-        QList<int> sizes = fdb.pointSizes(familyList->currentText(), styleList->currentText());
+        QList<int> sizes = QFontDatabase::pointSizes(familyList->currentText(), styleList->currentText());
 
         int i = 0;
         int current = -1;
         QStringList str_sizes;
+        str_sizes.reserve(sizes.size());
         for(QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); ++it) {
             str_sizes.append(QString::number(*it));
-            if (current == -1 && *it >= size)
+            if (current == -1 && *it == size)
                 current = i;
             ++i;
         }
         sizeList->model()->setStringList(str_sizes);
-        if (current == -1) {
-            // we request a size bigger than the ones in the list, select the biggest one
-            current = sizeList->count() - 1;
-        }
-        sizeList->setCurrentItem(current);
+        if (current != -1)
+            sizeList->setCurrentItem(current);
 
-        sizeEdit->blockSignals(true);
+        const QSignalBlocker blocker(sizeEdit);
         sizeEdit->setText((smoothScalable ? QString::number(size) : sizeList->currentText()));
-        if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+        if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
                 && sizeList->hasFocus())
             sizeEdit->selectAll();
-        sizeEdit->blockSignals(false);
     } else {
         sizeEdit->clear();
     }
@@ -655,7 +629,7 @@
 {
     // compute new font
     int pSize = sizeEdit->text().toInt();
-    QFont newFont(fdb.font(familyList->currentText(), style, pSize));
+    QFont newFont(QFontDatabase::font(familyList->currentText(), style, pSize));
     newFont.setStrikeOut(strikeout->isChecked());
     newFont.setUnderline(underline->isChecked());
 
@@ -680,7 +654,7 @@
 void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
 {
     writingSystem = QFontDatabase::WritingSystem(index);
-    sampleEdit->setText(fdb.writingSystemSample(writingSystem));
+    sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem));
     updateFamilies();
 }
 
@@ -692,7 +666,7 @@
     Q_Q(QFontDialog);
     family = familyList->text(i);
     familyEdit->setText(family);
-    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
             && familyList->hasFocus())
         familyEdit->selectAll();
 
@@ -709,7 +683,7 @@
     Q_Q(QFontDialog);
     QString s = styleList->text(index);
     styleEdit->setText(s);
-    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
             && styleList->hasFocus())
         styleEdit->selectAll();
 
@@ -728,7 +702,7 @@
     Q_Q(QFontDialog);
     QString s = sizeList->text(index);
     sizeEdit->setText(s);
-    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+    if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, nullptr, q)
             && sizeEdit->hasFocus())
         sizeEdit->selectAll();
 
@@ -756,9 +730,11 @@
             if (sizeList->text(i).toInt() >= this->size)
                 break;
         }
-        sizeList->blockSignals(true);
-        sizeList->setCurrentItem(i);
-        sizeList->blockSignals(false);
+        const QSignalBlocker blocker(sizeList);
+        if (sizeList->text(i).toInt() == this->size)
+            sizeList->setCurrentItem(i);
+        else
+            sizeList->clearSelection();
     }
     _q_updateSample();
 }
@@ -768,11 +744,7 @@
     familyAccel->setText(QFontDialog::tr("&Font"));
     styleAccel->setText(QFontDialog::tr("Font st&yle"));
     sizeAccel->setText(QFontDialog::tr("&Size"));
-#ifndef Q_WS_S60
-    // Removed the title due to lack of screen estate in small S60 screen.
-    // The effects are descriptive without a title (strikeout, underline).
     effects->setTitle(QFontDialog::tr("Effects"));
-#endif
     strikeout->setText(QFontDialog::tr("Stri&keout"));
     underline->setText(QFontDialog::tr("&Underline"));
     sample->setTitle(QFontDialog::tr("Sample"));
@@ -808,8 +780,8 @@
 void QFontDialog::setCurrentFont(const QFont &font)
 {
     Q_D(QFontDialog);
-    d->family = font.family();
-    d->style = d->fdb.styleString(font);
+    d->family = font.families().value(0);
+    d->style = QFontDatabase::styleString(font);
     d->size = font.pointSize();
     if (d->size == -1) {
         QFontInfo fi(font);
@@ -819,10 +791,10 @@
     d->underline->setChecked(font.underline());
     d->updateFamilies();
 
-#ifdef Q_WS_MAC
-    if (d->delegate)
-        QFontDialogPrivate::setFont(d->delegate, font);
-#endif
+    if (d->nativeDialogInUse) {
+        if (QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
+            helper->setCurrentFont(font);
+    }
 }
 
 /*!
@@ -835,11 +807,16 @@
 QFont QFontDialog::currentFont() const
 {
     Q_D(const QFontDialog);
+
+    if (d->nativeDialogInUse) {
+        if (const QPlatformFontDialogHelper *helper = d->platformFontDialogHelper())
+            return helper->currentFont();
+    }
     return d->sampleEdit->font();
 }
 
 /*!
-    Returns the font that the user selected by clicking the \gui{OK}
+    Returns the font that the user selected by clicking the \uicontrol{OK}
     or equivalent button.
 
     \note This font is not always the same as the font held by the
@@ -859,10 +836,20 @@
     This enum specifies various options that affect the look and feel
     of a font dialog.
 
-    \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
+    For instance, it allows to specify which type of font should be
+    displayed. If none are specified all fonts available will be listed.
+
+    Note that the font filtering options might not be supported on some
+    platforms (e.g. Mac). They are always supported by the non native
+    dialog (used on Windows or Linux).
+
+    \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
     \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's
-                               native font panel. (Currently, the native dialog is never used,
-                               but this is likely to change in future Qt releases.)
+                               native font panel.
+    \value ScalableFonts Show scalable fonts
+    \value NonScalableFonts Show non scalable fonts
+    \value MonospacedFonts Show monospaced fonts
+    \value ProportionalFonts Show proportional fonts
 
     \sa options, setOption(), testOption()
 */
@@ -875,13 +862,13 @@
 */
 void QFontDialog::setOption(FontDialogOption option, bool on)
 {
-    Q_D(QFontDialog);
-    if (!(d->opts & option) != !on)
-        setOptions(d->opts ^ option);
+    const QFontDialog::FontDialogOptions previousOptions = options();
+    if (!(previousOptions & option) != !on)
+        setOptions(previousOptions ^ option);
 }
 
 /*!
-    Returns true if the given \a option is enabled; otherwise, returns
+    Returns \c true if the given \a option is enabled; otherwise, returns
     false.
 
     \sa options, setOption()
@@ -889,7 +876,7 @@
 bool QFontDialog::testOption(FontDialogOption option) const
 {
     Q_D(const QFontDialog);
-    return (d->opts & option) != 0;
+    return d->options->testOption(static_cast<QFontDialogOptions::FontDialogOption>(option));
 }
 
 /*!
@@ -909,28 +896,21 @@
 {
     Q_D(QFontDialog);
 
-    FontDialogOptions changed = (options ^ d->opts);
-    if (!changed)
+    if (QFontDialog::options() == options)
         return;
 
-    d->opts = options;
+    d->options->setOptions(QFontDialogOptions::FontDialogOptions(int(options)));
     d->buttonBox->setVisible(!(options & NoButtons));
 }
 
 QFontDialog::FontDialogOptions QFontDialog::options() const
 {
     Q_D(const QFontDialog);
-    return d->opts;
+    return QFontDialog::FontDialogOptions(int(d->options->options()));
 }
 
-#ifdef Q_WS_MAC
-// can only have one Cocoa font panel active
-bool QFontDialogPrivate::sharedFontPanelAvailable = true;
-#endif
-
 /*!
     \since 4.5
-    \overload
 
     Opens the dialog and connects its fontSelected() signal to the slot specified
     by \a receiver and \a member.
@@ -980,23 +960,32 @@
 */
 void QFontDialog::setVisible(bool visible)
 {
-    if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
+    // will call QFontDialogPrivate::setVisible
+    QDialog::setVisible(visible);
+}
+
+/*!
+    \internal
+
+    The implementation of QFontDialog::setVisible() has to live here so that the call
+    to hide() in ~QDialog calls this function; it wouldn't call the override of
+    QDialog::setVisible().
+*/
+void QFontDialogPrivate::setVisible(bool visible)
+{
+    Q_Q(QFontDialog);
+    if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
         return;
-#ifdef Q_WS_MAC
-    Q_D(QFontDialog);
-    if (d->canBeNativeDialog()){
-        if (d->setVisible_sys(visible)){
-            d->nativeDialogInUse = true;
-            // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
-            // updates the state correctly, but skips showing the non-native version:
-            setAttribute(Qt::WA_DontShowOnScreen, true);
-        } else {
-            d->nativeDialogInUse = false;
-            setAttribute(Qt::WA_DontShowOnScreen, false);
-        }
+    if (canBeNativeDialog())
+        setNativeDialogVisible(visible);
+    if (nativeDialogInUse) {
+        // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+        // updates the state correctly, but skips showing the non-native version:
+        q->setAttribute(Qt::WA_DontShowOnScreen, true);
+    } else {
+        q->setAttribute(Qt::WA_DontShowOnScreen, false);
     }
-#endif // Q_WS_MAC
-    QDialog::setVisible(visible);
+    QDialogPrivate::setVisible(visible);
 }
 
 /*!
@@ -1009,11 +998,10 @@
 void QFontDialog::done(int result)
 {
     Q_D(QFontDialog);
-    QDialog::done(result);
     if (result == Accepted) {
         // We check if this is the same font we had before, if so we emit currentFontChanged
         QFont selectedFont = currentFont();
-        if(selectedFont != d->selectedFont)
+        if (selectedFont != d->selectedFont)
             emit(currentFontChanged(selectedFont));
         d->selectedFont = selectedFont;
         emit fontSelected(d->selectedFont);
@@ -1022,56 +1010,29 @@
     if (d->receiverToDisconnectOnClose) {
         disconnect(this, SIGNAL(fontSelected(QFont)),
                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
-        d->receiverToDisconnectOnClose = 0;
+        d->receiverToDisconnectOnClose = nullptr;
     }
     d->memberToDisconnectOnClose.clear();
+    QDialog::done(result);
 }
 
-#ifdef Q_WS_MAC
-bool QFontDialogPrivate::canBeNativeDialog()
+bool QFontDialogPrivate::canBeNativeDialog() const
 {
-    Q_Q(QFontDialog);
+    // Don't use Q_Q here! This function is called from ~QDialog,
+    // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
+    const QDialog * const q = static_cast<const QDialog*>(q_ptr);
     if (nativeDialogInUse)
         return true;
-    if (q->testAttribute(Qt::WA_DontShowOnScreen))
-        return false;
-    if (opts & QFontDialog::DontUseNativeDialog)
+    if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+        || q->testAttribute(Qt::WA_DontShowOnScreen)
+        || (options->options() & QFontDialog::DontUseNativeDialog)) {
         return false;
-
-    QLatin1String staticName(QFontDialog::staticMetaObject.className());
-    QLatin1String dynamicName(q->metaObject()->className());
-    return (staticName == dynamicName);
-}
-#endif // Q_WS_MAC
-
-/*!
-    \fn QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget* parent, const char* name)
-    \since 4.5
-
-    Call getFont(\a ok, \a initial, \a parent) instead.
+    }
 
-    \warning Do not delete \a parent during the execution of the dialog.
-             If you want to do this, you should create the dialog
-             yourself using one of the QFontDialog constructors.
-
-    The \a name parameter is ignored.
-*/
-
-/*!
-    \fn QFont QFontDialog::getFont(bool *ok, QWidget* parent, const char* name)
-
-    Call getFont(\a ok, \a parent) instead.
-
-  \warning Do not delete \a parent during the execution of the dialog.
-           If you want to do this, you should create the dialog
-           yourself using one of the QFontDialog constructors.
-
-    The \a name parameter is ignored.
-*/
+    return strcmp(QFontDialog::staticMetaObject.className(), q->metaObject()->className()) == 0;
+}
 
 QT_END_NAMESPACE
 
 #include "qfontdialog.moc"
 #include "moc_qfontdialog.cpp"
-
-#endif // QT_NO_FONTDIALOG
--- a/libgui/languages/build_ts/octave-qt/qhelpsearchquerywidget.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qhelpsearchquerywidget.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,43 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the Qt Assistant of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qhelpsearchquerywidget.h"
 
@@ -46,13 +8,13 @@
 #include <QtCore/QStringList>
 #include <QtCore/QtGlobal>
 
-#include <QtGui/QCompleter>
-#include <QtGui/QLabel>
-#include <QtGui/QLayout>
-#include <QtGui/QLineEdit>
+#include <QtWidgets/QCompleter>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QLayout>
+#include <QtWidgets/QLineEdit>
 #include <QtGui/QFocusEvent>
-#include <QtGui/QPushButton>
-#include <QtGui/QToolButton>
+#include <QtWidgets/QPushButton>
+#include <QtWidgets/QToolButton>
 
 QT_BEGIN_NAMESPACE
 
@@ -63,7 +25,7 @@
 private:
     struct QueryHistory {
         explicit QueryHistory() : curQuery(-1) {}
-        QList<QList<QHelpSearchQuery> > queries;
+        QStringList queries;
         int curQuery;
     };
 
@@ -73,14 +35,14 @@
         explicit CompleterModel(QObject *parent)
           : QAbstractListModel(parent) {}
 
-        int rowCount(const QModelIndex &parent = QModelIndex()) const
+        int rowCount(const QModelIndex &parent = QModelIndex()) const override
         {
             return parent.isValid() ? 0 : termList.size();
         }
 
-        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
         {
-            if (!index.isValid() || index.row() >= termList.count()||
+            if (!index.isValid() || index.row() >= termList.size()||
                 (role != Qt::EditRole && role != Qt::DisplayRole))
                 return QVariant();
             return termList.at(index.row());
@@ -89,8 +51,9 @@
         void addTerm(const QString &term)
         {
             if (!termList.contains(term)) {
+                beginResetModel();
                 termList.append(term);
-                reset();
+                endResetModel();
             }
         }
 
@@ -100,285 +63,112 @@
 
     QHelpSearchQueryWidgetPrivate()
         : QObject()
-        , simpleSearch(true)
-        , searchCompleter(new CompleterModel(this), this)
+        , m_searchCompleter(new CompleterModel(this), this)
     {
-        searchButton = 0;
-        advancedSearchWidget = 0;
-        showHideAdvancedSearchButton = 0;
-        defaultQuery = 0;
-        exactQuery = 0;
-        similarQuery = 0;
-        withoutQuery = 0;
-        allQuery = 0;
-        atLeastQuery = 0;
     }
 
-    ~QHelpSearchQueryWidgetPrivate()
+    ~QHelpSearchQueryWidgetPrivate() override
     {
         // nothing todo
     }
 
     void retranslate()
     {
-        simpleSearchLabel->setText(QHelpSearchQueryWidget::tr("Search for:"));
-        prevQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Previous search"));
-        nextQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Next search"));
-        searchButton->setText(QHelpSearchQueryWidget::tr("Search"));
-#ifdef QT_CLUCENE_SUPPORT
-        advancedSearchLabel->setText(QHelpSearchQueryWidget::tr("Advanced search"));
-        similarLabel->setText(QHelpSearchQueryWidget::tr("words <B>similar</B> to:"));
-        withoutLabel->setText(QHelpSearchQueryWidget::tr("<B>without</B> the words:"));
-        exactLabel->setText(QHelpSearchQueryWidget::tr("with <B>exact phrase</B>:"));
-        allLabel->setText(QHelpSearchQueryWidget::tr("with <B>all</B> of the words:"));
-        atLeastLabel->setText(QHelpSearchQueryWidget::tr("with <B>at least one</B> of the words:"));
+        m_searchLabel->setText(QHelpSearchQueryWidget::tr("Search for:"));
+        m_searchButton->setText(QHelpSearchQueryWidget::tr("Search"));
+#if QT_CONFIG(tooltip)
+        m_prevQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Previous search"));
+        m_nextQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Next search"));
 #endif
     }
 
-    QStringList buildTermList(const QString query)
-    {
-        bool s = false;
-        QString phrase;
-        QStringList wordList;
-        QString searchTerm = query;
-
-        for (int i = 0; i < searchTerm.length(); ++i) {
-            if (searchTerm[i] == QLatin1Char('\"') && !s) {
-                s = true;
-                phrase = searchTerm[i];
-                continue;
-            }
-            if (searchTerm[i] != QLatin1Char('\"') && s)
-                phrase += searchTerm[i];
-            if (searchTerm[i] == QLatin1Char('\"') && s) {
-                s = false;
-                phrase += searchTerm[i];
-                wordList.append(phrase);
-                searchTerm.remove(phrase);
-            }
-        }
-        if (s)
-            searchTerm.replace(phrase, phrase.mid(1));
-
-        const QRegExp exp(QLatin1String("\\s+"));
-        wordList += searchTerm.split(exp, QString::SkipEmptyParts);
-        return wordList;
-    }
-
-    void saveQuery(const QList<QHelpSearchQuery> &query, QueryHistory &queryHist)
+    void saveQuery(const QString &query)
     {
         // We only add the query to the list if it is different from the last one.
-        bool insert = false;
-        if (queryHist.queries.empty())
-            insert = true;
-        else {
-            const QList<QHelpSearchQuery> &lastQuery = queryHist.queries.last();
-            if (lastQuery.size() != query.size()) {
-                insert = true;
-            } else {
-                for (int i = 0; i < query.size(); ++i) {
-                    if (query.at(i).fieldName != lastQuery.at(i).fieldName
-                        || query.at(i).wordList != lastQuery.at(i).wordList) {
-                        insert = true;
-                        break;
-                    }
-                }
-            }
-        }
-        if (insert) {
-            queryHist.queries.append(query);
-            foreach (const QHelpSearchQuery &queryPart, query) {
-                static_cast<CompleterModel *>(searchCompleter.model())->
-                        addTerm(queryPart.wordList.join(" "));
-            }
-        }
+        if (!m_queries.queries.isEmpty() && m_queries.queries.last() == query)
+            return;
+
+        m_queries.queries.append(query);
+        static_cast<CompleterModel *>(m_searchCompleter.model())->addTerm(query);
     }
 
     void nextOrPrevQuery(int maxOrMinIndex, int addend, QToolButton *thisButton,
         QToolButton *otherButton)
     {
-        QueryHistory *queryHist;
-        QList<QLineEdit *> lineEdits;
-        if (simpleSearch) {
-            queryHist = &simpleQueries;
-            lineEdits << defaultQuery;
-        } else {
-            queryHist = &complexQueries;
-            lineEdits << allQuery << atLeastQuery << similarQuery
-                << withoutQuery << exactQuery;
-        }
-        foreach (QLineEdit *lineEdit, lineEdits)
-            lineEdit->clear();
+        m_lineEdit->clear();
 
         // Otherwise, the respective button would be disabled.
-        Q_ASSERT(queryHist->curQuery != maxOrMinIndex);
+        Q_ASSERT(m_queries.curQuery != maxOrMinIndex);
 
-        queryHist->curQuery += addend;
-        const QList<QHelpSearchQuery> &query =
-            queryHist->queries.at(queryHist->curQuery);
-        foreach (const QHelpSearchQuery &queryPart, query) {
-            if (QLineEdit *lineEdit = lineEditFor(queryPart.fieldName))
-                lineEdit->setText(queryPart.wordList.join(" "));
-        }
+        m_queries.curQuery = qBound(0, m_queries.curQuery + addend, m_queries.queries.size() - 1);
+        const QString &query = m_queries.queries.at(m_queries.curQuery);
+        m_lineEdit->setText(query);
 
-        if (queryHist->curQuery == maxOrMinIndex)
+        if (m_queries.curQuery == maxOrMinIndex)
             thisButton->setEnabled(false);
         otherButton->setEnabled(true);
     }
 
-    QLineEdit* lineEditFor(const QHelpSearchQuery::FieldName &fieldName) const
-    {
-        switch (fieldName) {
-            case QHelpSearchQuery::DEFAULT:
-                return defaultQuery;
-            case QHelpSearchQuery::ALL:
-                return allQuery;
-            case QHelpSearchQuery::ATLEAST:
-                return atLeastQuery;
-            case QHelpSearchQuery::FUZZY:
-                return similarQuery;
-            case QHelpSearchQuery::WITHOUT:
-                return withoutQuery;
-            case QHelpSearchQuery::PHRASE:
-                return exactQuery;
-            default:
-                Q_ASSERT(0);
-        }
-        return 0;
-    }
-
     void enableOrDisableToolButtons()
     {
-        const QueryHistory &queryHist = simpleSearch ? simpleQueries
-            : complexQueries;
-        prevQueryButton->setEnabled(queryHist.curQuery > 0);
-        nextQueryButton->setEnabled(queryHist.curQuery
-            < queryHist.queries.size() - 1);
+        m_prevQueryButton->setEnabled(m_queries.curQuery > 0);
+        m_nextQueryButton->setEnabled(m_queries.curQuery
+            < m_queries.queries.size() - 1);
     }
 
 private slots:
-    void showHideAdvancedSearch()
+    bool eventFilter(QObject *ob, QEvent *event) override
     {
-        if (simpleSearch) {
-            advancedSearchWidget->show();
-            showHideAdvancedSearchButton->setText((QLatin1String("-")));
-        } else {
-            advancedSearchWidget->hide();
-            showHideAdvancedSearchButton->setText((QLatin1String("+")));
+        if (event->type() == QEvent::KeyPress) {
+            QKeyEvent *const keyEvent = static_cast<QKeyEvent *>(event);
+            if (keyEvent->key() == Qt::Key_Down) {
+                if (m_queries.curQuery + 1 < m_queries.queries.size())
+                    nextQuery();
+                return true;
+            }
+            if (keyEvent->key() == Qt::Key_Up) {
+                if (m_queries.curQuery > 0)
+                    prevQuery();
+                return true;
+            }
+
         }
-
-        simpleSearch = !simpleSearch;
-        defaultQuery->setEnabled(simpleSearch);
-        enableOrDisableToolButtons();
+        return QObject::eventFilter(ob, event);
     }
 
     void searchRequested()
     {
-        QList<QHelpSearchQuery> queryList;
-#if !defined(QT_CLUCENE_SUPPORT)
-        queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT,
-            QStringList(defaultQuery->text())));
-
-#else
-        if (defaultQuery->isEnabled()) {
-            queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT,
-                buildTermList(defaultQuery->text())));
-        } else {
-            const QRegExp exp(QLatin1String("\\s+"));
-            QStringList lst = similarQuery->text().split(exp,
-                QString::SkipEmptyParts);
-            if (!lst.isEmpty()) {
-                QStringList fuzzy;
-                foreach (const QString &term, lst)
-                    fuzzy += buildTermList(term);
-                queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY,
-                    fuzzy));
-            }
-
-            lst = withoutQuery->text().split(exp, QString::SkipEmptyParts);
-            if (!lst.isEmpty()) {
-                QStringList without;
-                foreach (const QString &term, lst)
-                    without.append(term);
-                queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT,
-                    without));
-            }
-
-            if (!exactQuery->text().isEmpty()) {
-                QString phrase = exactQuery->text().remove(QLatin1Char('\"'));
-                phrase = phrase.simplified();
-                queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE,
-                    QStringList(phrase)));
-            }
-
-            lst = allQuery->text().split(exp, QString::SkipEmptyParts);
-            if (!lst.isEmpty()) {
-                QStringList all;
-                foreach (const QString &term, lst)
-                    all.append(term);
-                queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all));
-            }
-
-            lst = atLeastQuery->text().split(exp, QString::SkipEmptyParts);
-            if (!lst.isEmpty()) {
-                QStringList atLeast;
-                foreach (const QString &term, lst)
-                    atLeast += buildTermList(term);
-                queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST,
-                    atLeast));
-            }
-        }
-#endif
-        QueryHistory &queryHist = simpleSearch ? simpleQueries : complexQueries;
-        saveQuery(queryList, queryHist);
-        queryHist.curQuery = queryHist.queries.size() - 1;
-        if (queryHist.curQuery > 0)
-            prevQueryButton->setEnabled(true);
-        nextQueryButton->setEnabled(false);
+        saveQuery(m_lineEdit->text());
+        m_queries.curQuery = m_queries.queries.size() - 1;
+        if (m_queries.curQuery > 0)
+            m_prevQueryButton->setEnabled(true);
+        m_nextQueryButton->setEnabled(false);
     }
 
     void nextQuery()
     {
-        nextOrPrevQuery((simpleSearch ? simpleQueries
-            : complexQueries).queries.size() - 1, 1, nextQueryButton,
-                prevQueryButton);
+        nextOrPrevQuery(m_queries.queries.size() - 1, 1, m_nextQueryButton,
+                m_prevQueryButton);
     }
 
     void prevQuery()
     {
-        nextOrPrevQuery(0, -1, prevQueryButton, nextQueryButton);
+        nextOrPrevQuery(0, -1, m_prevQueryButton, m_nextQueryButton);
     }
 
 private:
     friend class QHelpSearchQueryWidget;
 
-    bool simpleSearch;
-    QLabel *simpleSearchLabel;
-    QLabel *advancedSearchLabel;
-    QLabel *similarLabel;
-    QLabel *withoutLabel;
-    QLabel *exactLabel;
-    QLabel *allLabel;
-    QLabel *atLeastLabel;
-    QPushButton *searchButton;
-    QWidget* advancedSearchWidget;
-    QToolButton *showHideAdvancedSearchButton;
-    QLineEdit *defaultQuery;
-    QLineEdit *exactQuery;
-    QLineEdit *similarQuery;
-    QLineEdit *withoutQuery;
-    QLineEdit *allQuery;
-    QLineEdit *atLeastQuery;
-    QToolButton *nextQueryButton;
-    QToolButton *prevQueryButton;
-    QueryHistory simpleQueries;
-    QueryHistory complexQueries;
-    QCompleter searchCompleter;
+    QLabel *m_searchLabel = nullptr;
+    QPushButton *m_searchButton = nullptr;
+    QLineEdit *m_lineEdit = nullptr;
+    QToolButton *m_nextQueryButton = nullptr;
+    QToolButton *m_prevQueryButton = nullptr;
+    QueryHistory m_queries;
+    QCompleter m_searchCompleter;
+    bool m_compactMode = false;
 };
 
-#include "qhelpsearchquerywidget.moc"
-
-
 /*!
     \class QHelpSearchQueryWidget
     \since 4.4
@@ -392,9 +182,8 @@
     \fn void QHelpSearchQueryWidget::search()
 
     This signal is emitted when a the user has the search button invoked.
-    After reciving the signal you can ask the QHelpSearchQueryWidget for the
-    build list of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's
-    search() function.
+    After receiving the signal you can ask the QHelpSearchQueryWidget for the
+    search input that you may pass to the QHelpSearchEngine::search() function.
 */
 
 /*!
@@ -406,100 +195,42 @@
     d = new QHelpSearchQueryWidgetPrivate();
 
     QVBoxLayout *vLayout = new QVBoxLayout(this);
-    vLayout->setMargin(0);
+    vLayout->setContentsMargins(QMargins());
 
     QHBoxLayout* hBoxLayout = new QHBoxLayout();
-    d->simpleSearchLabel = new QLabel(this);
-    d->defaultQuery = new QLineEdit(this);
-    d->defaultQuery->setCompleter(&d->searchCompleter);
-    d->prevQueryButton = new QToolButton(this);
-    d->prevQueryButton->setArrowType(Qt::LeftArrow);
-    d->prevQueryButton->setEnabled(false);
-    d->nextQueryButton = new QToolButton(this);
-    d->nextQueryButton->setArrowType(Qt::RightArrow);
-    d->nextQueryButton->setEnabled(false);
-    d->searchButton = new QPushButton(this);
-    hBoxLayout->addWidget(d->simpleSearchLabel);
-    hBoxLayout->addWidget(d->defaultQuery);
-    hBoxLayout->addWidget(d->prevQueryButton);
-    hBoxLayout->addWidget(d->nextQueryButton);
-    hBoxLayout->addWidget(d->searchButton);
-
-    vLayout->addLayout(hBoxLayout);
-
-    connect(d->prevQueryButton, SIGNAL(clicked()), d, SLOT(prevQuery()));
-    connect(d->nextQueryButton, SIGNAL(clicked()), d, SLOT(nextQuery()));
-    connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search()));
-    connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-
-#if defined(QT_CLUCENE_SUPPORT)
-    hBoxLayout = new QHBoxLayout();
-    d->showHideAdvancedSearchButton = new QToolButton(this);
-    d->showHideAdvancedSearchButton->setText(QLatin1String("+"));
-    d->showHideAdvancedSearchButton->setMinimumSize(25, 20);
-
-    d->advancedSearchLabel = new QLabel(this);
-    QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
-    sizePolicy.setHeightForWidth(d->advancedSearchLabel->sizePolicy().hasHeightForWidth());
-    d->advancedSearchLabel->setSizePolicy(sizePolicy);
-
-    QFrame* hLine = new QFrame(this);
-    hLine->setFrameStyle(QFrame::HLine);
-    hBoxLayout->addWidget(d->showHideAdvancedSearchButton);
-    hBoxLayout->addWidget(d->advancedSearchLabel);
-    hBoxLayout->addWidget(hLine);
+    d->m_searchLabel = new QLabel(this);
+    d->m_lineEdit = new QLineEdit(this);
+    d->m_lineEdit->setClearButtonEnabled(true);
+    d->m_lineEdit->setCompleter(&d->m_searchCompleter);
+    d->m_lineEdit->installEventFilter(d);
+    d->m_prevQueryButton = new QToolButton(this);
+    d->m_prevQueryButton->setArrowType(Qt::LeftArrow);
+    d->m_prevQueryButton->setEnabled(false);
+    d->m_nextQueryButton = new QToolButton(this);
+    d->m_nextQueryButton->setArrowType(Qt::RightArrow);
+    d->m_nextQueryButton->setEnabled(false);
+    d->m_searchButton = new QPushButton(this);
+    hBoxLayout->addWidget(d->m_searchLabel);
+    hBoxLayout->addWidget(d->m_lineEdit);
+    hBoxLayout->addWidget(d->m_prevQueryButton);
+    hBoxLayout->addWidget(d->m_nextQueryButton);
+    hBoxLayout->addWidget(d->m_searchButton);
 
     vLayout->addLayout(hBoxLayout);
 
-    // setup advanced search layout
-    d->advancedSearchWidget = new QWidget(this);
-    QGridLayout *gLayout = new QGridLayout(d->advancedSearchWidget);
-    gLayout->setMargin(0);
-
-    d->similarLabel = new QLabel(this);
-    gLayout->addWidget(d->similarLabel, 0, 0);
-    d->similarQuery = new QLineEdit(this);
-    d->similarQuery->setCompleter(&d->searchCompleter);
-    gLayout->addWidget(d->similarQuery, 0, 1);
-
-    d->withoutLabel = new QLabel(this);
-    gLayout->addWidget(d->withoutLabel, 1, 0);
-    d->withoutQuery = new QLineEdit(this);
-    d->withoutQuery->setCompleter(&d->searchCompleter);
-    gLayout->addWidget(d->withoutQuery, 1, 1);
-
-    d->exactLabel = new QLabel(this);
-    gLayout->addWidget(d->exactLabel, 2, 0);
-    d->exactQuery = new QLineEdit(this);
-    d->exactQuery->setCompleter(&d->searchCompleter);
-    gLayout->addWidget(d->exactQuery, 2, 1);
-
-    d->allLabel = new QLabel(this);
-    gLayout->addWidget(d->allLabel, 3, 0);
-    d->allQuery = new QLineEdit(this);
-    d->allQuery->setCompleter(&d->searchCompleter);
-    gLayout->addWidget(d->allQuery, 3, 1);
-
-    d->atLeastLabel = new QLabel(this);
-    gLayout->addWidget(d->atLeastLabel, 4, 0);
-    d->atLeastQuery = new QLineEdit(this);
-    d->atLeastQuery->setCompleter(&d->searchCompleter);
-    gLayout->addWidget(d->atLeastQuery, 4, 1);
-
-    vLayout->addWidget(d->advancedSearchWidget);
-    d->advancedSearchWidget->hide();
+    connect(d->m_prevQueryButton, &QAbstractButton::clicked,
+            d, &QHelpSearchQueryWidgetPrivate::prevQuery);
+    connect(d->m_nextQueryButton, &QAbstractButton::clicked,
+            d, &QHelpSearchQueryWidgetPrivate::nextQuery);
+    connect(d->m_searchButton, &QAbstractButton::clicked,
+            this, &QHelpSearchQueryWidget::search);
+    connect(d->m_lineEdit, &QLineEdit::returnPressed,
+            this, &QHelpSearchQueryWidget::search);
 
     d->retranslate();
-
-    connect(d->exactQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-    connect(d->similarQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-    connect(d->withoutQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-    connect(d->allQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-    connect(d->atLeastQuery, SIGNAL(returnPressed()), this, SIGNAL(search()));
-    connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()),
-        d, SLOT(showHideAdvancedSearch()));
-#endif
-    connect(this, SIGNAL(search()), d, SLOT(searchRequested()));
+    connect(this, &QHelpSearchQueryWidget::search,
+            d, &QHelpSearchQueryWidgetPrivate::searchRequested);
+    setCompactMode(true);
 }
 
 /*!
@@ -511,62 +242,92 @@
 }
 
 /*!
-    \since 4.8
-
     Expands the search query widget so that the extended search fields are shown.
 */
 void QHelpSearchQueryWidget::expandExtendedSearch()
 {
-    if (d->simpleSearch)
-        d->showHideAdvancedSearch();
+    // TODO: no extended search anymore, deprecate it?
 }
 
 /*!
-    \since 4.8
-
     Collapses the search query widget so that only the default search field is
     shown.
 */
 void QHelpSearchQueryWidget::collapseExtendedSearch()
 {
-    if (!d->simpleSearch)
-        d->showHideAdvancedSearch();
+    // TODO: no extended search anymore, deprecate it?
 }
 
+#if QT_DEPRECATED_SINCE(5, 9)
 /*!
-    Returns a list of queries to use in combination with the search engines
-    search(QList<QHelpSearchQuery> &queryList) function.
+    \deprecated
+
+    Use searchInput() instead.
 */
 QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const
 {
-    const QHelpSearchQueryWidgetPrivate::QueryHistory &queryHist =
-        d->simpleSearch ? d->simpleQueries : d->complexQueries;
-    return queryHist.queries.isEmpty() ?
-        QList<QHelpSearchQuery>() : queryHist.queries.last();
+    return QList<QHelpSearchQuery>() << QHelpSearchQuery(QHelpSearchQuery::DEFAULT,
+           searchInput().split(QChar::Space, Qt::SkipEmptyParts));
 }
 
 /*!
-    \since 4.8
+    \deprecated
 
-    Sets the QHelpSearchQueryWidget input fields to the values specified by
-    \a queryList search field name. Please note that one has to call the search
-    engine's search(QList<QHelpSearchQuery> &queryList) function to perform the
-    actual search.
+    Use setSearchInput() instead.
 */
 void QHelpSearchQueryWidget::setQuery(const QList<QHelpSearchQuery> &queryList)
 {
-    QList<QLineEdit *> lineEdits;
-    lineEdits << d->defaultQuery << d->allQuery << d->atLeastQuery
-        << d->similarQuery << d->withoutQuery << d->exactQuery;
-    foreach (QLineEdit *lineEdit, lineEdits)
-        lineEdit->clear();
+    if (queryList.isEmpty())
+        return;
+
+    setSearchInput(queryList.first().wordList.join(QChar::Space));
+}
+#endif // QT_DEPRECATED_SINCE(5, 9)
+
+/*!
+    \since 5.9
+
+    Returns a search phrase to use in combination with the
+    QHelpSearchEngine::search(const QString &searchInput) function.
+*/
+QString QHelpSearchQueryWidget::searchInput() const
+{
+    if (d->m_queries.queries.isEmpty())
+        return QString();
+    return d->m_queries.queries.last();
+}
+
+/*!
+    \since 5.9
+
+    Sets the QHelpSearchQueryWidget input field to the value specified by
+    \a searchInput.
 
-    const QLatin1String space(" ");
-    foreach (const QHelpSearchQuery &q, queryList) {
-        if (QLineEdit *lineEdit = d->lineEditFor(q.fieldName))
-            lineEdit->setText(lineEdit->text() + q.wordList.join(space) + space);
+    \note The QHelpSearchEngine::search(const QString &searchInput) function has
+    to be called to perform the actual search.
+*/
+void QHelpSearchQueryWidget::setSearchInput(const QString &searchInput)
+{
+    d->m_lineEdit->clear();
+
+    d->m_lineEdit->setText(searchInput);
+
+    d->searchRequested();
+}
+
+bool QHelpSearchQueryWidget::isCompactMode() const
+{
+    return d->m_compactMode;
+}
+
+void QHelpSearchQueryWidget::setCompactMode(bool on)
+{
+    if (d->m_compactMode != on) {
+        d->m_compactMode = on;
+        d->m_prevQueryButton->setVisible(!on);
+        d->m_nextQueryButton->setVisible(!on);
+        d->m_searchLabel->setVisible(!on);
     }
-    d->searchRequested();
 }
 
 /*!
@@ -575,12 +336,13 @@
 void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent)
 {
     if (focusEvent->reason() != Qt::MouseFocusReason) {
-        d->defaultQuery->selectAll();
-        d->defaultQuery->setFocus();
+        d->m_lineEdit->selectAll();
+        d->m_lineEdit->setFocus();
     }
 }
 
-/*! \reimp
+/*!
+    \reimp
 */
 void QHelpSearchQueryWidget::changeEvent(QEvent *event)
 {
@@ -591,3 +353,5 @@
 }
 
 QT_END_NAMESPACE
+
+#include "qhelpsearchquerywidget.moc"
--- a/libgui/languages/build_ts/octave-qt/qinputdialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qinputdialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,55 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qinputdialog.h"
 
-#ifndef QT_NO_INPUTDIALOG
-
 #include "qapplication.h"
 #include "qcombobox.h"
 #include "qdialogbuttonbox.h"
 #include "qlabel.h"
 #include "qlayout.h"
 #include "qlineedit.h"
-#include "qlistwidget.h"
+#include "qplaintextedit.h"
+#include "qlistview.h"
 #include "qpushbutton.h"
 #include "qspinbox.h"
 #include "qstackedlayout.h"
@@ -59,25 +20,37 @@
 
 QT_USE_NAMESPACE
 
+enum CandidateSignal {
+    TextValueSelectedSignal,
+    IntValueSelectedSignal,
+    DoubleValueSelectedSignal,
+
+    NumCandidateSignals
+};
+
+static const char *candidateSignal(int which)
+{
+    switch (CandidateSignal(which)) {
+    case TextValueSelectedSignal:   return SIGNAL(textValueSelected(QString));
+    case IntValueSelectedSignal:    return SIGNAL(intValueSelected(int));
+    case DoubleValueSelectedSignal: return SIGNAL(doubleValueSelected(double));
+
+    case NumCandidateSignals:
+        break;
+    };
+    Q_UNREACHABLE_RETURN(nullptr);
+}
+
 static const char *signalForMember(const char *member)
 {
-    static const int NumCandidates = 4;
-    static const char * const candidateSignals[NumCandidates] = {
-        SIGNAL(textValueSelected(QString)),
-        SIGNAL(intValueSelected(int)),
-        SIGNAL(doubleValueSelected(double)),
-        SIGNAL(accepted())
-    };
-
     QByteArray normalizedMember(QMetaObject::normalizedSignature(member));
 
-    int i = 0;
-    while (i < NumCandidates - 1) { // sic
-        if (QMetaObject::checkConnectArgs(candidateSignals[i], normalizedMember))
-            break;
-        ++i;
-    }
-    return candidateSignals[i];
+    for (int i = 0; i < NumCandidateSignals; ++i)
+        if (QMetaObject::checkConnectArgs(candidateSignal(i), normalizedMember))
+            return candidateSignal(i);
+
+    // otherwise, use fit-all accepted signal:
+    return SIGNAL(accepted());
 }
 
 QT_BEGIN_NAMESPACE
@@ -106,18 +79,16 @@
     void notifyTextChanged() { emit textChanged(hasAcceptableInput()); }
 
 private:
-    void keyPressEvent(QKeyEvent *event) {
+    void keyPressEvent(QKeyEvent *event) override {
         if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) {
-#ifndef QT_NO_PROPERTIES
             setProperty("value", property("value"));
-#endif
         } else {
             QSpinBox::keyPressEvent(event);
         }
         notifyTextChanged();
     }
 
-    void mousePressEvent(QMouseEvent *event) {
+    void mousePressEvent(QMouseEvent *event) override {
         QSpinBox::mousePressEvent(event);
         notifyTextChanged();
     }
@@ -128,7 +99,7 @@
     Q_OBJECT
 
 public:
-    QInputDialogDoubleSpinBox(QWidget *parent = 0)
+    QInputDialogDoubleSpinBox(QWidget *parent = nullptr)
         : QDoubleSpinBox(parent) {
         connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged()));
         connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged()));
@@ -141,26 +112,32 @@
     void notifyTextChanged() { emit textChanged(hasAcceptableInput()); }
 
 private:
-    void keyPressEvent(QKeyEvent *event) {
+    void keyPressEvent(QKeyEvent *event) override {
         if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) {
-#ifndef QT_NO_PROPERTIES
             setProperty("value", property("value"));
-#endif
         } else {
             QDoubleSpinBox::keyPressEvent(event);
         }
         notifyTextChanged();
     }
 
-    void mousePressEvent(QMouseEvent *event) {
+    void mousePressEvent(QMouseEvent *event) override {
         QDoubleSpinBox::mousePressEvent(event);
         notifyTextChanged();
     }
 };
 
-QT_BEGIN_INCLUDE_NAMESPACE
-#include "qinputdialog.moc"
-QT_END_INCLUDE_NAMESPACE
+class QInputDialogListView : public QListView
+{
+public:
+    QInputDialogListView(QWidget *parent = nullptr) : QListView(parent) {}
+    QVariant inputMethodQuery(Qt::InputMethodQuery query) const override
+    {
+        if (query == Qt::ImEnabled)
+            return false;
+        return QListView::inputMethodQuery(query);
+    }
+};
 
 class QInputDialogPrivate : public QDialogPrivate
 {
@@ -171,6 +148,7 @@
 
     void ensureLayout();
     void ensureLineEdit();
+    void ensurePlainTextEdit();
     void ensureComboBox();
     void ensureListView();
     void ensureIntSpinBox();
@@ -184,15 +162,17 @@
     void ensureLayout() const { const_cast<QInputDialogPrivate *>(this)->ensureLayout(); }
     bool useComboBoxOrListView() const { return comboBox && comboBox->count() > 0; }
     void _q_textChanged(const QString &text);
+    void _q_plainTextEditTextChanged();
     void _q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex);
 
     mutable QLabel *label;
     mutable QDialogButtonBox *buttonBox;
     mutable QLineEdit *lineEdit;
+    mutable QPlainTextEdit *plainTextEdit;
     mutable QSpinBox *intSpinBox;
     mutable QDoubleSpinBox *doubleSpinBox;
     mutable QComboBox *comboBox;
-    mutable QListView *listView;
+    mutable QInputDialogListView *listView;
     mutable QWidget *inputWidget;
     mutable QVBoxLayout *mainLayout;
     QInputDialog::InputDialogOptions opts;
@@ -202,8 +182,8 @@
 };
 
 QInputDialogPrivate::QInputDialogPrivate()
-    : label(0), buttonBox(0), lineEdit(0), intSpinBox(0), doubleSpinBox(0), comboBox(0), listView(0),
-      inputWidget(0), mainLayout(0)
+    : label(nullptr), buttonBox(nullptr), lineEdit(nullptr), plainTextEdit(nullptr), intSpinBox(nullptr), doubleSpinBox(nullptr),
+      comboBox(nullptr), listView(nullptr), inputWidget(nullptr), mainLayout(nullptr)
 {
 }
 
@@ -231,12 +211,7 @@
     QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
 
     mainLayout = new QVBoxLayout(q);
-    //we want to let the input dialog grow to available size on Symbian.
-#ifndef Q_OS_SYMBIAN
     mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
-#else
-    label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-#endif
     mainLayout->addWidget(label);
     mainLayout->addWidget(inputWidget);
     mainLayout->addWidget(buttonBox);
@@ -258,6 +233,21 @@
     }
 }
 
+void QInputDialogPrivate::ensurePlainTextEdit()
+{
+    Q_Q(QInputDialog);
+    if (!plainTextEdit) {
+        plainTextEdit = new QPlainTextEdit(q);
+        plainTextEdit->setLineWrapMode(QPlainTextEdit::NoWrap);
+#ifndef QT_NO_IM
+        qt_widget_private(plainTextEdit)->inheritsInputMethodHints = 1;
+#endif
+        plainTextEdit->hide();
+        QObject::connect(plainTextEdit, SIGNAL(textChanged()),
+                         q, SLOT(_q_plainTextEditTextChanged()));
+    }
+}
+
 void QInputDialogPrivate::ensureComboBox()
 {
     Q_Q(QInputDialog);
@@ -269,7 +259,7 @@
         comboBox->hide();
         QObject::connect(comboBox, SIGNAL(editTextChanged(QString)),
                          q, SLOT(_q_textChanged(QString)));
-        QObject::connect(comboBox, SIGNAL(currentIndexChanged(QString)),
+        QObject::connect(comboBox, SIGNAL(currentTextChanged(QString)),
                          q, SLOT(_q_textChanged(QString)));
     }
 }
@@ -279,8 +269,7 @@
     Q_Q(QInputDialog);
     if (!listView) {
         ensureComboBox();
-
-        listView = new QListView(q);
+        listView = new QInputDialogListView(q);
         listView->hide();
         listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
         listView->setSelectionMode(QAbstractItemView::SingleSelection);
@@ -352,6 +341,8 @@
     // textValue
     if (widget == lineEdit) {
         lineEdit->setText(textValue);
+    } else if (widget == plainTextEdit) {
+        plainTextEdit->setPlainText(textValue);
     } else if (widget == comboBox) {
         setComboBoxText(textValue);
     } else if (widget == listView) {
@@ -372,6 +363,9 @@
         } else {
             widget = comboBox;
         }
+    } else if (opts & QInputDialog::UsePlainTextEditForTextInput) {
+        ensurePlainTextEdit();
+        widget = plainTextEdit;
     } else {
         ensureLineEdit();
         widget = lineEdit;
@@ -425,6 +419,16 @@
     }
 }
 
+void QInputDialogPrivate::_q_plainTextEditTextChanged()
+{
+    Q_Q(QInputDialog);
+    QString text = plainTextEdit->toPlainText();
+    if (textValue != text) {
+        textValue = text;
+        emit q->textValueChanged(text);
+    }
+}
+
 void QInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex,
                                                const QModelIndex & /* oldIndex */)
 {
@@ -437,21 +441,21 @@
     \brief The QInputDialog class provides a simple convenience dialog to get a
     single value from the user.
     \ingroup standard-dialogs
-
+    \inmodule QtWidgets
 
     The input value can be a string, a number or an item from a list. A label
     must be set to tell the user what they should enter.
 
-    Four static convenience functions are provided: getText(), getInt(),
-    getDouble(), and getItem(). All the functions can be used in a similar way,
+    Five static convenience functions are provided: getText(), getMultiLineText(),
+    getInt(), getDouble(), and getItem(). All the functions can be used in a similar way,
     for example:
 
-    \snippet examples/dialogs/standarddialogs/dialog.cpp 3
+    \snippet dialogs/standarddialogs/dialog.cpp 3
 
-    The \c ok variable is set to true if the user clicks \gui OK; otherwise it
+    The \c ok variable is set to true if the user clicks \uicontrol OK; otherwise, it
     is set to false.
 
-    \img inputdialogs.png Input Dialogs
+    \image inputdialogs.png Input Dialogs
 
     The \l{dialogs/standarddialogs}{Standard Dialogs} example shows how to use
     QInputDialog as well as other built-in Qt dialogs.
@@ -500,7 +504,7 @@
 
     \brief the mode used for input
 
-    This property help determines which widget is used for entering input into
+    This property helps determine which widget is used for entering input into
     the dialog.
 */
 void QInputDialog::setInputMode(InputMode mode)
@@ -553,7 +557,7 @@
 
     \property QInputDialog::labelText
 
-    \brief the text to for the label to describe what needs to be input
+    \brief the label's text which describes what needs to be input
 */
 void QInputDialog::setLabelText(const QString &text)
 {
@@ -563,9 +567,6 @@
     } else {
         d->label->setText(text);
     }
-#ifdef Q_OS_SYMBIAN
-    d->label->setWordWrap(true);
-#endif
 }
 
 QString QInputDialog::labelText() const
@@ -583,9 +584,11 @@
     This enum specifies various options that affect the look and feel
     of an input dialog.
 
-    \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
+    \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons (useful for "live dialogs").
     \value UseListViewForComboBoxItems Use a QListView rather than a non-editable QComboBox for
                                        displaying the items set with setComboBoxItems().
+    \value UsePlainTextEditForTextInput Use a QPlainTextEdit for multiline text input. This value was
+                                       introduced in 5.2.
 
     \sa options, setOption(), testOption()
 */
@@ -604,7 +607,7 @@
 }
 
 /*!
-    Returns true if the given \a option is enabled; otherwise, returns
+    Returns \c true if the given \a option is enabled; otherwise, returns
     false.
 
     \sa options, setOption()
@@ -639,6 +642,8 @@
         d->buttonBox->setVisible(!(options & NoButtons));
     if ((changed & UseListViewForComboBoxItems) && inputMode() == TextInput)
         d->chooseRightTextInputWidget();
+    if ((changed & UsePlainTextEditForTextInput) && inputMode() == TextInput)
+        d->chooseRightTextInputWidget();
 }
 
 QInputDialog::InputDialogOptions QInputDialog::options() const
@@ -664,6 +669,8 @@
     setInputMode(TextInput);
     if (d->inputWidget == d->lineEdit) {
         d->lineEdit->setText(text);
+    } else if (d->inputWidget == d->plainTextEdit) {
+        d->plainTextEdit->setPlainText(text);
     } else if (d->inputWidget == d->comboBox) {
         d->setComboBoxText(text);
     } else {
@@ -709,7 +716,7 @@
 
     \property QInputDialog::comboBoxEditable
 
-    \brief whether or not the combo box is used in the input dialog is editable
+    \brief whether or not the combo box used in the input dialog is editable
 */
 void QInputDialog::setComboBoxEditable(bool editable)
 {
@@ -735,17 +742,18 @@
 
     \property QInputDialog::comboBoxItems
 
-    \brief the items used in the combobox for the input dialog
+    \brief the items used in the combo box for the input dialog
 */
 void QInputDialog::setComboBoxItems(const QStringList &items)
 {
     Q_D(QInputDialog);
 
     d->ensureComboBox();
-    d->comboBox->blockSignals(true);
-    d->comboBox->clear();
-    d->comboBox->addItems(items);
-    d->comboBox->blockSignals(false);
+    {
+        const QSignalBlocker blocker(d->comboBox);
+        d->comboBox->clear();
+        d->comboBox->addItems(items);
+    }
 
     if (inputMode() == TextInput)
         d->chooseRightTextInputWidget();
@@ -757,6 +765,7 @@
     QStringList result;
     if (d->comboBox) {
         const int count = d->comboBox->count();
+        result.reserve(count);
         for (int i = 0; i < count; ++i)
             result.append(d->comboBox->itemText(i));
     }
@@ -967,7 +976,7 @@
 
     \property QInputDialog::doubleDecimals
 
-    \brief sets the percision of the double spinbox in decimals
+    \brief sets the precision of the double spinbox in decimals
 
     \sa QDoubleSpinBox::setDecimals()
 */
@@ -1031,17 +1040,16 @@
 
 /*!
     \since 4.5
-    \overload
 
     This function connects one of its signals to the slot specified by \a receiver
     and \a member. The specific signal depends on the arguments that are specified
     in \a member. These are:
 
     \list
-      \o textValueSelected() if \a member has a QString for its first argument.
-      \o intValueSelected() if \a member has an int for its first argument.
-      \o doubleValueSelected() if \a member has a double for its first argument.
-      \o accepted() if \a member has NO arguments.
+      \li textValueSelected() if \a member has a QString for its first argument.
+      \li intValueSelected() if \a member has an int for its first argument.
+      \li doubleValueSelected() if \a member has a double for its first argument.
+      \li accepted() if \a member has NO arguments.
     \endlist
 
     The signal will be disconnected from the slot when the dialog is closed.
@@ -1086,6 +1094,8 @@
         d->inputWidget->setFocus();
         if (d->inputWidget == d->lineEdit) {
             d->lineEdit->selectAll();
+        } else if (d->inputWidget == d->plainTextEdit) {
+            d->plainTextEdit->selectAll();
         } else if (d->inputWidget == d->intSpinBox) {
             d->intSpinBox->selectAll();
         } else if (d->inputWidget == d->doubleSpinBox) {
@@ -1123,7 +1133,7 @@
     if (d->receiverToDisconnectOnClose) {
         disconnect(this, signalForMember(d->memberToDisconnectOnClose),
                    d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
-        d->receiverToDisconnectOnClose = 0;
+        d->receiverToDisconnectOnClose = nullptr;
     }
     d->memberToDisconnectOnClose.clear();
 }
@@ -1139,8 +1149,8 @@
     \a inputMethodHints is the input method hints that will be used in the
     edit widget if an input method is active.
 
-    If \a ok is nonnull \e *\a ok will be set to true if the user pressed
-    \gui OK and to false if the user pressed \gui Cancel. The dialog's parent
+    If \a ok is nonnull \e {*ok} will be set to true if the user pressed
+    \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent
     is \a parent. The dialog will be modal and uses the specified widget
     \a flags.
 
@@ -1149,45 +1159,78 @@
 
     Use this static function like this:
 
-    \snippet examples/dialogs/standarddialogs/dialog.cpp 3
+    \snippet dialogs/standarddialogs/dialog.cpp 3
 
-    \warning Do not delete \a parent during the execution of the dialog. If you
-    want to do this, you should create the dialog yourself using one of the
-    QInputDialog constructors.
-
-    \sa getInt(), getDouble(), getItem()
+    \sa getInt(), getDouble(), getItem(), getMultiLineText()
 */
 
 QString QInputDialog::getText(QWidget *parent, const QString &title, const QString &label,
                               QLineEdit::EchoMode mode, const QString &text, bool *ok,
                               Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
 {
-    QInputDialog dialog(parent, flags);
-    dialog.setWindowTitle(title);
-    dialog.setLabelText(label);
-    dialog.setTextValue(text);
-    dialog.setTextEchoMode(mode);
-    dialog.setInputMethodHints(inputMethodHints);
+    QAutoPointer<QInputDialog> dialog(new QInputDialog(parent, flags));
+    dialog->setWindowTitle(title);
+    dialog->setLabelText(label);
+    dialog->setTextValue(text);
+    dialog->setTextEchoMode(mode);
+    dialog->setInputMethodHints(inputMethodHints);
 
-    int ret = dialog.exec();
+    const int ret = dialog->exec();
     if (ok)
         *ok = !!ret;
     if (ret) {
-        return dialog.textValue();
+        return dialog->textValue();
     } else {
         return QString();
     }
 }
 
 /*!
-    \internal
+    \since 5.2
+
+    Static convenience function to get a multiline string from the user.
+
+    \a title is the text which is displayed in the title bar of the dialog.
+    \a label is the text which is shown to the user (it should say what should
+    be entered).
+    \a text is the default text which is placed in the plain text edit.
+    \a inputMethodHints is the input method hints that will be used in the
+    edit widget if an input method is active.
+
+    If \a ok is nonnull \e {*ok} will be set to true if the user pressed
+    \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent
+    is \a parent. The dialog will be modal and uses the specified widget
+    \a flags.
+
+    If the dialog is accepted, this function returns the text in the dialog's
+    plain text edit. If the dialog is rejected, a null QString is returned.
+
+    Use this static function like this:
+
+    \snippet dialogs/standarddialogs/dialog.cpp 4
+
+    \sa getInt(), getDouble(), getItem(), getText()
 */
-// ### Qt 5: Use only the version above.
-QString QInputDialog::getText(QWidget *parent, const QString &title, const QString &label,
-                              QLineEdit::EchoMode mode, const QString &text, bool *ok,
-                              Qt::WindowFlags flags)
+
+QString QInputDialog::getMultiLineText(QWidget *parent, const QString &title, const QString &label,
+                                       const QString &text, bool *ok, Qt::WindowFlags flags,
+                                       Qt::InputMethodHints inputMethodHints)
 {
-    return getText(parent, title, label, mode, text, ok, flags, Qt::ImhNone);
+    QAutoPointer<QInputDialog> dialog(new QInputDialog(parent, flags));
+    dialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
+    dialog->setWindowTitle(title);
+    dialog->setLabelText(label);
+    dialog->setTextValue(text);
+    dialog->setInputMethodHints(inputMethodHints);
+
+    const int ret = dialog->exec();
+    if (ok)
+        *ok = !!ret;
+    if (ret) {
+        return dialog->textValue();
+    } else {
+        return QString();
+    }
 }
 
 /*!
@@ -1203,8 +1246,8 @@
     \a step is the amount by which the values change as the user presses the
     arrow buttons to increment or decrement the value.
 
-    If \a ok is nonnull *\a ok will be set to true if the user pressed \gui OK
-    and to false if the user pressed \gui Cancel. The dialog's parent is
+    If \a ok is nonnull *\a ok will be set to true if the user pressed \uicontrol OK
+    and to false if the user pressed \uicontrol Cancel. The dialog's parent is
     \a parent. The dialog will be modal and uses the widget \a flags.
 
     On success, this function returns the integer which has been entered by the
@@ -1212,30 +1255,26 @@
 
     Use this static function like this:
 
-    \snippet examples/dialogs/standarddialogs/dialog.cpp 0
+    \snippet dialogs/standarddialogs/dialog.cpp 0
 
-    \warning Do not delete \a parent during the execution of the dialog. If you
-    want to do this, you should create the dialog yourself using one of the
-    QInputDialog constructors.
-
-    \sa getText(), getDouble(), getItem()
+    \sa getText(), getDouble(), getItem(), getMultiLineText()
 */
 
 int QInputDialog::getInt(QWidget *parent, const QString &title, const QString &label, int value,
                          int min, int max, int step, bool *ok, Qt::WindowFlags flags)
 {
-    QInputDialog dialog(parent, flags);
-    dialog.setWindowTitle(title);
-    dialog.setLabelText(label);
-    dialog.setIntRange(min, max);
-    dialog.setIntValue(value);
-    dialog.setIntStep(step);
+    QAutoPointer<QInputDialog> dialog(new QInputDialog(parent, flags));
+    dialog->setWindowTitle(title);
+    dialog->setLabelText(label);
+    dialog->setIntRange(min, max);
+    dialog->setIntValue(value);
+    dialog->setIntStep(step);
 
-    int ret = dialog.exec();
+    const int ret = dialog->exec();
     if (ok)
         *ok = !!ret;
     if (ret) {
-        return dialog.intValue();
+        return dialog->intValue();
     } else {
         return value;
     }
@@ -1251,9 +1290,11 @@
     set to.
     \a min and \a max are the minimum and maximum values the user may choose.
     \a decimals is the maximum number of decimal places the number may have.
+    \a step is the amount by which the values change as the user presses the
+    arrow buttons to increment or decrement the value.
 
-    If \a ok is nonnull, *\a ok will be set to true if the user pressed \gui OK
-    and to false if the user pressed \gui Cancel. The dialog's parent is
+    If \a ok is nonnull, *\a ok will be set to true if the user pressed \uicontrol OK
+    and to false if the user pressed \uicontrol Cancel. The dialog's parent is
     \a parent. The dialog will be modal and uses the widget \a flags.
 
     This function returns the floating point number which has been entered by
@@ -1261,31 +1302,28 @@
 
     Use this static function like this:
 
-    \snippet examples/dialogs/standarddialogs/dialog.cpp 1
+    \snippet dialogs/standarddialogs/dialog.cpp 1
 
-    \warning Do not delete \a parent during the execution of the dialog. If you
-    want to do this, you should create the dialog yourself using one of the
-    QInputDialog constructors.
-
-    \sa getText(), getInt(), getItem()
+    \sa getText(), getInt(), getItem(), getMultiLineText()
 */
 
 double QInputDialog::getDouble(QWidget *parent, const QString &title, const QString &label,
                                double value, double min, double max, int decimals, bool *ok,
-                               Qt::WindowFlags flags)
+                               Qt::WindowFlags flags, double step)
 {
-    QInputDialog dialog(parent, flags);
-    dialog.setWindowTitle(title);
-    dialog.setLabelText(label);
-    dialog.setDoubleDecimals(decimals);
-    dialog.setDoubleRange(min, max);
-    dialog.setDoubleValue(value);
+    QAutoPointer<QInputDialog> dialog(new QInputDialog(parent, flags));
+    dialog->setWindowTitle(title);
+    dialog->setLabelText(label);
+    dialog->setDoubleDecimals(decimals);
+    dialog->setDoubleRange(min, max);
+    dialog->setDoubleValue(value);
+    dialog->setDoubleStep(step);
 
-    int ret = dialog.exec();
+    const int ret = dialog->exec();
     if (ok)
         *ok = !!ret;
     if (ret) {
-        return dialog.doubleValue();
+        return dialog->doubleValue();
     } else {
         return value;
     }
@@ -1298,30 +1336,26 @@
     \a title is the text which is displayed in the title bar of the dialog.
     \a label is the text which is shown to the user (it should say what should
     be entered).
-    \a items is the string list which is inserted into the combobox.
+    \a items is the string list which is inserted into the combo box.
     \a current is the number  of the item which should be the current item.
     \a inputMethodHints is the input method hints that will be used if the
-    combobox is editable and an input method is active.
+    combo box is editable and an input method is active.
 
-    If \a editable is true the user can enter their own text; otherwise the
+    If \a editable is true the user can enter their own text; otherwise, the
     user may only select one of the existing items.
 
-    If \a ok is nonnull \e *\a ok will be set to true if the user pressed
-    \gui OK and to false if the user pressed \gui Cancel. The dialog's parent
+    If \a ok is nonnull \e {*ok} will be set to true if the user pressed
+    \uicontrol OK and to false if the user pressed \uicontrol Cancel. The dialog's parent
     is \a parent. The dialog will be modal and uses the widget \a flags.
 
     This function returns the text of the current item, or if \a editable is
-    true, the current text of the combobox.
+    true, the current text of the combo box.
 
     Use this static function like this:
 
-    \snippet examples/dialogs/standarddialogs/dialog.cpp 2
+    \snippet dialogs/standarddialogs/dialog.cpp 2
 
-    \warning Do not delete \a parent during the execution of the dialog. If you
-    want to do this, you should create the dialog yourself using one of the
-    QInputDialog constructors.
-
-    \sa getText(), getInt(), getDouble()
+    \sa getText(), getInt(), getDouble(), getMultiLineText()
 */
 
 QString QInputDialog::getItem(QWidget *parent, const QString &title, const QString &label,
@@ -1330,94 +1364,48 @@
 {
     QString text(items.value(current));
 
-    QInputDialog dialog(parent, flags);
-    dialog.setWindowTitle(title);
-    dialog.setLabelText(label);
-    dialog.setComboBoxItems(items);
-    dialog.setTextValue(text);
-    dialog.setComboBoxEditable(editable);
-    dialog.setInputMethodHints(inputMethodHints);
+    QAutoPointer<QInputDialog> dialog(new QInputDialog(parent, flags));
+    dialog->setWindowTitle(title);
+    dialog->setLabelText(label);
+    dialog->setComboBoxItems(items);
+    dialog->setTextValue(text);
+    dialog->setComboBoxEditable(editable);
+    dialog->setInputMethodHints(inputMethodHints);
 
-    int ret = dialog.exec();
+    const int ret = dialog->exec();
     if (ok)
         *ok = !!ret;
     if (ret) {
-        return dialog.textValue();
+        return dialog->textValue();
     } else {
         return text;
     }
 }
 
 /*!
-    \internal
-*/
-// ### Qt 5: Use only the version above.
-QString QInputDialog::getItem(QWidget *parent, const QString &title, const QString &label,
-                              const QStringList &items, int current, bool editable, bool *ok,
-                              Qt::WindowFlags flags)
-{
-    return getItem(parent, title, label, items, current, editable, ok, flags, Qt::ImhNone);
-}
-
-/*!
-    \obsolete
+    \property QInputDialog::doubleStep
+    \since 5.10
+    \brief the step by which the double value is increased and decreased
 
-    Use getInt() instead.
-*/
-int QInputDialog::getInteger(QWidget *parent, const QString &title, const QString &label,
-                             int value, int min, int max, int step, bool *ok,
-                             Qt::WindowFlags flags)
-{
-    return getInt(parent, title, label, value, min, max, step, ok, flags);
-}
-
-/*!
-    \fn QString QInputDialog::getText(const QString &title, const QString &label,
-                                      QLineEdit::EchoMode echo = QLineEdit::Normal,
-                                      const QString &text = QString(), bool *ok = 0,
-                                      QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
-
-    Call getText(\a parent, \a title, \a label, \a echo, \a text, \a
-    ok, \a flags) instead.
-
-    The \a name parameter is ignored.
+    This property is only relevant when the input dialog is used in
+    DoubleInput mode.
 */
 
-/*!
-    \fn int QInputDialog::getInteger(const QString &title, const QString &label, int value = 0,
-                                     int min = -2147483647, int max = 2147483647,
-                                     int step = 1, bool *ok = 0,
-                                     QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
-
-
-    Call getInteger(\a parent, \a title, \a label, \a value, \a
-    min, \a max, \a step, \a ok, \a flags) instead.
-
-    The \a name parameter is ignored.
-*/
+void QInputDialog::setDoubleStep(double step)
+{
+    Q_D(QInputDialog);
+    d->ensureDoubleSpinBox();
+    d->doubleSpinBox->setSingleStep(step);
+}
 
-/*!
-    \fn double QInputDialog::getDouble(const QString &title, const QString &label, double value = 0,
-                                       double min = -2147483647, double max = 2147483647,
-                                       int decimals = 1, bool *ok = 0,
-                                       QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
-
-    Call getDouble(\a parent, \a title, \a label, \a value, \a
-    min, \a max, \a decimals, \a ok, \a flags).
-
-    The \a name parameter is ignored.
-*/
-
-/*!
-    \fn QString QInputDialog::getItem(const QString &title, const QString &label, const QStringList &list,
-                                      int current = 0, bool editable = true, bool *ok = 0,
-                                      QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
-
-    Call getItem(\a parent, \a title, \a label, \a list, \a current,
-    \a editable, \a ok, \a flags) instead.
-
-    The \a name parameter is ignored.
-*/
+double QInputDialog::doubleStep() const
+{
+    Q_D(const QInputDialog);
+    if (d->doubleSpinBox)
+        return d->doubleSpinBox->singleStep();
+    else
+        return 1.0;
+}
 
 /*!
     \fn void QInputDialog::doubleValueChanged(double value)
@@ -1433,7 +1421,7 @@
     \fn void QInputDialog::doubleValueSelected(double value)
 
     This signal is emitted whenever the user selects a double value by
-    accepting the dialog; for example, by clicking the \gui{OK} button.
+    accepting the dialog; for example, by clicking the \uicontrol{OK} button.
     The selected value is specified by \a value.
 
     This signal is only relevant when the input dialog is used in
@@ -1454,7 +1442,7 @@
     \fn void QInputDialog::intValueSelected(int value)
 
     This signal is emitted whenever the user selects a integer value by
-    accepting the dialog; for example, by clicking the \gui{OK} button.
+    accepting the dialog; for example, by clicking the \uicontrol{OK} button.
     The selected value is specified by \a value.
 
     This signal is only relevant when the input dialog is used in
@@ -1475,7 +1463,7 @@
     \fn void QInputDialog::textValueSelected(const QString &text)
 
     This signal is emitted whenever the user selects a text string by
-    accepting the dialog; for example, by clicking the \gui{OK} button.
+    accepting the dialog; for example, by clicking the \uicontrol{OK} button.
     The selected string is specified by \a text.
 
     This signal is only relevant when the input dialog is used in
@@ -1484,6 +1472,5 @@
 
 QT_END_NAMESPACE
 
+#include "qinputdialog.moc"
 #include "moc_qinputdialog.cpp"
-
-#endif // QT_NO_INPUTDIALOG
--- a/libgui/languages/build_ts/octave-qt/qmessagebox.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qmessagebox.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,114 +1,91 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtGui/qmessagebox.h>
-
-#ifndef QT_NO_MESSAGEBOX
-
-#include <QtGui/qdialogbuttonbox.h>
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtWidgets/qmessagebox.h>
+
+#include <QtWidgets/qdialogbuttonbox.h>
 #include "private/qlabel_p.h"
 #include "private/qapplication_p.h"
 #include <QtCore/qlist.h>
 #include <QtCore/qdebug.h>
-#include <QtGui/qstyle.h>
-#include <QtGui/qstyleoption.h>
-#include <QtGui/qgridlayout.h>
-#include <QtGui/qdesktopwidget.h>
-#include <QtGui/qpushbutton.h>
+#include <QtWidgets/qstyle.h>
+#include <QtWidgets/qstyleoption.h>
+#include <QtWidgets/qgridlayout.h>
+#include <QtWidgets/qpushbutton.h>
+#include <QtWidgets/qcheckbox.h>
 #include <QtGui/qaccessible.h>
 #include <QtGui/qicon.h>
 #include <QtGui/qtextdocument.h>
-#include <QtGui/qapplication.h>
-#include <QtGui/qtextedit.h>
-#include <QtGui/qtextbrowser.h>
-#include <QtGui/qmenu.h>
+#include <QtWidgets/qapplication.h>
+#if QT_CONFIG(textedit)
+#include <QtWidgets/qtextedit.h>
+#endif
+#if QT_CONFIG(menu)
+#include <QtWidgets/qmenu.h>
+#endif
 #include "qdialog_p.h"
 #include <QtGui/qfont.h>
 #include <QtGui/qfontmetrics.h>
 #include <QtGui/qclipboard.h>
-
-#ifndef QT_NO_STYLE_S60
-#include <qs60style.h>
+#include "private/qabstractbutton_p.h"
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <QtCore/qanystringview.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qversionnumber.h>
+
+#ifdef Q_OS_WIN
+#    include <QtCore/qt_windows.h>
+#include <qpa/qplatformnativeinterface.h>
 #endif
 
-#ifdef Q_WS_WINCE
-extern bool qt_wince_is_mobile();    //defined in qguifunctions_wince.cpp
-extern bool qt_wince_is_smartphone();//defined in qguifunctions_wince.cpp
-extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wince.cpp
-
-#include "qguifunctions_wince.h"
-#endif
+#include <optional>
 
 QT_BEGIN_NAMESPACE
 
+using namespace Qt::StringLiterals;
+
+#if defined(Q_OS_WIN)
+HMENU qt_getWindowsSystemMenu(const QWidget *w)
+{
+    if (QWindow *window = QApplicationPrivate::windowForWidget(w))
+        if (void *handle = QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window))
+            return GetSystemMenu(reinterpret_cast<HWND>(handle), false);
+    return 0;
+}
+#endif
+
 enum Button { Old_Ok = 1, Old_Cancel = 2, Old_Yes = 3, Old_No = 4, Old_Abort = 5, Old_Retry = 6,
               Old_Ignore = 7, Old_YesAll = 8, Old_NoAll = 9, Old_ButtonMask = 0xFF,
               NewButtonMask = 0xFFFFFC00 };
 
 enum DetailButtonLabel { ShowLabel = 0, HideLabel = 1 };
-#ifndef QT_NO_TEXTEDIT
+#if QT_CONFIG(textedit)
 class QMessageBoxDetailsText : public QWidget
 {
+    Q_OBJECT
 public:
     class TextEdit : public QTextEdit
     {
     public:
-        TextEdit(QWidget *parent=0) : QTextEdit(parent) { }
-        void contextMenuEvent(QContextMenuEvent * e)
-        {
+        TextEdit(QWidget *parent=nullptr) : QTextEdit(parent) { }
 #ifndef QT_NO_CONTEXTMENU
-            QMenu *menu = createStandardContextMenu();
-            menu->setAttribute(Qt::WA_DeleteOnClose);
-            menu->popup(e->globalPos());
-#else
-            Q_UNUSED(e);
-#endif
+        void contextMenuEvent(QContextMenuEvent * e) override
+        {
+            if (QMenu *menu = createStandardContextMenu()) {
+                menu->setAttribute(Qt::WA_DeleteOnClose);
+                menu->popup(e->globalPos());
+            }
         }
+#endif // QT_NO_CONTEXTMENU
     };
 
-    QMessageBoxDetailsText(QWidget *parent=0)
+    QMessageBoxDetailsText(QWidget *parent=nullptr)
         : QWidget(parent)
+        , copyAvailable(false)
     {
         QVBoxLayout *layout = new QVBoxLayout;
-        layout->setMargin(0);
+        layout->setContentsMargins(QMargins());
         QFrame *line = new QFrame(this);
         line->setFrameShape(QFrame::HLine);
         line->setFrameShadow(QFrame::Sunken);
@@ -119,13 +96,41 @@
         textEdit->setReadOnly(true);
         layout->addWidget(textEdit);
         setLayout(layout);
+
+        connect(textEdit, SIGNAL(copyAvailable(bool)),
+                this, SLOT(textCopyAvailable(bool)));
     }
     void setText(const QString &text) { textEdit->setPlainText(text); }
     QString text() const { return textEdit->toPlainText(); }
+
+    bool copy()
+    {
+#ifdef QT_NO_CLIPBOARD
+        return false;
+#else
+        if (!copyAvailable)
+            return false;
+        textEdit->copy();
+        return true;
+#endif
+    }
+
+    void selectAll()
+    {
+        textEdit->selectAll();
+    }
+
+private slots:
+    void textCopyAvailable(bool available)
+    {
+        copyAvailable = available;
+    }
+
 private:
+    bool copyAvailable;
     TextEdit *textEdit;
 };
-#endif // QT_NO_TEXTEDIT
+#endif // QT_CONFIG(textedit)
 
 class DetailButton : public QPushButton
 {
@@ -141,7 +146,7 @@
     void setLabel(DetailButtonLabel lbl)
     { setText(label(lbl)); }
 
-    QSize sizeHint() const
+    QSize sizeHint() const override
     {
         ensurePolished();
         QStyleOptionButton opt;
@@ -149,31 +154,32 @@
         const QFontMetrics fm = fontMetrics();
         opt.text = label(ShowLabel);
         QSize sz = fm.size(Qt::TextShowMnemonic, opt.text);
-        QSize ret = style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this).
-                      expandedTo(QApplication::globalStrut());
+        QSize ret = style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this);
         opt.text = label(HideLabel);
         sz = fm.size(Qt::TextShowMnemonic, opt.text);
-        ret = ret.expandedTo(style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this).
-                      expandedTo(QApplication::globalStrut()));
+        ret = ret.expandedTo(style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this));
         return ret;
     }
 };
 
-
 class QMessageBoxPrivate : public QDialogPrivate
 {
     Q_DECLARE_PUBLIC(QMessageBox)
 
 public:
-    QMessageBoxPrivate() : escapeButton(0), defaultButton(0), clickedButton(0), detailsButton(0),
-#ifndef QT_NO_TEXTEDIT
-                           detailsText(0),
+    QMessageBoxPrivate() : escapeButton(nullptr), defaultButton(nullptr), checkbox(nullptr), clickedButton(nullptr), detailsButton(nullptr),
+#if QT_CONFIG(textedit)
+                           detailsText(nullptr),
 #endif
                            compatMode(false), autoAddOkButton(true),
-                           detectedEscapeButton(0), informativeLabel(0) { }
+                           detectedEscapeButton(nullptr), informativeLabel(nullptr),
+                           options(QMessageDialogOptions::create()) { }
 
     void init(const QString &title = QString(), const QString &text = QString());
+    void setupLayout();
     void _q_buttonClicked(QAbstractButton *);
+    void _q_helperClicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
+    void setClickedButton(QAbstractButton *button);
 
     QAbstractButton *findButton(int button0, int button1, int button2, int flags);
     void addOldButtons(int button0, int button1, int button2);
@@ -186,9 +192,8 @@
     int layoutMinimumWidth();
     void retranslateStrings();
 
-#ifdef Q_WS_WINCE
-    void hideSpecial();
-#endif
+    void setVisible(bool visible) override;
+    bool canBeNativeDialog() const override;
 
     static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
                                  const QString &title, const QString &text,
@@ -206,6 +211,7 @@
                 QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
 
     static QPixmap standardIcon(QMessageBox::Icon icon, QMessageBox *mb);
+    static QMessageBox::StandardButton standardButtonForRole(QMessageBox::ButtonRole role);
 
     QLabel *label;
     QMessageBox::Icon icon;
@@ -214,21 +220,24 @@
     QList<QAbstractButton *> customButtonList;
     QAbstractButton *escapeButton;
     QPushButton *defaultButton;
+    QCheckBox *checkbox;
     QAbstractButton *clickedButton;
     DetailButton *detailsButton;
-#ifndef QT_NO_TEXTEDIT
+#if QT_CONFIG(textedit)
     QMessageBoxDetailsText *detailsText;
 #endif
     bool compatMode;
     bool autoAddOkButton;
     QAbstractButton *detectedEscapeButton;
     QLabel *informativeLabel;
-#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
-    QTextBrowser *textBrowser;
-#endif
     QPointer<QObject> receiverToDisconnectOnClose;
     QByteArray memberToDisconnectOnClose;
     QByteArray signalToDisconnectOnClose;
+    QSharedPointer<QMessageDialogOptions> options;
+private:
+    void initHelper(QPlatformDialogHelper *) override;
+    void helperPrepareShow(QPlatformDialogHelper *) override;
+    int dialogCode() const override;
 };
 
 void QMessageBoxPrivate::init(const QString &title, const QString &text)
@@ -236,68 +245,84 @@
     Q_Q(QMessageBox);
 
     label = new QLabel;
-    label->setObjectName(QLatin1String("qt_msgbox_label"));
-    label->setTextInteractionFlags(Qt::TextInteractionFlags(q->style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, q)));
+    label->setObjectName("qt_msgbox_label"_L1);
+    label->setTextInteractionFlags(Qt::TextInteractionFlags(q->style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, nullptr, q)));
     label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
     label->setOpenExternalLinks(true);
-#if defined(Q_WS_MAC)
-    label->setContentsMargins(16, 0, 0, 0);
-#elif !defined(Q_WS_QWS)
-    label->setContentsMargins(2, 0, 0, 0);
-    label->setIndent(9);
-#endif
-    icon = QMessageBox::NoIcon;
-    iconLabel = new QLabel;
-    iconLabel->setObjectName(QLatin1String("qt_msgboxex_icon_label"));
+    iconLabel = new QLabel(q);
+    iconLabel->setObjectName("qt_msgboxex_icon_label"_L1);
     iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
 
     buttonBox = new QDialogButtonBox;
-    buttonBox->setObjectName(QLatin1String("qt_msgbox_buttonbox"));
-    buttonBox->setCenterButtons(q->style()->styleHint(QStyle::SH_MessageBox_CenterButtons, 0, q));
+    buttonBox->setObjectName("qt_msgbox_buttonbox"_L1);
+    buttonBox->setCenterButtons(q->style()->styleHint(QStyle::SH_MessageBox_CenterButtons, nullptr, q));
     QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)),
                      q, SLOT(_q_buttonClicked(QAbstractButton*)));
-
-    QGridLayout *grid = new QGridLayout;
-#ifndef Q_WS_MAC
-#ifdef Q_WS_S60
-    const int preferredIconColumn = (QApplication::layoutDirection() == Qt::LeftToRight) ? 1 : 0;
-    const int preferredTextColumn = (QApplication::layoutDirection() == Qt::LeftToRight) ? 0 : 1;
-#else
-    const int preferredIconColumn = 0;
-    const int preferredTextColumn = 1;
-#endif
-    grid->addWidget(iconLabel, 0, preferredIconColumn, 2, 1, Qt::AlignTop);
-    grid->addWidget(label, 0, preferredTextColumn, 1, 1);
-    // -- leave space for information label --
-    grid->addWidget(buttonBox, 2, 0, 1, 2);
-#else
-    grid->setMargin(0);
-    grid->setVerticalSpacing(8);
-    grid->setHorizontalSpacing(0);
-    q->setContentsMargins(24, 15, 24, 20);
-    grid->addWidget(iconLabel, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
-    grid->addWidget(label, 0, 1, 1, 1);
-    // -- leave space for information label --
-    grid->setRowStretch(1, 100);
-    grid->setRowMinimumHeight(2, 6);
-    grid->addWidget(buttonBox, 3, 1, 1, 1);
-#endif
-
-    grid->setSizeConstraint(QLayout::SetNoConstraint);
-    q->setLayout(grid);
-
+    setupLayout();
     if (!title.isEmpty() || !text.isEmpty()) {
         q->setWindowTitle(title);
         q->setText(text);
     }
     q->setModal(true);
-
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     QFont f = q->font();
     f.setBold(true);
     label->setFont(f);
 #endif
+    icon = QMessageBox::NoIcon;
+}
+
+void QMessageBoxPrivate::setupLayout()
+{
+    Q_Q(QMessageBox);
+    delete q->layout();
+    QGridLayout *grid = new QGridLayout;
+    const bool hasIcon = !iconLabel->pixmap().isNull();
+
+    if (hasIcon)
+        grid->addWidget(iconLabel, 0, 0, 2, 1, Qt::AlignTop);
+    iconLabel->setVisible(hasIcon);
+#ifdef Q_OS_MAC
+    QSpacerItem *indentSpacer = new QSpacerItem(14, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
+#else
+    QSpacerItem *indentSpacer = new QSpacerItem(hasIcon ? 7 : 15, 1, QSizePolicy::Fixed, QSizePolicy::Fixed);
+#endif
+    grid->addItem(indentSpacer, 0, hasIcon ? 1 : 0, 2, 1);
+    grid->addWidget(label, 0, hasIcon ? 2 : 1, 1, 1);
+    if (informativeLabel) {
+#ifndef Q_OS_MAC
+        informativeLabel->setContentsMargins(0, 7, 0, 7);
+#endif
+        grid->addWidget(informativeLabel, 1, hasIcon ? 2 : 1, 1, 1);
+    }
+    if (checkbox) {
+        grid->addWidget(checkbox, informativeLabel ? 2 : 1, hasIcon ? 2 : 1, 1, 1, Qt::AlignLeft);
+#ifdef Q_OS_MAC
+        grid->addItem(new QSpacerItem(1, 15, QSizePolicy::Fixed, QSizePolicy::Fixed), grid->rowCount(), 0);
+#else
+        grid->addItem(new QSpacerItem(1, 7, QSizePolicy::Fixed, QSizePolicy::Fixed), grid->rowCount(), 0);
+#endif
+    }
+#ifdef Q_OS_MAC
+    grid->addWidget(buttonBox, grid->rowCount(), hasIcon ? 2 : 1, 1, 1);
+    grid->setContentsMargins(0, 0, 0, 0);
+    grid->setVerticalSpacing(8);
+    grid->setHorizontalSpacing(0);
+    q->setContentsMargins(24, 15, 24, 20);
+    grid->setRowStretch(1, 100);
+    grid->setRowMinimumHeight(2, 6);
+#else
+    grid->addWidget(buttonBox, grid->rowCount(), 0, 1, grid->columnCount());
+#endif
+#if QT_CONFIG(textedit)
+    if (detailsText)
+        grid->addWidget(detailsText, grid->rowCount(), 0, 1, grid->columnCount());
+#endif
+    grid->setSizeConstraint(QLayout::SetNoConstraint);
+    q->setLayout(grid);
+
     retranslateStrings();
+    updateSize();
 }
 
 int QMessageBoxPrivate::layoutMinimumWidth()
@@ -313,27 +338,16 @@
     if (!q->isVisible())
         return;
 
-    QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
-#if defined(Q_WS_QWS) || defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
-    // the width of the screen, less the window border.
-    int hardLimit = screenSize.width() - (q->frameGeometry().width() - q->geometry().width());
-#else
+    const QSize screenSize = q->screen()->availableGeometry().size();
     int hardLimit = qMin(screenSize.width() - 480, 1000); // can never get bigger than this
     // on small screens allows the messagebox be the same size as the screen
     if (screenSize.width() <= 1024)
         hardLimit = screenSize.width();
-#endif
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     int softLimit = qMin(screenSize.width()/2, 420);
-#elif defined(Q_WS_QWS)
-    int softLimit = qMin(hardLimit, 500);
 #else
     // note: ideally on windows, hard and soft limits but it breaks compat
-#ifndef Q_WS_WINCE
     int softLimit = qMin(screenSize.width()/2, 500);
-#else
-    int softLimit = qMin(screenSize.width() * 3 / 4, 500);
-#endif //Q_WS_WINCE
 #endif
 
     if (informativeLabel)
@@ -348,7 +362,7 @@
 
         if (width > hardLimit) {
             label->d_func()->ensureTextControl();
-            if (QTextControl *control = label->d_func()->control) {
+            if (QWidgetTextControl *control = label->d_func()->control) {
                 QTextOption opt = control->document()->defaultTextOption();
                 opt.setWrapMode(QTextOption::WrapAnywhere);
                 control->document()->setDefaultTextOption(opt);
@@ -356,15 +370,6 @@
             width = hardLimit;
         }
     }
-#ifdef Q_WS_S60
-        // in S60 portait messageBoxes should always occupy maximum width
-        if (QApplication::desktop()->size().height() > QApplication::desktop()->size().width()){
-            width = hardLimit;
-        } else {
-            // in landscape the messageBoxes should be of same width as in portrait
-            width = qMin(QApplication::desktop()->size().height(), hardLimit);
-        }
-#endif
 
     if (informativeLabel) {
         label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
@@ -374,7 +379,7 @@
         width = qMax(width, layoutMinimumWidth());
         if (width > hardLimit) { // longest word is really big, so wrap anywhere
             informativeLabel->d_func()->ensureTextControl();
-            if (QTextControl *control = informativeLabel->d_func()->control) {
+            if (QWidgetTextControl *control = informativeLabel->d_func()->control) {
                 QTextOption opt = control->document()->defaultTextOption();
                 opt.setWrapMode(QTextOption::WrapAnywhere);
                 control->document()->setDefaultTextOption(opt);
@@ -385,8 +390,8 @@
         label->setSizePolicy(policy);
     }
 
-    QFontMetrics fm(QApplication::font("QWorkspaceTitleBar"));
-    int windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+    QFontMetrics fm(QApplication::font("QMdiSubWindowTitleBar"));
+    int windowTitleWidth = qMin(fm.horizontalAdvance(q->windowTitle()) + 50, hardLimit);
     if (windowTitleWidth > width)
         width = windowTitleWidth;
 
@@ -395,41 +400,10 @@
                      ? layout->totalHeightForWidth(width)
                      : layout->totalMinimumSize().height();
 
-#ifndef QT_NO_STYLE_S60
-        QS60Style *s60Style = 0;
-        s60Style = qobject_cast<QS60Style *>(QApplication::style());
-
-        //use custom pixel metric to deduce the minimum height of the messagebox
-        if (s60Style)
-            height = qMax(height, s60Style->pixelMetric((QStyle::PixelMetric)PM_MessageBoxHeight));
-#endif
-
     q->setFixedSize(width, height);
     QCoreApplication::removePostedEvents(q, QEvent::LayoutRequest);
 }
 
-
-#ifdef Q_WS_WINCE
-/*!
-  \internal
-  Hides special buttons which are rather shown in the title bar
-  on WinCE, to conserve screen space.
-*/
-
-void QMessageBoxPrivate::hideSpecial()
-{
-    Q_Q(QMessageBox);
-    QList<QPushButton*> list = q->findChildren<QPushButton*>();
-        for (int i=0; i<list.size(); ++i) {
-            QPushButton *pb = list.at(i);
-            QString text = pb->text();
-            text.remove(QChar::fromLatin1('&'));
-            if (text == QApplication::translate("QMessageBox", "OK" ))
-                pb->setFixedSize(0,0);
-        }
-}
-#endif
-
 static int oldButton(int button)
 {
     switch (button & QMessageBox::ButtonMask) {
@@ -467,10 +441,30 @@
     return ret;
 }
 
+int QMessageBoxPrivate::dialogCode() const
+{
+    Q_Q(const QMessageBox);
+
+    if (clickedButton) {
+        switch (q->buttonRole(clickedButton)) {
+        case QMessageBox::AcceptRole:
+        case QMessageBox::YesRole:
+            return QDialog::Accepted;
+        case QMessageBox::RejectRole:
+        case QMessageBox::NoRole:
+            return QDialog::Rejected;
+        default:
+            ;
+        }
+    }
+
+    return QDialogPrivate::dialogCode();
+}
+
 void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
 {
     Q_Q(QMessageBox);
-#ifndef QT_NO_TEXTEDIT
+#if QT_CONFIG(textedit)
     if (detailsButton && detailsText && button == detailsButton) {
         detailsButton->setLabel(detailsText->isHidden() ? HideLabel : ShowLabel);
         detailsText->setHidden(!detailsText->isHidden());
@@ -478,20 +472,48 @@
     } else
 #endif
     {
-        clickedButton = button;
-        q->done(execReturnCode(button)); // does not trigger closeEvent
-        emit q->buttonClicked(button);
+        setClickedButton(button);
 
         if (receiverToDisconnectOnClose) {
             QObject::disconnect(q, signalToDisconnectOnClose, receiverToDisconnectOnClose,
                                 memberToDisconnectOnClose);
-            receiverToDisconnectOnClose = 0;
+            receiverToDisconnectOnClose = nullptr;
         }
         signalToDisconnectOnClose.clear();
         memberToDisconnectOnClose.clear();
     }
 }
 
+void QMessageBoxPrivate::setClickedButton(QAbstractButton *button)
+{
+    Q_Q(QMessageBox);
+
+    clickedButton = button;
+    emit q->buttonClicked(clickedButton);
+
+    auto resultCode = execReturnCode(button);
+    q->done(resultCode);
+}
+
+void QMessageBoxPrivate::_q_helperClicked(QPlatformDialogHelper::StandardButton helperButton, QPlatformDialogHelper::ButtonRole role)
+{
+    Q_UNUSED(role);
+    Q_Q(QMessageBox);
+
+    // Map back to QAbstractButton, so that the message box behaves the same from
+    // the outside, regardless of whether it's backed by a native helper or not.
+    QAbstractButton *dialogButton = helperButton > QPlatformDialogHelper::LastButton ?
+        static_cast<QAbstractButton *>(options->customButton(helperButton)->button) :
+        q->button(QMessageBox::StandardButton(helperButton));
+
+    Q_ASSERT(dialogButton);
+
+    // Simulate click by explicitly clicking the button. This will ensure that
+    // any logic of the button that responds to the click is respected, including
+    // plumbing back to _q_buttonClicked above based on the clicked() signal.
+    dialogButton->click();
+}
+
 /*!
     \class QMessageBox
 
@@ -499,14 +521,15 @@
     the user or for asking the user a question and receiving an answer.
 
     \ingroup standard-dialogs
-
+    \inmodule QtWidgets
 
     A message box displays a primary \l{QMessageBox::text}{text} to
     alert the user to a situation, an \l{QMessageBox::informativeText}
-    {informative text} to further explain the alert or to ask the user
-    a question, and an optional \l{QMessageBox::detailedText}
-    {detailed text} to provide even more data if the user requests
-    it. A message box can also display an \l{QMessageBox::icon} {icon}
+    {informative text} to further explain the situation, and an optional
+    \l{QMessageBox::detailedText} {detailed text} to provide even more data
+    if the user requests it.
+
+    A message box can also display an \l{QMessageBox::icon} {icon}
     and \l{QMessageBox::standardButtons} {standard buttons} for
     accepting a user response.
 
@@ -523,52 +546,46 @@
     the message. The simplest configuration is to set only the
     \l{QMessageBox::text} {message text} property.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 5
-
-    The user must click the \gui{OK} button to dismiss the message
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 5
+
+    The user must click the \uicontrol{OK} button to dismiss the message
     box. The rest of the GUI is blocked until the message box is
     dismissed.
 
     \image msgbox1.png
 
     A better approach than just alerting the user to an event is to
-    also ask the user what to do about it. Store the question in the
-    \l{QMessageBox::informativeText} {informative text} property, and
-    set the \l{QMessageBox::standardButtons} {standard buttons}
+    also ask the user what to do about it.
+
+    Set the \l{QMessageBox::standardButtons} {standard buttons}
     property to the set of buttons you want as the set of user
     responses. The buttons are specified by combining values from
     StandardButtons using the bitwise OR operator. The display order
     for the buttons is platform-dependent. For example, on Windows,
-    \gui{Save} is displayed to the left of \gui{Cancel}, whereas on
-    Mac OS, the order is reversed.
-
-    Mark one of your standard buttons to be your
+    \uicontrol{Save} is displayed to the left of \uicontrol{Cancel}, whereas on
+    \macos, the order is reversed. Mark one of your standard buttons to be your
     \l{QMessageBox::defaultButton()} {default button}.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 6
-
-    This is the approach recommended in the
-    \l{http://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/AppleHIGuidelines/Windows/Windows.html#//apple_ref/doc/uid/20000961-BABCAJID}
-    {Mac OS X Guidelines}. Similar guidelines apply for the other
-    platforms, but note the different ways the
-    \l{QMessageBox::informativeText} {informative text} is handled for
-    different platforms.
+    The \l{QMessageBox::informativeText} {informative text} property can
+    be used to add additional context to help the user choose the appropriate action.
+
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 6
 
     \image msgbox2.png
 
     The exec() slot returns the StandardButtons value of the button
     that was clicked.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 7
-
-    To give the user more information to help him answer the question,
-    set the \l{QMessageBox::detailedText} {detailed text} property. If
-    the \l{QMessageBox::detailedText} {detailed text} property is set,
-    the \gui{Show Details...} button will be shown.
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 7
+
+    To give the user more information to help them choose the appropriate,
+    action, set the \l{QMessageBox::detailedText} {detailed text} property.
+    Depending on the platform the \l{QMessageBox::detailedText} {detailed text},
+    may require the user to click a \uicontrol{Show Details...} button to be shown.
 
     \image msgbox3.png
 
-    Clicking the \gui{Show Details...} button displays the detailed text.
+    Clicking the \uicontrol{Show Details...} button displays the detailed text.
 
     \image msgbox4.png
 
@@ -602,21 +619,21 @@
 
     \table
     \row
-    \o \img qmessagebox-quest.png
-    \o \l Question
-    \o For asking a question during normal operations.
+    \li \image qmessagebox-quest.png
+    \li \l Question
+    \li For asking a question during normal operations.
     \row
-    \o \img qmessagebox-info.png
-    \o \l Information
-    \o For reporting information about normal operations.
+    \li \image qmessagebox-info.png
+    \li \l Information
+    \li For reporting information about normal operations.
     \row
-    \o \img qmessagebox-warn.png
-    \o \l Warning
-    \o For reporting non-critical errors.
+    \li \image qmessagebox-warn.png
+    \li \l Warning
+    \li For reporting non-critical errors.
     \row
-    \o \img qmessagebox-crit.png
-    \o \l Critical
-    \o For reporting critical errors.
+    \li \image qmessagebox-crit.png
+    \li \l Critical
+    \li For reporting critical errors.
     \endtable
 
     \l{QMessageBox::Icon}{Predefined icons} are not defined by QMessageBox, but
@@ -657,7 +674,7 @@
     Static functions are available for creating information(),
     question(), warning(), and critical() message boxes.
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 0
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 0
 
     The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
     how to use QMessageBox and the other built-in Qt dialogs.
@@ -666,45 +683,51 @@
 
     If the \l{QMessageBox::StandardButtons} {standard buttons} are not
     flexible enough for your message box, you can use the addButton()
-    overload that takes a text and a ButtonRoleto to add custom
+    overload that takes a text and a ButtonRole to add custom
     buttons. The ButtonRole is used by QMessageBox to determine the
     ordering of the buttons on screen (which varies according to the
     platform). You can test the value of clickedButton() after calling
     exec(). For example,
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 2
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 2
 
     \section1 Default and Escape Keys
 
-    The default button (i.e., the button activated when \key Enter is
+    The default button (i.e., the button activated when \uicontrol Enter is
     pressed) can be specified using setDefaultButton(). If a default
     button is not specified, QMessageBox tries to find one based on
     the \l{ButtonRole} {button roles} of the buttons used in the
     message box.
 
-    The escape button (the button activated when \key Esc is pressed)
+    The escape button (the button activated when \uicontrol Esc is pressed)
     can be specified using setEscapeButton().  If an escape button is
     not specified, QMessageBox tries to find one using these rules:
 
     \list 1
 
-    \o If there is only one button, it is the button activated when
-    \key Esc is pressed.
-
-    \o If there is a \l Cancel button, it is the button activated when
-    \key Esc is pressed.
-
-    \o If there is exactly one button having either
+    \li If there is only one button, it is the button activated when
+    \uicontrol Esc is pressed.
+
+    \li If there is a \l Cancel button, it is the button activated when
+    \uicontrol Esc is pressed.
+
+    \li If there is exactly one button having either
        \l{QMessageBox::RejectRole} {the Reject role} or the
        \l{QMessageBox::NoRole} {the No role}, it is the button
-       activated when \key Esc is pressed.
+       activated when \uicontrol Esc is pressed.
 
     \endlist
 
     When an escape button can't be determined using these rules,
-    pressing \key Esc has no effect.
-
-    \sa QDialogButtonBox, {fowler}{GUI Design Handbook: Message Box}, {Standard Dialogs Example}, {Application Example}
+    pressing \uicontrol Esc has no effect.
+
+    \sa QDialogButtonBox, {Standard Dialogs Example}
+*/
+
+/*!
+    \enum QMessageBox::ButtonRole
+
+    \include qdialogbuttonbox.cpp buttonrole-enum
 */
 
 /*!
@@ -715,7 +738,7 @@
     defined \l ButtonRole.
 
     \value Ok An "OK" button defined with the \l AcceptRole.
-    \value Open A "Open" button defined with the \l AcceptRole.
+    \value Open An "Open" button defined with the \l AcceptRole.
     \value Save A "Save" button defined with the \l AcceptRole.
     \value Cancel A "Cancel" button defined with the \l RejectRole.
     \value Close A "Close" button defined with the \l RejectRole.
@@ -754,6 +777,12 @@
 */
 
 /*!
+    \enum QMessageBox::Option
+    \since 6.6
+    \value DontUseNativeDialog Don't use the native message dialog.
+*/
+
+/*!
     \fn void QMessageBox::buttonClicked(QAbstractButton *button)
 
     This signal is emitted whenever a button is clicked inside the QMessageBox.
@@ -761,14 +790,21 @@
 */
 
 /*!
-    Constructs a message box with no text and no buttons. \a parent is
-    passed to the QDialog constructor.
-
-    On Mac OS X, if you want your message box to appear
+    Constructs an \l{Qt::ApplicationModal} {application modal} message box with no text and no buttons.
+    \a parent is passed to the QDialog constructor.
+
+    The window modality can be overridden via setWindowModality() before calling show().
+
+    \note Using open() or exec() to show the message box affects the window modality.
+    Please see the detailed documentation for each function for more information.
+
+    On \macos, if you want your message box to appear
     as a Qt::Sheet of its \a parent, set the message box's
     \l{setWindowModality()} {window modality} to Qt::WindowModal or use open().
     Otherwise, the message box will be a standard dialog.
 
+    \sa setWindowTitle(), setText(), setIcon(), setStandardButtons(), setWindowModality()
+
 */
 QMessageBox::QMessageBox(QWidget *parent)
     : QDialog(*new QMessageBoxPrivate, parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
@@ -778,20 +814,22 @@
 }
 
 /*!
-    Constructs a message box with the given \a icon, \a title, \a
-    text, and standard \a buttons. Standard or custom buttons can be
+    Constructs an \l{Qt::ApplicationModal} {application modal} message box with the given \a icon,
+    \a title, \a text, and standard \a buttons. Standard or custom buttons can be
     added at any time using addButton(). The \a parent and \a f
     arguments are passed to the QDialog constructor.
 
-    The message box is an \l{Qt::ApplicationModal} {application modal}
-    dialog box.
-
-    On Mac OS X, if \a parent is not 0 and you want your message box
+    The window modality can be overridden via setWindowModality() before calling show().
+
+    \note Using open() or exec() to show the message box affects the window modality.
+    Please see the detailed documentation for each function for more information.
+
+    On \macos, if \a parent is not \nullptr and you want your message box
     to appear as a Qt::Sheet of that parent, set the message box's
     \l{setWindowModality()} {window modality} to Qt::WindowModal
     (default). Otherwise, the message box will be a standard dialog.
 
-    \sa setWindowTitle(), setText(), setIcon(), setStandardButtons()
+    \sa setWindowTitle(), setText(), setIcon(), setStandardButtons(), setWindowModality()
 */
 QMessageBox::QMessageBox(Icon icon, const QString &title, const QString &text,
                          StandardButtons buttons, QWidget *parent,
@@ -826,11 +864,39 @@
     if (!button)
         return;
     removeButton(button);
+
+    if (button->text().isEmpty()) {
+        if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+            if (auto standardButton = QMessageBoxPrivate::standardButtonForRole(role))
+                button->setText(platformTheme->standardButtonText(standardButton));
+        }
+
+        if (button->text().isEmpty()) {
+            qWarning() << "Cannot add" << button << "without title";
+            return;
+        }
+    }
+
     d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role);
     d->customButtonList.append(button);
     d->autoAddOkButton = false;
 }
 
+QMessageBox::StandardButton QMessageBoxPrivate::standardButtonForRole(QMessageBox::ButtonRole role)
+{
+    switch (role) {
+    case QMessageBox::AcceptRole: return QMessageBox::Ok;
+    case QMessageBox::RejectRole: return QMessageBox::Cancel;
+    case QMessageBox::DestructiveRole: return QMessageBox::Discard;
+    case QMessageBox::HelpRole: return QMessageBox::Help;
+    case QMessageBox::ApplyRole: return QMessageBox::Apply;
+    case QMessageBox::YesRole: return QMessageBox::Yes;
+    case QMessageBox::NoRole: return QMessageBox::No;
+    case QMessageBox::ResetRole: return QMessageBox::Reset;
+    default: return QMessageBox::NoButton;
+    }
+}
+
 /*!
     \since 4.2
     \overload
@@ -877,9 +943,9 @@
     Q_D(QMessageBox);
     d->customButtonList.removeAll(button);
     if (d->escapeButton == button)
-        d->escapeButton = 0;
+        d->escapeButton = nullptr;
     if (d->defaultButton == button)
-        d->defaultButton = 0;
+        d->defaultButton = nullptr;
     d->buttonBox->removeButton(button);
     d->updateSize();
 }
@@ -902,9 +968,9 @@
 
     QList<QAbstractButton *> buttonList = d->buttonBox->buttons();
     if (!buttonList.contains(d->escapeButton))
-        d->escapeButton = 0;
+        d->escapeButton = nullptr;
     if (!buttonList.contains(d->defaultButton))
-        d->defaultButton = 0;
+        d->defaultButton = nullptr;
     d->autoAddOkButton = false;
     d->updateSize();
 }
@@ -933,7 +999,13 @@
     \since 4.2
 
     Returns a pointer corresponding to the standard button \a which,
-    or 0 if the standard button doesn't exist in this message box.
+    or \nullptr if the standard button doesn't exist in this message box.
+
+    \note Modifying the properties of the returned button may not be reflected
+    in native implementations of the message dialog. To customize dialog
+    buttons add a \l{addButton(QAbstractButton *button, QMessageBox::ButtonRole role)}
+    {custom button} or \l{addButton(const QString &text, QMessageBox::ButtonRole role)}
+    {button title} instead, or set the \l Option::DontUseNativeDialog option.
 
     \sa standardButtons, standardButton()
 */
@@ -952,14 +1024,14 @@
     escape button as follows:
 
     \list 1
-    \o If there is only one button, it is made the escape button.
-    \o If there is a \l Cancel button, it is made the escape button.
-    \o On Mac OS X only, if there is exactly one button with the role
+    \li If there is only one button, it is made the escape button.
+    \li If there is a \l Cancel button, it is made the escape button.
+    \li On \macos only, if there is exactly one button with the role
        QMessageBox::RejectRole, it is made the escape button.
     \endlist
 
     When an escape button could not be automatically detected, pressing
-    \key Esc has no effect.
+    \uicontrol Esc has no effect.
 
     \sa addButton()
 */
@@ -972,7 +1044,7 @@
 /*!
     \since 4.2
 
-    Sets the button that gets activated when the \key Escape key is
+    Sets the button that gets activated when the \uicontrol Escape key is
     pressed to \a button.
 
     \sa addButton(), clickedButton()
@@ -987,7 +1059,7 @@
 /*!
     \since 4.3
 
-    Sets the buttons that gets activated when the \key Escape key is
+    Sets the buttons that gets activated when the \uicontrol Escape key is
     pressed to \a button.
 
     \sa addButton(), clickedButton()
@@ -1012,32 +1084,42 @@
 
     // If there is only one button, make it the escape button
     const QList<QAbstractButton *> buttons = buttonBox->buttons();
-    if (buttons.count() == 1) {
+    if (buttons.size() == 1) {
         detectedEscapeButton = buttons.first();
         return;
     }
 
+    // If there are two buttons and one of them is the "Show Details..."
+    // button, then make the other one the escape button
+    if (buttons.size() == 2 && detailsButton) {
+        auto idx = buttons.indexOf(detailsButton);
+        if (idx != -1) {
+            detectedEscapeButton = buttons.at(1 - idx);
+            return;
+        }
+    }
+
     // if the message box has one RejectRole button, make it the escape button
-    for (int i = 0; i < buttons.count(); i++) {
-        if (buttonBox->buttonRole(buttons.at(i)) == QDialogButtonBox::RejectRole) {
+    for (auto *button : buttons) {
+        if (buttonBox->buttonRole(button) == QDialogButtonBox::RejectRole) {
             if (detectedEscapeButton) { // already detected!
-                detectedEscapeButton = 0;
+                detectedEscapeButton = nullptr;
                 break;
             }
-            detectedEscapeButton = buttons.at(i);
+            detectedEscapeButton = button;
         }
     }
     if (detectedEscapeButton)
         return;
 
     // if the message box has one NoRole button, make it the escape button
-    for (int i = 0; i < buttons.count(); i++) {
-        if (buttonBox->buttonRole(buttons.at(i)) == QDialogButtonBox::NoRole) {
+    for (auto *button : buttons) {
+        if (buttonBox->buttonRole(button) == QDialogButtonBox::NoRole) {
             if (detectedEscapeButton) { // already detected!
-                detectedEscapeButton = 0;
+                detectedEscapeButton = nullptr;
                 break;
             }
-            detectedEscapeButton = buttons.at(i);
+            detectedEscapeButton = button;
         }
     }
 }
@@ -1046,14 +1128,14 @@
     \since 4.2
 
     Returns the button that was clicked by the user,
-    or 0 if the user hit the \key Esc key and
+    or \nullptr if the user hit the \uicontrol Esc key and
     no \l{setEscapeButton()}{escape button} was set.
 
-    If exec() hasn't been called yet, returns 0.
+    If exec() hasn't been called yet, returns nullptr.
 
     Example:
 
-    \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 3
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 3
 
     \sa standardButton(), button()
 */
@@ -1067,7 +1149,7 @@
     \since 4.2
 
     Returns the button that should be the message box's
-    \l{QPushButton::setDefault()}{default button}. Returns 0
+    \l{QPushButton::setDefault()}{default button}. Returns nullptr
     if no default button was set.
 
     \sa addButton(), QPushButton::setDefault()
@@ -1110,10 +1192,130 @@
     setDefaultButton(d->buttonBox->button(QDialogButtonBox::StandardButton(button)));
 }
 
+/*! \since 5.2
+
+    Sets the checkbox \a cb on the message dialog. The message box takes ownership of the checkbox.
+    The argument \a cb can be \nullptr to remove an existing checkbox from the message box.
+
+    \sa checkBox()
+*/
+
+void QMessageBox::setCheckBox(QCheckBox *cb)
+{
+    Q_D(QMessageBox);
+
+    if (cb == d->checkbox)
+        return;
+
+    if (d->checkbox) {
+        d->checkbox->hide();
+        layout()->removeWidget(d->checkbox);
+        if (d->checkbox->parentWidget() == this) {
+            d->checkbox->setParent(nullptr);
+            d->checkbox->deleteLater();
+        }
+    }
+    d->checkbox = cb;
+    if (d->checkbox) {
+        QSizePolicy sp = d->checkbox->sizePolicy();
+        sp.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
+        d->checkbox->setSizePolicy(sp);
+    }
+    d->setupLayout();
+}
+
+
+/*! \since 5.2
+
+    Returns the checkbox shown on the dialog. This is \nullptr if no checkbox is set.
+    \sa setCheckBox()
+*/
+
+QCheckBox* QMessageBox::checkBox() const
+{
+    Q_D(const QMessageBox);
+    return d->checkbox;
+}
+
+/*!
+    \since 6.6
+    Sets the given \a option to be enabled if \a on is true; otherwise,
+    clears the given \a option.
+
+    Options (particularly the \l Option::DontUseNativeDialog option) should be set
+    before showing the dialog.
+
+    Setting options while the dialog is visible is not guaranteed to have
+    an immediate effect on the dialog.
+
+    Setting options after changing other properties may cause these
+    values to have no effect.
+
+    \sa options, testOption()
+*/
+void QMessageBox::setOption(QMessageBox::Option option, bool on)
+{
+    const QMessageBox::Options previousOptions = options();
+    if (!(previousOptions & option) != !on)
+        setOptions(previousOptions ^ option);
+}
+
+/*!
+    \since 6.6
+
+    Returns \c true if the given \a option is enabled; otherwise, returns
+    false.
+
+    \sa options, setOption()
+*/
+bool QMessageBox::testOption(QMessageBox::Option option) const
+{
+    Q_D(const QMessageBox);
+    return d->options->testOption(static_cast<QMessageDialogOptions::Option>(option));
+}
+
+void QMessageBox::setOptions(QMessageBox::Options options)
+{
+    Q_D(QMessageBox);
+
+    if (QMessageBox::options() == options)
+        return;
+
+    d->options->setOptions(QMessageDialogOptions::Option(int(options)));
+}
+
+QMessageBox::Options QMessageBox::options() const
+{
+    Q_D(const QMessageBox);
+    return QMessageBox::Options(int(d->options->options()));
+}
+
+/*!
+    \property QMessageBox::options
+    \brief Options that affect the look and feel of the dialog.
+    \since 6.6
+
+    By default, these options are disabled.
+
+    The option \l Option::DontUseNativeDialog should be set
+    before changing dialog properties or showing the dialog.
+
+    Setting options while the dialog is visible is not guaranteed to have
+    an immediate effect on the dialog.
+
+    Setting options after changing other properties may cause these
+    values to have no effect.
+
+    \sa setOption(), testOption()
+*/
+
 /*!
   \property QMessageBox::text
   \brief the message box text to be displayed.
 
+  The text should be a brief sentence or phrase that describes the situation,
+  ideally formulated as a neutral statement, or a call-to-action question.
+
   The text will be interpreted either as a plain text or as rich text,
   depending on the text format setting (\l QMessageBox::textFormat).
   The default setting is Qt::AutoText, i.e., the message box will try
@@ -1167,11 +1369,11 @@
     values:
 
     \list
-    \o QMessageBox::NoIcon
-    \o QMessageBox::Question
-    \o QMessageBox::Information
-    \o QMessageBox::Warning
-    \o QMessageBox::Critical
+    \li QMessageBox::NoIcon
+    \li QMessageBox::Question
+    \li QMessageBox::Information
+    \li QMessageBox::Warning
+    \li QMessageBox::Critical
     \endlist
 
     The default is QMessageBox::NoIcon.
@@ -1212,17 +1414,15 @@
 QPixmap QMessageBox::iconPixmap() const
 {
     Q_D(const QMessageBox);
-    if (d->iconLabel && d->iconLabel->pixmap())
-        return *d->iconLabel->pixmap();
-    return QPixmap();
+    return d->iconLabel->pixmap();
 }
 
 void QMessageBox::setIconPixmap(const QPixmap &pixmap)
 {
     Q_D(QMessageBox);
     d->iconLabel->setPixmap(pixmap);
-    d->updateSize();
     d->icon = NoIcon;
+    d->setupLayout();
 }
 
 /*!
@@ -1252,6 +1452,30 @@
 }
 
 /*!
+    \property QMessageBox::textInteractionFlags
+    \since 5.1
+
+    Specifies how the label of the message box should interact with user
+    input.
+
+    The default value depends on the style.
+
+    \sa QStyle::SH_MessageBox_TextInteractionFlags
+*/
+
+Qt::TextInteractionFlags QMessageBox::textInteractionFlags() const
+{
+    Q_D(const QMessageBox);
+    return d->label->textInteractionFlags();
+}
+
+void QMessageBox::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+    Q_D(QMessageBox);
+    d->label->setTextInteractionFlags(flags);
+}
+
+/*!
     \reimp
 */
 bool QMessageBox::event(QEvent *e)
@@ -1264,24 +1488,6 @@
         case QEvent::LanguageChange:
             d_func()->retranslateStrings();
             break;
-#ifdef Q_WS_WINCE
-        case QEvent::OkRequest:
-        case QEvent::HelpRequest: {
-          QString bName =
-              (e->type() == QEvent::OkRequest)
-              ? QApplication::translate("QMessageBox", "OK")
-              : QApplication::translate("QMessageBox", "Help");
-          QList<QPushButton*> list = findChildren<QPushButton*>();
-          for (int i=0; i<list.size(); ++i) {
-              QPushButton *pb = list.at(i);
-              if (pb->text() == bName) {
-                  if (pb->isEnabled())
-                      pb->click();
-                  return pb->isEnabled();
-              }
-          }
-        }
-#endif
         default:
             break;
     }
@@ -1307,8 +1513,10 @@
         return;
     }
     QDialog::closeEvent(e);
-    d->clickedButton = d->detectedEscapeButton;
-    setResult(d->execReturnCode(d->detectedEscapeButton));
+    if (!d->clickedButton) {
+        d->clickedButton = d->detectedEscapeButton;
+        setResult(d->execReturnCode(d->detectedEscapeButton));
+    }
 }
 
 /*!
@@ -1322,22 +1530,23 @@
     {
         if (d->icon != NoIcon)
             setIcon(d->icon);
-        Qt::TextInteractionFlags flags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, this));
+        Qt::TextInteractionFlags flags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, nullptr, this));
         d->label->setTextInteractionFlags(flags);
-        d->buttonBox->setCenterButtons(style()->styleHint(QStyle::SH_MessageBox_CenterButtons, 0, this));
+        d->buttonBox->setCenterButtons(style()->styleHint(QStyle::SH_MessageBox_CenterButtons, nullptr, this));
         if (d->informativeLabel)
             d->informativeLabel->setTextInteractionFlags(flags);
-        // intentional fall through
+        Q_FALLTHROUGH();
     }
     case QEvent::FontChange:
     case QEvent::ApplicationFontChange:
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     {
         QFont f = font();
         f.setBold(true);
         d->label->setFont(f);
     }
 #endif
+        Q_FALLTHROUGH();
     default:
         break;
     }
@@ -1349,14 +1558,11 @@
 */
 void QMessageBox::keyPressEvent(QKeyEvent *e)
 {
-    Q_D(QMessageBox);
-    if (e->key() == Qt::Key_Escape
-#ifdef Q_WS_MAC
-        || (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period)
-#endif
-        ) {
+#if QT_CONFIG(shortcut)
+        Q_D(QMessageBox);
+        if (e->matches(QKeySequence::Cancel)) {
             if (d->detectedEscapeButton) {
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
                 d->detectedEscapeButton->animateClick();
 #else
                 d->detectedEscapeButton->click();
@@ -1364,39 +1570,56 @@
             }
             return;
         }
-
-#if defined (Q_OS_WIN) && !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
+#endif // QT_CONFIG(shortcut)
+
+#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
+
+#if QT_CONFIG(textedit)
         if (e == QKeySequence::Copy) {
-            QString separator = QString::fromLatin1("---------------------------\n");
-            QString textToCopy = separator;
-            separator.prepend(QLatin1Char('\n'));
-            textToCopy += windowTitle() + separator; // title
-            textToCopy += d->label->text() + separator; // text
+            if (d->detailsText && d->detailsText->isVisible() && d->detailsText->copy()) {
+                e->setAccepted(true);
+                return;
+            }
+        } else if (e == QKeySequence::SelectAll && d->detailsText && d->detailsText->isVisible()) {
+            d->detailsText->selectAll();
+            e->setAccepted(true);
+            return;
+        }
+#endif // QT_CONFIG(textedit)
+
+#if defined(Q_OS_WIN)
+        if (e == QKeySequence::Copy) {
+            const auto separator = "---------------------------\n"_L1;
+            QString textToCopy;
+            textToCopy += separator + windowTitle() + u'\n' + separator // title
+                          + d->label->text() + u'\n' + separator;       // text
 
             if (d->informativeLabel)
-                textToCopy += d->informativeLabel->text() + separator;
-
-            QString buttonTexts;
-            QList<QAbstractButton *> buttons = d->buttonBox->buttons();
-            for (int i = 0; i < buttons.count(); i++) {
-                buttonTexts += buttons[i]->text() + QLatin1String("   ");
-            }
-            textToCopy += buttonTexts + separator;
-
-            QApplication::clipboard()->setText(textToCopy);
+                textToCopy += d->informativeLabel->text() + u'\n' + separator;
+
+            const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
+            for (const auto *button : buttons)
+                textToCopy += button->text() + "   "_L1;
+            textToCopy += u'\n' + separator;
+#if QT_CONFIG(textedit)
+            if (d->detailsText)
+                textToCopy += d->detailsText->text() + u'\n' + separator;
+#endif
+            QGuiApplication::clipboard()->setText(textToCopy);
             return;
         }
-#endif //QT_NO_SHORTCUT QT_NO_CLIPBOARD Q_OS_WIN
+#endif // Q_OS_WIN
+
+#endif // !QT_NO_CLIPBOARD && !QT_NO_SHORTCUT
 
 #ifndef QT_NO_SHORTCUT
-    if (!(e->modifiers() & Qt::AltModifier)) {
-        int key = e->key() & ~((int)Qt::MODIFIER_MASK|(int)Qt::UNICODE_ACCEL);
+    if (!(e->modifiers() & (Qt::AltModifier | Qt::ControlModifier | Qt::MetaModifier))) {
+        int key = e->key() & ~Qt::MODIFIER_MASK;
         if (key) {
             const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
-            for (int i = 0; i < buttons.count(); ++i) {
-                QAbstractButton *pb = buttons.at(i);
-                int acc = pb->shortcut() & ~((int)Qt::MODIFIER_MASK|(int)Qt::UNICODE_ACCEL);
-                if (acc == key) {
+            for (auto *pb : buttons) {
+                QKeySequence shortcut = pb->shortcut();
+                if (!shortcut.isEmpty() && key == shortcut[0].key()) {
                     pb->animateClick();
                     return;
                 }
@@ -1407,23 +1630,7 @@
     QDialog::keyPressEvent(e);
 }
 
-#ifdef Q_WS_WINCE
 /*!
-    \reimp
-*/
-void QMessageBox::setVisible(bool visible)
-{
-    Q_D(QMessageBox);
-    if (visible)
-        d->hideSpecial();
-    QDialog::setVisible(visible);
-}
-#endif
-
-
-/*!
-    \overload
-
     Opens the dialog and connects its finished() or buttonClicked() signal to
     the slot specified by \a receiver and \a member. If the slot in \a member
     has a pointer for its first parameter the connection is to buttonClicked(),
@@ -1443,6 +1650,28 @@
     QDialog::open();
 }
 
+void QMessageBoxPrivate::setVisible(bool visible)
+{
+    Q_Q(QMessageBox);
+    if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
+        return;
+
+    // Last minute setup
+    if (autoAddOkButton)
+        q->addButton(QMessageBox::Ok);
+    detectEscapeButton();
+
+    if (canBeNativeDialog())
+        setNativeDialogVisible(visible);
+
+    // Update WA_DontShowOnScreen based on whether the native dialog was shown,
+    // so that QDialog::setVisible(visible) below updates the QWidget state correctly,
+    // but skips showing the non-native version.
+    q->setAttribute(Qt::WA_DontShowOnScreen, nativeDialogInUse);
+
+    QDialogPrivate::setVisible(visible);
+}
+
 /*!
     \since 4.5
 
@@ -1460,7 +1689,7 @@
     \since 4.5
 
     Returns the button role for the specified \a button. This function returns
-    \l InvalidRole if \a button is 0 or has not been added to the message box.
+    \l InvalidRole if \a button is \nullptr or has not been added to the message box.
 
     \sa buttons(), addButton()
 */
@@ -1476,27 +1705,17 @@
 void QMessageBox::showEvent(QShowEvent *e)
 {
     Q_D(QMessageBox);
-    if (d->autoAddOkButton) {
-        addButton(Ok);
-#if defined(Q_WS_WINCE)
-        d->hideSpecial();
-#endif
-    }
-    if (d->detailsButton)
-        addButton(d->detailsButton, QMessageBox::ActionRole);
-    d->detectEscapeButton();
+    d->clickedButton = nullptr;
     d->updateSize();
 
-#ifndef QT_NO_ACCESSIBILITY
-    QAccessible::updateAccessibility(this, 0, QAccessible::Alert);
+#if QT_CONFIG(accessibility)
+    QAccessibleEvent event(this, QAccessible::Alert);
+    QAccessible::updateAccessibility(&event);
 #endif
-#ifdef Q_WS_WIN
-    HMENU systemMenu = GetSystemMenu((HWND)winId(), FALSE);
-    if (!d->detectedEscapeButton) {
-        EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
-    }
-    else {
-        EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+#if defined(Q_OS_WIN)
+    if (const HMENU systemMenu = qt_getWindowsSystemMenu(this)) {
+        EnableMenuItem(systemMenu, SC_CLOSE, d->detectedEscapeButton ?
+                       MF_BYCOMMAND|MF_ENABLED : MF_BYCOMMAND|MF_GRAYED);
     }
 #endif
     QDialog::showEvent(e);
@@ -1519,7 +1738,7 @@
 
     QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
     QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
-    Q_ASSERT(buttonBox != 0);
+    Q_ASSERT(buttonBox != nullptr);
 
     uint mask = QMessageBox::FirstButton;
     while (mask <= QMessageBox::LastButton) {
@@ -1547,13 +1766,13 @@
     \a text in front of the specified \a parent widget.
 
     The standard \a buttons are added to the message box.
-    \a defaultButton specifies the button used when \key Enter is pressed.
+    \a defaultButton specifies the button used when \uicontrol Enter is pressed.
     \a defaultButton must refer to a button that was given in \a buttons.
     If \a defaultButton is QMessageBox::NoButton, QMessageBox
     chooses a suitable default automatically.
 
     Returns the identity of the standard button that was clicked. If
-    \key Esc was pressed instead, the \l{Default and Escape Keys}
+    \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
     {escape button} is returned.
 
     The message box is an \l{Qt::ApplicationModal}{application modal}
@@ -1581,13 +1800,13 @@
     text in front of the specified \a parent widget.
 
     The standard \a buttons are added to the message box. \a
-    defaultButton specifies the button used when \key Enter is
+    defaultButton specifies the button used when \uicontrol Enter is
     pressed. \a defaultButton must refer to a button that was given in \a buttons.
     If \a defaultButton is QMessageBox::NoButton, QMessageBox
     chooses a suitable default automatically.
 
     Returns the identity of the standard button that was clicked. If
-    \key Esc was pressed instead, the \l{Default and Escape Keys}
+    \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
     {escape button} is returned.
 
     The message box is an \l{Qt::ApplicationModal} {application modal}
@@ -1613,13 +1832,13 @@
     text in front of the specified \a parent widget.
 
     The standard \a buttons are added to the message box. \a
-    defaultButton specifies the button used when \key Enter is
+    defaultButton specifies the button used when \uicontrol Enter is
     pressed. \a defaultButton must refer to a button that was given in \a buttons.
     If \a defaultButton is QMessageBox::NoButton, QMessageBox
     chooses a suitable default automatically.
 
     Returns the identity of the standard button that was clicked. If
-    \key Esc was pressed instead, the \l{Default and Escape Keys}
+    \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
     {escape button} is returned.
 
     The message box is an \l{Qt::ApplicationModal} {application modal}
@@ -1645,13 +1864,13 @@
     text in front of the specified \a parent widget.
 
     The standard \a buttons are added to the message box. \a
-    defaultButton specifies the button used when \key Enter is
+    defaultButton specifies the button used when \uicontrol Enter is
     pressed. \a defaultButton must refer to a button that was given in \a buttons.
     If \a defaultButton is QMessageBox::NoButton, QMessageBox
     chooses a suitable default automatically.
 
     Returns the identity of the standard button that was clicked. If
-    \key Esc was pressed instead, the \l{Default and Escape Keys}
+    \uicontrol Esc was pressed instead, the \l{Default and Escape Keys}
     {escape button} is returned.
 
     The message box is an \l{Qt::ApplicationModal} {application modal}
@@ -1677,23 +1896,23 @@
     about() looks for a suitable icon in four locations:
 
     \list 1
-    \o It prefers \link QWidget::windowIcon() parent->icon() \endlink
+    \li It prefers \l{QWidget::windowIcon()}{parent->icon()}
     if that exists.
-    \o If not, it tries the top-level widget containing \a parent.
-    \o If that fails, it tries the \link
-    QApplication::activeWindow() active window. \endlink
-    \o As a last resort it uses the Information icon.
+    \li If not, it tries the top-level widget containing \a parent.
+    \li If that fails, it tries the \l{QApplication::activeWindow()}{active window.}
+    \li As a last resort it uses the Information icon.
     \endlist
 
-    The about box has a single button labelled "OK". On Mac OS X, the
-    about box is popped up as a modeless window; on other platforms,
-    it is currently application modal.
+    The about box has a single button labelled "OK".
+
+    On \macos, the about box is popped up as a modeless window; on
+    other platforms, it is currently application modal.
 
     \sa QWidget::windowIcon(), QApplication::activeWindow()
 */
 void QMessageBox::about(QWidget *parent, const QString &title, const QString &text)
 {
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     static QPointer<QMessageBox> oldMsgBox;
 
     if (oldMsgBox && oldMsgBox->text() == text) {
@@ -1704,8 +1923,8 @@
     }
 #endif
 
-    QMessageBox *msgBox = new QMessageBox(title, text, Information, 0, 0, 0, parent
-#ifdef Q_WS_MAC
+    QMessageBox *msgBox = new QMessageBox(Information, title, text, NoButton, parent
+#ifdef Q_OS_MAC
                                           , Qt::WindowTitleHint | Qt::WindowSystemMenuHint
 #endif
     );
@@ -1715,9 +1934,15 @@
     msgBox->setIconPixmap(icon.pixmap(size));
 
     // should perhaps be a style hint
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     oldMsgBox = msgBox;
-    msgBox->d_func()->buttonBox->setCenterButtons(true);
+    auto *d = msgBox->d_func();
+    d->buttonBox->setCenterButtons(true);
+#ifdef Q_OS_IOS
+    msgBox->setModal(true);
+#else
+    msgBox->setModal(false);
+#endif
     msgBox->show();
 #else
     msgBox->exec();
@@ -1726,22 +1951,22 @@
 
 /*!
     Displays a simple message box about Qt, with the given \a title
-    and centered over \a parent (if \a parent is not 0). The message
+    and centered over \a parent (if \a parent is not \nullptr). The message
     includes the version number of Qt being used by the application.
 
-    This is useful for inclusion in the \gui Help menu of an application,
+    This is useful for inclusion in the \uicontrol Help menu of an application,
     as shown in the \l{mainwindows/menus}{Menus} example.
 
     QApplication provides this functionality as a slot.
 
-    On Mac OS X, the about box is popped up as a modeless window; on
+    On \macos, the aboutQt box is popped up as a modeless window; on
     other platforms, it is currently application modal.
 
     \sa QApplication::aboutQt()
 */
 void QMessageBox::aboutQt(QWidget *parent, const QString &title)
 {
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     static QPointer<QMessageBox> oldMsgBox;
 
     if (oldMsgBox) {
@@ -1756,26 +1981,24 @@
     translatedTextAboutQtCaption = QMessageBox::tr(
         "<h3>About Qt</h3>"
         "<p>This program uses Qt version %1.</p>"
-        ).arg(QLatin1String(QT_VERSION_STR));
-    QString translatedTextAboutQtText;
-    translatedTextAboutQtText = QMessageBox::tr(
+        ).arg(QT_VERSION_STR ""_L1);
+    //: Leave this text untranslated or include a verbatim copy of it below
+    //: and note that it is the authoritative version in case of doubt.
+    const QString translatedTextAboutQtText = QMessageBox::tr(
         "<p>Qt is a C++ toolkit for cross-platform application "
         "development.</p>"
         "<p>Qt provides single-source portability across all major desktop "
         "operating systems. It is also available for embedded Linux and other "
         "embedded and mobile operating systems.</p>"
-        "<p>Qt is available under three different licensing options designed "
+        "<p>Qt is available under multiple licensing options designed "
         "to accommodate the needs of our various users.</p>"
         "<p>Qt licensed under our commercial license agreement is appropriate "
         "for development of proprietary/commercial software where you do not "
         "want to share any source code with third parties or otherwise cannot "
-        "comply with the terms of the GNU LGPL version 3 or GNU LGPL version 2.1.</p>"
-        "<p>Qt licensed under the GNU LGPL version 3 is appropriate for the "
+        "comply with the terms of GNU (L)GPL.</p>"
+        "<p>Qt licensed under GNU (L)GPL is appropriate for the "
         "development of Qt&nbsp;applications provided you can comply with the terms "
-        "and conditions of the GNU LGPL version 3.</p>"
-        "<p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the "
-        "development of Qt&nbsp;applications provided you can comply with the terms "
-        "and conditions of the GNU LGPL version 2.1.</p>"
+        "and conditions of the respective licenses.</p>"
         "<p>Please see <a href=\"http://%2/\">%2</a> "
         "for an overview of Qt licensing.</p>"
         "<p>Copyright (C) %1 The Qt Company Ltd and other "
@@ -1783,41 +2006,35 @@
         "<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
         "<p>Qt is The Qt Company Ltd product developed as an open source "
         "project. See <a href=\"http://%3/\">%3</a> for more information.</p>"
-        ).arg(QLatin1String("2015"),
-              QLatin1String("qt.io/licensing"),
-              QLatin1String("qt.io"));
+        ).arg(QLatin1String(QT_COPYRIGHT_YEAR),
+              QStringLiteral("qt.io/licensing"),
+              QStringLiteral("qt.io"));
     QMessageBox *msgBox = new QMessageBox(parent);
     msgBox->setAttribute(Qt::WA_DeleteOnClose);
     msgBox->setWindowTitle(title.isEmpty() ? tr("About Qt") : title);
     msgBox->setText(translatedTextAboutQtCaption);
     msgBox->setInformativeText(translatedTextAboutQtText);
 
-    QPixmap pm(QLatin1String(":/trolltech/qmessagebox/images/qtlogo-64.png"));
+    QPixmap pm(":/qt-project.org/qmessagebox/images/qtlogo-64.png"_L1);
     if (!pm.isNull())
         msgBox->setIconPixmap(pm);
-#if defined(Q_WS_WINCE)
-    msgBox->setDefaultButton(msgBox->addButton(QMessageBox::Ok));
-#endif
 
     // should perhaps be a style hint
-#ifdef Q_WS_MAC
+#ifdef Q_OS_MAC
     oldMsgBox = msgBox;
-    msgBox->d_func()->buttonBox->setCenterButtons(true);
+    auto *d = msgBox->d_func();
+    d->buttonBox->setCenterButtons(true);
+#ifdef Q_OS_IOS
+    msgBox->setModal(true);
+#else
+    msgBox->setModal(false);
+#endif
     msgBox->show();
 #else
     msgBox->exec();
 #endif
 }
 
-/*!
-    \internal
-*/
-QSize QMessageBox::sizeHint() const
-{
-    // ### Qt 5: remove
-    return QDialog::sizeHint();
-}
-
 /////////////////////////////////////////////////////////////////////////////////////////
 // Source and binary compatibility routines for 4.0 and 4.1
 
@@ -1827,31 +2044,7 @@
     if (button == QMessageBox::NoButton || (button & NewButtonMask))
         return QMessageBox::StandardButton(button & QMessageBox::ButtonMask);
 
-#if QT_VERSION < 0x050000
-    // this is needed for binary compatibility with Qt 4.0 and 4.1
-    switch (button & Old_ButtonMask) {
-    case Old_Ok:
-        return QMessageBox::Ok;
-    case Old_Cancel:
-        return QMessageBox::Cancel;
-    case Old_Yes:
-        return QMessageBox::Yes;
-    case Old_No:
-        return QMessageBox::No;
-    case Old_Abort:
-        return QMessageBox::Abort;
-    case Old_Retry:
-        return QMessageBox::Retry;
-    case Old_Ignore:
-        return QMessageBox::Ignore;
-    case Old_YesAll:
-        return QMessageBox::YesToAll;
-    case Old_NoAll:
-        return QMessageBox::NoToAll;
-    default:
-        return QMessageBox::NoButton;
-    }
-#endif
+    return QMessageBox::NoButton;
 }
 
 static bool detectedCompat(int button0, int button1, int button2)
@@ -1899,7 +2092,7 @@
     if (result)
         return result;
     if (id & QMessageBox::FlagMask)    // for compatibility with Qt 4.0/4.1 (even if it is silly)
-        return 0;
+        return nullptr;
     return q->button(newButton(id));
 }
 
@@ -1939,40 +2132,41 @@
 
 void QMessageBoxPrivate::retranslateStrings()
 {
-#ifndef QT_NO_TEXTEDIT
-    if (detailsButton)
+#if QT_CONFIG(textedit)
+    if (detailsButton && detailsText)
         detailsButton->setLabel(detailsText->isHidden() ? ShowLabel : HideLabel);
 #endif
 }
 
+#if QT_DEPRECATED_SINCE(6,2)
 /*!
-    \obsolete
+    \deprecated
 
     Constructs a message box with a \a title, a \a text, an \a icon,
     and up to three buttons.
 
     The \a icon must be one of the following:
     \list
-    \o QMessageBox::NoIcon
-    \o QMessageBox::Question
-    \o QMessageBox::Information
-    \o QMessageBox::Warning
-    \o QMessageBox::Critical
+    \li QMessageBox::NoIcon
+    \li QMessageBox::Question
+    \li QMessageBox::Information
+    \li QMessageBox::Warning
+    \li QMessageBox::Critical
     \endlist
 
     Each button, \a button0, \a button1 and \a button2, can have one
     of the following values:
     \list
-    \o QMessageBox::NoButton
-    \o QMessageBox::Ok
-    \o QMessageBox::Cancel
-    \o QMessageBox::Yes
-    \o QMessageBox::No
-    \o QMessageBox::Abort
-    \o QMessageBox::Retry
-    \o QMessageBox::Ignore
-    \o QMessageBox::YesAll
-    \o QMessageBox::NoAll
+    \li QMessageBox::NoButton
+    \li QMessageBox::Ok
+    \li QMessageBox::Cancel
+    \li QMessageBox::Yes
+    \li QMessageBox::No
+    \li QMessageBox::Abort
+    \li QMessageBox::Retry
+    \li QMessageBox::Ignore
+    \li QMessageBox::YesAll
+    \li QMessageBox::NoAll
     \endlist
 
     Use QMessageBox::NoButton for the later parameters to have fewer
@@ -1984,10 +2178,10 @@
     pressed).
 
     One of the buttons can be OR-ed with the QMessageBox::Escape flag
-    to make it the cancel or close button (clicked when \key Esc is
+    to make it the cancel or close button (clicked when \uicontrol Esc is
     pressed).
 
-    \snippet doc/src/snippets/dialogs/dialogs.cpp 2
+    \snippet dialogs/dialogs.cpp 2
 
     The message box is an \l{Qt::ApplicationModal} {application modal}
     dialog box.
@@ -2010,7 +2204,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
 
     Opens an information message box with the given \a title and the
     \a text. The dialog may have up to three buttons. Each of the
@@ -2018,16 +2212,16 @@
     of the following values:
 
     \list
-    \o QMessageBox::NoButton
-    \o QMessageBox::Ok
-    \o QMessageBox::Cancel
-    \o QMessageBox::Yes
-    \o QMessageBox::No
-    \o QMessageBox::Abort
-    \o QMessageBox::Retry
-    \o QMessageBox::Ignore
-    \o QMessageBox::YesAll
-    \o QMessageBox::NoAll
+    \li QMessageBox::NoButton
+    \li QMessageBox::Ok
+    \li QMessageBox::Cancel
+    \li QMessageBox::Yes
+    \li QMessageBox::No
+    \li QMessageBox::Abort
+    \li QMessageBox::Retry
+    \li QMessageBox::Ignore
+    \li QMessageBox::YesAll
+    \li QMessageBox::NoAll
     \endlist
 
     If you don't want all three buttons, set the last button, or last
@@ -2056,7 +2250,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated since 6.2. Use the overload taking StandardButtons instead.
     \overload
 
     Displays an information message box with the given \a title and
@@ -2071,8 +2265,8 @@
     default button; pressing Return or Enter is the same as clicking
     the default button. It defaults to 0 (the first button). \a
     escapeButtonNumber is the index of the escape button; pressing
-    \key Esc is the same as clicking this button. It defaults to -1;
-    supply 0, 1 or 2 to make pressing \key Esc equivalent to clicking
+    \uicontrol Esc is the same as clicking this button. It defaults to -1;
+    supply 0, 1 or 2 to make pressing \uicontrol Esc equivalent to clicking
     the relevant button.
 
     The message box is an \l{Qt::ApplicationModal} {application modal}
@@ -2096,7 +2290,8 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons
+    instead.
 
     Opens a question message box with the given \a title and \a text.
     The dialog may have up to three buttons. Each of the buttons, \a
@@ -2104,16 +2299,16 @@
     following values:
 
     \list
-    \o QMessageBox::NoButton
-    \o QMessageBox::Ok
-    \o QMessageBox::Cancel
-    \o QMessageBox::Yes
-    \o QMessageBox::No
-    \o QMessageBox::Abort
-    \o QMessageBox::Retry
-    \o QMessageBox::Ignore
-    \o QMessageBox::YesAll
-    \o QMessageBox::NoAll
+    \li QMessageBox::NoButton
+    \li QMessageBox::Ok
+    \li QMessageBox::Cancel
+    \li QMessageBox::Yes
+    \li QMessageBox::No
+    \li QMessageBox::Abort
+    \li QMessageBox::Retry
+    \li QMessageBox::Ignore
+    \li QMessageBox::YesAll
+    \li QMessageBox::NoAll
     \endlist
 
     If you don't want all three buttons, set the last button, or last
@@ -2142,7 +2337,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
     \overload
 
     Displays a question message box with the given \a title and \a
@@ -2182,7 +2377,7 @@
 
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
 
     Opens a warning message box with the given \a title and \a text.
     The dialog may have up to three buttons. Each of the button
@@ -2190,16 +2385,16 @@
     one of the following values:
 
     \list
-    \o QMessageBox::NoButton
-    \o QMessageBox::Ok
-    \o QMessageBox::Cancel
-    \o QMessageBox::Yes
-    \o QMessageBox::No
-    \o QMessageBox::Abort
-    \o QMessageBox::Retry
-    \o QMessageBox::Ignore
-    \o QMessageBox::YesAll
-    \o QMessageBox::NoAll
+    \li QMessageBox::NoButton
+    \li QMessageBox::Ok
+    \li QMessageBox::Cancel
+    \li QMessageBox::Yes
+    \li QMessageBox::No
+    \li QMessageBox::Abort
+    \li QMessageBox::Retry
+    \li QMessageBox::Ignore
+    \li QMessageBox::YesAll
+    \li QMessageBox::NoAll
     \endlist
 
     If you don't want all three buttons, set the last button, or last
@@ -2228,7 +2423,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
     \overload
 
     Displays a warning message box with the given \a title and \a
@@ -2267,7 +2462,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
 
     Opens a critical message box with the given \a title and \a text.
     The dialog may have up to three buttons. Each of the button
@@ -2275,16 +2470,16 @@
     one of the following values:
 
     \list
-    \o QMessageBox::NoButton
-    \o QMessageBox::Ok
-    \o QMessageBox::Cancel
-    \o QMessageBox::Yes
-    \o QMessageBox::No
-    \o QMessageBox::Abort
-    \o QMessageBox::Retry
-    \o QMessageBox::Ignore
-    \o QMessageBox::YesAll
-    \o QMessageBox::NoAll
+    \li QMessageBox::NoButton
+    \li QMessageBox::Ok
+    \li QMessageBox::Cancel
+    \li QMessageBox::Yes
+    \li QMessageBox::No
+    \li QMessageBox::Abort
+    \li QMessageBox::Retry
+    \li QMessageBox::Ignore
+    \li QMessageBox::YesAll
+    \li QMessageBox::NoAll
     \endlist
 
     If you don't want all three buttons, set the last button, or last
@@ -2314,7 +2509,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated [6.2]. Use the overload taking StandardButtons instead.
     \overload
 
     Displays a critical error message box with the given \a title and
@@ -2354,7 +2549,7 @@
 
 
 /*!
-    \obsolete
+    \deprecated
 
     Returns the text of the message box button \a button, or
     an empty string if the message box does not contain the button.
@@ -2375,7 +2570,7 @@
 }
 
 /*!
-    \obsolete
+    \deprecated
 
     Sets the text of the message box button \a button to \a text.
     Setting the text of a button that is not in the message box is
@@ -2393,8 +2588,10 @@
         addButton(QMessageBox::Ok)->setText(text);
     }
 }
-
-#ifndef QT_NO_TEXTEDIT
+#endif // QT_DEPRECATED_SINCE(6,2)
+
+
+#if QT_CONFIG(textedit)
 /*!
   \property QMessageBox::detailedText
   \brief the text to be displayed in the details area.
@@ -2416,26 +2613,33 @@
 {
     Q_D(QMessageBox);
     if (text.isEmpty()) {
-        delete d->detailsText;
-        d->detailsText = 0;
+        if (d->detailsText) {
+            d->detailsText->hide();
+            d->detailsText->deleteLater();
+        }
+        d->detailsText = nullptr;
         removeButton(d->detailsButton);
-        delete d->detailsButton;
-        d->detailsButton = 0;
-        return;
+        if (d->detailsButton) {
+            d->detailsButton->hide();
+            d->detailsButton->deleteLater();
+        }
+        d->detailsButton = nullptr;
+    } else {
+        if (!d->detailsText) {
+            d->detailsText = new QMessageBoxDetailsText(this);
+            d->detailsText->hide();
+        }
+        if (!d->detailsButton) {
+            const bool autoAddOkButton = d->autoAddOkButton; // QTBUG-39334, addButton() clears the flag.
+            d->detailsButton = new DetailButton(this);
+            addButton(d->detailsButton, QMessageBox::ActionRole);
+            d->autoAddOkButton = autoAddOkButton;
+        }
+        d->detailsText->setText(text);
     }
-
-    if (!d->detailsText) {
-        d->detailsText = new QMessageBoxDetailsText(this);
-        QGridLayout* grid = qobject_cast<QGridLayout*>(layout());
-        if (grid)
-            grid->addWidget(d->detailsText, grid->rowCount(), 0, 1, grid->columnCount());
-        d->detailsText->hide();
-    }
-    if (!d->detailsButton)
-        d->detailsButton = new DetailButton(this);
-    d->detailsText->setText(text);
+    d->setupLayout();
 }
-#endif // QT_NO_TEXTEDIT
+#endif // QT_CONFIG(textedit)
 
 /*!
   \property QMessageBox::informativeText
@@ -2445,10 +2649,9 @@
 
   \since 4.2
 
-  Infromative text can be used to expand upon the text() to give more
-  information to the user. On the Mac, this text appears in small
-  system font below the text().  On other platforms, it is simply
-  appended to the existing text.
+  Informative text can be used to expand upon the text() to give more
+  information to the user, for example describing the consequences of
+  the situation, or suggestion alternative solutions.
 
   By default, this property contains an empty string.
 
@@ -2464,58 +2667,29 @@
 {
     Q_D(QMessageBox);
     if (text.isEmpty()) {
-        layout()->removeWidget(d->informativeLabel);
-        delete d->informativeLabel;
-        d->informativeLabel = 0;
-#ifndef Q_WS_MAC
-        d->label->setContentsMargins(2, 0, 0, 0);
-#endif
-        d->updateSize();
-        return;
-    }
-
-    if (!d->informativeLabel) {
-        QLabel *label = new QLabel(this);
-        label->setObjectName(QLatin1String("qt_msgbox_informativelabel"));
-        label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, this)));
-        label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
-        label->setOpenExternalLinks(true);
-        label->setWordWrap(true);
-#ifndef Q_WS_MAC
-        d->label->setContentsMargins(2, 0, 0, 0);
-        label->setContentsMargins(2, 0, 0, 6);
-        label->setIndent(9);
-#else
-        label->setContentsMargins(16, 0, 0, 0);
-        // apply a smaller font the information label on the mac
-        label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
+        if (d->informativeLabel) {
+            d->informativeLabel->hide();
+            d->informativeLabel->deleteLater();
+        }
+        d->informativeLabel = nullptr;
+    } else {
+        if (!d->informativeLabel) {
+            QLabel *label = new QLabel;
+            label->setObjectName("qt_msgbox_informativelabel"_L1);
+            label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, nullptr, this)));
+            label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+            label->setOpenExternalLinks(true);
+            label->setWordWrap(true);
+#ifdef Q_OS_MAC
+            // apply a smaller font the information label on the mac
+            label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
 #endif
-        label->setWordWrap(true);
-        QGridLayout *grid = static_cast<QGridLayout *>(layout());
-#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
-        label->hide();
-        QTextBrowser *textBrowser = new QTextBrowser(this);
-        textBrowser->setOpenExternalLinks(true);
-#if defined(Q_OS_SYMBIAN)
-        const int preferredTextColumn = (QApplication::layoutDirection() == Qt::LeftToRight) ? 0 : 1;
-#else
-        const int preferredTextColumn = 1;
-#endif
-        grid->addWidget(textBrowser, 1, preferredTextColumn, 1, 1);
-        d->textBrowser = textBrowser;
-#else
-        grid->addWidget(label, 1, 1, 1, 1);
-#endif
-        d->informativeLabel = label;
+            label->setWordWrap(true);
+            d->informativeLabel = label;
+        }
+        d->informativeLabel->setText(text);
     }
-    d->informativeLabel->setText(text);
-
-#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
-    //We need to put the informative label inside textBrowser to enable scrolling of long texts.
-    d->textBrowser->setText(d->informativeLabel->text());
-#endif
-
-    d->updateSize();
+    d->setupLayout();
 }
 
 /*!
@@ -2523,14 +2697,14 @@
 
     This function shadows QWidget::setWindowTitle().
 
-    Sets the title of the message box to \a title. On Mac OS X,
-    the window title is ignored (as required by the Mac OS X
+    Sets the title of the message box to \a title. On \macos,
+    the window title is ignored (as required by the \macos
     Guidelines).
 */
 void QMessageBox::setWindowTitle(const QString &title)
 {
     // Message boxes on the mac do not have a title
-#ifndef Q_WS_MAC
+#ifndef Q_OS_MAC
     QDialog::setWindowTitle(title);
 #else
     Q_UNUSED(title);
@@ -2545,7 +2719,7 @@
 
     Sets the modality of the message box to \a windowModality.
 
-    On Mac OS X, if the modality is set to Qt::WindowModal and the message box
+    On \macos, if the modality is set to Qt::WindowModal and the message box
     has a parent, then the message box will be a Qt::Sheet, otherwise the
     message box will be a standard dialog.
 */
@@ -2560,132 +2734,184 @@
     setDefaultButton(d_func()->defaultButton);
 }
 
-#ifdef QT3_SUPPORT
-/*!
-    \compat
-
-    Constructs a message box with the given \a parent, \a name, and
-    window flags, \a f.
-    The window title is specified by \a title, and the message box
-    displays message text and an icon specified by \a text and \a icon.
-
-    The buttons that the user can access to respond to the message are
-    defined by \a button0, \a button1, and \a button2.
-*/
-QMessageBox::QMessageBox(const QString& title,
-                         const QString &text, Icon icon,
-                         int button0, int button1, int button2,
-                         QWidget *parent, const char *name,
-                         bool modal, Qt::WindowFlags f)
-    : QDialog(*new QMessageBoxPrivate, parent,
-              f | Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu | Qt::WindowCloseButtonHint)
-{
-    Q_D(QMessageBox);
-    setObjectName(QString::fromAscii(name));
-    d->init(title, text);
-    d->addOldButtons(button0, button1, button2);
-    setModal(modal);
-    setIcon(icon);
-}
-
-/*!
-    \compat
-    Constructs a message box with the given \a parent and \a name.
-*/
-QMessageBox::QMessageBox(QWidget *parent, const char *name)
-    : QDialog(*new QMessageBoxPrivate, parent,
-              Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu | Qt::WindowCloseButtonHint)
-{
-    Q_D(QMessageBox);
-    setObjectName(QString::fromAscii(name));
-    d->init();
-}
-
-/*!
-  Returns the pixmap used for a standard icon. This
-  allows the pixmaps to be used in more complex message boxes.
-  \a icon specifies the required icon, e.g. QMessageBox::Information,
-  QMessageBox::Warning or QMessageBox::Critical.
-
-  \a style is unused.
-*/
-
-QPixmap QMessageBox::standardIcon(Icon icon, Qt::GUIStyle style)
-{
-    Q_UNUSED(style);
-    return QMessageBox::standardIcon(icon);
-}
-
-/*!
-    \fn int QMessageBox::message(const QString &title, const QString &text,
-                                 const QString &buttonText, QWidget *parent = 0,
-                                 const char *name = 0)
-
-    Opens a modal message box with the given \a title and showing the
-    given \a text. The message box has a single button which has the
-    given \a buttonText (or tr("OK")). The message box is centred over
-    its \a parent and is called \a name.
-
-    Use information(), warning(), question(), or critical() instead.
-
-    \oldcode
-        QMessageBox::message(tr("My App"), tr("All occurrences replaced."),
-                             tr("Close"), this);
-    \newcode
-        QMessageBox::information(this, tr("My App"),
-                                 tr("All occurrences replaced."),
-                                 QMessageBox::Close);
-    \endcode
-*/
-
-/*!
-    \fn bool QMessageBox::query(const QString &caption,
-                                const QString& text,
-                                const QString& yesButtonText,
-                                const QString& noButtonText,
-                                QWidget *parent, const char *name)
-
-    \obsolete
-
-    Queries the user using a modal message box with up to two buttons.
-    The message box has the given \a caption (although some window
-    managers don't show it), and shows the given \a text. The left
-    button has the \a yesButtonText (or tr("OK")), and the right button
-    has the \a noButtonText (or isn't shown). The message box is centred
-    over its \a parent and is called \a name.
-
-    Use information(), question(), warning(), or critical() instead.
-*/
-
-#endif
 
 QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb)
 {
     QStyle *style = mb ? mb->style() : QApplication::style();
-    int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, mb);
+    int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, mb);
     QIcon tmpIcon;
     switch (icon) {
     case QMessageBox::Information:
-        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, 0, mb);
+        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, mb);
         break;
     case QMessageBox::Warning:
-        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, 0, mb);
+        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, mb);
         break;
     case QMessageBox::Critical:
-        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, 0, mb);
+        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, nullptr, mb);
         break;
     case QMessageBox::Question:
-        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mb);
+        tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mb);
     default:
         break;
     }
-    if (!tmpIcon.isNull())
-        return tmpIcon.pixmap(iconSize, iconSize);
+    if (!tmpIcon.isNull()) {
+        qreal dpr = mb ? mb->devicePixelRatio() : qApp->devicePixelRatio();
+        return tmpIcon.pixmap(QSize(iconSize, iconSize), dpr);
+    }
     return QPixmap();
 }
 
+void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
+{
+    Q_Q(QMessageBox);
+    QObject::connect(h, SIGNAL(clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)),
+                     q, SLOT(_q_helperClicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)));
+
+    auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(h);
+    QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged, q,
+        [this](Qt::CheckState state) {
+            if (checkbox)
+                checkbox->setCheckState(state);
+        }
+    );
+
+    static_cast<QPlatformMessageDialogHelper *>(h)->setOptions(options);
+}
+
+static QMessageDialogOptions::StandardIcon helperIcon(QMessageBox::Icon i)
+{
+    switch (i) {
+    case QMessageBox::NoIcon:
+        return QMessageDialogOptions::NoIcon;
+    case QMessageBox::Information:
+        return QMessageDialogOptions::Information;
+    case QMessageBox::Warning:
+        return QMessageDialogOptions::Warning;
+    case QMessageBox::Critical:
+        return QMessageDialogOptions::Critical;
+    case QMessageBox::Question:
+        return QMessageDialogOptions::Question;
+    }
+    return QMessageDialogOptions::NoIcon;
+}
+
+static QPlatformDialogHelper::StandardButtons helperStandardButtons(QMessageBox * q)
+{
+    QPlatformDialogHelper::StandardButtons buttons(int(q->standardButtons()));
+    return buttons;
+}
+
+bool QMessageBoxPrivate::canBeNativeDialog() const
+{
+    // Don't use Q_Q here! This function is called from ~QDialog,
+    // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
+    const QDialog * const q = static_cast<const QMessageBox*>(q_ptr);
+    if (nativeDialogInUse)
+        return true;
+    if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+        || q->testAttribute(Qt::WA_DontShowOnScreen)
+        || (options->options() & QMessageDialogOptions::Option::DontUseNativeDialog)) {
+        return false;
+    }
+
+    if (strcmp(QMessageBox::staticMetaObject.className(), q->metaObject()->className()) != 0)
+        return false;
+
+    for (auto *customButton : buttonBox->buttons()) {
+        if (QPushButton *pushButton = qobject_cast<QPushButton *>(customButton)) {
+            // We can't support buttons with menus in native dialogs (yet)
+            if (pushButton->menu())
+                return false;
+        }
+    }
+
+    return QDialogPrivate::canBeNativeDialog();
+}
+
+void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
+{
+    Q_Q(QMessageBox);
+    options->setWindowTitle(q->windowTitle());
+    options->setText(q->text());
+    options->setInformativeText(q->informativeText());
+#if QT_CONFIG(textedit)
+    options->setDetailedText(q->detailedText());
+#endif
+    options->setStandardIcon(helperIcon(q->icon()));
+    options->setIconPixmap(q->iconPixmap());
+
+    // Clear up front, since we might have prepared earlier
+    options->clearCustomButtons();
+
+    // Add standard buttons and resolve default/escape button
+    auto standardButtons = helperStandardButtons(q);
+    for (int button = QDialogButtonBox::StandardButton::FirstButton;
+             button <= QDialogButtonBox::StandardButton::LastButton; button <<= 1) {
+        auto *standardButton = buttonBox->button(QDialogButtonBox::StandardButton(button));
+        if (!standardButton)
+            continue;
+
+        if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+            if (standardButton->text() != platformTheme->standardButtonText(button)) {
+                // The standard button has been customized, so add it as
+                // a custom button instead.
+                const auto buttonRole = buttonBox->buttonRole(standardButton);
+                options->addButton(standardButton->text(),
+                    static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
+                    standardButton, button);
+                standardButtons &= ~QPlatformDialogHelper::StandardButton(button);
+            }
+        }
+
+        if (standardButton == defaultButton)
+            options->setDefaultButton(button);
+        else if (standardButton == detectedEscapeButton)
+            options->setEscapeButton(button);
+    }
+    options->setStandardButtons(standardButtons);
+
+    // Add custom buttons and resolve default/escape button
+    for (auto *customButton : customButtonList) {
+        // Unless it's the details button, since we don't do any
+        // plumbing for the button's action in that case.
+        if (customButton == detailsButton)
+            continue;
+
+        const auto buttonRole = buttonBox->buttonRole(customButton);
+        const int buttonId = options->addButton(customButton->text(),
+            static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
+            customButton);
+
+        if (customButton == defaultButton)
+            options->setDefaultButton(buttonId);
+        else if (customButton == detectedEscapeButton)
+            options->setEscapeButton(buttonId);
+    }
+
+    if (checkbox)
+        options->setCheckBox(checkbox->text(), checkbox->checkState());
+}
+
+void qRequireVersion(int argc, char *argv[], QAnyStringView req)
+{
+    const auto required = QVersionNumber::fromString(req).normalized();
+    const auto current = QVersionNumber::fromString(qVersion()).normalized();
+    if (current >= required)
+        return;
+    std::optional<QApplication> application;
+    if (!qApp)
+        application.emplace(argc, argv);
+    const QString message = QApplication::tr("Application \"%1\" requires Qt %2, found Qt %3.")
+                                    .arg(qAppName(), required.toString(), current.toString());
+    QMessageBox::critical(nullptr, QApplication::tr("Incompatible Qt Library Error"),
+                          message, QMessageBox::Abort);
+    qFatal("%ls", qUtf16Printable(message));
+}
+
+#if QT_DEPRECATED_SINCE(6,2)
 /*!
-    \obsolete
+    \deprecated
 
     Returns the pixmap used for a standard icon. This allows the
     pixmaps to be used in more complex message boxes. \a icon
@@ -2699,12 +2925,13 @@
 
 QPixmap QMessageBox::standardIcon(Icon icon)
 {
-    return QMessageBoxPrivate::standardIcon(icon, 0);
+    return QMessageBoxPrivate::standardIcon(icon, nullptr);
 }
+#endif
 
 /*!
     \typedef QMessageBox::Button
-    \obsolete
+    \deprecated
 
     Use QMessageBox::StandardButton instead.
 */
@@ -2733,12 +2960,13 @@
   Shows the message box as a \l{QDialog#Modal Dialogs}{modal dialog},
   blocking until the user closes it.
 
-  When using a QMessageBox with standard buttons, this functions returns a
+  When using a QMessageBox with standard buttons, this function returns a
   \l StandardButton value indicating the standard button that was clicked.
   When using QMessageBox with custom buttons, this function returns an
   opaque value; use clickedButton() to determine which button was clicked.
 
-  \note The result() function returns also \l StandardButton value instead of \l QDialog::DialogCode
+  \note The result() function returns also \l StandardButton value instead
+  of \l QDialog::DialogCode.
 
   Users cannot interact with any other window in the same
   application until they close the dialog, either by clicking a
@@ -2747,8 +2975,26 @@
   \sa show(), result()
 */
 
+/*!
+    \macro QT_REQUIRE_VERSION(int argc, char **argv, const char *version)
+    \relates QMessageBox
+
+    This macro can be used to ensure that the application is run
+    with a recent enough version of Qt. This is especially useful
+    if your application depends on a specific bug fix introduced in a
+    bug-fix release (for example, 6.1.2).
+
+    The \a argc and \a argv parameters are the \c main() function's
+    \c argc and \c argv parameters. The \a version parameter is a
+    string literal that specifies which version of Qt the application
+    requires (for example, "6.1.2").
+
+    Example:
+
+    \snippet code/src_gui_dialogs_qmessagebox.cpp 4
+*/
+
 QT_END_NAMESPACE
 
 #include "moc_qmessagebox.cpp"
-
-#endif // QT_NO_MESSAGEBOX
+#include "qmessagebox.moc"
--- a/libgui/languages/build_ts/octave-qt/qpagesetupdialog.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qpagesetupdialog.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,47 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-#include <private/qabstractpagesetupdialog_p.h>
+#include "qpagesetupdialog.h"
+#include <private/qpagesetupdialog_p.h>
 
-#ifndef QT_NO_PRINTDIALOG
+#include <QtPrintSupport/qprinter.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -53,18 +16,16 @@
 
     \ingroup standard-dialogs
     \ingroup printing
+    \inmodule QtPrintSupport
 
-    On Windows and Mac OS X the page setup dialog is implemented using
+    On Windows and \macos the page setup dialog is implemented using
     the native page setup dialogs.
 
-    Note that on Windows and Mac OS X custom paper sizes won't be
+    Note that on Windows and \macos custom paper sizes won't be
     reflected in the native page setup dialogs. Additionally, custom
-    page margins set on a QPrinter won't show in the native Mac OS X
+    page margins set on a QPrinter won't show in the native \macos
     page setup dialog.
 
-    In Symbian, there is no support for printing. Hence, this dialog should not
-    be used in Symbian.
-
     \sa QPrinter, QPrintDialog
 */
 
@@ -77,6 +38,12 @@
 */
 
 /*!
+    \fn QPageSetupDialog::~QPageSetupDialog()
+
+    Destroys the page setup dialog.
+*/
+
+/*!
     \since 4.5
 
     \fn QPageSetupDialog::QPageSetupDialog(QWidget *parent)
@@ -94,121 +61,25 @@
     constructor.
 */
 
-// hack
-class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+QPageSetupDialogPrivate::QPageSetupDialogPrivate(QPrinter *prntr) : printer(nullptr), ownsPrinter(false)
 {
-};
-
-/*!
-    \enum QPageSetupDialog::PageSetupDialogOption
-    \since 4.4
-
-    Used to specify options to the page setup dialog
-
-    This value is obsolete and does nothing since Qt 4.5:
-
-    \value DontUseSheet In previous versions of QDialog::exec() the
-    page setup dialog would create a sheet by default if the dialog
-    was given a parent.  This is no longer supported from Qt 4.5.  If
-    you want to use sheets, use QPageSetupDialog::open() instead.
-
-    \omitvalue None
-    \omitvalue OwnsPrinter
-*/
-
-/*!
-    Sets the given \a option to be enabled if \a on is true;
-    otherwise, clears the given \a option.
-
-    \sa options, testOption()
-*/
-void QPageSetupDialog::setOption(PageSetupDialogOption option, bool on)
-{
-    Q_D(QPageSetupDialog);
-    if (!(d->opts & option) != !on)
-        setOptions(d->opts ^ option);
-}
-
-/*!
-    Returns true if the given \a option is enabled; otherwise, returns
-    false.
-
-    \sa options, setOption()
-*/
-bool QPageSetupDialog::testOption(PageSetupDialogOption option) const
-{
-    Q_D(const QPageSetupDialog);
-    return (d->opts & option) != 0;
+    setPrinter(prntr);
 }
 
-/*!
-    \property QPageSetupDialog::options
-    \brief the various options that affect the look and feel of the dialog
-    \since 4.5
-
-    By default, all options are disabled.
-
-    Options should be set before showing the dialog. Setting them while the
-    dialog is visible is not guaranteed to have an immediate effect on the
-    dialog (depending on the option and on the platform).
-
-    \sa setOption(), testOption()
-*/
-void QPageSetupDialog::setOptions(PageSetupDialogOptions options)
+void QPageSetupDialogPrivate::setPrinter(QPrinter *newPrinter)
 {
-    Q_D(QPageSetupDialog);
-
-    PageSetupDialogOptions changed = (options ^ d->opts);
-    if (!changed)
-        return;
-
-    d->opts = options;
-}
-
-QPageSetupDialog::PageSetupDialogOptions QPageSetupDialog::options() const
-{
-    Q_D(const QPageSetupDialog);
-    return d->opts;
-}
-
-/*!
-    \obsolete
+    if (printer && ownsPrinter)
+        delete printer;
 
-    Use setOption(\a option, true) instead.
-*/
-void QPageSetupDialog::addEnabledOption(PageSetupDialogOption option)
-{
-    setOption(option, true);
-}
-
-/*!
-    \obsolete
-
-    Use setOptions(\a options) instead.
-*/
-void QPageSetupDialog::setEnabledOptions(PageSetupDialogOptions options)
-{
-    setOptions(options);
-}
-
-/*!
-    \obsolete
-
-    Use options() instead.
-*/
-QPageSetupDialog::PageSetupDialogOptions QPageSetupDialog::enabledOptions() const
-{
-    return options();
-}
-
-/*!
-    \obsolete
-
-    Use testOption(\a option) instead.
-*/
-bool QPageSetupDialog::isOptionEnabled(PageSetupDialogOption option) const
-{
-    return testOption(option);
+    if (newPrinter) {
+        printer = newPrinter;
+        ownsPrinter = false;
+    } else {
+        printer = new QPrinter;
+        ownsPrinter = true;
+    }
+    if (printer->outputFormat() != QPrinter::NativeFormat)
+        qWarning("QPageSetupDialog: Cannot be used on non-native printers");
 }
 
 /*!
@@ -229,12 +100,46 @@
     QDialog::open();
 }
 
-#if defined(Q_WS_MAC) || defined(Q_OS_WIN)
+#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
 /*! \fn void QPageSetupDialog::setVisible(bool visible)
     \reimp
 */
 #endif
 
-QT_END_NAMESPACE
+QPageSetupDialog::~QPageSetupDialog()
+{
+    Q_D(QPageSetupDialog);
+    if (d->ownsPrinter)
+        delete d->printer;
+}
+
+QPrinter *QPageSetupDialog::printer()
+{
+    Q_D(QPageSetupDialog);
+    return d->printer;
+}
+
+/*!
+    \fn int QPageSetupDialog::exec()
 
-#endif
+    This virtual function is called to pop up the dialog. It must be
+    reimplemented in subclasses.
+*/
+
+/*!
+    \reimp
+*/
+void QPageSetupDialog::done(int result)
+{
+    Q_D(QPageSetupDialog);
+    QDialog::done(result);
+    if (d->receiverToDisconnectOnClose) {
+        disconnect(this, SIGNAL(accepted()),
+                   d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+        d->receiverToDisconnectOnClose = nullptr;
+    }
+    d->memberToDisconnectOnClose.clear();
+
+}
+
+QT_END_NAMESPACE
--- a/libgui/languages/build_ts/octave-qt/qpagesetupdialog_unix.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qpagesetupdialog_unix.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,113 +1,36 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qpagesetupdialog.h"
 
-#ifndef QT_NO_PRINTDIALOG
 #include "qpagesetupdialog_unix_p.h"
 
+#include <private/qpagesetupdialog_p.h>
+#include <private/qprintdevice_p.h>
+#if QT_CONFIG(cups)
+#include <private/qcups_p.h>
+#endif
+
 #include "qpainter.h"
 #include "qprintdialog.h"
+#include "qstringconverter.h"
 #include "qdialogbuttonbox.h"
 #include <ui_qpagesetupwidget.h>
 
-#include <QtGui/qprinter.h>
-#include <private/qabstractpagesetupdialog_p.h>
-#include <private/qprinter_p.h>
+#include <QtPrintSupport/qprinter.h>
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-#  include <private/qcups_p.h>
-#  include <cups/cups.h>
-#  include <private/qpdf_p.h>
-#endif
-
+#include <qpa/qplatformprintplugin.h>
+#include <qpa/qplatformprintersupport.h>
 
 QT_BEGIN_NAMESPACE
 
-QSizeF qt_printerPaperSize(QPrinter::Orientation, QPrinter::PaperSize, QPrinter::Unit, int);
+using namespace Qt::StringLiterals;
+
+extern QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits);
 
 // Disabled until we have support for papersources on unix
 // #define PSD_ENABLE_PAPERSOURCE
 
-static void populatePaperSizes(QComboBox* cb)
-{
-    cb->addItem(QPrintDialog::tr("A0"), QPrinter::A0);
-    cb->addItem(QPrintDialog::tr("A1"), QPrinter::A1);
-    cb->addItem(QPrintDialog::tr("A2"), QPrinter::A2);
-    cb->addItem(QPrintDialog::tr("A3"), QPrinter::A3);
-    cb->addItem(QPrintDialog::tr("A4"), QPrinter::A4);
-    cb->addItem(QPrintDialog::tr("A5"), QPrinter::A5);
-    cb->addItem(QPrintDialog::tr("A6"), QPrinter::A6);
-    cb->addItem(QPrintDialog::tr("A7"), QPrinter::A7);
-    cb->addItem(QPrintDialog::tr("A8"), QPrinter::A8);
-    cb->addItem(QPrintDialog::tr("A9"), QPrinter::A9);
-    cb->addItem(QPrintDialog::tr("B0"), QPrinter::B0);
-    cb->addItem(QPrintDialog::tr("B1"), QPrinter::B1);
-    cb->addItem(QPrintDialog::tr("B2"), QPrinter::B2);
-    cb->addItem(QPrintDialog::tr("B3"), QPrinter::B3);
-    cb->addItem(QPrintDialog::tr("B4"), QPrinter::B4);
-    cb->addItem(QPrintDialog::tr("B5"), QPrinter::B5);
-    cb->addItem(QPrintDialog::tr("B6"), QPrinter::B6);
-    cb->addItem(QPrintDialog::tr("B7"), QPrinter::B7);
-    cb->addItem(QPrintDialog::tr("B8"), QPrinter::B8);
-    cb->addItem(QPrintDialog::tr("B9"), QPrinter::B9);
-    cb->addItem(QPrintDialog::tr("B10"), QPrinter::B10);
-    cb->addItem(QPrintDialog::tr("C5E"), QPrinter::C5E);
-    cb->addItem(QPrintDialog::tr("DLE"), QPrinter::DLE);
-    cb->addItem(QPrintDialog::tr("Executive"), QPrinter::Executive);
-    cb->addItem(QPrintDialog::tr("Folio"), QPrinter::Folio);
-    cb->addItem(QPrintDialog::tr("Ledger"), QPrinter::Ledger);
-    cb->addItem(QPrintDialog::tr("Legal"), QPrinter::Legal);
-    cb->addItem(QPrintDialog::tr("Letter"), QPrinter::Letter);
-    cb->addItem(QPrintDialog::tr("Tabloid"), QPrinter::Tabloid);
-    cb->addItem(QPrintDialog::tr("US Common #10 Envelope"), QPrinter::Comm10E);
-    cb->addItem(QPrintDialog::tr("Custom"), QPrinter::Custom);
-}
-
-
-static QSizeF sizeForOrientation(QPrinter::Orientation orientation, const QSizeF &size)
-{
-    return (orientation == QPrinter::Portrait) ? size : QSizeF(size.height(), size.width());
-}
-
 #ifdef PSD_ENABLE_PAPERSOURCE
 static const char *paperSourceNames[] = {
     "Only One",
@@ -136,6 +59,10 @@
 #endif
 
 
+// QPagePreview
+// - Private widget to display preview of page layout
+// - Embedded in QPageSetupWidget
+
 class QPagePreview : public QWidget
 {
 public:
@@ -145,40 +72,35 @@
         setMinimumSize(50, 50);
     }
 
-    void setPaperSize(const QSizeF& size)
+    void setPageLayout(const QPageLayout &layout)
     {
-        m_size = size;
+        m_pageLayout = layout;
         update();
     }
 
-    void setMargins(qreal left, qreal top, qreal right, qreal bottom)
+    void setPagePreviewLayout(int columns, int rows)
     {
-        m_left = left;
-        m_top = top;
-        m_right = right;
-        m_bottom = bottom;
-        update();
+      m_pagePreviewColumns = columns;
+      m_pagePreviewRows = rows;
+      update();
     }
 
 protected:
-    void paintEvent(QPaintEvent *)
+    void paintEvent(QPaintEvent *) override
     {
-        QRect pageRect;
-        QSizeF adjustedSize(m_size);
-        adjustedSize.scale(width()-10, height()-10, Qt::KeepAspectRatio);
-        pageRect = QRect(QPoint(0,0), adjustedSize.toSize());
+        QSize pageSize = m_pageLayout.fullRectPoints().size();
+        QSizeF scaledSize = pageSize.scaled(width() - 10, height() - 10, Qt::KeepAspectRatio);
+        QRect pageRect = QRect(QPoint(0,0), scaledSize.toSize());
         pageRect.moveCenter(rect().center());
-
-        qreal width_factor = pageRect.width() / m_size.width();
-        qreal height_factor = pageRect.height() / m_size.height();
-        int leftSize = qRound(m_left*width_factor);
-        int topSize = qRound(m_top*height_factor);
-        int rightSize = qRound(m_right*width_factor);
-        int bottomSize = qRound(m_bottom * height_factor);
-        QRect marginRect(pageRect.x()+leftSize,
-                         pageRect.y()+topSize,
-                         pageRect.width() - (leftSize+rightSize+1),
-                         pageRect.height() - (topSize+bottomSize+1));
+        qreal width_factor = scaledSize.width() / pageSize.width();
+        qreal height_factor = scaledSize.height() / pageSize.height();
+        QMarginsF margins = m_pageLayout.margins(QPageLayout::Point);
+        int left = qRound(margins.left() * width_factor);
+        int top = qRound(margins.top() * height_factor);
+        int right = qRound(margins.right() * width_factor);
+        int bottom = qRound(margins.bottom() * height_factor);
+        QRect marginRect(pageRect.x() + left, pageRect.y() + top,
+                         pageRect.width() - (left + right + 1), pageRect.height() - (top + bottom + 1));
 
         QPainter p(this);
         QColor shadow(palette().mid().color());
@@ -201,55 +123,63 @@
             font.setPointSizeF(font.pointSizeF()*0.25);
             p.setFont(font);
             p.setPen(palette().color(QPalette::Dark));
-            QString text(QLatin1String("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."));
+            QString text("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."_L1);
             for (int i=0; i<3; ++i)
                 text += text;
-            p.drawText(marginRect, Qt::TextWordWrap|Qt::AlignVCenter, text);
+
+            const int spacing = pageRect.width() * 0.1;
+            const int textWidth = (marginRect.width() - (spacing * (m_pagePreviewColumns-1))) / m_pagePreviewColumns;
+            const int textHeight = (marginRect.height() - (spacing * (m_pagePreviewRows-1))) / m_pagePreviewRows;
+
+            for (int x = 0 ; x < m_pagePreviewColumns; ++x) {
+                for (int y = 0 ; y < m_pagePreviewRows; ++y) {
+                    QRect textRect(marginRect.left() + x * (textWidth + spacing),
+                                   marginRect.top() + y * (textHeight + spacing),
+                                   textWidth, textHeight);
+                    p.drawText(textRect, Qt::TextWordWrap|Qt::AlignVCenter, text);
+                }
+            }
         }
     }
 
 private:
-    // all these are in points
-    qreal m_left, m_top, m_right, m_bottom;
-    QSizeF m_size;
+    // Page Layout
+    QPageLayout m_pageLayout;
+    // Pages Per Sheet / n-up layout
+    int m_pagePreviewColumns, m_pagePreviewRows;
 };
 
 
-class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+// QUnixPageSetupDialogPrivate
+// - Linux / Cups implementation of QPageSetupDialogPrivate
+// - Embeds QPageSetupWidget
+
+class QUnixPageSetupDialogPrivate : public QPageSetupDialogPrivate
 {
     Q_DECLARE_PUBLIC(QPageSetupDialog)
 
 public:
-    ~QPageSetupDialogPrivate();
+    QUnixPageSetupDialogPrivate(QPrinter *printer);
+    ~QUnixPageSetupDialogPrivate();
     void init();
 
     QPageSetupWidget *widget;
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    QCUPSSupport *cups;
-#endif
 };
 
-QPageSetupDialogPrivate::~QPageSetupDialogPrivate()
+QUnixPageSetupDialogPrivate::QUnixPageSetupDialogPrivate(QPrinter *printer) : QPageSetupDialogPrivate(printer)
 {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    delete cups;
-#endif
 }
 
-void QPageSetupDialogPrivate::init()
+QUnixPageSetupDialogPrivate::~QUnixPageSetupDialogPrivate()
+{
+}
+
+void QUnixPageSetupDialogPrivate::init()
 {
     Q_Q(QPageSetupDialog);
 
     widget = new QPageSetupWidget(q);
-    widget->setPrinter(printer);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    if (printer->outputFormat() == QPrinter::NativeFormat && QCUPSSupport::isAvailable()) {
-        cups = new QCUPSSupport;
-        widget->selectPrinter(cups);
-    } else {
-        cups = 0;
-    }
-#endif
+    widget->setPrinter(printer, nullptr, printer->outputFormat(), printer->printerName());
 
     QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok
                                                      | QDialogButtonBox::Cancel,
@@ -262,359 +192,530 @@
     lay->addWidget(buttons);
 }
 
+// QPageSetupWidget
+// - Private widget implementation for Linux / CUPS
+// - Embeds QPagePreview
+// - TODO Could be made public as a stand-alone widget?
+
 QPageSetupWidget::QPageSetupWidget(QWidget *parent)
     : QWidget(parent),
-    m_printer(0),
-    m_blockSignals(false),
-    m_cups(0)
+      m_pagePreview(nullptr),
+      m_printer(nullptr),
+      m_printDevice(nullptr),
+#if QT_CONFIG(cups)
+      m_pageSizePpdOption(nullptr),
+#endif
+      m_outputFormat(QPrinter::PdfFormat),
+      m_units(QPageLayout::Point),
+      m_savedUnits(QPageLayout::Point),
+      m_savedPagesPerSheet(-1),
+      m_savedPagesPerSheetLayout(-1),
+      m_blockSignals(false),
+      m_realCustomPageSizeIndex(-1)
 {
-    widget.setupUi(this);
+    m_ui.setupUi(this);
 
-    QString suffix = (QLocale::system().measurementSystem() == QLocale::ImperialSystem)
-                     ? QString::fromLatin1(" in")
-                     : QString::fromLatin1(" mm");
-    widget.topMargin->setSuffix(suffix);
-    widget.bottomMargin->setSuffix(suffix);
-    widget.leftMargin->setSuffix(suffix);
-    widget.rightMargin->setSuffix(suffix);
-    widget.paperWidth->setSuffix(suffix);
-    widget.paperHeight->setSuffix(suffix);
+    QVBoxLayout *lay = new QVBoxLayout(m_ui.preview);
+    m_pagePreview = new QPagePreview(m_ui.preview);
+    m_pagePreview->setPagePreviewLayout(1, 1);
 
-    QVBoxLayout *lay = new QVBoxLayout(widget.preview);
-    widget.preview->setLayout(lay);
-    m_pagePreview = new QPagePreview(widget.preview);
     lay->addWidget(m_pagePreview);
 
     setAttribute(Qt::WA_WState_Polished, false);
 
 #ifdef PSD_ENABLE_PAPERSOURCE
     for (int i=0; paperSourceNames[i]; ++i)
-        widget.paperSource->insertItem(paperSourceNames[i]);
+        m_ui.paperSource->insertItem(paperSourceNames[i]);
 #else
-    widget.paperSourceLabel->setVisible(false);
-    widget.paperSource->setVisible(false);
+    m_ui.paperSourceLabel->setVisible(false);
+    m_ui.paperSource->setVisible(false);
 #endif
 
-    widget.reverseLandscape->setVisible(false);
-    widget.reversePortrait->setVisible(false);
+    m_ui.reverseLandscape->setVisible(false);
+    m_ui.reversePortrait->setVisible(false);
+
+    initUnits();
+    initPagesPerSheet();
+
+    connect(m_ui.unitCombo, &QComboBox::activated, this, &QPageSetupWidget::unitChanged);
 
-    populatePaperSizes(widget.paperSize);
+    connect(m_ui.pageSizeCombo, &QComboBox::currentIndexChanged, this, &QPageSetupWidget::pageSizeChanged);
+    connect(m_ui.pageWidth, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::pageSizeChanged);
+    connect(m_ui.pageHeight, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::pageSizeChanged);
+
+    connect(m_ui.leftMargin, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::leftMarginChanged);
+    connect(m_ui.topMargin, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::topMarginChanged);
+    connect(m_ui.rightMargin, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::rightMarginChanged);
+    connect(m_ui.bottomMargin, &QDoubleSpinBox::valueChanged, this, &QPageSetupWidget::bottomMarginChanged);
+
+    connect(m_ui.portrait, &QRadioButton::clicked, this, &QPageSetupWidget::pageOrientationChanged);
+    connect(m_ui.landscape, &QRadioButton::clicked, this, &QPageSetupWidget::pageOrientationChanged);
+
+    connect(m_ui.pagesPerSheetCombo, &QComboBox::currentIndexChanged, this, &QPageSetupWidget::pagesPerSheetChanged);
+}
 
-    QStringList units;
-    units << tr("Centimeters (cm)") << tr("Millimeters (mm)") << tr("Inches (in)") << tr("Points (pt)");
-    widget.unit->addItems(units);
-    connect(widget.unit, SIGNAL(activated(int)), this, SLOT(unitChanged(int)));
-    widget.unit->setCurrentIndex((QLocale::system().measurementSystem() == QLocale::ImperialSystem) ? 2 : 1);
+// Init the Units combo box
+void QPageSetupWidget::initUnits()
+{
+    m_ui.unitCombo->addItem(tr("Millimeters (mm)"), QVariant::fromValue(QPageLayout::Millimeter));
+    m_ui.unitCombo->addItem(tr("Inches (in)"), QVariant::fromValue(QPageLayout::Inch));
+    m_ui.unitCombo->addItem(tr("Points (pt)"), QVariant::fromValue(QPageLayout::Point));
+    m_ui.unitCombo->addItem(tr("Pica (P̸)"), QVariant::fromValue(QPageLayout::Pica));
+    m_ui.unitCombo->addItem(tr("Didot (DD)"), QVariant::fromValue(QPageLayout::Didot));
+    m_ui.unitCombo->addItem(tr("Cicero (CC)"), QVariant::fromValue(QPageLayout::Cicero));
+
+    // Initially default to locale measurement system, mm if metric, in otherwise
+    m_ui.unitCombo->setCurrentIndex(QLocale().measurementSystem() != QLocale::MetricSystem);
+}
+
+// Init the Pages Per Sheet (n-up) combo boxes if using CUPS
+void QPageSetupWidget::initPagesPerSheet()
+{
+#if QT_CONFIG(cups)
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Top to Bottom"),
+                                           QVariant::fromValue(QCUPSSupport::LeftToRightTopToBottom));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Left to Right, Bottom to Top"),
+                                           QVariant::fromValue(QCUPSSupport::LeftToRightBottomToTop));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Bottom to Top"),
+                                           QVariant::fromValue(QCUPSSupport::RightToLeftBottomToTop));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Right to Left, Top to Bottom"),
+                                           QVariant::fromValue(QCUPSSupport::RightToLeftTopToBottom));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Left to Right"),
+                                           QVariant::fromValue(QCUPSSupport::BottomToTopLeftToRight));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Bottom to Top, Right to Left"),
+                                           QVariant::fromValue(QCUPSSupport::BottomToTopRightToLeft));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Left to Right"),
+                                           QVariant::fromValue(QCUPSSupport::TopToBottomLeftToRight));
+    m_ui.pagesPerSheetLayoutCombo->addItem(QPrintDialog::tr("Top to Bottom, Right to Left"),
+                                           QVariant::fromValue(QCUPSSupport::TopToBottomRightToLeft));
 
-    connect(widget.paperSize, SIGNAL(currentIndexChanged(int)), this, SLOT(_q_paperSizeChanged()));
-    connect(widget.paperWidth, SIGNAL(valueChanged(double)), this, SLOT(_q_paperSizeChanged()));
-    connect(widget.paperHeight, SIGNAL(valueChanged(double)), this, SLOT(_q_paperSizeChanged()));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("1 (1x1)"),
+                                     QVariant::fromValue(QCUPSSupport::OnePagePerSheet));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("2 (2x1)"),
+                                     QVariant::fromValue(QCUPSSupport::TwoPagesPerSheet));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("4 (2x2)"),
+                                     QVariant::fromValue(QCUPSSupport::FourPagesPerSheet));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("6 (2x3)"),
+                                     QVariant::fromValue(QCUPSSupport::SixPagesPerSheet));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("9 (3x3)"),
+                                     QVariant::fromValue(QCUPSSupport::NinePagesPerSheet));
+    m_ui.pagesPerSheetCombo->addItem(QPrintDialog::tr("16 (4x4)"),
+                                     QVariant::fromValue(QCUPSSupport::SixteenPagesPerSheet));
+
+    // Set to QCUPSSupport::OnePagePerSheet
+    m_ui.pagesPerSheetCombo->setCurrentIndex(0);
+    // Set to QCUPSSupport::LeftToRightTopToBottom
+    m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(0);
+#else
+    // Disable if CUPS wasn't found
+    m_ui.pagesPerSheetButtonGroup->hide();
+#endif
+}
+
+void QPageSetupWidget::initPageSizes()
+{
+    m_blockSignals = true;
+
+    m_ui.pageSizeCombo->clear();
+
+    m_realCustomPageSizeIndex = -1;
 
-    connect(widget.leftMargin, SIGNAL(valueChanged(double)), this, SLOT(setLeftMargin(double)));
-    connect(widget.topMargin, SIGNAL(valueChanged(double)), this, SLOT(setTopMargin(double)));
-    connect(widget.rightMargin, SIGNAL(valueChanged(double)), this, SLOT(setRightMargin(double)));
-    connect(widget.bottomMargin, SIGNAL(valueChanged(double)), this, SLOT(setBottomMargin(double)));
+    if (m_outputFormat == QPrinter::NativeFormat && !m_printerName.isEmpty()) {
+        QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
+        if (ps) {
+            QPrintDevice printDevice = ps->createPrintDevice(m_printerName);
+            const QPageSize defaultSize = printDevice.defaultPageSize();
+            const auto pageSizes = printDevice.supportedPageSizes();
+            for (const QPageSize &pageSize : pageSizes)
+                m_ui.pageSizeCombo->addItem(pageSize.name(), QVariant::fromValue(pageSize));
+            if (m_ui.pageSizeCombo->count() > 0) {
+                if (printDevice.supportsCustomPageSizes()) {
+                    m_ui.pageSizeCombo->addItem(tr("Custom"));
+                    m_realCustomPageSizeIndex = m_ui.pageSizeCombo->count() - 1;
+                }
+                m_blockSignals = false;
 
-    connect(widget.portrait, SIGNAL(clicked()), this, SLOT(_q_pageOrientationChanged()));
-    connect(widget.landscape, SIGNAL(clicked()), this, SLOT(_q_pageOrientationChanged()));
+                // If the defaultSize is index 0, setCurrentIndex won't emit the currentIndexChanged
+                // signal; workaround the issue by initially setting the currentIndex to -1
+                m_ui.pageSizeCombo->setCurrentIndex(-1);
+                m_ui.pageSizeCombo->setCurrentIndex(m_ui.pageSizeCombo->findData(QVariant::fromValue(defaultSize)));
+                return;
+            }
+        }
+    }
+
+    // If PdfFormat or no available printer page sizes, populate with all page sizes
+    for (int id = 0; id < QPageSize::LastPageSize; ++id) {
+        if (QPageSize::PageSizeId(id) == QPageSize::Custom) {
+            m_ui.pageSizeCombo->addItem(tr("Custom"));
+            m_realCustomPageSizeIndex = m_ui.pageSizeCombo->count() - 1;
+        } else {
+            QPageSize pageSize = QPageSize(QPageSize::PageSizeId(id));
+            m_ui.pageSizeCombo->addItem(pageSize.name(), QVariant::fromValue(pageSize));
+        }
+    }
+
+    m_blockSignals = false;
 }
 
-void QPageSetupWidget::setPrinter(QPrinter *printer)
+// Set the dialog to use the given QPrinter
+// Usually only called on first creation
+void QPageSetupWidget::setPrinter(QPrinter *printer, QPrintDevice *printDevice,
+                                  QPrinter::OutputFormat outputFormat, const QString &printerName)
 {
     m_printer = printer;
+    m_printDevice = printDevice;
+
+#if QT_CONFIG(cups)
+    // find the PageSize cups option
+    m_pageSizePpdOption = m_printDevice ? QCUPSSupport::findPpdOption("PageSize", m_printDevice) : nullptr;
+#endif
+
+    // Initialize the layout to the current QPrinter layout
+    m_pageLayout = m_printer->pageLayout();
+
+    // Assume if margins are Points then is by default, so set to locale default units
+    if (m_pageLayout.units() == QPageLayout::Point) {
+        if (QLocale().measurementSystem() == QLocale::MetricSystem)
+            m_pageLayout.setUnits(QPageLayout::Millimeter);
+        else
+            m_pageLayout.setUnits(QPageLayout::Inch);
+    }
+    m_units = m_pageLayout.units();
+    m_pagePreview->setPageLayout(m_pageLayout);
+
+    m_outputFormat = outputFormat;
+    m_printerName = printerName;
+    initPageSizes();
+    updateWidget();
+    updateSavedValues();
+
+    if (m_ui.pageSizeCombo->currentIndex() == -1) {
+        // This can happen in raw printers that since they don't have a default
+        // page size none will get selected so just default to the first size (A4)
+        m_ui.pageSizeCombo->setCurrentIndex(0);
+    }
+}
+
+// Update the widget with the current settings
+// TODO Break up into more intelligent chunks?
+void QPageSetupWidget::updateWidget()
+{
     m_blockSignals = true;
-    selectPdfPsPrinter(printer);
-    printer->getPageMargins(&m_leftMargin, &m_topMargin, &m_rightMargin, &m_bottomMargin, QPrinter::Point);
-    unitChanged(widget.unit->currentIndex());
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
-    m_paperSize = printer->paperSize(QPrinter::Point);
-    widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
-    widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
+
+    QString suffix;
+    switch (m_units) {
+    case QPageLayout::Millimeter:
+        //: Unit 'Millimeter'
+        suffix = tr("mm");
+        break;
+    case QPageLayout::Point:
+        //: Unit 'Points'
+        suffix = tr("pt");
+        break;
+    case QPageLayout::Inch:
+        //: Unit 'Inch'
+        suffix = tr("in");
+        break;
+    case QPageLayout::Pica:
+        //: Unit 'Pica'
+        suffix = tr("P̸");
+        break;
+    case QPageLayout::Didot:
+        //: Unit 'Didot'
+        suffix = tr("DD");
+        break;
+    case QPageLayout::Cicero:
+        //: Unit 'Cicero'
+        suffix = tr("CC");
+        break;
+    }
+
+    m_ui.unitCombo->setCurrentIndex(m_ui.unitCombo->findData(QVariant::fromValue(m_units)));
+
+    const bool isCustom = m_ui.pageSizeCombo->currentIndex() == m_realCustomPageSizeIndex && m_realCustomPageSizeIndex != -1;
+    if (!isCustom)
+        m_ui.pageSizeCombo->setCurrentIndex(m_ui.pageSizeCombo->findData(QVariant::fromValue(m_pageLayout.pageSize())));
+
+    QMarginsF min;
+    QMarginsF max;
 
-    widget.landscape->setChecked(printer->orientation() == QPrinter::Landscape);
+    if (m_pageLayout.mode() == QPageLayout::FullPageMode) {
+        min = QMarginsF(0.0, 0.0, 0.0, 0.0);
+        max = QMarginsF(9999.9999, 9999.9999, 9999.9999, 9999.9999);
+    } else {
+        min = m_pageLayout.minimumMargins();
+        max = m_pageLayout.maximumMargins();
+    }
+
+    m_ui.leftMargin->setSuffix(suffix);
+    m_ui.leftMargin->setMinimum(min.left());
+    m_ui.leftMargin->setMaximum(max.left());
+    m_ui.leftMargin->setValue(m_pageLayout.margins().left());
+
+    m_ui.rightMargin->setSuffix(suffix);
+    m_ui.rightMargin->setMinimum(min.right());
+    m_ui.rightMargin->setMaximum(max.right());
+    m_ui.rightMargin->setValue(m_pageLayout.margins().right());
+
+    m_ui.topMargin->setSuffix(suffix);
+    m_ui.topMargin->setMinimum(min.top());
+    m_ui.topMargin->setMaximum(max.top());
+    m_ui.topMargin->setValue(m_pageLayout.margins().top());
+
+    m_ui.bottomMargin->setSuffix(suffix);
+    m_ui.bottomMargin->setMinimum(min.bottom());
+    m_ui.bottomMargin->setMaximum(max.bottom());
+    m_ui.bottomMargin->setValue(m_pageLayout.margins().bottom());
+
+    m_ui.pageWidth->setSuffix(suffix);
+    m_ui.pageWidth->setValue(m_pageLayout.fullRect(m_units).width());
+    m_ui.pageWidth->setEnabled(isCustom);
+    m_ui.widthLabel->setEnabled(isCustom);
+
+    m_ui.pageHeight->setSuffix(suffix);
+    m_ui.pageHeight->setValue(m_pageLayout.fullRect(m_units).height());
+    m_ui.pageHeight->setEnabled(isCustom);
+    m_ui.heightLabel->setEnabled(isCustom);
+
+    m_ui.portrait->setChecked(m_pageLayout.orientation() == QPageLayout::Portrait);
+    m_ui.landscape->setChecked(m_pageLayout.orientation() == QPageLayout::Landscape);
+
+    m_ui.pagesPerSheetButtonGroup->setEnabled(m_outputFormat == QPrinter::NativeFormat);
 
 #ifdef PSD_ENABLE_PAPERSOURCE
-    widget.paperSource->setCurrentItem(printer->paperSource());
+    m_ui.paperSource->setCurrentItem(printer->paperSource());
 #endif
-    Q_ASSERT(m_blockSignals);
+
     m_blockSignals = false;
-    _q_paperSizeChanged();
 }
 
-// set gui data on printer
+// Set the dialog chosen options on the QPrinter
+// Normally only called when the QPrintDialog or QPageSetupDialog OK button is pressed
 void QPageSetupWidget::setupPrinter() const
 {
-    QPrinter::Orientation orientation = widget.portrait->isChecked()
-                                        ? QPrinter::Portrait
-                                        : QPrinter::Landscape;
-    m_printer->setOrientation(orientation);
-    // paper format
-    QVariant val = widget.paperSize->itemData(widget.paperSize->currentIndex());
-    int ps = m_printer->pageSize();
-    if (val.type() == QVariant::Int) {
-        ps = val.toInt();
-    }
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    else if (m_cups && QCUPSSupport::isAvailable() && m_cups->currentPPD()) {
-        QByteArray cupsPageSize = val.toByteArray();
-        QPrintEngine *engine = m_printer->printEngine();
-        engine->setProperty(PPK_CupsStringPageSize, QString::fromLatin1(cupsPageSize));
-        engine->setProperty(PPK_CupsOptions, m_cups->options());
-
-        QRect pageRect = m_cups->pageRect(cupsPageSize);
-        engine->setProperty(PPK_CupsPageRect, pageRect);
+    m_printer->setPageLayout(m_pageLayout);
+    m_printer->setPageOrientation(m_pageLayout.orientation());
+#if QT_CONFIG(cups)
+    QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(m_ui.pagesPerSheetCombo->currentData()
+);
+    QCUPSSupport::PagesPerSheetLayout pagesPerSheetLayout = qvariant_cast<QCUPSSupport::PagesPerSheetLayout>(m_ui.pagesPerSheetLayoutCombo->currentData()
+);
+    QCUPSSupport::setPagesPerSheetLayout(m_printer, pagesPerSheet, pagesPerSheetLayout);
+#endif
+#ifdef PSD_ENABLE_PAPERSOURCE
+    m_printer->setPaperSource((QPrinter::PaperSource)m_ui.paperSource->currentIndex());
+#endif
+}
 
-        QRect paperRect = m_cups->paperRect(cupsPageSize);
-        engine->setProperty(PPK_CupsPaperRect, paperRect);
+void QPageSetupWidget::updateSavedValues()
+{
+    m_savedUnits = m_units;
+    m_savedPageLayout = m_pageLayout;
+    m_savedPagesPerSheet = m_ui.pagesPerSheetCombo->currentIndex();
+    m_savedPagesPerSheetLayout = m_ui.pagesPerSheetLayoutCombo->currentIndex();
+}
 
-        for(ps = 0; ps < QPrinter::NPaperSize; ++ps) {
-            QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
-            if (size.width == paperRect.width() && size.height == paperRect.height())
-                break;
-        }
-    }
-#endif
-    if (ps == QPrinter::Custom)
-        m_printer->setPaperSize(sizeForOrientation(orientation, m_paperSize), QPrinter::Point);
-    else
-        m_printer->setPaperSize(static_cast<QPrinter::PaperSize>(ps));
+void QPageSetupWidget::revertToSavedValues()
+{
+    m_units = m_savedUnits;
+    m_pageLayout = m_savedPageLayout;
+    m_pagePreview->setPageLayout(m_pageLayout);
 
-#ifdef PSD_ENABLE_PAPERSOURCE
-    m_printer->setPaperSource((QPrinter::PaperSource)widget.paperSource->currentIndex());
-#endif
-    m_printer->setPageMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin, QPrinter::Point);
+    updateWidget();
 
+    m_ui.pagesPerSheetCombo->setCurrentIndex(m_savedPagesPerSheet);
+    m_ui.pagesPerSheetLayoutCombo->setCurrentIndex(m_savedPagesPerSheetLayout);
 }
 
-void QPageSetupWidget::selectPrinter(QCUPSSupport *cups)
+#if QT_CONFIG(cups)
+bool QPageSetupWidget::hasPpdConflict() const
 {
-    m_cups = cups;
-    widget.paperSize->clear();
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    if (m_cups && QCUPSSupport::isAvailable()) {
-        const ppd_option_t* pageSizes = m_cups->pageSizes();
-        const int numChoices = pageSizes ? pageSizes->num_choices : 0;
+    if (m_pageSizePpdOption) {
+        if (m_pageSizePpdOption->conflicted) {
+            const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
+            const int pixmap_size = m_ui.pageSizeCombo->sizeHint().height() * .75;
+            m_ui.pageSizeWarningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
+        } else {
+            m_ui.pageSizeWarningLabel->setPixmap(QPixmap());
+        }
+        return m_pageSizePpdOption->conflicted;
+    }
+
+    return false;
+}
+#endif
 
-        int cupsDefaultSize = 0;
-        QSize qtPreferredSize = m_printer->paperSize(QPrinter::Point).toSize();
-        bool preferredSizeMatched = false;
-        for (int i = 0; i < numChoices; ++i) {
-            widget.paperSize->addItem(QString::fromLocal8Bit(pageSizes->choices[i].text), QByteArray(pageSizes->choices[i].choice));
-            if (static_cast<int>(pageSizes->choices[i].marked) == 1)
-                cupsDefaultSize = i;
-            if (m_printer->d_func()->hasUserSetPageSize) {
-                QRect cupsPaperSize = m_cups->paperRect(pageSizes->choices[i].choice);
-                QSize diff = cupsPaperSize.size() - qtPreferredSize;
-                if (qAbs(diff.width()) < 5 && qAbs(diff.height()) < 5) {
-                    widget.paperSize->setCurrentIndex(i);
-                    preferredSizeMatched = true;
+// Updates size/preview after the combobox has been changed.
+void QPageSetupWidget::pageSizeChanged()
+{
+    QPageSize pageSize;
+    if (m_ui.pageSizeCombo->currentIndex() != m_realCustomPageSizeIndex) {
+        pageSize = qvariant_cast<QPageSize>(m_ui.pageSizeCombo->currentData());
+
+#if QT_CONFIG(cups)
+        if (m_pageSizePpdOption) {
+            ppd_file_t *ppd = qvariant_cast<ppd_file_t*>(m_printDevice->property(PDPK_PpdFile));
+            QStringDecoder toUtf16(ppd->lang_encoding, QStringDecoder::Flag::Stateless);
+            if (!toUtf16.isValid()) {
+                qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding;
+                toUtf16 = QStringDecoder(QStringDecoder::Utf8);
+            }
+            for (int i = 0; i < m_pageSizePpdOption->num_choices; ++i) {
+                const ppd_choice_t *choice = &m_pageSizePpdOption->choices[i];
+                if (toUtf16(choice->text) == m_ui.pageSizeCombo->currentText()) {
+                    const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword)
+                                                      << QString::fromLatin1(choice->choice);
+                    m_printDevice->setProperty(PDPK_PpdOption, values);
+                    emit ppdOptionChanged();
+                    break;
                 }
             }
         }
-        if (!preferredSizeMatched)
-            widget.paperSize->setCurrentIndex(cupsDefaultSize);
-        if (m_printer->d_func()->hasCustomPageMargins) {
-            m_printer->getPageMargins(&m_leftMargin, &m_topMargin, &m_rightMargin, &m_bottomMargin, QPrinter::Point);
-        } else {
-            QByteArray cupsPaperSizeChoice = widget.paperSize->itemData(widget.paperSize->currentIndex()).toByteArray();
-            QRect paper = m_cups->paperRect(cupsPaperSizeChoice);
-            QRect content = m_cups->pageRect(cupsPaperSizeChoice);
+#endif
 
-            m_leftMargin = content.x() - paper.x();
-            m_topMargin = content.y() - paper.y();
-            m_rightMargin = paper.right() - content.right();
-            m_bottomMargin = paper.bottom() - content.bottom();
+    } else {
+        QSizeF customSize;
+        if (m_pageLayout.orientation() == QPageLayout::Landscape)
+            customSize = QSizeF(m_ui.pageHeight->value(), m_ui.pageWidth->value());
+        else
+            customSize = QSizeF(m_ui.pageWidth->value(), m_ui.pageHeight->value());
+        pageSize = QPageSize(customSize, QPageSize::Unit(m_units));
+
+#if QT_CONFIG(cups)
+        if (m_pageSizePpdOption) {
+            const auto values = QStringList{} << QString::fromLatin1(m_pageSizePpdOption->keyword)
+                                              << QStringLiteral("Custom");
+            m_printDevice->setProperty(PDPK_PpdOption, values);
+            emit ppdOptionChanged();
         }
-    }
 #endif
-    if (widget.paperSize->count() == 0) {
-        populatePaperSizes(widget.paperSize);
-        widget.paperSize->setCurrentIndex(widget.paperSize->findData(
-            QLocale::system().measurementSystem() == QLocale::ImperialSystem ? QPrinter::Letter : QPrinter::A4));
     }
 
-    unitChanged(widget.unit->currentIndex());
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
-}
+    // We always need to update the m_pageSizePpdOption when the page size changes
+    // even if it's from inside updateWidget, so do not move up
+    if (m_blockSignals)
+        return;
 
-void QPageSetupWidget::selectPdfPsPrinter(const QPrinter *p)
-{
-    m_cups = 0;
-    widget.paperSize->clear();
-    populatePaperSizes(widget.paperSize);
-    widget.paperSize->setCurrentIndex(widget.paperSize->findData(p->paperSize()));
+    const QMarginsF printable = m_printDevice ? m_printDevice->printableMargins(pageSize, m_pageLayout.orientation(), m_printer->resolution())
+                                              : QMarginsF();
+    m_pageLayout.setPageSize(pageSize, qt_convertMargins(printable, QPageLayout::Point, m_pageLayout.units()));
+    m_pagePreview->setPageLayout(m_pageLayout);
 
-    m_leftMargin = 90;
-    m_topMargin = 72;
-    m_bottomMargin = 72;
-    m_rightMargin = 90;
-    unitChanged(widget.unit->currentIndex());
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+    updateWidget();
 }
 
-// Updates size/preview after the combobox has been changed.
-void QPageSetupWidget::_q_paperSizeChanged()
+void QPageSetupWidget::pageOrientationChanged()
 {
-    QVariant val = widget.paperSize->itemData(widget.paperSize->currentIndex());
-    int index = m_printer->pageSize();
-    if (val.type() == QVariant::Int) {
-        index = val.toInt();
-    }
-
-    if (m_blockSignals) return;
-    m_blockSignals = true;
-
-    QPrinter::PaperSize size = QPrinter::PaperSize(index);
-    QPrinter::Orientation orientation = widget.portrait->isChecked()
-                                        ? QPrinter::Portrait
-                                        : QPrinter::Landscape;
-
-    bool custom = size == QPrinter::Custom;
-
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    custom = custom ? !m_cups : custom;
-#endif
-
-    widget.paperWidth->setEnabled(custom);
-    widget.paperHeight->setEnabled(custom);
-    widget.widthLabel->setEnabled(custom);
-    widget.heightLabel->setEnabled(custom);
-    if (custom) {
-        m_paperSize.setWidth( widget.paperWidth->value() * m_currentMultiplier);
-        m_paperSize.setHeight( widget.paperHeight->value() * m_currentMultiplier);
-        m_pagePreview->setPaperSize(m_paperSize);
-    } else {
-        Q_ASSERT(m_printer);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-        if (m_cups) { // combobox is filled with cups based data
-            QByteArray cupsPageSize = widget.paperSize->itemData(widget.paperSize->currentIndex()).toByteArray();
-            m_paperSize = m_cups->paperRect(cupsPageSize).size();
-            if (orientation == QPrinter::Landscape)
-                m_paperSize = QSizeF(m_paperSize.height(), m_paperSize.width()); // swap
-        }
-        else
-#endif
-            m_paperSize = qt_printerPaperSize(orientation, size, QPrinter::Point, 1);
-
-        m_pagePreview->setPaperSize(m_paperSize);
-        widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
-        widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
-    }
-    m_blockSignals = false;
+    if (m_blockSignals)
+        return;
+    m_pageLayout.setOrientation(m_ui.portrait->isChecked() ? QPageLayout::Portrait : QPageLayout::Landscape);
+    m_pagePreview->setPageLayout(m_pageLayout);
+    updateWidget();
 }
 
-void QPageSetupWidget::_q_pageOrientationChanged()
-{
-    if (QPrinter::PaperSize(widget.paperSize->currentIndex()) == QPrinter::Custom) {
-        double tmp = widget.paperWidth->value();
-        widget.paperWidth->setValue(widget.paperHeight->value());
-        widget.paperHeight->setValue(tmp);
-    }
-    _q_paperSizeChanged();
-}
-
-extern double qt_multiplierForUnit(QPrinter::Unit unit, int resolution);
-
-void QPageSetupWidget::unitChanged(int item)
+void QPageSetupWidget::pagesPerSheetChanged()
 {
-    QString suffix;
-    switch(item) {
-    case 0:
-        m_currentMultiplier = 10 * qt_multiplierForUnit(QPrinter::Millimeter, 1);
-        suffix = QString::fromLatin1(" cm");
+#if QT_CONFIG(cups)
+    switch (m_ui.pagesPerSheetCombo->currentData().toInt()) {
+    case QCUPSSupport::OnePagePerSheet:
+        m_pagePreview->setPagePreviewLayout(1, 1);
+        break;
+    case QCUPSSupport::TwoPagesPerSheet:
+        m_pagePreview->setPagePreviewLayout(1, 2);
         break;
-    case 2:
-        m_currentMultiplier = qt_multiplierForUnit(QPrinter::Inch, 1);
-        suffix = QString::fromLatin1(" in");
+    case QCUPSSupport::FourPagesPerSheet:
+        m_pagePreview->setPagePreviewLayout(2, 2);
+        break;
+    case QCUPSSupport::SixPagesPerSheet:
+        m_pagePreview->setPagePreviewLayout(3, 2);
         break;
-    case 3:
-        m_currentMultiplier = qt_multiplierForUnit(QPrinter::Point, 1);
-        suffix = QString::fromLatin1(" pt");
+    case QCUPSSupport::NinePagesPerSheet:
+        m_pagePreview->setPagePreviewLayout(3, 3);
         break;
-    case 1:
-    default:
-        m_currentMultiplier = qt_multiplierForUnit(QPrinter::Millimeter, 1);
-        suffix = QString::fromLatin1(" mm");
+    case QCUPSSupport::SixteenPagesPerSheet:
+        m_pagePreview->setPagePreviewLayout(4, 4);
         break;
     }
-    const bool old = m_blockSignals;
-    m_blockSignals = true;
-    widget.topMargin->setSuffix(suffix);
-    widget.leftMargin->setSuffix(suffix);
-    widget.rightMargin->setSuffix(suffix);
-    widget.bottomMargin->setSuffix(suffix);
-    widget.paperWidth->setSuffix(suffix);
-    widget.paperHeight->setSuffix(suffix);
-    widget.topMargin->setValue(m_topMargin / m_currentMultiplier);
-    widget.leftMargin->setValue(m_leftMargin / m_currentMultiplier);
-    widget.rightMargin->setValue(m_rightMargin / m_currentMultiplier);
-    widget.bottomMargin->setValue(m_bottomMargin / m_currentMultiplier);
-    widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
-    widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
-    m_blockSignals = old;
+#endif
+}
+
+void QPageSetupWidget::unitChanged()
+{
+    if (m_blockSignals)
+        return;
+    m_units = qvariant_cast<QPageLayout::Unit>(m_ui.unitCombo->currentData());
+    m_pageLayout.setUnits(m_units);
+    updateWidget();
 }
 
-void QPageSetupWidget::setTopMargin(double newValue)
+void QPageSetupWidget::topMarginChanged(double newValue)
 {
-    if (m_blockSignals) return;
-    m_topMargin = newValue * m_currentMultiplier;
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+    if (m_blockSignals)
+        return;
+    m_pageLayout.setTopMargin(newValue);
+    m_pagePreview->setPageLayout(m_pageLayout);
 }
 
-void QPageSetupWidget::setBottomMargin(double newValue)
+void QPageSetupWidget::bottomMarginChanged(double newValue)
 {
-    if (m_blockSignals) return;
-    m_bottomMargin = newValue * m_currentMultiplier;
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+    if (m_blockSignals)
+        return;
+    m_pageLayout.setBottomMargin(newValue);
+    m_pagePreview->setPageLayout(m_pageLayout);
 }
 
-void QPageSetupWidget::setLeftMargin(double newValue)
+void QPageSetupWidget::leftMarginChanged(double newValue)
 {
-    if (m_blockSignals) return;
-    m_leftMargin = newValue * m_currentMultiplier;
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+    if (m_blockSignals)
+        return;
+    m_pageLayout.setLeftMargin(newValue);
+    m_pagePreview->setPageLayout(m_pageLayout);
 }
 
-void QPageSetupWidget::setRightMargin(double newValue)
+void QPageSetupWidget::rightMarginChanged(double newValue)
 {
-    if (m_blockSignals) return;
-    m_rightMargin = newValue * m_currentMultiplier;
-    m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+    if (m_blockSignals)
+        return;
+    m_pageLayout.setRightMargin(newValue);
+    m_pagePreview->setPageLayout(m_pageLayout);
 }
 
-
+// QPageSetupDialog
+// - Public Linux / CUPS class implementation
 
 QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
-    : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), printer, parent)
+    : QDialog(*(new QUnixPageSetupDialogPrivate(printer)), parent)
 {
     Q_D(QPageSetupDialog);
-    d->init();
+    setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+    static_cast<QUnixPageSetupDialogPrivate *>(d)->init();
 }
 
-
 QPageSetupDialog::QPageSetupDialog(QWidget *parent)
-    : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), 0, parent)
+    : QDialog(*(new QUnixPageSetupDialogPrivate(nullptr)), parent)
 {
     Q_D(QPageSetupDialog);
-    d->init();
+    setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+    static_cast<QUnixPageSetupDialogPrivate *>(d)->init();
 }
 
-/*!
-    \internal
-*/
 int QPageSetupDialog::exec()
 {
     Q_D(QPageSetupDialog);
 
     int ret = QDialog::exec();
-    if (ret == Accepted)
-        d->widget->setupPrinter();
+    if (ret == Accepted) {
+        static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->setupPrinter();
+        static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->updateSavedValues();
+    } else {
+        static_cast <QUnixPageSetupDialogPrivate*>(d)->widget->revertToSavedValues();
+    }
     return ret;
 }
 
-
 QT_END_NAMESPACE
 
-#include "moc_qpagesetupdialog.cpp"
+#include "moc_qpagesetupdialog_unix_p.cpp"
 
-#endif // QT_NO_PRINTDIALOG
+#include "moc_qpagesetupdialog.cpp"
--- a/libgui/languages/build_ts/octave-qt/qpagesetupdialog_win.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qpagesetupdialog_win.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,66 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qpagesetupdialog.h"
 
-#ifndef QT_NO_PRINTDIALOG
 #include <qapplication.h>
 
 #include <private/qprintengine_win_p.h>
-#include <private/qabstractpagesetupdialog_p.h>
+#include "qpagesetupdialog_p.h"
+#include "qprinter.h"
+#include <qpa/qplatformnativeinterface.h>
 
 QT_BEGIN_NAMESPACE
 
-class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
+    : QDialog(*(new QPageSetupDialogPrivate(printer)), parent)
 {
-};
-
-QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
-    : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), printer, parent)
-{
+    setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+    setAttribute(Qt::WA_DontShowOnScreen);
 }
 
 QPageSetupDialog::QPageSetupDialog(QWidget *parent)
-    : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), 0, parent)
+    : QDialog(*(new QPageSetupDialogPrivate(0)), parent)
 {
+    setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+    setAttribute(Qt::WA_DontShowOnScreen);
 }
 
 int QPageSetupDialog::exec()
@@ -80,7 +43,7 @@
     // we need a temp DEVMODE struct if we don't have a global DEVMODE
     HGLOBAL hDevMode = 0;
     int devModeSize = 0;
-    if (!ep->globalDevMode) {
+    if (!engine->globalDevMode()) {
         devModeSize = sizeof(DEVMODE) + ep->devMode->dmDriverExtra;
         hDevMode = GlobalAlloc(GHND, devModeSize);
         if (hDevMode) {
@@ -90,64 +53,97 @@
         }
         psd.hDevMode = hDevMode;
     } else {
-        psd.hDevMode = ep->devMode;
+        psd.hDevMode = engine->globalDevMode();
     }
 
-    HGLOBAL *tempDevNames = ep->createDevNames();
+    HGLOBAL *tempDevNames = engine->createGlobalDevNames();
     psd.hDevNames = tempDevNames;
 
     QWidget *parent = parentWidget();
     parent = parent ? parent->window() : QApplication::activeWindow();
     Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
-    psd.hwndOwner = parent ? parent->winId() : 0;
+
+    QWindow *parentWindow = parent ? parent->windowHandle() : 0;
+    psd.hwndOwner = parentWindow ? (HWND)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", parentWindow) : 0;
 
     psd.Flags = PSD_MARGINS;
-    double multiplier = 1;
-    switch (QLocale::system().measurementSystem()) {
-    case QLocale::MetricSystem:
-        psd.Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
-        multiplier = 1;
+    QPageLayout layout = d->printer->pageLayout();
+    switch (layout.units()) {
+    case QPageLayout::Millimeter:
+    case QPageLayout::Inch:
         break;
-    case QLocale::ImperialSystem:
-        psd.Flags |= PSD_INTHOUSANDTHSOFINCHES;
-        multiplier = 25.4/10;
+    case QPageLayout::Point:
+    case QPageLayout::Pica:
+    case QPageLayout::Didot:
+    case QPageLayout::Cicero:
+        layout.setUnits(QLocale::system().measurementSystem() == QLocale::MetricSystem ? QPageLayout::Millimeter
+                                                                                       : QPageLayout::Inch);
         break;
     }
-
-    QRect marginRect = ep->getPageMargins();
-    psd.rtMargin.left   = marginRect.left()   / multiplier;
-    psd.rtMargin.top    = marginRect.top()    / multiplier;
-    psd.rtMargin.right  = marginRect.width()  / multiplier;
-    psd.rtMargin.bottom = marginRect.height() / multiplier;
-
-    bool result = PageSetupDlg(&psd);
-    if (result) {
-        ep->readDevnames(psd.hDevNames);
-        ep->readDevmode(psd.hDevMode);
+    qreal multiplier = 1.0;
+    if (layout.units() == QPageLayout::Millimeter) {
+        psd.Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
+        multiplier = 100.0;
+    } else { // QPageLayout::Inch)
+        psd.Flags |= PSD_INTHOUSANDTHSOFINCHES;
+        multiplier = 1000.0;
+    }
+    psd.rtMargin.left   = layout.margins().left() * multiplier;
+    psd.rtMargin.top    = layout.margins().top() * multiplier;
+    psd.rtMargin.right  = layout.margins().right() * multiplier;
+    psd.rtMargin.bottom = layout.margins().bottom() * multiplier;
 
-        QRect theseMargins = QRect(psd.rtMargin.left   * multiplier,
-                                   psd.rtMargin.top    * multiplier,
-                                   psd.rtMargin.right  * multiplier,
-                                   psd.rtMargin.bottom * multiplier);
+    QDialog::setVisible(true);
+    bool result = PageSetupDlg(&psd);
+    QDialog::setVisible(false);
+    if (result) {
+        engine->setGlobalDevMode(psd.hDevNames, psd.hDevMode);
+        QPageSize pageSize;
+        // try to read orientation and paper size ID from the dialog's devmode struct
+        if (psd.hDevMode) {
+            DEVMODE *rDevmode = reinterpret_cast<DEVMODE*>(GlobalLock(psd.hDevMode));
+            if (rDevmode->dmFields & DM_ORIENTATION) {
+                layout.setOrientation(rDevmode->dmOrientation == DMORIENT_PORTRAIT
+                                      ? QPageLayout::Portrait : QPageLayout::Landscape);
+            }
+            if (rDevmode->dmFields & DM_PAPERSIZE)
+                pageSize = QPageSize::id(rDevmode->dmPaperSize);
+            GlobalUnlock(rDevmode);
+        }
+        // fall back to use our own matching, and assume that paper that's wider than long means landscape
+        if (!pageSize.isValid() || pageSize.id() == QPageSize::Custom) {
+            QSizeF unitSize(psd.ptPaperSize.x / multiplier, psd.ptPaperSize.y / multiplier);
+            if (unitSize.width() > unitSize.height()) {
+                layout.setOrientation(QPageLayout::Landscape);
+                unitSize.transpose();
+            } else {
+                layout.setOrientation(QPageLayout::Portrait);
+            }
+            pageSize = QPageSize(unitSize, layout.units() == QPageLayout::Inch
+                                                           ? QPageSize::Inch : QPageSize::Millimeter);
+        }
+        layout.setPageSize(pageSize);
 
-        if (theseMargins != marginRect) {
-            ep->setPageMargins(psd.rtMargin.left   * multiplier,
-                               psd.rtMargin.top    * multiplier,
-                               psd.rtMargin.right  * multiplier,
-                               psd.rtMargin.bottom * multiplier);
-        }
-
-        ep->updateCustomPaperSize();
+        const QMarginsF margins(psd.rtMargin.left, psd.rtMargin.top, psd.rtMargin.right, psd.rtMargin.bottom);
+        layout.setMargins(margins / multiplier);
+        d->printer->setPageLayout(layout);
 
         // copy from our temp DEVMODE struct
-        if (!ep->globalDevMode && hDevMode) {
+        if (!engine->globalDevMode() && hDevMode) {
+            // Make sure memory is allocated
+            if (ep->ownsDevMode && ep->devMode)
+                free(ep->devMode);
+            ep->devMode = (DEVMODE *) malloc(devModeSize);
+            ep->ownsDevMode = true;
+
+            // Copy
             void *src = GlobalLock(hDevMode);
             memcpy(ep->devMode, src, devModeSize);
             GlobalUnlock(hDevMode);
         }
     }
 
-    if (!ep->globalDevMode && hDevMode)
+    if (!engine->globalDevMode() && hDevMode)
         GlobalFree(hDevMode);
     GlobalFree(tempDevNames);
     done(result);
@@ -162,4 +158,3 @@
 }
 
 QT_END_NAMESPACE
-#endif
--- a/libgui/languages/build_ts/octave-qt/qplatformtheme.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qplatformtheme.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qplatformtheme.h"
 
@@ -64,6 +28,8 @@
     \ingroup qpa
     \brief The QPlatformTheme class allows customizing the UI based on themes.
 
+    See the init_platform function in qguiapplication.cpp for the complete
+    platform initialization process.
 */
 
 /*!
@@ -163,6 +129,30 @@
 
     \value ShowShortcutsInContextMenus (bool) Whether to display shortcut key sequences in context menus.
 
+    \value InteractiveResizeAcrossScreens (bool) Whether using the whole virtual geometry of all the screens
+                        as basis for the resize.
+                        This enum value has been added in Qt 6.2.
+
+    \value ShowDirectoriesFirst (bool) Whether directories should be shown
+           first (before files) in file dialogs.
+           This enum value was added in Qt 6.3.
+
+    \value PreselectFirstFileInDirectory (bool) Whether the first file in a directory
+           should be automatically selected when a file dialog opens.
+           This enum value was added in Qt 6.3.
+
+    \value ButtonPressKeys (QList<Qt::Key>) A list of keys that can be used to press buttons via keyboard input.
+
+    \value SetFocusOnTouchRelease (bool) Whether focus objects (line edits etc) should receive
+           input focus after a touch/mouse release.
+           This enum value has been added in Qt 6.5.
+
+    \value MouseCursorTheme (QString) Name of the mouse cursor theme.
+           This enum value has been added in Qt 6.5.
+
+    \value MouseCursorSize (QSize) Size of the mouse cursor.
+           This enum value has been added in Qt 6.5.
+
     \sa themeHint(), QStyle::pixelMetric()
 */
 
@@ -286,7 +276,7 @@
     {QKeySequence::MoveToEndOfLine,         0,          Qt::META | Qt::Key_Right,               KB_Mac},
     {QKeySequence::MoveToEndOfLine,         0,          Qt::CTRL | Qt::Key_Right,               KB_Mac },
     {QKeySequence::MoveToEndOfLine,         0,          Qt::Key_End,                            KB_Win | KB_X11},
-    {QKeySequence::MoveToEndOfLine,         0,          Qt::CTRL + Qt::Key_E,                   KB_X11},
+    {QKeySequence::MoveToEndOfLine,         0,          Qt::CTRL | Qt::Key_E,                   KB_X11},
     {QKeySequence::MoveToStartOfBlock,      0,          Qt::META | Qt::Key_A,                   KB_Mac},
     {QKeySequence::MoveToStartOfBlock,      1,          Qt::ALT  | Qt::Key_Up,                  KB_Mac}, //mac only
     {QKeySequence::MoveToEndOfBlock,        0,          Qt::META | Qt::Key_E,                   KB_Mac},
@@ -362,7 +352,61 @@
     delete systemPalette;
 }
 
-Q_GUI_EXPORT QPalette qt_fusionPalette();
+Q_GUI_EXPORT QPalette qt_fusionPalette()
+{
+    auto theme = QGuiApplicationPrivate::platformTheme();
+    const bool darkAppearance = theme
+                              ? theme->colorScheme() == Qt::ColorScheme::Dark
+                              : false;
+    const QColor windowText = darkAppearance ? QColor(240, 240, 240) : Qt::black;
+    const QColor backGround = darkAppearance ? QColor(50, 50, 50) : QColor(239, 239, 239);
+    const QColor light = backGround.lighter(150);
+    const QColor mid = (backGround.darker(130));
+    const QColor midLight = mid.lighter(110);
+    const QColor base = darkAppearance ? backGround.darker(140) : Qt::white;
+    const QColor disabledBase(backGround);
+    const QColor dark = backGround.darker(150);
+    const QColor darkDisabled = QColor(209, 209, 209).darker(110);
+    const QColor text = darkAppearance ? windowText : Qt::black;
+    const QColor highlight = QColor(48, 140, 198);
+    const QColor hightlightedText = darkAppearance ? windowText : Qt::white;
+    const QColor disabledText = darkAppearance ? QColor(130, 130, 130) : QColor(190, 190, 190);
+    const QColor button = backGround;
+    const QColor shadow = dark.darker(135);
+    const QColor disabledShadow = shadow.lighter(150);
+    const QColor disabledHighlight(145, 145, 145);
+    QColor placeholder = text;
+    placeholder.setAlpha(128);
+
+    QPalette fusionPalette(windowText, backGround, light, dark, mid, text, base);
+    fusionPalette.setBrush(QPalette::Midlight, midLight);
+    fusionPalette.setBrush(QPalette::Button, button);
+    fusionPalette.setBrush(QPalette::Shadow, shadow);
+    fusionPalette.setBrush(QPalette::HighlightedText, hightlightedText);
+
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Text, disabledText);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::WindowText, disabledText);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::ButtonText, disabledText);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Base, disabledBase);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Dark, darkDisabled);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Shadow, disabledShadow);
+
+    fusionPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
+    fusionPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, disabledHighlight);
+
+    fusionPalette.setBrush(QPalette::Active, QPalette::Accent, highlight);
+    fusionPalette.setBrush(QPalette::Inactive, QPalette::Accent, highlight);
+    fusionPalette.setBrush(QPalette::Disabled, QPalette::Accent, disabledHighlight);
+
+    fusionPalette.setBrush(QPalette::PlaceholderText, placeholder);
+
+    // Use a more legible light blue on dark backgrounds than the default Qt::blue.
+    if (darkAppearance)
+        fusionPalette.setBrush(QPalette::Link, highlight);
+
+    return fusionPalette;
+}
 
 void QPlatformThemePrivate::initializeSystemPalette()
 {
@@ -397,6 +441,11 @@
     return nullptr;
 }
 
+Qt::ColorScheme QPlatformTheme::colorScheme() const
+{
+    return Qt::ColorScheme::Unknown;
+}
+
 const QPalette *QPlatformTheme::palette(Palette type) const
 {
     Q_D(const QPlatformTheme);
@@ -410,7 +459,7 @@
 
 const QFont *QPlatformTheme::font(Font type) const
 {
-    Q_UNUSED(type)
+    Q_UNUSED(type);
     return nullptr;
 }
 
@@ -473,6 +522,16 @@
         return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::UiEffects);
     case QPlatformTheme::ShowShortcutsInContextMenus:
         return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::ShowShortcutsInContextMenus);
+    case QPlatformTheme::SetFocusOnTouchRelease:
+        return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::SetFocusOnTouchRelease);
+    case QPlatformTheme::FlickStartDistance:
+        return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FlickStartDistance);
+    case QPlatformTheme::FlickMaximumVelocity:
+        return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FlickMaximumVelocity);
+    case QPlatformTheme::FlickDeceleration:
+        return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FlickDeceleration);
+    case QPlatformTheme::UnderlineShortcut:
+        return QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::UnderlineShortcut);
     default:
         return QPlatformTheme::defaultThemeHint(hint);
     }
@@ -496,7 +555,7 @@
     case QPlatformTheme::PasswordMaskDelay:
         return QVariant(int(0));
     case QPlatformTheme::PasswordMaskCharacter:
-        return QVariant(QChar(0x25CF));
+        return QVariant(QChar(u'\x25CF'));
     case QPlatformTheme::StartDragVelocity:
         return QVariant(int(0)); // no limit
     case QPlatformTheme::UseFullScreenForPopupMenu:
@@ -563,7 +622,32 @@
         }
     case MouseQuickSelectionThreshold:
         return QVariant(10);
+    case InteractiveResizeAcrossScreens:
+        return true;
+    case ShowDirectoriesFirst:
+        return true;
+    case PreselectFirstFileInDirectory:
+        return false;
+    case ButtonPressKeys:
+        return QVariant::fromValue(QList<Qt::Key>({ Qt::Key_Space, Qt::Key_Select }));
+    case SetFocusOnTouchRelease:
+        return false;
+    case FlickStartDistance:
+        return QVariant(15);
+    case FlickMaximumVelocity:
+        return QVariant(2500);
+    case FlickDeceleration:
+        return QVariant(5000);
+    case MenuBarFocusOnAltPressRelease:
+        return false;
+    case MouseCursorTheme:
+        return QVariant(QString());
+    case MouseCursorSize:
+        return QVariant(QSize(16, 16));
+    case UnderlineShortcut:
+        return true;
     }
+
     return QVariant();
 }
 
@@ -608,21 +692,6 @@
     return new QIconLoaderEngine(iconName);
 }
 
-#if defined(Q_OS_MACX)
-static inline int maybeSwapShortcut(int shortcut)
-{
-    if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
-        uint oldshortcut = shortcut;
-        shortcut &= ~(Qt::CTRL | Qt::META);
-        if (oldshortcut & Qt::CTRL)
-            shortcut |= Qt::META;
-        if (oldshortcut & Qt::META)
-            shortcut |= Qt::CTRL;
-    }
-    return shortcut;
-}
-#endif
-
 #if QT_CONFIG(shortcut)
 // mixed-mode predicate: all of these overloads are actually needed (but not all for every compiler)
 struct ByStandardKey {
@@ -660,12 +729,8 @@
         if (!(it->platform & platform))
             continue;
 
-        uint shortcut =
-#if defined(Q_OS_MACX)
-            maybeSwapShortcut(it->shortcut);
-#else
-            it->shortcut;
-#endif
+        uint shortcut = it->shortcut.toCombined();
+
         if (it->priority > 0)
             list.prepend(QKeySequence(shortcut));
         else
@@ -698,7 +763,7 @@
 
 QKeySequence QPlatformTheme::standardButtonShortcut(int button) const
 {
-    Q_UNUSED(button)
+    Q_UNUSED(button);
     return QKeySequence();
 }
 #endif // QT_CONFIG(shortcut)
@@ -750,33 +815,38 @@
 
 QString QPlatformTheme::removeMnemonics(const QString &original)
 {
-    QString returnText(original.size(), 0);
+    const auto mnemonicInParentheses = [](QStringView text) {
+        /* Format of mnemonics to remove is /\(&[^&]\)/ but accept full-width
+           forms of ( and ) as equivalent, for cross-platform compatibility with
+           MS (and consequent behavior of translators, see QTBUG-110829).
+        */
+        Q_ASSERT(text.size() == 4); // Caller's responsibility.
+        constexpr QChar wideOpen = u'\uff08', wideClose = u'\uff09';
+        if (!text.startsWith(u'(') && !text.startsWith(wideOpen))
+            return false;
+        if (text[1] != u'&' || text[2] == u'&')
+            return false;
+        return text.endsWith(u')') || text.endsWith(wideClose);
+    };
+    QString returnText(original.size(), u'\0');
     int finalDest = 0;
-    int currPos = 0;
-    int l = original.length();
-    while (l) {
-        if (original.at(currPos) == QLatin1Char('&')) {
-            ++currPos;
-            --l;
-            if (l == 0)
+    QStringView text(original);
+    while (!text.isEmpty()) {
+        if (text.startsWith(u'&')) {
+            text = text.sliced(1);
+            if (text.isEmpty())
                 break;
-        } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 &&
-                   original.at(currPos + 1) == QLatin1Char('&') &&
-                   original.at(currPos + 2) != QLatin1Char('&') &&
-                   original.at(currPos + 3) == QLatin1Char(')')) {
-            /* remove mnemonics its format is "\s*(&X)" */
-            int n = 0;
-            while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
-                ++n;
-            finalDest -= n;
-            currPos += 4;
-            l -= 4;
+        } else if (text.size() >= 4 && mnemonicInParentheses(text.first(4))) {
+            // Advance over the matched mnemonic:
+            text = text.sliced(4);
+            // Also strip any leading space before it:
+            while (finalDest > 0 && returnText.at(finalDest - 1).isSpace())
+                --finalDest;
             continue;
         }
-        returnText[finalDest] = original.at(currPos);
-        ++currPos;
+        returnText[finalDest] = text.front();
+        text = text.sliced(1);
         ++finalDest;
-        --l;
     }
     returnText.truncate(finalDest);
     return returnText;
@@ -795,4 +865,11 @@
     return result;
 }
 
+QString QPlatformTheme::name() const
+{
+    return d_func()->name;
+}
+
 QT_END_NAMESPACE
+
+#include "moc_qplatformtheme.cpp"
--- a/libgui/languages/build_ts/octave-qt/qprintdialog_unix.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qprintdialog_unix.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,109 +1,193 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
 #include "qplatformdefs.h"
-
-#ifndef QT_NO_PRINTDIALOG
+#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
 
 #include "private/qabstractprintdialog_p.h"
-#include <QtGui/qmessagebox.h>
+#if QT_CONFIG(messagebox)
+#include <QtWidgets/qmessagebox.h>
+#endif
 #include "qprintdialog.h"
+#if QT_CONFIG(filedialog)
 #include "qfiledialog.h"
+#endif
+#include <QtCore/qdebug.h>
 #include <QtCore/qdir.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qstringconverter.h>
 #include <QtGui/qevent.h>
+#if QT_CONFIG(filesystemmodel)
 #include <QtGui/qfilesystemmodel.h>
-#include <QtGui/qstyleditemdelegate.h>
-#include <QtGui/qprinter.h>
+#endif
+#include <QtWidgets/qstyleditemdelegate.h>
+#include <QtWidgets/qformlayout.h>
+#include <QtPrintSupport/qprinter.h>
+
+#include <qpa/qplatformprintplugin.h>
+#include <qpa/qplatformprintersupport.h>
+
+#include <private/qprintdevice_p.h>
 
-#include <QtGui/qdialogbuttonbox.h>
+#include <QtWidgets/qdialogbuttonbox.h>
 
-#include "qfscompleter_p.h"
+#if QT_CONFIG(regularexpression)
+#include <qregularexpression.h>
+#endif
+
+#if QT_CONFIG(completer)
+#include <private/qcompleter_p.h>
+#endif
 #include "ui_qprintpropertieswidget.h"
 #include "ui_qprintsettingsoutput.h"
 #include "ui_qprintwidget.h"
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-#  include <private/qcups_p.h>
-#  include <cups/cups.h>
-#  include <private/qpdf_p.h>
-#else
-#  include <QtCore/qlibrary.h>
+#if QT_CONFIG(cups)
+Q_DECLARE_METATYPE(const ppd_option_t *)
+#include <private/qcups_p.h>
+#if QT_CONFIG(cupsjobwidget)
+#include "qcupsjobwidget_p.h"
+#endif
 #endif
 
-#include <private/qprinterinfo_unix_p.h>
+/*
+
+Print dialog class declarations
+
+    QPrintDialog:            The main Print Dialog, nothing really held here.
+
+    QUnixPrintWidget:
+    QUnixPrintWidgetPrivate: The real Unix Print Dialog implementation.
+
+                             Directly includes the upper half of the Print Dialog
+                             containing the Printer Selection widgets and
+                             Properties button.
+
+                             Embeds the Properties pop-up dialog from
+                             QPrintPropertiesDialog
+
+                             Embeds the lower half from separate widget class
+                             QPrintDialogPrivate
+
+                             Layout in qprintwidget.ui
+
+    QPrintDialogPrivate:     The lower half of the Print Dialog containing the
+                             Copies and Options tabs that expands when the
+                             Options button is selected.
+
+                             Layout in qprintsettingsoutput.ui
+
+    QPrintPropertiesDialog:  Dialog displayed when clicking on Properties button to
+                             allow editing of Page and Advanced tabs.
+
+                             Layout in qprintpropertieswidget.ui
+*/
+
+static void _q_pdu_initResources()
+{
+    Q_INIT_RESOURCE(qprintdialog);
+}
 
 QT_BEGIN_NAMESPACE
 
-class QOptionTreeItem;
-class QPPDOptionsModel;
+using namespace Qt::StringLiterals;
 
 class QPrintPropertiesDialog : public QDialog
 {
     Q_OBJECT
 public:
-    QPrintPropertiesDialog(QAbstractPrintDialog *parent = 0);
+    QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
+                           QPrinter::OutputFormat outputFormat, const QString &printerName,
+                           QAbstractPrintDialog *parent);
     ~QPrintPropertiesDialog();
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    void setCups(QCUPSSupport *cups) { m_cups = cups; }
-    void addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const;
+    void setupPrinter() const;
+
+private slots:
+    void reject() override;
+    void accept() override;
+
+private:
+    void showEvent(QShowEvent *event) override;
+
+    friend class QUnixPrintWidgetPrivate;
+#if QT_CONFIG(cups)
+    QPrinter *m_printer;
+#endif
+    Ui::QPrintPropertiesWidget widget;
+    QDialogButtonBox *m_buttons;
+#if QT_CONFIG(cupsjobwidget)
+    QCupsJobWidget *m_jobOptions;
 #endif
 
-    void selectPrinter();
-    void selectPdfPsPrinter(const QPrinter *p);
+#if QT_CONFIG(cups)
+    bool createAdvancedOptionsWidget();
+    void setPrinterAdvancedCupsOptions() const;
+    void revertAdvancedOptionsToSavedValues() const;
+    void advancedOptionsUpdateSavedValues() const;
+    bool anyPpdOptionConflict() const;
+    bool anyAdvancedOptionConflict() const;
+
+    QPrintDevice *m_currentPrintDevice;
 
-    /// copy printer properties to the widget
-    void applyPrinterProperties(QPrinter *p);
-    void setupPrinter() const;
+    QStringDecoder toUnicode;
+    QList<QComboBox*> m_advancedOptionsCombos;
+#endif
+};
+
+class QUnixPrintWidgetPrivate;
 
-protected:
-    void showEvent(QShowEvent* event);
+class QUnixPrintWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit QUnixPrintWidget(QPrinter *printer, QWidget *parent = nullptr);
+    ~QUnixPrintWidget();
+    void updatePrinter();
 
 private:
-    Ui::QPrintPropertiesWidget widget;
-    QDialogButtonBox *m_buttons;
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    QCUPSSupport *m_cups;
-    QPPDOptionsModel *m_cupsOptionsModel;
+    friend class QPrintDialog;
+    friend class QPrintDialogPrivate;
+    friend class QUnixPrintWidgetPrivate;
+    QUnixPrintWidgetPrivate *d;
+    Q_PRIVATE_SLOT(d, void _q_printerChanged(int))
+    Q_PRIVATE_SLOT(d, void _q_btnBrowseClicked())
+    Q_PRIVATE_SLOT(d, void _q_btnPropertiesClicked())
+};
+
+class QUnixPrintWidgetPrivate
+{
+public:
+    QUnixPrintWidgetPrivate(QUnixPrintWidget *q, QPrinter *prn);
+    ~QUnixPrintWidgetPrivate();
+
+    bool checkFields();
+    void setupPrinter();
+    void setOptionsPane(QPrintDialogPrivate *pane);
+    void setupPrinterProperties();
+// slots
+    void _q_printerChanged(int index);
+    void _q_btnPropertiesClicked();
+    void _q_btnBrowseClicked();
+
+    QUnixPrintWidget * const parent;
+    QPrintPropertiesDialog *propertiesDialog;
+    Ui::QPrintWidget widget;
+    QPrintDialog * q;
+    QPrinter *printer;
+    QPrintDevice m_currentPrintDevice;
+
+    void updateWidget();
+
+#if QT_CONFIG(cups)
+    void setPpdDuplex(QPrinter::DuplexMode mode);
+    ppd_option_t *m_duplexPpdOption;
 #endif
+
+private:
+    QPrintDialogPrivate *optionsPane;
+    bool filePrintersAdded;
 };
 
 class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
@@ -115,264 +199,392 @@
     ~QPrintDialogPrivate();
 
     void init();
-    /// copy printer properties to the widget
-    void applyPrinterProperties(QPrinter *p);
+
+    void selectPrinter(const QPrinter::OutputFormat outputFormat);
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    void selectPrinter(QCUPSSupport *cups);
-#endif
-
-    void _q_chbPrintLastFirstToggled(bool);
-#ifndef QT_NO_MESSAGEBOX
+    void _q_togglePageSetCombo(bool);
+#if QT_CONFIG(messagebox)
     void _q_checkFields();
 #endif
     void _q_collapseOrExpandDialog();
 
+#if QT_CONFIG(cups)
+    void updatePpdDuplexOption(QRadioButton *radio);
+#endif
     void setupPrinter();
     void updateWidgets();
 
-    virtual void setTabs(const QList<QWidget*> &tabs);
+    virtual void setTabs(const QList<QWidget*> &tabs) override;
 
     Ui::QPrintSettingsOutput options;
     QUnixPrintWidget *top;
     QWidget *bottom;
     QDialogButtonBox *buttons;
     QPushButton *collapseButton;
+    QPrinter::OutputFormat printerOutputFormat;
+private:
+    void setExplicitDuplexMode(QPrint::DuplexMode duplexMode);
+    // duplex mode explicitly set by user, QPrint::DuplexAuto otherwise
+    QPrint::DuplexMode explicitDuplexMode;
 };
 
-#if defined (Q_OS_UNIX)
-class QUnixPrintWidgetPrivate
-{
-public:
-    QUnixPrintWidgetPrivate(QUnixPrintWidget *q);
-    ~QUnixPrintWidgetPrivate();
-
-    /// copy printer properties to the widget
-    void applyPrinterProperties(QPrinter *p);
-    bool checkFields();
-    void setupPrinter();
-    void setOptionsPane(QPrintDialogPrivate *pane);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    void setCupsProperties();
-#endif
-
-// slots
-    void _q_printerChanged(int index);
-    void _q_btnPropertiesClicked();
-    void _q_btnBrowseClicked();
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
-    QUnixPrintWidget * const parent;
-    QPrintPropertiesDialog *propertiesDialog;
-    Ui::QPrintWidget widget;
-    QAbstractPrintDialog * q;
-    QPrinter *printer;
-    QList<QPrinterDescription> lprPrinters;
-    void updateWidget();
+/*
 
-private:
-    QPrintDialogPrivate *optionsPane;
-    bool filePrintersAdded;
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    QCUPSSupport* cups;
-    int cupsPrinterCount;
-    const cups_dest_t* cupsPrinters;
-    const ppd_file_t* cupsPPD;
-#endif
-};
-#endif
-
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-class QOptionTreeItem
-{
-public:
-    enum ItemType { Root, Group, Option, Choice };
-
-    QOptionTreeItem(ItemType t, int i, const void* p, const char* desc, QOptionTreeItem* pi)
-        : type(t),
-          index(i),
-          ptr(p),
-          description(desc),
-          selected(-1),
-          selDescription(0),
-          parentItem(pi) {}
+    QPrintPropertiesDialog
 
-    ~QOptionTreeItem() {
-        while (!childItems.isEmpty())
-            delete childItems.takeFirst();
-    }
-
-    ItemType type;
-    int index;
-    const void* ptr;
-    const char* description;
-    int selected;
-    const char* selDescription;
-    QOptionTreeItem* parentItem;
-    QList<QOptionTreeItem*> childItems;
-};
+    Dialog displayed when clicking on Properties button to allow editing of Page
+    and Advanced tabs.
 
-class QPPDOptionsModel : public QAbstractItemModel
-{
-    friend class QPPDOptionsEditor;
-public:
-    QPPDOptionsModel(QCUPSSupport *cups, QObject *parent = 0);
-    ~QPPDOptionsModel();
-
-    int columnCount(const QModelIndex& parent = QModelIndex()) const;
-    int rowCount(const QModelIndex& parent = QModelIndex()) const;
-    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-    QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
-    QModelIndex parent(const QModelIndex& index) const;
-    Qt::ItemFlags flags(const QModelIndex& index) const;
-    QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
+*/
 
-    QOptionTreeItem* rootItem;
-    QCUPSSupport *cups;
-    const ppd_file_t* ppd;
-    void parseItems();
-    void parseGroups(QOptionTreeItem* parent);
-    void parseOptions(QOptionTreeItem* parent);
-    void parseChoices(QOptionTreeItem* parent);
-};
-
-class QPPDOptionsEditor : public QStyledItemDelegate
-{
-    Q_OBJECT
-public:
-    QPPDOptionsEditor(QObject* parent = 0) : QStyledItemDelegate(parent) {}
-    ~QPPDOptionsEditor() {}
-
-    QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
-    void setEditorData(QWidget* editor, const QModelIndex& index) const;
-    void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
-
-private slots:
-    void cbChanged(int index);
-
-};
-
-#endif
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-QPrintPropertiesDialog::QPrintPropertiesDialog(QAbstractPrintDialog *parent)
+QPrintPropertiesDialog::QPrintPropertiesDialog(QPrinter *printer, QPrintDevice *currentPrintDevice,
+                                               QPrinter::OutputFormat outputFormat, const QString &printerName,
+                                               QAbstractPrintDialog *parent)
     : QDialog(parent)
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    , m_cups(0), m_cupsOptionsModel(0)
+#if QT_CONFIG(cups)
+    , m_printer(printer)
 #endif
 {
+    setWindowTitle(tr("Printer Properties"));
     QVBoxLayout *lay = new QVBoxLayout(this);
-    this->setLayout(lay);
     QWidget *content = new QWidget(this);
     widget.setupUi(content);
     m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
     lay->addWidget(content);
     lay->addWidget(m_buttons);
 
-    connect(m_buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept()));
-    connect(m_buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
+    connect(m_buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &QPrintPropertiesDialog::accept);
+    connect(m_buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &QPrintPropertiesDialog::reject);
+
+    widget.pageSetup->setPrinter(printer, currentPrintDevice, outputFormat, printerName);
+
+#if QT_CONFIG(cupsjobwidget)
+    m_jobOptions = new QCupsJobWidget(printer, currentPrintDevice);
+    widget.tabs->insertTab(1, m_jobOptions, tr("Job Options"));
+#endif
+
+    const int advancedTabIndex = widget.tabs->indexOf(widget.cupsPropertiesPage);
+#if QT_CONFIG(cups)
+    m_currentPrintDevice = currentPrintDevice;
+    const bool anyWidgetCreated = createAdvancedOptionsWidget();
+
+    widget.tabs->setTabEnabled(advancedTabIndex, anyWidgetCreated);
+
+    connect(widget.pageSetup, &QPageSetupWidget::ppdOptionChanged, this, [this] {
+        widget.conflictsLabel->setVisible(anyPpdOptionConflict());
+    });
+
+#else
+    Q_UNUSED(currentPrintDevice);
+    widget.tabs->setTabEnabled(advancedTabIndex, false);
+#endif
 }
 
 QPrintPropertiesDialog::~QPrintPropertiesDialog()
 {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    delete m_cupsOptionsModel;
-#else
-    delete widget.cupsPropertiesPage;
-#endif
-}
-
-void QPrintPropertiesDialog::applyPrinterProperties(QPrinter *p)
-{
-    widget.pageSetup->setPrinter(p);
 }
 
 void QPrintPropertiesDialog::setupPrinter() const
 {
-    widget.pageSetup->setupPrinter();
+#if QT_CONFIG(cups)
+    QCUPSSupport::clearCupsOptions(m_printer);
+#endif
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    QPPDOptionsModel* model = static_cast<QPPDOptionsModel*>(widget.treeView->model());
-    if (model) {
-        QOptionTreeItem* rootItem = model->rootItem;
-        QList<const ppd_option_t*> options;
-        QList<const char*> markedOptions;
+    widget.pageSetup->setupPrinter();
+#if QT_CONFIG(cupsjobwidget)
+    m_jobOptions->setupPrinter();
+#endif
 
-        addItemToOptions(rootItem, options, markedOptions);
-        model->cups->saveOptions(options, markedOptions);
-    }
+#if QT_CONFIG(cups)
+    // Set Color by default, that will change if the "ColorModel" property is available
+    m_printer->setColorMode(QPrinter::Color);
+
+    setPrinterAdvancedCupsOptions();
 #endif
 }
 
-void QPrintPropertiesDialog::selectPrinter()
+void QPrintPropertiesDialog::reject()
+{
+    widget.pageSetup->revertToSavedValues();
+
+#if QT_CONFIG(cupsjobwidget)
+    m_jobOptions->revertToSavedValues();
+#endif
+
+#if QT_CONFIG(cups)
+    revertAdvancedOptionsToSavedValues();
+#endif
+    QDialog::reject();
+}
+
+void QPrintPropertiesDialog::accept()
 {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    widget.pageSetup->selectPrinter(m_cups);
-    widget.treeView->setModel(0);
-    if (m_cups && QCUPSSupport::isAvailable()) {
+#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
+    if (widget.pageSetup->hasPpdConflict()) {
+        widget.tabs->setCurrentWidget(widget.tabPage);
+        const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Page Setup Conflicts"),
+                                                                        tr("There are conflicts in page setup options. Do you want to fix them?"),
+                                                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+        if (answer != QMessageBox::No)
+            return;
+    } else if (anyAdvancedOptionConflict()) {
+        widget.tabs->setCurrentWidget(widget.cupsPropertiesPage);
+        const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Advanced Option Conflicts"),
+                                                                        tr("There are conflicts in some advanced options. Do you want to fix them?"),
+                                                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+        if (answer != QMessageBox::No)
+            return;
+    }
+    advancedOptionsUpdateSavedValues();
+#endif
+
+#if QT_CONFIG(cupsjobwidget)
+    m_jobOptions->updateSavedValues();
+#endif
+
+    widget.pageSetup->updateSavedValues();
+
+    QDialog::accept();
+}
 
-        if (m_cupsOptionsModel == 0) {
-            m_cupsOptionsModel = new QPPDOptionsModel(m_cups);
+void QPrintPropertiesDialog::showEvent(QShowEvent *event)
+{
+#if QT_CONFIG(cups)
+    widget.conflictsLabel->setVisible(anyPpdOptionConflict());
+#endif
+    QDialog::showEvent(event);
+}
+
+#if QT_CONFIG(cups)
+
+// Used to store the ppd_option_t for each QComboBox that represents an advanced option
+static const char *ppdOptionProperty = "_q_ppd_option";
+
+// Used to store the originally selected choice index for each QComboBox that represents an advanced option
+static const char *ppdOriginallySelectedChoiceProperty = "_q_ppd_originally_selected_choice";
+
+// Used to store the warning label pointer for each QComboBox that represents an advanced option
+static const char *warningLabelProperty = "_q_warning_label";
+
+static bool isBlacklistedGroup(const ppd_group_t *group) noexcept
+{
+    return qstrcmp(group->name, "InstallableOptions") == 0;
+};
 
-            widget.treeView->setItemDelegate(new QPPDOptionsEditor(this));
-        } else {
-            // update the model
-            m_cupsOptionsModel->parseItems();
+static bool isBlacklistedOption(const char *keyword) noexcept
+{
+    // We already let the user set these options elsewhere
+    const char *cupsOptionBlacklist[] = {
+        "Collate",
+        "Copies",
+        "OutputOrder",
+        "PageRegion",
+        "PageSize",
+        "Duplex" // handled by the main dialog
+    };
+    auto equals = [](const char *keyword) {
+        return [keyword](const char *candidate) {
+            return qstrcmp(keyword, candidate) == 0;
+        };
+    };
+    return std::any_of(std::begin(cupsOptionBlacklist), std::end(cupsOptionBlacklist), equals(keyword));
+};
+
+bool QPrintPropertiesDialog::createAdvancedOptionsWidget()
+{
+    bool anyWidgetCreated = false;
+
+    ppd_file_t *ppd = qvariant_cast<ppd_file_t*>(m_currentPrintDevice->property(PDPK_PpdFile));
+
+    if (ppd) {
+        toUnicode = QStringDecoder(ppd->lang_encoding, QStringDecoder::Flag::Stateless);
+        if (!toUnicode.isValid()) {
+            qWarning() << "QPrinSupport: Cups uses unsupported encoding" << ppd->lang_encoding;
+            toUnicode = QStringDecoder(QStringDecoder::Utf8, QStringDecoder::Flag::Stateless);
         }
 
-        if (m_cupsOptionsModel->rowCount() > 0) {
-            widget.treeView->setModel(m_cupsOptionsModel);
+        QWidget *holdingWidget = new QWidget();
+        QVBoxLayout *layout = new QVBoxLayout(holdingWidget);
+
+        for (int i = 0; i < ppd->num_groups; ++i) {
+            const ppd_group_t *group = &ppd->groups[i];
+
+            if (!isBlacklistedGroup(group)) {
+                QFormLayout *groupLayout = new QFormLayout();
+
+                for (int i = 0; i < group->num_options; ++i) {
+                    const ppd_option_t *option = &group->options[i];
+
+                    if (!isBlacklistedOption(option->keyword)) {
+                        QComboBox *choicesCb = new QComboBox();
+
+                        const auto setPpdOptionFromCombo = [this, choicesCb, option] {
+                            // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
+                            // because some of them may not be present in the list because they conflict with the
+                            // installable options so use the index passed on addItem
+                            const int selectedChoiceIndex = choicesCb->currentData().toInt();
+                            const auto values = QStringList{} << QString::fromLatin1(option->keyword)
+                                                                << QString::fromLatin1(option->choices[selectedChoiceIndex].choice);
+                            m_currentPrintDevice->setProperty(PDPK_PpdOption, values);
+                            widget.conflictsLabel->setVisible(anyPpdOptionConflict());
+                        };
 
-            for (int i = 0; i < m_cupsOptionsModel->rowCount(); ++i)
-                widget.treeView->expand(m_cupsOptionsModel->index(i,0));
+                        bool foundMarkedChoice = false;
+                        bool markedChoiceNotAvailable = false;
+                        for (int i = 0; i < option->num_choices; ++i) {
+                            const ppd_choice_t *choice = &option->choices[i];
+                            const auto values = QStringList{} << QString::fromLatin1(option->keyword) << QString::fromLatin1(choice->choice);
+                            const bool choiceIsInstallableConflict = m_currentPrintDevice->isFeatureAvailable(PDPK_PpdChoiceIsInstallableConflict, values);
+                            if (choiceIsInstallableConflict && static_cast<int>(choice->marked) == 1) {
+                                markedChoiceNotAvailable = true;
+                            } else if (!choiceIsInstallableConflict) {
+                                choicesCb->addItem(toUnicode(choice->text), i);
+                                if (static_cast<int>(choice->marked) == 1) {
+                                    choicesCb->setCurrentIndex(choicesCb->count() - 1);
+                                    choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
+                                    foundMarkedChoice = true;
+                                } else if (!foundMarkedChoice && qstrcmp(choice->choice, option->defchoice) == 0) {
+                                    choicesCb->setCurrentIndex(choicesCb->count() - 1);
+                                    choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, QVariant(i));
+                                }
+                            }
+                        }
+
+                        if (markedChoiceNotAvailable) {
+                            // If the user default option is not available because of it conflicting with
+                            // the installed options, we need to set the internal ppd value to the value
+                            // being shown in the combo
+                            setPpdOptionFromCombo();
+                        }
+
+                        if (choicesCb->count() > 1) {
 
-            widget.tabs->setTabEnabled(1, true); // enable the advanced tab
-        } else {
-            widget.tabs->setTabEnabled(1, false);
+                            connect(choicesCb, &QComboBox::currentIndexChanged, this, setPpdOptionFromCombo);
+
+                            // We need an extra label at the end to show the conflict warning
+                            QWidget *choicesCbWithLabel = new QWidget();
+                            QHBoxLayout *choicesCbWithLabelLayout = new QHBoxLayout(choicesCbWithLabel);
+                            choicesCbWithLabelLayout->setContentsMargins(0, 0, 0, 0);
+                            QLabel *warningLabel = new QLabel();
+                            choicesCbWithLabelLayout->addWidget(choicesCb);
+                            choicesCbWithLabelLayout->addWidget(warningLabel);
+
+                            QLabel *optionLabel = new QLabel(toUnicode(option->text));
+                            groupLayout->addRow(optionLabel, choicesCbWithLabel);
+                            anyWidgetCreated = true;
+                            choicesCb->setProperty(ppdOptionProperty, QVariant::fromValue(option));
+                            choicesCb->setProperty(warningLabelProperty, QVariant::fromValue(warningLabel));
+                            m_advancedOptionsCombos << choicesCb;
+                        } else {
+                            delete choicesCb;
+                        }
+                    }
+                }
+
+                if (groupLayout->rowCount() > 0) {
+                    QGroupBox *groupBox = new QGroupBox(toUnicode(group->text));
+                    groupBox->setLayout(groupLayout);
+                    layout->addWidget(groupBox);
+                } else {
+                    delete groupLayout;
+                }
+            }
         }
 
-    } else
-#endif
-    {
-        widget.cupsPropertiesPage->setEnabled(false);
-        widget.pageSetup->selectPrinter(0);
+        layout->addStretch();
+        widget.scrollArea->setWidget(holdingWidget);
+    }
+
+    return anyWidgetCreated;
+}
+
+void QPrintPropertiesDialog::setPrinterAdvancedCupsOptions() const
+{
+    for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
+        const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
+
+        // We can't use choicesCb->currentIndex() to know the index of the option in the choices[] array
+        // because some of them may not be present in the list because they conflict with the
+        // installable options so use the index passed on addItem
+        const int selectedChoiceIndex = choicesCb->currentData().toInt();
+        const char *selectedChoice = option->choices[selectedChoiceIndex].choice;
+
+        if (qstrcmp(option->keyword, "ColorModel") == 0)
+            m_printer->setColorMode(qstrcmp(selectedChoice, "Gray") == 0 ? QPrinter::GrayScale : QPrinter::Color);
+
+        if (qstrcmp(option->defchoice, selectedChoice) != 0)
+            QCUPSSupport::setCupsOption(m_printer, QString::fromLatin1(option->keyword), QString::fromLatin1(selectedChoice));
     }
 }
 
-void QPrintPropertiesDialog::selectPdfPsPrinter(const QPrinter *p)
+void QPrintPropertiesDialog::revertAdvancedOptionsToSavedValues() const
 {
-    widget.treeView->setModel(0);
-    widget.pageSetup->selectPdfPsPrinter(p);
-    widget.tabs->setTabEnabled(1, false); // disable the advanced tab
+    for (QComboBox *choicesCb : m_advancedOptionsCombos) {
+        const int originallySelectedChoice = qvariant_cast<int>(choicesCb->property(ppdOriginallySelectedChoiceProperty));
+        const int newComboIndexToSelect = choicesCb->findData(originallySelectedChoice);
+        choicesCb->setCurrentIndex(newComboIndexToSelect);
+        // The currentIndexChanged lambda takes care of resetting the ppd option
+    }
+    widget.conflictsLabel->setVisible(anyPpdOptionConflict());
 }
 
-void QPrintPropertiesDialog::showEvent(QShowEvent* event)
+void QPrintPropertiesDialog::advancedOptionsUpdateSavedValues() const
 {
-    widget.treeView->resizeColumnToContents(0);
-    event->accept();
+    for (QComboBox *choicesCb : m_advancedOptionsCombos)
+        choicesCb->setProperty(ppdOriginallySelectedChoiceProperty, choicesCb->currentData());
+}
+
+bool QPrintPropertiesDialog::anyPpdOptionConflict() const
+{
+    // we need to execute both since besides returning true/false they update the warning icons
+    const bool pageSetupConflicts = widget.pageSetup->hasPpdConflict();
+    const bool advancedOptionConflicts = anyAdvancedOptionConflict();
+    return pageSetupConflicts || advancedOptionConflicts;
 }
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-void QPrintPropertiesDialog::addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const
+bool QPrintPropertiesDialog::anyAdvancedOptionConflict() const
 {
-    for (int i = 0; i < parent->childItems.count(); ++i) {
-        QOptionTreeItem *itm = parent->childItems.at(i);
-        if (itm->type == QOptionTreeItem::Option) {
-            const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
-            options << opt;
-            if (qstrcmp(opt->defchoice, opt->choices[itm->selected].choice) != 0) {
-                markedOptions << opt->keyword << opt->choices[itm->selected].choice;
-            }
+    const QIcon warning = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr);
+
+    bool anyConflicted = false;
+
+    for (const QComboBox *choicesCb : m_advancedOptionsCombos) {
+        const ppd_option_t *option = qvariant_cast<const ppd_option_t *>(choicesCb->property(ppdOptionProperty));
+        QLabel *warningLabel = qvariant_cast<QLabel *>(choicesCb->property(warningLabelProperty));
+        if (option->conflicted) {
+            anyConflicted = true;
+            const int pixmap_size = choicesCb->sizeHint().height() * .75;
+            warningLabel->setPixmap(warning.pixmap(pixmap_size, pixmap_size));
         } else {
-            addItemToOptions(itm, options, markedOptions);
+            warningLabel->setPixmap(QPixmap());
         }
     }
+
+    return anyConflicted;
 }
+
 #endif
 
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+
+    QPrintDialogPrivate
+
+    The lower half of the Print Dialog containing the Copies and Options
+    tabs that expands when the Options button is selected.
+
+*/
 QPrintDialogPrivate::QPrintDialogPrivate()
-    : top(0), bottom(0), buttons(0), collapseButton(0)
+    : top(nullptr), bottom(nullptr), buttons(nullptr), collapseButton(nullptr),
+      explicitDuplexMode(QPrint::DuplexAuto)
 {
+    _q_pdu_initResources();
 }
 
 QPrintDialogPrivate::~QPrintDialogPrivate()
@@ -383,13 +595,26 @@
 {
     Q_Q(QPrintDialog);
 
-    top = new QUnixPrintWidget(0, q);
+    top = new QUnixPrintWidget(q->printer(), q);
     bottom = new QWidget(q);
     options.setupUi(bottom);
     options.color->setIconSize(QSize(32, 32));
-    options.color->setIcon(QIcon(QLatin1String(":/trolltech/dialogs/qprintdialog/images/status-color.png")));
+    options.color->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-color.png"_L1));
     options.grayscale->setIconSize(QSize(32, 32));
-    options.grayscale->setIcon(QIcon(QLatin1String(":/trolltech/dialogs/qprintdialog/images/status-gray-scale.png")));
+    options.grayscale->setIcon(QIcon(":/qt-project.org/dialogs/qprintdialog/images/status-gray-scale.png"_L1));
+
+#if QT_CONFIG(cups)
+    // Add Page Set widget if CUPS is available
+    options.pageSetCombo->addItem(tr("All Pages"), QVariant::fromValue(QCUPSSupport::AllPages));
+    options.pageSetCombo->addItem(tr("Odd Pages"), QVariant::fromValue(QCUPSSupport::OddPages));
+    options.pageSetCombo->addItem(tr("Even Pages"), QVariant::fromValue(QCUPSSupport::EvenPages));
+#else
+    delete options.pagesRadioButton;
+    delete options.pagesLineEdit;
+    options.pagesRadioButton = nullptr;
+    options.pagesLineEdit = nullptr;
+#endif
+
     top->d->setOptionsPane(this);
 
     buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
@@ -402,57 +627,213 @@
     printButton->setDefault(true);
 
     QVBoxLayout *lay = new QVBoxLayout(q);
-    q->setLayout(lay);
     lay->addWidget(top);
     lay->addWidget(bottom);
     lay->addWidget(buttons);
 
-    QPrinter* p = q->printer();
-
-    applyPrinterProperties(p);
-
-#ifdef QT_NO_MESSAGEBOX
+#if !QT_CONFIG(messagebox)
     QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
 #else
     QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
 #endif
     QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
 
-    QObject::connect(options.reverse, SIGNAL(toggled(bool)),
-                     q, SLOT(_q_chbPrintLastFirstToggled(bool)));
+    QObject::connect(options.printSelection, SIGNAL(toggled(bool)),
+                     q, SLOT(_q_togglePageSetCombo(bool)));
+
+    QObject::connect(options.printCurrentPage, SIGNAL(toggled(bool)),
+                     q, SLOT(_q_togglePageSetCombo(bool)));
 
     QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog()));
+
+    QObject::connect(options.noDuplex, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexNone); });
+    QObject::connect(options.duplexLong, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexLongSide); });
+    QObject::connect(options.duplexShort, &QAbstractButton::clicked, q, [this] { setExplicitDuplexMode(QPrint::DuplexShortSide); });
+
+#if QT_CONFIG(cups)
+    QObject::connect(options.noDuplex, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.noDuplex); });
+    QObject::connect(options.duplexLong, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexLong); });
+    QObject::connect(options.duplexShort, &QAbstractButton::toggled, q, [this] { updatePpdDuplexOption(options.duplexShort); });
+#endif
+}
+
+// initialize printer options
+void QPrintDialogPrivate::selectPrinter(const QPrinter::OutputFormat outputFormat)
+{
+        Q_Q(QPrintDialog);
+        QPrinter *p = q->printer();
+        printerOutputFormat = outputFormat;
+
+        // printer supports duplex mode?
+        const auto supportedDuplexMode = top->d->m_currentPrintDevice.supportedDuplexModes();
+        options.duplexLong->setEnabled(supportedDuplexMode.contains(QPrint::DuplexLongSide));
+        options.duplexShort->setEnabled(supportedDuplexMode.contains(QPrint::DuplexShortSide));
+
+        if (p->colorMode() == QPrinter::Color)
+            options.color->setChecked(true);
+        else
+            options.grayscale->setChecked(true);
+
+        // duplex priorities to be as follows:
+        // 1) a user-selected duplex value in the dialog has highest priority
+        // 2) duplex value set in the QPrinter
+        QPrint::DuplexMode duplex;
+        if (explicitDuplexMode != QPrint::DuplexAuto && supportedDuplexMode.contains(explicitDuplexMode))
+            duplex = explicitDuplexMode;
+        else
+            duplex = static_cast<QPrint::DuplexMode>(p->duplex());
+        switch (duplex) {
+        case QPrint::DuplexNone:
+            options.noDuplex->setChecked(true); break;
+        case QPrint::DuplexLongSide:
+        case QPrint::DuplexAuto:
+            options.duplexLong->setChecked(true); break;
+        case QPrint::DuplexShortSide:
+            options.duplexShort->setChecked(true); break;
+        }
+        options.copies->setValue(p->copyCount());
+        options.collate->setChecked(p->collateCopies());
+        options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
+
+        if (outputFormat == QPrinter::PdfFormat || options.printSelection->isChecked()
+            || options.printCurrentPage->isChecked())
+
+            options.pageSetCombo->setEnabled(false);
+        else
+            options.pageSetCombo->setEnabled(true);
+
+#if QT_CONFIG(cups)
+        // Disable complex page ranges widget when printing to pdf
+        // It doesn't work since it relies on cups to do the heavy lifting and cups
+        // is not used when printing to PDF
+        options.pagesRadioButton->setEnabled(outputFormat != QPrinter::PdfFormat);
+
+        // Disable color options on main dialog if not printing to file, it will be handled by CUPS advanced dialog
+        options.colorMode->setVisible(outputFormat == QPrinter::PdfFormat);
+#endif
+}
+
+#if QT_CONFIG(cups)
+
+void QPrintDialogPrivate::updatePpdDuplexOption(QRadioButton *radio)
+{
+    const bool checked = radio->isChecked();
+    if (checked) {
+        if (radio == options.noDuplex) top->d->setPpdDuplex(QPrinter::DuplexNone);
+        else if (radio == options.duplexLong) top->d->setPpdDuplex(QPrinter::DuplexLongSide);
+        else if (radio == options.duplexShort) top->d->setPpdDuplex(QPrinter::DuplexShortSide);
+    }
+    const bool conflict = checked && top->d->m_duplexPpdOption && top->d->m_duplexPpdOption->conflicted;
+    radio->setIcon(conflict ? QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, nullptr) : QIcon());
+}
+
+#endif
+
+void QPrintDialogPrivate::setExplicitDuplexMode(const QPrint::DuplexMode duplexMode)
+{
+    explicitDuplexMode = duplexMode;
 }
 
-void QPrintDialogPrivate::applyPrinterProperties(QPrinter *p)
+void QPrintDialogPrivate::setupPrinter()
 {
-    if (p->colorMode() == QPrinter::Color)
-        options.color->setChecked(true);
-    else
-        options.grayscale->setChecked(true);
+    // First setup the requested OutputFormat, Printer and Page Size first
+    top->d->setupPrinter();
+
+    // Then setup Print Job options
+    Q_Q(QPrintDialog);
+    QPrinter* p = q->printer();
+
+    if (options.duplex->isEnabled()) {
+        if (options.noDuplex->isChecked())
+            p->setDuplex(QPrinter::DuplexNone);
+        else if (options.duplexLong->isChecked())
+            p->setDuplex(QPrinter::DuplexLongSide);
+        else
+            p->setDuplex(QPrinter::DuplexShortSide);
+    }
+
+#if QT_CONFIG(cups)
+    // When printing to a device the colorMode will be set by the advanced panel
+    if (p->outputFormat() == QPrinter::PdfFormat)
+#endif
+        p->setColorMode(options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale);
+
+    p->setPageOrder(options.reverse->isChecked() ? QPrinter::LastPageFirst : QPrinter::FirstPageFirst);
 
-    switch(p->duplex()) {
-    case QPrinter::DuplexNone:
-        options.noDuplex->setChecked(true); break;
-    case QPrinter::DuplexLongSide:
-    case QPrinter::DuplexAuto:
-        options.duplexLong->setChecked(true); break;
-    case QPrinter::DuplexShortSide:
-        options.duplexShort->setChecked(true); break;
+    // print range
+    if (options.printAll->isChecked()) {
+        p->setPrintRange(QPrinter::AllPages);
+        p->setPageRanges(QPageRanges());
+    } else if (options.printSelection->isChecked()) {
+        p->setPrintRange(QPrinter::Selection);
+        p->setPageRanges(QPageRanges());
+    } else if (options.printCurrentPage->isChecked()) {
+        p->setPrintRange(QPrinter::CurrentPage);
+        p->setPageRanges(QPageRanges());
+    } else if (options.printRange->isChecked()) {
+        if (q->testOption(QPrintDialog::PrintPageRange)) {
+            p->setPrintRange(QPrinter::PageRange);
+            p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
+        } else {
+            // This case happens when CUPS server-side page range is enabled
+            // Setting the range to the printer occurs below
+            p->setPrintRange(QPrinter::AllPages);
+            p->setPageRanges(QPageRanges());
+        }
+    }
+
+#if QT_CONFIG(cups)
+    if (options.pagesRadioButton->isChecked()) {
+        const QPageRanges ranges = QPageRanges::fromString(options.pagesLineEdit->text());
+        if (!ranges.isEmpty()) {
+            p->setPrintRange(QPrinter::PageRange);
+            p->setPageRanges(ranges);
+        }
+
+        // server-side page filtering
+        QCUPSSupport::setPageRange(p, ranges.toString());
     }
-    options.copies->setValue(p->copyCount());
-    options.collate->setChecked(p->collateCopies());
-    options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
-    top->d->applyPrinterProperties(p);
+
+    // page set
+    if (p->printRange() == QPrinter::AllPages || p->printRange() == QPrinter::PageRange) {
+        //If the application is selecting pages and the first page number is even then need to adjust the odd-even accordingly
+        QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(options.pageSetCombo->itemData(options.pageSetCombo->currentIndex()));
+        if (q->testOption(QPrintDialog::PrintPageRange)
+            && p->printRange() == QPrinter::PageRange
+            && (q->fromPage() % 2 == 0)) {
+
+            switch (pageSet) {
+            case QCUPSSupport::AllPages:
+                break;
+            case QCUPSSupport::OddPages:
+                QCUPSSupport::setPageSet(p, QCUPSSupport::EvenPages);
+                break;
+            case QCUPSSupport::EvenPages:
+                QCUPSSupport::setPageSet(p, QCUPSSupport::OddPages);
+                break;
+            }
+        } else if (pageSet != QCUPSSupport::AllPages) {
+            QCUPSSupport::setPageSet(p, pageSet);
+        }
+
+        // server-side page range, since we set the page range on the printer to 0-0/AllPages above,
+        // we need to take the values directly from the widget as q->fromPage() will return 0
+        if (!q->testOption(QPrintDialog::PrintPageRange) && options.printRange->isChecked())
+            QCUPSSupport::setPageRange(p, options.from->value(), qMax(options.from->value(), options.to->value()));
+    }
+#endif
+
+    // copies
+    p->setCopyCount(options.copies->value());
+    p->setCollateCopies(options.collate->isChecked());
 }
 
-void QPrintDialogPrivate::_q_chbPrintLastFirstToggled(bool checked)
+void QPrintDialogPrivate::_q_togglePageSetCombo(bool checked)
 {
-    Q_Q(QPrintDialog);
-    if (checked)
-        q->printer()->setPageOrder(QPrinter::LastPageFirst);
-    else
-        q->printer()->setPageOrder(QPrinter::FirstPageFirst);
+    if (printerOutputFormat == QPrinter::PdfFormat)
+        return;
+
+    options.pageSetCombo->setDisabled(checked);
 }
 
 void QPrintDialogPrivate::_q_collapseOrExpandDialog()
@@ -473,78 +854,65 @@
     }
 }
 
-#ifndef QT_NO_MESSAGEBOX
+#if QT_CONFIG(messagebox)
 void QPrintDialogPrivate::_q_checkFields()
 {
     Q_Q(QPrintDialog);
     if (top->d->checkFields())
         q->accept();
 }
-#endif // QT_NO_MESSAGEBOX
-
-void QPrintDialogPrivate::setupPrinter()
-{
-    Q_Q(QPrintDialog);
-    QPrinter* p = q->printer();
-
-    if (options.duplex->isEnabled()) {
-        if (options.noDuplex->isChecked())
-            p->setDuplex(QPrinter::DuplexNone);
-        else if (options.duplexLong->isChecked())
-            p->setDuplex(QPrinter::DuplexLongSide);
-        else
-            p->setDuplex(QPrinter::DuplexShortSide);
-    }
-
-    p->setColorMode( options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale );
+#endif // QT_CONFIG(messagebox)
 
-    // print range
-    if (options.printAll->isChecked()) {
-        p->setPrintRange(QPrinter::AllPages);
-        p->setFromTo(0,0);
-    } else if (options.printSelection->isChecked()) {
-        p->setPrintRange(QPrinter::Selection);
-        p->setFromTo(0,0);
-    } else if (options.printCurrentPage->isChecked()) {
-        p->setPrintRange(QPrinter::CurrentPage);
-        p->setFromTo(0,0);
-    } else if (options.printRange->isChecked()) {
-        p->setPrintRange(QPrinter::PageRange);
-        p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
-    }
-
-    // copies
-    p->setCopyCount(options.copies->value());
-    p->setCollateCopies(options.collate->isChecked());
-
-    top->d->setupPrinter();
-}
 
 void QPrintDialogPrivate::updateWidgets()
 {
     Q_Q(QPrintDialog);
-    options.gbPrintRange->setVisible(q->isOptionEnabled(QPrintDialog::PrintPageRange) ||
-                                     q->isOptionEnabled(QPrintDialog::PrintSelection) ||
-                                     q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
+    options.gbPrintRange->setVisible(q->testOption(QPrintDialog::PrintPageRange) ||
+                                     q->testOption(QPrintDialog::PrintSelection) ||
+                                     q->testOption(QPrintDialog::PrintCurrentPage));
+
+    options.printRange->setEnabled(q->testOption(QPrintDialog::PrintPageRange));
+    options.printSelection->setVisible(q->testOption(QPrintDialog::PrintSelection));
+    options.printCurrentPage->setVisible(q->testOption(QPrintDialog::PrintCurrentPage));
+    options.collate->setVisible(q->testOption(QPrintDialog::PrintCollateCopies));
 
-    options.printRange->setEnabled(q->isOptionEnabled(QPrintDialog::PrintPageRange));
-    options.printSelection->setVisible(q->isOptionEnabled(QPrintDialog::PrintSelection));
-    options.printCurrentPage->setVisible(q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
-    options.collate->setVisible(q->isOptionEnabled(QPrintDialog::PrintCollateCopies));
+#if QT_CONFIG(cups)
+    // Don't display Page Set if only Selection or Current Page are enabled
+    if (!q->testOption(QPrintDialog::PrintPageRange)
+        && (q->testOption(QPrintDialog::PrintSelection) || q->testOption(QPrintDialog::PrintCurrentPage))) {
+        options.pageSetCombo->setVisible(false);
+        options.pageSetLabel->setVisible(false);
+    } else {
+        options.pageSetCombo->setVisible(true);
+        options.pageSetLabel->setVisible(true);
+    }
+
+    if (!q->testOption(QPrintDialog::PrintPageRange)) {
+        // If we can do CUPS server side pages selection,
+        // display the page range widgets
+        options.gbPrintRange->setVisible(true);
+        options.printRange->setEnabled(true);
+    }
+#endif
 
     switch (q->printRange()) {
     case QPrintDialog::AllPages:
         options.printAll->setChecked(true);
+        options.pageSetCombo->setEnabled(true);
         break;
     case QPrintDialog::Selection:
         options.printSelection->setChecked(true);
+        options.pageSetCombo->setEnabled(false);
         break;
     case QPrintDialog::PageRange:
         options.printRange->setChecked(true);
+        options.pageSetCombo->setEnabled(true);
         break;
     case QPrintDialog::CurrentPage:
-        if (q->isOptionEnabled(QPrintDialog::PrintCurrentPage))
+        if (q->testOption(QPrintDialog::PrintCurrentPage)) {
             options.printCurrentPage->setChecked(true);
+            options.pageSetCombo->setEnabled(false);
+        }
         break;
     default:
         break;
@@ -564,9 +932,6 @@
 
 void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
 {
-    while(options.tabs->count() > 2)
-        delete options.tabs->widget(2);
-
     QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
     while(iter != tabWidgets.constEnd()) {
         QWidget *tab = *iter;
@@ -575,14 +940,16 @@
     }
 }
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-void QPrintDialogPrivate::selectPrinter(QCUPSSupport *cups)
-{
-    options.duplex->setEnabled(cups && cups->ppdOption("Duplex"));
-}
-#endif
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+/*
 
-////////////////////////////////////////////////////////////////////////////////
+    QPrintDialog
+
+    The main Print Dialog.
+
+*/
 
 QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
     : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
@@ -595,7 +962,7 @@
     Constructs a print dialog with the given \a parent.
 */
 QPrintDialog::QPrintDialog(QWidget *parent)
-    : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
+    : QAbstractPrintDialog(*(new QPrintDialogPrivate), nullptr, parent)
 {
     Q_D(QPrintDialog);
     d->init();
@@ -617,93 +984,78 @@
 
 int QPrintDialog::exec()
 {
-    return QDialog::exec();
+    return QAbstractPrintDialog::exec();
 }
 
 void QPrintDialog::accept()
 {
     Q_D(QPrintDialog);
+#if QT_CONFIG(cups) && QT_CONFIG(messagebox)
+    if (d->options.pagesRadioButton->isChecked() && printer()->pageRanges().isEmpty()) {
+        QMessageBox::critical(this, tr("Invalid Pages Definition"),
+                              tr("%1 does not follow the correct syntax. Please use ',' to separate "
+                              "ranges and pages, '-' to define ranges and make sure ranges do "
+                              "not intersect with each other.").arg(d->options.pagesLineEdit->text()),
+                              QMessageBox::Ok, QMessageBox::Ok);
+        return;
+    }
+    if (d->top->d->m_duplexPpdOption && d->top->d->m_duplexPpdOption->conflicted) {
+        const QMessageBox::StandardButton answer = QMessageBox::warning(this, tr("Duplex Settings Conflicts"),
+                                                                        tr("There are conflicts in duplex settings. Do you want to fix them?"),
+                                                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+        if (answer != QMessageBox::No)
+            return;
+    }
+#endif
     d->setupPrinter();
     QDialog::accept();
 }
 
-#ifdef QT3_SUPPORT
-QPrinter *QPrintDialog::printer() const
-{
-    Q_D(const QPrintDialog);
-    return d->printer;
-}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
-void QPrintDialog::setPrinter(QPrinter *printer, bool pickupSettings)
-{
-    if (!printer)
-        return;
+/*
 
-    Q_D(QPrintDialog);
-    d->printer = printer;
-
-    if (pickupSettings)
-        d->applyPrinterProperties(printer);
-}
+    QUnixPrintWidget && QUnixPrintWidgetPrivate
 
-void QPrintDialog::addButton(QPushButton *button)
-{
-    Q_D(QPrintDialog);
-    d->buttons->addButton(button, QDialogButtonBox::HelpRole);
-}
-#endif // QT3_SUPPORT
+    The upper half of the Print Dialog containing the Printer Selection widgets
+
+*/
 
 #if defined (Q_OS_UNIX)
 
 /*! \internal
 */
-QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p)
-    : parent(p), propertiesDialog(0), printer(0), optionsPane(0), filePrintersAdded(false)
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    , cups(0), cupsPrinterCount(0), cupsPrinters(0), cupsPPD(0)
+QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn)
+    : parent(p), propertiesDialog(nullptr), printer(prn),
+#if QT_CONFIG(cups)
+      m_duplexPpdOption(nullptr),
 #endif
+      optionsPane(nullptr), filePrintersAdded(false)
 {
-    q = 0;
+    q = nullptr;
     if (parent)
-        q = qobject_cast<QAbstractPrintDialog*> (parent->parent());
+        q = qobject_cast<QPrintDialog*> (parent->parent());
 
     widget.setupUi(parent);
 
     int currentPrinterIndex = 0;
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    cups = new QCUPSSupport;
-    if (QCUPSSupport::isAvailable()) {
-        cupsPPD = cups->currentPPD();
-        cupsPrinterCount = cups->availablePrintersCount();
-        cupsPrinters = cups->availablePrinters();
+    QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
+    if (ps) {
+        const QStringList printers = ps->availablePrintDeviceIds();
+        const QString defaultPrinter = ps->defaultPrintDeviceId();
 
-        for (int i = 0; i < cupsPrinterCount; ++i) {
-            QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
-            if (cupsPrinters[i].instance)
-                printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
+        widget.printers->addItems(printers);
 
-            widget.printers->addItem(printerName);
-            if (cupsPrinters[i].is_default)
-                widget.printers->setCurrentIndex(i);
-        }
-        // the model depends on valid ppd. so before enabling the
-        // properties button we make sure the ppd is in fact valid.
-        if (cupsPrinterCount && cups->currentPPD()) {
-            widget.properties->setEnabled(true);
-        }
-        currentPrinterIndex = cups->currentPrinterIndex();
-    } else {
-#endif
-        currentPrinterIndex = qt_getLprPrinters(lprPrinters);
-        // populating printer combo
-        QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin();
-        for(; i != lprPrinters.constEnd(); ++i)
-            widget.printers->addItem((*i).name);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+        const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;
+        const int idx = printers.indexOf(selectedPrinter);
+
+        if (idx >= 0)
+            currentPrinterIndex = idx;
     }
-#endif
+    widget.properties->setEnabled(true);
 
-#if !defined(QT_NO_FILESYSTEMMODEL) && !defined(QT_NO_COMPLETER)
+#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)
     QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
     fsm->setRootPath(QDir::homePath());
     widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
@@ -721,13 +1073,14 @@
 
 void QUnixPrintWidgetPrivate::updateWidget()
 {
-    const bool printToFile = q == 0 || q->isOptionEnabled(QPrintDialog::PrintToFile);
+    const bool printToFile = q == nullptr || q->testOption(QPrintDialog::PrintToFile);
     if (printToFile && !filePrintersAdded) {
         if (widget.printers->count())
             widget.printers->insertSeparator(widget.printers->count());
         widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
-        widget.printers->addItem(QPrintDialog::tr("Print to File (Postscript)"));
         filePrintersAdded = true;
+        if (widget.printers->count() == 1)
+            _q_printerChanged(0);
     }
     if (!printToFile && filePrintersAdded) {
         widget.printers->removeItem(widget.printers->count()-1);
@@ -740,8 +1093,6 @@
                                          || printer->printerName().isEmpty()))
     {
         if (printer->outputFormat() == QPrinter::PdfFormat)
-            widget.printers->setCurrentIndex(widget.printers->count() - 2);
-        else if (printer->outputFormat() == QPrinter::PostScriptFormat)
             widget.printers->setCurrentIndex(widget.printers->count() - 1);
         widget.filename->setEnabled(true);
         widget.lOutput->setEnabled(true);
@@ -751,14 +1102,12 @@
     widget.lOutput->setVisible(printToFile);
     widget.fileBrowser->setVisible(printToFile);
 
-    widget.properties->setVisible(q->isOptionEnabled(QAbstractPrintDialog::PrintShowPageSize));
+    if (q)
+        widget.properties->setVisible(q->testOption(QAbstractPrintDialog::PrintShowPageSize));
 }
 
 QUnixPrintWidgetPrivate::~QUnixPrintWidgetPrivate()
 {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    delete cups;
-#endif
 }
 
 void QUnixPrintWidgetPrivate::_q_printerChanged(int index)
@@ -769,68 +1118,53 @@
     widget.filename->setEnabled(false);
     widget.lOutput->setEnabled(false);
 
+    // Reset properties dialog when printer is changed
+    if (propertiesDialog){
+        delete propertiesDialog;
+        propertiesDialog = nullptr;
+    }
+
+#if QT_CONFIG(cups)
+    m_duplexPpdOption = nullptr;
+#endif
+
     if (filePrintersAdded) {
-        Q_ASSERT(index != printerCount - 3); // separator
-        if (index > printerCount - 3) { // PDF or postscript
-            bool pdfPrinter = (index == printerCount - 2);
+        Q_ASSERT(index != printerCount - 2); // separator
+        if (index == printerCount - 1) { // PDF
             widget.location->setText(QPrintDialog::tr("Local file"));
-            widget.type->setText(QPrintDialog::tr("Write %1 file").arg(pdfPrinter ? QString::fromLatin1("PDF")
-                                                                       : QString::fromLatin1("PostScript")));
+            widget.type->setText(QPrintDialog::tr("Write PDF file"));
             widget.properties->setEnabled(true);
             widget.filename->setEnabled(true);
             QString filename = widget.filename->text();
-            QString suffix = QFileInfo(filename).suffix();
-            if (pdfPrinter && suffix == QLatin1String("ps"))
-                filename = filename.replace(QLatin1String(".ps"), QLatin1String(".pdf"));
-            if (!pdfPrinter && suffix == QLatin1String("pdf"))
-                filename = filename.replace(QLatin1String(".pdf"), QLatin1String(".ps"));
             widget.filename->setText(filename);
             widget.lOutput->setEnabled(true);
-            if (propertiesDialog)
-                propertiesDialog->selectPdfPsPrinter(printer);
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+            printer->setOutputFormat(QPrinter::PdfFormat);
+            m_currentPrintDevice = QPrintDevice();
             if (optionsPane)
-                optionsPane->selectPrinter(0);
-#endif
+                optionsPane->selectPrinter(QPrinter::PdfFormat);
             return;
         }
     }
 
-    widget.location->setText(QString());
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-    if (QCUPSSupport::isAvailable()) {
-        cups->setCurrentPrinter(index);
+    if (printer) {
+        printer->setOutputFormat(QPrinter::NativeFormat);
 
-        const cups_option_t *opt = cups->printerOption(QString::fromLatin1("printer-location"));
-        QString location;
-        if (opt)
-            location = QString::fromLocal8Bit(opt->value);
-        widget.location->setText(location);
+        QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
+        if (ps)
+            m_currentPrintDevice = ps->createPrintDevice(widget.printers->itemText(index));
+        else
+            m_currentPrintDevice = QPrintDevice();
 
-        cupsPPD = cups->currentPPD();
-        // set printer type line
-        QString type;
-        if (cupsPPD)
-            type = QString::fromLocal8Bit(cupsPPD->manufacturer) + QLatin1String(" - ") + QString::fromLocal8Bit(cupsPPD->modelname);
-        widget.type->setText(type);
-        if (propertiesDialog)
-            propertiesDialog->selectPrinter();
-        if (optionsPane)
-            optionsPane->selectPrinter(cups);
-    } else {
+        printer->setPrinterName(m_currentPrintDevice.id());
+
+        widget.location->setText(m_currentPrintDevice.location());
+        widget.type->setText(m_currentPrintDevice.makeAndModel());
         if (optionsPane)
-            optionsPane->selectPrinter(0);
-#endif
-        if (lprPrinters.count() > 0) {
-            QString type = lprPrinters.at(index).name + QLatin1Char('@') + lprPrinters.at(index).host;
-            if (!lprPrinters.at(index).comment.isEmpty())
-            type += QLatin1String(", ") + lprPrinters.at(index).comment;
-            widget.type->setText(type);
-            if (propertiesDialog)
-                propertiesDialog->selectPrinter();
-        }
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+            optionsPane->selectPrinter(QPrinter::NativeFormat);
     }
+
+#if QT_CONFIG(cups)
+    m_duplexPpdOption = QCUPSSupport::findPpdOption("Duplex", &m_currentPrintDevice);
 #endif
 }
 
@@ -838,81 +1172,25 @@
 {
     optionsPane = pane;
     if (optionsPane)
-        _q_printerChanged(widget.printers->currentIndex());
+        optionsPane->selectPrinter(QPrinter::NativeFormat);
 }
 
 void QUnixPrintWidgetPrivate::_q_btnBrowseClicked()
 {
     QString filename = widget.filename->text();
-#ifndef QT_NO_FILEDIALOG
+#if QT_CONFIG(filedialog)
     filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
-                                            QString(), 0, QFileDialog::DontConfirmOverwrite);
+                                            QString(), nullptr, QFileDialog::DontConfirmOverwrite);
 #else
     filename.clear();
 #endif
     if (!filename.isEmpty()) {
         widget.filename->setText(filename);
-        if (filename.endsWith(QString::fromLatin1(".ps"), Qt::CaseInsensitive))
-            widget.printers->setCurrentIndex(widget.printers->count() - 1); // the postscript one
-        else if (filename.endsWith(QString::fromLatin1(".pdf"), Qt::CaseInsensitive))
-            widget.printers->setCurrentIndex(widget.printers->count() - 2); // the pdf one
-        else if (widget.printers->currentIndex() != widget.printers->count() - 1) // if ps is not selected, pdf is default
-            widget.printers->setCurrentIndex(widget.printers->count() - 2); // the pdf one
+        widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
     }
 }
 
-void QUnixPrintWidgetPrivate::applyPrinterProperties(QPrinter *p)
-{
-    if (p == 0)
-        return;
-    printer = p;
-    if (p->outputFileName().isEmpty()) {
-        QString home = QString::fromLocal8Bit(qgetenv("HOME").constData());
-        QString cur = QDir::currentPath();
-        if (home.at(home.length()-1) != QLatin1Char('/'))
-            home += QLatin1Char('/');
-        if (cur.at(cur.length()-1) != QLatin1Char('/'))
-            cur += QLatin1Char('/');
-        if (cur.left(home.length()) != home)
-            cur = home;
-#ifdef Q_WS_X11
-        if (p->docName().isEmpty()) {
-            if (p->outputFormat() == QPrinter::PostScriptFormat)
-                cur += QLatin1String("print.ps");
-            else
-                cur += QLatin1String("print.pdf");
-        } else {
-            QRegExp re(QString::fromLatin1("(.*)\\.\\S+"));
-            if (re.exactMatch(p->docName()))
-                cur += re.cap(1);
-            else
-                cur += p->docName();
-            if (p->outputFormat() == QPrinter::PostScriptFormat)
-                cur += QLatin1String(".ps");
-            else
-                cur += QLatin1String(".pdf");
-        }
-#endif
-        widget.filename->setText(cur);
-    }
-    else
-        widget.filename->setText( p->outputFileName() );
-    QString printer = p->printerName();
-    if (!printer.isEmpty()) {
-        for (int i = 0; i < widget.printers->count(); ++i) {
-            if (widget.printers->itemText(i) == printer) {
-                widget.printers->setCurrentIndex(i);
-                break;
-            }
-        }
-    }
-    // PDF and PS printers are not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
-
-    if (propertiesDialog)
-        propertiesDialog->applyPrinterProperties(p);
-}
-
-#ifndef QT_NO_MESSAGEBOX
+#if QT_CONFIG(messagebox)
 bool QUnixPrintWidgetPrivate::checkFields()
 {
     if (widget.filename->isEnabled()) {
@@ -943,74 +1221,81 @@
         }
     }
 
+#if QT_CONFIG(cups)
+    if (propertiesDialog) {
+        QCUPSSupport::PagesPerSheet pagesPerSheet = qvariant_cast<QCUPSSupport::PagesPerSheet>(propertiesDialog->widget.pageSetup->m_ui.pagesPerSheetCombo
+                                                                    ->currentData());
+
+        QCUPSSupport::PageSet pageSet = qvariant_cast<QCUPSSupport::PageSet>(optionsPane->options.pageSetCombo->currentData());
+
+
+        if (pagesPerSheet != QCUPSSupport::OnePagePerSheet
+            && pageSet != QCUPSSupport::AllPages) {
+            QMessageBox::warning(q, q->windowTitle(),
+                                 QPrintDialog::tr("Options 'Pages Per Sheet' and 'Page Set' cannot be used together.\nPlease turn one of those options off."));
+            return false;
+        }
+    }
+#endif
+
     // Every test passed. Accept the dialog.
     return true;
 }
-#endif // QT_NO_MESSAGEBOX
+#endif // QT_CONFIG(messagebox)
+
+void QUnixPrintWidgetPrivate::setupPrinterProperties()
+{
+    delete propertiesDialog;
+
+    QPrinter::OutputFormat outputFormat;
+    QString printerName;
+
+    if (q->testOption(QPrintDialog::PrintToFile)
+        && (widget.printers->currentIndex() == widget.printers->count() - 1)) {// PDF
+        outputFormat = QPrinter::PdfFormat;
+    } else {
+        outputFormat = QPrinter::NativeFormat;
+        printerName = widget.printers->currentText();
+    }
+
+    propertiesDialog = new QPrintPropertiesDialog(q->printer(), &m_currentPrintDevice, outputFormat, printerName, q);
+}
+
+#if QT_CONFIG(cups)
+void QUnixPrintWidgetPrivate::setPpdDuplex(QPrinter::DuplexMode mode)
+{
+    auto values = QStringList{} << QStringLiteral("Duplex");
+    if (mode == QPrinter::DuplexNone) values << QStringLiteral("None");
+    else if (mode == QPrinter::DuplexLongSide) values << QStringLiteral("DuplexNoTumble");
+    else if (mode == QPrinter::DuplexShortSide) values << QStringLiteral("DuplexTumble");
+
+    m_currentPrintDevice.setProperty(PDPK_PpdOption, values);
+}
+#endif
 
 void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked()
 {
-    if (!propertiesDialog) {
-        propertiesDialog = new QPrintPropertiesDialog(q);
-        propertiesDialog->setResult(QDialog::Rejected);
-    }
-
-    if (propertiesDialog->result() == QDialog::Rejected) {
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-        propertiesDialog->setCups(cups);
-#endif
-        propertiesDialog->applyPrinterProperties(q->printer());
-
-        if (q->isOptionEnabled(QPrintDialog::PrintToFile)
-            && (widget.printers->currentIndex() > widget.printers->count() - 3)) // PDF or postscript
-            propertiesDialog->selectPdfPsPrinter(q->printer());
-        else
-            propertiesDialog->selectPrinter();
-    }
+    if (!propertiesDialog)
+        setupPrinterProperties();
     propertiesDialog->exec();
-}
 
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-void QUnixPrintWidgetPrivate::setCupsProperties()
-{
-    if (cups && QCUPSSupport::isAvailable() && cups->pageSizes()) {
-        QPrintEngine *engine = printer->printEngine();
-        const ppd_option_t* pageSizes = cups->pageSizes();
-        QByteArray cupsPageSize;
-        for (int i = 0; i < pageSizes->num_choices; ++i) {
-            if (static_cast<int>(pageSizes->choices[i].marked) == 1)
-                cupsPageSize = pageSizes->choices[i].choice;
-        }
-        engine->setProperty(PPK_CupsStringPageSize, QString::fromLatin1(cupsPageSize));
-        engine->setProperty(PPK_CupsOptions, cups->options());
-
-        QRect pageRect = cups->pageRect(cupsPageSize);
-        engine->setProperty(PPK_CupsPageRect, pageRect);
-
-        QRect paperRect = cups->paperRect(cupsPageSize);
-        engine->setProperty(PPK_CupsPaperRect, paperRect);
-
-        for (int ps = 0; ps < QPrinter::NPaperSize; ++ps) {
-            QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
-            if (size.width == paperRect.width() && size.height == paperRect.height())
-                printer->setPaperSize(static_cast<QPrinter::PaperSize>(ps));
-        }
-    }
+#if QT_CONFIG(cups)
+    // update the warning icon on the duplex options if needed
+    optionsPane->updatePpdDuplexOption(optionsPane->options.noDuplex);
+    optionsPane->updatePpdDuplexOption(optionsPane->options.duplexLong);
+    optionsPane->updatePpdDuplexOption(optionsPane->options.duplexShort);
+#endif
 }
-#endif
 
 void QUnixPrintWidgetPrivate::setupPrinter()
 {
     const int printerCount = widget.printers->count();
     const int index = widget.printers->currentIndex();
 
-    if (filePrintersAdded && index > printerCount - 3) { // PDF or postscript
+    if (filePrintersAdded && index == printerCount - 1) { // PDF
         printer->setPrinterName(QString());
-        Q_ASSERT(index != printerCount - 3); // separator
-        if (index == printerCount - 2)
-            printer->setOutputFormat(QPrinter::PdfFormat);
-        else
-            printer->setOutputFormat(QPrinter::PostScriptFormat);
+        Q_ASSERT(index != printerCount - 2); // separator
+        printer->setOutputFormat(QPrinter::PdfFormat);
         QString path = widget.filename->text();
         if (QDir::isRelativePath(path))
             path = QDir::homePath() + QDir::separator() + path;
@@ -1021,21 +1306,55 @@
         printer->setOutputFileName(QString());
     }
 
-    if (propertiesDialog && propertiesDialog->result() == QDialog::Accepted)
-        propertiesDialog->setupPrinter();
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
     if (!propertiesDialog)
-        setCupsProperties();
-#endif
+        setupPrinterProperties();
+
+    propertiesDialog->setupPrinter();
 }
 
-
 /*! \internal
 */
 QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
-    : QWidget(parent), d(new QUnixPrintWidgetPrivate(this))
+    : QWidget(parent), d(new QUnixPrintWidgetPrivate(this, printer))
 {
-    d->applyPrinterProperties(printer);
+    if (printer == nullptr)
+        return;
+    if (printer->outputFileName().isEmpty()) {
+        QString home = QDir::homePath();
+        QString cur = QDir::currentPath();
+        if (!home.endsWith(u'/'))
+            home += u'/';
+        if (!cur.startsWith(home))
+            cur = home;
+        else if (!cur.endsWith(u'/'))
+            cur += u'/';
+        if (QGuiApplication::platformName() == QStringLiteral("xcb")) {
+            if (printer->docName().isEmpty()) {
+                cur += QStringLiteral("print.pdf");
+            } else {
+#if QT_CONFIG(regularexpression)
+                const QRegularExpression re(QStringLiteral("(.*)\\.\\S+"));
+                auto match = re.match(printer->docName());
+                if (match.hasMatch())
+                    cur += match.captured(1);
+                else
+#endif
+                    cur += printer->docName();
+                cur += QStringLiteral(".pdf");
+            }
+        } // xcb
+
+        d->widget.filename->setText(cur);
+    }
+    else
+        d->widget.filename->setText(printer->outputFileName());
+    const QString printerName = printer->printerName();
+    if (!printerName.isEmpty()) {
+        const int i = d->widget.printers->findText(printerName);
+        if (i >= 0)
+            d->widget.printers->setCurrentIndex(i);
+    }
+    // PDF printer not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
 }
 
 /*! \internal
@@ -1054,255 +1373,15 @@
     d->setupPrinter();
 }
 
-#endif
+#if QT_CONFIG(cups)
 
 ////////////////////////////////////////////////////////////////////////////////
-#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
-
-QPPDOptionsModel::QPPDOptionsModel(QCUPSSupport *c, QObject *parent)
-    : QAbstractItemModel(parent), rootItem(0), cups(c), ppd(c->currentPPD())
-{
-    parseItems();
-}
-
-QPPDOptionsModel::~QPPDOptionsModel()
-{
-}
-
-int QPPDOptionsModel::columnCount(const QModelIndex&) const
-{
-    return 2;
-}
-
-int QPPDOptionsModel::rowCount(const QModelIndex& parent) const
-{
-    QOptionTreeItem* itm;
-    if (!parent.isValid())
-        itm = rootItem;
-    else
-        itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
-
-    if (itm->type == QOptionTreeItem::Option)
-        return 0;
-
-    return itm->childItems.count();
-}
-
-QVariant QPPDOptionsModel::data(const QModelIndex& index, int role) const
-{
-    switch(role) {
-        case Qt::FontRole: {
-            QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
-            if (itm && itm->type == QOptionTreeItem::Group){
-                QFont font = QApplication::font();
-                font.setBold(true);
-                return QVariant(font);
-            }
-            return QVariant();
-        }
-        break;
-
-        case Qt::DisplayRole: {
-            QOptionTreeItem* itm;
-            if (!index.isValid())
-                itm = rootItem;
-            else
-                itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
-
-            if (index.column() == 0)
-                return cups->unicodeString(itm->description);
-            else if (itm->type == QOptionTreeItem::Option && itm->selected > -1)
-                return cups->unicodeString(itm->selDescription);
-            else
-                return QVariant();
-        }
-        break;
-
-        default:
-            return QVariant();
-    }
-    if (role != Qt::DisplayRole)
-        return QVariant();
-}
-
-QModelIndex QPPDOptionsModel::index(int row, int column, const QModelIndex& parent) const
-{
-    QOptionTreeItem* itm;
-    if (!parent.isValid())
-        itm = rootItem;
-    else
-        itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
-
-    return createIndex(row, column, itm->childItems.at(row));
-}
-
-
-QModelIndex QPPDOptionsModel::parent(const QModelIndex& index) const
-{
-    if (!index.isValid())
-        return QModelIndex();
-
-    QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
-
-    if (itm->parentItem && itm->parentItem != rootItem)
-        return createIndex(itm->parentItem->index, 0, itm->parentItem);
-    else
-        return QModelIndex();
-}
-
-Qt::ItemFlags QPPDOptionsModel::flags(const QModelIndex& index) const
-{
-    if (!index.isValid() || reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Group)
-        return Qt::ItemIsEnabled;
-
-    if (index.column() == 1)
-        return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
-
-    return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
-}
-
-void QPPDOptionsModel::parseItems()
-{
-    emit layoutAboutToBeChanged();
-    ppd = cups->currentPPD();
-    delete rootItem;
-    rootItem = new QOptionTreeItem(QOptionTreeItem::Root, 0, ppd, "Root Item", 0);
-    parseGroups(rootItem);
-    emit layoutChanged();
-}
-
-void QPPDOptionsModel::parseGroups(QOptionTreeItem* parent)
-{
-    if (parent->type == QOptionTreeItem::Root) {
-
-        const ppd_file_t* ppdFile = reinterpret_cast<const ppd_file_t*>(parent->ptr);
-
-        if (ppdFile) {
-            for (int i = 0; i < ppdFile->num_groups; ++i) {
-                QOptionTreeItem* group = new QOptionTreeItem(QOptionTreeItem::Group, i, &ppdFile->groups[i], ppdFile->groups[i].text, parent);
-                parent->childItems.append(group);
-                parseGroups(group); // parse possible subgroups
-                parseOptions(group); // parse options
-            }
-        }
-    } else if (parent->type == QOptionTreeItem::Group) {
-
-        const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
-
-        if (group) {
-            for (int i = 0; i < group->num_subgroups; ++i) {
-                QOptionTreeItem* subgroup = new QOptionTreeItem(QOptionTreeItem::Group, i, &group->subgroups[i], group->subgroups[i].text, parent);
-                parent->childItems.append(subgroup);
-                parseGroups(subgroup); // parse possible subgroups
-                parseOptions(subgroup); // parse options
-            }
-        }
-    }
-}
-
-void QPPDOptionsModel::parseOptions(QOptionTreeItem* parent)
-{
-    const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
-    for (int i = 0; i < group->num_options; ++i) {
-        QOptionTreeItem* opt = new QOptionTreeItem(QOptionTreeItem::Option, i, &group->options[i], group->options[i].text, parent);
-        parent->childItems.append(opt);
-        parseChoices(opt);
-    }
-}
-
-void QPPDOptionsModel::parseChoices(QOptionTreeItem* parent)
-{
-    const ppd_option_t* option = reinterpret_cast<const ppd_option_t*>(parent->ptr);
-    bool marked = false;
-    for (int i = 0; i < option->num_choices; ++i) {
-        QOptionTreeItem* choice = new QOptionTreeItem(QOptionTreeItem::Choice, i, &option->choices[i], option->choices[i].text, parent);
-        if (static_cast<int>(option->choices[i].marked) == 1) {
-            parent->selected = i;
-            parent->selDescription = option->choices[i].text;
-            marked = true;
-        } else if (!marked && qstrcmp(option->choices[i].choice, option->defchoice) == 0) {
-            parent->selected = i;
-            parent->selDescription = option->choices[i].text;
-        }
-        parent->childItems.append(choice);
-    }
-}
-
-QVariant QPPDOptionsModel::headerData(int section, Qt::Orientation, int role) const
-{
-    if (role != Qt::DisplayRole)
-        return QVariant();
-
-    switch(section){
-        case 0:
-            return QVariant(QApplication::translate("QPPDOptionsModel", "Name"));
-        case 1:
-            return QVariant(QApplication::translate("QPPDOptionsModel", "Value"));
-        default:
-            return QVariant();
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
-QWidget* QPPDOptionsEditor::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
-{
-    if (index.column() == 1 && reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Option)
-        return new QComboBox(parent);
-    else
-        return 0;
-}
-
-void QPPDOptionsEditor::setEditorData(QWidget* editor, const QModelIndex& index) const
-{
-    if (index.column() != 1)
-        return;
-
-    QComboBox* cb = static_cast<QComboBox*>(editor);
-    QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
-
-    if (itm->selected == -1)
-        cb->addItem(QString());
-
-    for (int i = 0; i < itm->childItems.count(); ++i)
-        cb->addItem(QString::fromLocal8Bit(itm->childItems.at(i)->description));
-
-    if (itm->selected > -1)
-        cb->setCurrentIndex(itm->selected);
-
-    connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(cbChanged(int)));
-}
-
-void QPPDOptionsEditor::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
-{
-    QComboBox* cb = static_cast<QComboBox*>(editor);
-    QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
-
-    if (itm->selected == cb->currentIndex())
-        return;
-
-    const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
-    QPPDOptionsModel* m = static_cast<QPPDOptionsModel*>(model);
-
-    if (m->cups->markOption(opt->keyword, opt->choices[cb->currentIndex()].choice) == 0) {
-        itm->selected = cb->currentIndex();
-        itm->selDescription = reinterpret_cast<const ppd_option_t*>(itm->ptr)->choices[itm->selected].text;
-    }
-}
-
-void QPPDOptionsEditor::cbChanged(int)
-{
-/*
-    emit commitData(static_cast<QWidget*>(sender()));
-*/
-}
-
-#endif
+#endif // QT_CONFIG(cups)
+#endif // defined (Q_OS_UNIX)
 
 QT_END_NAMESPACE
 
 #include "moc_qprintdialog.cpp"
 #include "qprintdialog_unix.moc"
-#include "qrc_qprintdialog.cpp"
-
-#endif // QT_NO_PRINTDIALOG
--- a/libgui/languages/build_ts/octave-qt/qprintdialog_win.cpp	Mon Dec 04 20:38:36 2023 -0800
+++ b/libgui/languages/build_ts/octave-qt/qprintdialog_win.cpp	Mon Dec 04 19:55:32 2023 +0100
@@ -1,45 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
 
-#ifndef QT_NO_PRINTDIALOG
+#include <QtPrintSupport/qtprintsupportglobal.h>
 
 #include "qprintdialog.h"
 
@@ -48,43 +10,39 @@
 #include <qmessagebox.h>
 #include <private/qapplication_p.h>
 
-#include <private/qabstractprintdialog_p.h>
+#include "qabstractprintdialog_p.h"
 #include <private/qprintengine_win_p.h>
-#include <private/qprinter_p.h>
+#include "../kernel/qprinter_p.h"
 
 #if !defined(PD_NOCURRENTPAGE)
 #define PD_NOCURRENTPAGE    0x00800000
-#define PD_RESULT_PRINT	1
-#define PD_RESULT_APPLY	2
+#define PD_RESULT_PRINT 1
+#define PD_RESULT_APPLY 2
 #define START_PAGE_GENERAL  0XFFFFFFFF
 #endif
 
 QT_BEGIN_NAMESPACE
 
-extern void qt_win_eatMouseMove();
+using namespace Qt::StringLiterals;
+
+//extern void qt_win_eatMouseMove();
 
 class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
 {
     Q_DECLARE_PUBLIC(QPrintDialog)
 public:
     QPrintDialogPrivate()
-        : ep(0)
+        : engine(0), ep(0)
     {
     }
 
-    inline void _q_printToFileChanged(int) {}
-    inline void _q_rbPrintRangeToggled(bool) {}
-    inline void _q_printerChanged(int) {}
-    inline void _q_chbPrintLastFirstToggled(bool) {}
-    inline void _q_paperSizeChanged(int) {}
-    inline void _q_btnBrowseClicked() {}
-    inline void _q_btnPropertiesClicked() {}
     int openWindowsPrintDialogModally();
 
+    QWin32PrintEngine *engine;
     QWin32PrintEnginePrivate *ep;
 };
 
-static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWidget *parent,
+static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWindow *parentWindow,
                                     QPrintDialog *pdlg,
                                     QPrintDialogPrivate *d, HGLOBAL *tempDevNames)
 {
@@ -106,21 +64,21 @@
     pd->Flags = PD_RETURNDC;
     pd->Flags |= PD_USEDEVMODECOPIESANDCOLLATE;
 
-    if (!pdlg->isOptionEnabled(QPrintDialog::PrintSelection))
+    if (!pdlg->testOption(QPrintDialog::PrintSelection))
         pd->Flags |= PD_NOSELECTION;
-    if (pdlg->isOptionEnabled(QPrintDialog::PrintPageRange)) {
+    if (pdlg->testOption(QPrintDialog::PrintPageRange)) {
         pd->nMinPage = pdlg->minPage();
         pd->nMaxPage = pdlg->maxPage();
     }
 
-    if(!pdlg->isOptionEnabled(QPrintDialog::PrintToFile))
+    if (!pdlg->testOption(QPrintDialog::PrintToFile))
         pd->Flags |= PD_DISABLEPRINTTOFILE;
 
-    if (pdlg->isOptionEnabled(QPrintDialog::PrintSelection) && pdlg->printRange() == QPrintDialog::Selection)
+    if (pdlg->testOption(QPrintDialog::PrintSelection) && pdlg->printRange() == QPrintDialog::Selection)
         pd->Flags |= PD_SELECTION;
-    else if (pdlg->isOptionEnabled(QPrintDialog::PrintPageRange) && pdlg->printRange() == QPrintDialog::PageRange)
+    else if (pdlg->testOption(QPrintDialog::PrintPageRange) && pdlg->printRange() == QPrintDialog::PageRange)
         pd->Flags |= PD_PAGENUMS;
-    else if (pdlg->isOptionEnabled(QPrintDialog::PrintCurrentPage) && pdlg->printRange() == QPrintDialog::CurrentPage)
+    else if (pdlg->testOption(QPrintDialog::PrintCurrentPage) && pdlg->printRange() == QPrintDialog::CurrentPage)
         pd->Flags |= PD_CURRENTPAGE;
     else
         pd->Flags |= PD_ALLPAGES;
@@ -131,7 +89,7 @@
         pd->Flags |= PD_NOPAGENUMS;
 
     // Disable Current Page option if not required as default is Enabled
-    if (!pdlg->isOptionEnabled(QPrintDialog::PrintCurrentPage))
+    if (!pdlg->testOption(QPrintDialog::PrintCurrentPage))
         pd->Flags |= PD_NOCURRENTPAGE;
 
     // Default to showing the General tab first
@@ -143,38 +101,40 @@
 
     if (d->ep->printToFile)
         pd->Flags |= PD_PRINTTOFILE;
-    Q_ASSERT(parent);
-    pd->hwndOwner = parent->window()->winId();
+
+    WId wId = parentWindow ? parentWindow->winId() : 0;
+    //QTBUG-118899 PrintDlg needs valid window handle in hwndOwner
+    //So in case there is no valid handle in the application,
+    //use the desktop as valid handle.
+    pd->hwndOwner = wId != 0 ? HWND(wId) : GetDesktopWindow();
     pd->lpPageRanges[0].nFromPage = qMax(pdlg->fromPage(), pdlg->minPage());
     pd->lpPageRanges[0].nToPage   = (pdlg->toPage() > 0) ? qMin(pdlg->toPage(), pdlg->maxPage()) : 1;
-    pd->nCopies = d->ep->num_copies;
+    pd->nCopies = d->printer->copyCount();
 }
 
 static void qt_win_read_back_PRINTDLGEX(PRINTDLGEX *pd, QPrintDialog *pdlg, QPrintDialogPrivate *d)
 {
     if (pd->Flags & PD_SELECTION) {
         pdlg->setPrintRange(QPrintDialog::Selection);
-        pdlg->setFromTo(0, 0);
+        pdlg->printer()->setPageRanges(QPageRanges());
     } else if (pd->Flags & PD_PAGENUMS) {
         pdlg->setPrintRange(QPrintDialog::PageRange);
         pdlg->setFromTo(pd->lpPageRanges[0].nFromPage, pd->lpPageRanges[0].nToPage);
     } else if (pd->Flags & PD_CURRENTPAGE) {
         pdlg->setPrintRange(QPrintDialog::CurrentPage);
-        pdlg->setFromTo(0, 0);
+       pdlg->printer()->setPageRanges(QPageRanges());
     } else { // PD_ALLPAGES
         pdlg->setPrintRange(QPrintDialog::AllPages);
-        pdlg->setFromTo(0, 0);
+        pdlg->printer()->setPageRanges(QPageRanges());
     }
 
     d->ep->printToFile = (pd->Flags & PD_PRINTTOFILE) != 0;
 
-    d->ep->readDevnames(pd->hDevNames);
-    d->ep->readDevmode(pd->hDevMode);
-    d->ep->updateCustomPaperSize();
+    d->engine->setGlobalDevMode(pd->hDevNames, pd->hDevMode);
 
     if (d->ep->printToFile && d->ep->fileName.isEmpty())
-        d->ep->fileName = d->ep->port;
-    else if (!d->ep->printToFile && d->ep->fileName == QLatin1String("FILE:"))
+        d->ep->fileName = "FILE:"_L1;
+    else if (!d->ep->printToFile && d->ep->fileName == "FILE:"_L1)
         d->ep->fileName.clear();
 }
 
@@ -193,7 +153,9 @@
     Q_D(QPrintDialog);
     if (!warnIfNotNative(d->printer))
         return;
-    d->ep = static_cast<QWin32PrintEngine *>(d->printer->paintEngine())->d_func();
+    d->engine = static_cast<QWin32PrintEngine *>(d->printer->printEngine());
+    d->ep = static_cast<QWin32PrintEngine *>(d->printer->printEngine())->d_func();
+    setAttribute(Qt::WA_DontShowOnScreen);
 }
 
 QPrintDialog::QPrintDialog(QWidget *parent)
@@ -202,7 +164,9 @@
     Q_D(QPrintDialog);
     if (!warnIfNotNative(d->printer))
         return;
-    d->ep = static_cast<QWin32PrintEngine *>(d->printer->paintEngine())->d_func();
+    d->engine = static_cast<QWin32PrintEngine *>(d->printer->printEngine());
+    d->ep = static_cast<QWin32PrintEngine *>(d->printer->printEngine())->d_func();
+    setAttribute(Qt::WA_DontShowOnScreen);
 }
 
 QPrintDialog::~QPrintDialog()
@@ -221,22 +185,24 @@
 int QPrintDialogPrivate::openWindowsPrintDialogModally()
 {
     Q_Q(QPrintDialog);
-    QWidget *parent = q->parentWidget();
-    if (parent)
-        parent = parent->window();
-    else
-        parent = QApplication::activeWindow();
+    QWindow *parentWindow = q->windowHandle() ? q->windowHandle()->transientParent() : nullptr;
+    if (!parentWindow) {
+        QWidget *parent = q->parentWidget();
+        if (parent)
+            parent = parent->window();
+        else
+            parent = QApplication::activeWindow();
 
-    // If there is no window, fall back to the print dialog itself
-    if (parent == 0)
-        parent = q;
+        // If there is no window, fall back to the print dialog itself
+        if (!parent)
+            parent = q;
 
-    QWidget modal_widget;
-    modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
-    modal_widget.setParent(parent, Qt::Window);
-    QApplicationPrivate::enterModal(&modal_widget);
+        parentWindow = parent->windowHandle();
+    }
 
-    HGLOBAL *tempDevNames = ep->createDevNames();
+    q->QDialog::setVisible(true);
+
+    HGLOBAL *tempDevNames = engine->createGlobalDevNames();
 
     bool done;
     bool result;
@@ -247,7 +213,7 @@
     memset(&pd, 0, sizeof(PRINTDLGEX));
     pd.lStructSize = sizeof(PRINTDLGEX);
     pd.lpPageRanges = &pageRange;
-    qt_win_setup_PRINTDLGEX(&pd, parent, q, this, tempDevNames);
+    qt_win_setup_PRINTDLGEX(&pd, parentWindow, q, this, tempDevNames);
 
     do {
         done = true;
@@ -269,15 +235,15 @@
         }
 
         if (!done) {
-            QMessageBox::warning(0, QPrintDialog::tr("Print"),
-                                 QPrintDialog::tr("The 'From' value cannot be greater than the 'To' value."),
-                                 QPrintDialog::tr("OK"));
+            QMessageBox::warning(nullptr,
+                                 QPrintDialog::tr("Print"),
+                                 QPrintDialog::tr("The 'From' value cannot be greater than the 'To' value."));
         }
     } while (!done);
 
-    QApplicationPrivate::leaveModal(&modal_widget);
+    q->QDialog::setVisible(false);
 
-    qt_win_eatMouseMove();
+//    qt_win_eatMouseMove();
 
     // write values back...
     if (result && (pd.dwResultAction == PD_RESULT_PRINT
@@ -285,7 +251,7 @@
     {
         qt_win_read_back_PRINTDLGEX(&pd, q, this);
         // update printer validity
-        printer->d_func()->validPrinter = !ep->name.isEmpty();
+        printer->d_func()->validPrinter = !printer->printerName().isEmpty();
     }
 
     // Cleanup...
@@ -307,12 +273,10 @@
     if (!warnIfNotNative(d->printer))
         return;
 
-    ()d->openWindowsPrintDialogModally();
+    (void)d->openWindowsPrintDialogModally();
     return;
 }
 
 QT_END_NAMESPACE
 
 #include "moc_qprintdialog.cpp"
-
-#endif // QT_NO_PRINTDIALOG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/languages/build_ts/update_external_sources	Mon Dec 04 19:55:32 2023 +0100
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+# This scripts updates the external source files from Qt and QScintilla
+# in the subdirectories "octave-qt" and "octave-qsci". These files are
+# later used by the script "update_ts_files" for languages for which
+# without translations provided by Qt and/or QScintilla in order to get
+# the strings to translate
+#
+# Syntax
+# 
+#     update_external_sources  path-to-qt-src  path-to-qsci-src
+#
+# Parameter
+#
+#     path-to-qt-src:   Relative or absolute path to the new Qt
+#                       sources
+#     path-to-qsci-src: Relative or absolute path to the new
+#                       QScintilla sources
+#
+
+if [ $# -ne 2 ]
+then
+  echo
+  echo "Syntax"
+  echo
+  echo "     update_external_sources  path-to-qt-src  path-to-qsci-src"
+  echo
+  echo "Parameter"
+  echo
+  echo "     path-to-qt-src:   Relative or absolute path to the new Qt"
+  echo "                       sources"
+  echo "     path-to-qsci-src: Relative or absolute path to the new"
+  echo "                       QScintilla sources"
+  echo
+  exit
+fi
+
+QT=$1
+QSCI=$2
+
+OCTQT="octave-qt"
+OCTQSCI="octave-qsci"
+
+if [ ! -d $QT ] 
+then
+    echo "Directory $QT does not exist." 
+    exit 1
+fi
+if [ ! -d $QSCI ] 
+then
+    echo "Directory $QSCI does not exist." 
+    exit 1
+fi
+
+echo
+echo "$OCTQT"
+echo
+
+for file in $(find $OCTQT -maxdepth 1 -not -type d)
+do
+    bfile=`basename $file`
+    find $QT -type f -name $bfile -exec cp -v -u "{}" $OCTQT \;
+done
+
+echo
+echo "$OCTQSCI"
+echo
+
+for file in $(find $OCTQSCI -maxdepth 1 -not -type d)
+do
+    bfile=`basename $file`  
+    find $QSCI -type f -name $bfile -exec cp -v -u "{}" $OCTQSCI \;
+done
+
+echo
+echo "$OCTQSCI/Qsci"
+echo
+
+for file in $(find $OCTQSCI/Qsci -maxdepth 1 -not -type d)
+do
+    bfile=`basename $file`
+    find $QSCI -type f -name $bfile -exec cp -v -u "{}" $OCTQSCI/Qsci \;
+done
+
+echo
+echo done
+echo