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/qjniarray.h>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace QtJniTypes;
++
++ QModelIndex QAndroidModelIndexProxy::qInstance(JQtModelIndex jModelIndex)
++ {
++ if (!jModelIndex.isValid())
++ return QModelIndex();
++
++ const QJniArray<jlong> jPrivateArray = jModelIndex.getField<jlong[]>("m_privateData");
++ const auto privateData = jPrivateArray.toContainer();
++ // The private data must hold row, column, internalId, and model reference.
++ Q_ASSERT(privateData.size() == 4);
++ if (privateData.size() != 4) {
++ qCritical("QtModelIndex has %lld private data entries, expected 4",
++ qlonglong(privateData.size()));
++ return QModelIndex();
++ }
++
++ const jlong modelReference = privateData[3];
++ if (!modelReference)
++ return QModelIndex();
++
++ const jint row = privateData[0];
++ const jint column = privateData[1];
++ QAbstractItemModel *model = reinterpret_cast<QAbstractItemModel *>(modelReference);
++ QAndroidItemModelProxy *proxyModel = qobject_cast<QAndroidItemModelProxy *>(model);
++
++ // If the native model instance is a proxy we have access to the protected function
++ // createIndex(). Else, if the native instance is not a results Java->Qt proxy, we
++ // use index() to get the QModelIndex.
++ if (proxyModel) {
++ const jint internalId = privateData[2];
++ return proxyModel->createIndex(row, column, internalId);
++ } else {
++ const JQtModelIndex parent = jModelIndex.getField<JQtModelIndex>("m_parent");
++ if (parent.isValid())
++ return model->index(row, column, QAndroidModelIndexProxy::qInstance(parent));
++ }
++ return QModelIndex();
++ }
++
++ JQtModelIndex QAndroidModelIndexProxy::jInstance(QModelIndex modelIndex)
++ {
++ if (!modelIndex.isValid())
++ return JQtModelIndex();
++ bool isModelProxy = qobject_cast<const QAndroidItemModelProxy *>(modelIndex.model());
++ if (isModelProxy)
++ return JQtModelIndex(modelIndex.row(), modelIndex.column(), jlong(modelIndex.internalId()),
++ reinterpret_cast<jlong>(modelIndex.model()));
++ else
++ return JQtModelIndex(modelIndex.row(), modelIndex.column(),
++ QAndroidModelIndexProxy::jInstance(modelIndex.parent()),
++ reinterpret_cast<jlong>(modelIndex.model()));
++ }
++
++ jobject QAndroidModelIndexProxy::data(JNIEnv *env, jobject object, int role)
++ {
++ Q_ASSERT(env);
++ Q_ASSERT(object);
++
++ QModelIndex modelIndex = qInstance(object);
++ if (!modelIndex.isValid())
++ return nullptr;
++
++ return QAndroidTypeConverter::toJavaObject(modelIndex.model()->data(modelIndex, role), env);
++ }
++
++ jlong QAndroidModelIndexProxy::internalId(JNIEnv *env, jobject object)
++ {
++ Q_ASSERT(env);
++ Q_ASSERT(object);
++ return qInstance(object).internalId();
++ };
++
++ jboolean QAndroidModelIndexProxy::isValid(JNIEnv *env, jobject object)
++ {
++ Q_ASSERT(env);
++ Q_ASSERT(object);
++ return qInstance(object).isValid();
++ }
++
++ JQtModelIndex QAndroidModelIndexProxy::parent(JNIEnv *env, jobject object)
++ {
++ Q_ASSERT(env);
++ Q_ASSERT(object);
++ return jInstance(qInstance(object).parent());
++ };
++
++ bool QAndroidModelIndexProxy::registerNatives(QJniEnvironment &env)
++ {
++ return env.registerNativeMethods(
++ Traits<JQtModelIndex>::className(),
++ { Q_JNI_NATIVE_SCOPED_METHOD(data, QAndroidModelIndexProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(internalId, QAndroidModelIndexProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(isValid, QAndroidModelIndexProxy),
++ Q_JNI_NATIVE_SCOPED_METHOD(parent, QAndroidModelIndexProxy) });
++ }
++
++ QT_END_NAMESPACE