this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
disconnect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
- m_roleEditor->deleteLater();
+ // Do not delete the role editor using deleteLater() because we might be
+ // inside a nested event loop which has been started by one of its event
+ // handlers (contextMenuEvent() or drag&drop inside mouseMoveEvent()).
+ m_roleEditor->deleteWhenIdle();
m_roleEditor = 0;
}
return;
this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
disconnect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
- m_roleEditor->deleteLater();
+
+ // Do not delete the role editor using deleteLater() because we might be
+ // inside a nested event loop which has been started by one of its event
+ // handlers (contextMenuEvent() or drag&drop inside mouseMoveEvent()).
+ m_roleEditor->deleteWhenIdle();
m_roleEditor = 0;
}
KTextEdit(parent),
m_index(0),
m_role(),
- m_blockFinishedSignal(false)
+ m_blockFinishedSignal(false),
+ m_eventHandlingLevel(0),
+ m_deleteAfterEventHandling(false)
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
return m_role;
}
+void KItemListRoleEditor::deleteWhenIdle()
+{
+ if (m_eventHandlingLevel > 0) {
+ // We are handling an event at the moment. It could be that we
+ // are in a nested event loop run by contextMenuEvent() or a
+ // call of mousePressEvent() which results in drag&drop.
+ // -> do not call deleteLater() to prevent a crash when we
+ // return from the nested event loop.
+ m_deleteAfterEventHandling = true;
+ } else {
+ deleteLater();
+ }
+}
+
bool KItemListRoleEditor::eventFilter(QObject* watched, QEvent* event)
{
if (watched == parentWidget() && event->type() == QEvent::Resize) {
bool KItemListRoleEditor::event(QEvent* event)
{
+ ++m_eventHandlingLevel;
+
if (event->type() == QEvent::FocusOut) {
QFocusEvent* focusEvent = static_cast<QFocusEvent*>(event);
if (focusEvent->reason() != Qt::PopupFocusReason) {
emitRoleEditingFinished();
}
}
- return KTextEdit::event(event);
+
+ const int result = KTextEdit::event(event);
+ --m_eventHandlingLevel;
+
+ if (m_deleteAfterEventHandling && m_eventHandlingLevel == 0) {
+ // Schedule this object for deletion and make sure that we do not try
+ // to deleteLater() again when the DeferredDelete event is received.
+ deleteLater();
+ m_deleteAfterEventHandling = false;
+ }
+
+ return result;
+}
+
+bool KItemListRoleEditor::viewportEvent(QEvent* event)
+{
+ ++m_eventHandlingLevel;
+ const bool result = KTextEdit::viewportEvent(event);
+ --m_eventHandlingLevel;
+
+ if (m_deleteAfterEventHandling && m_eventHandlingLevel == 0) {
+ // Schedule this object for deletion and make sure that we do not try
+ // to deleteLater() again when the DeferredDelete event is received.
+ deleteLater();
+ m_deleteAfterEventHandling = false;
+ }
+
+ return result;
}
void KItemListRoleEditor::keyPressEvent(QKeyEvent* event)
void setRole(const QByteArray& role);
QByteArray role() const;
+ /**
+ * Calls deleteLater() if no event is being handled at the moment.
+ * Otherwise, the deletion is deferred until the event handling is
+ * finished. This prevents that the deletion happens inside a nested
+ * event loop which might be run in contextMenuEvent() or
+ * mouseMoveEvent() because this would probably cause a crash.
+ */
+ void deleteWhenIdle();
+
virtual bool eventFilter(QObject* watched, QEvent* event);
signals:
protected:
virtual bool event(QEvent* event);
+ virtual bool viewportEvent(QEvent* event);
virtual void keyPressEvent(QKeyEvent* event);
private slots:
int m_index;
QByteArray m_role;
bool m_blockFinishedSignal;
+ int m_eventHandlingLevel;
+ bool m_deleteAfterEventHandling;
};
#endif