Allow exposing QItemSelectionModel to QML
This requires being able to create a QItemSelectionModel without specifiying its model, and also setting the model later. Also, several classes, like QPersistentModelIndex, need to be declared as meta-type. Finally, and in order to introduce the 'model' property, we need to have a type compatible getter. Hence the new, non-const model() function. Where needed, meta-type declarations have been removed from auto-tests. [ChangeLog][QtCore][Item Models] QItemSelectionModel can now be created without a model and have one set later. Change-Id: If49bed061a5d1012331f335ca7f6e3959ecd3f1c Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com> Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
This commit is contained in:
parent
ae9d3f4c6c
commit
7ab29c4ebb
@ -481,4 +481,7 @@ inline uint qHash(const QModelIndex &index) Q_DECL_NOTHROW
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QModelIndexList)
|
||||
Q_DECLARE_METATYPE(QPersistentModelIndex)
|
||||
|
||||
#endif // QABSTRACTITEMMODEL_H
|
||||
|
@ -589,33 +589,51 @@ void QItemSelection::split(const QItemSelectionRange &range,
|
||||
}
|
||||
|
||||
|
||||
void QItemSelectionModelPrivate::initModel(QAbstractItemModel *model)
|
||||
void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
|
||||
{
|
||||
this->model = model;
|
||||
struct Cx {
|
||||
const char *signal;
|
||||
const char *slot;
|
||||
};
|
||||
static const Cx connections[] = {
|
||||
{ SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)) },
|
||||
{ SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)) },
|
||||
{ SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
|
||||
SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)) },
|
||||
{ SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
|
||||
SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)) },
|
||||
{ SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
SLOT(_q_layoutAboutToBeChanged()) },
|
||||
{ SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
SLOT(_q_layoutAboutToBeChanged()) },
|
||||
{ SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
SLOT(_q_layoutChanged()) },
|
||||
{ SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
SLOT(_q_layoutChanged()) },
|
||||
{ SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
|
||||
SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
|
||||
{ SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
|
||||
SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
|
||||
{ SIGNAL(modelReset()),
|
||||
SLOT(reset()) },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
if (model == m)
|
||||
return;
|
||||
|
||||
Q_Q(QItemSelectionModel);
|
||||
if (model) {
|
||||
Q_Q(QItemSelectionModel);
|
||||
QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
|
||||
q, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
|
||||
QObject::connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
|
||||
q, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
QObject::connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
|
||||
q, SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)));
|
||||
QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
q, SLOT(_q_layoutAboutToBeChanged()));
|
||||
QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
q, SLOT(_q_layoutAboutToBeChanged()));
|
||||
QObject::connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
q, SLOT(_q_layoutChanged()));
|
||||
QObject::connect(model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
|
||||
q, SLOT(_q_layoutChanged()));
|
||||
QObject::connect(model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
|
||||
q, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
|
||||
QObject::connect(model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
|
||||
q, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
|
||||
QObject::connect(model, SIGNAL(modelReset()),
|
||||
q, SLOT(reset()));
|
||||
for (const Cx *cx = &connections[0]; cx->signal; cx++)
|
||||
QObject::disconnect(model, cx->signal, q, cx->slot);
|
||||
q->reset();
|
||||
}
|
||||
model = m;
|
||||
if (model) {
|
||||
for (const Cx *cx = &connections[0]; cx->signal; cx++)
|
||||
QObject::connect(model, cx->signal, q, cx->slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1078,6 +1096,10 @@ void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIn
|
||||
selection. All functions operate on both layers; for example,
|
||||
\l {QTableWidget::selectedItems()}{selecteditems()} will return items from both layers.
|
||||
|
||||
\note Since 5.5, \l{QItemSelectionModel::model()}{model},
|
||||
\l{QItemSelectionModel::hasSelection()}{hasSelection}, and
|
||||
\l{QItemSelectionModel::currentIndex()}{currentIndex} are meta-object properties.
|
||||
|
||||
\sa {Model/View Programming}, QAbstractItemModel, {Chart Example}
|
||||
*/
|
||||
|
||||
@ -1174,6 +1196,16 @@ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::
|
||||
\sa select(), currentChanged()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QItemSelectionModel::modelChanged(QAbstractItemModel *model)
|
||||
\since 5.5
|
||||
|
||||
This signal is emitted when the model is successfully set with setModel().
|
||||
|
||||
\sa model(), setModel()
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\enum QItemSelectionModel::SelectionFlag
|
||||
|
||||
@ -1205,6 +1237,10 @@ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::
|
||||
void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
Q_D(QItemSelectionModel);
|
||||
if (!d->model) {
|
||||
qWarning("QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
|
||||
return;
|
||||
}
|
||||
if (command == NoUpdate)
|
||||
return;
|
||||
|
||||
@ -1312,6 +1348,10 @@ void QItemSelectionModel::clearSelection()
|
||||
void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
|
||||
{
|
||||
Q_D(QItemSelectionModel);
|
||||
if (!d->model) {
|
||||
qWarning("QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
|
||||
return;
|
||||
}
|
||||
if (index == d->currentIndex) {
|
||||
if (command != NoUpdate)
|
||||
select(index, command); // select item
|
||||
@ -1387,6 +1427,8 @@ bool QItemSelectionModel::isSelected(const QModelIndex &index) const
|
||||
bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) const
|
||||
{
|
||||
Q_D(const QItemSelectionModel);
|
||||
if (!d->model)
|
||||
return false;
|
||||
if (parent.isValid() && d->model != parent.model())
|
||||
return false;
|
||||
|
||||
@ -1447,6 +1489,8 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons
|
||||
bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_D(const QItemSelectionModel);
|
||||
if (!d->model)
|
||||
return false;
|
||||
if (parent.isValid() && d->model != parent.model())
|
||||
return false;
|
||||
|
||||
@ -1503,6 +1547,8 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent
|
||||
bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &parent) const
|
||||
{
|
||||
Q_D(const QItemSelectionModel);
|
||||
if (!d->model)
|
||||
return false;
|
||||
if (parent.isValid() && d->model != parent.model())
|
||||
return false;
|
||||
|
||||
@ -1535,6 +1581,8 @@ bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &par
|
||||
bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_D(const QItemSelectionModel);
|
||||
if (!d->model)
|
||||
return false;
|
||||
if (parent.isValid() && d->model != parent.model())
|
||||
return false;
|
||||
|
||||
@ -1671,6 +1719,35 @@ const QItemSelection QItemSelectionModel::selection() const
|
||||
return selected;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
\property QItemSelectionModel::hasSelection
|
||||
\internal
|
||||
*/
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
\property QItemSelectionModel::currentIndex
|
||||
\internal
|
||||
*/
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
\property QItemSelectionModel::model
|
||||
\internal
|
||||
*/
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
Returns the item model operated on by the selection model.
|
||||
*/
|
||||
QAbstractItemModel *QItemSelectionModel::model()
|
||||
{
|
||||
return d_func()->model;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the item model operated on by the selection model.
|
||||
*/
|
||||
@ -1679,6 +1756,23 @@ const QAbstractItemModel *QItemSelectionModel::model() const
|
||||
return d_func()->model;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
Sets the model. The modelChanged() signal will be emitted.
|
||||
|
||||
\sa model(), modelChanged()
|
||||
*/
|
||||
void QItemSelectionModel::setModel(QAbstractItemModel *model)
|
||||
{
|
||||
Q_D(QItemSelectionModel);
|
||||
if (d->model == model)
|
||||
return;
|
||||
|
||||
d->initModel(model);
|
||||
emit modelChanged(model);
|
||||
}
|
||||
|
||||
/*!
|
||||
Compares the two selections \a newSelection and \a oldSelection
|
||||
and emits selectionChanged() with the deselected and selected items.
|
||||
|
@ -143,6 +143,10 @@ class QItemSelectionModelPrivate;
|
||||
class Q_CORE_EXPORT QItemSelectionModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
|
||||
Q_PROPERTY(bool hasSelection READ hasSelection NOTIFY selectionChanged STORED false DESIGNABLE false)
|
||||
Q_PROPERTY(QModelIndex currentIndex READ currentIndex NOTIFY currentChanged STORED false DESIGNABLE false)
|
||||
|
||||
Q_DECLARE_PRIVATE(QItemSelectionModel)
|
||||
Q_FLAGS(SelectionFlags)
|
||||
|
||||
@ -164,27 +168,31 @@ public:
|
||||
|
||||
Q_DECLARE_FLAGS(SelectionFlags, SelectionFlag)
|
||||
|
||||
explicit QItemSelectionModel(QAbstractItemModel *model);
|
||||
explicit QItemSelectionModel(QAbstractItemModel *model = 0);
|
||||
explicit QItemSelectionModel(QAbstractItemModel *model, QObject *parent);
|
||||
virtual ~QItemSelectionModel();
|
||||
|
||||
QModelIndex currentIndex() const;
|
||||
|
||||
bool isSelected(const QModelIndex &index) const;
|
||||
bool isRowSelected(int row, const QModelIndex &parent) const;
|
||||
bool isColumnSelected(int column, const QModelIndex &parent) const;
|
||||
Q_INVOKABLE bool isSelected(const QModelIndex &index) const;
|
||||
Q_INVOKABLE bool isRowSelected(int row, const QModelIndex &parent) const;
|
||||
Q_INVOKABLE bool isColumnSelected(int column, const QModelIndex &parent) const;
|
||||
|
||||
bool rowIntersectsSelection(int row, const QModelIndex &parent) const;
|
||||
bool columnIntersectsSelection(int column, const QModelIndex &parent) const;
|
||||
Q_INVOKABLE bool rowIntersectsSelection(int row, const QModelIndex &parent) const;
|
||||
Q_INVOKABLE bool columnIntersectsSelection(int column, const QModelIndex &parent) const;
|
||||
|
||||
bool hasSelection() const;
|
||||
|
||||
QModelIndexList selectedIndexes() const;
|
||||
QModelIndexList selectedRows(int column = 0) const;
|
||||
QModelIndexList selectedColumns(int row = 0) const;
|
||||
const QItemSelection selection() const;
|
||||
Q_INVOKABLE QModelIndexList selectedIndexes() const;
|
||||
Q_INVOKABLE QModelIndexList selectedRows(int column = 0) const;
|
||||
Q_INVOKABLE QModelIndexList selectedColumns(int row = 0) const;
|
||||
Q_INVOKABLE const QItemSelection selection() const;
|
||||
|
||||
// ### Qt 6: Merge these two as "QAbstractItemModel *model() const"
|
||||
const QAbstractItemModel *model() const;
|
||||
QAbstractItemModel *model();
|
||||
|
||||
void setModel(QAbstractItemModel *model);
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command);
|
||||
@ -201,6 +209,7 @@ Q_SIGNALS:
|
||||
void currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void currentColumnChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void modelChanged(QAbstractItemModel *model);
|
||||
|
||||
protected:
|
||||
QItemSelectionModel(QItemSelectionModelPrivate &dd, QAbstractItemModel *model);
|
||||
@ -243,4 +252,7 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QItemSelectionRange &);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QItemSelectionRange)
|
||||
Q_DECLARE_METATYPE(QItemSelection)
|
||||
|
||||
#endif // QITEMSELECTIONMODEL_H
|
||||
|
@ -211,7 +211,6 @@ void tst_QAbstractProxyModel::mapFromSource()
|
||||
QCOMPARE(model.mapFromSource(sourceIndex), mapFromSource);
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QItemSelection)
|
||||
void tst_QAbstractProxyModel::mapSelectionFromSource_data()
|
||||
{
|
||||
QTest::addColumn<QItemSelection>("selection");
|
||||
|
@ -86,6 +86,7 @@ private slots:
|
||||
void deselectRemovedMiddleRange();
|
||||
void rangeOperatorLessThan_data();
|
||||
void rangeOperatorLessThan();
|
||||
void setModel();
|
||||
|
||||
void testDifferentModels();
|
||||
|
||||
@ -107,8 +108,6 @@ typedef QList<int> IntList;
|
||||
typedef QPair<int, int> IntPair;
|
||||
typedef QList<IntPair> PairList;
|
||||
|
||||
Q_DECLARE_METATYPE(QItemSelection)
|
||||
|
||||
class QStreamHelper: public QAbstractItemModel
|
||||
{
|
||||
public:
|
||||
@ -2561,6 +2560,21 @@ void tst_QItemSelectionModel::rangeOperatorLessThan()
|
||||
QVERIFY(r4 < r2);
|
||||
}
|
||||
|
||||
void tst_QItemSelectionModel::setModel()
|
||||
{
|
||||
QItemSelectionModel sel;
|
||||
QVERIFY(!sel.model());
|
||||
QSignalSpy modelChangedSpy(&sel, SIGNAL(modelChanged(QAbstractItemModel*)));
|
||||
QStringListModel model(QStringList() << "Blah" << "Blah" << "Blah");
|
||||
sel.setModel(&model);
|
||||
QCOMPARE(sel.model(), &model);
|
||||
QCOMPARE(modelChangedSpy.count(), 1);
|
||||
sel.select(model.index(0), QItemSelectionModel::Select);
|
||||
QVERIFY(!sel.selection().isEmpty());
|
||||
sel.setModel(0);
|
||||
QVERIFY(sel.selection().isEmpty());
|
||||
}
|
||||
|
||||
void tst_QItemSelectionModel::testDifferentModels()
|
||||
{
|
||||
QStandardItemModel model1;
|
||||
|
@ -1827,7 +1827,6 @@ void tst_QAbstractItemView::testFocusPolicy()
|
||||
QVERIFY(!qApp->focusWidget());
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QItemSelection)
|
||||
void tst_QAbstractItemView::QTBUG31411_noSelection()
|
||||
{
|
||||
QWidget window;
|
||||
|
Loading…
Reference in New Issue
Block a user