Merge remote-tracking branch 'origin/5.15' into dev

Conflicts:
	tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp

Change-Id: I6b82507bf9a80a374c40393e72f4843f1557de89
This commit is contained in:
Qt Forward Merge Bot 2019-12-11 01:00:10 +01:00 committed by Edward Welbourne
commit a4a7c1bcf7
101 changed files with 1232 additions and 505 deletions

View File

@ -29,16 +29,18 @@
\example widgets/shapedclock \example widgets/shapedclock
\title Shaped Clock Example \title Shaped Clock Example
\ingroup examples-widgets \ingroup examples-widgets
\brief The Shaped Clock example shows how to apply a widget mask to a top-level \brief The Shaped Clock example shows how to apply a translucent background
widget to produce a shaped window. and a widget mask to a top-level widget to produce a shaped window.
\borderedimage shapedclock-example.png \borderedimage shapedclock-example.png
Widget masks are used to customize the shapes of top-level widgets by restricting Widget masks are used to customize the shapes of top-level widgets by
the available area for painting. On some window systems, setting certain window flags restricting the area available for painting and mouse input. Using a
will cause the window decoration (title bar, window frame, buttons) to be disabled, translucent background facilitates partially transparent windows and smooth
allowing specially-shaped windows to be created. In this example, we use this feature edges. On most window systems, setting certain window flags will cause the
to create a circular window containing an analog clock. window decoration (title bar, window frame, buttons) to be disabled,
allowing specially-shaped windows to be created. In this example, we use
this feature to create a circular window containing an analog clock.
Since this example's window does not provide a \uicontrol File menu or a close Since this example's window does not provide a \uicontrol File menu or a close
button, we provide a context menu with an \uicontrol Exit entry so that the example button, we provide a context menu with an \uicontrol Exit entry so that the example
@ -52,8 +54,10 @@
\snippet widgets/shapedclock/shapedclock.h 0 \snippet widgets/shapedclock/shapedclock.h 0
The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as that found The \l{QWidget::paintEvent()}{paintEvent()} implementation is the same as
in the \c AnalogClock class. We implement \l{QWidget::sizeHint()}{sizeHint()} that found in the \c AnalogClock class, with one important exception: we
now must also draw background (the clock face) ourselves, since the widget
background is just transparent. We implement \l{QWidget::sizeHint()}{sizeHint()}
so that we don't have to resize the widget explicitly. We also provide an event so that we don't have to resize the widget explicitly. We also provide an event
handler for resize events. This allows us to update the mask if the clock is resized. handler for resize events. This allows us to update the mask if the clock is resized.
@ -70,9 +74,11 @@
\snippet widgets/shapedclock/shapedclock.cpp 0 \snippet widgets/shapedclock/shapedclock.cpp 0
We inform the window manager that the widget is not to be decorated with a window We request a transparent window by setting the Qt::WA_TranslucentBackground
frame by setting the Qt::FramelessWindowHint flag on the widget. As a result, we need widget attribute. We inform the window manager that the widget is not to be
to provide a way for the user to move the clock around the screen. decorated with a window frame by setting the Qt::FramelessWindowHint flag
on the widget. As a result, we need to provide a way for the user to move
the clock around the screen.
Mouse button events are delivered to the \c mousePressEvent() handler: Mouse button events are delivered to the \c mousePressEvent() handler:
@ -94,14 +100,20 @@
widget is moved to the point given by subtracting the \c dragPosition from the current widget is moved to the point given by subtracting the \c dragPosition from the current
cursor position in global coordinates. If we drag the widget, we also accept the event. cursor position in global coordinates. If we drag the widget, we also accept the event.
The \c paintEvent() function is given for completeness. See the The \c paintEvent() function is mainly the same as described in the
\l{Analog Clock Example}{Analog Clock} example for a description of the process used \l{Analog Clock Example}{Analog Clock} example. The one addition is that we
to render the clock. use QPainter::drawEllipse() to draw a round clock face with the current
palette's default background color. We make the clock face a bit smaller
than the widget mask, so that the anti-aliased, semi-transparent pixels on
the edge are not clipped away by the widget mask. This gives the shaped
window smooth edges on the screen.
\snippet widgets/shapedclock/shapedclock.cpp 3 \snippet widgets/shapedclock/shapedclock.cpp 3
In the \c resizeEvent() handler, we re-use some of the code from the \c paintEvent() In the \c resizeEvent() handler, we re-use some of the code from the \c
to determine the region of the widget that is visible to the user: paintEvent() to determine the region of the widget that is visible to the
user. This tells the system the area where mouse clicks should go to us,
and not to whatever window is behind us:
\snippet widgets/shapedclock/shapedclock.cpp 4 \snippet widgets/shapedclock/shapedclock.cpp 4
@ -121,6 +133,12 @@
\section1 Notes on Widget Masks \section1 Notes on Widget Masks
Widget masks are used to hint to the window system that the application
does not want mouse events for areas outside the mask. On most systems,
they also result in coarse visual clipping. To get smooth window edges, one
should use translucent background and anti-aliased painting, as shown in
this example.
Since QRegion allows arbitrarily complex regions to be created, widget masks can be Since QRegion allows arbitrarily complex regions to be created, widget masks can be
made to suit the most unconventionally-shaped windows, and even allow widgets to be made to suit the most unconventionally-shaped windows, and even allow widgets to be
displayed with holes in them. displayed with holes in them.

View File

@ -61,6 +61,7 @@
ShapedClock::ShapedClock(QWidget *parent) ShapedClock::ShapedClock(QWidget *parent)
: QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint) : QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint)
{ {
setAttribute(Qt::WA_TranslucentBackground);
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, QOverload<>::of(&ShapedClock::update)); connect(timer, &QTimer::timeout, this, QOverload<>::of(&ShapedClock::update));
timer->start(1000); timer->start(1000);
@ -122,6 +123,10 @@ void ShapedClock::paintEvent(QPaintEvent *)
painter.translate(width() / 2, height() / 2); painter.translate(width() / 2, height() / 2);
painter.scale(side / 200.0, side / 200.0); painter.scale(side / 200.0, side / 200.0);
painter.setPen(Qt::NoPen);
painter.setBrush(palette().window());
painter.drawEllipse(QPoint(0, 0), 98, 98);
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
painter.setBrush(hourColor); painter.setBrush(hourColor);
@ -168,6 +173,6 @@ void ShapedClock::resizeEvent(QResizeEvent * /* event */)
//! [5] //! [5]
QSize ShapedClock::sizeHint() const QSize ShapedClock::sizeHint() const
{ {
return QSize(100, 100); return QSize(200, 200);
} }
//! [5] //! [5]

View File

@ -71,7 +71,7 @@ contains(TEMPLATE, .*app) {
# replacing the app name placeholder with the actual app name. # replacing the app name placeholder with the actual app name.
apphtml.name = application main html file apphtml.name = application main html file
apphtml.output = $$DESTDIR/$$TARGET_HTML apphtml.output = $$DESTDIR/$$TARGET_HTML
apphtml.commands = sed -e s/@APPNAME@/$$TARGET_BASE/g $$WASM_PLUGIN_PATH/wasm_shell.html > $$DESTDIR/$$TARGET_HTML apphtml.commands = $$QMAKE_STREAM_EDITOR -e s/@APPNAME@/$$TARGET_BASE/g $$WASM_PLUGIN_PATH/wasm_shell.html > $$DESTDIR/$$TARGET_HTML
apphtml.input = $$WASM_PLUGIN_PATH/wasm_shell.html apphtml.input = $$WASM_PLUGIN_PATH/wasm_shell.html
apphtml.depends = $$apphtml.input apphtml.depends = $$apphtml.input
QMAKE_EXTRA_COMPILERS += apphtml QMAKE_EXTRA_COMPILERS += apphtml

View File

@ -25,7 +25,7 @@ EMTERP_FLAGS = \
-s ASSERTIONS=1 \ -s ASSERTIONS=1 \
--profiling-funcs --profiling-funcs
EMCC_COMMON_LFLAGS = \ EMCC_COMMON_LFLAGS += \
-s WASM=1 \ -s WASM=1 \
-s FULL_ES2=1 \ -s FULL_ES2=1 \
-s FULL_ES3=1 \ -s FULL_ES3=1 \

View File

@ -154,7 +154,7 @@ static int doSed(int argc, char **argv)
FILE *f; FILE *f;
if (!strcmp(inFile, "-")) { if (!strcmp(inFile, "-")) {
f = stdin; f = stdin;
} else if (!(f = fopen(inFile, "r"))) { } else if (!(f = fopen(inFile, "rb"))) {
perror(inFile); perror(inFile);
return 1; return 1;
} }

View File

@ -492,6 +492,39 @@
# error "Qt has not been tested with this compiler - see http://www.qt-project.org/" # error "Qt has not been tested with this compiler - see http://www.qt-project.org/"
#endif #endif
/*
* SG10's SD-6 feature detection and some useful extensions from Clang and GCC
* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
* http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros
* Not using wrapper macros, per http://eel.is/c++draft/cpp.cond#7.sentence-2
*/
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
#ifndef __has_feature
# define __has_feature(x) 0
#endif
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#ifndef __has_include
# define __has_include(x) 0
#endif
#ifndef __has_include_next
# define __has_include_next(x) 0
#endif
// Kept around until all submodules have transitioned
#define QT_HAS_BUILTIN(x) __has_builtin(x)
#define QT_HAS_FEATURE(x) __has_feature(x)
#define QT_HAS_ATTRIBUTE(x) __has_attribute(x)
#define QT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#define QT_HAS_INCLUDE(x) __has_include(x)
#define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x)
/* /*
* C++11 support * C++11 support
* *
@ -1018,37 +1051,6 @@
# endif # endif
#endif #endif
/*
* SG10's SD-6 feature detection and some useful extensions from Clang and GCC
* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
* http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros
*/
#ifdef __has_builtin
# define QT_HAS_BUILTIN(x) __has_builtin(x)
#else
# define QT_HAS_BUILTIN(x) 0
#endif
#ifdef __has_attribute
# define QT_HAS_ATTRIBUTE(x) __has_attribute(x)
#else
# define QT_HAS_ATTRIBUTE(x) 0
#endif
#ifdef __has_cpp_attribute
# define QT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define QT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#ifdef __has_include
# define QT_HAS_INCLUDE(x) __has_include(x)
#else
# define QT_HAS_INCLUDE(x) 0
#endif
#ifdef __has_include_next
# define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x)
#else
# define QT_HAS_INCLUDE_NEXT(x) 0
#endif
/* /*
* C++11 keywords and expressions * C++11 keywords and expressions
*/ */
@ -1123,7 +1125,7 @@
# define Q_DECL_ALIGN(n) alignas(n) # define Q_DECL_ALIGN(n) alignas(n)
#endif #endif
#if QT_HAS_CPP_ATTRIBUTE(nodiscard) && !defined(Q_CC_CLANG) // P0188R1 #if __has_cpp_attribute(nodiscard) && !defined(Q_CC_CLANG) // P0188R1
// Can't use [[nodiscard]] with Clang, see https://bugs.llvm.org/show_bug.cgi?id=33518 // Can't use [[nodiscard]] with Clang, see https://bugs.llvm.org/show_bug.cgi?id=33518
# undef Q_REQUIRED_RESULT # undef Q_REQUIRED_RESULT
# define Q_REQUIRED_RESULT [[nodiscard]] # define Q_REQUIRED_RESULT [[nodiscard]]
@ -1225,11 +1227,6 @@
#ifndef QT_MAKE_CHECKED_ARRAY_ITERATOR #ifndef QT_MAKE_CHECKED_ARRAY_ITERATOR
# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) (x) # define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) (x)
#endif #endif
#ifdef __has_feature
# define QT_HAS_FEATURE(x) __has_feature(x)
#else
# define QT_HAS_FEATURE(x) 0
#endif
/* /*
* Warning/diagnostic handling * Warning/diagnostic handling
@ -1320,11 +1317,11 @@
} while (false) } while (false)
#if defined(__cplusplus) #if defined(__cplusplus)
#if QT_HAS_CPP_ATTRIBUTE(clang::fallthrough) #if __has_cpp_attribute(clang::fallthrough)
# define Q_FALLTHROUGH() [[clang::fallthrough]] # define Q_FALLTHROUGH() [[clang::fallthrough]]
#elif QT_HAS_CPP_ATTRIBUTE(gnu::fallthrough) #elif __has_cpp_attribute(gnu::fallthrough)
# define Q_FALLTHROUGH() [[gnu::fallthrough]] # define Q_FALLTHROUGH() [[gnu::fallthrough]]
#elif QT_HAS_CPP_ATTRIBUTE(fallthrough) #elif __has_cpp_attribute(fallthrough)
# define Q_FALLTHROUGH() [[fallthrough]] # define Q_FALLTHROUGH() [[fallthrough]]
#endif #endif
#endif #endif

View File

@ -77,13 +77,13 @@
#define QT_FEATURE_binaryjson -1 #define QT_FEATURE_binaryjson -1
#define QT_FEATURE_cborstream -1 #define QT_FEATURE_cborstream -1
#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1 #define QT_CRYPTOGRAPHICHASH_ONLY_SHA1
#define QT_FEATURE_cxx11_random (QT_HAS_INCLUDE(<random>) ? 1 : -1) #define QT_FEATURE_cxx11_random (__has_include(<random>) ? 1 : -1)
#define QT_NO_DATASTREAM #define QT_NO_DATASTREAM
#define QT_FEATURE_datestring 1 #define QT_FEATURE_datestring 1
#define QT_FEATURE_datetimeparser -1 #define QT_FEATURE_datetimeparser -1
#define QT_FEATURE_easingcurve -1 #define QT_FEATURE_easingcurve -1
#define QT_FEATURE_etw -1 #define QT_FEATURE_etw -1
#define QT_FEATURE_getauxval (QT_HAS_INCLUDE(<sys/auxv.h>) ? 1 : -1) #define QT_FEATURE_getauxval (__has_include(<sys/auxv.h>) ? 1 : -1)
#define QT_FEATURE_getentropy -1 #define QT_FEATURE_getentropy -1
#define QT_NO_GEOM_VARIANT #define QT_NO_GEOM_VARIANT
#define QT_FEATURE_hijricalendar -1 #define QT_FEATURE_hijricalendar -1

View File

@ -66,7 +66,7 @@ template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest)
// Using sizeof(T) inside memcpy function produces internal compiler error with // Using sizeof(T) inside memcpy function produces internal compiler error with
// MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T. // MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T.
const size_t size = sizeof(T); const size_t size = sizeof(T);
#if QT_HAS_BUILTIN(__builtin_memcpy) #if __has_builtin(__builtin_memcpy)
__builtin_memcpy __builtin_memcpy
#else #else
memcpy memcpy
@ -78,7 +78,7 @@ template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const void *src)
{ {
T dest; T dest;
const size_t size = sizeof(T); const size_t size = sizeof(T);
#if QT_HAS_BUILTIN(__builtin_memcpy) #if __has_builtin(__builtin_memcpy)
__builtin_memcpy __builtin_memcpy
#else #else
memcpy memcpy

View File

@ -92,7 +92,7 @@
# include <sys/systeminfo.h> # include <sys/systeminfo.h>
#endif #endif
#if defined(Q_OS_DARWIN) && QT_HAS_INCLUDE(<IOKit/IOKitLib.h>) #if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
# include <IOKit/IOKitLib.h> # include <IOKit/IOKitLib.h>
# include <private/qcore_mac_p.h> # include <private/qcore_mac_p.h>
#endif #endif
@ -3067,7 +3067,7 @@ enum {
*/ */
QByteArray QSysInfo::machineUniqueId() QByteArray QSysInfo::machineUniqueId()
{ {
#if defined(Q_OS_DARWIN) && QT_HAS_INCLUDE(<IOKit/IOKitLib.h>) #if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
char uuid[UuidStringLen + 1]; char uuid[UuidStringLen + 1];
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);

View File

@ -717,7 +717,7 @@ inline void qt_noop(void) {}
#if !defined(QT_NO_EXCEPTIONS) #if !defined(QT_NO_EXCEPTIONS)
# if !defined(Q_MOC_RUN) # if !defined(Q_MOC_RUN)
# if (defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_FEATURE(cxx_exceptions)) || \ # if (defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_feature(cxx_exceptions)) || \
(defined(Q_CC_GNU) && !defined(__EXCEPTIONS)) (defined(Q_CC_GNU) && !defined(__EXCEPTIONS))
# define QT_NO_EXCEPTIONS # define QT_NO_EXCEPTIONS
# endif # endif

View File

@ -74,7 +74,7 @@ Q_CORE_EXPORT time_t qMkTime(struct tm *when);
QT_END_NAMESPACE QT_END_NAMESPACE
#if !QT_HAS_BUILTIN(__builtin_available) #if !__has_builtin(__builtin_available)
#include <initializer_list> #include <initializer_list>
#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qversionnumber.h> #include <QtCore/qversionnumber.h>
@ -142,7 +142,7 @@ QT_END_NAMESPACE
QT_BUILTIN_AVAILABLE1, \ QT_BUILTIN_AVAILABLE1, \
QT_BUILTIN_AVAILABLE0, ) QT_BUILTIN_AVAILABLE0, )
#define __builtin_available(...) QT_BUILTIN_AVAILABLE_CHOOSER(__VA_ARGS__)(__VA_ARGS__) #define __builtin_available(...) QT_BUILTIN_AVAILABLE_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
#endif // !QT_HAS_BUILTIN(__builtin_available) #endif // !__has_builtin(__builtin_available)
#endif // defined(__cplusplus) #endif // defined(__cplusplus)
#endif // QGLOBAL_P_H #endif // QGLOBAL_P_H

View File

@ -70,7 +70,7 @@
#if QT_CONFIG(slog2) #if QT_CONFIG(slog2)
#include <sys/slog2.h> #include <sys/slog2.h>
#endif #endif
#if QT_HAS_INCLUDE(<paths.h>) #if __has_include(<paths.h>)
#include <paths.h> #include <paths.h>
#endif #endif
@ -106,7 +106,7 @@
# if __UCLIBC_HAS_BACKTRACE__ # if __UCLIBC_HAS_BACKTRACE__
# define QLOGGING_HAVE_BACKTRACE # define QLOGGING_HAVE_BACKTRACE
# endif # endif
# elif (defined(__GLIBC__) && defined(__GLIBCXX__)) || (QT_HAS_INCLUDE(<cxxabi.h>) && QT_HAS_INCLUDE(<execinfo.h>)) # elif (defined(__GLIBC__) && defined(__GLIBCXX__)) || (__has_include(<cxxabi.h>) && __has_include(<execinfo.h>))
# define QLOGGING_HAVE_BACKTRACE # define QLOGGING_HAVE_BACKTRACE
# endif # endif
#endif #endif
@ -116,7 +116,7 @@ extern char *__progname;
#endif #endif
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || QT_HAS_INCLUDE(<sys/syscall.h>)) #if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
# include <sys/syscall.h> # include <sys/syscall.h>
# if defined(Q_OS_ANDROID) && !defined(SYS_gettid) # if defined(Q_OS_ANDROID) && !defined(SYS_gettid)
@ -1276,7 +1276,7 @@ void QMessagePattern::setPattern(const QString &pattern)
#if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED) #if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED)
// make sure the function has "Message" in the name so the function is removed // make sure the function has "Message" in the name so the function is removed
#if ((defined(Q_CC_GNU) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) || QT_HAS_ATTRIBUTE(optimize)) \ #if ((defined(Q_CC_GNU) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) || __has_attribute(optimize)) \
&& !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
// force skipping the frame pointer, to save the backtrace() function some work // force skipping the frame pointer, to save the backtrace() function some work
__attribute__((optimize("omit-frame-pointer"))) __attribute__((optimize("omit-frame-pointer")))

View File

@ -253,7 +253,7 @@ QT_WARNING_POP
// size_t. Implementations for 8- and 16-bit types will work but may not be as // size_t. Implementations for 8- and 16-bit types will work but may not be as
// efficient. Implementations for 64-bit may be missing on 32-bit platforms. // efficient. Implementations for 64-bit may be missing on 32-bit platforms.
#if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || (defined(Q_CC_INTEL) && !defined(Q_OS_WIN))) || QT_HAS_BUILTIN(__builtin_add_overflow) #if (defined(Q_CC_GNU) && (Q_CC_GNU >= 500) || (defined(Q_CC_INTEL) && !defined(Q_OS_WIN))) || __has_builtin(__builtin_add_overflow)
// GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows // GCC 5, ICC 18, and Clang 3.8 have builtins to detect overflows
template <typename T> inline template <typename T> inline

