Android: Add Java QtAbstractItemModel and QtAbstractListModel

These classes used to be a part of QtDeclarative and are being moved
to QtCore based on API reviews.

Task-number: QTBUG-126976
Task-number: QTBUG-126977
Change-Id: Ic269f23ca2292031cda62faf41428667889537d0
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit 55fc15ce8272073b9b404762b83e3e7acee0111e)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Soheil Armin 2024-07-09 16:23:46 +03:00 committed by Qt Cherry-pick Bot
parent 81a9cbe1db
commit e544ae0abd
12 changed files with 1377 additions and 3 deletions

View File

@ -46,6 +46,10 @@ set(java_sources
src/org/qtproject/qt/android/QtMenuInterface.java src/org/qtproject/qt/android/QtMenuInterface.java
src/org/qtproject/qt/android/QtLayoutInterface.java src/org/qtproject/qt/android/QtLayoutInterface.java
src/org/qtproject/qt/android/QtInputInterface.java src/org/qtproject/qt/android/QtInputInterface.java
src/org/qtproject/qt/android/QtAbstractItemModel.java
src/org/qtproject/qt/android/QtAbstractItemModelProxy.java
src/org/qtproject/qt/android/QtModelIndex.java
src/org/qtproject/qt/android/QtAbstractListModel.java
) )
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android

View File

