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

Change-Id: Ib4df563fc7b1f7c40f425e0e71180d9517a672be
This commit is contained in:
Qt Forward Merge Bot 2019-10-30 01:00:14 +01:00
commit a317bff298
25 changed files with 5705 additions and 4233 deletions

View File

@ -734,7 +734,13 @@ defineTest(qtConfOutput_preparePaths) {
}
have_prefix = false
} else {
config.input.prefix = $$absolute_path($$config.input.prefix, $$OUT_PWD)
equals(XSPEC, $$[QMAKE_SPEC]) {
# Only make the user-specified prefix absolute if we're not cross-compiling.
config.input.prefix = $$absolute_path($$config.input.prefix, $$OUT_PWD)
} else {
# But we still must normalize path separators.
config.input.prefix = $$replace(config.input.prefix, \\\\, /)
}
have_prefix = true
}

View File

@ -25,14 +25,16 @@ defineTest(addInstallFiles) {
export($$1)
}
probase = $$relative_path($$_PRO_FILE_PWD_, $$dirname(_QMAKE_CONF_)/examples)
moduleRoot = $$dirname(_QMAKE_CONF_)
probase = $$relative_path($$_PRO_FILE_PWD_, $$moduleRoot/examples)
isEmpty(probase)|contains(probase, ^\\..*): \
return()
isEmpty(_QMAKE_CACHE_) {
!equals(OUT_PWD, $$_PRO_FILE_PWD_): \
return()
error("You cannot build examples inside the Qt source tree, except as part of a proper Qt build.")
moduleRootRelativeToBuildDir = $$relative_path($$moduleRoot, $$OUT_PWD)
# Check if OUT_PWD is inside module root
equals(moduleRootRelativeToBuildDir, .)|contains(moduleRootRelativeToBuildDir, \(\.\./\)+\(\.\.\)?): \
error("You cannot build examples inside the Qt source tree, except as part of a proper Qt build.")
}
contains(TEMPLATE, "vc.*"): \

View File

@ -1,42 +0,0 @@
From 3442a3ce9c2bd366eb0bd1c18d37a6ce732a888d Mon Sep 17 00:00:00 2001
From: Andy Shaw <andy.shaw@qt.io>
Date: Wed, 25 Sep 2019 09:17:01 +0200
Subject: [PATCH] Fix CVE-2019-16168 in SQLite
v3.29.0 is the latest and there is no indication as to when the next
release is so we will apply this separately for now and it can be
reverted once it is in a release that we ship with.
This patch is taken from https://www.sqlite.org/src/info/98357d8c1263920b
Change-Id: I82d398b093b67842a4369e3220c01e7eea30763a
---
src/3rdparty/sqlite/sqlite3.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 61bfdeb766..b3e6ae27b6 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -105933,7 +105933,9 @@ static void decodeIntArray(
if( sqlite3_strglob("unordered*", z)==0 ){
pIndex->bUnordered = 1;
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
- pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
+ int sz = sqlite3Atoi(z+3);
+ if( sz<2 ) sz = 2;
+ pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
}
@@ -143260,6 +143262,7 @@ static int whereLoopAddBtreeIndex(
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
+ assert( pSrc->pTab->szTabRow>0 );
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
--
2.20.1 (Apple Git-117)

View File

@ -6,8 +6,8 @@
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "https://www.sqlite.org/",
"Version": "3.29.0",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3290000.zip",
"Version": "3.30.1",
"DownloadLocation": "https://www.sqlite.org/2019/sqlite-amalgamation-3300100.zip",
"License": "Public Domain",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
}

File diff suppressed because it is too large Load Diff

View File

@ -123,9 +123,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.29.0"
#define SQLITE_VERSION_NUMBER 3029000
#define SQLITE_SOURCE_ID "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88bfa6"
#define SQLITE_VERSION "3.30.1"
#define SQLITE_VERSION_NUMBER 3030001
#define SQLITE_SOURCE_ID "2019-10-10 20:19:45 18db032d058f1436ce3dea84081f4ee5a0f2259ad97301d43c426bc7f3df1b0b"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -2093,6 +2093,17 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
** There should be two additional arguments.
** The first argument is an integer which is 0 to disable views,
** positive to enable views or negative to leave the setting unchanged.
** The second parameter is a pointer to an integer into which
** is written 0 or 1 to indicate whether views are disabled or enabled
** following this call. The second parameter may be a NULL pointer, in
** which case the view setting is not reported back. </dd>
**
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
** <dd> ^This option is used to enable or disable the
@ -2265,7 +2276,8 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_LEGACY_ALTER_TABLE 1012 /* int int* */
#define SQLITE_DBCONFIG_DQS_DML 1013 /* int int* */
#define SQLITE_DBCONFIG_DQS_DDL 1014 /* int int* */
#define SQLITE_DBCONFIG_MAX 1014 /* Largest DBCONFIG */
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_MAX 1015 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@ -3814,7 +3826,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** ^The specific value of WHERE-clause [parameter] might influence the
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
** </li>
** </ol>
**
@ -4849,6 +4861,12 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^The fourth parameter may also optionally include the [SQLITE_DIRECTONLY]
** flag, which if present prevents the function from being invoked from
** within VIEWs or TRIGGERs. For security reasons, the [SQLITE_DIRECTONLY]
** flag is recommended for any application-defined SQL function that has
** side-effects.
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
**
@ -4965,8 +4983,30 @@ SQLITE_API int sqlite3_create_window_function(
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
**
** The SQLITE_DETERMINISTIC flag means that the new function will always
** maps the same inputs into the same output. The abs() function is
** deterministic, for example, but randomblob() is not.
**
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
** from top-level SQL, and cannot be used in VIEWs or TRIGGERs. This is
** a security feature which is recommended for all
** [application-defined SQL functions] that have side-effects. This flag
** prevents an attacker from adding triggers and views to a schema then
** tricking a high-privilege application into causing unintended side-effects
** while performing ordinary queries.
**
** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
** Specifying this flag makes no difference for scalar or aggregate user
** functions. However, if it is not specified for a user-defined window
** function, then any sub-types belonging to arguments passed to the window
** function may be discarded before the window function is called (i.e.
** sqlite3_value_subtype() will always return 0).
*/
#define SQLITE_DETERMINISTIC 0x800
#define SQLITE_DETERMINISTIC 0x000000800
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
/*
** CAPI3REF: Deprecated Functions
@ -6612,6 +6652,12 @@ struct sqlite3_index_info {
** ^The sqlite3_create_module()
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
**
** ^If the third parameter (the pointer to the sqlite3_module object) is
** NULL then no new module is create and any existing modules with the
** same name are dropped.
**
** See also: [sqlite3_drop_modules()]
*/
SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
@ -6627,6 +6673,23 @@ SQLITE_API int sqlite3_create_module_v2(
void(*xDestroy)(void*) /* Module destructor function */
);
/*
** CAPI3REF: Remove Unnecessary Virtual Table Implementations
** METHOD: sqlite3
**
** ^The sqlite3_drop_modules(D,L) interface removes all virtual
** table modules from database connection D except those named on list L.
** The L parameter must be either NULL or a pointer to an array of pointers
** to strings where the array is terminated by a single NULL pointer.
** ^If the L parameter is NULL, then all virtual table modules are removed.
**
** See also: [sqlite3_create_module()]
*/
SQLITE_API int sqlite3_drop_modules(
sqlite3 *db, /* Remove modules from this connection */
const char **azKeep /* Except, do not remove the ones named here */
);
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
@ -7335,7 +7398,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_FIRST 5
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@ -7358,7 +7421,9 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_IMPOSTER 25
#define SQLITE_TESTCTRL_PARSER_COVERAGE 26
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
#define SQLITE_TESTCTRL_LAST 27 /* Largest TESTCTRL */
#define SQLITE_TESTCTRL_PRNG_SEED 28
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking

View File

@ -168,6 +168,9 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild)
-D CMAKE_FIND_ROOT_PATH_MODE_INCLUDE=${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}
-D CMAKE_FIND_ROOT_PATH_MODE_PACKAGE=${CMAKE_FIND_ROOT_PATH_MODE_PACKAGE}
-D CMAKE_SHARED_LIBRARY_SUFFIX_CXX=_${android_abi}.so
-D CMAKE_SHARED_MODULE_SUFFIX_CXX=_${android_abi}.so
-D CMAKE_SHARED_LIBRARY_SUFFIX_C=_${android_abi}.so
-D CMAKE_SHARED_MODULE_SUFFIX_C=_${android_abi}.so
-D CMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_BINARY_DIR}/android-build/libs/${android_abi}
-D ${PROJECT_NAME}-MultiAbiBuild=ON
)
@ -181,7 +184,10 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild)
else()
# For the default abi just use the regular cmake run, to have
# nice IDE integration and so on
set(CMAKE_SHARED_MODULE_SUFFIX_CXX "_${ANDROID_ABI}.so")
set(CMAKE_SHARED_LIBRARY_SUFFIX_CXX "_${ANDROID_ABI}.so")
set(CMAKE_SHARED_MODULE_SUFFIX_C "_${ANDROID_ABI}.so")
set(CMAKE_SHARED_LIBRARY_SUFFIX_C "_${ANDROID_ABI}.so")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/android-build/libs/${ANDROID_ABI})
endif()
endforeach()