View File

@ -55,7 +55,7 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#if QT_HAS_INCLUDE(<paths.h>) #if __has_include(<paths.h>)
# include <paths.h> # include <paths.h>
#endif #endif
#ifndef _PATH_TMP // from <paths.h> #ifndef _PATH_TMP // from <paths.h>

View File

@ -100,7 +100,7 @@ QT_END_NAMESPACE
#include <private/qcore_unix_p.h> #include <private/qcore_unix_p.h>
#endif #endif
#if QT_HAS_INCLUDE(<paths.h>) #if __has_include(<paths.h>)
#include <paths.h> #include <paths.h>
#endif #endif

View File

@ -48,7 +48,7 @@
#include <qcoreapplication.h> #include <qcoreapplication.h>
#endif #endif
#if QT_HAS_INCLUDE(<paths.h>) #if __has_include(<paths.h>)
#include <paths.h> #include <paths.h>
#endif #endif

View File

@ -108,7 +108,7 @@
# endif // QT_LARGEFILE_SUPPORT # endif // QT_LARGEFILE_SUPPORT
#endif // Q_OS_BSD4 #endif // Q_OS_BSD4
#if QT_HAS_INCLUDE(<paths.h>) #if __has_include(<paths.h>)
# include <paths.h> # include <paths.h>
#endif #endif
#ifndef _PATH_MOUNTED #ifndef _PATH_MOUNTED

View File

@ -52,7 +52,7 @@
#include <limits> #include <limits>
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
# include <chrono> # include <chrono>
#endif #endif
@ -120,7 +120,7 @@ public:
QDeadlineTimer &operator-=(qint64 msecs) QDeadlineTimer &operator-=(qint64 msecs)
{ *this = *this + (-msecs); return *this; } { *this = *this + (-msecs); return *this; }
#if QT_HAS_INCLUDE(<chrono>) || defined(Q_CLANG_QDOC) #if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
template <class Clock, class Duration> template <class Clock, class Duration>
QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_, QDeadlineTimer(std::chrono::time_point<Clock, Duration> deadline_,
Qt::TimerType type_ = Qt::CoarseTimer) : t2(0) Qt::TimerType type_ = Qt::CoarseTimer) : t2(0)

View File

@ -55,7 +55,7 @@
#include <QtCore/qobject_impl.h> #include <QtCore/qobject_impl.h>
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
# include <chrono> # include <chrono>
#endif #endif
@ -154,7 +154,7 @@ public:
void moveToThread(QThread *thread); void moveToThread(QThread *thread);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer); int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
Q_ALWAYS_INLINE Q_ALWAYS_INLINE
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer) int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
{ {

View File

@ -47,7 +47,7 @@
#include <QtCore/qbasictimer.h> // conceptual inheritance #include <QtCore/qbasictimer.h> // conceptual inheritance
#include <QtCore/qobject.h> #include <QtCore/qobject.h>
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
# include <chrono> # include <chrono>
#endif #endif
@ -177,7 +177,7 @@ Q_SIGNALS:
void timeout(QPrivateSignal); void timeout(QPrivateSignal);
public: public:
#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC) #if __has_include(<chrono>) || defined(Q_QDOC)
void setInterval(std::chrono::milliseconds value) void setInterval(std::chrono::milliseconds value)
{ {
setInterval(int(value.count())); setInterval(int(value.count()));
@ -223,7 +223,7 @@ private:
static void singleShotImpl(int msec, Qt::TimerType timerType, static void singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj); const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval)
{ return defaultTypeFor(int(interval.count())); } { return defaultTypeFor(int(interval.count())); }

View File

@ -53,7 +53,7 @@
#include <QtCore/qbytearraylist.h> #include <QtCore/qbytearraylist.h>
#endif #endif
#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L #if __has_include(<variant>) && __cplusplus >= 201703L
#include <variant> #include <variant>
#elif defined(Q_CLANG_QDOC) #elif defined(Q_CLANG_QDOC)
namespace std { template<typename...> struct variant; } namespace std { template<typename...> struct variant; }
@ -372,7 +372,7 @@ class Q_CORE_EXPORT QVariant
static inline QVariant fromValue(const T &value) static inline QVariant fromValue(const T &value)
{ return QVariant(qMetaTypeId<T>(), &value, QTypeInfo<T>::isPointer); } { return QVariant(qMetaTypeId<T>(), &value, QTypeInfo<T>::isPointer); }
#if (QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC) #if (__has_include(<variant>) && __cplusplus >= 201703L) || defined(Q_CLANG_QDOC)
template<typename... Types> template<typename... Types>
static inline QVariant fromStdVariant(const std::variant<Types...> &value) static inline QVariant fromStdVariant(const std::variant<Types...> &value)
{ {
@ -538,7 +538,7 @@ inline QVariant QVariant::fromValue(const QVariant &value)
return value; return value;
} }
#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L #if __has_include(<variant>) && __cplusplus >= 201703L
template<> template<>
inline QVariant QVariant::fromValue(const std::monostate &) inline QVariant QVariant::fromValue(const std::monostate &)
{ {

View File

@ -214,7 +214,7 @@ public:
bool contains(const QCborValue &value) const; bool contains(const QCborValue &value) const;
int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION; int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION;
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
std::strong_ordering operator<=>(const QCborArray &other) const std::strong_ordering operator<=>(const QCborArray &other) const
{ {
int c = compare(other); int c = compare(other);

View File

@ -245,7 +245,7 @@ public:
{ const_iterator it = find(key); return it != end(); } { const_iterator it = find(key); return it != end(); }
int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION; int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION;
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
std::strong_ordering operator<=>(const QCborMap &other) const std::strong_ordering operator<=>(const QCborMap &other) const
{ {
int c = compare(other); int c = compare(other);

View File

@ -59,7 +59,7 @@
# undef False # undef False
#endif #endif
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
# include <compare> # include <compare>
#endif #endif
@ -265,7 +265,7 @@ public:
QCborValueRef operator[](const QString & key); QCborValueRef operator[](const QString & key);
int compare(const QCborValue &other) const; int compare(const QCborValue &other) const;
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
std::strong_ordering operator<=>(const QCborValue &other) const std::strong_ordering operator<=>(const QCborValue &other) const
{ {
int c = compare(other); int c = compare(other);
@ -421,7 +421,7 @@ public:
int compare(const QCborValue &other) const int compare(const QCborValue &other) const
{ return concrete().compare(other); } { return concrete().compare(other); }
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
std::strong_ordering operator<=>(const QCborValue &other) const std::strong_ordering operator<=>(const QCborValue &other) const
{ {
int c = compare(other); int c = compare(other);

View File

@ -196,8 +196,7 @@ public:
if (value.container) if (value.container)
return replaceAt_complex(e, value, disp); return replaceAt_complex(e, value, disp);
e.value = value.value_helper(); e = { value.value_helper(), value.type() };
e.type = value.type();
if (value.isContainer()) if (value.isContainer())
e.container = nullptr; e.container = nullptr;
} }

View File

@ -334,7 +334,7 @@ int qstricmp(const char *str1, const char *str2)
return int(Incomplete); return int(Incomplete);
}; };
#if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || QT_HAS_FEATURE(address_sanitizer)) #if defined(__SSE4_1__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
enum { PageSize = 4096, PageMask = PageSize - 1 }; enum { PageSize = 4096, PageMask = PageSize - 1 };
const __m128i zero = _mm_setzero_si128(); const __m128i zero = _mm_setzero_si128();
forever { forever {

View File

@ -243,7 +243,7 @@ public:
void chop(int n); void chop(int n);
#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) # if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT") # pragma push_macro("Q_REQUIRED_RESULT")
# undef Q_REQUIRED_RESULT # undef Q_REQUIRED_RESULT

View File

@ -146,6 +146,9 @@ qsizetype qFindStringBoyerMoore(QStringView haystack, qsizetype from, QStringVie
static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept; static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept;
template <typename Haystack> template <typename Haystack>
static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept; static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle, qsizetype from, Qt::CaseSensitivity cs) noexcept;
template <>
inline qsizetype qLastIndexOf(QString haystack, QChar needle,
qsizetype from, Qt::CaseSensitivity cs) noexcept = delete; // unwanted, would detach
static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs); static inline qsizetype qt_string_count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs);
static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs); static inline qsizetype qt_string_count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs);
@ -3813,7 +3816,7 @@ int QString::indexOf(const QStringRef &str, int from, Qt::CaseSensitivity cs) co
int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const int QString::lastIndexOf(const QString &str, int from, Qt::CaseSensitivity cs) const
{ {
// ### Qt6: qsizetype // ### Qt6: qsizetype
return int(QtPrivate::lastIndexOf(*this, from, str, cs)); return int(QtPrivate::lastIndexOf(QStringView(*this), from, str, cs));
} }
#endif // QT_STRINGVIEW_LEVEL < 2 #endif // QT_STRINGVIEW_LEVEL < 2
@ -3852,7 +3855,7 @@ int QString::lastIndexOf(QLatin1String str, int from, Qt::CaseSensitivity cs) co
int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const int QString::lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
{ {
// ### Qt6: qsizetype // ### Qt6: qsizetype
return int(qLastIndexOf(*this, ch, from, cs)); return int(qLastIndexOf(QStringView(*this), ch, from, cs));
} }
#if QT_STRINGVIEW_LEVEL < 2 #if QT_STRINGVIEW_LEVEL < 2

View File

@ -485,7 +485,7 @@ public:
Q_REQUIRED_RESULT QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const; Q_REQUIRED_RESULT QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const;
#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC) #if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !QT_HAS_CPP_ATTRIBUTE(nodiscard) # if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) && !__has_cpp_attribute(nodiscard)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT") # pragma push_macro("Q_REQUIRED_RESULT")
# undef Q_REQUIRED_RESULT # undef Q_REQUIRED_RESULT

View File

@ -81,7 +81,7 @@ QT_END_NAMESPACE
// if not defined in linux/futex.h // if not defined in linux/futex.h
# define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22 # define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22
# if QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) # if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
# include <sanitizer/tsan_interface.h> # include <sanitizer/tsan_interface.h>
inline void _q_tsan_acquire(void *addr, void *addr2) inline void _q_tsan_acquire(void *addr, void *addr2)
{ {
@ -98,7 +98,7 @@ inline void _q_tsan_release(void *addr, void *addr2)
# else # else
inline void _q_tsan_acquire(void *, void *) {} inline void _q_tsan_acquire(void *, void *) {}
inline void _q_tsan_release(void *, void *) {} inline void _q_tsan_release(void *, void *) {}
# endif // QT_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) # endif // __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace QtLinuxFutex { namespace QtLinuxFutex {

View File

@ -44,7 +44,7 @@
#include <QtCore/qatomic.h> #include <QtCore/qatomic.h>
#include <new> #include <new>
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
# include <chrono> # include <chrono>
# include <limits> # include <limits>
#endif #endif
@ -147,7 +147,7 @@ public:
// Lockable concept // Lockable concept
bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); } bool try_lock() QT_MUTEX_LOCK_NOEXCEPT { return tryLock(); }
#if QT_HAS_INCLUDE(<chrono>) || defined(Q_CLANG_QDOC) #if __has_include(<chrono>) || defined(Q_CLANG_QDOC)
// TimedLockable concept // TimedLockable concept
template <class Rep, class Period> template <class Rep, class Period>
bool try_lock_for(std::chrono::duration<Rep, Period> duration) bool try_lock_for(std::chrono::duration<Rep, Period> duration)
@ -175,7 +175,7 @@ private:
friend class QRecursiveMutex; friend class QRecursiveMutex;
friend class ::tst_QMutex; friend class ::tst_QMutex;
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
template<class Rep, class Period> template<class Rep, class Period>
static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration) static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration)
{ {
@ -213,7 +213,7 @@ public:
using QMutex::tryLock; using QMutex::tryLock;
using QMutex::unlock; using QMutex::unlock;
using QMutex::try_lock; using QMutex::try_lock;
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
using QMutex::try_lock_for; using QMutex::try_lock_for;
using QMutex::try_lock_until; using QMutex::try_lock_until;
#endif #endif
@ -295,7 +295,7 @@ public:
inline void unlock() noexcept {} inline void unlock() noexcept {}
inline bool isRecursive() const noexcept { return true; } inline bool isRecursive() const noexcept { return true; }
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
template <class Rep, class Period> template <class Rep, class Period>
inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) noexcept
{ {

View File

@ -127,7 +127,7 @@ static const char qt_shortMonthNames[][4] = {
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
}; };
static int qt_monthNumberFromShortName(QStringRef shortName) static int qt_monthNumberFromShortName(QStringView shortName)
{ {
for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) { for (unsigned int i = 0; i < sizeof(qt_shortMonthNames) / sizeof(qt_shortMonthNames[0]); ++i) {
if (shortName == QLatin1String(qt_shortMonthNames[i], 3)) if (shortName == QLatin1String(qt_shortMonthNames[i], 3))
@ -136,9 +136,9 @@ static int qt_monthNumberFromShortName(QStringRef shortName)
return -1; return -1;
} }
static int qt_monthNumberFromShortName(const QString &shortName) static int qt_monthNumberFromShortName(const QString &shortName)
{ return qt_monthNumberFromShortName(QStringRef(&shortName)); } { return qt_monthNumberFromShortName(QStringView(shortName)); }
static int fromShortMonthName(const QStringRef &monthName, int year) static int fromShortMonthName(QStringView monthName, int year)
{ {
// Assume that English monthnames are the default // Assume that English monthnames are the default
int month = qt_monthNumberFromShortName(monthName); int month = qt_monthNumberFromShortName(monthName);
@ -207,7 +207,7 @@ static QString toOffsetString(Qt::DateFormat format, int offset)
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
// Parse offset in [+-]HH[[:]mm] format // Parse offset in [+-]HH[[:]mm] format
static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcept static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
{ {
*valid = false; *valid = false;
@ -228,22 +228,23 @@ static int fromOffsetString(const QStringRef &offsetString, bool *valid) noexcep
return 0; return 0;
// Split the hour and minute parts // Split the hour and minute parts
const QStringRef time = offsetString.mid(1); const QStringView time = offsetString.mid(1);
int hhLen = time.indexOf(QLatin1Char(':')); qsizetype hhLen = time.indexOf(QLatin1Char(':'));
int mmIndex; qsizetype mmIndex;
if (hhLen == -1) if (hhLen == -1)
mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format
else else
mmIndex = hhLen + 1; mmIndex = hhLen + 1;
const QStringRef hhRef = time.left(hhLen); const QLocale C = QLocale::c();
const QStringView hhRef = time.left(qMin(hhLen, time.size()));
bool ok = false; bool ok = false;
const int hour = hhRef.toInt(&ok); const int hour = C.toInt(hhRef, &ok);
if (!ok) if (!ok)
return 0; return 0;
const QStringRef mmRef = time.mid(mmIndex); const QStringView mmRef = time.mid(qMin(mmIndex, time.size()));
const int minute = mmRef.isEmpty() ? 0 : mmRef.toInt(&ok); const int minute = mmRef.isEmpty() ? 0 : C.toInt(mmRef, &ok);
if (!ok || minute < 0 || minute > 59) if (!ok || minute < 0 || minute > 59)
return 0; return 0;
@ -2324,7 +2325,7 @@ int QTime::msecsTo(const QTime &t) const
#if QT_CONFIG(datestring) #if QT_CONFIG(datestring)
static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, bool *isMidnight24) static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *isMidnight24)
{ {
if (isMidnight24) if (isMidnight24)
*isMidnight24 = false; *isMidnight24 = false;
@ -2333,11 +2334,12 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format,
if (size < 5) if (size < 5)
return QTime(); return QTime();
const QLocale C(QLocale::c());
bool ok = false; bool ok = false;
int hour = string.mid(0, 2).toInt(&ok); int hour = C.toInt(string.mid(0, 2), &ok);
if (!ok) if (!ok)
return QTime(); return QTime();
const int minute = string.mid(3, 2).toInt(&ok); const int minute = C.toInt(string.mid(3, 2), &ok);
if (!ok) if (!ok)
return QTime(); return QTime();
int second = 0; int second = 0;
@ -2358,11 +2360,11 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format,
// seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds // seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
// will then be rounded up AND clamped to 999. // will then be rounded up AND clamped to 999.
const QStringRef minuteFractionStr = string.mid(6, 5); const QStringView minuteFractionStr = string.mid(6, qMin(qsizetype(5), string.size() - 6));
const long minuteFractionInt = minuteFractionStr.toLong(&ok); const long minuteFractionInt = C.toLong(minuteFractionStr, &ok);
if (!ok) if (!ok)
return QTime(); return QTime();
const float minuteFraction = double(minuteFractionInt) / (std::pow(double(10), minuteFractionStr.count())); const float minuteFraction = double(minuteFractionInt) / (std::pow(double(10), minuteFractionStr.size()));
const float secondWithMs = minuteFraction * 60; const float secondWithMs = minuteFraction * 60;
const float secondNoMs = std::floor(secondWithMs); const float secondNoMs = std::floor(secondWithMs);
@ -2371,15 +2373,20 @@ static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format,
msec = qMin(qRound(secondFraction * 1000.0), 999); msec = qMin(qRound(secondFraction * 1000.0), 999);
} else { } else {
// HH:mm:ss or HH:mm:ss.zzz // HH:mm:ss or HH:mm:ss.zzz
second = string.mid(6, 2).toInt(&ok); second = C.toInt(string.mid(6, qMin(qsizetype(2), string.size() - 6)), &ok);
if (!ok) if (!ok)
return QTime(); return QTime();
if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) { if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) {
const QStringRef msecStr(string.mid(9, 4)); QStringView msecStr(string.mid(9, qMin(qsizetype(4), string.size() - 9)));
int msecInt = msecStr.isEmpty() ? 0 : msecStr.toInt(&ok); // toInt() ignores leading spaces, so catch them before calling it
if (!msecStr.isEmpty() && !msecStr.at(0).isDigit())
return QTime();
// We do, however, want to ignore *trailing* spaces.
msecStr = msecStr.trimmed();
int msecInt = msecStr.isEmpty() ? 0 : C.toInt(msecStr, &ok);
if (!ok) if (!ok)
return QTime(); return QTime();
const double secondFraction(msecInt / (std::pow(double(10), msecStr.count()))); const double secondFraction(msecInt / (std::pow(double(10), msecStr.size())));
msec = qMin(qRound(secondFraction * 1000.0), 999); msec = qMin(qRound(secondFraction * 1000.0), 999);
} }
} }
@ -2428,7 +2435,7 @@ QTime QTime::fromString(const QString &string, Qt::DateFormat format)
case Qt::ISODateWithMs: case Qt::ISODateWithMs:
case Qt::TextDate: case Qt::TextDate:
default: default:
return fromIsoTimeString(QStringRef(&string), format, nullptr); return fromIsoTimeString(QStringView(string), format, nullptr);
} }
} }
@ -3410,6 +3417,7 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT
DaylightStatus hint, DaylightStatus hint,
QDate *zoneDate, QTime *zoneTime) QDate *zoneDate, QTime *zoneTime)
{ {
Q_ASSERT(zone.isValid());
// Get the effective data from QTimeZone // Get the effective data from QTimeZone
QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint)); QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
// Docs state any time before 1970-01-01 will *not* have any DST applied // Docs state any time before 1970-01-01 will *not* have any DST applied
@ -3799,8 +3807,9 @@ QTimeZone QDateTime::timeZone() const
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
return QTimeZone(d->m_offsetFromUtc); return QTimeZone(d->m_offsetFromUtc);
case Qt::TimeZone: case Qt::TimeZone:
Q_ASSERT(d->m_timeZone.isValid()); if (d->m_timeZone.isValid())
return d->m_timeZone; return d->m_timeZone;
break;
case Qt::LocalTime: case Qt::LocalTime:
return QTimeZone::systemTimeZone(); return QTimeZone::systemTimeZone();
} }
@ -3884,6 +3893,7 @@ QString QDateTime::timeZoneAbbreviation() const
#if !QT_CONFIG(timezone) #if !QT_CONFIG(timezone)
break; break;
#else #else
Q_ASSERT(d->m_timeZone.isValid());
return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch()); return d->m_timeZone.d->abbreviation(toMSecsSinceEpoch());
#endif // timezone #endif // timezone
case Qt::LocalTime: { case Qt::LocalTime: {
@ -3920,6 +3930,7 @@ bool QDateTime::isDaylightTime() const
#if !QT_CONFIG(timezone) #if !QT_CONFIG(timezone)
break; break;
#else #else
Q_ASSERT(d->m_timeZone.isValid());
return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch()); return d->m_timeZone.d->isDaylightTime(toMSecsSinceEpoch());
#endif // timezone #endif // timezone
case Qt::LocalTime: { case Qt::LocalTime: {
@ -4044,6 +4055,10 @@ void QDateTime::setTimeZone(const QTimeZone &toZone)
*/ */
qint64 QDateTime::toMSecsSinceEpoch() const qint64 QDateTime::toMSecsSinceEpoch() const
{ {
// Note: QDateTimeParser relies on this producing a useful result, even when
// !isValid(), at least when the invalidity is a time in a fall-back (that
// we'll have adjusted to lie outside it, but marked invalid because it's
// not what was asked for). Other things may be doing similar.
switch (getSpec(d)) { switch (getSpec(d)) {
case Qt::UTC: case Qt::UTC:
return getMSecs(d); return getMSecs(d);
@ -4058,12 +4073,13 @@ qint64 QDateTime::toMSecsSinceEpoch() const
} }
case Qt::TimeZone: case Qt::TimeZone:
#if !QT_CONFIG(timezone) #if QT_CONFIG(timezone)
return 0; if (d->m_timeZone.isValid()) {
#else return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone, extractDaylightStatus(getStatus(d)));
extractDaylightStatus(getStatus(d))); }
#endif #endif
return 0;
} }
Q_UNREACHABLE(); Q_UNREACHABLE();
return 0; return 0;
@ -4158,9 +4174,11 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
case Qt::TimeZone: case Qt::TimeZone:
Q_ASSERT(!d.isShort()); Q_ASSERT(!d.isShort());
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
d.detach();
if (!d->m_timeZone.isValid())
break;
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied // Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied. // but all affected times afterwards will have DST applied.
d.detach();
if (msecs >= 0) { if (msecs >= 0) {
status = mergeDaylightStatus(status, status = mergeDaylightStatus(status,
d->m_timeZone.d->isDaylightTime(msecs) d->m_timeZone.d->isDaylightTime(msecs)
@ -4433,7 +4451,7 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date,
QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime; QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime;
localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time); localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
} else if (spec == Qt::TimeZone) { } else if (spec == Qt::TimeZone && d->m_timeZone.isValid()) {
QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
d->m_timeZone, d->m_timeZone,
QDateTimePrivate::UnknownDaylightTime, QDateTimePrivate::UnknownDaylightTime,
@ -5094,7 +5112,8 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone
{ {
QDateTime dt; QDateTime dt;
dt.setTimeZone(timeZone); dt.setTimeZone(timeZone);
dt.setMSecsSinceEpoch(msecs); if (timeZone.isValid())
dt.setMSecsSinceEpoch(msecs);
return dt; return dt;
} }
@ -5197,16 +5216,17 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
if (!date.isValid()) if (!date.isValid())
return QDateTime(); return QDateTime();
if (size == 10) if (size == 10)
return QDateTime(date); return date.startOfDay();
Qt::TimeSpec spec = Qt::LocalTime; Qt::TimeSpec spec = Qt::LocalTime;
QStringRef isoString(&string); QStringView isoString = QStringView(string).mid(10); // trim "yyyy-MM-dd"
isoString = isoString.mid(10); // trim "yyyy-MM-dd"
// Must be left with T and at least one digit for the hour: // Must be left with T (or space) and at least one digit for the hour:
if (isoString.size() < 2 if (isoString.size() < 2
|| !(isoString.startsWith(QLatin1Char('T')) || !(isoString.startsWith(QLatin1Char('T'), Qt::CaseInsensitive)
// FIXME: QSql relies on QVariant::toDateTime() accepting a space here: // RFC 3339 (section 5.6) allows a space here. (It actually
// allows any separator one considers more readable, merely
// giving space as an example - but let's not go wild !)
|| isoString.startsWith(QLatin1Char(' ')))) { || isoString.startsWith(QLatin1Char(' ')))) {
return QDateTime(); return QDateTime();
} }
@ -5214,7 +5234,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
int offset = 0; int offset = 0;
// Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset
if (isoString.endsWith(QLatin1Char('Z'))) { if (isoString.endsWith(QLatin1Char('Z'), Qt::CaseInsensitive)) {
spec = Qt::UTC; spec = Qt::UTC;
isoString.chop(1); // trim 'Z' isoString.chop(1); // trim 'Z'
} else { } else {
@ -5345,7 +5365,7 @@ QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format)
if (parts.count() == 5) if (parts.count() == 5)
return QDateTime(date, time, Qt::LocalTime); return QDateTime(date, time, Qt::LocalTime);
QStringRef tz = parts.at(5); QStringView tz = parts.at(5);
if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive)) if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive))
return QDateTime(); return QDateTime();
tz = tz.mid(3); tz = tz.mid(3);

View File

@ -1363,7 +1363,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue,
// given date (which might be a spring-forward, skipping an hour). // given date (which might be a spring-forward, skipping an hour).
if (parserType == QVariant::DateTime && !(isSet & HourSectionMask) && !when.isValid()) { if (parserType == QVariant::DateTime && !(isSet & HourSectionMask) && !when.isValid()) {
qint64 msecs = when.toMSecsSinceEpoch(); qint64 msecs = when.toMSecsSinceEpoch();
// Fortunately, that gets a useful answer ... // Fortunately, that gets a useful answer, even though when is invalid ...
const QDateTime replace = const QDateTime replace =
#if QT_CONFIG(timezone) #if QT_CONFIG(timezone)
tspec == Qt::TimeZone tspec == Qt::TimeZone

View File

@ -381,18 +381,15 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
On the first pass, the case we consider is what hint told us to expect On the first pass, the case we consider is what hint told us to expect
(except when hint was -1 and didn't actually tell us what to expect), (except when hint was -1 and didn't actually tell us what to expect),
so it's likely right. We only get a second pass if the first failed, so it's likely right. We only get a second pass if the first failed,
by which time the second case, that we're trying, is likely right. If by which time the second case, that we're trying, is likely right.
an overwhelming majority of calls have hint == -1, the Q_LIKELY here
shall be wrong half the time; otherwise, its errors shall be rarer
than that.
*/ */
if (nextFirst ? i == 0 : i) { if (nextFirst ? i == 0 : i) {
Q_ASSERT(nextStart != invalidMSecs()); Q_ASSERT(nextStart != invalidMSecs());
if (Q_LIKELY(nextStart <= nextTran.atMSecsSinceEpoch)) if (nextStart <= nextTran.atMSecsSinceEpoch)
return nextTran; return nextTran;
} else { } else {
// If next is invalid, nextFirst is false, to route us here first: // If next is invalid, nextFirst is false, to route us here first:
if (nextStart == invalidMSecs() || Q_LIKELY(nextStart > tran.atMSecsSinceEpoch)) if (nextStart == invalidMSecs() || nextStart > tran.atMSecsSinceEpoch)
return tran; return tran;
} }
} }
@ -421,7 +418,7 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
int early = offsetFromUtc(recent); int early = offsetFromUtc(recent);
int late = offsetFromUtc(imminent); int late = offsetFromUtc(imminent);
if (Q_LIKELY(early == late)) { // > 99% of the time if (early == late) { // > 99% of the time
utcEpochMSecs = forLocalMSecs - early * 1000; utcEpochMSecs = forLocalMSecs - early * 1000;
} else { } else {
// Close to a DST transition: early > late is near a fall-back, // Close to a DST transition: early > late is near a fall-back,
@ -433,7 +430,7 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
const qint64 forStd = forLocalMSecs - offsetInStd * 1000; const qint64 forStd = forLocalMSecs - offsetInStd * 1000;
// Best guess at the answer: // Best guess at the answer:
const qint64 hinted = hint > 0 ? forDst : forStd; const qint64 hinted = hint > 0 ? forDst : forStd;
if (Q_LIKELY(offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd))) { if (offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd)) {
utcEpochMSecs = hinted; utcEpochMSecs = hinted;
} else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) { } else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) {
utcEpochMSecs = forDst; utcEpochMSecs = forDst;

View File

@ -535,7 +535,7 @@ QT_DEPRECATED_X("Use std::binary_search") Q_OUTOFLINE_TEMPLATE RandomAccessItera
# define QT_HAS_BUILTIN_CTZS # define QT_HAS_BUILTIN_CTZS
Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept
{ {
# if QT_HAS_BUILTIN(__builtin_ctzs) # if __has_builtin(__builtin_ctzs)
return __builtin_ctzs(v); return __builtin_ctzs(v);
# else # else
return __builtin_ctz(v); return __builtin_ctz(v);
@ -544,7 +544,7 @@ Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_ctzs(quint16 v) noexcept
#define QT_HAS_BUILTIN_CLZS #define QT_HAS_BUILTIN_CLZS
Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept Q_DECL_CONSTEXPR Q_ALWAYS_INLINE uint qt_builtin_clzs(quint16 v) noexcept
{ {
# if QT_HAS_BUILTIN(__builtin_clzs) # if __has_builtin(__builtin_clzs)
return __builtin_clzs(v); return __builtin_clzs(v);
# else # else
return __builtin_clz(v) - 16U; return __builtin_clz(v) - 16U;

View File

@ -51,7 +51,7 @@ template <typename F> QScopeGuard<F> qScopeGuard(F f);
template <typename F> template <typename F>
class class
#if QT_HAS_CPP_ATTRIBUTE(nodiscard) #if __has_cpp_attribute(nodiscard)
// Q_REQUIRED_RESULT can be defined as __warn_unused_result__ or as [[nodiscard]] // Q_REQUIRED_RESULT can be defined as __warn_unused_result__ or as [[nodiscard]]
// but the 1st one has some limitations for example can be placed only on functions. // but the 1st one has some limitations for example can be placed only on functions.
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
@ -91,7 +91,7 @@ private:
template <typename F> template <typename F>
#if QT_HAS_CPP_ATTRIBUTE(nodiscard) #if __has_cpp_attribute(nodiscard)
Q_REQUIRED_RESULT Q_REQUIRED_RESULT
#endif #endif
QScopeGuard<F> qScopeGuard(F f) QScopeGuard<F> qScopeGuard(F f)

View File

@ -131,6 +131,14 @@ void QPlatformCursor::setPos(const QPoint &pos)
QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos, Qt::NoButton, Qt::NoButton, QEvent::MouseMove); QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos, Qt::NoButton, Qt::NoButton, QEvent::MouseMove);
} }
/*!
Returns the size of the cursor, in native pixels.
*/
QSize QPlatformCursor::size() const
{
return QSize(16, 16);
}
// End of display and pointer event handling code // End of display and pointer event handling code
// Beginning of built-in cursor graphics // Beginning of built-in cursor graphics
// from src/gui/embedded/QGraphicsSystemCursorImage_qws.cpp // from src/gui/embedded/QGraphicsSystemCursorImage_qws.cpp

View File

@ -96,6 +96,7 @@ public:
#endif // QT_NO_CURSOR #endif // QT_NO_CURSOR
virtual QPoint pos() const; virtual QPoint pos() const;
virtual void setPos(const QPoint &pos); virtual void setPos(const QPoint &pos);
virtual QSize size() const;
static Capabilities capabilities() { return m_capabilities; } static Capabilities capabilities() { return m_capabilities; }
static void setCapabilities(Capabilities c) { m_capabilities = c; } static void setCapabilities(Capabilities c) { m_capabilities = c; }

View File

@ -784,10 +784,12 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
QDebugStateSaver saver(dbg); QDebugStateSaver saver(dbg);
dbg.nospace(); dbg.nospace();
dbg << "QColorSpace("; dbg << "QColorSpace(";
if (colorSpace.d_ptr->namedColorSpace) if (colorSpace.d_ptr) {
dbg << colorSpace.d_ptr->namedColorSpace << ", "; if (colorSpace.d_ptr->namedColorSpace)
dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction(); dbg << colorSpace.d_ptr->namedColorSpace << ", ";
dbg << ", gamma=" << colorSpace.gamma(); dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
dbg << ", gamma=" << colorSpace.gamma();
}
dbg << ')'; dbg << ')';
return dbg; return dbg;
} }