@ -0,0 +1,490 @@
// 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
package org.qtproject.qt.android;
import java.util.HashMap;
/**
* QtAbstractItemModel is a base class for implementing custom models in Java,
* similar to the C++ QAbstractItemModel.
*
* The QAbstractItemModel class defines the standard interface that item
* models must use to be able to interoperate with other components in the
* model/view architecture. It is not supposed to be instantiated directly.
* Instead, you should extend it to create new models.
*
* A QtAbstractItemModel can be used as the underlying data model for the
* item view elements in QML.
*
* If you need a model to use with an item view, such as QML's ListView element,
* you should consider extending {@link QtAbstractListModel} instead of this class.
*
* The underlying data model is exposed to views and delegates as a hierarchy
* of tables. If you do not use the hierarchy, the model is a simple table of
* rows and columns. Each item has a unique index specified by a {@link QtModelIndex}.
*
* @image modelindex-no-parent.png
*
* Every item of data that can be accessed via a model has an associated model
* index. You can obtain this model index using the {@link #index(int, int)} method.
* Each index may have a {@link #sibling(int, int)} index; child items have a
* {@link #parent()} index.
*
* Each item has data elements associated with it, and they can be
* retrieved by specifying a role to the model's {@link #data(QtModelIndex, int)} function.
*
* If an item has child objects, {@link #hasChildren(QtModelIndex)} returns true for the
* corresponding index.
*
* The model has a {@link #rowCount(QtModelIndex)} and a {@link #columnCount(QtModelIndex)}
* for each level of the hierarchy.
*
* Extending QtAbstractItemModel:
*
* Some general guidelines for sub-classing models are available in the
* {@link https://doc.qt.io/qt-6/model-view-programming.html#model-subclassing-reference}
* model sub-classing reference.
*
* When sub-classing QtAbstractItemModel, at the very least, you must implement
* {@link #index(int, int)}, {@link #parent(QtModelIndex)},{@link #rowCount(QtModelIndex)},
* {@link #columnCount(QtModelIndex)}, and {@link #data(QtModelIndex, int)}.
* These abstract methods are used in all models.
*
* You can also re-implement {@link #hasChildren(QtModelIndex)} to provide special behavior for
* models where the implementation of {@link #rowCount(QtModelIndex)} is expensive. This makes it
* possible for models to restrict the amount of data requested by views and
* can be used as a way to implement the population of model data.
*
* Custom models need to create model indexes for other components to use. To
* do this, call {@link #createIndex(int, int, long)} with suitable row and column numbers for the
* item, and a long type identifier for it.
* The combination of these values must be unique for each item. Custom models
* typically use these unique identifiers in other re-implemented functions to
* retrieve item data and access information about the item's parents and
* children.
*
* To create models that populate incrementally, you can re-implement
* {@link #fetchMore(QtModelIndex)} and {@link #canFetchMore(QtModelIndex)}.
* If the re-implementation of {@link #fetchMore(QtModelIndex)} adds
* rows to the model, {@link QtAbstractItemModel#beginInsertRows(QtModelIndex, int, int)} and
* {@link QtAbstractItemModel#endInsertRows()} must be called.
* @since 6.8
*/
public abstract class QtAbstractItemModel
{
/**
* Constructs a new QtAbstractItemModel.
*/
public QtAbstractItemModel(){};
/**
* Returns the number of columns for the children of the given parent.
* In most subclasses, the number of columns is independent of the parent.
*
* For example:
* @Override
* int columnCount(const QtModelIndex parent)
* {
* return 3;
* }
*
* When implementing a table-based model, columnCount() should return 0,
* when the parent is valid.
*
* @param parent The parent index.
* @return The number of columns.
* @see #rowCount(QtModelIndex)
*/
public abstract int columnCount(QtModelIndex parent);
/**
* Returns the data for the given index and role.
* Types conversions are:
* QML <- Java
* int <- Integer
* string <- String
* double <- Double
* real <- Double
* bool <- Boolean
*
* @param index The index.
* @param role The role.
* @return The data object.
*/
public abstract Object data(QtModelIndex index, int role);
/**
* Returns the index for the specified row and column for the supplied parent index.
* When re-implementing this function in a subclass, call createIndex() to generate model
* indexes that other components can use to refer to items in your model.
*
* @param row The row.
* @param column The column.
* @param parent The parent index.
* @return The index.
* @see #createIndex(int row, int column, long id)
*/
public abstract QtModelIndex index(int row, int column, QtModelIndex parent);
/**
* Returns the parent of the model item with the given index. If the item
* has no parent, then an invalid QtModelIndex is returned.
*
* A common convention used in models that expose tree data structures is that
* only items in the first column have children. For that case, when
* re-implementing this function in a subclass, the column of the returned
* QtModelIndex would be 0.
* When re-implementing this function in a subclass, be careful to avoid
* calling QtModelIndex member functions, such as QtModelIndex::parent(), since
* indexes belonging to your model will call your implementation,
* leading to infinite recursion.
*
* @param index The index.
* @return The parent index.
* @see #createIndex(int row, int column, long id)
*/
public abstract QtModelIndex parent(QtModelIndex index);
/**
* Returns the number of rows under the given parent. When the parent is
* valid, it means that rowCount is returning the number of children of the parent.
* Note: when implementing a table-based model, rowCount() should return 0,
* when the parent is valid.
*
* @param parent The parent index.
* @return The number of rows.
* @see #columnCount(QtModelIndex parent)
*/
public abstract int rowCount(QtModelIndex parent);
/**
* Returns whether more items can be fetched for the given parent index.
*
* @param parent The parent index.
* @return True if more items can be fetched, false otherwise.
*/
public native boolean canFetchMore(QtModelIndex parent);
/**
* Fetches any available data for the items with the parent specified by the
* parent index.
*
* @param parent The parent index.
*/
public native void fetchMore(QtModelIndex parent);
/**
* Returns true if the parent has any children; otherwise, returns false.
* Use rowCount() on the parent to get the number of children.
*
* @param parent The parent index.
* @return True if the parent has children, false otherwise.
* @see #parent(QtModelIndex index)
* @see #index(int row, int column, QtModelIndex parent)
*/
public native boolean hasChildren(QtModelIndex parent);
/**
* Returns true if the model returns a valid QModelIndex for row and
* column with parent, otherwise returns \c{false}.
*
* @param row The row.
* @param column The column.
* @param parent The parent index.
* @return True if the index exists, false otherwise.
*/
public native boolean hasIndex(int row, int column, QtModelIndex parent);
/**
* Returns a map of role names.
* You must override this to provide your own role names or the
* {@link https://doc.qt.io/qt-6/qabstractitemmodel.html#roleNames defaults}
* will be used.
*
* @return The role names map.
*/
public HashMap<Integer, String> roleNames()
{
return (HashMap<Integer, String>)jni_roleNames();
}
/**
* Returns the sibling at row and column for the item at index or an
* invalid QModelIndex if there is no sibling at that location.
*
* sibling() is just a convenience function that finds the item's parent and
* uses it to retrieve the index of the child item in the specified row and
* column.
*
* This method can optionally be overridden to optimize a specific implementation.
*
* @param row The row.
* @param column The column.
* @param parent The parent index.
* @return The sibling index.
*/
public QtModelIndex sibling(int row, int column, QtModelIndex parent)
{
return (QtModelIndex)jni_sibling(row, column, parent);
}
/**
* Begins a column insertion operation.
* The parent index corresponds to the parent into which the new columns
* are inserted; first and last are the column numbers of the new
* columns will have after they have been inserted.
*
* @see #endInsertColumns()
*/
protected final void beginInsertColumns(QtModelIndex parent, int first, int last)
{
jni_beginInsertColumns(parent, first, last);
}
/**
* Begins a row insertion operation.
* Parent index corresponds to the parent into which the new rows
* are inserted; first and last are the row numbers the new rows will have
* after they have been inserted.
* @see #endInsertRows()
*/
protected final void beginInsertRows(QtModelIndex parent, int first, int last)
{
jni_beginInsertRows(parent, first, last);
}
/**
Begins a column move operation.
When re-implementing a subclass, this method simplifies moving
entities in your model. This method is responsible for moving
persistent indexes in the model.
The sourceParent index corresponds to the parent from which the
columns are moved; sourceFirst and sourceLast are the first and last
column numbers of the columns to be moved. The destinationParent index
corresponds to the parent into which those columns are moved. The
destinationChild is the column to which the columns will be moved. That
is, the index at column sourceFirst in sourceParent will become
column destinationChild in destinationParent, followed by all other
columns up to sourceLast.
However, when moving columns down in the same parent (sourceParent
and destinationParent are equal), the columns will be placed before the
destinationChild index. If you wish to move columns 0 and 1 so
they will become columns 1 and 2, destinationChild should be 3. In this
case, the new index for the source column i (which is between
sourceFirst and sourceLast) is equal to (destinationChild-sourceLast-1+i).
Note that if sourceParent and destinationParent are the same,
you must ensure that the destinationChild is not within the range
of sourceFirst and sourceLast + 1. You must also ensure that you
do not attempt to move a column to one of its own children or ancestors.
This method returns false if either condition is true, in which case you
should abort your move operation.
@see endMoveColumns()
*/
protected final boolean beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
int sourceLast, QtModelIndex destinationParent,
int destinationChild)
{
return jni_beginMoveColumns(sourceParent, sourceFirst, sourceLast, destinationParent,
destinationChild);
}
/**
* Begins a row move operation.
* When re-implementing a subclass, this method simplifies moving
* entities in your model.
* The sourceParent index corresponds to the parent from which the
* rows are moved; sourceFirst and sourceLast are the first and last
* row numbers of the rows to be moved. The destinationParent index
* corresponds to the parent into which those rows are moved. The
* destinationChild is the row to which the rows will be moved. That
* is, the index at row sourceFirst in sourceParent will become
* row destinationChild in destinationParent, followed by all other
* rows up to sourceLast.
* However, when moving rows down in the same parent (sourceParent
* and destinationParent are equal), the rows will be placed before the
* destinationChild index. That is, if you wish to move rows 0 and 1 so
* they will become rows 1 and 2, destinationChild should be 3. In this
* case, the new index for the source row i (which is between
* sourceFirst and sourceLast) is equal to
* (destinationChild-sourceLast-1+i).
* Note that if sourceParent and destinationParent are the same,
* you must ensure that the destinationChild is not within the range
* of sourceFirst and sourceLast + 1. You must also ensure that you
* do not attempt to move a row to one of its own children or ancestors.
* This method returns false if either condition is true, in which case you
* should abort your move operation.
* {@link https://doc.qt.io/qt-6/qabstractitemmodel.html#beginMoveRows PossibleOps}
* @see #endMoveRows()
*/
protected final boolean beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
int sourceLast, QtModelIndex destinationParent,
int destinationChild)
{
return jni_beginMoveRows(sourceParent, sourceFirst, sourceLast, destinationParent,
destinationChild);
}
/**
* Begins a column removal operation.
* When re-implementing removeColumns() in a subclass, you must call this
* function before removing data from the model's underlying data store.
* The parent index corresponds to the parent from which the new columns
* are removed; first and last are the column numbers of the first and
* last columns to be removed.
*
* {@link https://doc.qt.io/qt-6/qabstractitemmodel.html#beginRemoveColumns RemoveColums}
* @see #endRemoveColumns()
*/
protected final void beginRemoveColumns(QtModelIndex parent, int first, int last)
{
jni_beginRemoveColumns(parent, first, last);
}
/**
* Begins a row removal operation.
* When re-implementing removeRows() in a subclass, you must call this
* function before removing data from the model's underlying data store.
* The parent index corresponds to the parent from which the new rows are
* removed; first and last are the row numbers of the rows to be.
{@link https://doc.qt.io/qt-6/qabstractitemmodel.html#beginRemoveRows RemoveRows}
* @see #endRemoveRow()
*/
protected final void beginRemoveRows(QtModelIndex parent, int first, int last)
{
jni_beginRemoveRows(parent, first, last);
}
/**
* Begins a model reset operation.
* A reset operation resets the model to its current state in any attached views.
* Note: any views attached to this model will also be reset.
* When a model is reset, any previous data reported from the
* model is now invalid and has to be queried again. This also means that
* the current and any selected items will become invalid.
* When a model radically changes its data, it can sometimes be easier to just
* call this function rather than emit dataChanged() to inform other
* components when the underlying data source, or its structure, has changed.
* You must call this function before resetting any internal data structures
in your model.
* @see #modelAboutToBeReset()
* @see #modelReset()
* @see #endResetModel()
*/
protected final void beginResetModel() { jni_beginResetModel(); }
/**
* Creates a model index for the given row and column with the internal
* identifier id.
* This function provides a consistent interface, which model sub classes must
* use to create model indexes.
*/
protected final QtModelIndex createIndex(int row, int column, long id)
{
return (QtModelIndex)jni_createIndex(row, column, id);
}
/**
* Ends a column insertion operation.
* When re-implementing insertColumns() in a subclass, you must call this
* function after inserting data into the model's underlying data
* store.
* @see #beginInsertColumns()
*/
protected final void endInsertColumns() { jni_endInsertColumns(); }
/**
* Ends a row insertion operation.
* When re-implementing insertRows() in a subclass, you must call this function
* after inserting data into the model's underlying data store.
* @see #beginInsertRows()
*/
protected final void endInsertRows() { jni_endInsertRows(); }
/**
* Ends a column move operation.
* When implementing a subclass, you must call this
* function after moving data within the model's underlying data
* store.
* @see #beginMoveColumns()
*/
protected final void endMoveColumns() { jni_endMoveColumns(); }
/**
Ends a row move operation.
When implementing a subclass, you must call this
function after moving data within the model's underlying data
store.
@see #beginMoveRows()
*/
protected final void endMoveRows() { jni_endMoveRows(); }
/**
* Ends a column removal operation.
* When reimplementing removeColumns() in a subclass, you must call this
* function after removing data from the model's underlying data store.
* @see #beginRemoveColumns()
*/
protected final void endRemoveColumns() { jni_endRemoveColumns(); }
/**
* Ends a row move operation.
* When implementing a subclass, you must call this
* function after moving data within the model's underlying data
* store.
* @see #beginMoveRows(QtModelIndex sourceParent, int sourceFirst, int sourceLast, QtModelIndexdestinationParent, int destinationChild)
*/
protected final void endRemoveRows() { jni_endRemoveRows(); }
/**
* Completes a model reset operation.
* You must call this function after resetting any internal data structure in your model.
* @see #beginResetModel()
*/
protected final void endResetModel() { jni_endResetModel(); }
private native void jni_beginInsertColumns(QtModelIndex parent, int first, int last);
private native void jni_beginInsertRows(QtModelIndex parent, int first, int last);
private native boolean jni_beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
int sourceLast, QtModelIndex destinationParent,
int destinationChild);
private native boolean jni_beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
int sourceLast, QtModelIndex destinationParent,
int destinationChild);
private native void jni_beginRemoveColumns(QtModelIndex parent, int first, int last);
private native void jni_beginRemoveRows(QtModelIndex parent, int first, int last);
private native void jni_beginResetModel();
private native Object jni_createIndex(int row, int column, long id);
private native void jni_endInsertColumns();
private native void jni_endInsertRows();
private native void jni_endMoveColumns();
private native void jni_endMoveRows();
private native void jni_endRemoveColumns();
private native void jni_endRemoveRows();
private native void jni_endResetModel();
private native Object jni_roleNames();
private native Object jni_sibling(int row, int column, QtModelIndex parent);
private long m_nativeReference = 0;
private QtAbstractItemModel(long nativeReference) { m_nativeReference = nativeReference; }
private void detachFromNative() { m_nativeReference = 0; };
private long nativeReference() { return m_nativeReference; }
private void setNativeReference(long nativeReference) { m_nativeReference = nativeReference; }
private static boolean instanceOf(Object obj) { return (obj instanceof QtAbstractItemModel); }
}

