QtProtobuf: Provide support for Qt types in a separate library

Task-number: QTBUG-103985
Change-Id: I2086f5cf46e1424b62b2044d0bcab315a5d447d9
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Tatiana Borisova 2022-12-15 19:05:01 +01:00
parent fdd1d0339f
commit 6637773cbd
24 changed files with 1507 additions and 13 deletions

View File

@ -14,4 +14,5 @@ add_subdirectory(tools)
if(TARGET Qt6::qtprotobufgen AND TARGET WrapProtobuf::WrapLibProtobuf) if(TARGET Qt6::qtprotobufgen AND TARGET WrapProtobuf::WrapLibProtobuf)
add_subdirectory(wellknown) add_subdirectory(wellknown)
add_subdirectory(protobufqttypes)
endif() endif()

View File

@ -71,7 +71,6 @@ function(qt_internal_add_protobuf_module target)
${arg_PROTO_FILES} ${arg_PROTO_FILES}
OUTPUT_TARGETS generated_targets OUTPUT_TARGETS generated_targets
GENERATE_PACKAGE_SUBFOLDERS GENERATE_PACKAGE_SUBFOLDERS
EXTRA_NAMESPACE ${QT_NAMESPACE}
) )
qt_internal_module_info(module ${target}) qt_internal_module_info(module ${target})

View File

@ -0,0 +1,8 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(protobufqtcoretypes)
if(TARGET Qt6::Gui)
add_subdirectory(protobufqtguitypes)
endif()

View File

@ -0,0 +1,106 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtProtobufQtTypes
\title Protobuf Qt types module
\brief Provides support for using native Qt types in protobuf.
Qt::ProtobufQtCoreTypes, Qt::ProtobufQtGuiTypes are libraries with
pre-defined protobuf messages designed to encapsulate a selection
of Qt Core and Qt Gui types.
List of supported types:
\list QtCore
\li QByteArray \note Type reflects the \e bytes protobuf type.
\li QChar
\li QDate
\li QDateTime
\li QPoint
\li QPointF
\li QRect
\li QRectF
\li QSize
\li QSizeF
\li QString \note Type reflects the \e string protobuf type.
\li QTime
\li QUrl
\li QUuid
\li QVersionNumber
\endlist
\list QtGui
\li QImage
\li QMatrix4x4
\li QQuaternion
\li QRgba64
\li QTransform
\li QVector2D
\li QVector3D
\li QVector4D
\endlist
\section1 Qt Core usage
To enable QtCore types support add ProtobufQtCoreTypes as a dependency
to your CMake project:
\badcode
...
find_package(Qt REQUIRED COMPONENTS Protobuf ProtobufQtCoreTypes)
... # After target creation
target_link_libraries(${TARGET} PRIVATE Qt::ProtobufQtCoreTypes)
\endcode
Before any serialization/deserialization of messages that use QtCore types
as fields, call the registration method:
\code
// e.g. in main.cpp
QtProtobuf::qRegisterProtobufQtCoreTypes();
...
\endcode
\section1 Qt Gui usage
To enable QtGui types support add ProtobufQtGuiTypes as a dependency
to your CMake project:
\badcode
...
find_package(Qt REQUIRED COMPONENTS Protobuf ProtobufQtGuiTypes)
... # After target creation
target_link_libraries(${TARGET} PRIVATE Qt::ProtobufQtGuiTypes)
\endcode
Before any serialization/deserialization of messages that use QtGui types
as fields, call the registration method:
\code
// e.g. in main.cpp
QtProtobuf::qRegisterProtobufQtGuiTypes();
...
\endcode
All supported messages are described in special .proto files:
- QtCore.proto - describes Qt types from QtCore module
- QtGui.proto - describes Qt types from QtGui module
These files are also useful if you would like to generate code for other
languages or frameworks.
Import the required Qt types module in your interface .proto file,
for example:
\badcode
syntax = "proto3";
package project.module.component;
import "QtCore/QtCore.proto";
message QUrlMessage {
QtCore.QUrl url = 1;
}
\endcode
The QtProtobuf generator detects Qt types, supplied by the
ProtobufQtCoreTypes and ProtobufQtGuiTypes packages, and
uses them directly. This gives you flexibility to use these
types without additional conversion.
*/

View File

@ -0,0 +1,19 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_protobuf_module(ProtobufQtCoreTypes
SOURCES
qtprotobufqtcoretypes.cpp
qtprotobufqtcoretypes.h
qtprotobufqtcoretypesglobal.h
qtprotobufqttypescommon_p.h
GENERATE_CPP_EXPORTS
LIBRARIES
Qt::Core
Qt::Protobuf
Qt::ProtobufPrivate
PROTO_FILES
QtCore/QtCore.proto
PRIVATE_HEADER_FILTERS
".*\\.qpb\\.h"
)

View File

@ -0,0 +1,69 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
syntax = "proto3";
package QtCore;
message QUrl {
string url = 1;
}
message QChar {
uint32 utf16_code_point = 1;
}
message QUuid {
bytes rfc4122_uuid = 1;
}
message QTime {
int32 milliseconds_since_midnight = 1;
}
message QDate {
int64 julian_day = 1;
}
message QDateTime {
int64 utc_msecs_since_unix_epoch = 1;
// TBD: QTBUG-109658 - QTimeZone support
}
message QSize {
int32 width = 1;
int32 height = 2;
}
message QSizeF {
double width = 1;
double height = 2;
}
message QPoint {
sint32 x = 1;
sint32 y = 2;
}
message QPointF {
double x = 1;
double y = 2;
}
message QRect {
sint32 x = 1;
sint32 y = 2;
int32 width = 3;
int32 height = 4;
}
message QRectF {
double x = 1;
double y = 2;
double width = 3;
double height = 4;
}
message QVersionNumber {
repeated int32 segments = 1;
}

View File