View File

@ -2428,7 +2428,15 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src)); f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
break; break;
case QShaderDescription::Mat3: case QShaderDescription::Mat3:
f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src)); {
// 4 floats per column (or row, if row-major)
float mat[9];
const float *srcMat = reinterpret_cast<const float *>(src);
memcpy(mat, srcMat, 3 * sizeof(float));
memcpy(mat + 3, srcMat + 4, 3 * sizeof(float));
memcpy(mat + 6, srcMat + 8, 3 * sizeof(float));
f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, mat);
}
break; break;
case QShaderDescription::Mat4: case QShaderDescription::Mat4:
f->glUniformMatrix4fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src)); f->glUniformMatrix4fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
@ -2919,21 +2927,64 @@ bool QRhiGles2::linkProgram(GLuint program)
return true; return true;
} }
void QRhiGles2::gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, void QRhiGles2::registerUniformIfActive(const QShaderDescription::BlockVariable &var,
const QByteArray &namePrefix,
int binding,
int baseOffset,
GLuint program,
QVector<QGles2UniformDescription> *dst)
{
if (var.type == QShaderDescription::Struct) {
qWarning("Nested structs are not supported at the moment. '%s' ignored.",
qPrintable(var.name));
return;
}
QGles2UniformDescription uniform;
uniform.type = var.type;
const QByteArray name = namePrefix + var.name.toUtf8();
uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
if (uniform.glslLocation >= 0) {
uniform.binding = binding;
uniform.offset = uint(baseOffset + var.offset);
uniform.size = var.size;
dst->append(uniform);
}
}
void QRhiGles2::gatherUniforms(GLuint program,
const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst) QVector<QGles2UniformDescription> *dst)
{ {
const QByteArray prefix = ub.structName.toUtf8() + '.'; QByteArray prefix = ub.structName.toUtf8() + '.';
for (const QShaderDescription::BlockVariable &blockMember : ub.members) { for (const QShaderDescription::BlockVariable &blockMember : ub.members) {
// ### no array support for now if (blockMember.type == QShaderDescription::Struct) {
QGles2UniformDescription uniform; prefix += blockMember.name.toUtf8();
uniform.type = blockMember.type; const int baseOffset = blockMember.offset;
const QByteArray name = prefix + blockMember.name.toUtf8(); if (blockMember.arrayDims.isEmpty()) {
uniform.glslLocation = f->glGetUniformLocation(program, name.constData()); for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
if (uniform.glslLocation >= 0) { registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst);
uniform.binding = ub.binding; } else {
uniform.offset = uint(blockMember.offset); if (blockMember.arrayDims.count() > 1) {
uniform.size = blockMember.size; qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.",
dst->append(uniform); qPrintable(blockMember.name));
}
const int dim = blockMember.arrayDims.first();
const int elemSize = blockMember.size / dim;
int elemOffset = baseOffset;
for (int di = 0; di < dim; ++di) {
const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.';
for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst);
elemOffset += elemSize;
}
}
} else {
if (!blockMember.arrayDims.isEmpty()) {
qWarning("Arrays are only supported for structs at the moment. '%s' ignored.",
qPrintable(blockMember.name));
continue;
}
registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, dst);
} }
} }
} }

View File

@ -706,7 +706,14 @@ public:
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion); QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion); bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program); bool linkProgram(GLuint program);
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub, void registerUniformIfActive(const QShaderDescription::BlockVariable &var,
const QByteArray &namePrefix,
int binding,
int baseOffset,
GLuint program,
QVector<QGles2UniformDescription> *dst);
void gatherUniforms(GLuint program,
const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst); QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v, void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst); QVector<QGles2SamplerDescription> *dst);

View File

@ -3215,7 +3215,10 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
[opts release]; [opts release];
// src is autoreleased // src is autoreleased
if (err) { // if lib is null and err is non-null, we had errors (fail)
// if lib is non-null and err is non-null, we had warnings (success)
// if lib is non-null and err is null, there were no errors or warnings (success)
if (!lib) {
const QString msg = QString::fromNSString(err.localizedDescription); const QString msg = QString::fromNSString(err.localizedDescription);
*error = msg; *error = msg;
return nil; return nil;

View File

@ -2261,6 +2261,7 @@ void QTextCursor::insertFragment(const QTextDocumentFragment &fragment)
d->remove(); d->remove();
fragment.d->insert(*this); fragment.d->insert(*this);
d->priv->endEditBlock(); d->priv->endEditBlock();
d->setX();
if (fragment.d && fragment.d->doc) if (fragment.d && fragment.d->doc)
d->priv->mergeCachedResources(fragment.d->doc->docHandle()); d->priv->mergeCachedResources(fragment.d->doc->docHandle());

View File

@ -347,7 +347,19 @@ QTextDocument *QTextDocument::clone(QObject *parent) const
{ {
Q_D(const QTextDocument); Q_D(const QTextDocument);
QTextDocument *doc = new QTextDocument(parent); QTextDocument *doc = new QTextDocument(parent);
QTextCursor(doc).insertFragment(QTextDocumentFragment(this)); if (isEmpty()) {
const QTextCursor thisCursor(const_cast<QTextDocument *>(this));
const auto blockFormat = thisCursor.blockFormat();
if (blockFormat.isValid() && !blockFormat.isEmpty())
QTextCursor(doc).setBlockFormat(blockFormat);
const auto blockCharFormat = thisCursor.blockCharFormat();
if (blockCharFormat.isValid() && !blockCharFormat.isEmpty())
QTextCursor(doc).setBlockCharFormat(blockCharFormat);
} else {
QTextCursor(doc).insertFragment(QTextDocumentFragment(this));
}
doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat()); doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat());
QTextDocumentPrivate *priv = doc->d_func(); QTextDocumentPrivate *priv = doc->d_func();
priv->title = d->title; priv->title = d->title;

View File

@ -67,7 +67,7 @@ void QCocoaClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
} }
pasteBoard->sync(); pasteBoard->sync();
pasteBoard->setMimeData(data); pasteBoard->setMimeData(data, QMacPasteboard::LazyRequest);
emitChanged(mode); emitChanged(mode);
} }
} }

View File

@ -56,6 +56,9 @@ public:
void changeCursor(QCursor *cursor, QWindow *window) override; void changeCursor(QCursor *cursor, QWindow *window) override;
QPoint pos() const override; QPoint pos() const override;
void setPos(const QPoint &position) override; void setPos(const QPoint &position) override;
QSize size() const override;
private: private:
QHash<Qt::CursorShape, NSCursor *> m_cursors; QHash<Qt::CursorShape, NSCursor *> m_cursors;
NSCursor *convertCursor(QCursor *cursor); NSCursor *convertCursor(QCursor *cursor);

View File

