From 20801bee306cbf6c6790cd0af4a7e389a811aa79 Mon Sep 17 00:00:00 2001
From: Kai Koehne <kai.koehne@nokia.com>
Date: Tue, 19 Jan 2010 13:53:48 +0100
Subject: [PATCH] Update project tree if .qmlproject file / included
 directories change

---
 .../fileformat/filefilteritems.cpp            | 36 +++++++++++++---
 .../fileformat/filefilteritems.h              |  9 +++-
 .../fileformat/qmlprojectitem.cpp             |  5 ++-
 .../fileformat/qmlprojectitem.h               |  4 +-
 src/plugins/qmlprojectmanager/qmlproject.cpp  | 42 ++++++++++++++-----
 src/plugins/qmlprojectmanager/qmlproject.h    | 18 ++++++--
 6 files changed, 90 insertions(+), 24 deletions(-)

diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
index d80f3de97ec..7ccee302ce7 100644
--- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
+++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
@@ -7,6 +7,8 @@ FileFilterBaseItem::FileFilterBaseItem(QObject *parent) :
         QmlProjectContentItem(parent),
         m_recursive(false)
 {
+    connect(&m_fsWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(updateFileList()));
+    connect(&m_fsWatcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFileList()));
 }
 
 QString FileFilterBaseItem::directory() const
@@ -82,24 +84,48 @@ QString FileFilterBaseItem::absoluteDir() const
 
 void FileFilterBaseItem::updateFileList()
 {
-    const QString dir = absoluteDir();
-    if (dir.isEmpty())
+    const QString projectDir = absoluteDir();
+    if (projectDir.isEmpty())
         return;
 
-    const QSet<QString> newFiles = filesInSubTree(QDir(m_defaultDir), QDir(dir));
+    QSet<QString> dirsToBeWatched;
+    const QSet<QString> newFiles = filesInSubTree(QDir(m_defaultDir), QDir(projectDir), &dirsToBeWatched);
+
     if (newFiles != m_files) {
+        // update watched files
+        foreach (const QString &file, m_files - newFiles) {
+            m_fsWatcher.removePath(QDir(projectDir).absoluteFilePath(file));
+        }
+        foreach (const QString &file, newFiles - m_files) {
+            m_fsWatcher.addPath(QDir(projectDir).absoluteFilePath(file));
+        }
+
         m_files = newFiles;
+
         emit filesChanged();
     }
+
+    // update watched directories
+    QSet<QString> watchedDirectories = m_fsWatcher.directories().toSet();
+    foreach (const QString &dir, watchedDirectories - dirsToBeWatched) {
+        m_fsWatcher.removePath(QDir(projectDir).absoluteFilePath(dir));
+    }
+    foreach (const QString &dir, dirsToBeWatched - watchedDirectories) {
+        m_fsWatcher.addPath(QDir(projectDir).absoluteFilePath(dir));
+    }
 }
 