View File

@ -0,0 +1,35 @@
// 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
package org.qtproject.qt.android;
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
class QtAndroidItemModelProxy extends QtAbstractItemModel
{
@Override public int columnCount(QtModelIndex parent) { return jni_columnCount(parent); };
@Override public Object data(QtModelIndex index, int role) { return jni_data(index, role); }
@Override public QtModelIndex index(int row, int column, QtModelIndex parent)
{
return (QtModelIndex)jni_index(row, column, parent);
}
@Override public QtModelIndex parent(QtModelIndex index)
{
return (QtModelIndex)jni_parent(index);
}
@Override public int rowCount(QtModelIndex parent) { return jni_rowCount(parent); }
private native int jni_columnCount(QtModelIndex parent);
private native Object jni_data(QtModelIndex index, int role);
private native Object jni_index(int row, int column, QtModelIndex parent);
private native Object jni_parent(QtModelIndex index);
private native int jni_rowCount(QtModelIndex parent);
}

View File

@ -0,0 +1,30 @@
// 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
package org.qtproject.qt.android;
import java.util.HashMap;
public abstract class QtAbstractListModel extends QtAbstractItemModel
{
public QtAbstractListModel(){};
@Override public final int columnCount(QtModelIndex parent) { return parent.isValid() ? 0 : 1; }
@Override public QtModelIndex index(int row, int column, QtModelIndex parent)
{
return hasIndex(row, column, parent) ? createIndex(row, column, 0) : new QtModelIndex();
}
@Override public final QtModelIndex parent(QtModelIndex index) { return new QtModelIndex(); }
@Override public final boolean hasChildren(QtModelIndex parent)
{
return parent.isValid() ? false : (rowCount(new QtModelIndex()) > 0);
}
@Override public QtModelIndex sibling(int row, int column, QtModelIndex parent)
{
return index(row, column, new QtModelIndex());
}
}

