8#include "datastream_p_p.h"
23#undef AKONADI_DECLARE_PRIVATE
24#define AKONADI_DECLARE_PRIVATE(Class) \
25 inline Class##Private *Class::d_func() \
27 return reinterpret_cast<Class##Private *>(d_ptr.data()); \
29 inline const Class##Private *Class::d_func() const \
31 return reinterpret_cast<const Class##Private *>(d_ptr.constData()); \
43 case Command::Invalid:
44 return dbg <<
"Invalid";
47 return dbg <<
"Hello";
49 return dbg <<
"Login";
51 return dbg <<
"Logout";
53 case Command::Transaction:
54 return dbg <<
"Transaction";
56 case Command::CreateItem:
57 return dbg <<
"CreateItem";
58 case Command::CopyItems:
59 return dbg <<
"CopyItems";
60 case Command::DeleteItems:
61 return dbg <<
"DeleteItems";
62 case Command::FetchItems:
63 return dbg <<
"FetchItems";
64 case Command::LinkItems:
65 return dbg <<
"LinkItems";
66 case Command::ModifyItems:
67 return dbg <<
"ModifyItems";
68 case Command::MoveItems:
69 return dbg <<
"MoveItems";
71 case Command::CreateCollection:
72 return dbg <<
"CreateCollection";
73 case Command::CopyCollection:
74 return dbg <<
"CopyCollection";
75 case Command::DeleteCollection:
76 return dbg <<
"DeleteCollection";
77 case Command::FetchCollections:
78 return dbg <<
"FetchCollections";
79 case Command::FetchCollectionStats:
80 return dbg <<
"FetchCollectionStats";
81 case Command::ModifyCollection:
82 return dbg <<
"ModifyCollection";
83 case Command::MoveCollection:
84 return dbg <<
"MoveCollection";
87 return dbg <<
"Search";
88 case Command::SearchResult:
89 return dbg <<
"SearchResult";
90 case Command::StoreSearch:
91 return dbg <<
"StoreSearch";
93 case Command::CreateTag:
94 return dbg <<
"CreateTag";
95 case Command::DeleteTag:
96 return dbg <<
"DeleteTag";
97 case Command::FetchTags:
98 return dbg <<
"FetchTags";
99 case Command::ModifyTag:
100 return dbg <<
"ModifyTag";
102 case Command::SelectResource:
103 return dbg <<
"SelectResource";
105 case Command::StreamPayload:
106 return dbg <<
"StreamPayload";
107 case Command::ItemChangeNotification:
108 return dbg <<
"ItemChangeNotification";
109 case Command::CollectionChangeNotification:
110 return dbg <<
"CollectionChangeNotification";
111 case Command::TagChangeNotification:
112 return dbg <<
"TagChangeNotification";
113 case Command::SubscriptionChangeNotification:
114 return dbg <<
"SubscriptionChangeNotification";
115 case Command::DebugChangeNotification:
116 return dbg <<
"DebugChangeNotification";
117 case Command::CreateSubscription:
118 return dbg <<
"CreateSubscription";
119 case Command::ModifySubscription:
120 return dbg <<
"ModifySubscription";
122 case Command::_ResponseBit:
124 return dbg << static_cast<int>(type);
128 return dbg << static_cast<int>(type);
134 Protocol::serialize(stream, ptr);
141 ptr = Protocol::deserialize(stream.device()).
staticCast<T>();
147Command::Command(quint8 type)
152bool Command::operator==(
const Command &other)
const
154 return mType == other.mType;
159 json[QStringLiteral(
"response")] =
static_cast<bool>(mType & Command::_ResponseBit);
161#define case_label(x) \
163 json[QStringLiteral("type")] = QStringLiteral(#x); \
167 switch (mType & ~Command::_ResponseBit) {
173 case_label(Transaction)
175 case_label(CreateItem)
176 case_label(CopyItems)
177 case_label(DeleteItems)
178 case_label(FetchItems)
179 case_label(LinkItems)
180 case_label(ModifyItems)
181 case_label(MoveItems)
183 case_label(CreateCollection)
184 case_label(CopyCollection)
185 case_label(DeleteCollection)
186 case_label(FetchCollections)
187 case_label(FetchCollectionStats)
188 case_label(ModifyCollection)
189 case_label(MoveCollection)
192 case_label(SearchResult)
193 case_label(StoreSearch)
195 case_label(CreateTag)
196 case_label(DeleteTag)
197 case_label(FetchTags)
198 case_label(ModifyTag)
200 case_label(SelectResource)
202 case_label(StreamPayload)
203 case_label(CreateSubscription)
204 case_label(ModifySubscription)
206 case_label(DebugChangeNotification)
207 case_label(ItemChangeNotification)
208 case_label(CollectionChangeNotification)
209 case_label(TagChangeNotification)
210 case_label(SubscriptionChangeNotification)
216DataStream &
operator<<(DataStream &stream,
const Command &cmd)
218 return stream << cmd.mType;
221DataStream &
operator>>(DataStream &stream, Command &cmd)
223 return stream >> cmd.mType;
228 return dbg.
noquote() << ((cmd.mType & Command::_ResponseBit) ?
"Response:" :
"Command:") <<
static_cast<Command::Type
>(cmd.mType & ~Command::_ResponseBit)
232void toJson(
const Akonadi::Protocol::Command *command,
QJsonObject &json)
234#define case_notificationlabel(x, class) \
236 static_cast<const Akonadi::Protocol::class *>(command)->toJson(json); \
238#define case_commandlabel(x, cmd, resp) \
240 static_cast<const Akonadi::Protocol::cmd *>(command)->toJson(json); \
242 case Command::x | Command::_ResponseBit: { \
243 static_cast<const Akonadi::Protocol::resp *>(command)->toJson(json); \
246 switch (command->mType) {
247 case Command::Invalid:
251 case Command::Hello | Command::_ResponseBit: {
252 static_cast<const Akonadi::Protocol::HelloResponse *
>(command)->toJson(json);
254 case_commandlabel(Login, LoginCommand, LoginResponse)
255 case_commandlabel(Logout, LogoutCommand, LogoutResponse)
257 case_commandlabel(Transaction, TransactionCommand, TransactionResponse)
259 case_commandlabel(CreateItem, CreateItemCommand, CreateItemResponse)
260 case_commandlabel(CopyItems, CopyItemsCommand, CopyItemsResponse)
261 case_commandlabel(DeleteItems, DeleteItemsCommand, DeleteItemsResponse)
262 case_commandlabel(FetchItems, FetchItemsCommand, FetchItemsResponse)
263 case_commandlabel(LinkItems, LinkItemsCommand, LinkItemsResponse)
264 case_commandlabel(ModifyItems, ModifyItemsCommand, ModifyItemsResponse)
265 case_commandlabel(MoveItems, MoveItemsCommand, MoveItemsResponse)
267 case_commandlabel(CreateCollection, CreateCollectionCommand, CreateCollectionResponse)
268 case_commandlabel(CopyCollection, CopyCollectionCommand, CopyCollectionResponse)
269 case_commandlabel(DeleteCollection, DeleteCollectionCommand, DeleteCollectionResponse)
270 case_commandlabel(FetchCollections, FetchCollectionsCommand, FetchCollectionsResponse)
271 case_commandlabel(FetchCollectionStats, FetchCollectionStatsCommand, FetchCollectionStatsResponse)
272 case_commandlabel(ModifyCollection, ModifyCollectionCommand, ModifyCollectionResponse)
273 case_commandlabel(MoveCollection, MoveCollectionCommand, MoveCollectionResponse)
275 case_commandlabel(Search, SearchCommand, SearchResponse)
276 case_commandlabel(SearchResult, SearchResultCommand, SearchResultResponse)
277 case_commandlabel(StoreSearch, StoreSearchCommand, StoreSearchResponse)
279 case_commandlabel(CreateTag, CreateTagCommand, CreateTagResponse)
280 case_commandlabel(DeleteTag, DeleteTagCommand, DeleteTagResponse)
281 case_commandlabel(FetchTags, FetchTagsCommand, FetchTagsResponse)
282 case_commandlabel(ModifyTag, ModifyTagCommand, ModifyTagResponse)
284 case_commandlabel(SelectResource, SelectResourceCommand, SelectResourceResponse)
286 case_commandlabel(StreamPayload, StreamPayloadCommand, StreamPayloadResponse)
288 case_commandlabel(CreateSubscription, CreateSubscriptionCommand, CreateSubscriptionResponse)
289 case_commandlabel(ModifySubscription, ModifySubscriptionCommand, ModifySubscriptionResponse)
291 case_notificationlabel(DebugChangeNotification, DebugChangeNotification)
292 case_notificationlabel(ItemChangeNotification, ItemChangeNotification)
293 case_notificationlabel(CollectionChangeNotification, CollectionChangeNotification)
294 case_notificationlabel(TagChangeNotification, TagChangeNotification)
295 case_notificationlabel(SubscriptionChangeNotification, SubscriptionChangeNotification)
298#undef case_notificationlabel
299#undef case_commandlabel
305 : Command(Command::Invalid | Command::_ResponseBit)
310Response::Response(Command::Type type)
311 : Command(
type | Command::_ResponseBit)
316bool Response::operator==(
const Response &other)
const
318 return *
static_cast<const Command *
>(
this) ==
static_cast<const Command &
>(other) && mErrorCode == other.mErrorCode && mErrorMsg == other.mErrorMsg;
323 static_cast<const Command *
>(
this)->toJson(json);
326 error[QStringLiteral(
"code")] = errorCode();
328 json[QStringLiteral(
"error")] =
error;
330 json[QStringLiteral(
"error")] =
false;
334DataStream &
operator<<(DataStream &stream,
const Response &cmd)
336 return stream << static_cast<const Command &>(cmd) << cmd.mErrorCode << cmd.mErrorMsg;
339DataStream &
operator>>(DataStream &stream, Response &cmd)
341 return stream >>
static_cast<Command &
>(cmd) >> cmd.mErrorCode >> cmd.mErrorMsg;
346 return dbg.
noquote() <<
static_cast<const Command &
>(resp) <<
"Error code:" << resp.mErrorCode <<
"\n"
347 <<
"Error msg:" << resp.mErrorMsg <<
"\n";
355 typedef CommandPtr (*CommandFactoryFunc)();
356 typedef ResponsePtr (*ResponseFactoryFunc)();
361 registerType<Command::Hello, Command , HelloResponse>();
362 registerType<Command::Login, LoginCommand, LoginResponse>();
363 registerType<Command::Logout, LogoutCommand, LogoutResponse>();
366 registerType<Command::Transaction, TransactionCommand, TransactionResponse>();
369 registerType<Command::CreateItem, CreateItemCommand, CreateItemResponse>();
370 registerType<Command::CopyItems, CopyItemsCommand, CopyItemsResponse>();
371 registerType<Command::DeleteItems, DeleteItemsCommand, DeleteItemsResponse>();
372 registerType<Command::FetchItems, FetchItemsCommand, FetchItemsResponse>();
373 registerType<Command::LinkItems, LinkItemsCommand, LinkItemsResponse>();
374 registerType<Command::ModifyItems, ModifyItemsCommand, ModifyItemsResponse>();
375 registerType<Command::MoveItems, MoveItemsCommand, MoveItemsResponse>();
378 registerType<Command::CreateCollection, CreateCollectionCommand, CreateCollectionResponse>();
379 registerType<Command::CopyCollection, CopyCollectionCommand, CopyCollectionResponse>();
380 registerType<Command::DeleteCollection, DeleteCollectionCommand, DeleteCollectionResponse>();
381 registerType<Command::FetchCollections, FetchCollectionsCommand, FetchCollectionsResponse>();
382 registerType<Command::FetchCollectionStats, FetchCollectionStatsCommand, FetchCollectionStatsResponse>();
383 registerType<Command::ModifyCollection, ModifyCollectionCommand, ModifyCollectionResponse>();
384 registerType<Command::MoveCollection, MoveCollectionCommand, MoveCollectionResponse>();
387 registerType<Command::Search, SearchCommand, SearchResponse>();
388 registerType<Command::SearchResult, SearchResultCommand, SearchResultResponse>();
389 registerType<Command::StoreSearch, StoreSearchCommand, StoreSearchResponse>();
392 registerType<Command::CreateTag, CreateTagCommand, CreateTagResponse>();
393 registerType<Command::DeleteTag, DeleteTagCommand, DeleteTagResponse>();
394 registerType<Command::FetchTags, FetchTagsCommand, FetchTagsResponse>();
395 registerType<Command::ModifyTag, ModifyTagCommand, ModifyTagResponse>();
398 registerType<Command::SelectResource, SelectResourceCommand, SelectResourceResponse>();
401 registerType<Command::StreamPayload, StreamPayloadCommand, StreamPayloadResponse>();
402 registerType<Command::ItemChangeNotification, ItemChangeNotification, Response >();
403 registerType<Command::CollectionChangeNotification, CollectionChangeNotification, Response >();
404 registerType<Command::TagChangeNotification, TagChangeNotification, Response >();
405 registerType<Command::SubscriptionChangeNotification, SubscriptionChangeNotification, Response >();
406 registerType<Command::DebugChangeNotification, DebugChangeNotification, Response >();
407 registerType<Command::CreateSubscription, CreateSubscriptionCommand, CreateSubscriptionResponse>();
408 registerType<Command::ModifySubscription, ModifySubscriptionCommand, ModifySubscriptionResponse>();
417 static CommandPtr commandFactoryFunc()
422 static ResponsePtr responseFactoryFunc()
427 template<Command::Type T,
typename CmdType,
typename RespType>
430 CommandFactoryFunc cmdFunc = &commandFactoryFunc<CmdType>;
431 ResponseFactoryFunc respFunc = &responseFactoryFunc<RespType>;
432 registrar.
insert(T, qMakePair(cmdFunc, respFunc));
436Q_GLOBAL_STATIC(FactoryPrivate, sFactoryPrivate)
438CommandPtr Factory::command(Command::Type type)
440 auto iter = sFactoryPrivate->registrar.constFind(type);
441 if (iter == sFactoryPrivate->registrar.constEnd()) {
444 return iter->first();
447ResponsePtr Factory::response(Command::Type type)
449 auto iter = sFactoryPrivate->registrar.constFind(type);
450 if (iter == sFactoryPrivate->registrar.constEnd()) {
453 return iter->second();
460bool ItemFetchScope::operator==(
const ItemFetchScope &other)
const
462 return mRequestedParts == other.mRequestedParts && mChangedSince == other.mChangedSince && mAncestorDepth == other.mAncestorDepth && mFlags == other.mFlags;
468 std::copy_if(mRequestedParts.begin(), mRequestedParts.end(), std::back_inserter(rv), [](
const QByteArray &ba) {
469 return ba.startsWith(
"PLD:");
474void ItemFetchScope::setFetch(FetchFlags attributes,
bool fetch)
477 mFlags |= attributes;
478 if (attributes & FullPayload) {
479 if (!mRequestedParts.contains(AKONADI_PARAM_PLD_RFC822)) {
480 mRequestedParts << AKONADI_PARAM_PLD_RFC822;
484 mFlags &= ~attributes;
488bool ItemFetchScope::fetch(FetchFlags flags)
const
491 return mFlags ==
None;
493 return mFlags & flags;
497void ItemFetchScope::toJson(
QJsonObject &json)
const
499 json[QStringLiteral(
"flags")] =
static_cast<int>(mFlags);
500 json[QStringLiteral(
"ChangedSince")] = mChangedSince.toString();
501 json[QStringLiteral(
"AncestorDepth")] =
static_cast<std::underlying_type<AncestorDepth>::type
>(mAncestorDepth);
504 for (
const auto &part : std::as_const(mRequestedParts)) {
507 json[QStringLiteral(
"RequestedParts")] = requestedPartsArray;
513 case ItemFetchScope::NoAncestor:
514 return dbg <<
"No ancestor";
515 case ItemFetchScope::ParentAncestor:
516 return dbg <<
"Parent ancestor";
517 case ItemFetchScope::AllAncestors:
518 return dbg <<
"All ancestors";
523DataStream &
operator<<(DataStream &stream,
const ItemFetchScope &scope)
525 return stream << scope.mRequestedParts << scope.mChangedSince << scope.mAncestorDepth << scope.mFlags;
528DataStream &
operator>>(DataStream &stream, ItemFetchScope &scope)
530 return stream >> scope.mRequestedParts >> scope.mChangedSince >> scope.mAncestorDepth >> scope.mFlags;
535 return dbg.
noquote() <<
"FetchScope(\n"
536 <<
"Fetch Flags:" << scope.mFlags <<
"\n"
537 <<
"Changed Since:" << scope.mChangedSince <<
"\n"
538 <<
"Ancestor Depth:" << scope.mAncestorDepth <<
"\n"
539 <<
"Requested Parts:" << scope.mRequestedParts <<
")\n";
544ScopeContext::ScopeContext(Type type, qint64
id)
546 if (type == ScopeContext::Tag) {
548 }
else if (type == ScopeContext::Collection) {
553ScopeContext::ScopeContext(Type type,
const QString &ctx)
555 if (type == ScopeContext::Tag) {
557 }
else if (type == ScopeContext::Collection) {
562bool ScopeContext::operator==(
const ScopeContext &other)
const
564 return mColCtx == other.mColCtx && mTagCtx == other.mTagCtx;
570 json[QStringLiteral(
"scopeContext")] =
false;
571 }
else if (hasContextId(ScopeContext::Tag)) {
572 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"tag");
573 json[QStringLiteral(
"TagID")] = contextId(ScopeContext::Tag);
574 }
else if (hasContextId(ScopeContext::Collection)) {
575 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"collection");
576 json[QStringLiteral(
"ColID")] = contextId(ScopeContext::Collection);
577 }
else if (hasContextRID(ScopeContext::Tag)) {
578 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"tagrid");
579 json[QStringLiteral(
"TagRID")] = contextRID(ScopeContext::Tag);
580 }
else if (hasContextRID(ScopeContext::Collection)) {
581 json[QStringLiteral(
"scopeContext")] = QStringLiteral(
"colrid");
582 json[QStringLiteral(
"ColRID")] = contextRID(ScopeContext::Collection);
586DataStream &
operator<<(DataStream &stream,
const ScopeContext &context)
591 auto vType = context.mColCtx.typeId();
594 stream << context.mColCtx.toLongLong();
596 stream << context.mColCtx.toString();
599 vType = context.mTagCtx.typeId();
602 stream << context.mTagCtx.toLongLong();
604 stream << context.mTagCtx.toString();
610DataStream &
operator>>(DataStream &stream, ScopeContext &context)
616 for (ScopeContext::Type type : {ScopeContext::Collection, ScopeContext::Tag}) {
620 context.setContext(type,
id);
623 context.setContext(type, rid);
633 dbg <<
"ScopeContext(";
636 }
else if (ctx.hasContextId(ScopeContext::Tag)) {
637 dbg <<
"Tag ID:" << ctx.contextId(ScopeContext::Tag);
638 }
else if (ctx.hasContextId(ScopeContext::Collection)) {
639 dbg <<
"Col ID:" << ctx.contextId(ScopeContext::Collection);
640 }
else if (ctx.hasContextRID(ScopeContext::Tag)) {
641 dbg <<
"Tag RID:" << ctx.contextRID(ScopeContext::Tag);
642 }
else if (ctx.hasContextRID(ScopeContext::Collection)) {
643 dbg <<
"Col RID:" << ctx.contextRID(ScopeContext::Collection);
650ChangeNotification::ChangeNotification(Command::Type type)
655bool ChangeNotification::operator==(
const ChangeNotification &other)
const
657 return static_cast<const Command &
>(*this) == other && mSessionId == other.mSessionId;
665 std::transform(items.
cbegin(), items.
cend(), std::back_inserter(rv), [](
const FetchItemsResponse &item) {
671bool ChangeNotification::isRemove()
const
674 case Command::Invalid:
676 case Command::ItemChangeNotification:
677 return static_cast<const class ItemChangeNotification *
>(
this)->operation() == ItemChangeNotification::Remove;
678 case Command::CollectionChangeNotification:
679 return static_cast<const class CollectionChangeNotification *
>(
this)->operation() == CollectionChangeNotification::Remove;
680 case Command::TagChangeNotification:
681 return static_cast<const class TagChangeNotification *
>(
this)->operation() == TagChangeNotification::Remove;
682 case Command::SubscriptionChangeNotification:
683 return static_cast<const class SubscriptionChangeNotification *
>(
this)->operation() == SubscriptionChangeNotification::Remove;
684 case Command::DebugChangeNotification:
687 Q_ASSERT_X(
false, __FUNCTION__,
"Unknown ChangeNotification type");
693bool ChangeNotification::isMove()
const
696 case Command::Invalid:
698 case Command::ItemChangeNotification:
699 return static_cast<const class ItemChangeNotification *
>(
this)->operation() == ItemChangeNotification::Move;
700 case Command::CollectionChangeNotification:
701 return static_cast<const class CollectionChangeNotification *
>(
this)->operation() == CollectionChangeNotification::Move;
702 case Command::TagChangeNotification:
703 case Command::SubscriptionChangeNotification:
704 case Command::DebugChangeNotification:
707 Q_ASSERT_X(
false, __FUNCTION__,
"Unknown ChangeNotification type");
713bool ChangeNotification::appendAndCompress(ChangeNotificationList &list,
const ChangeNotificationPtr &msg)
716 static const int maxCompressionSearchLength = 10;
717 int searchCounter = 0;
721 if (msg->type() == Command::CollectionChangeNotification) {
722 const auto &cmsg = Protocol::cmdCast<class CollectionChangeNotification>(msg);
723 if (cmsg.operation() == CollectionChangeNotification::Modify) {
728 if ((*iter)->type() == Protocol::Command::CollectionChangeNotification) {
729 auto &it = Protocol::cmdCast<class CollectionChangeNotification>(*iter);
730 const auto &msgCol = cmsg.collection();
731 const auto &itCol = it.collection();
732 if (msgCol.id() == itCol.id() && msgCol.remoteId() == itCol.remoteId() && msgCol.remoteRevision() == itCol.remoteRevision()
733 && msgCol.resource() == itCol.resource() && cmsg.destinationResource() == it.destinationResource()
734 && cmsg.parentCollection() == it.parentCollection() && cmsg.parentDestCollection() == it.parentDestCollection()) {
736 if (cmsg.operation() == CollectionChangeNotification::Modify && it.operation() == CollectionChangeNotification::Modify) {
737 const auto parts = it.changedParts();
738 it.setChangedParts(parts + cmsg.changedParts());
743 if (it.operation() == CollectionChangeNotification::Add) {
749 if (searchCounter >= maxCompressionSearchLength) {
761void ChangeNotification::toJson(
QJsonObject &json)
const
763 static_cast<const Command *
>(
this)->toJson(json);
767 for (
const auto &m : std::as_const(mMetaData)) {
770 json[QStringLiteral(
"metadata")] = metadata;
773DataStream &
operator<<(DataStream &stream,
const ChangeNotification &ntf)
775 return stream << static_cast<const Command &>(ntf) << ntf.mSessionId;
778DataStream &
operator>>(DataStream &stream, ChangeNotification &ntf)
780 return stream >>
static_cast<Command &
>(ntf) >> ntf.mSessionId;
785 return dbg.
noquote() <<
static_cast<const Command &
>(ntf) <<
"Session:" << ntf.mSessionId <<
"\n"
786 <<
"MetaData:" << ntf.mMetaData <<
"\n";
797template<
typename Value,
template<
typename>
class Container>
798inline bool containerComparator(
const Container<Value> &c1,
const Container<Value> &c2)
803template<
typename T,
template<
typename>
class Container>
806 if (c1.size() != c2.size()) {
810 for (
auto it1 = c1.cbegin(), it2 = c2.cbegin(), end1 = c1.cend(); it1 != end1; ++it1, ++it2) {
811 if (**it1 != **it2) {
824#include "protocol_gen.cpp"
Helper integration between Akonadi and Qt.
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QDebug operator<<(QDebug dbg, const DcrawInfoContainer &c)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
iterator insert(const Key &key, const T &value)
void append(const QJsonValue &value)
void append(QList< T > &&value)
const_iterator cbegin() const const
const_iterator cend() const const
void reserve(qsizetype size)
qsizetype size() const const
QSharedPointer< T > create(Args &&... args)
QSharedPointer< X > staticCast() const const
QString fromUtf8(QByteArrayView str)