@ -85,6 +85,31 @@ void QCocoaCursor::setPos(const QPoint &position)
CFRelease(e); CFRelease(e);
} }
QSize QCocoaCursor::size() const
{
NSCursor *cocoaCursor = NSCursor.currentSystemCursor;
if (!cocoaCursor)
return QPlatformCursor::size();
NSImage *cursorImage = cocoaCursor.image;
if (!cursorImage)
return QPlatformCursor::size();
QSizeF size = QSizeF::fromCGSize(cursorImage.size);
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
NSDictionary *accessSettings = [defaults persistentDomainForName:@"com.apple.universalaccess"];
if (accessSettings == nil)
return size.toSize();
float sizeScale = [accessSettings[@"mouseDriverCursorSize"] floatValue];
if (sizeScale > 0) {
size.rwidth() *= sizeScale;
size.rheight() *= sizeScale;
}
return size.toSize();
}
NSCursor *QCocoaCursor::convertCursor(QCursor *cursor) NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
{ {
if (!cursor) if (!cursor)

View File

@ -186,6 +186,7 @@ public:
QAtomicInt serialNumber; QAtomicInt serialNumber;
int lastSerial; int lastSerial;
bool interrupt; bool interrupt;
bool propagateInterrupt = false;
static void postedEventsSourceCallback(void *info); static void postedEventsSourceCallback(void *info);
static void waitingObserverCallback(CFRunLoopObserverRef observer, static void waitingObserverCallback(CFRunLoopObserverRef observer,

View File

@ -84,13 +84,12 @@
#include "private/qthread_p.h" #include "private/qthread_p.h"
#include "private/qguiapplication_p.h" #include "private/qguiapplication_p.h"
#include <qdebug.h> #include <qdebug.h>
#include <qscopeguard.h>
#include <AppKit/AppKit.h> #include <AppKit/AppKit.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
static inline CFRunLoopRef mainRunLoop() static inline CFRunLoopRef mainRunLoop()
{ {
return CFRunLoopGetMain(); return CFRunLoopGetMain();
@ -348,6 +347,16 @@ static inline void qt_mac_waitForMoreEvents(NSString *runLoopMode = NSDefaultRun
bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{ {
Q_D(QCocoaEventDispatcher); Q_D(QCocoaEventDispatcher);
// In rare rather corner cases a user's application messes with
// QEventLoop::exec()/exit() and QCoreApplication::processEvents(),
// we have to undo what bool blocker normally does.
d->propagateInterrupt = false;
const auto boolBlockerUndo = qScopeGuard([d](){
if (d->propagateInterrupt)
d->interrupt = true;
d->propagateInterrupt = false;
});
QBoolBlocker interruptBlocker(d->interrupt, false); QBoolBlocker interruptBlocker(d->interrupt, false);
bool interruptLater = false; bool interruptLater = false;
@ -496,7 +505,16 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) { if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
// When called "manually", always process posted events and timers // When called "manually", always process posted events and timers
bool oldInterrupt = d->interrupt;
d->processPostedEvents(); d->processPostedEvents();
if (!oldInterrupt && d->interrupt && !d->currentModalSession()) {
// We had direct processEvent call, coming not from QEventLoop::exec().
// One of the posted events triggered an application to interrupt the loop.
// But bool blocker will reset d->interrupt to false, so the real event
// loop will never notice it was interrupted. Now we'll have to fix it by
// enforcing the value of d->interrupt.
d->propagateInterrupt = true;
}
retVal = d->processTimers() || retVal; retVal = d->processTimers() || retVal;
} }

View File

@ -86,6 +86,10 @@ private:
QSurfaceFormat m_format; QSurfaceFormat m_format;
QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers; QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers;
QAtomicInt m_needsUpdate = false; QAtomicInt m_needsUpdate = false;
#ifndef QT_NO_DEBUG_STREAM
friend QDebug operator<<(QDebug debug, const QCocoaGLContext *screen);
#endif
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -158,6 +158,8 @@ void QCocoaGLContext::initialize()
[m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder]; [m_context setValues:&order forParameter:NSOpenGLCPSurfaceOrder];
updateSurfaceFormat(); updateSurfaceFormat();
qCDebug(lcQpaOpenGLContext).verbosity(3) << "Created" << this << "based on requested" << context()->format();
} }
NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format) NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurfaceFormat &format)
@ -355,7 +357,7 @@ QCocoaGLContext::~QCocoaGLContext()
bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
{ {
qCDebug(lcQpaOpenGLContext) << "Making" << m_context << "current" qCDebug(lcQpaOpenGLContext) << "Making" << this << "current"
<< "in" << QThread::currentThread() << "for" << surface; << "in" << QThread::currentThread() << "for" << surface;
Q_ASSERT(surface->surface()->supportsOpenGL()); Q_ASSERT(surface->surface()->supportsOpenGL());
@ -555,4 +557,20 @@ QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName); return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName);
} }
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QCocoaGLContext *context)
{
QDebugStateSaver saver(debug);
debug.nospace();
debug << "QCocoaGLContext(" << (const void *)context;
if (context) {
if (debug.verbosity() > QDebug::DefaultVerbosity)
debug << ", " << context->format();
debug << ", " << context->nativeContext();
}
debug << ')';
return debug;
}
#endif // !QT_NO_DEBUG_STREAM
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -559,7 +559,10 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) { if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior; NSWindowCollectionBehavior behavior = m_view.window.collectionBehavior;
if ((flags & Qt::WindowFullscreenButtonHint) || m_view.window.qt_fullScreen) { const bool enableFullScreen = m_view.window.qt_fullScreen
|| !(flags & Qt::CustomizeWindowHint)
|| (flags & Qt::WindowFullscreenButtonHint);
if (enableFullScreen) {
behavior |= NSWindowCollectionBehaviorFullScreenPrimary; behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary; behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
} else { } else {

View File

@ -138,8 +138,12 @@ QMacPasteboard::QMacPasteboard(CFStringRef name, uchar mt)
QMacPasteboard::~QMacPasteboard() QMacPasteboard::~QMacPasteboard()
{ {
// commit all promises for paste after exit close /*
resolvingBeforeDestruction = true; Commit all promises for paste when shutting down,
unless we are the stack-allocated clipboard used by QCocoaDrag.
*/
if (mime_type == QMacInternalPasteboardMime::MIME_DND)
resolvingBeforeDestruction = true;
PasteboardResolvePromises(paste); PasteboardResolvePromises(paste);
if (paste) if (paste)
CFRelease(paste); CFRelease(paste);

View File

@ -60,6 +60,18 @@ static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0;
static const int c_armCode = _PULSE_CODE_MINAVAIL + 1; static const int c_armCode = _PULSE_CODE_MINAVAIL + 1;
static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2; static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
#if !defined(screen_register_event)
int screen_register_event(screen_context_t, struct sigevent *event)
{
return MsgRegisterEvent(event, -1);
}
int screen_unregister_event(struct sigevent *event)
{
return MsgUnregisterEvent(event);
}
#endif
QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context) QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context)
: QThread() : QThread()
, m_screenContext(context) , m_screenContext(context)
@ -75,10 +87,14 @@ QQnxScreenEventThread::QQnxScreenEventThread(screen_context_t context)
qFatal("QQnxScreenEventThread: Can't continue without a channel connection"); qFatal("QQnxScreenEventThread: Can't continue without a channel connection");
} }
struct sigevent screenEvent; SIGEV_PULSE_INIT(&m_screenEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_screenCode, 0);
SIGEV_PULSE_INIT(&screenEvent, m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_screenCode, 0); if (screen_register_event(m_screenContext, &m_screenEvent) == -1) {
ConnectDetach(m_connectionId);
ChannelDestroy(m_channelId);
qFatal("QQnxScreenEventThread: Can't continue without a registered event");
}
screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &screenEvent); screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, &m_screenEvent);
} }
QQnxScreenEventThread::~QQnxScreenEventThread() QQnxScreenEventThread::~QQnxScreenEventThread()
@ -86,6 +102,8 @@ QQnxScreenEventThread::~QQnxScreenEventThread()
// block until thread terminates // block until thread terminates
shutdown(); shutdown();
screen_notify(m_screenContext, SCREEN_NOTIFY_EVENT, nullptr, nullptr);
screen_unregister_event(&m_screenEvent);
ConnectDetach(m_connectionId); ConnectDetach(m_connectionId);
ChannelDestroy(m_channelId); ChannelDestroy(m_channelId);
} }

View File

@ -45,6 +45,7 @@
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <screen/screen.h> #include <screen/screen.h>
#include <sys/siginfo.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -73,6 +74,7 @@ private:
int m_channelId; int m_channelId;
int m_connectionId; int m_connectionId;
struct sigevent m_screenEvent;
screen_context_t m_screenContext; screen_context_t m_screenContext;
bool m_emitNeededOnNextScreenPulse = true; bool m_emitNeededOnNextScreenPulse = true;
int m_screenPulsesSinceLastArmPulse = 0; int m_screenPulsesSinceLastArmPulse = 0;

View File

@ -54,6 +54,8 @@ QWasmScreen::QWasmScreen(const QString &canvasId)
m_compositor = new QWasmCompositor(this); m_compositor = new QWasmCompositor(this);
m_eventTranslator = new QWasmEventTranslator(this); m_eventTranslator = new QWasmEventTranslator(this);
updateQScreenAndCanvasRenderSize(); updateQScreenAndCanvasRenderSize();
emscripten::val canvas = emscripten::val::global(m_canvasId.toUtf8().constData());
canvas.call<void>("focus");
} }
QWasmScreen::~QWasmScreen() QWasmScreen::~QWasmScreen()

View File

@ -50,6 +50,7 @@
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include <QtGui/private/qguiapplication_p.h> // getPixmapCursor() #include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/private/qwinregistry_p.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qscopedpointer.h> #include <QtCore/qscopedpointer.h>
@ -686,6 +687,30 @@ void QWindowsCursor::setPos(const QPoint &pos)
SetCursorPos(pos.x() , pos.y()); SetCursorPos(pos.x() , pos.y());
} }
/*
The standard size is 32x32, even though the cursor is actually just
16 pixels large. If a large cursor is set in the accessibility settings,
then the cursor increases with 8 pixels for each step.
*/
QSize QWindowsCursor::size() const
{
const QPair<DWORD,bool> cursorSizeSetting =
QWinRegistryKey(HKEY_CURRENT_USER, LR"(Control Panel\Cursors)")
.dwordValue(L"CursorBaseSize");
const int baseSize = screenCursorSize(m_screen).width() / 2;
if (!cursorSizeSetting.second)
return QSize(baseSize / 2, baseSize / 2);
// The registry values are dpi-independent, so we need to scale the result.
int cursorSizeValue = cursorSizeSetting.first * m_screen->logicalDpi().first
/ m_screen->logicalBaseDpi().first;
// map from registry value 32-256 to 0-14, and from there to pixels
cursorSizeValue = (cursorSizeValue - 2 * baseSize) / baseSize;
const int cursorSize = baseSize + cursorSizeValue * (baseSize / 2);
return QSize(cursorSize, cursorSize);
}
QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const
{ {
switch (action) { switch (action) {

View File

@ -113,6 +113,8 @@ public:
QPoint pos() const override; QPoint pos() const override;
void setPos(const QPoint &pos) override; void setPos(const QPoint &pos) override;
QSize size() const override;
static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1); static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1);
static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); } static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); }
static PixmapCursor customCursor(Qt::CursorShape cursorShape, const QPlatformScreen *screen = nullptr); static PixmapCursor customCursor(Qt::CursorShape cursorShape, const QPlatformScreen *screen = nullptr);

View File

@ -57,11 +57,13 @@
#include "qwindowsmenu.h" #include "qwindowsmenu.h"
#include "qwindowsscreen.h" #include "qwindowsscreen.h"
#include <QtGui/qguiapplication.h>
#include <QtGui/qpixmap.h> #include <QtGui/qpixmap.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qrect.h> #include <QtCore/qrect.h>
#include <QtCore/qvector.h> #include <QtCore/qvector.h>
#include <QtCore/qsettings.h> #include <QtCore/qsettings.h>
#include <qpa/qwindowsysteminterface.h>
#include <qt_windows.h> #include <qt_windows.h>
#include <commctrl.h> #include <commctrl.h>
@ -134,9 +136,12 @@ static int indexOfHwnd(HWND hwnd)
extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message, extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam) WPARAM wParam, LPARAM lParam)
{ {
// QTBUG-79248: Trigger screen update if there are no other windows.
if (message == WM_DPICHANGED && QGuiApplication::topLevelWindows().isEmpty())
QWindowsContext::instance()->screenManager().handleScreenChanges();
if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON
|| message == WM_INITMENU || message == WM_INITMENUPOPUP || message == WM_INITMENU || message == WM_INITMENUPOPUP
|| message == WM_COMMAND) { || message == WM_CLOSE || message == WM_COMMAND) {
const int index = indexOfHwnd(hwnd); const int index = indexOfHwnd(hwnd);
if (index >= 0) { if (index >= 0) {
MSG msg; MSG msg;
@ -439,6 +444,9 @@ bool QWindowsSystemTrayIcon::winEvent(const MSG &message, long *result)
case WM_INITMENUPOPUP: case WM_INITMENUPOPUP:
QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(message.wParam)); QWindowsPopupMenu::notifyAboutToShow(reinterpret_cast<HMENU>(message.wParam));
break; break;
case WM_CLOSE:
QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>();
break;
case WM_COMMAND: case WM_COMMAND:
QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam)); QWindowsPopupMenu::notifyTriggered(LOWORD(message.wParam));
break; break;

View File

@ -289,7 +289,8 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
break; break;
case UIA_TogglePatternId: case UIA_TogglePatternId:
// Checkbox controls. // Checkbox controls.
if (accessible->role() == QAccessible::CheckBox) { if (accessible->role() == QAccessible::CheckBox
|| (accessible->role() == QAccessible::MenuItem && accessible->state().checkable)) {
*pRetVal = new QWindowsUiaToggleProvider(id()); *pRetVal = new QWindowsUiaToggleProvider(id());
} }
break; break;

View File

@ -41,6 +41,7 @@
#include "qxcbwindow.h" #include "qxcbwindow.h"
#include "qxcbcursor.h" #include "qxcbcursor.h"
#include "qxcbimage.h" #include "qxcbimage.h"
#include "qxcbintegration.h"
#include "qnamespace.h" #include "qnamespace.h"
#include "qxcbxsettings.h" #include "qxcbxsettings.h"
@ -49,6 +50,7 @@
#include <QDebug> #include <QDebug>
#include <QtAlgorithms> #include <QtAlgorithms>
#include <qpa/qplatformservices.h>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include <private/qmath_p.h> #include <private/qmath_p.h>
#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qhighdpiscaling_p.h>
@ -356,6 +358,15 @@ static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stri
void QXcbVirtualDesktop::readXResources() void QXcbVirtualDesktop::readXResources()
{ {
const QPlatformServices *services = QXcbIntegration::instance()->services();
bool useXftConf = false;
if (services) {
const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':');
useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE");
}
if (!useXftConf)
return;
int offset = 0; int offset = 0;
QByteArray resources; QByteArray resources;
while (true) { while (true) {

View File

@ -838,6 +838,7 @@ QSqlRecord QPSQLResult::record() const
} }
int ptype = PQftype(d->result, i); int ptype = PQftype(d->result, i);
f.setType(qDecodePSQLType(ptype)); f.setType(qDecodePSQLType(ptype));
f.setValue(QVariant(f.type())); // only set in setType() when it's invalid before
int len = PQfsize(d->result, i); int len = PQfsize(d->result, i);
int precision = PQfmod(d->result, i); int precision = PQfmod(d->result, i);

View File

@ -0,0 +1,14 @@
project(mytest LANGUAGES CXX)
find_package(Qt5Test REQUIRED)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
enable_testing(true)
add_executable(mytest tst_mytest.cpp)
add_test(NAME mytest COMMAND mytest)
target_link_libraries(mytest PRIVATE Qt5::Test)

View File

@ -83,6 +83,10 @@
\li Custom types can easily be added to the test data and test output. \li Custom types can easily be added to the test data and test output.
\endtable \endtable
You can use a Qt Creator wizard to create a project that contains Qt tests
and build and run them directly from Qt Creator. For more information, see
\l {Running Autotests}.
\section1 Creating a Test \section1 Creating a Test
To create a test, subclass QObject and add one or more private slots to it. Each To create a test, subclass QObject and add one or more private slots to it. Each
@ -133,6 +137,41 @@
\if !defined(qtforpython) \if !defined(qtforpython)
\section1 Building a Test \section1 Building a Test
You can build an executable that contains one test class that typically
tests one class of production code. However, usually you would want to
test several classes in a project by running one command.
See \l {Chapter 1: Writing a Unit Test}{Writing a Unit Test} for a step by
step explanation.
\section2 Building with CMake and CTest
You can use \l {CMake and CTest} to create a test.
\l{https://cmake.org/cmake/help/latest/manual/ctest.1.html}{CTest} enables
you to include or exclude tests based on a regular expression that is
matched against the test name. You can further apply the \c LABELS property
to a test and CTest can then include or exclude tests based on those labels.
All labeled targets will be run when \c {test} target is called on the
command line.
There are several other advantages with CMake. For example, the result of
a test run can be published on a web server using CDash with virtually no
effort.
CTest scales to very different unit test frameworks, and works out of the
box with QTest.
The following is an example of a CMakeLists.txt file that specifies the
project name and the language used (here, \e mytest and C++), the Qt
modules required for building the test (Qt5Test), and the files that are
included in the test (\e tst_mytest.cpp).
\quotefile code/doc_src_cmakelists.txt
For more information about the options you have, see \l {Build with CMake}.
\section2 Building with qmake
If you are using \c qmake as your build tool, just add the If you are using \c qmake as your build tool, just add the
following to your project file: following to your project file:
@ -146,14 +185,14 @@
See the \l{Building a Testcase}{qmake manual} for See the \l{Building a Testcase}{qmake manual} for
more information about \c{make check}. more information about \c{make check}.
\section2 Building with Other Tools
If you are using other build tools, make sure that you add the location If you are using other build tools, make sure that you add the location
of the Qt Test header files to your include path (usually \c{include/QtTest} of the Qt Test header files to your include path (usually \c{include/QtTest}
under your Qt installation directory). If you are using a release build under your Qt installation directory). If you are using a release build
of Qt, link your test to the \c QtTest library. For debug builds, use of Qt, link your test to the \c QtTest library. For debug builds, use
\c{QtTest_debug}. \c{QtTest_debug}.
See \l {Chapter 1: Writing a Unit Test}{Writing a Unit Test} for a step by
step explanation.
\endif \endif
\section1 Qt Test Command Line Arguments \section1 Qt Test Command Line Arguments

View File

@ -299,6 +299,8 @@ QAccessible::State QAccessibleMenuItem::state() const
s.disabled = true; s.disabled = true;
if (m_action->isChecked()) if (m_action->isChecked())
s.checked = true; s.checked = true;
if (m_action->isCheckable())
s.checkable = true;
return s; return s;
} }

View File

@ -710,14 +710,17 @@ void QProgressDialog::setValue(int progress)
QSize QProgressDialog::sizeHint() const QSize QProgressDialog::sizeHint() const
{ {
Q_D(const QProgressDialog); Q_D(const QProgressDialog);
QSize sh = d->label ? d->label->sizeHint() : QSize(0, 0); QSize labelSize = d->label ? d->label->sizeHint() : QSize(0, 0);
QSize bh = d->bar->sizeHint(); QSize barSize = d->bar->sizeHint();
int margin = style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin); int marginBottom = style()->pixelMetric(QStyle::PM_LayoutBottomMargin, 0, this);
int spacing = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); int spacing = style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing, 0, this);
int h = margin * 2 + bh.height() + sh.height() + spacing; int marginLeft = style()->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, this);
int marginRight = style()->pixelMetric(QStyle::PM_LayoutRightMargin, 0, this);
int height = marginBottom * 2 + barSize.height() + labelSize.height() + spacing;
if (d->cancel) if (d->cancel)
h += d->cancel->sizeHint().height() + spacing; height += d->cancel->sizeHint().height() + spacing;
return QSize(qMax(200, sh.width() + 2 * margin), h); return QSize(qMax(200, labelSize.width() + marginLeft + marginRight), height);
} }
/*!\reimp /*!\reimp

View File

@ -3074,9 +3074,10 @@ void QAbstractItemView::keyboardSearch(const QString &search)
QSize QAbstractItemView::sizeHintForIndex(const QModelIndex &index) const QSize QAbstractItemView::sizeHintForIndex(const QModelIndex &index) const
{ {
Q_D(const QAbstractItemView); Q_D(const QAbstractItemView);
if (!d->isIndexValid(index) || !d->itemDelegate) if (!d->isIndexValid(index))
return QSize(); return QSize();
return d->delegateForIndex(index)->sizeHint(d->viewOptionsV1(), index); const auto delegate = d->delegateForIndex(index);
return delegate ? delegate->sizeHint(d->viewOptionsV1(), index) : QSize();
} }
/*! /*!
@ -3318,6 +3319,8 @@ void QAbstractItemView::update(const QModelIndex &index)
The \a roles which have been changed can either be an empty container (meaning everything The \a roles which have been changed can either be an empty container (meaning everything
has changed), or a non-empty container with the subset of roles which have changed. has changed), or a non-empty container with the subset of roles which have changed.
\note: Qt::ToolTipRole is not honored by dataChanged() in the views provided by Qt.
*/ */
void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{ {
@ -4451,7 +4454,9 @@ QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIn
rect |= current; rect |= current;
} }
} }
rect &= viewportRect; QRect clipped = rect & viewportRect;
rect.setLeft(clipped.left());
rect.setRight(clipped.right());
return ret; return ret;
} }