@ -0,0 +1,250 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtprotobufqtcoretypes.h"
#include "qtprotobufqttypescommon_p.h"
#include "private/QtCore.qpb.h"
#include <QtCore/qurl.h>
#include <QtCore/qchar.h>
#include <QtCore/quuid.h>
#include <QtCore/qtimezone.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qsize.h>
#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qbuffer.h>
#include <QtCore/qversionnumber.h>
#include <QtCore/qendian.h>
QT_BEGIN_NAMESPACE
std::optional<QUrl> convert(const QtProtobufPrivate::QtCore::QUrl &from)
{
QUrl url(from.url());
return (url.isValid() || url.isEmpty()) ? std::optional<QUrl>(url) : std::nullopt;
}
std::optional<QtProtobufPrivate::QtCore::QUrl> convert(const QUrl &from)
{
if (from.isValid() || from.isEmpty()) {
QtProtobufPrivate::QtCore::QUrl url;
url.setUrl(from.url());
return url;
}
return std::nullopt;
}
QChar convert(const QtProtobufPrivate::QtCore::QChar &from)
{
return QChar(from.utf16CodePoint());
}
QtProtobufPrivate::QtCore::QChar convert(const QChar &from)
{
QtProtobufPrivate::QtCore::QChar symbol;
symbol.setUtf16CodePoint(from.unicode());
return symbol;
}
std::optional<QUuid> convert(const QtProtobufPrivate::QtCore::QUuid &from)
{
if (from.rfc4122Uuid().size() != 16)
return std::nullopt;
return QUuid::fromRfc4122(from.rfc4122Uuid());
}
std::optional<QtProtobufPrivate::QtCore::QUuid> convert(const QUuid &from)
{
if (from.toRfc4122().size() != 16)
return std::nullopt;
QtProtobufPrivate::QtCore::QUuid uuid;
uuid.setRfc4122Uuid(from.toRfc4122());
return uuid;
}
std::optional<QTime> convert(const QtProtobufPrivate::QtCore::QTime &from)
{
QTime time = QTime::fromMSecsSinceStartOfDay(from.millisecondsSinceMidnight());
return time.isValid() ? std::optional<QTime>(time) : std::nullopt;
}
std::optional<QtProtobufPrivate::QtCore::QTime> convert(const QTime &from)
{
if (!from.isValid())
return std::nullopt;
QtProtobufPrivate::QtCore::QTime time;
time.setMillisecondsSinceMidnight(from.msecsSinceStartOfDay());
return time;
}
std::optional<QDate> convert(const QtProtobufPrivate::QtCore::QDate &from)
{
QDate date = QDate::fromJulianDay(from.julianDay());
return date.isValid() ? std::optional<QDate>(date) : std::nullopt;
}
std::optional<QtProtobufPrivate::QtCore::QDate> convert(const QDate &from)
{
if (!from.isValid())
return std::nullopt;
QtProtobufPrivate::QtCore::QDate date;
date.setJulianDay(from.toJulianDay());
return date;
}
std::optional<QDateTime> convert(const QtProtobufPrivate::QtCore::QDateTime &from)
{
QDateTime dateTime(QDateTime::fromMSecsSinceEpoch(from.utcMsecsSinceUnixEpoch(),
QTimeZone::UTC));
return dateTime.isValid() ? std::optional<QDateTime>(dateTime) : std::nullopt;
}
std::optional<QtProtobufPrivate::QtCore::QDateTime> convert(const QDateTime &from)
{
if (!from.isValid())
return std::nullopt;
QtProtobufPrivate::QtCore::QDateTime datetime;
datetime.setUtcMsecsSinceUnixEpoch(from.toMSecsSinceEpoch());
return datetime;
}
QSize convert(const QtProtobufPrivate::QtCore::QSize &from)
{
return QSize(from.width(), from.height());
}
QtProtobufPrivate::QtCore::QSize convert(const QSize &from)
{
QtProtobufPrivate::QtCore::QSize size;
size.setWidth(from.width());
size.setHeight(from.height());
return size;
}
QSizeF convert(const QtProtobufPrivate::QtCore::QSizeF &from)
{
return QSizeF(from.width(), from.height());
}
QtProtobufPrivate::QtCore::QSizeF convert(const QSizeF &from)
{
QtProtobufPrivate::QtCore::QSizeF sizeF;
sizeF.setWidth(from.width());
sizeF.setHeight(from.height());
return sizeF;
}
QPoint convert(const QtProtobufPrivate::QtCore::QPoint &from)
{
return QPoint(from.x(), from.y());
}
QtProtobufPrivate::QtCore::QPoint convert(const QPoint &from)
{
QtProtobufPrivate::QtCore::QPoint pointT;
pointT.setX(from.x());
pointT.setY(from.y());
return pointT;
}
QPointF convert(const QtProtobufPrivate::QtCore::QPointF &from)
{
return QPointF(from.x(), from.y());
}
QtProtobufPrivate::QtCore::QPointF convert(const QPointF &from)
{
QtProtobufPrivate::QtCore::QPointF pointF;
pointF.setX(from.x());
pointF.setY(from.y());
return pointF;
}
QRect convert(const QtProtobufPrivate::QtCore::QRect &from)
{
return QRect(QPoint(from.x(), from.y()),
QSize(from.width(), from.height()));
}
QtProtobufPrivate::QtCore::QRect convert(const QRect &from)
{
QtProtobufPrivate::QtCore::QRect rect;
rect.setX(from.x());
rect.setY(from.y());
rect.setWidth(from.width());
rect.setHeight(from.height());
return rect;
}
QRectF convert(const QtProtobufPrivate::QtCore::QRectF &from)
{
return QRectF(QPointF(from.x(), from.y()),
QSizeF(from.width(), from.height()));
}
QtProtobufPrivate::QtCore::QRectF convert(const QRectF &from)
{
QtProtobufPrivate::QtCore::QRectF rectF;
rectF.setX(from.x());
rectF.setY(from.y());
rectF.setWidth(from.width());
rectF.setHeight(from.height());
return rectF;
}
std::optional<QVersionNumber> convert(const QtProtobufPrivate::QtCore::QVersionNumber &from)
{
if (from.segments().size() == 0)
return std::nullopt;
QList<int> versionList;
const auto segments = from.segments();
for (const auto &segment : segments)
versionList.append(segment);
return QVersionNumber(versionList);
}
std::optional<QtProtobufPrivate::QtCore::QVersionNumber> convert(const QVersionNumber &from)
{
if (from.segments().size() == 0)
return std::nullopt;
QtProtobufPrivate::QtCore::QVersionNumber version;
const auto segments = from.segments();
for (const auto &segment : segments)
version.segments().append(segment);
return version;
}
namespace QtProtobuf {
/*!
Registers serializers for the Qt::ProtobufQtCoreTypes library.
*/
void qRegisterProtobufQtCoreTypes() {
QtProtobufPrivate::registerQtTypeHandler<QUrl, QtProtobufPrivate::QtCore::QUrl>();
QtProtobufPrivate::registerQtTypeHandler<QChar, QtProtobufPrivate::QtCore::QChar>();
QtProtobufPrivate::registerQtTypeHandler<QUuid, QtProtobufPrivate::QtCore::QUuid>();
QtProtobufPrivate::registerQtTypeHandler<QTime, QtProtobufPrivate::QtCore::QTime>();
QtProtobufPrivate::registerQtTypeHandler<QDate, QtProtobufPrivate::QtCore::QDate>();
QtProtobufPrivate::registerQtTypeHandler<QDateTime, QtProtobufPrivate::QtCore::QDateTime>();
QtProtobufPrivate::registerQtTypeHandler<QSize, QtProtobufPrivate::QtCore::QSize>();
QtProtobufPrivate::registerQtTypeHandler<QSizeF, QtProtobufPrivate::QtCore::QSizeF>();
QtProtobufPrivate::registerQtTypeHandler<QPoint, QtProtobufPrivate::QtCore::QPoint>();
QtProtobufPrivate::registerQtTypeHandler<QPointF, QtProtobufPrivate::QtCore::QPointF>();
QtProtobufPrivate::registerQtTypeHandler<QRect, QtProtobufPrivate::QtCore::QRect>();
QtProtobufPrivate::registerQtTypeHandler<QRectF, QtProtobufPrivate::QtCore::QRectF>();
QtProtobufPrivate::registerQtTypeHandler<QVersionNumber,
QtProtobufPrivate::QtCore::QVersionNumber>();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFQTCORETYPES_H
#define QTPROTOBUFQTCORETYPES_H
#include <QtProtobufQtCoreTypes/qtprotobufqtcoretypesglobal.h>
QT_BEGIN_NAMESPACE
namespace QtProtobuf {
Q_PROTOBUFQTCORETYPES_EXPORT void qRegisterProtobufQtCoreTypes();
}
QT_END_NAMESPACE
#endif // QTPROTOBUFQTCORETYPES_H

View File

@ -0,0 +1,11 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFQTCORETYPESGLOBAL_H
#define QTPROTOBUFQTCORETYPESGLOBAL_H
#include <QtProtobufQtCoreTypes/qtprotobufqtcoretypesexports.h>
#include <QtCore/QtGlobal>
#endif // QTPROTOBUFQTCORETYPESGLOBAL_H

View File

@ -0,0 +1,78 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFQTTYPESCOMMON_P_H
#define QTPROTOBUFQTTYPESCOMMON_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtProtobuf/qtprotobuftypes.h>
#include <QtProtobuf/qprotobufserializer.h>
#include <QtCore/QDebug>
#include <QtCore/QVariant>
#include <QtCore/QtGlobal>
#include <optional>
QT_BEGIN_NAMESPACE
namespace QtProtobufPrivate {
template <typename T>
constexpr inline bool is_optional_v = false;
template <typename T>
constexpr inline bool is_optional_v<std::optional<T>> = true;
template<typename QType, typename PType>
void registerQtTypeHandler()
{
registerHandler(
QMetaType::fromType<QType>(),
{ [](const QProtobufSerializer *serializer, const QVariant &value,
const QProtobufPropertyOrderingInfo &info, QByteArray &buffer) {
auto do_convert = [](const QType &qtype) {
auto res = convert(qtype);
if constexpr (is_optional_v<decltype(res)>) {
if (!res) {
qWarning() << "Qt Proto Type conversion error.";
return PType();
}
return PType(std::move(*res));
} else {
return PType(std::move(res));
}
};
PType object = do_convert(value.value<QType>());
buffer.append(serializer->serializeObject(&object,
PType::propertyOrdering, info));
},
[](const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it,
QVariant &value) {
PType object;
serializer->deserializeObject(&object, PType::propertyOrdering, it);
auto res = convert(object);
if constexpr (is_optional_v<decltype(res)>) {
if (!res)
qWarning() << "Qt Proto Type conversion error.";
else
value = QVariant::fromValue<QType>(*res);
} else {
value = QVariant::fromValue<QType>(res);
}
}
});
}
} // namespace QtProtobufPrivate
QT_END_NAMESPACE
#endif // QTPROTOBUFQTTYPESCOMMON_P_H

View File

@ -0,0 +1,20 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_protobuf_module(ProtobufQtGuiTypes
SOURCES
qtprotobufqtguitypes.cpp
qtprotobufqtguitypes.h
qtprotobufqtguitypesglobal.h
GENERATE_CPP_EXPORTS
LIBRARIES
Qt::Core
Qt::Gui
Qt::Protobuf
Qt::ProtobufPrivate
Qt::ProtobufQtCoreTypesPrivate
PROTO_FILES
QtGui/QtGui.proto
PRIVATE_HEADER_FILTERS
".*\\.qpb\\.h"
)

View File

@ -0,0 +1,49 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
syntax = "proto3";
package QtGui;
message QRgba64 {
uint64 rgba64 = 1;
}
message QMatrix4x4 {
// 16 floats in row-major order
repeated float m = 1;
}
message QVector2D {
float x_pos = 1;
float y_pos = 2;
}
message QVector3D {
float x_pos = 1;
float y_pos = 2;
float z_pos = 3;
}
message QVector4D {
float x_pos = 1;
float y_pos = 2;
float z_pos = 3;
float w_pos = 4;
}
message QTransform {
repeated double m = 1;
}
message QQuaternion {
float scalar = 1;
float x = 2;
float y = 3;
float z = 4;
}
message QImage {
bytes data = 1;
string format = 2; // see QImageWriter::supportedImageFormats()
}

View File

@ -0,0 +1,173 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtprotobufqtguitypes.h"
#include "private/QtGui.qpb.h"
#include <QtProtobufQtCoreTypes/private/qtprotobufqttypescommon_p.h>
#include <QtGui/qrgba64.h>
#include <QtGui/qmatrix4x4.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qtransform.h>
#include <QtGui/qquaternion.h>
#include <QtGui/qimage.h>
#include <QtCore/qbuffer.h>
QT_BEGIN_NAMESPACE
QRgba64 convert(const QtProtobufPrivate::QtGui::QRgba64 &from)
{
return QRgba64::fromRgba64(from.rgba64());
}
QtProtobufPrivate::QtGui::QRgba64 convert(const QRgba64 &from)
{
QtProtobufPrivate::QtGui::QRgba64 rgba64;
rgba64.setRgba64((quint64)from);
return rgba64;
}
std::optional<QMatrix4x4> convert(const QtProtobufPrivate::QtGui::QMatrix4x4 &from)
{
QtProtobuf::floatList list = from.m();
if (list.size() == 16) {
return QMatrix4x4(list[0], list[1], list[2], list[3],
list[4], list[5], list[6], list[7],
list[8], list[9], list[10], list[11],
list[12], list[13], list[14], list[15]);
}
qWarning() << "Input for QMatrix4x4 should provide 16 values, but size = "
<< list.size();
return std::nullopt;
}
QtProtobufPrivate::QtGui::QMatrix4x4 convert(const QMatrix4x4 &from)
{
const float *matrixData = from.data();
QtProtobufPrivate::QtGui::QMatrix4x4 matrix;
// QMatrix4x4::data returned in column-major format
matrix.setM({matrixData[0], matrixData[4], matrixData[8], matrixData[12],
matrixData[1], matrixData[5], matrixData[9], matrixData[13],
matrixData[2], matrixData[6], matrixData[10], matrixData[14],
matrixData[3], matrixData[7], matrixData[11], matrixData[15]});
return matrix;
}
QVector2D convert(const QtProtobufPrivate::QtGui::QVector2D &from)
{
return QVector2D(from.xPos(), from.yPos());;
}
QtProtobufPrivate::QtGui::QVector2D convert(const QVector2D &from)
{
QtProtobufPrivate::QtGui::QVector2D vector2D;
vector2D.setXPos(from.x());
vector2D.setYPos(from.y());
return vector2D;
}
QVector3D convert(const QtProtobufPrivate::QtGui::QVector3D &from)
{
return QVector3D(from.xPos(), from.yPos(), from.zPos());
}
QtProtobufPrivate::QtGui::QVector3D convert(const QVector3D &from)
{
QtProtobufPrivate::QtGui::QVector3D vector3D;
vector3D.setXPos(from.x());
vector3D.setYPos(from.y());
vector3D.setZPos(from.z());
return vector3D;
}
QVector4D convert(const QtProtobufPrivate::QtGui::QVector4D &from)
{
return QVector4D(from.xPos(), from.yPos(), from.zPos(), from.wPos());
}
QtProtobufPrivate::QtGui::QVector4D convert(const QVector4D &from)
{
QtProtobufPrivate::QtGui::QVector4D vector4D;
vector4D.setXPos(from.x());
vector4D.setYPos(from.y());
vector4D.setZPos(from.z());
vector4D.setWPos(from.w());
return vector4D;
}
std::optional<QTransform> convert(const QtProtobufPrivate::QtGui::QTransform &from)
{
QtProtobuf::doubleList list = from.m();
if (list.size() == 9) {
return QTransform(list[0], list[1], list[2],
list[3], list[4], list[5],
list[6], list[7], list[8]);
}
qWarning() << "Input list for QTransform should provide 9 members. But size = "
<< list.size();
return std::nullopt;
}
QtProtobufPrivate::QtGui::QTransform convert(const QTransform &from)
{
QtProtobufPrivate::QtGui::QTransform transform;
transform.setM({from.m11(), from.m12(), from.m13(),
from.m21(), from.m22(), from.m23(),
from.m31(), from.m32(), from.m33()});
return transform;
}
QQuaternion convert(const QtProtobufPrivate::QtGui::QQuaternion &from)
{
return QQuaternion(from.scalar(), from.x(), from.y(), from.z());
}
QtProtobufPrivate::QtGui::QQuaternion convert(const QQuaternion &from)
{
QtProtobufPrivate::QtGui::QQuaternion quaternion;
quaternion.setScalar(from.scalar());
quaternion.setX(from.x());
quaternion.setY(from.y());
quaternion.setZ(from.z());
return quaternion;
}
QImage convert(const QtProtobufPrivate::QtGui::QImage &from)
{
return QImage::fromData(from.data(), from.format().toLatin1().data());
}
std::optional<QtProtobufPrivate::QtGui::QImage> convert(const QImage &from)
{
QByteArray data;
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
if (from.save(&buffer, "PNG")) {
QtProtobufPrivate::QtGui::QImage image;
image.setData(data);
image.setFormat(QLatin1StringView("PNG"));
return image;
}
return std::nullopt;
}
namespace QtProtobuf {
/*!
Registers serializers for the Qt::ProtobufQtGuiTypes library.
*/
void qRegisterProtobufQtGuiTypes() {
QtProtobufPrivate::registerQtTypeHandler<QRgba64, QtProtobufPrivate::QtGui::QRgba64>();
QtProtobufPrivate::registerQtTypeHandler<QMatrix4x4, QtProtobufPrivate::QtGui::QMatrix4x4>();
QtProtobufPrivate::registerQtTypeHandler<QVector2D, QtProtobufPrivate::QtGui::QVector2D>();
QtProtobufPrivate::registerQtTypeHandler<QVector3D, QtProtobufPrivate::QtGui::QVector3D>();
QtProtobufPrivate::registerQtTypeHandler<QVector4D, QtProtobufPrivate::QtGui::QVector4D>();
QtProtobufPrivate::registerQtTypeHandler<QTransform, QtProtobufPrivate::QtGui::QTransform>();
QtProtobufPrivate::registerQtTypeHandler<QQuaternion, QtProtobufPrivate::QtGui::QQuaternion>();
QtProtobufPrivate::registerQtTypeHandler<QImage, QtProtobufPrivate::QtGui::QImage>();
}
}
QT_END_NAMESPACE

View File

@ -0,0 +1,20 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFQTGUITYPES_H
#define QTPROTOBUFQTGUITYPES_H
#include <QtProtobufQtGuiTypes/qtprotobufqtguitypesglobal.h>
QT_BEGIN_NAMESPACE
namespace QtProtobuf {
Q_PROTOBUFQTGUITYPES_EXPORT void qRegisterProtobufQtGuiTypes();
}
QT_END_NAMESPACE
#endif // QTPROTOBUFQTGUITYPES_H

View File

@ -0,0 +1,11 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2019 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTPROTOBUFQTTYPESGLOBAL_H
#define QTPROTOBUFQTTYPESGLOBAL_H
#include <QtProtobufQtGuiTypes/qtprotobufqtguitypesexports.h>
#include <QtCore/QtGlobal>
#endif // QTPROTOBUFQTTYPESGLOBAL_H

View File

@ -135,16 +135,16 @@ void QProtobufGenerator::GenerateHeader(const FileDescriptor *file,
externalIncludes.insert("QByteArray"); externalIncludes.insert("QByteArray");
externalIncludes.insert("QString"); externalIncludes.insert("QString");
bool hasQtTypes = false;
bool hasOneofFields = false; bool hasOneofFields = false;
std::unordered_set<std::string> qtTypesSet;
common::iterateMessages( common::iterateMessages(
file, [&externalIncludes, &hasQtTypes, &hasOneofFields](const Descriptor *message) { file, [&](const Descriptor *message) {
for (int i = 0; i < message->field_count(); ++i) { for (int i = 0; i < message->field_count(); ++i) {
const auto *field = message->field(i); const auto *field = message->field(i);
if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map() if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_map()
&& !field->is_repeated() && common::isQtType(field)) { && !field->is_repeated() && common::isQtType(field)) {
externalIncludes.insert(field->message_type()->name()); externalIncludes.insert(field->message_type()->name());
hasQtTypes = true; qtTypesSet.insert(field->message_type()->file()->package());
} }
} }
@ -162,13 +162,13 @@ void QProtobufGenerator::GenerateHeader(const FileDescriptor *file,
if (hasOneofFields) if (hasOneofFields)
externalIncludes.insert("QProtobufOneof"); externalIncludes.insert("QProtobufOneof");
if (hasQtTypes) { for (const auto &qtTypeInclude: qtTypesSet) {
externalIncludes.insert("QtProtobufQtTypes"); externalIncludes.insert("QtProtobuf" + qtTypeInclude + "Types");
} }
for (int i = 0; i < file->dependency_count(); ++i) { for (int i = 0; i < file->dependency_count(); ++i) {
if (file->dependency(i)->name() == "QtProtobuf/QtCore.proto" if (file->dependency(i)->name() == "QtCore/QtCore.proto"
|| file->dependency(i)->name() == "QtProtobuf/QtGui.proto") { || file->dependency(i)->name() == "QtGui/QtGui.proto") {
continue; continue;
} }
// Override the any.proto include with our own specific support // Override the any.proto include with our own specific support

View File

@ -53,12 +53,13 @@ void GeneratorBase::OpenFileNamespaces(
google::protobuf::io::Printer *printer) const google::protobuf::io::Printer *printer) const
{ {
assert(printer != nullptr); assert(printer != nullptr);
assert(file != nullptr);
const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE"); const bool hasQtNamespace = (Options::instance().extraNamespace() == "QT_NAMESPACE");
const std::string scopeNamespaces = file->message_type_count() > 0 const std::string scopeNamespaces = file->message_type_count() > 0
? common::getFullNamespace(file->message_type(0), "::") ? common::getFullNamespace(file->message_type(0), "::")
: common::getFullNamespace(file->enum_type(0), "::"); : common::getFullNamespace(file->enum_type(0), "::");
printer->Print("\n"); printer->Print("\n");
if (hasQtNamespace) if (hasQtNamespace || file->package() == "QtCore" || file->package() == "QtGui")
printer->PrintRaw("QT_BEGIN_NAMESPACE\n"); printer->PrintRaw("QT_BEGIN_NAMESPACE\n");
if (!scopeNamespaces.empty()) { if (!scopeNamespaces.empty()) {
printer->Print({ { "scope_namespaces", scopeNamespaces } }, printer->Print({ { "scope_namespaces", scopeNamespaces } },
@ -79,7 +80,7 @@ void GeneratorBase::CloseFileNamespaces(
printer->Print({ { "scope_namespaces", scopeNamespaces } }, printer->Print({ { "scope_namespaces", scopeNamespaces } },
CommonTemplates::NamespaceClosingTemplate()); CommonTemplates::NamespaceClosingTemplate());
} }
if (hasQtNamespace) if (hasQtNamespace || file->package() == "QtCore" || file->package() == "QtGui")
printer->PrintRaw("QT_END_NAMESPACE\n"); printer->PrintRaw("QT_END_NAMESPACE\n");
printer->Print("\n"); printer->Print("\n");
} }

View File

@ -60,6 +60,8 @@ std::string common::getFullNamespace(std::string_view fullDescriptorName,
return output; return output;
std::string namespacesStr = std::string namespacesStr =
utils::replace(fullDescriptorName.substr(0, nameIndex), ".", separator); utils::replace(fullDescriptorName.substr(0, nameIndex), ".", separator);
if (namespacesStr == "QtCore" || namespacesStr == "QtGui")
namespacesStr = "QtProtobufPrivate" + std::string(separator) + namespacesStr;
if (!output.empty() && !namespacesStr.empty()) if (!output.empty() && !namespacesStr.empty())
output += separator; output += separator;
output += namespacesStr; output += namespacesStr;
@ -393,9 +395,10 @@ TypeMap common::produceClientTypeMap(const ServiceDescriptor *service, const Des
bool common::isQtType(const FieldDescriptor *field) bool common::isQtType(const FieldDescriptor *field)
{ {
return utils::startsWith(field->message_type()->full_name(), "QtProtobuf.") const auto fullName = field->message_type()->full_name();
&& field->file()->package() != "QtProtobuf"; // Used for qttypes library to avoid types const auto package = field->file()->package();
// conversion inside library return (utils::startsWith(fullName, "QtCore.") || utils::startsWith(fullName, "QtGui."))
&& package != "QtCore" && package != "QtGui";
} }
bool common::isOverridden(const FieldDescriptor *field) bool common::isOverridden(const FieldDescriptor *field)

View File

@ -12,3 +12,9 @@ add_subdirectory(protobuf)
if(QT_FEATURE_grpc AND TARGET Qt6::qtprotobufgen AND TARGET Qt6::qtgrpcgen) if(QT_FEATURE_grpc AND TARGET Qt6::qtprotobufgen AND TARGET Qt6::qtgrpcgen)
add_subdirectory(grpc) add_subdirectory(grpc)
endif() endif()
if(TARGET Qt6::ProtobufQtCoreTypes
AND TARGET Qt6::ProtobufQtGuiTypes
AND TARGET Qt6::qtprotobufgen)
add_subdirectory(protobufqttypes)
endif()

View File

@ -0,0 +1,53 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_protobuf_qtcoretypes
SOURCES
qtprotobufqttypescoretest.cpp
INCLUDE_DIRECTORIES
../protobuf/shared
LIBRARIES
Qt::Test
Qt::Protobuf
Qt::ProtobufQtCoreTypes
Qt::Core
DEFINES
PROTOC_EXECUTABLE="$<TARGET_FILE:WrapProtoc::WrapProtoc>"
)
qt_add_protobuf(tst_protobuf_qtcoretypes
PROTO_FILES
../shared/data/proto/qtcoretypes.proto
PROTO_INCLUDES
$<TARGET_PROPERTY:Qt6::ProtobufQtCoreTypes,QT_PROTO_INCLUDES>
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated"
)
qt_autogen_tools_initial_setup(tst_protobuf_qtcoretypes)
if(QT_FEATURE_gui)
qt_internal_add_test(tst_protobuf_qtguitypes
SOURCES
qtprotobufqttypesguitest.cpp
INCLUDE_DIRECTORIES
../protobuf/shared
LIBRARIES
Qt::Test
Qt::Protobuf
Qt::ProtobufQtGuiTypes
Qt::Core
Qt::Gui
DEFINES
PROTOC_EXECUTABLE="$<TARGET_FILE:WrapProtoc::WrapProtoc>"
)
qt_add_protobuf(tst_protobuf_qtguitypes
PROTO_FILES
../shared/data/proto/qtguitypes.proto
PROTO_INCLUDES
$<TARGET_PROPERTY:Qt6::ProtobufQtGuiTypes,QT_PROTO_INCLUDES>
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/generated_gui"
)
qt_autogen_tools_initial_setup(tst_protobuf_qtguitypes)
endif()

View File

@ -0,0 +1,322 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2020 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtcoretypes.qpb.h"
#include <qtprotobuftestscommon.h>
#include <QProtobufSerializer>
#include <QObject>
#include <QtTest/QtTest>
const QTime testTime = QTime(7, 30, 18, 321);
const QDate testDate = QDate(1856, 6, 10);
class QtProtobufQtTypesQtCoreTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void qUrl();
void qChar();
void qUuid();
void qTime();
void qDate();
void qDateTime();
void qSize();
void qPoint();
void qPointF();
void qSizeF();
void qRect();
void qRectF();
void qVersionNumber();
private:
QProtobufSerializer serializer;
};
void QtProtobufQtTypesQtCoreTest::initTestCase()
{
QtProtobuf::qRegisterProtobufQtCoreTypes();
}
using namespace qtprotobufnamespace::qttypes::tests;
void QtProtobufQtTypesQtCoreTest::qUrl()
{
qProtobufAssertMessagePropertyRegistered<QUrlMessage, QUrl>(1, "QUrl", "testField");
QUrlMessage msg;
const char *qtUrl = "https://www.qt.io/product/framework";
const char *hexUrlValue
= "0a250a2368747470733a2f2f7777772e71742e696f2f70726f647563742f6672616d65776f726b";
msg.setTestField(QUrl(qtUrl));
QCOMPARE(QByteArray::fromHex(hexUrlValue), msg.serialize(&serializer));
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexUrlValue));
QCOMPARE(QString::fromLatin1(qtUrl), msg.testField().url());
}
void QtProtobufQtTypesQtCoreTest::qChar()
{
qProtobufAssertMessagePropertyRegistered<QCharMessage, QChar>(1, "QChar", "testField");
QCharMessage msg;
msg.setTestField(QChar('q'));
QCOMPARE(QByteArray::fromHex("0a020871"), msg.serialize(&serializer));
msg.setTestField({});
msg.setTestField({QChar(8364)});
msg.deserialize(&serializer, QByteArray::fromHex("0a0308ac41"));
QCOMPARE(QChar(8364), msg.testField());
}
void QtProtobufQtTypesQtCoreTest::qUuid()
{
qProtobufAssertMessagePropertyRegistered<QUuidMessage, QUuid>(1, "QUuid", "testField");
const char *hexUuidValue = "0a120a104bcbcdc3c5b34d3497feaf78c825cc7d";
const char *uuidValue = "{4bcbcdc3-c5b3-4d34-97fe-af78c825cc7d}";
QUuidMessage msg;
msg.setTestField(QUuid(uuidValue));
QCOMPARE(QByteArray::fromHex(hexUuidValue), msg.serialize(&serializer));
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexUuidValue));
QCOMPARE(QUuid(uuidValue), msg.testField());
}
void QtProtobufQtTypesQtCoreTest::qTime()
{
qProtobufAssertMessagePropertyRegistered<QTimeMessage, QTime>(1, "QTime", "testField");
QTimeMessage msg;
msg.setTestField(QTime(5, 30, 48, 123));
QByteArray result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a0508bbb7bb09"), result);
msg.deserialize(&serializer, QByteArray::fromHex("0a0508d188f10c"));
QCOMPARE(msg.testField().hour(), testTime.hour());
QCOMPARE(msg.testField().minute(), testTime.minute());
QCOMPARE(msg.testField().second(), testTime.second());
QCOMPARE(msg.testField().msec(), testTime.msec());
}
void QtProtobufQtTypesQtCoreTest::qDate()
{
qProtobufAssertMessagePropertyRegistered<QDateMessage, QDate>(1, "QDate", "testField");
QDateMessage msg;
msg.setTestField(testDate);
QByteArray result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a050887b79201"), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a0508aeab9301"));
QCOMPARE(msg.testField().year(), 1897);
}
void QtProtobufQtTypesQtCoreTest::qDateTime()
{
qProtobufAssertMessagePropertyRegistered<QDateTimeMessage, QDateTime>(1,
"QDateTime",
"testField");
QDateTimeMessage msg;
const QDate checkingDate = QDate(1897, 3, 14);
msg.setTestField({checkingDate, testTime, QTimeZone::UTC});
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a0b08d1f8d1da91bdffffff01";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField(), QDateTime(checkingDate, testTime, QTimeZone::UTC));
msg.setTestField({});
msg.setTestField(QDateTime(testDate, testTime, QTimeZone::UTC));
msg.deserialize(&serializer, QByteArray::fromHex("0a0b08d1f0918dda97ffffff01"));
QCOMPARE(msg.testField(), QDateTime(testDate, testTime, QTimeZone::UTC));
}
void QtProtobufQtTypesQtCoreTest::qSize()
{
qProtobufAssertMessagePropertyRegistered<QSizeMessage, QSize>(1, "QSize", "testField");
QSizeMessage msg;
const QSize size({1024, 768});
msg.setTestField(size);
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a06088008108006";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField().width(), size.width());
QCOMPARE(msg.testField().height(), size.height());
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a06088006108008"));
QCOMPARE(msg.testField().width(), size.height());
QCOMPARE(msg.testField().height(), size.width());
}
void QtProtobufQtTypesQtCoreTest::qSizeF()
{
qProtobufAssertMessagePropertyRegistered<QSizeFMessage, QSizeF>(1, "QSizeF", "testField");
QSizeFMessage msg;
const QSizeF sizeF = {1024.0, 768.0};
msg.setTestField(sizeF);
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a12090000000000009040110000000000008840";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField().width(), sizeF.width());
QCOMPARE(msg.testField().height(), sizeF.height());
msg.deserialize(&serializer,
QByteArray::fromHex("0a12090000000000008840110000000000009040"));
QCOMPARE(msg.testField().width(), sizeF.height());
QCOMPARE(msg.testField().height(), sizeF.width());
}
void QtProtobufQtTypesQtCoreTest::qPoint()
{
qProtobufAssertMessagePropertyRegistered<QPointMessage, QPoint>(1, "QPoint", "testField");
QPointMessage msg;
const QPoint point = {1024, 768};
msg.setTestField(point);
QByteArray result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a0608801010800c"), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a0608801010800c"));
QCOMPARE(msg.testField().x(), point.x());
QCOMPARE(msg.testField().y(), point.y());
msg.deserialize(&serializer, QByteArray::fromHex("0a0608800c108010"));
QCOMPARE(msg.testField().x(), point.y());
QCOMPARE(msg.testField().y(), point.x());
}
void QtProtobufQtTypesQtCoreTest::qPointF()
{
qProtobufAssertMessagePropertyRegistered<QPointFMessage, QPointF>(1, "QPointF", "testField");
QPointFMessage msg;
const QPointF pointF = {1024.0, 768.0};
msg.setTestField(pointF);
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a12090000000000009040110000000000008840";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField().x(), pointF.x());
QCOMPARE(msg.testField().y(), pointF.y());
msg.deserialize(&serializer,
QByteArray::fromHex("0a12090000000000008840110000000000009040"));
QCOMPARE(msg.testField().x(), pointF.y());
QCOMPARE(msg.testField().y(), pointF.x());
}
void QtProtobufQtTypesQtCoreTest::qRect()
{
qProtobufAssertMessagePropertyRegistered<QRectMessage, QRect>(1, "QRect", "testField");
QRectMessage msg;
QPoint point(768, 768);
QSize size(500, 1212);
msg.setTestField({point, size});
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a0c08800c10800c18f40320bc09";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField().x(), point.x());
QCOMPARE(msg.testField().y(), point.y());
QCOMPARE(msg.testField().width(), size.width());
QCOMPARE(msg.testField().height(), size.height());
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a06188008208006"));
QCOMPARE(msg.testField().x(), 0);
QCOMPARE(msg.testField().y(), 0);
QCOMPARE(msg.testField().width(), 1024);
QCOMPARE(msg.testField().height(), 768);
}
void QtProtobufQtTypesQtCoreTest::qRectF()
{
qProtobufAssertMessagePropertyRegistered<QRectFMessage, QRectF>(1, "QRectF", "testField");
QRectFMessage msg;
QPointF pointF(768.0, 768.0);
QSizeF sizeF(1024.0, 1024.0);
msg.setTestField({pointF.x(), pointF.y(), sizeF.width(), sizeF.height()});
QByteArray result = msg.serialize(&serializer);
const char *hexValue
= "0a24090000000000008840110000000000008840190000000000009040210000000000009040";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField().x(), pointF.x());
QCOMPARE(msg.testField().y(), pointF.y());
QCOMPARE(msg.testField().width(), sizeF.width());
QCOMPARE(msg.testField().height(),sizeF.height());
msg.setTestField({QPointF(0.0, 0.0), QSizeF(1024.0, 768.0)});
msg.deserialize(&serializer,
QByteArray::fromHex("0a24090000000000000000110000000000000"
"000190000000000009040210000000000008840"));
QCOMPARE(msg.testField().x(), 0.0);
QCOMPARE(msg.testField().y(), 0.0);
QCOMPARE(msg.testField().width(), 1024.0);
QCOMPARE(msg.testField().height(), 768.0);
}
void QtProtobufQtTypesQtCoreTest::qVersionNumber()
{
qProtobufAssertMessagePropertyRegistered<QVersionNumberFMessage,
QVersionNumber>(1, "QVersionNumber", "testField");
QVersionNumberFMessage msg;
QVersionNumber version(1, 1, 0);
msg.setTestField({version});
QByteArray result = msg.serialize(&serializer);
const char *hexValue = "0a050a03010100";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(hexValue));
QCOMPARE(msg.testField(), version);
}
QTEST_MAIN(QtProtobufQtTypesQtCoreTest)
#include "qtprotobufqttypescoretest.moc"

