summaryrefslogtreecommitdiffstats
path: root/src/common-lib/qml-utilities.cpp
blob: e639190fdad092e1f6bc3cfd1fa134d21a924afc (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
// 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

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