View File

@ -664,7 +664,9 @@ QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList
rect |= current; rect |= current;
} }
} }
rect &= viewportRect; QRect clipped = rect & viewportRect;
rect.setLeft(clipped.left());
rect.setRight(clipped.right());
return ret; return ret;
} }

View File

@ -53,11 +53,14 @@
#endif #endif
#include <qtextdocument.h> #include <qtextdocument.h>
#include <qdebug.h> #include <qdebug.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformcursor.h>
#include <private/qstylesheetstyle_p.h> #include <private/qstylesheetstyle_p.h>
#ifndef QT_NO_TOOLTIP #ifndef QT_NO_TOOLTIP
#include <qlabel.h> #include <qlabel.h>
#include <QtWidgets/private/qlabel_p.h> #include <QtWidgets/private/qlabel_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <qtooltip.h> #include <qtooltip.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -398,24 +401,34 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
} }
#endif //QT_NO_STYLE_STYLESHEET #endif //QT_NO_STYLE_STYLESHEET
QRect screen = QDesktopWidgetPrivate::screenGeometry(getTipScreen(pos, w));
QPoint p = pos; QPoint p = pos;
p += QPoint(2, 16); int screenNumber = getTipScreen(pos, w);
QScreen *screen = QGuiApplication::screens().at(screenNumber);
if (screen) {
const QPlatformScreen *platformScreen = screen->handle();
const QSize cursorSize = QHighDpi::fromNativePixels(platformScreen->cursor()->size(),
platformScreen);
QPoint offset(2, cursorSize.height());
// assuming an arrow shape, we can just move to the side for very large cursors
if (cursorSize.height() > 2 * this->height())
offset = QPoint(cursorSize.width() / 2, 0);
if (p.x() + this->width() > screen.x() + screen.width()) p += offset;
QRect screenRect = screen->geometry();
if (p.x() + this->width() > screenRect.x() + screenRect.width())
p.rx() -= 4 + this->width(); p.rx() -= 4 + this->width();
if (p.y() + this->height() > screen.y() + screen.height()) if (p.y() + this->height() > screenRect.y() + screenRect.height())
p.ry() -= 24 + this->height(); p.ry() -= 24 + this->height();
if (p.y() < screen.y()) if (p.y() < screenRect.y())
p.setY(screen.y()); p.setY(screenRect.y());
if (p.x() + this->width() > screen.x() + screen.width()) if (p.x() + this->width() > screenRect.x() + screenRect.width())
p.setX(screen.x() + screen.width() - this->width()); p.setX(screenRect.x() + screenRect.width() - this->width());
if (p.x() < screen.x()) if (p.x() < screenRect.x())
p.setX(screen.x()); p.setX(screenRect.x());
if (p.y() + this->height() > screen.y() + screen.height()) if (p.y() + this->height() > screenRect.y() + screenRect.height())
p.setY(screen.y() + screen.height() - this->height()); p.setY(screenRect.y() + screenRect.height() - this->height());
}
this->move(p); this->move(p);
} }

View File

@ -8621,6 +8621,23 @@ bool QWidget::event(QEvent *event)
} }
} }
switch (event->type()) { switch (event->type()) {
case QEvent::PlatformSurface: {
// Sync up QWidget's view of whether or not the widget has been created
switch (static_cast<QPlatformSurfaceEvent*>(event)->surfaceEventType()) {
case QPlatformSurfaceEvent::SurfaceCreated:
if (!testAttribute(Qt::WA_WState_Created))
create();
break;
case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
if (testAttribute(Qt::WA_WState_Created)) {
// Child windows have already been destroyed by QWindow,
// so we skip them here.
destroy(false, false);
}
break;
}
break;
}
case QEvent::MouseMove: case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event); mouseMoveEvent((QMouseEvent*)event);
break; break;

View File

@ -1363,7 +1363,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
if (!button->icon.isNull()) { if (!button->icon.isNull()) {
//Center both icon and text //Center both icon and text
QRect iconRect;
QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
if (mode == QIcon::Normal && button->state & State_HasFocus) if (mode == QIcon::Normal && button->state & State_HasFocus)
mode = QIcon::Active; mode = QIcon::Active;
@ -1372,28 +1371,29 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
state = QIcon::On; state = QIcon::On;
QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state); QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state);
int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio(); int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio(); int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
int labelWidth = pixmapWidth; int labelWidth = pixmapWidth;
int labelHeight = pixmapHeight; int labelHeight = pixmapHeight;
int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint() int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width(); if (!button->text.isEmpty()) {
if (!button->text.isEmpty()) int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
labelWidth += (textWidth + iconSpacing); labelWidth += (textWidth + iconSpacing);
}
iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2, QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
textRect.y() + (textRect.height() - labelHeight) / 2, textRect.y() + (textRect.height() - labelHeight) / 2,
pixmapWidth, pixmapHeight); pixmapWidth, pixmapHeight);
iconRect = visualRect(button->direction, textRect, iconRect); iconRect = visualRect(button->direction, textRect, iconRect);
tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead if (button->direction == Qt::RightToLeft) {
tf |= Qt::AlignRight;
if (button->direction == Qt::RightToLeft)
textRect.setRight(iconRect.left() - iconSpacing); textRect.setRight(iconRect.left() - iconSpacing);
else } else {
tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing); textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
}
if (button->state & (State_On | State_Sunken)) if (button->state & (State_On | State_Sunken))
iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget), iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),

View File

@ -1770,59 +1770,10 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
break; break;
case CE_PushButtonLabel: case CE_PushButtonLabel:
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
QRect ir = button->rect; QStyleOptionButton b(*button);
uint tf = Qt::AlignVCenter; // no PM_ButtonShiftHorizontal and PM_ButtonShiftVertical for fusion style
if (styleHint(SH_UnderlineShortcut, button, widget)) b.state &= ~(State_On | State_Sunken);
tf |= Qt::TextShowMnemonic; QCommonStyle::drawControl(element, &b, painter, widget);
else
tf |= Qt::TextHideMnemonic;
if (!button->icon.isNull()) {
//Center both icon and text
QPoint point;
QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal
: QIcon::Disabled;
if (mode == QIcon::Normal && button->state & State_HasFocus)
mode = QIcon::Active;
QIcon::State state = QIcon::Off;
if (button->state & State_On)
state = QIcon::On;
QPixmap pixmap = button->icon.pixmap(qt_getWindow(widget), button->iconSize, mode, state);
int w = pixmap.width() / pixmap.devicePixelRatio();
int h = pixmap.height() / pixmap.devicePixelRatio();
if (!button->text.isEmpty())
w += button->fontMetrics.boundingRect(option->rect, tf, button->text).width() + 2;
point = QPoint(ir.x() + ir.width() / 2 - w / 2,
ir.y() + ir.height() / 2 - h / 2);
w = pixmap.width() / pixmap.devicePixelRatio();
if (button->direction == Qt::RightToLeft)
point.rx() += w;
painter->drawPixmap(visualPos(button->direction, button->rect, point), pixmap);
if (button->direction == Qt::RightToLeft)
ir.translate(-point.x() - 2, 0);
else
ir.translate(point.x() + w, 0);
// left-align text if there is
if (!button->text.isEmpty())
tf |= Qt::AlignLeft;
} else {
tf |= Qt::AlignHCenter;
}
if (button->features & QStyleOptionButton::HasMenu)
ir = ir.adjusted(0, 0, -proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget), 0);
proxy()->drawItemText(painter, ir, tf, button->palette, (button->state & State_Enabled),
button->text, QPalette::ButtonText);
} }
break; break;
case CE_MenuBarEmptyArea: case CE_MenuBarEmptyArea:

View File

@ -3501,6 +3501,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
} else { } else {
QWindowsStyle::drawControl(ce, &btnOpt, p, w); QWindowsStyle::drawControl(ce, &btnOpt, p, w);
} }
rule.drawImage(p, rule.contentsRect(opt->rect));
if (!customMenu) if (!customMenu)
return; return;
} else { } else {
@ -3730,6 +3731,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
bool dis = !(opt->state & QStyle::State_Enabled), bool dis = !(opt->state & QStyle::State_Enabled),
act = opt->state & QStyle::State_Selected; act = opt->state & QStyle::State_Selected;
int textRectOffset = m->maxIconWidth;
if (!mi.icon.isNull()) { if (!mi.icon.isNull()) {
QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal; QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
if (act && !dis) if (act && !dis)
@ -3755,19 +3757,21 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
p->drawPixmap(pmr.topLeft(), pixmap); p->drawPixmap(pmr.topLeft(), pixmap);
} else if (checkable) { } else if (checkable) {
QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark);
const QRect cmRect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction);
if (subSubRule.hasDrawable() || checked) { if (subSubRule.hasDrawable() || checked) {
QStyleOptionMenuItem newMi = mi; QStyleOptionMenuItem newMi = mi;
if (!dis) if (!dis)
newMi.state |= State_Enabled; newMi.state |= State_Enabled;
if (act) if (mi.checked)
newMi.state |= State_On; newMi.state |= State_On;
newMi.rect = positionRect(w, subRule, subSubRule, PseudoElement_MenuCheckMark, opt->rect, opt->direction); newMi.rect = cmRect;
drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w);
} }
textRectOffset = std::max(textRectOffset, cmRect.width());
} }
QRect textRect = subRule.contentsRect(opt->rect); QRect textRect = subRule.contentsRect(opt->rect);
textRect.setLeft(textRect.left() + m->maxIconWidth); textRect.setLeft(textRect.left() + textRectOffset);
textRect.setWidth(textRect.width() - mi.tabWidth); textRect.setWidth(textRect.width() - mi.tabWidth);
const QRect vTextRect = visualRect(opt->direction, m->rect, textRect); const QRect vTextRect = visualRect(opt->direction, m->rect, textRect);

View File

@ -90,12 +90,10 @@ QT_BEGIN_NAMESPACE
today's date, and restricted the valid date range to today plus or today's date, and restricted the valid date range to today plus or
minus 365 days. We've set the order to month, day, year. minus 365 days. We've set the order to month, day, year.
The minimum value for QDateTimeEdit is 14 September 1752. You can The range of valid values for a QDateTimeEdit is controlled by the properties
change this by calling setMinimumDate(), taking into account that \l minimumDateTime, \l maximumDateTime, and their respective date and time
the minimum value for QDate is 2 January 4713BC. components. By default, any date-time from the start of 100 CE to the end of
9999 CE is valid.
Other useful functions are setMaximumDate(), setMinimumTime()
and setMaximumTime().
\section1 Using a Pop-up Calendar Widget \section1 Using a Pop-up Calendar Widget
@ -223,10 +221,16 @@ QDateTimeEdit::~QDateTimeEdit()
When setting this property the timespec of the QDateTimeEdit remains the same When setting this property the timespec of the QDateTimeEdit remains the same
and the timespec of the new QDateTime is ignored. and the timespec of the new QDateTime is ignored.
By default, this property contains a date that refers to January 1, By default, this property is set to the start of 2000 CE. It can only be set
2000 and a time of 00:00:00 and 0 milliseconds. to a valid QDateTime value. If any operation causes this property to have an
invalid date-time as value, it is reset to the value of the \l minimumDateTime
property.
\sa date, time If the QDateTimeEdit has no date fields, setting this property sets the
widget's date-range to start and end on the date of the new value of this
property.
\sa date, time, minimumDateTime, maximumDateTime
*/ */
QDateTime QDateTimeEdit::dateTime() const QDateTime QDateTimeEdit::dateTime() const
@ -329,25 +333,23 @@ void QDateTimeEdit::setCalendar(QCalendar calendar)
} }
/*! /*!
\property QDateTimeEdit::minimumDateTime
\since 4.4 \since 4.4
\property QDateTimeEdit::minimumDateTime
\brief the minimum datetime of the date time edit \brief the minimum datetime of the date time edit
When setting this property the \l maximumDateTime() is adjusted if Changing this property implicitly updates the \l minimumDate and \l
necessary to ensure that the range remains valid. If the datetime is minimumTime properties to the date and time parts of this property,
not a valid QDateTime object, this function does nothing. respectively. When setting this property, the \l maximumDateTime is adjusted,
if necessary, to ensure that the range remains valid. Otherwise, changing this
property preserves the \l minimumDateTime property.
The default minimumDateTime can be restored with This property can only be set to a valid QDateTime value. The earliest
clearMinimumDateTime() date-time that setMinimumDateTime() accepts is the start of 100 CE. The
property's default is the start of September 14, 1752 CE. This default can be
restored with clearMinimumDateTime().
By default, this property contains a date that refers to September 14, \sa maximumDateTime, minimumTime, minimumDate, setDateTimeRange(), QDateTime::isValid()
1752 and a time of 00:00:00 and 0 milliseconds.
\sa maximumDateTime(), minimumTime(), maximumTime(), minimumDate(),
maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
clearMaximumDateTime(), clearMinimumDate(),
clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
*/ */
QDateTime QDateTimeEdit::minimumDateTime() const QDateTime QDateTimeEdit::minimumDateTime() const
@ -372,25 +374,23 @@ void QDateTimeEdit::setMinimumDateTime(const QDateTime &dt)
} }
/*! /*!
\property QDateTimeEdit::maximumDateTime
\since 4.4 \since 4.4
\property QDateTimeEdit::maximumDateTime
\brief the maximum datetime of the date time edit \brief the maximum datetime of the date time edit
When setting this property the \l minimumDateTime() is adjusted if Changing this property implicitly updates the \l maximumDate and \l
necessary to ensure that the range remains valid. If the datetime is maximumTime properties to the date and time parts of this property,
not a valid QDateTime object, this function does nothing. respectively. When setting this property, the \l minimumDateTime is adjusted,
if necessary, to ensure that the range remains valid. Otherwise, changing this
property preserves the \l minimumDateTime property.
The default maximumDateTime can be restored with This property can only be set to a valid QDateTime value. The latest
date-time that setMaximumDateTime() accepts is the end of 9999 CE. This is the
default for this property. This default can be restored with
clearMaximumDateTime(). clearMaximumDateTime().
By default, this property contains a date that refers to 31 December, \sa minimumDateTime, maximumTime, maximumDate(), setDateTimeRange(), QDateTime::isValid()
9999 and a time of 23:59:59 and 999 milliseconds.
\sa minimumDateTime(), minimumTime(), maximumTime(), minimumDate(),
maximumDate(), setDateTimeRange(), setDateRange(), setTimeRange(),
clearMinimumDateTime(), clearMinimumDate(),
clearMaximumDate(), clearMinimumTime(), clearMaximumTime()
*/ */
QDateTime QDateTimeEdit::maximumDateTime() const QDateTime QDateTimeEdit::maximumDateTime() const
@ -414,11 +414,12 @@ void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt)
} }
} }
/*! /*!
Convenience function to set minimum and maximum date time with one
function call.
\since 4.4 \since 4.4
\brief Set the range of allowed date-times for the date time edit.
This convenience function sets the \l minimumDateTime and \l maximumDateTime
properties.
\snippet code/src_gui_widgets_qdatetimeedit.cpp 1 \snippet code/src_gui_widgets_qdatetimeedit.cpp 1
@ -426,21 +427,18 @@ void QDateTimeEdit::setMaximumDateTime(const QDateTime &dt)
\snippet code/src_gui_widgets_qdatetimeedit.cpp 2 \snippet code/src_gui_widgets_qdatetimeedit.cpp 2
If either \a min or \a max are not valid, this function does If either \a min or \a max is invalid, this function does nothing. If \a max
nothing. is less than \a min, \a min is used also as \a max.
\sa setMinimumDate(), maximumDate(), setMaximumDate(), \sa minimumDateTime, maximumDateTime, setDateRange(), setTimeRange(), QDateTime::isValid()
clearMinimumDate(), setMinimumTime(), maximumTime(),
setMaximumTime(), clearMinimumTime(), QDateTime::isValid()
*/ */
void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max) void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
// FIXME: does none of the range checks applied to setMin/setMax methods !
const QDateTime minimum = min.toTimeSpec(d->spec); const QDateTime minimum = min.toTimeSpec(d->spec);
QDateTime maximum = max.toTimeSpec(d->spec); const QDateTime maximum = (min > max ? minimum : max.toTimeSpec(d->spec));
if (min > max)
maximum = minimum;
d->setRange(minimum, maximum); d->setRange(minimum, maximum);
} }
@ -449,15 +447,20 @@ void QDateTimeEdit::setDateTimeRange(const QDateTime &min, const QDateTime &max)
\brief the minimum date of the date time edit \brief the minimum date of the date time edit
When setting this property the \l maximumDate is adjusted if Changing this property updates the date of the \l minimumDateTime property
necessary, to ensure that the range remains valid. If the date is while preserving the \l minimumTime property. When setting this property,
not a valid QDate object, this function does nothing. the \l maximumDate is adjusted, if necessary, to ensure that the range remains
valid. When this happens, the \l maximumTime property is also adjusted if it
is less than the \l minimumTime property. Otherwise, changes to this property
preserve the \l maximumDateTime property.
By default, this property contains a date that refers to September 14, 1752. This property can only be set to a valid QDate object describing a date on
The minimum date must be at least the first day in year 100, otherwise which the current \l minimumTime property makes a valid QDateTime object. The
setMinimumDate() has no effect. earliest date that setMinimumDate() accepts is the start of 100 CE. The
default for this property is September 14, 1752 CE. This default can be
restored with clearMinimumDateTime().
\sa minimumTime(), maximumTime(), setDateRange() \sa maximumDate, minimumTime, minimumDateTime, setDateRange(), QDate::isValid()
*/ */
QDate QDateTimeEdit::minimumDate() const QDate QDateTimeEdit::minimumDate() const
@ -484,13 +487,20 @@ void QDateTimeEdit::clearMinimumDate()
\brief the maximum date of the date time edit \brief the maximum date of the date time edit
When setting this property the \l minimumDate is adjusted if Changing this property updates the date of the \l maximumDateTime property
necessary to ensure that the range remains valid. If the date is while preserving the \l maximumTime property. When setting this property, the
not a valid QDate object, this function does nothing. \l minimumDate is adjusted, if necessary, to ensure that the range remains
valid. When this happens, the \l minimumTime property is also adjusted if it
is greater than the \l maximumTime property. Otherwise, changes to this
property preserve the \l minimumDateTime property.
By default, this property contains a date that refers to December 31, 9999. This property can only be set to a valid QDate object describing a date on
which the current \l maximumTime property makes a valid QDateTime object. The
latest date that setMaximumDate() accepts is the end of 9999 CE. This is the
default for this property. This default can be restored with
clearMaximumDateTime().
\sa minimumDate, minimumTime, maximumTime, setDateRange() \sa minimumDate, maximumTime, maximumDateTime, setDateRange(), QDate::isValid()
*/ */
QDate QDateTimeEdit::maximumDate() const QDate QDateTimeEdit::maximumDate() const
@ -502,9 +512,8 @@ QDate QDateTimeEdit::maximumDate() const
void QDateTimeEdit::setMaximumDate(const QDate &max) void QDateTimeEdit::setMaximumDate(const QDate &max)
{ {
Q_D(QDateTimeEdit); Q_D(QDateTimeEdit);
if (max.isValid()) { if (max.isValid())
setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec)); setMaximumDateTime(QDateTime(max, d->maximum.toTime(), d->spec));
}
} }
void QDateTimeEdit::clearMaximumDate() void QDateTimeEdit::clearMaximumDate()
@ -517,13 +526,18 @@ void QDateTimeEdit::clearMaximumDate()
\brief the minimum time of the date time edit \brief the minimum time of the date time edit
When setting this property the \l maximumTime is adjusted if Changing this property updates the time of the \l minimumDateTime property
necessary, to ensure that the range remains valid. If the time is while preserving the \l minimumDate and \l maximumDate properties. If those
not a valid QTime object, this function does nothing. date properties coincide, when setting this property, the \l maximumTime
property is adjusted, if necessary, to ensure that the range remains
valid. Otherwise, changing this property preserves the \l maximumDateTime
property.
By default, this property contains a time of 00:00:00 and 0 milliseconds. This property can be set to any valid QTime value. By default, this property
contains a time of 00:00:00 and 0 milliseconds. This default can be restored
with clearMinimumTime().
\sa maximumTime, minimumDate, maximumDate, setTimeRange() \sa maximumTime, minimumDate, minimumDateTime, setTimeRange(), QTime::isValid()
*/ */
QTime QDateTimeEdit::minimumTime() const QTime QDateTimeEdit::minimumTime() const
@ -551,13 +565,18 @@ void QDateTimeEdit::clearMinimumTime()
\brief the maximum time of the date time edit \brief the maximum time of the date time edit
When setting this property, the \l minimumTime is adjusted if Changing this property updates the time of the \l maximumDateTime property
necessary to ensure that the range remains valid. If the time is while preserving the \l minimumDate and \l maximumDate properties. If those
not a valid QTime object, this function does nothing. date properties coincide, when setting this property, the \l minimumTime
property is adjusted, if necessary, to ensure that the range remains
valid. Otherwise, changing this property preserves the \l minimumDateTime
property.
By default, this property contains a time of 23:59:59 and 999 milliseconds. This property can be set to any valid QTime value. By default, this property
contains a time of 23:59:59 and 999 milliseconds. This default can be restored
with clearMaximumTime().
\sa minimumTime, minimumDate, maximumDate, setTimeRange() \sa minimumTime, maximumDate, maximumDateTime, setTimeRange(), QTime::isValid()
*/ */
QTime QDateTimeEdit::maximumTime() const QTime QDateTimeEdit::maximumTime() const
{ {
@ -580,8 +599,10 @@ void QDateTimeEdit::clearMaximumTime()
} }
/*! /*!
Convenience function to set minimum and maximum date with one \brief Set the range of allowed dates for the date time edit.
function call.
This convenience function sets the \l minimumDate and \l maximumDate
properties.
\snippet code/src_gui_widgets_qdatetimeedit.cpp 3 \snippet code/src_gui_widgets_qdatetimeedit.cpp 3
@ -589,12 +610,14 @@ void QDateTimeEdit::clearMaximumTime()
\snippet code/src_gui_widgets_qdatetimeedit.cpp 4 \snippet code/src_gui_widgets_qdatetimeedit.cpp 4
If either \a min or \a max are not valid, this function does If either \a min or \a max is invalid, this function does nothing. This
nothing. function preserves the \l minimumTime property. If \a max is less than \a min,
the new maximumDateTime property shall be the new minimumDateTime property. If
\a max is equal to \a min and the \l maximumTime property was less then the \l
minimumTime property, the \l maximumTime property is set to the \l minimumTime
property. Otherwise, this preserves the \l maximumTime property.
\sa setMinimumDate(), maximumDate(), setMaximumDate(), \sa minimumDate, maximumDate, setDateTimeRange(), QDate::isValid()
clearMinimumDate(), setMinimumTime(), maximumTime(),
setMaximumTime(), clearMinimumTime(), QDate::isValid()
*/ */
void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max) void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max)
@ -607,8 +630,16 @@ void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max)
} }
/*! /*!
Convenience function to set minimum and maximum time with one \brief Set the range of allowed times for the date time edit.
function call.
This convenience function sets the \l minimumTime and \l maximumTime
properties.
Note that these only constrain the date time edit's value on,
respectively, the \l minimumDate and \l maximumDate. When these date
properties do not coincide, times after \a maximumTime are allowed on dates
before \l maximumDate and times before \a minimumTime are allowed on dates
after \l minimumDate.
\snippet code/src_gui_widgets_qdatetimeedit.cpp 5 \snippet code/src_gui_widgets_qdatetimeedit.cpp 5
@ -616,12 +647,11 @@ void QDateTimeEdit::setDateRange(const QDate &min, const QDate &max)
\snippet code/src_gui_widgets_qdatetimeedit.cpp 6 \snippet code/src_gui_widgets_qdatetimeedit.cpp 6
If either \a min or \a max are not valid, this function does If either \a min or \a max is invalid, this function does nothing. This
nothing. function preserves the \l minimumDate and \l maximumDate properties. If those
properties coincide and max is \a less than \a min, \a min is used as \a max.
\sa setMinimumDate(), maximumDate(), setMaximumDate(), \sa minimumTime, maximumTime, setDateTimeRange(), QTime::isValid()
clearMinimumDate(), setMinimumTime(), maximumTime(),
setMaximumTime(), clearMinimumTime(), QTime::isValid()
*/ */
void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max) void QDateTimeEdit::setTimeRange(const QTime &min, const QTime &max)
@ -865,7 +895,7 @@ QString QDateTimeEdit::sectionText(Section section) const
Note that if you specify a two digit year, it will be interpreted Note that if you specify a two digit year, it will be interpreted
to be in the century in which the date time edit was initialized. to be in the century in which the date time edit was initialized.
The default century is the 21 (2000-2099). The default century is the 21st (2000-2099).
If you specify an invalid format the format will not be set. If you specify an invalid format the format will not be set.