View File

@ -0,0 +1,81 @@
// 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
package org.qtproject.qt.android;
/**
* Represents an index in a custom item model, similar to
* {@link https://doc.qt.io/qt-6/https://doc.qt.io/qt-6/qmodelindex.html QModelindex}
* in c++.
*/
public class QtModelIndex
{
/**
* Constructs a new QtModelIndex.
*/
public QtModelIndex() { }
/**
* Returns the column of this index.
*
* @return The column.
*/
public int column() { return (int)m_privateData[1]; }
/**
* Retrieves data for this index based on the specified role.
*
* @param role The role for which data is requested.
* @return The data object.
*/
public native Object data(int role);
/**
* Returns the internal ID associated with this index.
*
* @return The internal ID.
*/
public native long internalId();
/**
* Checks if this index is valid.
*
* @return True if the index is valid, false otherwise.
*/
public native boolean isValid();
/**
* Returns the parent index of this index.
*
* @return The parent index.
*/
public native QtModelIndex parent();
/**
* Returns the row of this index.
*
* @return The row.
*/
public int row() { return (int)m_privateData[0]; }
private long[] m_privateData = { -1 /*row*/, -1 /*column*/, 0 /*internalId*/,
0 /*modelReference*/ };
private QtModelIndex m_parent = null;
private QtModelIndex(int row, int column, long internalId, long modelReference)
{
m_privateData[0] = row;
m_privateData[1] = column;
m_privateData[2] = internalId;
m_privateData[3] = modelReference;
m_parent = null;
}
private QtModelIndex(int row, int column, QtModelIndex parent, long modelReference)
{
m_privateData[0] = row;
m_privateData[1] = column;
m_privateData[2] = 0;
m_privateData[3] = modelReference;
m_parent = parent;
}
private void detachFromNative()
{
m_privateData[0] = -1;
m_privateData[1] = -1;
m_privateData[2] = 0;
m_privateData[3] = 0;
};
}

