Fix Qt 5 todo issues for QSizePolicy.

* Merge the two public ctors.
* Use bitflags instead of shifting bits (more readable).
* Add autotest
* Use int datatype for the "stretch setters". (values out of bounds are clamped)

Streaming to QDataStream will still use the Qt 4 format.

Task-number: QTBUG-25100

Change-Id: Iecb1e78cb12717e4d84448484c3ad8ca469d571a
Reviewed-by: Paul Olav Tvete <paul.tvete@nokia.com>
bb10
Jan-Arve Saether 2012-05-23 14:58:55 +02:00 committed by Qt by Nokia
parent ef204659b9
commit 7cdcc26722
6 changed files with 299 additions and 60 deletions

View File

@ -1419,17 +1419,17 @@ void QSizePolicy::setControlType(ControlType type)
Example:
0x00000001 maps to 0x00000000
0x00000002 maps to 0x00000200
0x00000004 maps to 0x00000400
0x00000008 maps to 0x00000600
0x00000001 maps to 0
0x00000002 maps to 1
0x00000004 maps to 2
0x00000008 maps to 3
etc.
*/
int i = 0;
while (true) {
if (type & (0x1 << i)) {
data = (data & ~CTMask) | (i << CTShift);
bits.ctype = i;
return;
}
++i;
@ -1438,10 +1438,11 @@ void QSizePolicy::setControlType(ControlType type)
QSizePolicy::ControlType QSizePolicy::controlType() const
{
return QSizePolicy::ControlType(0x1 << ((data & CTMask) >> CTShift));
return QSizePolicy::ControlType(1 << bits.ctype);
}
#ifndef QT_NO_DATASTREAM
/*!
\relates QSizePolicy
\since 4.2
@ -1452,9 +1453,20 @@ QSizePolicy::ControlType QSizePolicy::controlType() const
*/
QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy)
{
return stream << policy.data;
// The order here is for historical reasons. (compatibility with Qt4)
quint32 data = (policy.bits.horPolicy | // [0, 3]
policy.bits.verPolicy << 4 | // [4, 7]
policy.bits.hfw << 8 | // [8]
policy.bits.ctype << 9 | // [9, 13]
policy.bits.wfh << 14 | // [14]
//policy.bits.padding << 15 | // [15]
policy.bits.verStretch << 16 | // [16, 23]
policy.bits.horStretch << 24); // [24, 31]
return stream << data;
}
#define VALUE_OF_BITS(data, bitstart, bitcount) ((data >> bitstart) & ((1 << bitcount) -1))
/*!
\relates QSizePolicy
\since 4.2
@ -1465,7 +1477,17 @@ QDataStream &operator<<(QDataStream &stream, const QSizePolicy &policy)
*/
QDataStream &operator>>(QDataStream &stream, QSizePolicy &policy)
{
return stream >> policy.data;
quint32 data;
stream >> data;
policy.bits.horPolicy = VALUE_OF_BITS(data, 0, 4);
policy.bits.verPolicy = VALUE_OF_BITS(data, 4, 4);
policy.bits.hfw = VALUE_OF_BITS(data, 8, 1);
policy.bits.ctype = VALUE_OF_BITS(data, 9, 5);
policy.bits.wfh = VALUE_OF_BITS(data, 14, 1);
policy.bits.padding = 0;
policy.bits.verStretch = VALUE_OF_BITS(data, 16, 8);
policy.bits.horStretch = VALUE_OF_BITS(data, 24, 8);
return stream;
}
#endif // QT_NO_DATASTREAM

View File