View File

@ -1216,8 +1216,8 @@ QMargins QLineEdit::textMargins() const
\row \li \c a \li ASCII alphabetic character permitted but not required. \row \li \c a \li ASCII alphabetic character permitted but not required.
\row \li \c N \li ASCII alphanumeric character required. A-Z, a-z, 0-9. \row \li \c N \li ASCII alphanumeric character required. A-Z, a-z, 0-9.
\row \li \c n \li ASCII alphanumeric character permitted but not required. \row \li \c n \li ASCII alphanumeric character permitted but not required.
\row \li \c X \li Any character required. \row \li \c X \li Any non-blank character required.
\row \li \c x \li Any character permitted but not required. \row \li \c x \li Any non-blank character permitted but not required.
\row \li \c 9 \li ASCII digit required. 0-9. \row \li \c 9 \li ASCII digit required. 0-9.
\row \li \c 0 \li ASCII digit permitted but not required. \row \li \c 0 \li ASCII digit permitted but not required.
\row \li \c D \li ASCII digit required. 1-9. \row \li \c D \li ASCII digit required. 1-9.

View File

@ -792,6 +792,8 @@ void QMenuSloppyState::setSubMenuPopup(const QRect &actionRect, QAction *resetAc
m_use_reset_action = true; m_use_reset_action = true;
m_time.stop(); m_time.stop();
m_action_rect = actionRect; m_action_rect = actionRect;
if (m_sub_menu)
QMenuPrivate::get(m_sub_menu)->sloppyState.m_parent = nullptr;
m_sub_menu = subMenu; m_sub_menu = subMenu;
QMenuPrivate::get(subMenu)->sloppyState.m_parent = this; QMenuPrivate::get(subMenu)->sloppyState.m_parent = this;
m_reset_action = resetAction; m_reset_action = resetAction;

View File

@ -846,7 +846,8 @@ QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title)
} }
/*! /*!
Appends \a menu to the menu bar. Returns the menu's menuAction(). Appends \a menu to the menu bar. Returns the menu's menuAction(). The menu bar
does not take ownership of the menu.
\note The returned QAction object can be used to hide the corresponding \note The returned QAction object can be used to hide the corresponding
menu. menu.

View File

@ -2328,6 +2328,7 @@ void QPlainTextEdit::changeEvent(QEvent *e)
d->autoScrollTimer.stop(); d->autoScrollTimer.stop();
} else if (e->type() == QEvent::EnabledChange) { } else if (e->type() == QEvent::EnabledChange) {
e->setAccepted(isEnabled()); e->setAccepted(isEnabled());
d->control->setPalette(palette());
d->sendControlEvent(e); d->sendControlEvent(e);
} else if (e->type() == QEvent::PaletteChange) { } else if (e->type() == QEvent::PaletteChange) {
d->control->setPalette(palette()); d->control->setPalette(palette());

View File

@ -1090,7 +1090,7 @@ bool QWidgetLineControl::isValidInput(QChar key, QChar mask) const
return true; return true;
break; break;
case 'X': case 'X':
if (key.isPrint()) if (key.isPrint() && key != m_blank)
return true; return true;
break; break;
case 'x': case 'x':

View File

@ -1283,6 +1283,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
} else { } else {
QTextCursor localCursor = cursor; QTextCursor localCursor = cursor;
localCursor.deletePreviousChar(); localCursor.deletePreviousChar();
if (cursor.d)
cursor.d->setX();
} }
goto accept; goto accept;
} }
@ -1322,9 +1324,13 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e)
else if (e == QKeySequence::Delete) { else if (e == QKeySequence::Delete) {
QTextCursor localCursor = cursor; QTextCursor localCursor = cursor;
localCursor.deleteChar(); localCursor.deleteChar();
if (cursor.d)
cursor.d->setX();
} else if (e == QKeySequence::Backspace) { } else if (e == QKeySequence::Backspace) {
QTextCursor localCursor = cursor; QTextCursor localCursor = cursor;
localCursor.deletePreviousChar(); localCursor.deletePreviousChar();
if (cursor.d)
cursor.d->setX();
}else if (e == QKeySequence::DeleteEndOfWord) { }else if (e == QKeySequence::DeleteEndOfWord) {
if (!cursor.hasSelection()) if (!cursor.hasSelection())
cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor); cursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);

View File

@ -28,7 +28,7 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#if QT_HAS_INCLUDE(<stdbool.h>) || __STDC_VERSION__ >= 199901L #if __has_include(<stdbool.h>) || __STDC_VERSION__ >= 199901L
# include <stdbool.h> # include <stdbool.h>
#else #else
# undef true # undef true

View File

@ -32,7 +32,7 @@
#include <QtCore/QElapsedTimer> #include <QtCore/QElapsedTimer>
#include <QtTest/QtTest> #include <QtTest/QtTest>
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
# include <chrono> # include <chrono>
#endif #endif
@ -519,7 +519,7 @@ void tst_QDeadlineTimer::expire()
void tst_QDeadlineTimer::stdchrono() void tst_QDeadlineTimer::stdchrono()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("std::chrono not found on this system"); QSKIP("std::chrono not found on this system");
#else #else
using namespace std::chrono; using namespace std::chrono;

View File

@ -67,6 +67,7 @@ private slots:
void sendPostedEvents_data(); void sendPostedEvents_data();
void sendPostedEvents(); void sendPostedEvents();
void processEventsOnlySendsQueuedEvents(); void processEventsOnlySendsQueuedEvents();
void eventLoopExit();
}; };
bool tst_QEventDispatcher::event(QEvent *e) bool tst_QEventDispatcher::event(QEvent *e)
@ -314,5 +315,49 @@ void tst_QEventDispatcher::processEventsOnlySendsQueuedEvents()
QCOMPARE(object.eventsReceived, 4); QCOMPARE(object.eventsReceived, 4);
} }
void tst_QEventDispatcher::eventLoopExit()
{
// This test was inspired by QTBUG-79477. A particular
// implementation detail in QCocoaEventDispatcher allowed
// QEventLoop::exit() to fail to really exit the event loop.
// Thus this test is a part of the dispatcher auto-test.
// Imitates QApplication::exec():
QEventLoop mainLoop;
// The test itself is a lambda:
QTimer::singleShot(0, [&mainLoop]() {
// Two more single shots, both will be posted as events
// (zero timeout) and supposed to be processes by the
// mainLoop:
QTimer::singleShot(0, [&mainLoop]() {
// wakeUp triggers QCocoaEventDispatcher into incrementing
// its 'serialNumber':
mainLoop.wakeUp();
// QCocoaEventDispatcher::processEvents() will process
// posted events and execute the second lambda defined below:
QCoreApplication::processEvents();
});
QTimer::singleShot(0, [&mainLoop]() {
// With QCocoaEventDispatcher this is executed while in the
// processEvents (see above) and would fail to actually
// interrupt the loop.
mainLoop.exit();
});
});
bool timeoutObserved = false;
QTimer::singleShot(500, [&timeoutObserved, &mainLoop]() {
// In case the QEventLoop::exit above failed, we have to bail out
// early, not wasting time:
mainLoop.exit();
timeoutObserved = true;
});
mainLoop.exec();
QVERIFY(!timeoutObserved);
}
QTEST_MAIN(tst_QEventDispatcher) QTEST_MAIN(tst_QEventDispatcher)
#include "tst_qeventdispatcher.moc" #include "tst_qeventdispatcher.moc"

View File

@ -223,7 +223,7 @@ void tst_QTimer::remainingTimeDuringActivation()
namespace { namespace {
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
template <typename T> template <typename T>
std::chrono::milliseconds to_ms(T t) std::chrono::milliseconds to_ms(T t)
{ return std::chrono::duration_cast<std::chrono::milliseconds>(t); } { return std::chrono::duration_cast<std::chrono::milliseconds>(t); }
@ -233,7 +233,7 @@ namespace {
void tst_QTimer::basic_chrono() void tst_QTimer::basic_chrono()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires C++11 <chrono> support"); QSKIP("This test requires C++11 <chrono> support");
#else #else
// duplicates zeroTimer, singleShotTimeout, interval and remainingTime // duplicates zeroTimer, singleShotTimeout, interval and remainingTime
@ -871,7 +871,7 @@ void tst_QTimer::singleShotToFunctors()
void tst_QTimer::singleShot_chrono() void tst_QTimer::singleShot_chrono()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires C++11 <chrono> support"); QSKIP("This test requires C++11 <chrono> support");
#else #else
// duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors // duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors

View File

@ -45,7 +45,7 @@
#include <limits.h> #include <limits.h>
#include <float.h> #include <float.h>
#include <cmath> #include <cmath>
#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L #if __has_include(<variant>) && __cplusplus >= 201703L
#include <variant> #include <variant>
#endif #endif
#include <QLinkedList> #include <QLinkedList>
@ -4568,7 +4568,7 @@ void tst_QVariant::accessSequentialContainerKey()
void tst_QVariant::fromStdVariant() void tst_QVariant::fromStdVariant()
{ {
#if QT_HAS_INCLUDE(<variant>) && __cplusplus >= 201703L #if __has_include(<variant>) && __cplusplus >= 201703L
{ {
typedef std::variant<int, bool> intorbool_t; typedef std::variant<int, bool> intorbool_t;
intorbool_t stdvar = 5; intorbool_t stdvar = 5;

View File

@ -384,7 +384,7 @@ void tst_QCborValue::copyCompare()
QCOMPARE(v, other); QCOMPARE(v, other);
QVERIFY(!(v != other)); QVERIFY(!(v != other));
QVERIFY(!(v < other)); QVERIFY(!(v < other));
#if 0 && QT_HAS_INCLUDE(<compare>) #if 0 && __has_include(<compare>)
QVERIFY(v <= other); QVERIFY(v <= other);
QVERIFY(v >= other); QVERIFY(v >= other);
QVERIFY(!(v > other)); QVERIFY(!(v > other));
@ -821,9 +821,37 @@ void tst_QCborValue::mapMutation()
QVERIFY(v.isUndefined()); QVERIFY(v.isUndefined());
// now mutate the list // now mutate the list
// simple -> HasByteData
const QString strValue = QStringLiteral("value");
v = strValue;
QVERIFY(v.isString());
QCOMPARE(v, QCborValue(strValue));
QCOMPARE(m, QCborMap({{42, strValue}}));
// HasByteData -> HasByteData
const QLatin1String otherStrValue("othervalue");
v = otherStrValue;
QVERIFY(v.isString());
QCOMPARE(v, QCborValue(otherStrValue));
QCOMPARE(m, QCborMap({{42, otherStrValue}}));
// HasByteData -> simple
v = 42;
QVERIFY(v.isInteger());
QCOMPARE(v, QCborValue(42));
QCOMPARE(m, QCborMap({{42, 42}}));
// simple -> container
v = QCborArray{1, 2, 3};
QVERIFY(v.isArray());
QCOMPARE(v, QCborArray({1, 2, 3}));
QCOMPARE(m, QCborMap({{42, QCborArray{1, 2, 3}}}));
// container -> simple
v = true; v = true;
QVERIFY(v.isBool()); QVERIFY(v.isBool());
QVERIFY(v.isTrue()); QVERIFY(v.isTrue());
QCOMPARE(m, QCborMap({{42, true}}));
QVERIFY(m.begin()->isTrue()); QVERIFY(m.begin()->isTrue());
QVERIFY(m.begin().value() == v); QVERIFY(m.begin().value() == v);
QVERIFY(v == m.begin().value()); QVERIFY(v == m.begin().value());

View File

@ -89,7 +89,7 @@ enum {
waitTime = 100 waitTime = 100
}; };
#if QT_HAS_INCLUDE(<chrono>) #if __has_include(<chrono>)
static Q_CONSTEXPR std::chrono::milliseconds waitTimeAsDuration(waitTime); static Q_CONSTEXPR std::chrono::milliseconds waitTimeAsDuration(waitTime);
#endif #endif
@ -100,7 +100,7 @@ void tst_QMutex::convertToMilliseconds_data()
QTest::addColumn<qint64>("intValue"); QTest::addColumn<qint64>("intValue");
QTest::addColumn<qint64>("expected"); QTest::addColumn<qint64>("expected");
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#endif #endif
@ -156,7 +156,7 @@ void tst_QMutex::convertToMilliseconds_data()
void tst_QMutex::convertToMilliseconds() void tst_QMutex::convertToMilliseconds()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#else #else
QFETCH(TimeUnit, unit); QFETCH(TimeUnit, unit);
@ -325,7 +325,7 @@ void tst_QMutex::tryLock_non_recursive()
} }
void tst_QMutex::try_lock_for_non_recursive() { void tst_QMutex::try_lock_for_non_recursive() {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#else #else
class Thread : public QThread class Thread : public QThread
@ -454,7 +454,7 @@ void tst_QMutex::try_lock_for_non_recursive() {
void tst_QMutex::try_lock_until_non_recursive() void tst_QMutex::try_lock_until_non_recursive()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#else #else
class Thread : public QThread class Thread : public QThread
@ -707,7 +707,7 @@ void tst_QMutex::tryLock_recursive()
void tst_QMutex::try_lock_for_recursive() void tst_QMutex::try_lock_for_recursive()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#else #else
class Thread : public QThread class Thread : public QThread
@ -836,7 +836,7 @@ void tst_QMutex::try_lock_for_recursive()
void tst_QMutex::try_lock_until_recursive() void tst_QMutex::try_lock_until_recursive()
{ {
#if !QT_HAS_INCLUDE(<chrono>) #if !__has_include(<chrono>)
QSKIP("This test requires <chrono>"); QSKIP("This test requires <chrono>");
#else #else
class Thread : public QThread class Thread : public QThread

View File

@ -150,6 +150,7 @@ private slots:
void timeZones() const; void timeZones() const;
void systemTimeZoneChange() const; void systemTimeZoneChange() const;
void invalid_data() const;
void invalid() const; void invalid() const;
void range() const; void range() const;
@ -2209,6 +2210,13 @@ void tst_QDateTime::fromStringDateFormat_data()
<< Qt::TextDate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456)); << Qt::TextDate << QDateTime(QDate(2013, 5, 6), QTime(1, 2, 3, 456));
// Test Qt::ISODate format. // Test Qt::ISODate format.
QTest::newRow("trailing space") // QTBUG-80445
<< QString("2000-01-02 03:04:05.678 ")
<< Qt::ISODate << QDateTime(QDate(2000, 1, 2), QTime(3, 4, 5, 678));
QTest::newRow("space before millis")
<< QString("2000-01-02 03:04:05. 678") << Qt::ISODate << QDateTime();
// Normal usage:
QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00") QTest::newRow("ISO +01:00") << QString::fromLatin1("1987-02-13T13:24:51+01:00")
<< Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC); << Qt::ISODate << QDateTime(QDate(1987, 2, 13), QTime(12, 24, 51), Qt::UTC);
QTest::newRow("ISO +00:01") << QString::fromLatin1("1987-02-13T13:24:51+00:01") QTest::newRow("ISO +00:01") << QString::fromLatin1("1987-02-13T13:24:51+00:01")
@ -2229,11 +2237,17 @@ void tst_QDateTime::fromStringDateFormat_data()
<< Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), Qt::UTC); << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9), Qt::UTC);
QTest::newRow("ISO zzz-3") << QString::fromLatin1("2014-12-15T12:37:09.745-3") QTest::newRow("ISO zzz-3") << QString::fromLatin1("2014-12-15T12:37:09.745-3")
<< Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), Qt::UTC); << Qt::ISODate << QDateTime(QDate(2014, 12, 15), QTime(15, 37, 9, 745), Qt::UTC);
QTest::newRow("ISO lower-case") << QString::fromLatin1("2005-06-28T07:57:30.002z")
<< Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC);
// No time specified - defaults to Qt::LocalTime. // No time specified - defaults to Qt::LocalTime.
QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01") QTest::newRow("ISO data3") << QString::fromLatin1("2002-10-01")
<< Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0), Qt::LocalTime); << Qt::ISODate << QDateTime(QDate(2002, 10, 1), QTime(0, 0, 0, 0), Qt::LocalTime);
// Excess digits in milliseconds, round correctly:
QTest::newRow("ISO") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z") QTest::newRow("ISO") << QString::fromLatin1("2005-06-28T07:57:30.0010000000Z")
<< Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC); << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 1), Qt::UTC);
QTest::newRow("ISO rounding") << QString::fromLatin1("2005-06-28T07:57:30.0015Z")
<< Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 2), Qt::UTC);
// ... and accept comma as separator:
QTest::newRow("ISO with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z") QTest::newRow("ISO with comma 1") << QString::fromLatin1("2005-06-28T07:57:30,0040000000Z")
<< Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4), Qt::UTC); << Qt::ISODate << QDateTime(QDate(2005, 6, 28), QTime(7, 57, 30, 4), Qt::UTC);
QTest::newRow("ISO with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z") QTest::newRow("ISO with comma 2") << QString::fromLatin1("2005-06-28T07:57:30,0015Z")
@ -2458,6 +2472,7 @@ void tst_QDateTime::fromStringStringFormat_data()
if (southBrazil.isValid()) { if (southBrazil.isValid()) {
QTest::newRow("spring-forward-midnight") QTest::newRow("spring-forward-midnight")
<< QString("2008-10-19 23:45.678 America/Sao_Paulo") << QString("yyyy-MM-dd mm:ss.zzz t") << QString("2008-10-19 23:45.678 America/Sao_Paulo") << QString("yyyy-MM-dd mm:ss.zzz t")
// That's in the hour skipped - expect the matching time after the spring-forward, in DST:
<< QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil); << QDateTime(QDate(2008, 10, 19), QTime(1, 23, 45, 678), southBrazil);
} }
#endif #endif
@ -3359,6 +3374,9 @@ void tst_QDateTime::timeZones() const
QCOMPARE(utc.date(), utcDst.date()); QCOMPARE(utc.date(), utcDst.date());
QCOMPARE(utc.time(), utcDst.time()); QCOMPARE(utc.time(), utcDst.time());
// Crash test, QTBUG-80146:
QVERIFY(!nzStd.toTimeZone(QTimeZone()).isValid());
// Sydney is 2 hours behind New Zealand // Sydney is 2 hours behind New Zealand
QTimeZone ausTz = QTimeZone("Australia/Sydney"); QTimeZone ausTz = QTimeZone("Australia/Sydney");
QDateTime aus = nzStd.toTimeZone(ausTz); QDateTime aus = nzStd.toTimeZone(ausTz);
@ -3528,23 +3546,42 @@ void tst_QDateTime::systemTimeZoneChange() const
QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs); QCOMPARE(tzDate.toMSecsSinceEpoch(), tzMsecs);
} }
void tst_QDateTime::invalid_data() const
{
QTest::addColumn<QDateTime>("when");
QTest::addColumn<Qt::TimeSpec>("spec");
QTest::addColumn<bool>("goodZone");
QTest::newRow("default") << QDateTime() << Qt::LocalTime << true;
QDateTime invalidDate = QDateTime(QDate(0, 0, 0), QTime(-1, -1, -1));
QTest::newRow("simple") << invalidDate << Qt::LocalTime << true;
QTest::newRow("UTC") << invalidDate.toUTC() << Qt::UTC << true;
QTest::newRow("offset")
<< invalidDate.toOffsetFromUtc(3600) << Qt::OffsetFromUTC << true;
QTest::newRow("CET")
<< invalidDate.toTimeZone(QTimeZone("Europe/Oslo")) << Qt::TimeZone << true;
// Crash tests, QTBUG-80146:
QTest::newRow("nozone+construct")
<< QDateTime(QDate(1970, 1, 1), QTime(12, 0), QTimeZone()) << Qt::TimeZone << false;
QTest::newRow("nozone+fromMSecs")
<< QDateTime::fromMSecsSinceEpoch(42, QTimeZone()) << Qt::TimeZone << false;
QDateTime valid(QDate(1970, 1, 1), QTime(12, 0), Qt::UTC);
QTest::newRow("tonozone") << valid.toTimeZone(QTimeZone()) << Qt::TimeZone << false;
}
void tst_QDateTime::invalid() const void tst_QDateTime::invalid() const
{ {
QDateTime invalidDate = QDateTime(QDate(0, 0, 0), QTime(-1, -1, -1)); QFETCH(QDateTime, when);
QCOMPARE(invalidDate.isValid(), false); QFETCH(Qt::TimeSpec, spec);
QCOMPARE(invalidDate.timeSpec(), Qt::LocalTime); QFETCH(bool, goodZone);
QVERIFY(!when.isValid());
QDateTime utcDate = invalidDate.toUTC(); QCOMPARE(when.timeSpec(), spec);
QCOMPARE(utcDate.isValid(), false); QCOMPARE(when.timeZoneAbbreviation(), QString());
QCOMPARE(utcDate.timeSpec(), Qt::UTC); if (!goodZone)
QCOMPARE(when.toMSecsSinceEpoch(), 0);
QDateTime offsetDate = invalidDate.toOffsetFromUtc(3600); QVERIFY(!when.isDaylightTime());
QCOMPARE(offsetDate.isValid(), false); QCOMPARE(when.timeZone().isValid(), goodZone);
QCOMPARE(offsetDate.timeSpec(), Qt::OffsetFromUTC);
QDateTime tzDate = invalidDate.toTimeZone(QTimeZone("Europe/Oslo"));
QCOMPARE(tzDate.isValid(), false);
QCOMPARE(tzDate.timeSpec(), Qt::TimeZone);
} }
void tst_QDateTime::range() const void tst_QDateTime::range() const

View File

@ -51,7 +51,7 @@
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
#define COMPILER_HAS_STDLIB_INCLUDE(x) 1 #define COMPILER_HAS_STDLIB_INCLUDE(x) 1
#else #else
#define COMPILER_HAS_STDLIB_INCLUDE(x) QT_HAS_INCLUDE(x) #define COMPILER_HAS_STDLIB_INCLUDE(x) __has_include(x)
#endif #endif
#if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>) #if COMPILER_HAS_STDLIB_INCLUDE(<forward_list>)

View File

@ -125,6 +125,7 @@ private slots:
void clonePreservesResources(); void clonePreservesResources();
void clonePreservesUserStates(); void clonePreservesUserStates();
void clonePreservesIndentWidth(); void clonePreservesIndentWidth();
void clonePreservesFormatsWhenEmpty();
void blockCount(); void blockCount();
void defaultStyleSheet(); void defaultStyleSheet();
@ -2348,6 +2349,32 @@ void tst_QTextDocument::clonePreservesIndentWidth()
delete clone; delete clone;
} }
void tst_QTextDocument::clonePreservesFormatsWhenEmpty()
{
QTextDocument document;
QTextCursor cursor(&document);
// Change a few char format attributes
QTextCharFormat charFormat;
charFormat.setFontPointSize(charFormat.fontPointSize() + 1);
charFormat.setFontWeight(charFormat.fontWeight() + 1);
cursor.setBlockCharFormat(charFormat);
// Change a few block format attributes
QTextBlockFormat blockFormat;
blockFormat.setAlignment(Qt::AlignRight); // The default is Qt::AlignLeft
blockFormat.setIndent(blockFormat.indent() + 1);
cursor.setBlockFormat(blockFormat);
auto clone = document.clone();
QTextCursor cloneCursor(clone);
QCOMPARE(cloneCursor.blockCharFormat().fontPointSize(), charFormat.fontPointSize());
QCOMPARE(cloneCursor.blockCharFormat().fontWeight(), charFormat.fontWeight());
QCOMPARE(cloneCursor.blockFormat().alignment(), blockFormat.alignment());
QCOMPARE(cloneCursor.blockFormat().indent(), blockFormat.indent());
}
void tst_QTextDocument::blockCount() void tst_QTextDocument::blockCount()
{ {
QCOMPARE(doc->blockCount(), 1); QCOMPARE(doc->blockCount(), 1);

View File

@ -1,3 +0,0 @@
# QTBUG-65667
[localAddress:linklocal-ipv4]
windows ci

View File

@ -215,31 +215,45 @@ void tst_QNetworkInterface::loopbackIPv6()
} }
void tst_QNetworkInterface::localAddress_data() void tst_QNetworkInterface::localAddress_data()
{ {
bool ipv6 = isIPv6Working();
QTest::addColumn<QHostAddress>("target"); QTest::addColumn<QHostAddress>("target");
QTest::newRow("localhost-ipv4") << QHostAddress(QHostAddress::LocalHost); QTest::newRow("localhost-ipv4") << QHostAddress(QHostAddress::LocalHost);
if (isIPv6Working()) if (ipv6)
QTest::newRow("localhost-ipv6") << QHostAddress(QHostAddress::LocalHostIPv6); QTest::newRow("localhost-ipv6") << QHostAddress(QHostAddress::LocalHostIPv6);
QTest::newRow("test-server") << QtNetworkSettings::serverIP(); QTest::newRow("test-server") << QtNetworkSettings::serverIP();
// Since we don't actually transmit anything, we can list any IPv4 address QSet<QHostAddress> added;
// and it should work. But we're using a linklocal address so that this const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
// test can pass even machines that failed to reach a DHCP server. for (const QNetworkInterface &iface : ifaces) {
QTest::newRow("linklocal-ipv4") << QHostAddress("169.254.0.1"); if ((iface.flags() & QNetworkInterface::IsUp) == 0)
continue;
const QList<QNetworkAddressEntry> addrs = iface.addressEntries();
for (const QNetworkAddressEntry &entry : addrs) {
QHostAddress addr = entry.ip();
if (addr.isLoopback())
continue; // added above
if (isIPv6Working()) { if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
// On the other hand, we can't list just any IPv6 here. It's very // add an IPv4 address with bits in the host portion of the address flipped
// likely that this machine has not received a route via ICMPv6-RA or quint32 ip4 = entry.ip().toIPv4Address();
// DHCPv6, so it won't have a global route. On some OSes, IPv6 may be addr.setAddress(ip4 ^ ~entry.netmask().toIPv4Address());
// enabled per interface, so we need to know which ones work. } else if (!ipv6 || entry.prefixLength() != 64) {
const QList<QHostAddress> addrs = QNetworkInterface::allAddresses();
for (const QHostAddress &addr : addrs) {
QString scope = addr.scopeId();
if (scope.isEmpty())
continue; continue;
QTest::addRow("linklocal-ipv6-%s", qPrintable(scope)) } else {
<< QHostAddress("fe80::1234%" + scope); // add a random node in this IPv6 network
quint64 randomid = qFromBigEndian(Q_UINT64_C(0x8f41f072e5733caa));
QIPv6Address ip6 = addr.toIPv6Address();
memcpy(&ip6[8], &randomid, sizeof(randomid));
addr.setAddress(ip6);
}
if (added.contains(addr))
continue;
added.insert(addr);
QTest::addRow("%s-%s", qPrintable(iface.name()), qPrintable(addr.toString())) << addr;
} }
} }
} }

View File

@ -965,9 +965,7 @@ void tst_QSqlQuery::blob()
//don' make it too big otherwise sybase and mysql will complain //don' make it too big otherwise sybase and mysql will complain
QByteArray ba( BLOBSIZE, 0 ); QByteArray ba( BLOBSIZE, 0 );
int i; for (int i = 0; i < ba.size(); ++i)
for ( i = 0; i < ( int )ba.size(); ++i )
ba[i] = i % 256; ba[i] = i % 256;
QSqlQuery q( db ); QSqlQuery q( db );
@ -980,7 +978,7 @@ void tst_QSqlQuery::blob()
QVERIFY_SQL(q, prepare("insert into " + qTableName("qtest_blob", __FILE__, db) + " (id, t_blob) values (?, ?)")); QVERIFY_SQL(q, prepare("insert into " + qTableName("qtest_blob", __FILE__, db) + " (id, t_blob) values (?, ?)"));
for ( i = 0; i < BLOBCOUNT; ++i ) { for (int i = 0; i < BLOBCOUNT; ++i) {
q.addBindValue( i ); q.addBindValue( i );
q.addBindValue( ba ); q.addBindValue( ba );
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
@ -988,13 +986,13 @@ void tst_QSqlQuery::blob()
QVERIFY_SQL(q, exec("select * from " + qTableName("qtest_blob", __FILE__, db))); QVERIFY_SQL(q, exec("select * from " + qTableName("qtest_blob", __FILE__, db)));
for ( i = 0; i < BLOBCOUNT; ++i ) { for (int i = 0; i < BLOBCOUNT; ++i) {
QVERIFY( q.next() ); QVERIFY( q.next() );
QByteArray res = q.value( 1 ).toByteArray(); QByteArray res = q.value( 1 ).toByteArray();
QVERIFY2( res.size() >= ba.size(), QVERIFY2( res.size() >= ba.size(),
QString( "array sizes differ, expected %1, got %2" ).arg( ba.size() ).arg( res.size() ).toLatin1() ); QString( "array sizes differ, expected %1, got %2" ).arg( ba.size() ).arg( res.size() ).toLatin1() );
for ( int i2 = 0; i2 < ( int )ba.size(); ++i2 ) { for (int i2 = 0; i2 < ba.size(); ++i2) {
if ( res[i2] != ba[i2] ) if ( res[i2] != ba[i2] )
QFAIL( QString( "ByteArrays differ at position %1, expected %2, got %3" ).arg( QFAIL( QString( "ByteArrays differ at position %1, expected %2, got %3" ).arg(
i2 ).arg(( int )( unsigned char )ba[i2] ).arg(( int )( unsigned char )res[i2] ).toLatin1() ); i2 ).arg(( int )( unsigned char )ba[i2] ).arg(( int )( unsigned char )res[i2] ).toLatin1() );
@ -1834,7 +1832,7 @@ void tst_QSqlQuery::oci_rawField()
} }
// test whether we can fetch values with more than DOUBLE precision // test whether we can fetch values with more than DOUBLE precision
// note that MySQL's 3.x highest precision is that of a double, although // note that SQLite highest precision is that of a double, although
// you can define field with higher precision // you can define field with higher precision
void tst_QSqlQuery::precision() void tst_QSqlQuery::precision()
{ {
@ -1845,46 +1843,41 @@ void tst_QSqlQuery::precision()
if (dbType == QSqlDriver::Interbase) if (dbType == QSqlDriver::Interbase)
QSKIP("DB unable to store high precision"); QSKIP("DB unable to store high precision");
const auto oldPrecision = db.driver()->numericalPrecisionPolicy();
db.driver()->setNumericalPrecisionPolicy(QSql::HighPrecision);
const QString qtest_precision(qTableName("qtest_precision", __FILE__, db)); const QString qtest_precision(qTableName("qtest_precision", __FILE__, db));
static const char precStr[] = "1.2345678901234567891"; static const QLatin1String precStr("1.2345678901234567891");
const int precStrLen = sizeof(precStr);
{ {
// need a new scope for SQLITE // need a new scope for SQLITE
QSqlQuery q( db ); QSqlQuery q( db );
q.exec("drop table " + qtest_precision); q.exec("drop table " + qtest_precision);
if ( tst_Databases::isMSAccess( db ) ) if (tst_Databases::isMSAccess(db))
QVERIFY_SQL( q, exec( "create table " + qtest_precision + " (col1 number)" ) ); QVERIFY_SQL(q, exec("CREATE TABLE " + qtest_precision + " (col1 number)"));
else else
QVERIFY_SQL( q, exec( "create table " + qtest_precision + " (col1 numeric(21, 20))" ) ); QVERIFY_SQL(q, exec("CREATE TABLE " + qtest_precision + " (col1 numeric(21, 20))"));
QVERIFY_SQL( q, exec( "insert into " + qtest_precision + " (col1) values (1.2345678901234567891)" ) ); QVERIFY_SQL(q, exec("INSERT INTO " + qtest_precision + " (col1) VALUES (" + precStr + ")"));
QVERIFY_SQL(q, exec("SELECT * FROM " + qtest_precision));
QVERIFY_SQL( q, exec( "select * from " + qtest_precision ) ); QVERIFY(q.next());
QVERIFY( q.next() ); const QString val = q.value(0).toString();
if (!val.startsWith(precStr)) {
QString val = q.value( 0 ).toString();
if ( !val.startsWith( "1.2345678901234567891" ) ) {
int i = 0; int i = 0;
while (i < val.size() && precStr[i] != 0 && precStr[i] == val[i].toLatin1())
while ( i < precStrLen && i < val.size() && precStr[i] != 0 && *( precStr + i ) == val[i].toLatin1() )
i++; i++;
// MySQL and TDS have crappy precisions by default // TDS has crappy precisions by default
if (dbType == QSqlDriver::MySqlServer) { if (dbType == QSqlDriver::Sybase) {
if ( i < 17 ) if (i < 18)
QWARN( "MySQL didn't return the right precision" ); QWARN("TDS didn't return the right precision");
} else if (dbType == QSqlDriver::Sybase) {
if ( i < 18 )
QWARN( "TDS didn't return the right precision" );
} else { } else {
QWARN( QString( tst_Databases::dbToString( db ) + " didn't return the right precision (" + QWARN(QString(tst_Databases::dbToString(db) + " didn't return the right precision (" +
QString::number( i ) + " out of 21), " + val ).toLatin1() ); QString::number(i) + " out of 21), " + val).toUtf8());
} }
} }
} // SQLITE scope } // SQLITE scope
db.driver()->setNumericalPrecisionPolicy(oldPrecision);
} }
void tst_QSqlQuery::nullResult() void tst_QSqlQuery::nullResult()
@ -2840,10 +2833,11 @@ void tst_QSqlQuery::psql_bindWithDoubleColonCastOperator()
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QVERIFY_SQL( q, next() ); QVERIFY_SQL( q, next() );
if ( db.driver()->hasFeature( QSqlDriver::PreparedQueries ) ) // the positional placeholders are converted to named placeholders in executedQuery()
QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = ? and id2 =? and id3=?" ) ); if (db.driver()->hasFeature(QSqlDriver::PreparedQueries))
QCOMPARE(q.executedQuery(), QString("select sum((fld1 - fld2)::int) from " + tablename + " where id1 = :myid1 and id2 =:myid2 and id3=:myid3"));
else else
QCOMPARE( q.executedQuery(), QString( "select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3" ) ); QCOMPARE(q.executedQuery(), QString("select sum((fld1 - fld2)::int) from " + tablename + " where id1 = 1 and id2 =2 and id3=3"));
} }
void tst_QSqlQuery::psql_specialFloatValues() void tst_QSqlQuery::psql_specialFloatValues()
@ -4003,8 +3997,8 @@ void tst_QSqlQuery::QTBUG_2192()
// Check if retrieved value preserves reported precision // Check if retrieved value preserves reported precision
int precision = qMax(0, q.record().field("dt").precision()); int precision = qMax(0, q.record().field("dt").precision());
int diff = qAbs(q.value(0).toDateTime().msecsTo(dt)); qint64 diff = qAbs(q.value(0).toDateTime().msecsTo(dt));
int keep = qMin(1000, (int)qPow(10.0, precision)); qint64 keep = qMin(1000LL, qRound64(qPow(10.0, precision)));
QVERIFY(diff <= 1000 - keep); QVERIFY(diff <= 1000 - keep);
} }
} }
@ -4021,8 +4015,10 @@ void tst_QSqlQuery::QTBUG_36211()
QSqlQuery q(db); QSqlQuery q(db);
QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dtwtz timestamptz, dtwotz timestamp)").arg(tableName))); QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dtwtz timestamptz, dtwotz timestamp)").arg(tableName)));
QTimeZone l_tzBrazil("BRT"); QTimeZone l_tzBrazil("America/Sao_Paulo");
QTimeZone l_tzChina("CST"); QTimeZone l_tzChina("Asia/Shanghai");
QVERIFY(l_tzBrazil.isValid());
QVERIFY(l_tzChina.isValid());
QDateTime dt = QDateTime(QDate(2014, 10, 30), QTime(14, 12, 02, 357)); QDateTime dt = QDateTime(QDate(2014, 10, 30), QTime(14, 12, 02, 357));
QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " (dtwtz, dtwotz) VALUES (:dt, :dt)")); QVERIFY_SQL(q, prepare("INSERT INTO " + tableName + " (dtwtz, dtwotz) VALUES (:dt, :dt)"));
q.bindValue(":dt", dt); q.bindValue(":dt", dt);
@ -4040,8 +4036,8 @@ void tst_QSqlQuery::QTBUG_36211()
for (int j = 0; j < 2; ++j) { for (int j = 0; j < 2; ++j) {
// Check if retrieved value preserves reported precision // Check if retrieved value preserves reported precision
int precision = qMax(0, q.record().field(j).precision()); int precision = qMax(0, q.record().field(j).precision());
int diff = qAbs(q.value(j).toDateTime().msecsTo(dt)); qint64 diff = qAbs(q.value(j).toDateTime().msecsTo(dt));
int keep = qMin(1000, (int)qPow(10.0, precision)); qint64 keep = qMin(1000LL, qRound64(qPow(10.0, precision)));
QVERIFY(diff <= 1000 - keep); QVERIFY(diff <= 1000 - keep);
} }
} }

View File

@ -1380,6 +1380,7 @@ void tst_QFiledialog::clearLineEdit()
fd.setFileMode(QFileDialog::AnyFile); fd.setFileMode(QFileDialog::AnyFile);
fd.show(); fd.show();
QVERIFY(QTest::qWaitForWindowExposed(&fd));
QLineEdit *lineEdit = fd.findChild<QLineEdit*>("fileNameEdit"); QLineEdit *lineEdit = fd.findChild<QLineEdit*>("fileNameEdit");
QVERIFY(lineEdit); QVERIFY(lineEdit);
QCOMPARE(lineEdit->text(), QLatin1String("foo")); QCOMPARE(lineEdit->text(), QLatin1String("foo"));

View File

@ -60,6 +60,7 @@
#include <QtGui/qpaintengine.h> #include <QtGui/qpaintengine.h>
#include <QtGui/qbackingstore.h> #include <QtGui/qbackingstore.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformwindow.h>
#include <QtGui/qscreen.h> #include <QtGui/qscreen.h>
#include <qmenubar.h> #include <qmenubar.h>
#include <qcompleter.h> #include <qcompleter.h>
@ -227,6 +228,7 @@ private slots:
void setFixedSize(); void setFixedSize();
void ensureCreated(); void ensureCreated();
void createAndDestroy();
void winIdChangeEvent(); void winIdChangeEvent();
void persistentWinId(); void persistentWinId();
void showNativeChild(); void showNativeChild();
@ -4250,6 +4252,58 @@ public:
int winIdChangeEventCount() const { return m_winIdList.count(); } int winIdChangeEventCount() const { return m_winIdList.count(); }
}; };
class CreateDestroyWidget : public WinIdChangeWidget
{
public:
void create() { QWidget::create(); }
void destroy() { QWidget::destroy(); }
};
void tst_QWidget::createAndDestroy()
{
CreateDestroyWidget widget;
// Create and destroy via QWidget
widget.create();
QVERIFY(widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 1);
QVERIFY(widget.internalWinId());
widget.destroy();
QVERIFY(!widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 2);
QVERIFY(!widget.internalWinId());
// Create via QWidget, destroy via QWindow
widget.create();
QVERIFY(widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 3);
QVERIFY(widget.internalWinId());
widget.windowHandle()->destroy();
QVERIFY(!widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 4);
QVERIFY(!widget.internalWinId());
// Create via QWidget again
widget.create();
QVERIFY(widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 5);
QVERIFY(widget.internalWinId());
// Destroy via QWindow, create via QWindow
widget.windowHandle()->destroy();
QVERIFY(widget.windowHandle());
QVERIFY(!widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 6);
QVERIFY(!widget.internalWinId());
widget.windowHandle()->create();
QVERIFY(widget.testAttribute(Qt::WA_WState_Created));
QCOMPARE(widget.winIdChangeEventCount(), 7);
QVERIFY(widget.internalWinId());
}
void tst_QWidget::winIdChangeEvent() void tst_QWidget::winIdChangeEvent()
{ {
{ {

View File

@ -885,9 +885,6 @@ void tst_QLineEdit::hasAcceptableInputMask()
qApp->sendEvent(testWidget, &lostFocus); qApp->sendEvent(testWidget, &lostFocus);
QVERIFY(validInput); QVERIFY(validInput);
// at the moment we don't strip the blank character if it is valid input, this makes the test between x vs X useless
QEXPECT_FAIL( "Any optional and required", "To eat blanks or not? Known issue. Task 43172", Abort);
// test requiredMask // test requiredMask
testWidget->setInputMask(requiredMask); testWidget->setInputMask(requiredMask);
validInput = true; validInput = true;

View File

@ -155,6 +155,7 @@ private slots:
#if QT_CONFIG(scrollbar) #if QT_CONFIG(scrollbar)
void updateAfterChangeCenterOnScroll(); void updateAfterChangeCenterOnScroll();
#endif #endif
void updateCursorPositionAfterEdit();
private: private:
void createSelection(); void createSelection();
@ -1802,5 +1803,50 @@ void tst_QPlainTextEdit::updateAfterChangeCenterOnScroll()
#endif #endif
void tst_QPlainTextEdit::updateCursorPositionAfterEdit()
{
QPlainTextEdit plaintextEdit;
plaintextEdit.setPlainText("some text some text\nsome text some text");
const auto initialPosition = 1;
// select some text
auto cursor = plaintextEdit.textCursor();
cursor.setPosition(initialPosition, QTextCursor::MoveAnchor);
cursor.setPosition(initialPosition + 3, QTextCursor::KeepAnchor);
plaintextEdit.setTextCursor(cursor);
QVERIFY(plaintextEdit.textCursor().hasSelection());
QTest::keyClick(&plaintextEdit, Qt::Key_Delete);
QTest::keyClick(&plaintextEdit, Qt::Key_Down);
QTest::keyClick(&plaintextEdit, Qt::Key_Up);
// Moving the cursor down and up should bring it to the initial position
QCOMPARE(plaintextEdit.textCursor().position(), initialPosition);
// Test the same with backspace
cursor = plaintextEdit.textCursor();
cursor.setPosition(initialPosition + 3, QTextCursor::KeepAnchor);
plaintextEdit.setTextCursor(cursor);
QVERIFY(plaintextEdit.textCursor().hasSelection());
QTest::keyClick(&plaintextEdit, Qt::Key_Backspace);
QTest::keyClick(&plaintextEdit, Qt::Key_Down);
QTest::keyClick(&plaintextEdit, Qt::Key_Up);
// Moving the cursor down and up should bring it to the initial position
QCOMPARE(plaintextEdit.textCursor().position(), initialPosition);
// Test insertion
const QString txt("txt");
QApplication::clipboard()->setText(txt);
plaintextEdit.paste();
QTest::keyClick(&plaintextEdit, Qt::Key_Down);
QTest::keyClick(&plaintextEdit, Qt::Key_Up);
// The curser should move back to the end of the copied text
QCOMPARE(plaintextEdit.textCursor().position(), initialPosition + txt.length());
}
QTEST_MAIN(tst_QPlainTextEdit) QTEST_MAIN(tst_QPlainTextEdit)
#include "tst_qplaintextedit.moc" #include "tst_qplaintextedit.moc"

View File

@ -30,7 +30,7 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <QtCore/private/qmemory_p.h> #include <QtCore/private/qmemory_p.h>
#include <mutex> #include <mutex>
#if QT_HAS_INCLUDE(<shared_mutex>) #if __has_include(<shared_mutex>)
#if __cplusplus > 201103L #if __cplusplus > 201103L
#include <shared_mutex> #include <shared_mutex>
#endif #endif

View File

@ -39,6 +39,7 @@
#include <QButtonGroup> #include <QButtonGroup>
#include <QLineEdit> #include <QLineEdit>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QTabWidget>
#include <QScrollBar> #include <QScrollBar>
#include <QSlider> #include <QSlider>
#include <QSpinBox> #include <QSpinBox>
@ -51,12 +52,14 @@
#include <QGraphicsView> #include <QGraphicsView>
#include <QGraphicsTextItem> #include <QGraphicsTextItem>
#include <QFile> #include <QFile>
#include <QFontMetrics>
#include <QMouseEvent> #include <QMouseEvent>
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTimer> #include <QTimer>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QCommandLineOption> #include <QCommandLineOption>
#include <QDebug> #include <QDebug>
#include <QElapsedTimer>
#include <private/qhighdpiscaling_p.h> #include <private/qhighdpiscaling_p.h>
#include <qpa/qplatformscreen.h> #include <qpa/qplatformscreen.h>
@ -64,6 +67,12 @@
#include <utility> #include <utility>
static QTextStream &operator<<(QTextStream &str, const QSizeF &s)
{
str << s.width() << 'x' << s.height();
return str;
}
static QTextStream &operator<<(QTextStream &str, const QRect &r) static QTextStream &operator<<(QTextStream &str, const QRect &r)
{ {
str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; str << r.width() << 'x' << r.height() << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
@ -1241,7 +1250,7 @@ public:
} }
}; };
class MetricsTest : public QWidget class MetricsTest : public QTabWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -1258,14 +1267,25 @@ QT_SCREEN_SCALE_FACTORS=N;N;N or QT_SCREEN_SCALE_FACTORS=name:N
QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough
QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)"; QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)";
resize(480, 360); m_textEdit = addTextPage("Parameters");
m_logEdit = addTextPage("Screen Change Log");
auto layout = new QVBoxLayout(this); const auto screens = QGuiApplication::screens();
for (auto screen : screens)
connectScreenChangeSignals(screen);
connect(qApp, &QGuiApplication::screenAdded, this, &MetricsTest::slotScreenAdded);
connect(qApp, &QGuiApplication::primaryScreenChanged, this, &MetricsTest::slotPrimaryScreenChanged);
connect(qApp, &QGuiApplication::screenRemoved, this, &MetricsTest::slotScreenRemoved);
m_textEdit = new QPlainTextEdit;
m_textEdit->setReadOnly(true);
layout->addWidget(m_textEdit);
setWindowTitle(formatWindowTitle("Screens")); setWindowTitle(formatWindowTitle("Screens"));
m_logTimer.start();
logMessage(briefFormatScreens());
// Resize to roughly match the metrics text.
const auto metrics = QFontMetrics(m_textEdit->font(), m_textEdit);
const int width = 10 + metrics.horizontalAdvance(QStringLiteral("X")) * 50;
const int height = 40 + metrics.height() * (10 + 8 * screens.size());
resize(width, height);
} }
void setVisible(bool visible) override void setVisible(bool visible) override
@ -1323,15 +1343,118 @@ QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)";
private slots: private slots:
void screenChanged() void screenChanged()
{ {
qDebug().noquote() << __FUNCTION__ << windowHandle()->screen()->name(); const QString message = QLatin1String("screenChanged ") + windowHandle()->screen()->name();
qInfo("%s", qPrintable(message));
logMessage(message);
updateMetrics(); updateMetrics();
} }
void slotScreenAdded(QScreen *);
void slotScreenRemoved(QScreen *);
void slotPrimaryScreenChanged(QScreen *);
void slotScreenGeometryChanged(const QRect &geometry)
{ logScreenChangeSignal(sender(), "geometry", geometry); }
void slotScreenAvailableGeometryChanged(const QRect &geometry)
{ logScreenChangeSignal(sender(), "availableGeometry", geometry); }
void slotScreenPhysicalSizeChanged(const QSizeF &size)
{ logScreenChangeSignal(sender(), "physicalSize", size); }
void slotScreenPhysicalDotsPerInchChanged(qreal dpi)
{ logScreenChangeSignal(sender(), "physicalDotsPerInch", dpi); }
void slotScreenLogicalDotsPerInchChanged(qreal dpi)
{ logScreenChangeSignal(sender(), "logicalDotsPerInch", dpi); }
void slotScreenVirtualGeometryChanged(const QRect &rect)
{ logScreenChangeSignal(sender(), "virtualGeometry", rect); }
void slotScreenPrimaryOrientationChanged(Qt::ScreenOrientation orientation)
{ logScreenChangeSignal(sender(), "primaryOrientation", orientation); }
void slotScreenOrientationChanged(Qt::ScreenOrientation orientation)
{ logScreenChangeSignal(sender(), "orientation", orientation); }
void slotScreenRefreshRateChanged(qreal refreshRate)
{ logScreenChangeSignal(sender(), "refreshRate", refreshRate); }
private: private:
QPlainTextEdit *addTextPage(const QString &title);
void logMessage(const QString &);
void connectScreenChangeSignals(QScreen *s);
static QString briefFormatScreens();
template <class T>
void logScreenChangeSignal(const QObject *o, const char *name, const T &value);
QPlainTextEdit *m_textEdit; QPlainTextEdit *m_textEdit;
QPlainTextEdit *m_logEdit;
QElapsedTimer m_logTimer;
bool m_screenChangedConnected = false; bool m_screenChangedConnected = false;
}; };
void MetricsTest::slotScreenAdded(QScreen *screen)
{
logMessage(QLatin1String("Added ") + screen->name() + QLatin1Char(' ')
+ briefFormatScreens());
connectScreenChangeSignals(screen);
}
void MetricsTest::slotScreenRemoved(QScreen *screen)
{
logMessage(QLatin1String("Removed ") + screen->name() + QLatin1Char(' ')
+ briefFormatScreens());
}
void MetricsTest::slotPrimaryScreenChanged(QScreen *screen)
{
logMessage(QLatin1String("PrimaryScreenChanged ") + screen->name() + QLatin1Char(' ')
+ briefFormatScreens());
}
QPlainTextEdit *MetricsTest::addTextPage(const QString &title)
{
auto result = new QPlainTextEdit(this);
result->setReadOnly(true);
result->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
addTab(result, title);
return result;
}
void MetricsTest::logMessage(const QString &m)
{
const QString timeStamp =
QStringLiteral("%1ms: %2").arg(m_logTimer.elapsed(), 6, 10, QLatin1Char('0')).arg(m);
m_logEdit->appendPlainText(timeStamp);
}
void MetricsTest::connectScreenChangeSignals(QScreen *s)
{
connect(s, &QScreen::geometryChanged, this, &MetricsTest::slotScreenGeometryChanged);
connect(s, &QScreen::availableGeometryChanged, this, &MetricsTest::slotScreenAvailableGeometryChanged);
connect(s, &QScreen::physicalSizeChanged, this, &MetricsTest::slotScreenPhysicalSizeChanged);
connect(s, &QScreen::physicalDotsPerInchChanged, this, &MetricsTest::slotScreenPhysicalDotsPerInchChanged);
connect(s, &QScreen::logicalDotsPerInchChanged, this, &MetricsTest::slotScreenLogicalDotsPerInchChanged);
connect(s, &QScreen::virtualGeometryChanged, this, &MetricsTest::slotScreenVirtualGeometryChanged);
connect(s, &QScreen::primaryOrientationChanged, this, &MetricsTest::slotScreenPrimaryOrientationChanged);
connect(s, &QScreen::orientationChanged, this, &MetricsTest::slotScreenOrientationChanged);
connect(s, &QScreen::refreshRateChanged, this, &MetricsTest::slotScreenRefreshRateChanged);
}
QString MetricsTest::briefFormatScreens()
{
QString message;
QTextStream str(&message);
const auto screens = QGuiApplication::screens();
for (int i = 0, size = screens.size(); i < size; ++i) {
str << (i ? ", " : "(");
str << screens.at(i)->name() << " " << screens.at(i)->geometry();
}
str << ')';
return message;
}
template <class T>
void MetricsTest::logScreenChangeSignal(const QObject *o, const char *name, const T &value)
{
auto screen = qobject_cast<const QScreen *>(o);
QString message;
QTextStream(&message) << (screen ? screen->name() : QString()) << ' ' << name << " changed: " << value;
logMessage(message);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#define NOSCALINGOPTION "noscaling" #define NOSCALINGOPTION "noscaling"

View File

@ -1,11 +1,20 @@
version: '2.1' version: '2.1'
# The tag of images is used by docker compose file to launch the corresponding # The tag of images is used by docker compose file to launch the correct
# docker containers. The value of tag comes from the provisioning script # docker containers. By default we always launch the "latest" tag.
# (coin/provisioning/.../testserver/docker_testserver.sh). The script gets SHA-1 #
# of each server context as the tag of docker images. If one of the server # But in the "docker build" phase, we also tag the images with a unique tag,
# contexts gets changes, please make sure to update this compose file as well. # the SHA1 hash of all files used for "docker build" - see sha1tree() in
# You can run command 'docker images' to list all the tags of test server images. # provisioning.
#
# So if you want to update the docker image at a specific time, make sure that
# 1. you modify this file to run the specific image's SHA1 tag, instead of
# "latest"
# 2. you build two docker images in provisioning, the currently used one,
# plus the new one that you tag as "latest"
# 3. you switch this file to the "latest" tag when ready
# You can run `docker images` to list all the tags of available images:
# For example: # For example:
# REPOSITORY TAG # REPOSITORY TAG
# qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13 # qt-test-server-apache2 537fe302f61851d1663f41495230d8e3554a4a13
@ -20,7 +29,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-apache2:537fe302f61851d1663f41495230d8e3554a4a13 provisioningImage: qt-test-server-apache2:latest
shareDir: ./common shareDir: ./common
serviceDir: ./apache2 serviceDir: ./apache2
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -43,7 +52,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-squid:9c32f41b19aca3d778733c4d8fb0ecc5955e893c provisioningImage: qt-test-server-squid:latest
shareDir: ./common shareDir: ./common
serviceDir: ./squid serviceDir: ./squid
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -58,7 +67,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-vsftpd:f3a9c8d793a77cc007c0e4e481bec01f9e3eeb7e provisioningImage: qt-test-server-vsftpd:latest
shareDir: ./common shareDir: ./common
serviceDir: ./vsftpd serviceDir: ./vsftpd
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -77,7 +86,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-ftp-proxy:d7de8b28392d173db512a558ccc84ead8bece2ae provisioningImage: qt-test-server-ftp-proxy:latest
shareDir: ./common shareDir: ./common
serviceDir: ./ftp-proxy serviceDir: ./ftp-proxy
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -102,7 +111,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-danted:35607f9b790524cf9690c7d12a9a401696b7b6b5 provisioningImage: qt-test-server-danted:latest
shareDir: ./common shareDir: ./common
serviceDir: ./danted serviceDir: ./danted
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -117,7 +126,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-cyrus:c8d72754abc0e501afd624ce838e4df35505abc9 provisioningImage: qt-test-server-cyrus:latest
shareDir: ./common shareDir: ./common
serviceDir: ./cyrus serviceDir: ./cyrus
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -132,7 +141,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-iptables:cb7a8bd6d28602085a88c8ced7d67e28e75781e2 provisioningImage: qt-test-server-iptables:latest
shareDir: ./common shareDir: ./common
serviceDir: ./iptables serviceDir: ./iptables
entrypoint: service/startup.sh entrypoint: service/startup.sh
@ -150,7 +159,7 @@ services:
build: build:
context: . context: .
args: args:
provisioningImage: qt-test-server-echo:b29ad409e746a834c1055fd0f7a55fd5056da6ea provisioningImage: qt-test-server-echo:latest
shareDir: ./common shareDir: ./common
serviceDir: ./echo serviceDir: ./echo
entrypoint: service/startup.sh entrypoint: service/startup.sh

Some files were not shown because too many files have changed in this diff Show More