View File

@ -1064,6 +1064,8 @@ qt_internal_extend_target(Core CONDITION ANDROID
platform/android/qandroidnativeinterface.cpp platform/android/qandroidnativeinterface.cpp
platform/android/qandroidtypes_p.h platform/android/qandroidtypes_p.h
platform/android/qandroidtypeconverter_p.h platform/android/qandroidtypeconverter_p.h
platform/android/qandroiditemmodelproxy_p.h platform/android/qandroiditemmodelproxy.cpp
platform/android/qandroidmodelindexproxy_p.h platform/android/qandroidmodelindexproxy.cpp
NO_UNITY_BUILD_SOURCES NO_UNITY_BUILD_SOURCES
platform/android/qandroidextras.cpp platform/android/qandroidextras.cpp
# qtNativeClassName conflicts with similar symbols in android headers # qtNativeClassName conflicts with similar symbols in android headers

View File

@ -0,0 +1,379 @@
// 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
#include <QtCore/private/qandroiditemmodelproxy_p.h>
#include <QtCore/private/qandroidmodelindexproxy_p.h>
#include <QtCore/private/qandroidtypeconverter_p.h>
QT_BEGIN_NAMESPACE
using namespace QtJniTypes;
jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const
{
Q_ASSERT(jInstance.isValid());
auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
return jInstance.callMethod<jint>("columnCount", parentIndex);
}
bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const
{
Q_ASSERT(jInstance.isValid());
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());
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());
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());
auto jIndex = QAndroidModelIndexProxy::jInstance(index);
return QAndroidModelIndexProxy::qInstance(
jInstance.callMethod<JQtModelIndex>("parent", jIndex));
}
int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const
{
Q_ASSERT(jInstance.isValid());
auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
return jInstance.callMethod<int>("rowCount", parentIndex);
}
QHash<int, QByteArray> QAndroidItemModelProxy::roleNames() const
{
Q_ASSERT(jInstance.isValid());
QHash<int, QByteArray> roleNames;
HashMap hashMap = jInstance.callMethod<HashMap>("roleNames");
Set set = hashMap.callMethod<Set>("keySet");
QJniArray<jobject> keyArray = set.callMethod<QJniArray<jobject>>("toArray");
for (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());
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());
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());
return QAndroidModelIndexProxy::qInstance(jInstance.callMethod<jobject>(
"sibling", row, column, QAndroidModelIndexProxy::jInstance(parent)));
}
QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QModelIndex &parent)
{
return QAbstractItemModel::sibling(row, column, parent);
}
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) {
nativeProxy = new QAndroidItemModelProxy(itemModel);
itemModel.callMethod<void>("setNativeReference", reinterpret_cast<jlong>(nativeProxy));
connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) {
auto proxy = qobject_cast<QAndroidItemModelProxy *>(obj);
if (proxy)
proxy->jInstance.callMethod<void>("detachFromNative");
});
}
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);
const QJniObject jRoleName = QJniObject::fromString(roleName);
jRoleNames.callMethod<jobject>("put", jRole.object(), jRoleName.object());
}
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, 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());
}
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) });
}
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

