From a4e34a804af1aef8983a70784efddbfa3bfa9e02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Aum=C3=BCller?= <aumuell@reserv.at>
Date: Fri, 22 Jan 2010 13:56:50 +0100
Subject: [PATCH] fakevim: make sure that FakeVimHandler has returned before
 being deleted

some actions might cause the parent editor to be deleted,
don't crash in that case

Merge-request: 101
Reviewed-by: hjk <qtc-committer@nokia.com>
---
 src/plugins/fakevim/fakevimhandler.cpp | 35 ++++++++++++++++++--------
 src/plugins/fakevim/fakevimhandler.h   |  3 +++
 src/plugins/fakevim/fakevimplugin.cpp  | 29 ++++++++++++++++++++-
 3 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index f4626e0a922..941718d3eeb 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -662,17 +662,20 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     EventResult result = handleKey(key, um, ev->text());
     //endEditBlock();
 
-    // We fake vi-style end-of-line behaviour
-    m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
+    // the command might have destroyed the editor
+    if (m_textedit || m_plaintextedit) {
+        // We fake vi-style end-of-line behaviour
+        m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
 
-    QTC_ASSERT(!(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
-               qDebug() << "Cursor at EOL after key handler");
+        QTC_ASSERT(!(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
+                   qDebug() << "Cursor at EOL after key handler");
 
-    if (m_fakeEnd)
-        moveLeft();
+        if (m_fakeEnd)
+            moveLeft();
 
-    EDITOR(setTextCursor(m_tc));
-    m_oldPosition = m_tc.position();
+        EDITOR(setTextCursor(m_tc));
+        m_oldPosition = m_tc.position();
+    }
     return result;
 }
 
@@ -1033,6 +1036,9 @@ void FakeVimHandler::Private::updateSelection()
 
 void FakeVimHandler::Private::updateMiniBuffer()
 {
+    if (!m_textedit && !m_plaintextedit)
+        return;
+
     QString msg;
     if (m_passing) {
         msg = "-- PASSING --  ";
@@ -2060,8 +2066,10 @@ EventResult FakeVimHandler::Private::handleMiniBufferModes(int key, int unmodifi
             m_commandHistory.append(m_commandBuffer);
             EDITOR(setTextCursor(m_tc));
             handleExCommand(m_commandBuffer);
-            m_tc = EDITOR(textCursor());
-            leaveVisualMode();
+            if (m_textedit || m_plaintextedit) {
+                m_tc = EDITOR(textCursor());
+                leaveVisualMode();
+            }
         }
     } else if (unmodified == Key_Return && isSearchMode()) {
         if (!m_commandBuffer.isEmpty()) {
@@ -3428,6 +3436,13 @@ FakeVimHandler::~FakeVimHandler()
     delete d;
 }
 
+// gracefully handle that the parent editor is deleted
+void FakeVimHandler::disconnectFromEditor()
+{
+    d->m_textedit = 0;
+    d->m_plaintextedit = 0;
+}
+
 bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
 {
     bool active = theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h
index 8620aadb16f..59e5c85b1d0 100644
--- a/src/plugins/fakevim/fakevimhandler.h
+++ b/src/plugins/fakevim/fakevimhandler.h
@@ -48,6 +48,9 @@ public:
 
     QWidget *widget();
 
+    // call before widget is deleted
+    void disconnectFromEditor();
+
 public slots:
     void setCurrentFileName(const QString &fileName);
     void showBlackMessage(const QString &msg);
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index 97e9d5db4c5..178440b1363 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -744,6 +744,30 @@ void FakeVimPluginPrivate::findNext(bool reverse)
         triggerAction(Find::Constants::FIND_NEXT);
 }
 
+// this class defers deletion of a child FakeVimHandler using 'deleteLater'
+// - direct children QObject's would be 'delete'ed immediately before their parents
+class DeferredDeleter : public QObject
+{
+    Q_OBJECT
+
+    FakeVimHandler *m_handler;
+
+public:
+    DeferredDeleter(QObject *parent, FakeVimHandler *handler)
+        : QObject(parent)
+          , m_handler(handler)
+    {}
+
+    virtual ~DeferredDeleter()
+    {
+        if (m_handler) {
+            m_handler->disconnectFromEditor();
+            m_handler->deleteLater();
+            m_handler = 0;
+        }
+    }
+};
+
 void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
 {
     if (!editor)
@@ -760,7 +784,10 @@ void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
     //qDebug() << "OPENING: " << editor << editor->widget()
     //    << "MODE: " << theFakeVimSetting(ConfigUseFakeVim)->value();
 
-    FakeVimHandler *handler = new FakeVimHandler(widget, widget);
+    FakeVimHandler *handler = new FakeVimHandler(widget, 0);
+    // the handler might have triggered the deletion of the editor:
+    // make sure that it can return before being deleted itself
+    new DeferredDeleter(widget, handler);
     m_editorToHandler[editor] = handler;
 
     connect(handler, SIGNAL(extraInformationChanged(QString)),
-- 
GitLab