1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmllistaccessor_p.h"
41
42#include <private/qqmlmetatype_p.h>
43
44#include <QtCore/qstringlist.h>
45#include <QtCore/qdebug.h>
46
47// ### Remove me
48#include <private/qqmlengine_p.h>
49
50QT_BEGIN_NAMESPACE
51
52QQmlListAccessor::QQmlListAccessor()
53: m_type(Invalid)
54{
55}
56
57QQmlListAccessor::~QQmlListAccessor()
58{
59}
60
61QVariant QQmlListAccessor::list() const
62{
63 return d;
64}
65
66void QQmlListAccessor::setList(const QVariant &v, QQmlEngine *engine)
67{
68 d = v;
69
70 // An incoming JS array as model is treated as a variant list, so we need to
71 // convert it first with toVariant().
72 if (d.userType() == qMetaTypeId<QJSValue>())
73 d = d.value<QJSValue>().toVariant();
74
75 QQmlEnginePrivate *enginePrivate = engine?QQmlEnginePrivate::get(e: engine):nullptr;
76
77 if (!d.isValid()) {
78 m_type = Invalid;
79 } else if (d.userType() == QMetaType::QStringList) {
80 m_type = StringList;
81 } else if (d.userType() == QMetaType::QVariantList) {
82 m_type = VariantList;
83 } else if (d.userType() == qMetaTypeId<QList<QObject *>>()) {
84 m_type = ObjectList;
85 } else if (d.canConvert(targetTypeId: QMetaType::Int)) {
86 // Here we have to check for an upper limit, because down the line code might (well, will)
87 // allocate memory depending on the number of elements. The upper limit cannot be INT_MAX:
88 // QVector<QPointer<QQuickItem>> something;
89 // something.resize(count());
90 // (See e.g. QQuickRepeater::regenerate())
91 // This will allocate data along the lines of:
92 // sizeof(QPointer<QQuickItem>) * count() + QVector::headerSize
93 // So, doing an approximate round-down-to-nice-number, we get:
94 const int upperLimit = 100 * 1000 * 1000;
95
96 int i = v.toInt();
97 if (i < 0) {
98 qWarning(msg: "Model size of %d is less than 0", i);
99 m_type = Invalid;
100 } else if (i > upperLimit) {
101 qWarning(msg: "Model size of %d is bigger than the upper limit %d", i, upperLimit);
102 m_type = Invalid;
103 } else {
104 m_type = Integer;
105 }
106 } else if ((!enginePrivate && QQmlMetaType::isQObject(d.userType())) ||
107 (enginePrivate && enginePrivate->isQObject(d.userType()))) {
108 QObject *data = enginePrivate?enginePrivate->toQObject(d):QQmlMetaType::toQObject(d);
109 d = QVariant::fromValue(value: data);
110 m_type = Instance;
111 } else if (d.userType() == qMetaTypeId<QQmlListReference>()) {
112 m_type = ListProperty;
113 } else {
114 m_type = Instance;
115 }
116}
117
118int QQmlListAccessor::count() const
119{
120 switch(m_type) {
121 case StringList:
122 return qvariant_cast<QStringList>(v: d).count();
123 case VariantList:
124 return qvariant_cast<QVariantList>(v: d).count();
125 case ObjectList:
126 return qvariant_cast<QList<QObject *>>(v: d).count();
127 case ListProperty:
128 return ((const QQmlListReference *)d.constData())->count();
129 case Instance:
130 return 1;
131 case Integer:
132 return d.toInt();
133 default:
134 case Invalid:
135 return 0;
136 }
137}
138
139QVariant QQmlListAccessor::at(int idx) const
140{
141 Q_ASSERT(idx >= 0 && idx < count());
142 switch(m_type) {
143 case StringList:
144 return QVariant::fromValue(value: qvariant_cast<QStringList>(v: d).at(i: idx));
145 case VariantList:
146 return qvariant_cast<QVariantList>(v: d).at(i: idx);
147 case ObjectList:
148 return QVariant::fromValue(value: qvariant_cast<QList<QObject *>>(v: d).at(i: idx));
149 case ListProperty:
150 return QVariant::fromValue(value: ((const QQmlListReference *)d.constData())->at(idx));
151 case Instance:
152 return d;
153 case Integer:
154 return QVariant(idx);
155 default:
156 case Invalid:
157 return QVariant();
158 }
159}
160
161bool QQmlListAccessor::isValid() const
162{
163 return m_type != Invalid;
164}
165
166QT_END_NAMESPACE
167

source code of qtdeclarative/src/qmlmodels/qqmllistaccessor.cpp