QQuickLayout introspection in PlasmaQuick::Dialog
There's a problem with PlasmaQuick::Dialog. It is full of [[Big Shot]] duck-qu@ck [[HYPERLINK BLOCKED]] that should've never existed. Namely, it dynamically looks for Layout
attached property on a mainItem
through truly powerful introspection tricks. Behold:
// Search a child that has the needed Layout properties
// HACK: here we are not type safe, but is the only way to access to a pointer of Layout
const auto lstChild = mainItem->children();
for (QObject *child : lstChild) {
// find for the needed property of Layout: minimum/maximum/preferred sizes and fillWidth/fillHeight
if (child->property("minimumWidth").isValid()
&& child->property("minimumHeight").isValid()
&& child->property("preferredWidth").isValid()
&& child->property("preferredHeight").isValid()
&& child->property("maximumWidth").isValid()
&& child->property("maximumHeight").isValid()
&& child->property("fillWidth").isValid()
&& child->property("fillHeight").isValid()) {
layout = child;
break;
}
}
Nothing else is legally possible, since QQuickLayout C++ class is not in public API. We mEaN It.
So, I experimented a bit, and came up with some mildly-cursed-[[Hyperlink blocked.]]-approach absolutely [Little Sponge] code which might seem like its sole intention is to [[TRANSIT KROMER]] to whoever attempts to read it. Totally don't check out this [Patch Shaped File]. I mean it.
class LayoutInspector : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
public:
explicit LayoutInspector(QObject *parent = nullptr);
void classBegin() override;
void componentComplete() override;
Q_INVOKABLE bool isLayout(QObject *object) const;
private:
static const QMetaObject *layoutMetaObject;
};
const QMetaObject *LayoutInspector::layoutMetaObject = nullptr;
void LayoutInspector::classBegin()
{
if (layoutMetaObject) { return; }
const auto engine = qmlEngine(this);
QQmlComponent component(engine, this);
component.setData(QByteArrayLiteral(
"import QtQml 2.15\n"
"import QtQuick.Layouts 1.15\n"
"QtObject {\n"
" Layout.objectName: '123'\n"
"}"),
QUrl(QStringLiteral("LayoutIntrospection.qml")));
const auto item = component.create(nullptr);
const auto layout = item->children().at(0);
// use either one of asserts
Q_ASSERT(layout->objectName() == QStringLiteral("123"));
const auto mo = layout->metaObject();
Q_ASSERT(QString(mo->className()) == QString("QQuickLayoutAttached"));
layoutMetaObject = layout->metaObject();
}
bool LayoutInspector::isLayout(QObject *object) const
{
return layoutMetaObject && object && layoutMetaObject == object->metaObject();
}
hashtag #abnormal_programming #esoteric
Edited by ivan tkachenko