From 3abe2a72eab8534ba4ce25a3bb1015139964a987 Mon Sep 17 00:00:00 2001
From: Daniel Teske <daniel.teske@digia.com>
Date: Thu, 21 Mar 2013 19:24:34 +0100
Subject: [PATCH] UicCodeModelSupport: Make the code not so eager to run uic
 processes

Instead mostly postpone it until the contents are needed.

Task-number: QTCREATORBUG-9149

Change-Id: I83167537e97fbd965531d990c8073409ff7b0b32
Reviewed-by: Eike Ziller <eike.ziller@digia.com>
---
 .../cmakeuicodemodelsupport.h                 |  1 +
 src/plugins/cpptools/abstracteditorsupport.h  |  4 +-
 .../cpptools/uicodecompletionsupport.cpp      | 47 ++++++++++++++-----
 .../cpptools/uicodecompletionsupport.h        |  9 ++--
 .../qt4projectmanager/qtuicodemodelsupport.h  |  1 +
 5 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/src/plugins/cmakeprojectmanager/cmakeuicodemodelsupport.h b/src/plugins/cmakeprojectmanager/cmakeuicodemodelsupport.h
index 13188dd818..0e2261a802 100644
--- a/src/plugins/cmakeprojectmanager/cmakeuicodemodelsupport.h
+++ b/src/plugins/cmakeprojectmanager/cmakeuicodemodelsupport.h
@@ -42,6 +42,7 @@ class CMakeProject;
 
 class CMakeUiCodeModelSupport : public CppTools::UiCodeModelSupport
 {
+    Q_OBJECT
 public:
     CMakeUiCodeModelSupport(CPlusPlus::CppModelManagerInterface *modelmanager,
                           CMakeProject *project,
diff --git a/src/plugins/cpptools/abstracteditorsupport.h b/src/plugins/cpptools/abstracteditorsupport.h
index e52eebf319..858f893cb8 100644
--- a/src/plugins/cpptools/abstracteditorsupport.h
+++ b/src/plugins/cpptools/abstracteditorsupport.h
@@ -33,6 +33,7 @@
 #include "cpptools_global.h"
 
 #include <QString>
+#include <QObject>
 
 namespace CPlusPlus {
 class CppModelManagerInterface;
@@ -40,8 +41,9 @@ class CppModelManagerInterface;
 
 namespace CppTools {
 
-class CPPTOOLS_EXPORT AbstractEditorSupport
+class CPPTOOLS_EXPORT AbstractEditorSupport : public QObject
 {
+    Q_OBJECT
 public:
     explicit AbstractEditorSupport(CPlusPlus::CppModelManagerInterface *modelmanager);
     virtual ~AbstractEditorSupport();
diff --git a/src/plugins/cpptools/uicodecompletionsupport.cpp b/src/plugins/cpptools/uicodecompletionsupport.cpp
index b9e2f7bdde..54403f9a93 100644
--- a/src/plugins/cpptools/uicodecompletionsupport.cpp
+++ b/src/plugins/cpptools/uicodecompletionsupport.cpp
@@ -44,11 +44,12 @@ UiCodeModelSupport::UiCodeModelSupport(CppModelManagerInterface *modelmanager,
     : AbstractEditorSupport(modelmanager),
       m_sourceName(source),
       m_fileName(uiHeaderFile),
-      m_initialized(false),
-      m_running(false)
+      m_state(BARE)
 {
     if (debug)
         qDebug()<<"ctor UiCodeModelSupport for"<<m_sourceName<<uiHeaderFile;
+    connect(&m_process, SIGNAL(finished(int)),
+            this, SLOT(finishProcess()));
 }
 
 UiCodeModelSupport::~UiCodeModelSupport()
@@ -59,7 +60,8 @@ UiCodeModelSupport::~UiCodeModelSupport()
 
 void UiCodeModelSupport::init() const
 {
-    m_initialized = true;
+    if (m_state != BARE)
+        return;
     QDateTime sourceTime = QFileInfo(m_sourceName).lastModified();
     QFileInfo uiHeaderFileInfo(m_fileName);
     QDateTime uiHeaderTime = uiHeaderFileInfo.exists() ? uiHeaderFileInfo.lastModified() : QDateTime();
@@ -71,6 +73,7 @@ void UiCodeModelSupport::init() const
             QTextStream stream(&file);
             m_contents = stream.readAll().toUtf8();
             m_cacheTime = uiHeaderTime;
+            m_state = FINISHED;
             return;
         }
     }
@@ -91,20 +94,25 @@ void UiCodeModelSupport::init() const
                 qDebug()<<"uic run wasn't succesfull";
             m_cacheTime = QDateTime ();
             m_contents = QByteArray();
+            m_state = FINISHED;
             return;
         }
     } else {
         if (debug)
             qDebug()<<"Could open "<<m_sourceName<<"needed for the cpp model";
         m_contents = QByteArray();
+        m_state = FINISHED;
     }
 }
 
 QByteArray UiCodeModelSupport::contents() const
 {
-    if (!m_initialized)
+    // Check the common case first
+    if (m_state == FINISHED)
+        return m_contents;
+    if (m_state == BARE)
         init();
-    if (m_running)
+    if (m_state == RUNNING)
         finishProcess();
 
     return m_contents;
@@ -120,13 +128,16 @@ void UiCodeModelSupport::setFileName(const QString &name)
     if (m_fileName == name && m_cacheTime.isValid())
         return;
 
+    if (m_state == RUNNING)
+        finishProcess();
+
     if (debug)
         qDebug() << "UiCodeModelSupport::setFileName"<<name;
 
     m_fileName = name;
     m_contents.clear();
     m_cacheTime = QDateTime();
-    init();
+    m_state = BARE;
 }
 
 bool UiCodeModelSupport::runUic(const QString &ui) const
@@ -145,19 +156,23 @@ bool UiCodeModelSupport::runUic(const QString &ui) const
     if (!m_process.waitForBytesWritten(3000))
         goto error;
     m_process.closeWriteChannel();
-    m_running = true;
+    m_state = RUNNING;
     return true;
 
 error:
     if (debug)
         qDebug() << "failed" << m_process.readAllStandardError();
     m_process.kill();
-    m_running = false;
+    m_state = FINISHED;
     return false;
 }
 
 void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents)
 {
+    if (m_state == BARE)
+        init();
+    if (m_state == RUNNING)
+        finishProcess();
     if (runUic(formEditorContents))
         if (finishProcess())
             updateDocument();
@@ -165,23 +180,29 @@ void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents)
 
 bool UiCodeModelSupport::finishProcess() const
 {
-    if (!m_running)
+    if (m_state != RUNNING)
         return false;
     if (!m_process.waitForFinished(3000)
             && m_process.exitStatus() != QProcess::NormalExit
             && m_process.exitCode() != 0) {
+        if (m_state != RUNNING) // waitForFinished can recurse into finishProcess
+            return false;
+
         if (debug)
             qDebug() << "failed" << m_process.readAllStandardError();
         m_process.kill();
-        m_running = false;
+        m_state = FINISHED;
         return false;
     }
 
+    if (m_state != RUNNING) // waitForFinished can recurse into finishProcess
+        return true;
+
     m_contents = m_process.readAllStandardOutput();
     m_cacheTime = QDateTime::currentDateTime();
     if (debug)
         qDebug() << "ok" << m_contents.size() << "bytes.";
-    m_running = false;
+    m_state = FINISHED;
     return true;
 }
 