@ -56,19 +56,6 @@ class Q_WIDGETS_EXPORT QSizePolicy
Q_GADGET
Q_ENUMS(Policy)
private:
enum SizePolicyMasks {
HSize = 4,
HMask = 0x0f,
VMask = HMask << HSize,
CTShift = 9,
CTSize = 5,
CTMask = ((0x1 << CTSize) - 1) << CTShift,
WFHShift = CTShift + CTSize,
UnusedShift = WFHShift + 1,
UnusedSize = 1
};
public:
enum PolicyFlag {
GrowFlag = 1,
@ -109,17 +96,18 @@ public:
QSizePolicy() : data(0) { }
// ### Qt 5: merge these two constructors (with type == DefaultType)
QSizePolicy(Policy horizontal, Policy vertical)
: data(horizontal | (vertical << HSize)) { }
QSizePolicy(Policy horizontal, Policy vertical, ControlType type)
: data(horizontal | (vertical << HSize)) { setControlType(type); }
Policy horizontalPolicy() const { return static_cast<Policy>(data & HMask); }
Policy verticalPolicy() const { return static_cast<Policy>((data & VMask) >> HSize); }
QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType)
: data(0) {
bits.horPolicy = horizontal;
bits.verPolicy = vertical;
setControlType(type);
}
Policy horizontalPolicy() const { return static_cast<Policy>(bits.horPolicy); }
Policy verticalPolicy() const { return static_cast<Policy>(bits.verPolicy); }
ControlType controlType() const;
void setHorizontalPolicy(Policy d) { data = (data & ~HMask) | d; }
void setVerticalPolicy(Policy d) { data = (data & ~(HMask << HSize)) | (d << HSize); }
void setHorizontalPolicy(Policy d) { bits.horPolicy = d; }
void setVerticalPolicy(Policy d) { bits.verPolicy = d; }
void setControlType(ControlType type);
Qt::Orientations expandingDirections() const {
@ -131,19 +119,19 @@ public:
return result;
}
void setHeightForWidth(bool b) { data = b ? (data | (1 << 2*HSize)) : (data & ~(1 << 2*HSize)); }
bool hasHeightForWidth() const { return data & (1 << 2*HSize); }
void setWidthForHeight(bool b) { data = b ? (data | (1 << (WFHShift))) : (data & ~(1 << (WFHShift))); }
bool hasWidthForHeight() const { return data & (1 << (WFHShift)); }
void setHeightForWidth(bool b) { bits.hfw = b; }
bool hasHeightForWidth() const { return bits.hfw; }
void setWidthForHeight(bool b) { bits.wfh = b; }
bool hasWidthForHeight() const { return bits.wfh; }
bool operator==(const QSizePolicy& s) const { return data == s.data; }
bool operator!=(const QSizePolicy& s) const { return data != s.data; }
operator QVariant() const; // implemented in qabstractlayout.cpp
operator QVariant() const; // implemented in qlayoutitem.cpp
int horizontalStretch() const { return data >> 24; }
int verticalStretch() const { return (data >> 16) & 0xff; }
void setHorizontalStretch(uchar stretchFactor) { data = (data&0x00ffffff) | (uint(stretchFactor)<<24); }
void setVerticalStretch(uchar stretchFactor) { data = (data&0xff00ffff) | (uint(stretchFactor)<<16); }
int horizontalStretch() const { return static_cast<int>(bits.horStretch); }
int verticalStretch() const { return static_cast<int>(bits.verStretch); }
void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
void transpose();
@ -155,21 +143,19 @@ private:
#endif
QSizePolicy(int i) : data(i) { }
quint32 data;
/* Qt5: Use bit flags instead, keep it here for improved readability for now.
We can maybe change it for Qt4, but we'd have to be careful, since the behaviour
is implementation defined. It usually varies between little- and big-endian compilers, but
it might also not vary.
quint32 horzPolicy : 4;
quint32 vertPolicy : 4;
quint32 hfw : 1;
quint32 ctype : 5;
quint32 wfh : 1;
quint32 padding : 1; // we cannot use the highest bit
quint32 verStretch : 8;
quint32 horStretch : 8;
*/
union {
struct {
quint32 horStretch : 8;
quint32 verStretch : 8;
quint32 horPolicy : 4;
quint32 verPolicy : 4;
quint32 ctype : 5;
quint32 hfw : 1;
quint32 wfh : 1;
quint32 padding : 1; // feel free to use
} bits;
quint32 data;
};
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes)
@ -187,8 +173,8 @@ Q_WIDGETS_EXPORT QDebug operator<<(QDebug dbg, const QSizePolicy &);
inline void QSizePolicy::transpose() {
Policy hData = horizontalPolicy();
Policy vData = verticalPolicy();
uchar hStretch = uchar(horizontalStretch());
uchar vStretch = uchar(verticalStretch());
int hStretch = horizontalStretch();
int vStretch = verticalStretch();
setHorizontalPolicy(vData);
setVerticalPolicy(hData);
setHorizontalStretch(vStretch);

View File

@ -319,19 +319,19 @@
*/
/*!
\fn void QSizePolicy::setHorizontalStretch(uchar stretchFactor)
\fn void QSizePolicy::setHorizontalStretch(int stretchFactor)
Sets the horizontal stretch factor of the size policy to the given \a
stretchFactor.
stretchFactor. \a stretchFactor must be in the range [0,255].
\sa horizontalStretch(), setVerticalStretch(), setHorizontalPolicy()
*/
/*!
\fn void QSizePolicy::setVerticalStretch(uchar stretchFactor)
\fn void QSizePolicy::setVerticalStretch(int stretchFactor)
Sets the vertical stretch factor of the size policy to the given
\a stretchFactor.
\a stretchFactor. \a stretchFactor must be in the range [0,255].
\sa verticalStretch(), setHorizontalStretch(), setVerticalPolicy()
*/

View File

@ -14,5 +14,6 @@ SUBDIRS=\
qwidget_window \
qwidgetaction \
qshortcut \
qsizepolicy
SUBDIRS -= qsound

View File

@ -0,0 +1,6 @@
CONFIG += testcase
TARGET = tst_qsizepolicy
QT += widgets widgets-private testlib
SOURCES += tst_qsizepolicy.cpp

View File

@ -0,0 +1,224 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qsizepolicy.h>
class tst_QSizePolicy : public QObject
{
Q_OBJECT
public:
tst_QSizePolicy();
virtual ~tst_QSizePolicy();
private slots:
void getSetCheck();
void dataStream();
void horizontalStretch();
void verticalStretch();
};
tst_QSizePolicy::tst_QSizePolicy()
{
}
tst_QSizePolicy::~tst_QSizePolicy()
{
}
// Testing get/set functions
void tst_QSizePolicy::getSetCheck()
{
{
// check values of a default constructed QSizePolicy
QSizePolicy sp;
QCOMPARE(sp.horizontalPolicy(), QSizePolicy::Fixed);
QCOMPARE(sp.verticalPolicy(), QSizePolicy::Fixed);
QCOMPARE(sp.horizontalStretch(), 0);
QCOMPARE(sp.verticalStretch(), 0);
QCOMPARE(sp.verticalStretch(), 0);
QCOMPARE(sp.controlType(), QSizePolicy::DefaultType);
QCOMPARE(sp.hasHeightForWidth(), false);
QCOMPARE(sp.hasWidthForHeight(), false);
}
{
static const QSizePolicy::Policy policies[3] = {
QSizePolicy::Fixed,
QSizePolicy::Minimum,
QSizePolicy::Ignored
};
static const QSizePolicy::ControlType controlTypes[4] = {
QSizePolicy::DefaultType,
QSizePolicy::ButtonBox,
QSizePolicy::CheckBox,
QSizePolicy::ToolButton
};
#define ITEMCOUNT(arr) sizeof(arr)/sizeof(arr[0])
QSizePolicy sp, oldsp;
#ifdef GENERATE_BASELINE
QFile out(QString::fromAscii("qsizepolicy-Qt%1%2.txt").arg((QT_VERSION >> 16) & 0xff).arg((QT_VERSION) >> 8 & 0xff));
if (out.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QDataStream stream(&out);
#endif
/* Loop for permutating over the values most likely to trigger a bug:
- mininumum, maximum values
- Some values with LSB set, others with MSB unset. (check if shifts are ok)
*/
// Look specifically for
for (int ihp = 0; ihp < ITEMCOUNT(policies); ++ihp) {
QSizePolicy::Policy hp = policies[ihp];
for (int ivp = 0; ivp < ITEMCOUNT(policies); ++ivp) {
QSizePolicy::Policy vp = policies[ivp];
for (int ict = 0; ict < ITEMCOUNT(controlTypes); ++ict) {
QSizePolicy::ControlType ct = controlTypes[ict];
for (int hst= 0; hst <= 255; hst+=85) { //[0,85,170,255]
for (int vst = 0; vst <= 255; vst+=85) {
for (int j = 0; j < 3; ++j) {
bool hfw = j & 1;
bool wfh = j & 2; // cannot set hfw and wfh at the same time
oldsp = sp;
for (int i = 0; i < 5; ++i) {
switch (i) {
case 0: sp.setHorizontalPolicy(hp); break;
case 1: sp.setVerticalPolicy(vp); break;
case 2: sp.setHorizontalStretch(hst); break;
case 3: sp.setVerticalStretch(vst); break;
case 4: sp.setControlType(ct); break;
case 5: sp.setHeightForWidth(hfw); sp.setWidthForHeight(wfh); break;
default: break;
}
QCOMPARE(sp.horizontalPolicy(), (i >= 0 ? hp : oldsp.horizontalPolicy()));
QCOMPARE(sp.verticalPolicy(), (i >= 1 ? vp : oldsp.verticalPolicy()));
QCOMPARE(sp.horizontalStretch(), (i >= 2 ? hst : oldsp.horizontalStretch()));
QCOMPARE(sp.verticalStretch(), (i >= 3 ? vst : oldsp.verticalStretch()));
QCOMPARE(sp.controlType(), (i >= 4 ? ct : oldsp.controlType()));
QCOMPARE(sp.hasHeightForWidth(), (i >= 5 ? hfw : oldsp.hasHeightForWidth()));
QCOMPARE(sp.hasWidthForHeight(), (i >= 5 ? wfh : oldsp.hasWidthForHeight()));
Qt::Orientations orients;
if (sp.horizontalPolicy() & QSizePolicy::ExpandFlag)
orients |= Qt::Horizontal;
if (sp.verticalPolicy() & QSizePolicy::ExpandFlag)
orients |= Qt::Vertical;
QCOMPARE(sp.expandingDirections(), orients);
#ifdef GENERATE_BASELINE
stream << sp;
#endif
}
}
}
}
}
}
}
#ifdef GENERATE_BASELINE
out.close();
}
#endif
}
}
void tst_QSizePolicy::dataStream()
{
QByteArray data;
QSizePolicy sp(QSizePolicy::Minimum, QSizePolicy::Expanding);
{
QDataStream stream(&data, QIODevice::ReadWrite);
sp.setHorizontalStretch(42);
sp.setVerticalStretch(10);
sp.setControlType(QSizePolicy::CheckBox);
sp.setHeightForWidth(true);
stream << sp; // big endian
/*
| BYTE 0 | BYTE 1 |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| Horizontal stretch | Vertical stretch |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| BYTE 2 | BYTE 3 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| pad | wfh | Control Type | hfw | Vertical policy | Horizontal policy |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
*/
QCOMPARE((char)data[0], char(42)); // h stretch
QCOMPARE((char)data[1], char(10)); // v stretch
QCOMPARE((char)data[2], char(1 | (2 << 1))); // (hfw + CheckBox)
QCOMPARE((char)data[3], char(QSizePolicy::Minimum | (QSizePolicy::Expanding << 4)));
}
{
QSizePolicy readSP;
QDataStream stream(data);
stream >> readSP;
QCOMPARE(sp, readSP);
}
}
void tst_QSizePolicy::horizontalStretch()
{
QSizePolicy sp;
sp.setHorizontalStretch(257);
QCOMPARE(sp.horizontalStretch(), 255);
sp.setHorizontalStretch(-2);
QCOMPARE(sp.horizontalStretch(), 0);
}
void tst_QSizePolicy::verticalStretch()
{
QSizePolicy sp;
sp.setVerticalStretch(-2);
QCOMPARE(sp.verticalStretch(), 0);
sp.setVerticalStretch(257);
QCOMPARE(sp.verticalStretch(), 255);
}
QTEST_MAIN(tst_QSizePolicy)
#include "tst_qsizepolicy.moc"