Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qandroiditemmodelproxy.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QtCore/private/qandroiditemmodelproxy_p.h>
6#include <QtCore/private/qandroidmodelindexproxy_p.h>
7#include <QtCore/private/qandroidtypeconverter_p.h>
8
9#include <QtCore/qcoreapplication.h>
10
11QT_BEGIN_NAMESPACE
12
13using namespace QtJniTypes;
14
15std::map<const QAbstractItemModel *, QRecursiveMutex> QAndroidItemModelProxy::s_mutexes =
16 std::map<const QAbstractItemModel *, QRecursiveMutex>{};
17
18jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const
19{
20 Q_ASSERT(jInstance.isValid());
21 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
22 auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
23 return jInstance.callMethod<jint>("columnCount", parentIndex);
24}
25
26bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const
27{
28 Q_ASSERT(jInstance.isValid());
29 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
30 auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
31 return jInstance.callMethod<jboolean>("canFetchMore", parentIndex);
32}
33
34bool QAndroidItemModelProxy::canFetchMoreDefault(const QModelIndex &parent) const
35{
36 return QAbstractItemModel::canFetchMore(parent);
37}
38
39QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const
40{
41 Q_ASSERT(jInstance.isValid());
42 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
43 auto jIndex = QAndroidModelIndexProxy::jInstance(index);
44 QJniObject jData = jInstance.callMethod<jobject>("data", jIndex, role);
45 return QAndroidTypeConverter::toQVariant(jData);
46}
47
48QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex &parent) const
49{
50 Q_ASSERT(jInstance.isValid());
51 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
52 JQtModelIndex jIndex = jInstance.callMethod<JQtModelIndex>(
53 "index", row, column, QAndroidModelIndexProxy::jInstance(parent));
54 return QAndroidModelIndexProxy::qInstance(jIndex);
55}
56
57QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const
58{
59 Q_ASSERT(jInstance.isValid());
60 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
61
62 auto jIndex = QAndroidModelIndexProxy::jInstance(index);
63 return QAndroidModelIndexProxy::qInstance(
64 jInstance.callMethod<JQtModelIndex>("parent", jIndex));
65}
66int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const
67{
68 Q_ASSERT(jInstance.isValid());
69 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
70
71 auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
72 return jInstance.callMethod<int>("rowCount", parentIndex);
73}
74
75QHash<int, QByteArray> QAndroidItemModelProxy::roleNames() const
76{
77 Q_ASSERT(jInstance.isValid());
78 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
79
80 QHash<int, QByteArray> roleNames;
81 HashMap hashMap = jInstance.callMethod<HashMap>("roleNames");
82 Set set = hashMap.callMethod<Set>("keySet");
83 const QJniArray keyArray = set.callMethod<jobject[]>("toArray");
84
85 for (const auto &key : keyArray) {
86 const QJniObject roleName = hashMap.callMethod<jobject>("get", key);
87 const int intKey = QJniObject(key).callMethod<jint>("intValue");
88 const QByteArray roleByteArray = String(roleName).toString().toLatin1();
89 roleNames.insert(intKey, roleByteArray);
90 }
91 return roleNames;
92}
93
94QHash<int, QByteArray> QAndroidItemModelProxy::defaultRoleNames() const
95{
96 return QAbstractItemModel::roleNames();
97}
98
99void QAndroidItemModelProxy::fetchMore(const QModelIndex &parent)
100{
101 Q_ASSERT(jInstance.isValid());
102 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
103 auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
104 jInstance.callMethod<void>("fetchMore", parentIndex);
105}
106
107void QAndroidItemModelProxy::fetchMoreDefault(const QModelIndex &parent)
108{
109 QAbstractItemModel::fetchMore(parent);
110}
111
112bool QAndroidItemModelProxy::hasChildren(const QModelIndex &parent) const
113{
114 Q_ASSERT(jInstance.isValid());
115 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
116 auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
117 return jInstance.callMethod<jboolean>("hasChildren", parentIndex);
118}
119
120bool QAndroidItemModelProxy::hasChildrenDefault(const QModelIndex &parent) const
121{
122 return QAbstractItemModel::hasChildren(parent);
123}
124
125QModelIndex QAndroidItemModelProxy::sibling(int row, int column, const QModelIndex &parent) const
126{
127 Q_ASSERT(jInstance.isValid());
128 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
129 return QAndroidModelIndexProxy::qInstance(jInstance.callMethod<JQtModelIndex>(
130 "sibling", row, column, QAndroidModelIndexProxy::jInstance(parent)));
131}
132
133QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QModelIndex &parent)
134{
135 return QAbstractItemModel::sibling(row, column, parent);
136}
137
138bool QAndroidItemModelProxy::setData(const QModelIndex &index, const QVariant &value, int role)
139{
140 Q_ASSERT(jInstance.isValid());
141 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
142 auto jIndex = QAndroidModelIndexProxy::jInstance(index);
143 auto jValue = QAndroidTypeConverter::toJavaObject(value, QJniEnvironment::getJniEnv());
144 return jInstance.callMethod<jboolean>("setData", jIndex, jValue, role);
145}
146
147bool QAndroidItemModelProxy::setDataDefault(const QModelIndex &index, const QVariant &value,
148 int role)
149{
150 return QAbstractItemModel::setData(index, value, role);
151}
152
154QAndroidItemModelProxy::nativeInstance(JQtAbstractItemModel itemModel)
155{
156 jlong nativeReference = itemModel.callMethod<jlong>("nativeReference");
157 return reinterpret_cast<QAbstractItemModel *>(nativeReference);
158}
159
161QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel)
162{
163 QAbstractItemModel *nativeProxy = nativeInstance(itemModel);
164 if (!nativeProxy) {
165 Q_ASSERT(QCoreApplication::instance());
166
167 nativeProxy = new QAndroidItemModelProxy(itemModel);
168 QThread *qtMainThread = QCoreApplication::instance()->thread();
169 if (nativeProxy->thread() != qtMainThread)
170 nativeProxy->moveToThread(qtMainThread);
171
172 itemModel.callMethod<void>("setNativeReference", reinterpret_cast<jlong>(nativeProxy));
173 connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) {
174 auto proxy = qobject_cast<QAndroidItemModelProxy *>(obj);
175 if (proxy) {
176 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(proxy);
177 proxy->jInstance.callMethod<void>("detachFromNative");
178 }
179 });
180
181 connect(nativeProxy, &QAndroidItemModelProxy::dataChanged, nativeProxy,
182 [nativeProxy](const QModelIndex &topLeft, const QModelIndex &bottomRight,
183 const QList<int> &roles) {
184 auto proxy = qobject_cast<QAndroidItemModelProxy *>(nativeProxy);
185 if (proxy) {
186 QJniObject jInstance = proxy->jInstance;
187 const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(proxy);
188 jInstance.callMethod<void>("handleDataChanged",
189 QAndroidModelIndexProxy::jInstance(topLeft),
190 QAndroidModelIndexProxy::jInstance(bottomRight),
191 QJniArray<jint>(roles));
192 }
193 });
194 }
195 return nativeProxy;
196}
197
198QJniObject QAndroidItemModelProxy::createProxy(QAbstractItemModel *itemModel)
199{
200 return JQtAndroidItemModelProxy(reinterpret_cast<jlong>(itemModel));
201}
202
203int QAndroidItemModelProxy::jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent)
204{
205 const QModelIndex nativeParent = QAndroidModelIndexProxy::qInstance(parent);
206 return invokeNativeMethod(env, object, &QAbstractItemModel::columnCount, nativeParent);
207}
208
209jobject QAndroidItemModelProxy::jni_data(JNIEnv *env, jobject object, JQtModelIndex index,
210 jint role)
211{
212 const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
213 const QVariant data =
214 invokeNativeMethod(env, object, &QAbstractItemModel::data, nativeIndex, role);
215 return QAndroidTypeConverter::toJavaObject(data, env);
216}
217
218jobject QAndroidItemModelProxy::jni_index(JNIEnv *env, jobject object, jint row, jint column,
219 JQtModelIndex parent)
220{
221 auto nativeParent = QAndroidModelIndexProxy::qInstance(parent);
222 const QModelIndex modelIndex =
223 invokeNativeMethod(env, object, &QAbstractItemModel::index, row, column, nativeParent);
224 return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(modelIndex).object());
225}
226
227jobject QAndroidItemModelProxy::jni_parent(JNIEnv *env, jobject object, JQtModelIndex index)
228{
229 const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
230 QModelIndex (QAbstractItemModel::*parentOverloadPtr)(const QModelIndex &) const =
231 &QAbstractItemModel::parent;
232 const QModelIndex parent = invokeNativeMethod(env, object, parentOverloadPtr, nativeIndex);
233 return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(parent).object());
234}
235
236jint QAndroidItemModelProxy::jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent)
237{
238 return invokeNativeMethod(env, object, &QAbstractItemModel::rowCount,
239 QAndroidModelIndexProxy::qInstance(parent));
240}
241
242jobject QAndroidItemModelProxy::jni_roleNames(JNIEnv *env, jobject object)
243{
244 auto roleNames = invokeNativeImpl(env, object, &QAndroidItemModelProxy::defaultRoleNames,
245 &QAbstractItemModel::roleNames);
246 HashMap jRoleNames{};
247 for (auto [role, roleName] : roleNames.asKeyValueRange()) {
248 const Integer jRole(role);
249 jRoleNames.callMethod<jobject>("put", jRole.object(), QString::fromUtf8(roleName));
250 }
251 return env->NewLocalRef(jRoleNames.object());
252}
253
254jobject QAndroidItemModelProxy::jni_createIndex(JNIEnv *env, jobject object, jint row, jint column,
255 jlong id)
256{
257 QModelIndex (QAndroidItemModelProxy::*createIndexPtr)(int, int, quintptr) const =
258 &QAndroidItemModelProxy::createIndex;
259 const QModelIndex index =
260 invokeNativeProxyMethod(env, object, createIndexPtr, row, column, quintptr(id));
261 return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
262}
263
264jboolean QAndroidItemModelProxy::jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
265{
266 return invokeNativeImpl(env, object, &QAndroidItemModelProxy::canFetchMoreDefault,
267 &QAbstractItemModel::canFetchMore,
268 QAndroidModelIndexProxy::qInstance(parent));
269}
270
271void QAndroidItemModelProxy::jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
272{
273 return invokeNativeImpl(env, object, &QAndroidItemModelProxy::fetchMoreDefault,
274 &QAbstractItemModel::fetchMore,
275 QAndroidModelIndexProxy::qInstance(parent));
276}
277
278jboolean QAndroidItemModelProxy::jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent)
279{
280 return invokeNativeImpl(env, object, &QAndroidItemModelProxy::hasChildrenDefault,
281 &QAbstractItemModel::hasChildren,
282 QAndroidModelIndexProxy::qInstance(parent));
283}
284
285jboolean QAndroidItemModelProxy::jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
286 JQtModelIndex parent)
287{
288 return invokeNativeMethod(env, object, &QAbstractItemModel::hasIndex, row, column,
289 QAndroidModelIndexProxy::qInstance(parent));
290}
291
292void QAndroidItemModelProxy::jni_beginInsertColumns(JNIEnv *env, jobject object,
293 JQtModelIndex parent, jint first, jint last)
294{
295
296 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertColumns,
297 QAndroidModelIndexProxy::qInstance(parent), first, last);
298}
299
300void QAndroidItemModelProxy::jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent,
301 jint first, jint last)
302{
303 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertRows,
304 QAndroidModelIndexProxy::qInstance(parent), first, last);
305}
306
307jboolean QAndroidItemModelProxy::jni_beginMoveColumns(JNIEnv *env, jobject object,
308 JQtModelIndex sourceParent, jint sourceFirst,
309 jint sourceLast,
310 JQtModelIndex destinationParent,
311 jint destinationChild)
312{
313 return invokeNativeProxyMethod(
314 env, object, &QAndroidItemModelProxy::beginMoveColumns,
315 QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
316 QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
317}
318
319jboolean QAndroidItemModelProxy::jni_beginMoveRows(JNIEnv *env, jobject object,
320 JQtModelIndex sourceParent, jint sourceFirst,
321 jint sourceLast, JQtModelIndex destinationParent,
322 jint destinationChild)
323{
324 return invokeNativeProxyMethod(
325 env, object, &QAndroidItemModelProxy::beginMoveRows,
326 QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
327 QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
328}
329
330void QAndroidItemModelProxy::jni_beginRemoveColumns(JNIEnv *env, jobject object,
331 JQtModelIndex parent, jint first, jint last)
332{
333 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveColumns,
334 QAndroidModelIndexProxy::qInstance(parent), first, last);
335}
336
337void QAndroidItemModelProxy::jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent,
338 jint first, jint last)
339{
340 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveRows,
341 QAndroidModelIndexProxy::qInstance(parent), first, last);
342}
343
344void QAndroidItemModelProxy::jni_beginResetModel(JNIEnv *env, jobject object)
345{
346 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginResetModel);
347}
348
349void QAndroidItemModelProxy::jni_endInsertColumns(JNIEnv *env, jobject object)
350{
351 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertColumns);
352}
353
354void QAndroidItemModelProxy::jni_endInsertRows(JNIEnv *env, jobject object)
355{
356 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertRows);
357}
358
359void QAndroidItemModelProxy::jni_endMoveColumns(JNIEnv *env, jobject object)
360{
361 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveColumns);
362}
363
364void QAndroidItemModelProxy::jni_endMoveRows(JNIEnv *env, jobject object)
365{
366 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveRows);
367}
368
369void QAndroidItemModelProxy::jni_endRemoveColumns(JNIEnv *env, jobject object)
370{
371 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveColumns);
372}
373
374void QAndroidItemModelProxy::jni_endRemoveRows(JNIEnv *env, jobject object)
375{
376 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveRows);
377}
378
379void QAndroidItemModelProxy::jni_endResetModel(JNIEnv *env, jobject object)
380{
381 invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endResetModel);
382}
383
384jobject QAndroidItemModelProxy::jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
385 JQtModelIndex parent)
386{
387 const QModelIndex index = invokeNativeImpl(env, object, &QAndroidItemModelProxy::siblingDefault,
388 &QAbstractItemModel::sibling, row, column,
389 QAndroidModelIndexProxy::qInstance(parent));
390 return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
391}
392
393jboolean QAndroidItemModelProxy::jni_setData(JNIEnv *env, jobject object, JQtModelIndex index,
394 jobject value, jint role)
395{
396 const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
397 const QVariant qValue = QAndroidTypeConverter::toQVariant(QJniObject(value));
398 return invokeNativeImpl(env, object, &QAndroidItemModelProxy::setDataDefault,
399 &QAbstractItemModel::setData, nativeIndex, qValue, role);
400}
401
402void QAndroidItemModelProxy::jni_dataChanged(JNIEnv *env, jobject object, JQtModelIndex topLeft,
403 JQtModelIndex bottomRight, QJniArray<jint> roles)
404{
405 const QModelIndex nativeTopLeft = QAndroidModelIndexProxy::qInstance(topLeft);
406 const QModelIndex nativeBottomRight = QAndroidModelIndexProxy::qInstance(bottomRight);
407 const QList<int> nativeRoles = roles.toContainer();
408 invokeNativeImpl(env, object, &QAndroidItemModelProxy::dataChanged,
409 &QAbstractItemModel::dataChanged, nativeTopLeft, nativeBottomRight,
410 nativeRoles);
411}
412
413bool QAndroidItemModelProxy::registerAbstractNatives(QJniEnvironment &env)
414{
415 return env.registerNativeMethods(
416 Traits<JQtAbstractItemModel>::className(),
417 { Q_JNI_NATIVE_SCOPED_METHOD(jni_roleNames, QAndroidItemModelProxy),
418 Q_JNI_NATIVE_SCOPED_METHOD(jni_canFetchMore, QAndroidItemModelProxy),
419 Q_JNI_NATIVE_SCOPED_METHOD(jni_createIndex, QAndroidItemModelProxy),
420 Q_JNI_NATIVE_SCOPED_METHOD(jni_fetchMore, QAndroidItemModelProxy),
421 Q_JNI_NATIVE_SCOPED_METHOD(jni_hasChildren, QAndroidItemModelProxy),
422 Q_JNI_NATIVE_SCOPED_METHOD(jni_hasIndex, QAndroidItemModelProxy),
423 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertColumns, QAndroidItemModelProxy),
424 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertRows, QAndroidItemModelProxy),
425 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveColumns, QAndroidItemModelProxy),
426 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveRows, QAndroidItemModelProxy),
427 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveColumns, QAndroidItemModelProxy),
428 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveRows, QAndroidItemModelProxy),
429 Q_JNI_NATIVE_SCOPED_METHOD(jni_beginResetModel, QAndroidItemModelProxy),
430 Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertColumns, QAndroidItemModelProxy),
431 Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertRows, QAndroidItemModelProxy),
432 Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveColumns, QAndroidItemModelProxy),
433 Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveRows, QAndroidItemModelProxy),
434 Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveColumns, QAndroidItemModelProxy),
435 Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveRows, QAndroidItemModelProxy),
436 Q_JNI_NATIVE_SCOPED_METHOD(jni_endResetModel, QAndroidItemModelProxy),
437 Q_JNI_NATIVE_SCOPED_METHOD(jni_sibling, QAndroidItemModelProxy),
438 Q_JNI_NATIVE_SCOPED_METHOD(jni_setData, QAndroidItemModelProxy),
439 Q_JNI_NATIVE_SCOPED_METHOD(jni_dataChanged, QAndroidItemModelProxy) });
440}
441
442bool QAndroidItemModelProxy::registerProxyNatives(QJniEnvironment &env)
443{
444 return env.registerNativeMethods(
445 Traits<JQtAndroidItemModelProxy>::className(),
446 { Q_JNI_NATIVE_SCOPED_METHOD(jni_columnCount, QAndroidItemModelProxy),
447 Q_JNI_NATIVE_SCOPED_METHOD(jni_data, QAndroidItemModelProxy),
448 Q_JNI_NATIVE_SCOPED_METHOD(jni_index, QAndroidItemModelProxy),
449 Q_JNI_NATIVE_SCOPED_METHOD(jni_parent, QAndroidItemModelProxy),
450 Q_JNI_NATIVE_SCOPED_METHOD(jni_rowCount, QAndroidItemModelProxy) });
451}
452
453QT_END_NAMESPACE