View File

@ -0,0 +1,190 @@
// 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
#ifndef QANDROIDITEMMODELPROXY_P_H
#define QANDROIDITEMMODELPROXY_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
#include <QtCore/private/qandroidmodelindexproxy_p.h>
#include <QtCore/private/qandroidtypes_p.h>
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qjniobject.h>
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QAndroidItemModelProxy : public QAbstractItemModel
{
Q_OBJECT
public:
explicit QAndroidItemModelProxy(QtJniTypes::JQtAbstractItemModel jInstance)
: jInstance(jInstance)
{
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool canFetchMore(const QModelIndex &parent) const override;
bool canFetchMoreDefault(const QModelIndex &parent) const;
QHash<int, QByteArray> roleNames() const override;
QHash<int, QByteArray> defaultRoleNames() const;
void fetchMore(const QModelIndex &parent) override;
void fetchMoreDefault(const QModelIndex &parent);
bool hasChildren(const QModelIndex &parent) const override;
bool hasChildrenDefault(const QModelIndex &parent) const;
QModelIndex sibling(int row, int column, const QModelIndex &parent) const override;
QModelIndex siblingDefault(int row, int column, const QModelIndex &parent);
Q_REQUIRED_RESULT static QAbstractItemModel *
nativeInstance(QtJniTypes::JQtAbstractItemModel itemModel);
Q_REQUIRED_RESULT static QAbstractItemModel *createNativeProxy(QJniObject itemModel);
static QJniObject createProxy(QAbstractItemModel *abstractClass);
template <typename Func, typename... Args>
static auto invokeNativeProxyMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
{
Q_ASSERT(jvmObject);
auto model = qobject_cast<QAndroidItemModelProxy *>(nativeInstance(jvmObject));
Q_ASSERT(model);
return std::invoke(func, model, std::forward<Args>(args)...);
}
template <typename Func, typename... Args>
static auto invokeNativeMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
{
Q_ASSERT(jvmObject);
auto model = nativeInstance(jvmObject);
Q_ASSERT(model);
return std::invoke(func, model, std::forward<Args>(args)...);
}
template <typename Func1, typename Func2, typename... Args>
static auto invokeNativeImpl(JNIEnv */*env*/, jobject jvmObject, Func1 defaultFunc, Func2 func,
Args &&...args)
{
Q_ASSERT(jvmObject);
auto nativeModel = nativeInstance(jvmObject);
auto nativeProxyModel = qobject_cast<QAndroidItemModelProxy *>(nativeModel);
if (nativeProxyModel)
return std::invoke(defaultFunc, nativeProxyModel, std::forward<Args>(args)...);
else
return std::invoke(func, nativeModel, std::forward<Args>(args)...);
}
static jint jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_columnCount)
static jobject jni_data(JNIEnv *env, jobject object, JQtModelIndex index, jint role);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_data)
static jobject jni_index(JNIEnv *env, jobject object, jint row, jint column,
JQtModelIndex parent);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_index)
static jobject jni_parent(JNIEnv *env, jobject object, JQtModelIndex index);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_parent)
static jint jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_rowCount)
static jboolean jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_canFetchMore, canFetchMore)
static void jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_fetchMore, fetchMore)
static jboolean jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent);
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasChildren, hasChildren)
static jboolean jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
JQtModelIndex parent);
QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasIndex, hasIndex)
static jobject jni_roleNames(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_roleNames)
static void jni_beginInsertColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
jint first, jint last);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertColumns)
static void jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
jint last);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertRows)
static jboolean jni_beginMoveColumns(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
jint sourceFirst, jint sourceLast,
JQtModelIndex destinationParent, jint destinationChild);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveColumns)
static jboolean jni_beginMoveRows(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
jint sourceFirst, jint sourceLast,
JQtModelIndex destinationParent, jint destinationChild);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveRows)
static void jni_beginRemoveColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
jint first, jint last);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveColumns)
static void jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
jint last);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveRows)
static void jni_beginResetModel(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginResetModel)
static jobject jni_createIndex(JNIEnv *env, jobject object, jint row, jint column, jlong id);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_createIndex)
static void jni_endInsertColumns(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertColumns)
static void jni_endInsertRows(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertRows)
static void jni_endMoveColumns(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveColumns)
static void jni_endMoveRows(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveRows)
static void jni_endRemoveColumns(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveColumns)
static void jni_endRemoveRows(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveRows)
static void jni_endResetModel(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endResetModel)
static jobject jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
JQtModelIndex parent);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_sibling)
static bool registerAbstractNatives(QJniEnvironment &env);
static bool registerProxyNatives(QJniEnvironment &env);
private:
QJniObject jInstance;
friend class QAndroidModelIndexProxy;
};
QT_END_NAMESPACE
#endif // QANDROIDITEMMODELPROXY_P_H