View File

@ -919,6 +919,16 @@ QThreadPrivate::~QThreadPrivate()
delete data;
}
void QThread::setStackSize(uint stackSize)
{
Q_UNUSED(stackSize);
}
uint QThread::stackSize() const
{
return 0;
}
#endif // QT_CONFIG(thread)
/*!

View File

@ -113,11 +113,12 @@ Qt::DropAction QDragManager::drag(QDrag *o)
m_object->d_func()->target = 0;
QGuiApplicationPrivate::instance()->notifyDragStarted(o);
QGuiApplicationPrivate::instance()->notifyDragStarted(m_object.data());
const Qt::DropAction result = m_platformDrag->drag(m_object);
m_object = 0;
if (!m_platformDrag->ownsDragObject())
o->deleteLater();
if (!m_object.isNull() && !m_platformDrag->ownsDragObject())
m_object->deleteLater();
m_object.clear();
return result;
}

View File

@ -101,13 +101,13 @@ public:
void setCurrentTarget(QObject *target, bool dropped = false);
QObject *currentTarget() const;
QDrag *object() const { return m_object; }
QPointer<QDrag> object() const { return m_object; }
QObject *source() const;
private:
QObject *m_currentDropTarget;
QPlatformDrag *m_platformDrag;
QDrag *m_object;
QPointer<QDrag> m_object;
static QDragManager *m_instance;
Q_DISABLE_COPY_MOVE(QDragManager)

View File

@ -279,8 +279,11 @@ Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defa
}
d->supported_actions = supportedActions;
d->default_action = transformedDefaultDropAction;
d->executed_action = QDragManager::self()->drag(this);
QPointer<QDrag> self = this;
auto executed_action = QDragManager::self()->drag(self.data());
if (self.isNull())
return Qt::IgnoreAction;
d->executed_action = executed_action;
return d->executed_action;
}

View File

@ -828,7 +828,8 @@ void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrima
*/
void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
{
// Important to keep this order since the QSceen doesn't own the platform screen
// Important to keep this order since the QSceen doesn't own the platform screen.
// The QScreen destructor will take care changing the primary screen, so no need here.
delete platformScreen->screen();
delete platformScreen;
}

