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