From 41a7cd15be9d83717cbb343083b81f3c2e7a3247 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 15 Oct 2019 10:31:01 +0200 Subject: [PATCH] QmlDesigner: Fix assert TimelineWidget::invalidateTimelineDuration() is called by TimelineView::instancePropertyChanged(), which is a callback from the model. Those callbacks are not supposed to mutate the model and write access to the model will trigger an assert. The method setCurrentFrame() calls ModelNode::setAuxiliaryData(). The reasoning for this behavior is to avoid events casades from the get go and to avoid that a view has a side effect on the operation of another view. This way we also avoid any circular information flow in the application. In theory a view should never act as a 'gatekeeper' like in this case. The simple 'hack' for trivial cases is to use a timer. Generally we try to move the logic into the model in such cases. Change-Id: I0b46bb38ee0a9603d4617f1a13d8cfcd2e7378b8 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../components/timelineeditor/timelinewidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp index 82321a1198c..7d64fad56a3 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp @@ -453,7 +453,11 @@ void TimelineWidget::invalidateTimelineDuration(const QmlTimeline &timeline) else if (playHeadFrame > timeline.endKeyframe()) playHeadFrame = timeline.endKeyframe(); - graphicsScene()->setCurrentFrame(playHeadFrame); + /* We have to set the current frame asynchronously, + * because callbacks are not supposed to mutate the model. */ + QTimer::singleShot(0, [this, playHeadFrame] { + graphicsScene()->setCurrentFrame(playHeadFrame); + }); } } }