View File

@ -1512,17 +1512,6 @@ bool QCocoaWindow::updatesWithDisplayLink() const
void QCocoaWindow::deliverUpdateRequest()
{
// Don't send update requests for views that need display, as the update
// request doesn't carry any information about dirty rects, so the app
// may end up painting a smaller region than required. (For some reason
// the layer and view's needsDisplay status isn't always in sync, even if
// the view is layer-backed, not layer-hosted, so we check both).
if (m_view.layer.needsDisplay || m_view.needsDisplay) {
qCDebug(lcQpaDrawing) << "View needs display, deferring update request for" << window();
requestUpdate();
return;
}
qCDebug(lcQpaDrawing) << "Delivering update request to" << window();
QPlatformWindow::deliverUpdateRequest();
}

View File

@ -17,7 +17,7 @@
<body onload="init()">
<figure style="overflow:visible;" id="qtspinner">
<center style="margin-top:1.5em; line-height:150%">
<img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
<img src="qtlogo.svg" width="320" height="200" style="display:block"></img>
<strong>Qt for WebAssembly: @APPNAME@</strong>
<div id="qtstatus"></div>
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>

View File

@ -354,6 +354,11 @@ bool QXcbDrag::findXdndAwareTarget(const QPoint &globalPos, xcb_window_t *target
void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods)
{
// currentDrag() might be deleted while 'drag' is progressing
if (!currentDrag()) {
cancel();
return;
}
// The source sends XdndEnter and XdndPosition to the target.
if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid())
return;
@ -1076,7 +1081,8 @@ void QXcbDrag::cancel()
send_leave();
// remove canceled object
currentDrag()->deleteLater();
if (currentDrag())
currentDrag()->deleteLater();
canceled = true;
}

View File