View File

@ -0,0 +1,103 @@
// 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
#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();
Q_ASSERT(privateData.size() == 4);
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

View File

@ -0,0 +1,55 @@
// 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
#ifndef QANDROIDMODELINDEXPROXY_P_H
#define QANDROIDMODELINDEXPROXY_P_H
#include <QtCore/private/qandroidtypes_p.h>
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qjniobject.h>
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjnitypes.h>
#include <QDebug>
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
QT_BEGIN_NAMESPACE
using namespace QtJniTypes;
class QAndroidItemModelProxy;
class Q_CORE_EXPORT QAndroidModelIndexProxy
{
public:
static JQtModelIndex jInstance(QModelIndex modelIndex);
static QModelIndex qInstance(JQtModelIndex jModelIndex);
static jobject data(JNIEnv *env, jobject object, int role);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(data)
static jlong internalId(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(internalId)
static jboolean isValid(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(isValid)
static JQtModelIndex parent(JNIEnv *env, jobject object);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(parent)
static bool registerNatives(QJniEnvironment &env);
};
QT_BEGIN_NAMESPACE
#endif // QANDROIDMODELINDEXPROXY_P_H

View File

@ -14,8 +14,8 @@
// //
// We mean it. // We mean it.
#include <QtQuick/private/qandroidtypes_p.h> #include <QtCore/private/qandroidtypes_p.h>
#include <QtQuick/private/qandroiditemmodelproxy_p.h> #include <QtCore/private/qandroiditemmodelproxy_p.h>
#include <QtCore/qjniobject.h> #include <QtCore/qjniobject.h>
#include <QtCore/qjnienvironment.h> #include <QtCore/qjnienvironment.h>

View File

@ -33,6 +33,8 @@
#include <QtCore/qresource.h> #include <QtCore/qresource.h>
#include <QtCore/qscopeguard.h> #include <QtCore/qscopeguard.h>
#include <QtCore/qthread.h> #include <QtCore/qthread.h>
#include <QtCore/private/qandroiditemmodelproxy_p.h>
#include <QtCore/private/qandroidmodelindexproxy_p.h>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/private/qhighdpiscaling_p.h>
@ -881,7 +883,10 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
|| !QAndroidPlatformClipboard::registerNatives(env) || !QAndroidPlatformClipboard::registerNatives(env)
|| !QAndroidPlatformWindow::registerNatives(env) || !QAndroidPlatformWindow::registerNatives(env)
|| !QtAndroidWindowEmbedding::registerNatives(env) || !QtAndroidWindowEmbedding::registerNatives(env)
|| !AndroidBackendRegister::registerNatives()) { || !AndroidBackendRegister::registerNatives()
|| !QAndroidModelIndexProxy::registerNatives(env)
|| !QAndroidItemModelProxy::registerAbstractNatives(env)
|| !QAndroidItemModelProxy::registerProxyNatives(env)) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1; return -1;
} }