summaryrefslogtreecommitdiffstats
path: root/src/common-lib/qml-utilities.cpp
blob: 3019aae227464c2899b0ff9e9bcf59f1bd32e654 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2019 Luxoft Sweden AB
// Copyright (C) 2018 Pelagicore AG
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <QDir>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQmlInfo>
#include <private/qqmlmetatype_p.h>
#include <private/qv4engine_p.h>
#include <private/qqmlcontext_p.h>
#include <private/qqmlcontextdata_p.h>
#include "logging.h"
#include "utilities.h"
#include "qml-utilities.h"

using namespace Qt::StringLiterals;

QT_BEGIN_NAMESPACE_AM

// copied straight from Qt 5.1.0 qmlscene/main.cpp for now - needs to be revised
void loadQmlDummyDataFiles(QQmlEngine *engine, const QString &directory)
{
    QDir dir(directory + u"/dummydata"_s, u"*.qml"_s);
    QStringList list = dir.entryList();
    for (int i = 0; i < list.size(); ++i) {
        QString qml = list.at(i);
        QQmlComponent comp(engine, dir.filePath(qml));
        QObject *dummyData = comp.create();

        if (comp.isError()) {
            const QList<QQmlError> errors = comp.errors();
            for (const QQmlError &error : errors)
                qCWarning(LogQml) << "Loading dummy data:" << error;
        }

        if (dummyData) {
            qml.truncate(qml.length() - 4);
            engine->rootContext()->setContextProperty(qml, dummyData);
            dummyData->setParent(engine);
        }
    }
}

QVariant convertFromJSVariant(const QVariant &variant)
{
    int type = variant.userType();

    if (type == qMetaTypeId<QJSValue>()) {
        return convertFromJSVariant(variant.value<QJSValue>().toVariant());
    } else if (type == QMetaType::QVariant) {
        // got a matryoshka variant
        return convertFromJSVariant(variant.value<QVariant>());
    } else if (type == QMetaType::QVariantList) {
        QVariantList outList;
        QVariantList inList = variant.toList();
        for (auto it = inList.cbegin(); it != inList.cend(); ++it)
            outList.append(convertFromJSVariant(*it));
        return outList;
    } else if (type == QMetaType::QVariantMap) {
        QVariantMap outMap;
        QVariantMap inMap = variant.toMap();
        for (auto it = inMap.cbegin(); it != inMap.cend(); ++it)
            outMap.insert(it.key(), convertFromJSVariant(it.value()));
        return outMap;
    } else {
        return variant;
    }
}


static const char *qmlContextTag = "_q_am_context_tag";


QVariant findTaggedQmlContext(QObject *object)
{
    auto findTag = [](QQmlContext *context) -> QVariant {
        while (context) {
            auto v = context->property(qmlContextTag);
            if (v.isValid())
                return v;
            context = context->parentContext();
        }
        return { };
    };

    // check the context the object lives in
    QVariant v  = findTag(QQmlEngine::contextForObject(object));
    if (!v.isValid()) {
        // if this didn't work out, check out the calling context
        if (QQmlEngine *engine = qmlEngine(object)) {
            if (QV4::ExecutionEngine *v4 = engine->handle()) {
                if (QQmlContextData *callingContext = v4->callingQmlContext().data())
                    v = findTag(callingContext->asQQmlContext());
            }
        }
    }
    return v;
}

bool tagQmlContext(QQmlContext *context, const QVariant &value)
{
    if (!context || !value.isValid())
        return false;
    return !context->setProperty(qmlContextTag, value);
}

bool ensureCurrentContextIsSystemUI(QObject *object)
{
    static const char *error = "This object can not be used in an Application context";

    if (findTaggedQmlContext(object).isValid()) {
        qmlWarning(object) << error;
        Q_ASSERT_X(false, object ? object->metaObject()->className() : "", error);
        return false;
    }
    return true;
}

bool ensureCurrentContextIsInProcessApplication(QObject *object)
{
    static const char *error = "This object can not be used in the SystemUI context";

    if (!findTaggedQmlContext(object).isValid()) {
        qmlWarning(object) << error;
        Q_ASSERT_X(false, object ? object->metaObject()->className() : "", error);
        return false;
    }
    return true;
}

QT_END_NAMESPACE_AM