-QSet<QString> FileFilterBaseItem::filesInSubTree(const QDir &rootDir, const QDir &dir)
+QSet<QString> FileFilterBaseItem::filesInSubTree(const QDir &rootDir, const QDir &dir, QSet<QString> *parsedDirs)
 {
     QSet<QString> fileSet;
 
+    if (parsedDirs)
+        parsedDirs->insert(dir.absolutePath());
+
     foreach (const QFileInfo &file, dir.entryInfoList(QDir::Files)) {
-        if (m_regex.exactMatch(file.fileName()))
+        if (m_regex.exactMatch(file.fileName())) {
             fileSet.insert(rootDir.relativeFilePath(file.absoluteFilePath()));
+        }
     }
 
     if (m_recursive) {
diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
index 5857495be14..d3abe526b25 100644
--- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
+++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
@@ -5,6 +5,7 @@
 #include <QObject>
 #include <QSet>
 #include <qml.h>
+#include <QFileSystemWatcher>
 
 #include "qmlprojectitem.h"
 
@@ -40,11 +41,13 @@ signals:
     void filterChanged();
     void filesChanged();
 
+private slots:
+    void updateFileList();
+
 private:
     QString absoluteDir() const;
 
-    void updateFileList();
-    QSet<QString> filesInSubTree(const QDir &rootDir, const QDir &dir);
+    QSet<QString> filesInSubTree(const QDir &rootDir, const QDir &dir, QSet<QString> *parsedDirs = 0);
 
     QString m_rootDir;
     QString m_defaultDir;
@@ -53,6 +56,8 @@ private:
     QRegExp m_regex;
     bool m_recursive;
 
+    QFileSystemWatcher m_fsWatcher;
+
     QSet<QString> m_files;
 
     friend class ProjectItem;
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
index 4bc66ecbd49..1308c1bbe5b 100644
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
@@ -56,6 +56,7 @@ QString QmlProjectItem::sourceDirectory() const
     return d->sourceDirectory;
 }
 
+// kind of initialization
 void QmlProjectItem::setSourceDirectory(const QString &directoryPath)
 {
     Q_D(QmlProjectItem);
@@ -68,8 +69,10 @@ void QmlProjectItem::setSourceDirectory(const QString &directoryPath)
     for (int i = 0; i < d->content.size(); ++i) {
         QmlProjectContentItem *contentElement = d->content.at(i);
         FileFilterBaseItem *fileFilter = qobject_cast<FileFilterBaseItem*>(contentElement);
-        if (fileFilter)
+        if (fileFilter) {
             fileFilter->setDefaultDirectory(directoryPath);
+            connect(fileFilter, SIGNAL(filesChanged()), this, SIGNAL(qmlFilesChanged()));
+        }
     }
 
     emit sourceDirectoryChanged();
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
index ce7a6b54670..47a1353bfab 100644
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
@@ -1,7 +1,7 @@
 #ifndef PROJECTITEM_H
 #define PROJECTITEM_H
 
-#include <QObject>
+#include <QtCore/QObject>
 #include <qml.h>
 
 namespace QmlProjectManager {
@@ -38,11 +38,11 @@ public:
     QStringList qmlFiles() const;
 
 signals:
+    void qmlFilesChanged();
     void sourceDirectoryChanged();
 
 protected:
     QmlProjectItemPrivate *d_ptr;
-
 };
 
 } // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 04458845c9e..8b1c28f289e 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -76,7 +76,8 @@ enum {
 QmlProject::QmlProject(Manager *manager, const QString &fileName)
     : m_manager(manager),
       m_fileName(fileName),
-      m_modelManager(ExtensionSystem::PluginManager::instance()->getObject<QmlJSEditor::QmlModelManagerInterface>())
+      m_modelManager(ExtensionSystem::PluginManager::instance()->getObject<QmlJSEditor::QmlModelManagerInterface>()),
+      m_fileWatcher(new ProjectExplorer::FileWatcher(this))
 {
     QFileInfo fileInfo(m_fileName);
     m_projectName = fileInfo.completeBaseName();
@@ -84,6 +85,10 @@ QmlProject::QmlProject(Manager *manager, const QString &fileName)
     m_file = new QmlProjectFile(this, fileName);
     m_rootNode = new QmlProjectNode(this, m_file);
 
+    m_fileWatcher->addFile(fileName),
+    connect(m_fileWatcher, SIGNAL(fileChanged(QString)),
+            this, SLOT(refreshProjectFile()));
+
     m_manager->registerProject(this);
 }
 
@@ -129,16 +134,23 @@ static QStringList readLines(const QString &absoluteFileName)
 void QmlProject::parseProject(RefreshOptions options)
 {
     if (options & Files) {
+        if (options & ProjectFile)
+            delete m_projectItem.data();
         if (!m_projectItem) {
-            QmlComponent *component = new QmlComponent(&m_engine, m_fileName, this);
-            if (component->isReady()
-                && qobject_cast<QmlProjectItem*>(component->create())) {
-                m_projectItem = qobject_cast<QmlProjectItem*>(component->create());
-            } else {
-                qWarning() << m_fileName << "is not valid qml file, falling back to old format ...";
-                m_files = convertToAbsoluteFiles(readLines(filesFileName()));
-                m_files.removeDuplicates();
-                m_modelManager->updateSourceFiles(m_files);
+            QFile file(m_fileName);
+            if (file.open(QFile::ReadOnly)) {
+                QmlComponent *component = new QmlComponent(&m_engine, this);
+                component->setData(file.readAll(), QUrl::fromLocalFile(m_fileName));
+                if (component->isReady()
+                    && qobject_cast<QmlProjectItem*>(component->create())) {
+                    m_projectItem = qobject_cast<QmlProjectItem*>(component->create());
+                    connect(m_projectItem.data(), SIGNAL(qmlFilesChanged()), this, SLOT(refreshFiles()));
+                } else {
+                    qWarning() << m_fileName << "is not valid qml file, falling back to old format ...";
+                    m_files = convertToAbsoluteFiles(readLines(filesFileName()));
+                    m_files.removeDuplicates();
+                    m_modelManager->updateSourceFiles(m_files);
+                }
             }
         }
         if (m_projectItem) {
@@ -191,6 +203,16 @@ QStringList QmlProject::files() const
     return files;
 }
 
+void QmlProject::refreshProjectFile()
+{
+    refresh(QmlProject::ProjectFile | Files);
+}
+
+void QmlProject::refreshFiles()
+{
+    refresh(Files);
+}
+
 QString QmlProject::displayName() const
 {
     return m_projectName;
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index ec695092d83..96d836f0841 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -39,6 +39,7 @@
 #include <projectexplorer/projectnodes.h>
 #include <projectexplorer/buildstep.h>
 #include <projectexplorer/applicationrunconfiguration.h>
+#include <projectexplorer/filewatcher.h>
 #include <coreplugin/ifile.h>
 
 #include <QtCore/QDir>
@@ -170,17 +171,23 @@ public:
     virtual Internal::QmlProjectNode *rootProjectNode() const;
     virtual QStringList files(FilesMode fileMode) const;
 
-    enum RefreshOptions {
-        Files         = 0x01,
-        Configuration = 0x02,
-        Everything    = Files | Configuration
+    enum RefreshOption {
+        ProjectFile   = 0x01,
+        Files         = 0x02,
+        Configuration = 0x04,
+        Everything    = ProjectFile | Files | Configuration
     };
+    Q_DECLARE_FLAGS(RefreshOptions,RefreshOption)
 
     void refresh(RefreshOptions options);
 
     QDir projectDir() const;
     QStringList files() const;
 
+private slots:
+    void refreshProjectFile();
+    void refreshFiles();
+
 protected:
     virtual void saveSettingsImpl(ProjectExplorer::PersistentSettingsWriter &writer);
     virtual bool restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader &reader);
@@ -202,6 +209,7 @@ private:
     // qml based, new format
     QmlEngine m_engine;
     QWeakPointer<QmlProjectItem> m_projectItem;
+    ProjectExplorer::FileWatcher *m_fileWatcher;
 
     Internal::QmlProjectNode *m_rootNode;
 };
@@ -243,4 +251,6 @@ private:
 
 } // namespace QmlProjectManager
 
+Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlProject::RefreshOptions)
+
 #endif // QMLPROJECT_H
-- 
GitLab