QPointerUniqueId: make fit for release
- Declare as Q_MOVABLE_TYPE - Prevent QList<QPointerUniqueId> from being instantiated (use QVector instead) - Add equality relational operators - Add qHash() overload - Replace non-default ctor with named ctor. - Add Q_DECL_NOTHROW. - Add Q_DECL_CONSTEXPR. - Rename numeric() -> numericId(). - Update docs. The extension vector for this class calls for additional properties to be added later, but these are not user- settable. It thus suffices to rely on the only data member, a qint64, which can be reinterpreted to an index into an array or hash with actual objects. This allows to make the class a Trivial Type (ie. no overhead over an int) while still supporting later extension. Cf. QSslEllipticCurve as another example of such a class. The extension has to maintain the following invariants, encoded into user code by way of being used in inline functions: - m_numericId == -1 <=> !isValid() This is trivial to support. An extension could not and still cannot reinterpret the qint64 member as a d-pointer, but a d-pointer is only necessary for user-settable properties where updating a central private data structure would cause too much contention. Add a test. Since this type is used in other modules, keep the existing functions, but mark them as deprecated with the expectation that these compat functions be removed before 5.8.0 final. Task-number: QTBUG-54616 Change-Id: Ia3ede0ecaeeef4cd3ffa94a72b1050bd409713a5 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
parent
f4a33e345e
commit
048447346b
@ -44,6 +44,7 @@
|
||||
#include "qpa/qplatformdrag.h"
|
||||
#include "private/qevent_p.h"
|
||||
#include "qfile.h"
|
||||
#include "qhashfunctions.h"
|
||||
#include "qmetaobject.h"
|
||||
#include "qmimedata.h"
|
||||
#include "private/qdnd_p.h"
|
||||
@ -4474,7 +4475,7 @@ int QTouchEvent::TouchPoint::id() const
|
||||
\since 5.8
|
||||
Returns the unique ID of this touch point or token, if any.
|
||||
|
||||
It is normally invalid (with a \l {QPointerUniqueId::numeric()} {numeric()} value of -1),
|
||||
It is normally invalid (see \l {QPointerUniqueId::isValid()} {isValid()}),
|
||||
because touchscreens cannot uniquely identify fingers. But when the
|
||||
\l {TouchPoint::InfoFlag} {Token} flag is set, it is expected to uniquely
|
||||
identify a specific token (fiducial object).
|
||||
@ -4757,7 +4758,7 @@ void QTouchEvent::TouchPoint::setUniqueId(qint64 uid)
|
||||
{
|
||||
if (d->ref.load() != 1)
|
||||
d = d->detach();
|
||||
d->uniqueId = QPointerUniqueId(uid);
|
||||
d->uniqueId = QPointerUniqueId::fromNumericId(uid);
|
||||
}
|
||||
|
||||
/*! \internal */
|
||||
@ -5184,28 +5185,91 @@ Qt::ApplicationState QApplicationStateChangeEvent::applicationState() const
|
||||
\brief QPointerUniqueId identifies a unique object, such as a tagged token
|
||||
or stylus, which is used with a pointing device.
|
||||
|
||||
QPointerUniqueIds can be compared for equality, and can be used as keys in a QHash.
|
||||
You get access to the numerical ID via numericId(), if the device supports such IDs.
|
||||
For future extensions, though, you should not use that function, but compare objects
|
||||
of this type using the equality operator.
|
||||
|
||||
This class is a thin wrapper around an integer ID. You pass it into and out of
|
||||
functions by value.
|
||||
|
||||
This type actively prevents you from holding it in a QList, because doing so would
|
||||
be very inefficient. Use a QVector instead, which has the same API as QList, but more
|
||||
efficient storage.
|
||||
|
||||
\sa QTouchEvent::TouchPoint
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a unique pointer ID with a numeric \a id provided by the hardware.
|
||||
The default is -1, which means an invalid pointer ID.
|
||||
\fn QPointerUniqueId::QPointerUniqueId()
|
||||
Constructs an invalid unique pointer ID.
|
||||
*/
|
||||
QPointerUniqueId::QPointerUniqueId(qint64 id)
|
||||
: m_numericId(id)
|
||||
|
||||
/*!
|
||||
Constructs a unique pointer ID from numeric ID \a id.
|
||||
*/
|
||||
QPointerUniqueId QPointerUniqueId::fromNumericId(qint64 id)
|
||||
{
|
||||
QPointerUniqueId result;
|
||||
result.m_numericId = id;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QPointerUniqueId::numeric
|
||||
\fn bool QPointerUniqueId::isValid()
|
||||
|
||||
Returns whether this unique pointer ID is valid, that is, it represents an actual
|
||||
pointer.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\property QPointerUniqueId::numericId
|
||||
\brief the numeric unique ID of the token represented by a touchpoint
|
||||
|
||||
This is the numeric unique ID if the device provides that type of ID;
|
||||
If the device provides a numeric ID, isValid() returns true, and this
|
||||
property provides the numeric ID;
|
||||
otherwise it is -1.
|
||||
|
||||
You should not use the value of this property in portable code, but
|
||||
instead rely on equality to identify pointers.
|
||||
|
||||
\sa isValid()
|
||||
*/
|
||||
qint64 QPointerUniqueId::numeric() const
|
||||
qint64 QPointerUniqueId::numericId() const Q_DECL_NOTHROW
|
||||
{
|
||||
return m_numericId;
|
||||
}
|
||||
|
||||
/*!
|
||||
\relates QPointerUniqueId
|
||||
\since 5.8
|
||||
|
||||
Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer
|
||||
(\c true) or not (\c false).
|
||||
*/
|
||||
bool operator==(QPointerUniqueId lhs, QPointerUniqueId rhs) Q_DECL_NOTHROW
|
||||
{
|
||||
return lhs.numericId() == rhs.numericId();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool operator!=(QPointerUniqueId lhs, QPointerUniqueId rhs)
|
||||
\relates QPointerUniqueId
|
||||
\since 5.8
|
||||
|
||||
Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers
|
||||
(\c true) or not (\c false).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\relates QPointerUniqueId
|
||||
\since 5.8
|
||||
|
||||
Returns the hash value for \a key, using \a seed to seed the calculation.
|
||||
*/
|
||||
uint qHash(QPointerUniqueId key, uint seed) Q_DECL_NOTHROW
|
||||
{
|
||||
return qHash(key.numericId(), seed);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -793,21 +793,45 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ?
|
||||
inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);}
|
||||
#endif // QT_NO_SHORTCUT
|
||||
|
||||
class QPointerUniqueIdPrivate;
|
||||
class Q_GUI_EXPORT QPointerUniqueId
|
||||
{
|
||||
Q_GADGET
|
||||
Q_PROPERTY(qint64 numeric READ numeric CONSTANT)
|
||||
// ### kept these to keep other modules compiling. Remove before 5.8.0 final!
|
||||
#if QT_DEPRECATED_SINCE(5, 8)
|
||||
Q_PROPERTY(qint64 numeric READ numericId CONSTANT)
|
||||
#endif
|
||||
Q_PROPERTY(qint64 numericId READ numericId CONSTANT)
|
||||
public:
|
||||
explicit QPointerUniqueId(qint64 id = -1);
|
||||
Q_ALWAYS_INLINE
|
||||
Q_DECL_CONSTEXPR QPointerUniqueId() Q_DECL_NOTHROW : m_numericId(-1) {}
|
||||
// compiler-generated copy/move ctor/assignment operators are ok!
|
||||
// compiler-generated dtor is ok!
|
||||
|
||||
qint64 numeric() const;
|
||||
static QPointerUniqueId fromNumericId(qint64 id);
|
||||
|
||||
Q_ALWAYS_INLINE Q_DECL_CONSTEXPR bool isValid() const Q_DECL_NOTHROW { return m_numericId != -1; }
|
||||
qint64 numericId() const Q_DECL_NOTHROW;
|
||||
|
||||
// ### kept these to keep other modules compiling. Remove before 5.8.0 final!
|
||||
#if QT_DEPRECATED_SINCE(5, 8)
|
||||
Q_ALWAYS_INLINE Q_DECL_DEPRECATED qint64 numeric() const { return numericId(); }
|
||||
Q_ALWAYS_INLINE Q_DECL_DEPRECATED explicit QPointerUniqueId(qint64 id) : m_numericId(id) {}
|
||||
#endif
|
||||
private:
|
||||
// TODO for TUIO 2, or any other type of complex token ID, a d-pointer can replace
|
||||
// m_numericId without changing the size of this class.
|
||||
// TODO: for TUIO 2, or any other type of complex token ID, an internal
|
||||
// array (or hash) can be added to hold additional properties.
|
||||
// In this case, m_numericId will then turn into an index into that array (or hash).
|
||||
qint64 m_numericId;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(QPointerUniqueId, Q_MOVABLE_TYPE);
|
||||
template <> class QList<QPointerUniqueId> {}; // to prevent instantiation: use QVector instead
|
||||
|
||||
Q_GUI_EXPORT bool operator==(QPointerUniqueId lhs, QPointerUniqueId rhs) Q_DECL_NOTHROW;
|
||||
inline bool operator!=(QPointerUniqueId lhs, QPointerUniqueId rhs) Q_DECL_NOTHROW
|
||||
{ return !operator==(lhs, rhs); }
|
||||
Q_GUI_EXPORT uint qHash(QPointerUniqueId key, uint seed = 0) Q_DECL_NOTHROW;
|
||||
|
||||
|
||||
|
||||
class QTouchEventTouchPointPrivate;
|
||||
class Q_GUI_EXPORT QTouchEvent : public QInputEvent
|
||||
|
@ -194,6 +194,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void cleanup();
|
||||
void qPointerUniqueId();
|
||||
void touchDisabledByDefault();
|
||||
void touchEventAcceptedByDefault();
|
||||
void touchBeginPropagatesWhenIgnored();
|
||||
@ -224,6 +225,44 @@ void tst_QTouchEvent::cleanup()
|
||||
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
|
||||
}
|
||||
|
||||
void tst_QTouchEvent::qPointerUniqueId()
|
||||
{
|
||||
QPointerUniqueId id1, id2;
|
||||
|
||||
QCOMPARE(id1.numericId(), Q_INT64_C(-1));
|
||||
QVERIFY(!id1.isValid());
|
||||
|
||||
QVERIFY( id1 == id2);
|
||||
QVERIFY(!(id1 != id2));
|
||||
|
||||
QSet<QPointerUniqueId> set; // compile test
|
||||
set.insert(id1);
|
||||
set.insert(id2);
|
||||
QCOMPARE(set.size(), 1);
|
||||
|
||||
|
||||
const auto id3 = QPointerUniqueId::fromNumericId(-1);
|
||||
QCOMPARE(id3.numericId(), Q_INT64_C(-1));
|
||||
QVERIFY(!id3.isValid());
|
||||
|
||||
QVERIFY( id1 == id3);
|
||||
QVERIFY(!(id1 != id3));
|
||||
|
||||
set.insert(id3);
|
||||
QCOMPARE(set.size(), 1);
|
||||
|
||||
|
||||
const auto id4 = QPointerUniqueId::fromNumericId(4);
|
||||
QCOMPARE(id4.numericId(), Q_INT64_C(4));
|
||||
QVERIFY(id4.isValid());
|
||||
|
||||
QVERIFY( id1 != id4);
|
||||
QVERIFY(!(id1 == id4));
|
||||
|
||||
set.insert(id4);
|
||||
QCOMPARE(set.size(), 2);
|
||||
}
|
||||
|
||||
void tst_QTouchEvent::touchDisabledByDefault()
|
||||
{
|
||||
// QWidget
|
||||
|
Loading…
x
Reference in New Issue
Block a user