@ -1528,7 +1528,7 @@ void TestMethods::invokeTests(QObject *testObject) const
QTestResult::setCurrentTestFunction(nullptr);
}
#if defined(Q_OS_UNIX)
#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
class FatalSignalHandler
{
public:
@ -1928,7 +1928,7 @@ int QTest::qRun()
} else
#endif
{
#if defined(Q_OS_UNIX)
#if defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
QScopedPointer<FatalSignalHandler> handler;
if (!noCrashHandler)
handler.reset(new FatalSignalHandler);

View File

@ -504,7 +504,7 @@ void QWellArray::keyPressEvent(QKeyEvent* e)
// Event filter to be installed on the dialog while in color-picking mode.
class QColorPickingEventFilter : public QObject {
public:
explicit QColorPickingEventFilter(QColorDialogPrivate *dp, QObject *parent = 0) : QObject(parent), m_dp(dp) {}
explicit QColorPickingEventFilter(QColorDialogPrivate *dp, QObject *parent) : QObject(parent), m_dp(dp) {}
bool eventFilter(QObject *, QEvent *event) override
{
@ -1611,7 +1611,7 @@ void QColorDialogPrivate::_q_pickScreenColor()
{
Q_Q(QColorDialog);
if (!colorPickingEventFilter)
colorPickingEventFilter = new QColorPickingEventFilter(this);
colorPickingEventFilter = new QColorPickingEventFilter(this, q);
q->installEventFilter(colorPickingEventFilter);
// If user pushes Escape, the last color before picking will be restored.
beforeScreenColorPicking = cs->currentColor();

View File

@ -4550,6 +4550,8 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co
}
#if QT_DEPRECATED_SINCE(5, 13)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
/*!
\obsolete
@ -4588,6 +4590,7 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
// Send post-notification.
itemChange(ItemTransformHasChanged, QVariant::fromValue<QTransform>(newTransform));
}
QT_WARNING_POP
#endif
/*!
@ -11524,9 +11527,12 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change)
str = "ItemFlagsHaveChanged";
break;
#if QT_DEPRECATED_SINCE(5, 14)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
case QGraphicsItem::ItemMatrixChange:
str = "ItemMatrixChange";
break;
QT_WARNING_POP
#endif
case QGraphicsItem::ItemParentChange:
str = "ItemParentChange";

View File

@ -35,59 +35,106 @@
#include <math.h>
#include <float.h>
namespace {
template <typename F> struct Fuzzy {};
/* Data taken from qglobal.h's implementation of qFuzzyCompare:
* qFuzzyCompare conflates values with fractional difference up to (and
* including) the given scale.
*/
template <> struct Fuzzy<double> { constexpr static double scale = 1e12; };
template <> struct Fuzzy<float> { constexpr static float scale = 1e5f; };
}
class tst_QNumeric: public QObject
{
Q_OBJECT
private slots:
void fuzzyCompare_data();
void fuzzyCompare();
void rawNaN_data();
void rawNaN();
// Support for floating-point:
template<typename F> inline void fuzzyCompare_data();
template<typename F> inline void fuzzyCompare();
template<typename F> inline void checkNaN(F nan);
template<typename F> inline void rawNaN_data();
template<typename F> inline void rawNaN();
#if QT_CONFIG(signaling_nan)
void distinctNaN();
template<typename F> inline void distinctNaN();
#endif
void generalNaN_data();
void generalNaN();
void infinity();
void classifyfp();
void floatDistance_data();
void floatDistance();
void floatDistance_double_data();
void floatDistance_double();
template<typename F, typename Whole> inline void generalNaN_data();
template<typename F, typename Whole> inline void generalNaN();
template<typename F> inline void infinity();
template<typename F> inline void classifyfp();
template<typename F, typename Count> inline void distance_data();
template<typename F, typename Count> inline void distance();
private slots:
// Floating-point tests:
void fuzzyCompareF_data() { fuzzyCompare_data<float>(); }
void fuzzyCompareF() { fuzzyCompare<float>(); }
void fuzzyCompareD_data() { fuzzyCompare_data<double>(); }
void fuzzyCompareD() { fuzzyCompare<double>(); }
void rawNaNF_data() { rawNaN_data<float>(); }
void rawNaNF() { rawNaN<float>(); }
void rawNaND_data() { rawNaN_data<double>(); }
void rawNaND() { rawNaN<double>(); }
#if QT_CONFIG(signaling_nan)
void distinctNaNF();
void distinctNaND() { distinctNaN<double>(); }
#endif
void generalNaNd_data() { generalNaN_data<double, quint64>(); }
void generalNaNd() { generalNaN<double, quint64>(); }
void generalNaNf_data() { generalNaN_data<float, quint32>(); }
void generalNaNf() { generalNaN<float, quint32>(); }
void infinityF() { infinity<float>(); }
void infinityD() { infinity<double>(); }
void classifyF() { classifyfp<float>(); }
void classifyD() { classifyfp<double>(); }
void floatDistance_data() { distance_data<float, quint32>(); }
void floatDistance() { distance<float, quint32>(); }
void doubleDistance_data() { distance_data<double, quint64>(); }
void doubleDistance() { distance<double, quint64>(); }
// Whole number tests:
void addOverflow_data();
void addOverflow();
void mulOverflow_data();
void mulOverflow();
void signedOverflow();
private:
void checkNaN(double nan);
};
// Floating-point tests:
template<typename F>
void tst_QNumeric::fuzzyCompare_data()
{
QTest::addColumn<double>("val1");
QTest::addColumn<double>("val2");
QTest::addColumn<F>("val1");
QTest::addColumn<F>("val2");
QTest::addColumn<bool>("isEqual");
const F zero(0), one(1), ten(10);
const F huge = Fuzzy<F>::scale, tiny = one / huge;
const F deci(.1), giga(1e9), nano(1e-9), big(1e7), small(1e-10);
QTest::newRow("zero") << 0.0 << 0.0 << true;
QTest::newRow("ten") << 10.0 << 10.0 << true;
QTest::newRow("large") << 1000000000.0 << 1000000000.0 << true;
QTest::newRow("small") << 0.00000000001 << 0.00000000001 << true;
QTest::newRow("eps") << 10.000000000000001 << 10.00000000000002 << true;
QTest::newRow("eps2") << 10.000000000000001 << 10.000000000000009 << true;
QTest::newRow("zero") << zero << zero << true;
QTest::newRow("ten") << ten << ten << true;
QTest::newRow("large") << giga << giga << true;
QTest::newRow("small") << small << small << true;
QTest::newRow("10+9*tiny==10") << (ten + 9 * tiny) << ten << true;
QTest::newRow("huge+.9==huge") << (huge + 9 * deci) << huge << true;
QTest::newRow("eps2") << (ten + tiny) << (ten + 2 * tiny) << true;
QTest::newRow("eps9") << (ten + tiny) << (ten + 9 * tiny) << true;
QTest::newRow("mis1") << 0.0 << 1.0 << false;
QTest::newRow("mis2") << 0.0 << 10000000.0 << false;
QTest::newRow("mis3") << 0.0 << 0.000000001 << false;
QTest::newRow("mis4") << 100000000.0 << 0.000000001 << false;
QTest::newRow("mis5") << 0.0000000001 << 0.000000001 << false;
QTest::newRow("0!=1") << zero << one << false;
QTest::newRow("0!=big") << zero << big << false;
QTest::newRow("0!=nano") << zero << nano << false;
QTest::newRow("giga!=nano") << giga << nano << false;
QTest::newRow("small!=nano") << small << nano << false;
QTest::newRow("huge+1.1!=huge") << (huge + 1 + deci) << huge << false;
QTest::newRow("1+1.1*tiny!=1") << (one + tiny * (one + deci)) << one << false;
}
template<typename F>
void tst_QNumeric::fuzzyCompare()
{
QFETCH(double, val1);
QFETCH(double, val2);
QFETCH(F, val1);
QFETCH(F, val2);
QFETCH(bool, isEqual);
QCOMPARE(::qFuzzyCompare(val1, val2), isEqual);
@ -101,11 +148,12 @@ void tst_QNumeric::fuzzyCompare()
# pragma GCC optimize "no-fast-math"
#endif
void tst_QNumeric::checkNaN(double nan)
template<typename F>
void tst_QNumeric::checkNaN(F nan)
{
#define CHECKNAN(value) \
do { \
const double v = (value); \
const F v = (value); \
QCOMPARE(qFpClassify(v), FP_NAN); \
QVERIFY(qIsNaN(v)); \
QVERIFY(!qIsFinite(v)); \
@ -134,211 +182,197 @@ void tst_QNumeric::checkNaN(double nan)
#undef CHECKNAN
}
template<typename F>
void tst_QNumeric::rawNaN_data()
{
#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404)
QSKIP("Non-conformant fast math mode is enabled, cannot run test");
#endif
QTest::addColumn<double>("nan");
QTest::addColumn<F>("nan");
QTest::newRow("quiet") << qQNaN();
QTest::newRow("quiet") << F(qQNaN());
#if QT_CONFIG(signaling_nan)
QTest::newRow("signaling") << qSNaN();
QTest::newRow("signaling") << F(qSNaN());
#endif
}
template<typename F>
void tst_QNumeric::rawNaN()
{
QFETCH(double, nan);
QFETCH(F, nan);
#ifdef Q_OS_WASM
# ifdef __asmjs
QEXPECT_FAIL("", "Fastcomp conflates quiet and signaling NaNs", Continue);
# endif // but the modern clang compiler handls it fine.
#endif
checkNaN(nan);
}
#if QT_CONFIG(signaling_nan)
template<typename F>
void tst_QNumeric::distinctNaN()
{
const double qnan = qQNaN();
const double snan = qSNaN();
QVERIFY(memcmp(&qnan, &snan, sizeof(double)) != 0);
const F qnan = qQNaN();
const F snan = qSNaN();
QVERIFY(memcmp(&qnan, &snan, sizeof(F)) != 0);
}
#endif
void tst_QNumeric::distinctNaNF() {
#ifdef Q_CC_MSVC
QEXPECT_FAIL("", "MSVC's float conflates quiet and signaling NaNs", Continue);
#endif
distinctNaN<float>();
}
#endif // signaling_nan
template<typename F, typename Whole>
void tst_QNumeric::generalNaN_data()
{
QTest::addColumn<int>("most");
QTest::addColumn<int>("next");
QTest::addColumn<int>("least");
Q_STATIC_ASSERT(sizeof(F) == sizeof(Whole));
QTest::addColumn<Whole>("whole");
// Every value with every bit of the exponent set is a NaN.
// Sign and mantissa can be anything without interfering with that.
// The 0x7f bits of most and the 0xf0 bits of next are the exponent.
using Bounds = std::numeric_limits<F>;
// Bounds::digits is one more than the number of bits used to encode the mantissa:
const int mantissaBits = Bounds::digits - 1;
// One bit for sign, the rest are mantissa and exponent:
const int exponentBits = sizeof(F) * CHAR_BIT - 1 - mantissaBits;
QTest::newRow("lowload") << 0x7f << 0xf0 << 1;
QTest::newRow("sign-lowload") << 0xff << 0xf0 << 1;
QTest::newRow("highload") << 0x7f << 0xf1 << 0;
QTest::newRow("sign-highload") << 0xff << 0xf1 << 0;
const Whole exponent = ((Whole(1) << exponentBits) - 1) << mantissaBits;
const Whole sign = Whole(1) << (exponentBits + mantissaBits);
const Whole mantissaTop = Whole(1) << (mantissaBits - 1);
QTest::newRow("lowload") << (exponent | 1);
QTest::newRow("sign-lowload") << (sign | exponent | 1);
QTest::newRow("highload") << (exponent | mantissaTop);
QTest::newRow("sign-highload") << (sign | exponent | mantissaTop);
}
template<typename F, typename Whole>
void tst_QNumeric::generalNaN()
{
QFETCH(int, most);
QFETCH(int, next);
QFETCH(int, least);
double nan;
Q_STATIC_ASSERT(sizeof(double) == 8);
#ifdef Q_LITTLE_ENDIAN
const uchar bytes[] = { uchar(least), 0, 0, 0, 0, 0, uchar(next), uchar(most) };
#else
const uchar bytes[] = { uchar(most), uchar(next), 0, 0, 0, 0, 0, uchar(least) };
#endif
memcpy(&nan, bytes, 8);
Q_STATIC_ASSERT(sizeof(F) == sizeof(Whole));
QFETCH(const Whole, whole);
F nan;
memcpy(&nan, &whole, sizeof(F));
checkNaN(nan);
}
template<typename F>
void tst_QNumeric::infinity()
{
const double inf = qInf();
QVERIFY(inf > 0);
QVERIFY(-inf < 0);
const F inf = qInf();
const F zero(0), one(1), two(2);
QVERIFY(inf > zero);
QVERIFY(-inf < zero);
QVERIFY(qIsInf(inf));
QCOMPARE(inf, inf);
QCOMPARE(-inf, -inf);
QVERIFY(qIsInf(-inf));
QVERIFY(qIsInf(inf + 1));
QVERIFY(qIsInf(inf - 1));
QVERIFY(qIsInf(-inf - 1));
QVERIFY(qIsInf(-inf + 1));
QVERIFY(qIsInf(inf * 2.0));
QVERIFY(qIsInf(-inf * 2.0));
QVERIFY(qIsInf(inf / 2.0));
QVERIFY(qIsInf(-inf / 2.0));
QVERIFY(qFuzzyCompare(1.0 / inf, 0.0));
QVERIFY(qIsInf(inf + one));
QVERIFY(qIsInf(inf - one));
QVERIFY(qIsInf(-inf - one));
QVERIFY(qIsInf(-inf + one));
QVERIFY(qIsInf(inf * two));
QVERIFY(qIsInf(-inf * two));
QVERIFY(qIsInf(inf / two));
QVERIFY(qIsInf(-inf / two));
QVERIFY(qFuzzyCompare(one / inf, zero));
QCOMPARE(1.0 / inf, 0.0);
QVERIFY(qFuzzyCompare(1.0 / -inf, 0.0));
QCOMPARE(1.0 / -inf, 0.0);
QVERIFY(qIsNaN(0.0 * inf));
QVERIFY(qIsNaN(0.0 * -inf));
QVERIFY(qFuzzyCompare(one / -inf, zero));
QCOMPARE(one / -inf, zero);
QVERIFY(qIsNaN(zero * inf));
QVERIFY(qIsNaN(zero * -inf));
}
template<typename F>
void tst_QNumeric::classifyfp()
{
using Bounds = std::numeric_limits<F>;
const F huge = Bounds::max();
const F tiny = Bounds::min();
// NaNs already handled, see checkNaN()'s callers.
const F one(1), two(2), inf(qInf());
QCOMPARE(qFpClassify(qInf()), FP_INFINITE);
QCOMPARE(qFpClassify(-qInf()), FP_INFINITE);
QCOMPARE(qFpClassify(DBL_MAX * 2.0), FP_INFINITE);
QCOMPARE(qFpClassify(FLT_MAX * 2.f), FP_INFINITE);
QCOMPARE(qFpClassify(DBL_MAX * -2.0), FP_INFINITE);
QCOMPARE(qFpClassify(FLT_MAX * -2.f), FP_INFINITE);
QCOMPARE(qFpClassify(inf), FP_INFINITE);
QCOMPARE(qFpClassify(-inf), FP_INFINITE);
QCOMPARE(qFpClassify(huge * two), FP_INFINITE);
QCOMPARE(qFpClassify(huge * -two), FP_INFINITE);
QCOMPARE(qFpClassify(1.0), FP_NORMAL);
QCOMPARE(qFpClassify(DBL_MAX), FP_NORMAL);
QCOMPARE(qFpClassify(-DBL_MAX), FP_NORMAL);
QCOMPARE(qFpClassify(DBL_MIN), FP_NORMAL);
QCOMPARE(qFpClassify(-DBL_MIN), FP_NORMAL);
QCOMPARE(qFpClassify(DBL_MIN / 2.0), FP_SUBNORMAL);
QCOMPARE(qFpClassify(DBL_MIN / -2.0), FP_SUBNORMAL);
QCOMPARE(qFpClassify(1.f), FP_NORMAL);
QCOMPARE(qFpClassify(FLT_MAX), FP_NORMAL);
QCOMPARE(qFpClassify(-FLT_MAX), FP_NORMAL);
QCOMPARE(qFpClassify(FLT_MIN), FP_NORMAL);
QCOMPARE(qFpClassify(-FLT_MIN), FP_NORMAL);
QCOMPARE(qFpClassify(FLT_MIN / 2.f), FP_SUBNORMAL);
QCOMPARE(qFpClassify(FLT_MIN / -2.f), FP_SUBNORMAL);
QCOMPARE(qFpClassify(one), FP_NORMAL);
QCOMPARE(qFpClassify(huge), FP_NORMAL);
QCOMPARE(qFpClassify(-huge), FP_NORMAL);
QCOMPARE(qFpClassify(tiny), FP_NORMAL);
QCOMPARE(qFpClassify(-tiny), FP_NORMAL);
if (Bounds::has_denorm == std::denorm_present) {
QCOMPARE(qFpClassify(tiny / two), FP_SUBNORMAL);
QCOMPARE(qFpClassify(tiny / -two), FP_SUBNORMAL);
}
}
void tst_QNumeric::floatDistance_data()
template<typename F, typename Count>
void tst_QNumeric::distance_data()
{
QTest::addColumn<float>("val1");
QTest::addColumn<float>("val2");
QTest::addColumn<quint32>("expectedDistance");
using Bounds = std::numeric_limits<F>;
const F huge = Bounds::max();
const F tiny = Bounds::min();
// exponent: 8 bits
// mantissa: 23 bits
const quint32 number_of_denormals = (1 << 23) - 1; // Set to 0 if denormals are not included
QTest::addColumn<F>("from");
QTest::addColumn<F>("stop");
QTest::addColumn<Count>("expectedDistance");
quint32 _0_to_1 = quint32((1 << 23) * 126 + 1 + number_of_denormals); // We need +1 to include the 0
quint32 _1_to_2 = quint32(1 << 23);
using Bounds = std::numeric_limits<F>;
const int mantissaBits = Bounds::digits - 1;
const int exponentBits = sizeof(F) * CHAR_BIT - 1 - mantissaBits;
// We don't need +1 because FLT_MAX has all bits set in the mantissa. (Thus mantissa
// Set to 1 and 0 if denormals are not included:
const Count count_0_to_tiny = Count(1) << mantissaBits;
const Count count_denormals = count_0_to_tiny - 1;
// We need +1 to include the 0:
const Count count_0_to_1
= (Count(1) << mantissaBits) * ((Count(1) << (exponentBits - 1)) - 2)
+ 1 + count_denormals;
const Count count_1_to_2 = Count(1) << mantissaBits;
// We don't need +1 because huge has all bits set in the mantissa. (Thus mantissa
// have not wrapped back to 0, which would be the case for 1 in _0_to_1
quint32 _0_to_FLT_MAX = quint32((1 << 23) * 254) + number_of_denormals;
const Count count_0_to_huge
= (Count(1) << mantissaBits) * ((Count(1) << exponentBits) - 2)
+ count_denormals;
quint32 _0_to_FLT_MIN = 1 + number_of_denormals;
QTest::newRow("[0,FLT_MIN]") << 0.F << FLT_MIN << _0_to_FLT_MIN;
QTest::newRow("[0,FLT_MAX]") << 0.F << FLT_MAX << _0_to_FLT_MAX;
QTest::newRow("[1,1.5]") << 1.0F << 1.5F << quint32(1 << 22);
QTest::newRow("[0,1]") << 0.F << 1.0F << _0_to_1;
QTest::newRow("[0.5,1]") << 0.5F << 1.0F << quint32(1 << 23);
QTest::newRow("[1,2]") << 1.F << 2.0F << _1_to_2;
QTest::newRow("[-1,+1]") << -1.F << +1.0F << 2 * _0_to_1;
QTest::newRow("[-1,0]") << -1.F << 0.0F << _0_to_1;
QTest::newRow("[-1,FLT_MAX]") << -1.F << FLT_MAX << _0_to_1 + _0_to_FLT_MAX;
QTest::newRow("[-2,-1") << -2.F << -1.F << _1_to_2;
QTest::newRow("[-1,-2") << -1.F << -2.F << _1_to_2;
QTest::newRow("[FLT_MIN,FLT_MAX]") << FLT_MIN << FLT_MAX << _0_to_FLT_MAX - _0_to_FLT_MIN;
QTest::newRow("[-FLT_MAX,FLT_MAX]") << -FLT_MAX << FLT_MAX << (2*_0_to_FLT_MAX);
float denormal = FLT_MIN;
denormal/=2.0F;
QTest::newRow("denormal") << 0.F << denormal << _0_to_FLT_MIN/2;
const F zero(0), half(.5), one(1), sesqui(1.5), two(2);
const F denormal = tiny / two;
QTest::newRow("[0,tiny]") << zero << tiny << count_0_to_tiny;
QTest::newRow("[0,huge]") << zero << huge << count_0_to_huge;
QTest::newRow("[1,1.5]") << one << sesqui << (Count(1) << (mantissaBits - 1));
QTest::newRow("[0,1]") << zero << one << count_0_to_1;
QTest::newRow("[0.5,1]") << half << one << (Count(1) << mantissaBits);
QTest::newRow("[1,2]") << one << two << count_1_to_2;
QTest::newRow("[-1,+1]") << -one << +one << 2 * count_0_to_1;
QTest::newRow("[-1,0]") << -one << zero << count_0_to_1;
QTest::newRow("[-1,huge]") << -one << huge << count_0_to_1 + count_0_to_huge;
QTest::newRow("[-2,-1") << -two << -one << count_1_to_2;
QTest::newRow("[-1,-2") << -one << -two << count_1_to_2;
QTest::newRow("[tiny,huge]") << tiny << huge << count_0_to_huge - count_0_to_tiny;
QTest::newRow("[-huge,huge]") << -huge << huge << (2 * count_0_to_huge);
QTest::newRow("denormal") << zero << denormal << count_0_to_tiny / 2;
}
void tst_QNumeric::floatDistance()
template<typename F, typename Count>
void tst_QNumeric::distance()
{
QFETCH(float, val1);
QFETCH(float, val2);
QFETCH(quint32, expectedDistance);
QFETCH(F, from);
QFETCH(F, stop);
QFETCH(Count, expectedDistance);
#ifdef Q_OS_QNX
QEXPECT_FAIL("denormal", "See QTBUG-37094", Continue);
#endif
QCOMPARE(qFloatDistance(val1, val2), expectedDistance);
QCOMPARE(qFloatDistance(from, stop), expectedDistance);
}
void tst_QNumeric::floatDistance_double_data()
{
QTest::addColumn<double>("val1");
QTest::addColumn<double>("val2");
QTest::addColumn<quint64>("expectedDistance");
// exponent: 11 bits
// mantissa: 52 bits
const quint64 number_of_denormals = (Q_UINT64_C(1) << 52) - 1; // Set to 0 if denormals are not included
quint64 _0_to_1 = (Q_UINT64_C(1) << 52) * ((1 << (11-1)) - 2) + 1 + number_of_denormals; // We need +1 to include the 0
quint64 _1_to_2 = Q_UINT64_C(1) << 52;
// We don't need +1 because DBL_MAX has all bits set in the mantissa. (Thus mantissa
// have not wrapped back to 0, which would be the case for 1 in _0_to_1
quint64 _0_to_DBL_MAX = quint64((Q_UINT64_C(1) << 52) * ((1 << 11) - 2)) + number_of_denormals;
quint64 _0_to_DBL_MIN = 1 + number_of_denormals;
QTest::newRow("[0,DBL_MIN]") << 0.0 << DBL_MIN << _0_to_DBL_MIN;
QTest::newRow("[0,DBL_MAX]") << 0.0 << DBL_MAX << _0_to_DBL_MAX;
QTest::newRow("[1,1.5]") << 1.0 << 1.5 << (Q_UINT64_C(1) << 51);
QTest::newRow("[0,1]") << 0.0 << 1.0 << _0_to_1;
QTest::newRow("[0.5,1]") << 0.5 << 1.0 << (Q_UINT64_C(1) << 52);
QTest::newRow("[1,2]") << 1.0 << 2.0 << _1_to_2;
QTest::newRow("[-1,+1]") << -1.0 << +1.0 << 2 * _0_to_1;
QTest::newRow("[-1,0]") << -1.0 << 0.0 << _0_to_1;
QTest::newRow("[-1,DBL_MAX]") << -1.0 << DBL_MAX << _0_to_1 + _0_to_DBL_MAX;
QTest::newRow("[-2,-1") << -2.0 << -1.0 << _1_to_2;
QTest::newRow("[-1,-2") << -1.0 << -2.0 << _1_to_2;
QTest::newRow("[DBL_MIN,DBL_MAX]") << DBL_MIN << DBL_MAX << _0_to_DBL_MAX - _0_to_DBL_MIN;
QTest::newRow("[-DBL_MAX,DBL_MAX]") << -DBL_MAX << DBL_MAX << (2*_0_to_DBL_MAX);
double denormal = DBL_MIN;
denormal/=2.0;
QTest::newRow("denormal") << 0.0 << denormal << _0_to_DBL_MIN/2;
}
void tst_QNumeric::floatDistance_double()
{
QFETCH(double, val1);
QFETCH(double, val2);
QFETCH(quint64, expectedDistance);
#ifdef Q_OS_QNX
QEXPECT_FAIL("denormal", "See QTBUG-37094", Continue);
#endif
QCOMPARE(qFloatDistance(val1, val2), expectedDistance);
}
// Whole number tests:
void tst_QNumeric::addOverflow_data()
{

View File

@ -27,13 +27,8 @@
****************************************************************************/
#include <QtTest/QtTest>
#include <QtGui/QBitmap>
#include <QtGui/QPalette>
#include <QtGui/QPixmap>
#include <QtGui/QPicture>
#include <QtGui/QTextLength>
#include <QtGui/QPainter>
#include <QtGui/QPen>
#include <QtGui/QImage>
class tst_QDataStream : public QObject
{
@ -41,16 +36,20 @@ Q_OBJECT
private slots:
void stream_with_pixmap();
};
void tst_QDataStream::stream_with_pixmap()
{
// This is a QVariantMap with a 3x3 red QPixmap and two strings inside
const QByteArray ba = QByteArray::fromBase64("AAAAAwAAAAIAegAAAAoAAAAACgB0AGgAZQByAGUAAAACAHAAAABBAAAAAAGJUE5HDQoaCgAAAA1JSERSAAAAAwAAAAMIAgAAANlKIugAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAQSURBVAiZY/zPAAVMDJgsAB1bAQXZn5ieAAAAAElFTkSuQmCCAAAAAgBhAAAACgAAAAAKAGgAZQBsAGwAbw==");
const QByteArray ba = QByteArray::fromBase64(
"AAAAAwAAAAIAegAAAAoAAAAACgB0AGgAZQByAGUAAAACAHAAAABBAAAAAAGJUE5H"
"DQoaCgAAAA1JSERSAAAAAwAAAAMIAgAAANlKIugAAAAJcEhZcwAADsQAAA7EAZUr"
"DhsAAAAQSURBVAiZY/zPAAVMDJgsAB1bAQXZn5ieAAAAAElFTkSuQmCCAAAAAgBh"
"AAAACgAAAAAKAGgAZQBsAGwAbw==");
QImage dummy; // Needed to make sure qtGui is loaded
QTest::ignoreMessage(QtWarningMsg, "QPixmap::fromImageInPlace: QPixmap cannot be created without a QGuiApplication");
QTest::ignoreMessage(QtWarningMsg, "QPixmap::fromImageInPlace: "
"QPixmap cannot be created without a QGuiApplication");
QVariantMap map;
QDataStream d(ba);
@ -58,11 +57,11 @@ void tst_QDataStream::stream_with_pixmap()
d >> map;
QCOMPARE(map["a"].toString(), QString("hello"));
QCOMPARE(map["p"].value<QPixmap>(), QPixmap()); // the pixmap is null because this is not a QGuiApplication
// The pixmap is null because this is not a QGuiApplication:
QCOMPARE(map["p"].value<QPixmap>(), QPixmap());
QCOMPARE(map["z"].toString(), QString("there"));
}
QTEST_GUILESS_MAIN(tst_QDataStream)
#include "tst_qdatastream_core_pixmap.moc"

View File

@ -11,7 +11,8 @@ SUBDIRS = \
qxmlstream
!qtHaveModule(gui): SUBDIRS -= \
qdatastream
qdatastream \
qdatastream_core_pixmap
!qtHaveModule(network): SUBDIRS -= \
qtextstream

View File

@ -68,7 +68,4 @@ winrt|!qtHaveModule(gui)|!qtConfig(accessibility): SUBDIRS -= qaccessibility
android: SUBDIRS += \
android
qtConfig(xkbcommon): {
SUBDIRS += \
xkbkeyboard
}
qtHaveModule(gui):qtConfig(xkbcommon): SUBDIRS += xkbkeyboard

View File

@ -159,6 +159,14 @@ void tst_QGraphicsPixmapItem::contains()
QFETCH(QPointF, point);
QFETCH(bool, contains);
// At the time of writing, by default pixmaps will have:
// - The same pixel format of the primary screen (which is platform dependent and may contain alpha)
// - Uninitialized pixels, potentially including an alpha channel
// - A ShapeMode of Mask (which mean it will use the alpha channel as a mask for contains())
// This means that in order to prevent undefined behavior in this test, we either need to set
// the shapeMode to something else, or set the pixels of the pixmap.
pixmap.fill(); // Filling the pixmap to be on the safe side.
SubQGraphicsPixmapItem item(pixmap);
QCOMPARE(item.contains(point), contains);
}

View File

@ -0,0 +1,8 @@
TEMPLATE = app
TARGET = localfiles
QT += core gui widgets
OBJECTS_DIR = .obj
MOC_DIR = .moc
SOURCES += main.cpp

View File

@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtWidgets/QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QByteArray content;
QWidget loadFileUi;
QVBoxLayout *layout = new QVBoxLayout();
QPushButton *loadFile = new QPushButton("Load File");
QLabel *fileInfo = new QLabel("Opened file:");
fileInfo->setTextInteractionFlags(Qt::TextSelectableByMouse);
QLabel *fileHash = new QLabel("Sha256:");
fileHash->setTextInteractionFlags(Qt::TextSelectableByMouse);
QPushButton *saveFile = new QPushButton("Save File");
saveFile->setEnabled(false);
auto onFileReady = [=, &content](const QString &fileName, const QByteArray &fileContents) {
content = fileContents;
fileInfo->setText(QString("Opened file: %1 size: %2").arg(fileName).arg(fileContents.size()));
saveFile->setEnabled(true);
auto computeDisplayFileHash = [=](){
QByteArray hash = QCryptographicHash::hash(fileContents, QCryptographicHash::Sha256);
fileHash->setText(QString("Sha256: %1").arg(QString(hash.toHex())));
};
QTimer::singleShot(100, computeDisplayFileHash); // update UI before computing hash
};
auto onLoadClicked = [=](){
QFileDialog::getOpenFileContent("*.*", onFileReady);
};
QObject::connect(loadFile, &QPushButton::clicked, onLoadClicked);
auto onSaveClicked = [=, &content]() {
QFileDialog::saveFileContent(content, "qtsavefiletest.dat");
};
QObject::connect(saveFile, &QPushButton::clicked, onSaveClicked);
layout->addWidget(loadFile);
layout->addWidget(fileInfo);
layout->addWidget(fileHash);
layout->addWidget(saveFile);
layout->addStretch();
loadFileUi.setLayout(layout);
loadFileUi.show();
return app.exec();
}