Revision control
++ // Copyright (C) 2024 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include <QtCore/private/qandroiditemmodelproxy_p.h>
++ #include <QtCore/private/qandroidmodelindexproxy_p.h>
++ #include <QtCore/private/qandroidtypeconverter_p.h>
++
++ #include <QtCore/qcoreapplication.h>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace QtJniTypes;
++
++ std::map<const QAbstractItemModel *, QRecursiveMutex> QAndroidItemModelProxy::s_mutexes =
++ std::map<const QAbstractItemModel *, QRecursiveMutex>{};
++
++ jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
++ return jInstance.callMethod<jint>("columnCount", parentIndex);
++ }
++
++ bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
++ return jInstance.callMethod<jboolean>("canFetchMore", parentIndex);
++ }
++
++ bool QAndroidItemModelProxy::canFetchMoreDefault(const QModelIndex &parent) const
++ {
++ return QAbstractItemModel::canFetchMore(parent);
++ }
++
++ QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
++ QJniObject jData = jInstance.callMethod<jobject>("data", jIndex, role);
++ return QAndroidTypeConverter::toQVariant(jData);
++ }
++
++ QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ JQtModelIndex jIndex = jInstance.callMethod<JQtModelIndex>(
++ "index", row, column, QAndroidModelIndexProxy::jInstance(parent));
++ return QAndroidModelIndexProxy::qInstance(jIndex);
++ }
++
++ QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++
++ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
++ return QAndroidModelIndexProxy::qInstance(
++ jInstance.callMethod<JQtModelIndex>("parent", jIndex));
++ }
++ int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++
++ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
++ return jInstance.callMethod<int>("rowCount", parentIndex);
++ }
++
++ QHash<int, QByteArray> QAndroidItemModelProxy::roleNames() const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++
++ QHash<int, QByteArray> roleNames;
++ HashMap hashMap = jInstance.callMethod<HashMap>("roleNames");
++ Set set = hashMap.callMethod<Set>("keySet");
++ const QJniArray keyArray = set.callMethod<jobject[]>("toArray");
++
++ for (const auto &key : keyArray) {
++ const QJniObject roleName = hashMap.callMethod<jobject>("get", key);
++ const int intKey = QJniObject(key).callMethod<jint>("intValue");
++ const QByteArray roleByteArray = String(roleName).toString().toLatin1();
++ roleNames.insert(intKey, roleByteArray);
++ }
++ return roleNames;
++ }
++
++ QHash<int, QByteArray> QAndroidItemModelProxy::defaultRoleNames() const
++ {
++ return QAbstractItemModel::roleNames();
++ }
++
++ void QAndroidItemModelProxy::fetchMore(const QModelIndex &parent)
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
++ jInstance.callMethod<void>("fetchMore", parentIndex);
++ }
++
++ void QAndroidItemModelProxy::fetchMoreDefault(const QModelIndex &parent)
++ {
++ QAbstractItemModel::fetchMore(parent);
++ }
++
++ bool QAndroidItemModelProxy::hasChildren(const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
++ return jInstance.callMethod<jboolean>("hasChildren", parentIndex);
++ }
++
++ bool QAndroidItemModelProxy::hasChildrenDefault(const QModelIndex &parent) const
++ {
++ return QAbstractItemModel::hasChildren(parent);
++ }
++
++ QModelIndex QAndroidItemModelProxy::sibling(int row, int column, const QModelIndex &parent) const
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ return QAndroidModelIndexProxy::qInstance(jInstance.callMethod<JQtModelIndex>(
++ "sibling", row, column, QAndroidModelIndexProxy::jInstance(parent)));
++ }
++
++ QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QModelIndex &parent)
++ {
++ return QAbstractItemModel::sibling(row, column, parent);
++ }
++
++ bool QAndroidItemModelProxy::setData(const QModelIndex &index, const QVariant &value, int role)
++ {
++ Q_ASSERT(jInstance.isValid());
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(this);
++ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
++ auto jValue = QAndroidTypeConverter::toJavaObject(value, QJniEnvironment::getJniEnv());
++ return jInstance.callMethod<jboolean>("setData", jIndex, jValue, role);
++ }
++
++ bool QAndroidItemModelProxy::setDataDefault(const QModelIndex &index, const QVariant &value,
++ int role)
++ {
++ return QAbstractItemModel::setData(index, value, role);
++ }
++
++ Q_REQUIRED_RESULT QAbstractItemModel *
++ QAndroidItemModelProxy::nativeInstance(JQtAbstractItemModel itemModel)
++ {
++ jlong nativeReference = itemModel.callMethod<jlong>("nativeReference");
++ return reinterpret_cast<QAbstractItemModel *>(nativeReference);
++ }
++
++ Q_REQUIRED_RESULT QAbstractItemModel *
++ QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel)
++ {
++ QAbstractItemModel *nativeProxy = nativeInstance(itemModel);
++ if (!nativeProxy) {
++ Q_ASSERT(QCoreApplication::instance());
++
++ nativeProxy = new QAndroidItemModelProxy(itemModel);
++ QThread *qtMainThread = QCoreApplication::instance()->thread();
++ if (nativeProxy->thread() != qtMainThread)
++ nativeProxy->moveToThread(qtMainThread);
++
++ itemModel.callMethod<void>("setNativeReference", reinterpret_cast<jlong>(nativeProxy));
++ connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) {
++ auto proxy = qobject_cast<QAndroidItemModelProxy *>(obj);
++ if (proxy) {
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(proxy);
++ proxy->jInstance.callMethod<void>("detachFromNative");
++ }
++ });
++
++ connect(nativeProxy, &QAndroidItemModelProxy::dataChanged, nativeProxy,
++ [nativeProxy](const QModelIndex &topLeft, const QModelIndex &bottomRight,
++ const QList<int> &roles) {
++ auto proxy = qobject_cast<QAndroidItemModelProxy *>(nativeProxy);
++ if (proxy) {
++ QJniObject jInstance = proxy->jInstance;
++ const QMutexLocker<QRecursiveMutex> lock = getMutexLocker(proxy);
++ jInstance.callMethod<void>("handleDataChanged",
++ QAndroidModelIndexProxy::jInstance(topLeft),
++ QAndroidModelIndexProxy::jInstance(bottomRight),
++ QJniArray<jint>(roles));
++ }
++ });
++ }
++ return nativeProxy;
++ }
++
++ QJniObject QAndroidItemModelProxy::createProxy(QAbstractItemModel *itemModel)
++ {
++ return JQtAndroidItemModelProxy(reinterpret_cast<jlong>(itemModel));
++ }
++
++ int QAndroidItemModelProxy::jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent)
++ {
++ const QModelIndex nativeParent = QAndroidModelIndexProxy::qInstance(parent);
++ return invokeNativeMethod(env, object, &QAbstractItemModel::columnCount, nativeParent);
++ }
++
++ jobject QAndroidItemModelProxy::jni_data(JNIEnv *env, jobject object, JQtModelIndex index,
++ jint role)
++ {
++ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
++ const QVariant data =
++ invokeNativeMethod(env, object, &QAbstractItemModel::data, nativeIndex, role);
++ return QAndroidTypeConverter::toJavaObject(data, env);
++ }
++
++ jobject QAndroidItemModelProxy::jni_index(JNIEnv *env, jobject object, jint row, jint column,
++ JQtModelIndex parent)
++ {
++ auto nativeParent = QAndroidModelIndexProxy::qInstance(parent);
++ const QModelIndex modelIndex =
++ invokeNativeMethod(env, object, &QAbstractItemModel::index, row, column, nativeParent);
++ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(modelIndex).object());
++ }
++
++ jobject QAndroidItemModelProxy::jni_parent(JNIEnv *env, jobject object, JQtModelIndex index)
++ {
++ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
++ QModelIndex (QAbstractItemModel::*parentOverloadPtr)(const QModelIndex &) const =
++ &QAbstractItemModel::parent;
++ const QModelIndex parent = invokeNativeMethod(env, object, parentOverloadPtr, nativeIndex);
++ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(parent).object());
++ }
++
++ jint QAndroidItemModelProxy::jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent)
++ {
++ return invokeNativeMethod(env, object, &QAbstractItemModel::rowCount,
++ QAndroidModelIndexProxy::qInstance(parent));
++ }
++
++ jobject QAndroidItemModelProxy::jni_roleNames(JNIEnv *env, jobject object)
++ {
++ auto roleNames = invokeNativeImpl(env, object, &QAndroidItemModelProxy::defaultRoleNames,
++ &QAbstractItemModel::roleNames);
++ HashMap jRoleNames{};
++ for (auto [role, roleName] : roleNames.asKeyValueRange()) {
++ const Integer jRole(role);
++ jRoleNames.callMethod<jobject>("put", jRole.object(), QString::fromUtf8(roleName));
++ }
++ return env->NewLocalRef(jRoleNames.object());
++ }
++
++ jobject QAndroidItemModelProxy::jni_createIndex(JNIEnv *env, jobject object, jint row, jint column,
++ jlong id)
++ {
++ QModelIndex (QAndroidItemModelProxy::*createIndexPtr)(int, int, quintptr) const =
++ &QAndroidItemModelProxy::createIndex;
++ const QModelIndex index =
++ invokeNativeProxyMethod(env, object, createIndexPtr, row, column, quintptr(id));
++ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
++ }
++
++ jboolean QAndroidItemModelProxy::jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
++ {
++ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::canFetchMoreDefault,
++ &QAbstractItemModel::canFetchMore,
++ QAndroidModelIndexProxy::qInstance(parent));
++ }
++
++ void QAndroidItemModelProxy::jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
++ {
++ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::fetchMoreDefault,
++ &QAbstractItemModel::fetchMore,
++ QAndroidModelIndexProxy::qInstance(parent));
++ }
++
++ jboolean QAndroidItemModelProxy::jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent)
++ {
++ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::hasChildrenDefault,
++ &QAbstractItemModel::hasChildren,
++ QAndroidModelIndexProxy::qInstance(parent));
++ }
++
++ jboolean QAndroidItemModelProxy::jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
++ JQtModelIndex parent)
++ {
++ return invokeNativeMethod(env, object, &QAbstractItemModel::hasIndex, row, column,
++ QAndroidModelIndexProxy::qInstance(parent));
++ }
++
++ void QAndroidItemModelProxy::jni_beginInsertColumns(JNIEnv *env, jobject object,
++ JQtModelIndex parent, jint first, jint last)
++ {
++
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertColumns,
++ QAndroidModelIndexProxy::qInstance(parent), first, last);
++ }
++
++ void QAndroidItemModelProxy::jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent,
++ jint first, jint last)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertRows,
++ QAndroidModelIndexProxy::qInstance(parent), first, last);
++ }
++
++ jboolean QAndroidItemModelProxy::jni_beginMoveColumns(JNIEnv *env, jobject object,
++ JQtModelIndex sourceParent, jint sourceFirst,
++ jint sourceLast,
++ JQtModelIndex destinationParent,
++ jint destinationChild)
++ {
++ return invokeNativeProxyMethod(
++ env, object, &QAndroidItemModelProxy::beginMoveColumns,
++ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
++ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
++ }
++
++ jboolean QAndroidItemModelProxy::jni_beginMoveRows(JNIEnv *env, jobject object,
++ JQtModelIndex sourceParent, jint sourceFirst,
++ jint sourceLast, JQtModelIndex destinationParent,
++ jint destinationChild)
++ {
++ return invokeNativeProxyMethod(
++ env, object, &QAndroidItemModelProxy::beginMoveRows,
++ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
++ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
++ }
++
++ void QAndroidItemModelProxy::jni_beginRemoveColumns(JNIEnv *env, jobject object,
++ JQtModelIndex parent, jint first, jint last)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveColumns,
++ QAndroidModelIndexProxy::qInstance(parent), first, last);
++ }
++
++ void QAndroidItemModelProxy::jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent,
++ jint first, jint last)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveRows,
++ QAndroidModelIndexProxy::qInstance(parent), first, last);
++ }
++
++ void QAndroidItemModelProxy::jni_beginResetModel(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginResetModel);
++ }
++
++ void QAndroidItemModelProxy::jni_endInsertColumns(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertColumns);
++ }
++
++ void QAndroidItemModelProxy::jni_endInsertRows(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertRows);
++ }
++
++ void QAndroidItemModelProxy::jni_endMoveColumns(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveColumns);
++ }
++
++ void QAndroidItemModelProxy::jni_endMoveRows(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveRows);
++ }
++
++ void QAndroidItemModelProxy::jni_endRemoveColumns(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveColumns);
++ }
++
++ void QAndroidItemModelProxy::jni_endRemoveRows(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveRows);
++ }
++
++ void QAndroidItemModelProxy::jni_endResetModel(JNIEnv *env, jobject object)
++ {
++ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endResetModel);
++ }
++
++ jobject QAndroidItemModelProxy::jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
++ JQtModelIndex parent)
++ {
++ const QModelIndex index = invokeNativeImpl(env, object, &QAndroidItemModelProxy::siblingDefault,
++ &QAbstractItemModel::sibling, row, column,
++ QAndroidModelIndexProxy::qInstance(parent));
++ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
++ }
++
++ jboolean QAndroidItemModelProxy::jni_setData(JNIEnv *env, jobject object, JQtModelIndex index,
++ jobject value, jint role)
++ {
++ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
++ const QVariant qValue = QAndroidTypeConverter::toQVariant(QJniObject(value));
++ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::setDataDefault,
++ &QAbstractItemModel::setData, nativeIndex, qValue, role);
++ }
++
++ void QAndroidItemModelProxy::jni_dataChanged(JNIEnv *env, jobject object, JQtModelIndex topLeft,
++ JQtModelIndex bottomRight, QJniArray<jint> roles)
++ {
++ const QModelIndex nativeTopLeft = QAndroidModelIndexProxy::qInstance(topLeft);
++ const QModelIndex nativeBottomRight = QAndroidModelIndexProxy::qInstance(bottomRight);
++ const QList<int> nativeRoles = roles.toContainer();
++ invokeNativeImpl(env, object, &QAndroidItemModelProxy::dataChanged,
++ &QAbstractItemModel::dataChanged, nativeTopLeft, nativeBottomRight,
++ nativeRoles);
++ }
++
++ bool QAndroidItemModelProxy::registerAbstractNatives(QJniEnvironment &env)
++ {
++ return env.registerNativeMethods(
++ Traits<JQtAbstractItemModel>::className(),
++ { Q_JNI_NATIVE_SCOPED_METHOD(jni_roleNames, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_canFetchMore, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_createIndex, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_fetchMore, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasChildren, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasIndex, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginResetModel, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveColumns, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveRows, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_endResetModel, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_sibling, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_setData, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_dataChanged, QAndroidItemModelProxy) });
++ }
++
++ bool QAndroidItemModelProxy::registerProxyNatives(QJniEnvironment &env)
++ {
++ return env.registerNativeMethods(
++ Traits<JQtAndroidItemModelProxy>::className(),
++ { Q_JNI_NATIVE_SCOPED_METHOD(jni_columnCount, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_data, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_index, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_parent, QAndroidItemModelProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(jni_rowCount, QAndroidItemModelProxy) });
++ }
++
++ QT_END_NAMESPACE