View File

@ -0,0 +1,187 @@
// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2020 Alexey Edelev <semlanik@gmail.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtguitypes.qpb.h"
#include <qtprotobuftestscommon.h>
#include <QProtobufSerializer>
#include <QObject>
#include <QtGui/QPainter>
#include <QtTest/QtTest>
#include <memory>
class QtProtobufQtTypesQtGuiTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase() {
QtProtobuf::qRegisterProtobufQtGuiTypes();
}
void qMatrix4x4();
void qVector2D();
void qVector3D();
void qVector4D();
void qTransform();
void qQuaternion();
void qImage();
private:
QProtobufSerializer serializer;
};
using namespace qtprotobufnamespace::qttypes::tests;
void QtProtobufQtTypesQtGuiTest::qMatrix4x4()
{
qProtobufAssertMessagePropertyRegistered<QMatrix4x4Message,
QMatrix4x4>(1, "QMatrix4x4", "testField");
QMatrix4x4Message msg;
const QMatrix4x4 matrix = QMatrix4x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
msg.setTestField(matrix);
auto result = msg.serialize(&serializer);
const char *matrixHex = "0a420a40000000000000803f0000004000004040000080400000a040"
"0000c0400000e0400000004100001041000020410000304100004041"
"000050410000604100007041";
QCOMPARE(QByteArray::fromHex(matrixHex), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex(matrixHex));
QCOMPARE(matrix, msg.testField());
}
void QtProtobufQtTypesQtGuiTest::qVector2D()
{
qProtobufAssertMessagePropertyRegistered<QVector2DMessage,
QVector2D>(1, "QVector2D", "testField");
QVector2DMessage msg;
QVector2D vector(42, 24);
msg.setTestField(vector);
auto result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a0a0d00002842150000c041"), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a0a0d0000c0411500002842"));
QCOMPARE(QVector2D(vector.y(), vector.x()), msg.testField());
}
void QtProtobufQtTypesQtGuiTest::qVector3D()
{
qProtobufAssertMessagePropertyRegistered<QVector3DMessage,
QVector3D>(1, "QVector3D", "testField");
QVector3DMessage msg;
QVector3D vector(42, 24, 11);
msg.setTestField(vector);
auto result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a0f0d00002842150000c0411d00003041"), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a0f0d0000c04115000030411d00002842"));
QCOMPARE(QVector3D(vector.y(), vector.z(), vector.x()), msg.testField());
}
void QtProtobufQtTypesQtGuiTest::qVector4D()
{
qProtobufAssertMessagePropertyRegistered<QVector4DMessage,
QVector4D>(1, "QVector4D", "testField");
QVector4DMessage msg;
const QVector4D vector({24, 11, 42, 0});
msg.setTestField(vector);
auto result = msg.serialize(&serializer);
QCOMPARE(QByteArray::fromHex("0a140d0000c04115000030411d000028422500000000"), result);
msg.setTestField({});
msg.deserialize(&serializer, QByteArray::fromHex("0a0f0d0000c04115000030411d00002842"));
QCOMPARE(vector, msg.testField());
}
void QtProtobufQtTypesQtGuiTest::qTransform()
{
qProtobufAssertMessagePropertyRegistered<QTransformMessage,
QTransform>(1, "QTransform", "testField");
QTransformMessage msg;
msg.setTestField(QTransform(0, 1, 2, 3, 4, 5, 6, 7, 8));
auto result = msg.serialize(&serializer);
const char * transformHex = "0a4a0a480000000000000000000000000000f03f0000000000000040000"
"00000000008400000000000001040000000000000144000000000000018"
"400000000000001c400000000000002040";
QCOMPARE(QByteArray::fromHex(transformHex), result);
msg.setTestField({});
msg.deserialize(&serializer,
QByteArray::fromHex("0a4a0a4800000000000020400000000000001c40000000000"
"0001840000000000000144000000000000010400000000000"
"0008400000000000000040000000000000f03f0000000000000000"));
QCOMPARE(QTransform(8, 7, 6, 5, 4, 3, 2, 1, 0), msg.testField());
}
void QtProtobufQtTypesQtGuiTest::qQuaternion()
{
qProtobufAssertMessagePropertyRegistered<QQuaternionMessage, QQuaternion>(1, "QQuaternion",
"testField");
QQuaternionMessage msg;
const QQuaternion quater(14, 10, 24, 22);
msg.setTestField(quater);
auto result = msg.serialize(&serializer);
const char *hexValue = "0a140d0000604115000020411d0000c041250000b041";
QCOMPARE(QByteArray::fromHex(hexValue), result);
msg.setTestField({});
msg.deserialize(&serializer,
QByteArray::fromHex(hexValue));
QCOMPARE(quater, msg.testField());
}
void fillTestImage(QImage &testImage)
{
testImage.fill(Qt::transparent);
QPainter painter;
painter.begin(&testImage);
QColor color_1(255, 0, 0, 255);
QColor color_2(0, 255, 0, 255);
QRect rect_1(0, 0, 100, 100);
QRect rect_2(50, 50, 10, 50);
painter.fillRect(rect_1, color_1);
painter.fillRect(rect_2, color_2);
painter.end();
}
void QtProtobufQtTypesQtGuiTest::qImage()
{
qProtobufAssertMessagePropertyRegistered<QImageMessage,
QImage>(1, "QImage", "testField");
QImageMessage msg;
QSize imgSize(200, 200);
QImage initialImage(imgSize, QImage::Format_RGBA64);
fillTestImage(initialImage);
msg.setTestField(initialImage);
QVERIFY(!msg.testField().isNull());
auto result = msg.serialize(&serializer);
msg.setTestField({});
msg.deserialize(&serializer, result);
QCOMPARE(initialImage, msg.testField());
}
QTEST_MAIN(QtProtobufQtTypesQtGuiTest)
#include "qtprotobufqttypesguitest.moc"