@@ -189,6 +210,10 @@ void UiCodeModelSupport::updateFromBuild()
 {
     if (debug)
         qDebug()<<"UiCodeModelSupport::updateFromBuild() for file"<<m_sourceName;
+    if (m_state == BARE)
+        init();
+    if (m_state == RUNNING)
+        finishProcess();
     // This is mostly a fall back for the cases when uic couldn't be run
     // it pays special attention to the case where a ui_*h was newly created
     QDateTime sourceTime = QFileInfo(m_sourceName).lastModified();
diff --git a/src/plugins/cpptools/uicodecompletionsupport.h b/src/plugins/cpptools/uicodecompletionsupport.h
index 5a1d8883de..eb25bbef61 100644
--- a/src/plugins/cpptools/uicodecompletionsupport.h
+++ b/src/plugins/cpptools/uicodecompletionsupport.h
@@ -43,6 +43,7 @@ namespace CppTools {
 
 class CPPTOOLS_EXPORT UiCodeModelSupport : public AbstractEditorSupport
 {
+    Q_OBJECT
 public:
     UiCodeModelSupport(CPlusPlus::CppModelManagerInterface *modelmanager,
                        const QString &sourceFile,
@@ -58,16 +59,18 @@ protected:
     virtual QString uicCommand() const = 0;
     virtual QStringList environment() const = 0;
 private:
+    enum State { BARE, RUNNING, FINISHED };
+
     void init() const;
     bool runUic(const QString &ui) const;
-    bool finishProcess() const;
+    Q_SLOT bool finishProcess() const;
     mutable QProcess m_process;
     QString m_sourceName;
     QString m_fileName;
-    mutable bool m_initialized;
+    mutable State m_state;
     mutable QByteArray m_contents;
     mutable QDateTime m_cacheTime;
-    mutable bool m_running;
+    static QList<UiCodeModelSupport *> m_waitingForStart;
 };
 
 } // CppTools
diff --git a/src/plugins/qt4projectmanager/qtuicodemodelsupport.h b/src/plugins/qt4projectmanager/qtuicodemodelsupport.h
index 7816da191d..d09e2f9126 100644
--- a/src/plugins/qt4projectmanager/qtuicodemodelsupport.h
+++ b/src/plugins/qt4projectmanager/qtuicodemodelsupport.h
@@ -42,6 +42,7 @@ namespace Internal {
 
 class Qt4UiCodeModelSupport : public CppTools::UiCodeModelSupport
 {
+    Q_OBJECT
 public:
     Qt4UiCodeModelSupport(CPlusPlus::CppModelManagerInterface *modelmanager,
                           Qt4Project *project,
-- 
GitLab