From 7091ec8cd1ec94fb889230d69fc70d40a9f69b2d Mon Sep 17 00:00:00 2001 From: Leonardo Sobral Cunha Date: Thu, 27 Aug 2009 18:19:22 +0200 Subject: QAbstractAnimation: replacing QPointer usage for QWeakPointer Added guard checks after the virtual method calls. Reviewed-by: thierry --- src/corelib/animation/qabstractanimation.cpp | 31 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index dfd6779..49bd8e9 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -259,28 +259,33 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) } state = newState; - QPointer guard(q); + QWeakPointer guard(q); - guard->updateState(oldState, newState); + q->updateState(oldState, newState); + if (!guard) + return; //this is to be safe if updateState changes the state if (state == oldState) return; // Notify state change - if (guard) - emit guard->stateChanged(oldState, newState); + emit q->stateChanged(oldState, newState); + if (!guard) + return; - switch (state) - { + switch (state) { case QAbstractAnimation::Paused: case QAbstractAnimation::Running: //this ensures that the value is updated now that the animation is running - if(oldState == QAbstractAnimation::Stopped && guard) - guard->setCurrentTime(currentTime); + if(oldState == QAbstractAnimation::Stopped) { + q->setCurrentTime(currentTime); + if (!guard) + return; + } // Register timer if our parent is not running. - if (state == QAbstractAnimation::Running && guard) { + if (state == QAbstractAnimation::Running) { if (!group || group->state() == QAbstractAnimation::Stopped) { QUnifiedTimer::instance()->registerAnimation(q); } @@ -292,7 +297,10 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) case QAbstractAnimation::Stopped: // Leave running state. int dura = q->duration(); - if (deleteWhenStopped && guard) + if (!guard) + return; + + if (deleteWhenStopped) q->deleteLater(); QUnifiedTimer::instance()->unregisterAnimation(q); @@ -300,8 +308,7 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) if (dura == -1 || loopCount < 0 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount)) || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) { - if (guard) - emit q->finished(); + emit q->finished(); } break; } -- cgit v0.12 From 4d197ec0eaeae61499d8ee6dc0e98147800f583e Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Fri, 31 Jul 2009 12:00:40 +0100 Subject: Fix the API for resetting QAbstractItemModels. This commit deprecates the QAIM::reset() method, and adds beginResetModel() and endResetModel() methods, addressing Qt issue 247023. http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=247023 If models and proxies use QAIM::reset() alone, then proxies will emit modelAboutToBeReset after its source model is reset. This means that mapToSource will not behave as expected (Will always return an invalid index) in a slot connected to modelAboutToBeReset. The usecase for this is maintaining viewstate (which items are selected, expanded) when the model is reset. See BrowserWidget::modelChanged here: http://websvn.kde.org/trunk/KDE/kdepim/akonadi/akonadiconsole/browserwidget.cpp?view=markup Task-number: 247023 Reviewed-by: Olivier Goffart Merge-request: 1072 --- src/corelib/kernel/qabstractitemmodel.cpp | 49 +++++++-- src/corelib/kernel/qabstractitemmodel.h | 3 + src/gui/itemviews/qsortfilterproxymodel.cpp | 11 +- src/gui/itemviews/qsortfilterproxymodel.h | 1 + tests/auto/qabstractitemmodel/dynamictreemodel.cpp | 118 ++++++++++++++++----- tests/auto/qabstractitemmodel/dynamictreemodel.h | 39 +++++++ .../qabstractitemmodel/tst_qabstractitemmodel.cpp | 106 +++++++++++++++++- 7 files changed, 290 insertions(+), 37 deletions(-) diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index 1c9104a..2175542 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -1339,7 +1339,7 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, \endlist - \sa layoutAboutToBeChanged(), dataChanged(), headerDataChanged(), reset(), + \sa layoutAboutToBeChanged(), dataChanged(), headerDataChanged(), modelReset(), changePersistentIndex() */ @@ -2769,7 +2769,25 @@ void QAbstractItemModel::endMoveColumns() /*! Resets the model to its original state in any attached views. - The view to which the model is attached to will be reset as well. + Use beginResetModel() and endResetModel() instead whenever possible. If usng this method, the modelAboutToBeReset signal will + not function as expected through proxy models. + + Use this method only if there is no way to call beginResetModel() before invalidating the model. +*/ +void QAbstractItemModel::reset() +{ + Q_D(QAbstractItemModel); + emit modelAboutToBeReset(); + d->invalidatePersistentIndexes(); + emit modelReset(); +} + +/*! + 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 be reset as well. When a model is reset it means that any previous data reported from the model is now invalid and has to be queried for again. This also means that @@ -2779,12 +2797,29 @@ void QAbstractItemModel::endMoveColumns() call this function rather than emit dataChanged() to inform other components when the underlying data source, or its structure, has changed. - \sa modelAboutToBeReset(), modelReset() + You must call this function before resetting any internal data structures in your model + or proxy model. + + \sa modelAboutToBeReset(), modelReset(), endResetModel() + \since 4.6 */ -void QAbstractItemModel::reset() +void QAbstractItemModel::beginResetModel() { - Q_D(QAbstractItemModel); emit modelAboutToBeReset(); +} + +/*! + Completes a model reset operation. + + You must call this function after resetting any internal data structure in your model + or proxy model. + + \sa beginResetModel() + \since 4.6 +*/ +void QAbstractItemModel::endResetModel() +{ + Q_D(QAbstractItemModel); d->invalidatePersistentIndexes(); emit modelReset(); } @@ -3256,7 +3291,7 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti This signal is emitted when reset() is called, before the model's internal state (e.g. persistent model indexes) has been invalidated. - \sa reset(), modelReset() + \sa beginResetModel(), modelReset() */ /*! @@ -3266,7 +3301,7 @@ bool QAbstractListModel::dropMimeData(const QMimeData *data, Qt::DropAction acti This signal is emitted when reset() is called, after the model's internal state (e.g. persistent model indexes) has been invalidated. - \sa reset(), modelAboutToBeReset() + \sa endResetModel(), modelAboutToBeReset() */ /*! diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h index b47e4cb..1ca6cbe 100644 --- a/src/corelib/kernel/qabstractitemmodel.h +++ b/src/corelib/kernel/qabstractitemmodel.h @@ -293,6 +293,9 @@ protected: void reset(); + void beginResetModel(); + void endResetModel(); + void changePersistentIndex(const QModelIndex &from, const QModelIndex &to); void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to); QModelIndexList persistentIndexList() const; diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index d173efe..18fbf7b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -174,6 +174,7 @@ public: const QModelIndex &source_bottom_right); void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end); + void _q_sourceAboutToBeReset(); void _q_sourceReset(); void _q_sourceLayoutAboutToBeChanged(); @@ -1148,11 +1149,17 @@ void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation or emit q->headerDataChanged(orientation, proxy_start, proxy_end); } +void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset() +{ + Q_Q(QSortFilterProxyModel); + q->beginResetModel(); +} + void QSortFilterProxyModelPrivate::_q_sourceReset() { Q_Q(QSortFilterProxyModel); // All internal structures are deleted in clear() - q->reset(); + q->endResetModel(); update_source_sort_column(); if (dynamic_sortfilter) sort(); @@ -1499,6 +1506,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_sourceLayoutChanged())); + disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); QAbstractProxyModel::setSourceModel(sourceModel); @@ -1539,6 +1547,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_sourceLayoutChanged())); + connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); d->clear_mapping(); diff --git a/src/gui/itemviews/qsortfilterproxymodel.h b/src/gui/itemviews/qsortfilterproxymodel.h index 12baa19..0314aec 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.h +++ b/src/gui/itemviews/qsortfilterproxymodel.h @@ -177,6 +177,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right)) Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceAboutToBeReset()) Q_PRIVATE_SLOT(d_func(), void _q_sourceReset()) Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged()) Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged()) diff --git a/tests/auto/qabstractitemmodel/dynamictreemodel.cpp b/tests/auto/qabstractitemmodel/dynamictreemodel.cpp index 6c3e0cb..374b7db 100644 --- a/tests/auto/qabstractitemmodel/dynamictreemodel.cpp +++ b/tests/auto/qabstractitemmodel/dynamictreemodel.cpp @@ -204,42 +204,106 @@ ModelMoveCommand::ModelMoveCommand(DynamicTreeModel *model, QObject *parent) { } +bool ModelMoveCommand::emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) +{ + return m_model->beginMoveRows(srcParent, srcStart, srcEnd, destParent, destRow); +} void ModelMoveCommand::doCommand() { - QModelIndex srcParent = findIndex(m_rowNumbers); - QModelIndex destParent = findIndex(m_destRowNumbers); - - if (!m_model->beginMoveRows(srcParent, m_startRow, m_endRow, destParent, m_destRow)) - { - return; - } - - for (int column = 0; column < m_numCols; ++column) - { - QList l = m_model->m_childItems.value(srcParent.internalId())[column].mid(m_startRow, m_endRow - m_startRow + 1 ); + QModelIndex srcParent = findIndex(m_rowNumbers); + QModelIndex destParent = findIndex(m_destRowNumbers); - for (int i = m_startRow; i <= m_endRow ; i++) + if (!emitPreSignal(srcParent, m_startRow, m_endRow, destParent, m_destRow)) { - m_model->m_childItems[srcParent.internalId()][column].removeAt(m_startRow); - } - int d; - if (m_destRow < m_startRow) - d = m_destRow; - else - { - if (srcParent == destParent) - d = m_destRow - (m_endRow - m_startRow + 1); - else - d = m_destRow - (m_endRow - m_startRow) + 1; + return; } - foreach(const qint64 id, l) + for (int column = 0; column < m_numCols; ++column) { - m_model->m_childItems[destParent.internalId()][column].insert(d++, id); + QList l = m_model->m_childItems.value(srcParent.internalId())[column].mid(m_startRow, m_endRow - m_startRow + 1 ); + + for (int i = m_startRow; i <= m_endRow ; i++) + { + m_model->m_childItems[srcParent.internalId()][column].removeAt(m_startRow); + } + int d; + if (m_destRow < m_startRow) + d = m_destRow; + else + { + if (srcParent == destParent) + d = m_destRow - (m_endRow - m_startRow + 1); + else + d = m_destRow - (m_endRow - m_startRow) + 1; + } + + foreach(const qint64 id, l) + { + m_model->m_childItems[destParent.internalId()][column].insert(d++, id); + } } - } - m_model->endMoveRows(); + emitPostSignal(); +} + +void ModelMoveCommand::emitPostSignal() +{ + m_model->endMoveRows(); +} + +ModelResetCommand::ModelResetCommand(DynamicTreeModel* model, QObject* parent) + : ModelMoveCommand(model, parent) +{ + +} + +ModelResetCommand::~ModelResetCommand() +{ + +} + +bool ModelResetCommand::emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) +{ + Q_UNUSED(srcParent); + Q_UNUSED(srcStart); + Q_UNUSED(srcEnd); + Q_UNUSED(destParent); + Q_UNUSED(destRow); + + return true; +} + +void ModelResetCommand::emitPostSignal() +{ + m_model->reset(); +} + +ModelResetCommandFixed::ModelResetCommandFixed(DynamicTreeModel* model, QObject* parent) + : ModelMoveCommand(model, parent) +{ + +} + +ModelResetCommandFixed::~ModelResetCommandFixed() +{ + +} + +bool ModelResetCommandFixed::emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow) +{ + Q_UNUSED(srcParent); + Q_UNUSED(srcStart); + Q_UNUSED(srcEnd); + Q_UNUSED(destParent); + Q_UNUSED(destRow); + + m_model->beginResetModel(); + return true; +} + +void ModelResetCommandFixed::emitPostSignal() +{ + m_model->endResetModel(); } diff --git a/tests/auto/qabstractitemmodel/dynamictreemodel.h b/tests/auto/qabstractitemmodel/dynamictreemodel.h index 88e293c..c19ed9d 100644 --- a/tests/auto/qabstractitemmodel/dynamictreemodel.h +++ b/tests/auto/qabstractitemmodel/dynamictreemodel.h @@ -70,6 +70,8 @@ private: friend class ModelInsertCommand; friend class ModelMoveCommand; + friend class ModelResetCommand; + friend class ModelResetCommandFixed; }; @@ -118,6 +120,7 @@ public: virtual void doCommand(); }; + class ModelMoveCommand : public ModelChangeCommand { Q_OBJECT @@ -126,8 +129,12 @@ public: virtual ~ModelMoveCommand() {} + virtual bool emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow); + virtual void doCommand(); + virtual void emitPostSignal(); + void setDestAncestors( QList rows ) { m_destRowNumbers = rows; } void setDestRow(int row) { m_destRow = row; } @@ -137,5 +144,37 @@ protected: int m_destRow; }; +/** + A command which does a move and emits a reset signal. +*/ +class ModelResetCommand : public ModelMoveCommand +{ + Q_OBJECT +public: + ModelResetCommand(DynamicTreeModel* model, QObject* parent = 0); + + virtual ~ModelResetCommand(); + + virtual bool emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow); + virtual void emitPostSignal(); + +}; + +/** + A command which does a move and emits a beginResetModel and endResetModel signals. +*/ +class ModelResetCommandFixed : public ModelMoveCommand +{ + Q_OBJECT +public: + ModelResetCommandFixed(DynamicTreeModel* model, QObject* parent = 0); + + virtual ~ModelResetCommandFixed(); + + virtual bool emitPreSignal(const QModelIndex &srcParent, int srcStart, int srcEnd, const QModelIndex &destParent, int destRow); + virtual void emitPostSignal(); + +}; + #endif diff --git a/tests/auto/qabstractitemmodel/tst_qabstractitemmodel.cpp b/tests/auto/qabstractitemmodel/tst_qabstractitemmodel.cpp index 9c83474..61eeae7 100644 --- a/tests/auto/qabstractitemmodel/tst_qabstractitemmodel.cpp +++ b/tests/auto/qabstractitemmodel/tst_qabstractitemmodel.cpp @@ -43,6 +43,8 @@ #include #include +#include + //TESTED_CLASS=QAbstractListModel QAbstractTableModel //TESTED_FILES= @@ -110,6 +112,8 @@ private slots: void testMoveWithinOwnRange_data(); void testMoveWithinOwnRange(); + void testReset(); + private: DynamicTreeModel *m_model; @@ -814,7 +818,7 @@ void tst_QAbstractItemModel::complexChangesWithPersistent() //remove a bunch of columns model.removeColumns(2, 4); - + QVERIFY(a == model.index(1, 1, QModelIndex())); QVERIFY(b == model.index(9, 3, QModelIndex())); QVERIFY(c == model.index(5, 2, QModelIndex())); @@ -825,7 +829,7 @@ void tst_QAbstractItemModel::complexChangesWithPersistent() QVERIFY(!e[i].isValid()); for (int i=6; i <10 ; i++) QVERIFY(e[i] == model.index(2, i-4 , QModelIndex())); - + //move some indexes around model.setPersistent(model.index(1, 1 , QModelIndex()), model.index(9, 3 , QModelIndex())); model.setPersistent(model.index(9, 3 , QModelIndex()), model.index(8, 4 , QModelIndex())); @@ -1652,6 +1656,104 @@ void tst_QAbstractItemModel::testMoveWithinOwnRange() } +class ListenerObject : public QObject +{ + Q_OBJECT +public: + ListenerObject(QAbstractProxyModel *parent); + +protected: + void fillIndexStores(const QModelIndex &parent); + +public slots: + void slotAboutToBeReset(); + void slotReset(); + +private: + QAbstractProxyModel *m_model; + QList m_persistentIndexes; + QModelIndexList m_nonPersistentIndexes; +}; + + +ListenerObject::ListenerObject(QAbstractProxyModel *parent) + : QObject(parent), m_model(parent) +{ + connect(m_model, SIGNAL(modelAboutToBeReset()), SLOT(slotAboutToBeReset())); + connect(m_model, SIGNAL(modelReset()), SLOT(slotReset())); + + fillIndexStores(QModelIndex()); +} + +void ListenerObject::fillIndexStores(const QModelIndex &parent) +{ + const int column = 0; + int row = 0; + QModelIndex idx = m_model->index(row, column, parent); + while (idx.isValid()) + { + m_persistentIndexes << QPersistentModelIndex(idx); + m_nonPersistentIndexes << idx; + if (m_model->hasChildren(idx)) + { + fillIndexStores(idx); + } + ++row; + idx = m_model->index(row, column, parent); + } +} + +void ListenerObject::slotAboutToBeReset() +{ + // Nothing has been changed yet. All indexes should be the same. + for (int i = 0; i < m_persistentIndexes.size(); ++i) + { + QModelIndex idx = m_persistentIndexes.at(i); + QVERIFY(idx == m_nonPersistentIndexes.at(i)); + QVERIFY(m_model->mapToSource(idx).isValid()); + } +} + +void ListenerObject::slotReset() +{ + foreach(const QModelIndex &idx, m_persistentIndexes) + { + QVERIFY(!idx.isValid()); + } +} + + +void tst_QAbstractItemModel::testReset() +{ + QSignalSpy beforeResetSpy(m_model, SIGNAL(modelAboutToBeReset())); + QSignalSpy afterResetSpy(m_model, SIGNAL(modelReset())); + + + QSortFilterProxyModel *nullProxy = new QSortFilterProxyModel(this); + nullProxy->setSourceModel(m_model); + + // Makes sure the model and proxy are in a consistent state. before and after reset. + new ListenerObject(nullProxy); + + ModelResetCommandFixed *resetCommand = new ModelResetCommandFixed(m_model, this); + + resetCommand->setNumCols(4); + resetCommand->setStartRow(0); + resetCommand->setEndRow(0); + resetCommand->setDestRow(0); + resetCommand->setDestAncestors(QList() << 5); + resetCommand->doCommand(); + + // Verify that the correct signals were emitted + QVERIFY(beforeResetSpy.size() == 1); + QVERIFY(afterResetSpy.size() == 1); + + // Verify that the move actually happened. + QVERIFY(m_model->rowCount() == 9); + QModelIndex destIndex = m_model->index(4, 0); + QVERIFY(m_model->rowCount(destIndex) == 11); + +} QTEST_MAIN(tst_QAbstractItemModel) -- cgit v0.12 From 399d7f19ea356a29933b5a08d66b791061586c87 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 28 Aug 2009 09:56:07 +0200 Subject: Documentation of QAbstractProxyModel::reset Rectification after the last merge request integration Reviewed-by: Thierry --- src/corelib/kernel/qabstractitemmodel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index 2175542..5e8848b 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -2769,10 +2769,9 @@ void QAbstractItemModel::endMoveColumns() /*! Resets the model to its original state in any attached views. - Use beginResetModel() and endResetModel() instead whenever possible. If usng this method, the modelAboutToBeReset signal will - not function as expected through proxy models. - + \note Use beginResetModel() and endResetModel() instead whenever possible. Use this method only if there is no way to call beginResetModel() before invalidating the model. + Otherwise it could lead to unexcpected behaviour, especially when used with proxy models. */ void QAbstractItemModel::reset() { -- cgit v0.12 From e88a947cd8ac7bd78922a5468cd8b631b8ccf479 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 27 Aug 2009 18:53:15 +0200 Subject: Q_ASSERT failure in QStateMachinePrivate::handleTransitionSignal. The signal index actually emitted was different from the signal index registered. This was due to recent changes in the meta-object protocol, where new indexes are being created (cloned) for signals with default parameters. When registering the transition signal, we now look for the original (non cloned) signal index. The transition keeps track of the user-specified signal index, and sets it when calling onTransition. Reviewed-by: Kent Hansen Reviewed-by: Olivier Goffart Task-number: 260403 --- src/corelib/statemachine/qabstracttransition_p.h | 2 +- src/corelib/statemachine/qsignalevent.h | 2 ++ src/corelib/statemachine/qsignaltransition.cpp | 17 ++++++++++ src/corelib/statemachine/qsignaltransition_p.h | 3 ++ src/corelib/statemachine/qstatemachine.cpp | 7 ++++ tests/auto/qstatemachine/tst_qstatemachine.cpp | 42 ++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h index 328be16..33e4474 100644 --- a/src/corelib/statemachine/qabstracttransition_p.h +++ b/src/corelib/statemachine/qabstracttransition_p.h @@ -75,7 +75,7 @@ public: static QAbstractTransitionPrivate *get(QAbstractTransition *q); bool callEventTest(QEvent *e); - void callOnTransition(QEvent *e); + virtual void callOnTransition(QEvent *e); QState *sourceState() const; QStateMachine *machine() const; void emitTriggered(); diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h index 7e5d888..de166f4 100644 --- a/src/corelib/statemachine/qsignalevent.h +++ b/src/corelib/statemachine/qsignalevent.h @@ -70,6 +70,8 @@ private: QObject *m_sender; int m_signalIndex; QList m_arguments; + + friend class QSignalTransitionPrivate; }; #endif //QT_NO_STATEMACHINE diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index e34448f..fb28c08 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -245,6 +245,23 @@ bool QSignalTransition::event(QEvent *e) return QAbstractTransition::event(e); } +void QSignalTransitionPrivate::callOnTransition(QEvent *e) +{ + Q_Q(QSignalTransition); + + QSignalEvent *se = static_cast(e); + int savedSignalIndex; + if (e->type() == QEvent::Signal) { + savedSignalIndex = se->m_signalIndex; + se->m_signalIndex = originalSignalIndex; + } + + q->onTransition(e); + + if (e->type() == QEvent::Signal) + se->m_signalIndex = savedSignalIndex; +} + QT_END_NAMESPACE #endif //QT_NO_STATEMACHINE diff --git a/src/corelib/statemachine/qsignaltransition_p.h b/src/corelib/statemachine/qsignaltransition_p.h index 21082ab..69bbcc9 100644 --- a/src/corelib/statemachine/qsignaltransition_p.h +++ b/src/corelib/statemachine/qsignaltransition_p.h @@ -69,9 +69,12 @@ public: void unregister(); void maybeRegister(); + virtual void callOnTransition(QEvent *e); + QObject *sender; QByteArray signal; int signalIndex; + int originalSignalIndex; }; QT_END_NAMESPACE diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index d6946de..e5bca2c 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1408,6 +1408,7 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio signal.remove(0, 1); const QMetaObject *meta = sender->metaObject(); int signalIndex = meta->indexOfSignal(signal); + int originalSignalIndex = signalIndex; if (signalIndex == -1) { signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal)); if (signalIndex == -1) { @@ -1416,6 +1417,11 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio return; } } + // The signal index we actually want to connect to is the one + // that is going to be sent, i.e. the non-cloned original index. + while (meta->method(signalIndex).attributes() & QMetaMethod::Cloned) + --signalIndex; + QVector &connectedSignalIndexes = connections[sender]; if (connectedSignalIndexes.size() <= signalIndex) connectedSignalIndexes.resize(signalIndex+1); @@ -1435,6 +1441,7 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio } ++connectedSignalIndexes[signalIndex]; QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex; + QSignalTransitionPrivate::get(transition)->originalSignalIndex = originalSignalIndex; #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": added signal transition from" << transition->sourceState() << ": ( sender =" << sender << ", signal =" << signal diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 20e69ce..643daa2 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -93,10 +93,13 @@ Q_OBJECT { emit signalWithIntArg(arg); } void emitSignalWithStringArg(const QString &arg) { emit signalWithStringArg(arg); } + void emitSignalWithDefaultArg() + { emit signalWithDefaultArg(); } Q_SIGNALS: void signalWithNoArg(); void signalWithIntArg(int); void signalWithStringArg(const QString &); + void signalWithDefaultArg(int i = 42); }; class tst_QStateMachine : public QObject @@ -193,6 +196,8 @@ private slots: void nestedStateMachines(); void goToState(); + + void task260403_clonedSignals(); }; tst_QStateMachine::tst_QStateMachine() @@ -3937,5 +3942,42 @@ void tst_QStateMachine::goToState() QVERIFY(machine.configuration().contains(s2_1)); } +class CloneSignalTransition : public QSignalTransition +{ +public: + CloneSignalTransition(QObject *sender, const char *signal, QAbstractState *target) + : QSignalTransition(sender, signal) + { + setTargetState(target); + } + + void onTransition(QEvent *e) + { + QSignalTransition::onTransition(e); + QSignalEvent *se = static_cast(e); + eventSignalIndex = se->signalIndex(); + } + + int eventSignalIndex; +}; + +void tst_QStateMachine::task260403_clonedSignals() +{ + SignalEmitter emitter; + QStateMachine machine; + QState *s1 = new QState(&machine); + QState *s2 = new QState(&machine); + CloneSignalTransition *t1 = new CloneSignalTransition(&emitter, SIGNAL(signalWithDefaultArg()), s2); + s1->addTransition(t1); + + machine.setInitialState(s1); + machine.start(); + QTest::qWait(1); + + emitter.emitSignalWithDefaultArg(); + QTest::qWait(1); + QCOMPARE(t1->eventSignalIndex, emitter.metaObject()->indexOfSignal("signalWithDefaultArg()")); +} + QTEST_MAIN(tst_QStateMachine) #include "tst_qstatemachine.moc" -- cgit v0.12