View File

@ -0,0 +1,56 @@
syntax = "proto3";
package qtprotobufnamespace.qttypes.tests;
import "QtCore/QtCore.proto";
message QUrlMessage {
QtCore.QUrl testField = 1;
}
message QUuidMessage {
QtCore.QUuid testField = 1;
}
message QCharMessage {
QtCore.QChar testField = 1;
}
message QTimeMessage {
QtCore.QTime testField = 1;
}
message QDateMessage {
QtCore.QDate testField = 1;
}
message QDateTimeMessage {
QtCore.QDateTime testField = 1;
}
message QSizeMessage {
QtCore.QSize testField = 1;
}
message QSizeFMessage {
QtCore.QSizeF testField = 1;
}
message QPointMessage {
QtCore.QPoint testField = 1;
}
message QPointFMessage {
QtCore.QPointF testField = 1;
}
message QRectMessage {
QtCore.QRect testField = 1;
}
message QRectFMessage {
QtCore.QRectF testField = 1;
}
message QVersionNumberFMessage {
QtCore.QVersionNumber testField = 1;
}

View File

@ -0,0 +1,32 @@
syntax = "proto3";
package qtprotobufnamespace.qttypes.tests;
import "QtGui/QtGui.proto";
message QMatrix4x4Message {
QtGui.QMatrix4x4 testField = 1;
}
message QVector2DMessage {
QtGui.QVector2D testField = 1;
}
message QVector3DMessage {
QtGui.QVector3D testField = 1;
}
message QVector4DMessage {
QtGui.QVector4D testField = 1;
}
message QTransformMessage {
QtGui.QTransform testField = 1;
}
message QQuaternionMessage {
QtGui.QQuaternion testField = 1;
}
message QImageMessage {
QtGui.QImage testField = 1;
}