From 75545a2bf0121af9f081b2e5e76879e42e490cc2 Mon Sep 17 00:00:00 2001
From: dt <qtc-committer@nokia.com>
Date: Fri, 22 Jan 2010 16:49:57 +0100
Subject: [PATCH] Fix FileManager to correctly handle multiple IFile's for the
 same file

And port the Qt4ProjectManager to use that API for synchronization
between editors and the .pro file tree.

Reviewed-By: con
---
 src/plugins/coreplugin/filemanager.cpp        | 349 ++++++++++++------
 src/plugins/coreplugin/filemanager.h          |  14 +-
 .../scriptmanager/qworkbench_wrapper.cpp      |   6 -
 .../scriptmanager/qworkbench_wrapper.h        |   1 -
 src/plugins/cvs/cvsplugin.cpp                 |   1 -
 src/plugins/git/gitplugin.cpp                 |   1 -
 src/plugins/perforce/perforceplugin.cpp       |   1 -
 .../qt4projectmanager/profileeditor.cpp       |  16 +-
 src/plugins/qt4projectmanager/profileeditor.h |   6 +-
 src/plugins/qt4projectmanager/qt4nodes.cpp    |  55 ++-
 src/plugins/qt4projectmanager/qt4nodes.h      |   7 +-
 src/plugins/subversion/subversionplugin.cpp   |   1 -
 12 files changed, 264 insertions(+), 194 deletions(-)

diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp
index 24e2178307a..a81002bcace 100644
--- a/src/plugins/coreplugin/filemanager.cpp
+++ b/src/plugins/coreplugin/filemanager.cpp
@@ -41,7 +41,6 @@
 #include <utils/qtcassert.h>
 #include <utils/pathchooser.h>
 
-#include <QtCore/QDebug>
 #include <QtCore/QSettings>
 #include <QtCore/QFileInfo>
 #include <QtCore/QFile>
@@ -66,9 +65,13 @@
   be asked to save all modified files.
 
   Different IFile objects in the set can point to the same file in the
-  filesystem. The monitoring of a file can be blocked by blockFileChange(), and
+  filesystem. The monitoring for a IFile can be blocked by blockFileChange(), and
   enabled again by unblockFileChange().
 
+  The functions expectFileChange() and unexpectFileChange() mark a file change
+  as expected. On expected file changes all IFile objects are notified to reload
+  themselves.
+
   The FileManager service also provides two convenience methods for saving
   files: saveModifiedFiles() and saveModifiedFilesSilently(). Both take a list
   of FileInterfaces as an argument, and return the list of files which were
@@ -88,17 +91,24 @@ static const char useProjectDirectoryKeyC[] = "UseProjectsDirectory";
 namespace Core {
 namespace Internal {
 
-struct FileInfo
+struct FileStateItem
 {
-    QString fileName;
     QDateTime modified;
     QFile::Permissions permissions;
 };
 
+struct FileState
+{
+    QMap<IFile *, FileStateItem> lastUpdatedState;
+    FileStateItem expected;
+};
+
+
 struct FileManagerPrivate {
     explicit FileManagerPrivate(QObject *q, QMainWindow *mw);
 
-    QMap<IFile*, FileInfo> m_managedFiles;
+    QMap<QString, FileState> m_states;
+    QStringList m_changedFiles;
 
     QStringList m_recentFiles;
     static const int m_maxRecentFiles = 7;
@@ -107,7 +117,6 @@ struct FileManagerPrivate {
 
     QMainWindow *m_mainWindow;
     QFileSystemWatcher *m_fileWatcher;
-    QList<QPointer<IFile> > m_changedFiles;
     bool m_blockActivated;
     QString m_lastVisitedDirectory;
     QString m_projectsDirectory;
@@ -178,17 +187,90 @@ bool FileManager::addFiles(const QList<IFile *> &files)
 {
     bool filesAdded = false;
     foreach (IFile *file, files) {
-        if (!file || d->m_managedFiles.contains(file))
+        if (!file)
+            continue;
+        const QString &fixedFileName = fixFileName(file->fileName());
+        if (d->m_states.value(fixedFileName).lastUpdatedState.contains(file))
             continue;
         connect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
         connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
         filesAdded = true;
-        addWatch(fixFileName(file->fileName()));
-        updateFileInfo(file);
+
+        addFileInfo(file);
     }
     return filesAdded;
 }
 
+void FileManager::addFileInfo(IFile *file)
+{
+    // We do want to insert the IFile into d->m_states even if the filename is empty
+    // Such that m_states always contains all IFiles
+
+    const QString fixedname = fixFileName(file->fileName());
+    Internal::FileStateItem item;
+    if (!fixedname.isEmpty()) {
+        const QFileInfo fi(file->fileName());
+        item.modified = fi.lastModified();
+        item.permissions = fi.permissions();
+    }
+
+    if (!d->m_states.contains(fixedname)) {
+        d->m_states.insert(fixedname, Internal::FileState());
+        if (!fixedname.isEmpty())
+            d->m_fileWatcher->addPath(fixedname);
+    }
+
+    d->m_states[fixedname].lastUpdatedState.insert(file, item);
+}
+
+void FileManager::updateFileInfo(IFile *file)
+{
+    const QString fixedname = fixFileName(file->fileName());
+    // If the filename is empty there's nothing to do
+    if (fixedname.isEmpty())
+        return;
+    const QFileInfo fi(file->fileName());
+
+    Internal::FileStateItem item;
+    item.modified = fi.lastModified();
+    item.permissions = fi.permissions();
+
+    d->m_states[fixedname].lastUpdatedState.insert(file, item);
+}
+
+///
+/// Does not use file->fileName, as such is save to use
+/// with renamed files and deleted files
+void FileManager::removeFileInfo(IFile *file)
+{
+    QString fileName;
+    QMap<QString, Internal::FileState>::const_iterator it, end;
+    end = d->m_states.constEnd();
+    for (it = d->m_states.constBegin(); it != end; ++it) {
+        if (it.value().lastUpdatedState.contains(file)) {
+            fileName = it.key();
+            break;
+        }
+    }
+
+    // The filename might be empty but not null
+    Q_ASSERT(fileName != QString::null);
+
+    removeFileInfo(fileName, file);
+}
+
+void FileManager::removeFileInfo(const QString &fileName, IFile *file)
+{
+    const QString &fixedName = fixFileName(fileName);
+    d->m_states[fixedName].lastUpdatedState.remove(file);
+
+    if (d->m_states.value(fixedName).lastUpdatedState.isEmpty()) {
+        d->m_states.remove(fixedName);
+        if (!fixedName.isEmpty())
+            d->m_fileWatcher->removePath(fixedName);
+    }
+}
+
 /*!
     \fn bool FileManager::addFile(IFile *files)
 
@@ -203,11 +285,9 @@ bool FileManager::addFile(IFile *file)
 
 void FileManager::fileDestroyed(QObject *obj)
 {
-    // we can't use qobject_cast here, because meta data is already destroyed
+    // removeFileInfo works even if the file does not really exist anymore
     IFile *file = static_cast<IFile*>(obj);
-    const QString filename = d->m_managedFiles.value(file).fileName;
-    d->m_managedFiles.remove(file);
-    removeWatch(filename);
+    removeFileInfo(file);
 }
 
 /*!
@@ -225,37 +305,29 @@ bool FileManager::removeFile(IFile *file)
     disconnect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
     disconnect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
 
-    if (!d->m_managedFiles.contains(file))
-        return false;
-    const Internal::FileInfo info = d->m_managedFiles.take(file);
-    const QString filename = info.fileName;
-    removeWatch(filename);
+    removeFileInfo(file->fileName(), file);
     return true;
 }
 
-void FileManager::addWatch(const QString &filename)
-{
-    if (!filename.isEmpty() && managedFiles(filename).isEmpty())
-        d->m_fileWatcher->addPath(filename);
-}
 
-void FileManager::removeWatch(const QString &filename)
-{
-    if (!filename.isEmpty() && managedFiles(filename).isEmpty())
-        d->m_fileWatcher->removePath(filename);
-}
 
 void FileManager::checkForNewFileName()
 {
     IFile *file = qobject_cast<IFile *>(sender());
     QTC_ASSERT(file, return);
-    const QString newfilename = fixFileName(file->fileName());
-    const QString oldfilename = d->m_managedFiles.value(file).fileName;
-    if (!newfilename.isEmpty() && newfilename != oldfilename) {
-        d->m_managedFiles[file].fileName = newfilename;
-        removeWatch(oldfilename);
-        addWatch(newfilename);
+    const QString &fileName = fixFileName(file->fileName());
+
+    // check if the IFile is in the map
+    if (d->m_states[fileName].lastUpdatedState.contains(file)) {
+        // Should checkForNewFileName also call updateFileInfo if the name didn't change?
+        updateFileInfo(file);
+        return;
     }
+
+    // Probably the name has changed...
+    // This also updates the state to the on disk state
+    removeFileInfo(file);
+    addFileInfo(file);
 }
 
 // TODO Rename to nativeFileName
@@ -280,7 +352,7 @@ bool FileManager::isFileManaged(const QString &fileName) const
     if (fileName.isEmpty())
         return false;
 
-    return !managedFiles(fixFileName(fileName)).isEmpty();
+    return !d->m_states.contains(fixFileName(fileName));
 }
 
 /*!
@@ -292,11 +364,15 @@ QList<IFile *> FileManager::modifiedFiles() const
 {
     QList<IFile *> modifiedFiles;
 
-    const QMap<IFile*, Internal::FileInfo>::const_iterator cend =  d->m_managedFiles.constEnd();
-    for (QMap<IFile*, Internal::FileInfo>::const_iterator i = d->m_managedFiles.constBegin(); i != cend; ++i) {
-        IFile *fi = i.key();
-        if (fi->isModified())
-            modifiedFiles << fi;
+    QMap<QString, Internal::FileState>::const_iterator it, end;
+    end = d->m_states.constEnd();
+    for(it = d->m_states.constBegin(); it != end; ++it) {
+        QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
+        jt = it.value().lastUpdatedState.constBegin();
+        jend = it.value().lastUpdatedState.constEnd();
+        for( ; jt != jend; ++jt)
+            if (jt.key()->isModified())
+                modifiedFiles << jt.key();
     }
     return modifiedFiles;
 }
@@ -308,8 +384,8 @@ QList<IFile *> FileManager::modifiedFiles() const
 */
 void FileManager::blockFileChange(IFile *file)
 {
-    if (!file->fileName().isEmpty())
-        d->m_fileWatcher->removePath(file->fileName());
+    // Nothing to do
+    Q_UNUSED(file);
 }
 
 /*!
@@ -319,21 +395,58 @@ void FileManager::blockFileChange(IFile *file)
 */
 void FileManager::unblockFileChange(IFile *file)
 {
-    foreach (IFile *managedFile, managedFiles(file->fileName()))
-        updateFileInfo(managedFile);
-    if (!file->fileName().isEmpty())
-        d->m_fileWatcher->addPath(file->fileName());
+    // We are updating the lastUpdated time to the current modification time
+    // in changedFile we'll compare the modification time with the last updated
+    // time, and if they are the same, then we don't deliver that notification
+    // to corresponding IFile
+    //
+    // Also we are updating the expected time of the file
+    // in changedFile we'll check if the modification time
+    // is the same as the saved one here
+    // If so then it's a expected change
+
+    updateFileInfo(file);
+    updateExpectedState(fixFileName(file->fileName()));
 }
 
-void FileManager::updateFileInfo(IFile *file)
+/*!
+    \fn void FileManager::expectFileChange(const QString &fileName)
+
+    Any subsequent change to \a fileName is treated as a expected file change.
+
+    \see FileManager::unexpectFileChange(const QString &fileName)
+*/
+void FileManager::expectFileChange(const QString &fileName)
 {
-    const QString fixedname = fixFileName(file->fileName());
-    const QFileInfo fi(file->fileName());
-    Internal::FileInfo info;
-    info.fileName = fixedname;
-    info.modified = fi.lastModified();
-    info.permissions = fi.permissions();
-    d->m_managedFiles.insert(file, info);
+    // Nothing to do
+    Q_UNUSED(fileName);
+}
+
+/*!
+    \fn void FileManager::unexpectFileChange(const QString &fileName)
+
+    Any change to \a fileName are unexpected again.
+
+    \see FileManager::expectFileChange(const QString &fileName)
+*/
+void FileManager::unexpectFileChange(const QString &fileName)
+{
+    // We are updating the expected time of the file
+    // And in changedFile we'll check if the modification time
+    // is the same as the saved one here
+    // If so then it's a expected change
+
+    updateExpectedState(fileName);
+}
+
+void FileManager::updateExpectedState(const QString &fileName)
+{
+    const QString &fixedName = fixFileName(fileName);
+    if (fixedName.isEmpty())
+        return;
+    QFileInfo fi(fixedName);
+    d->m_states[fixedName].expected.modified = fi.lastModified();
+    d->m_states[fixedName].expected.permissions = fi.permissions();
 }
 
 /*!
@@ -543,11 +656,14 @@ QStringList FileManager::getOpenFileNames(const QString &filters,
 }
 
 
-void FileManager::changedFile(const QString &file)
+void FileManager::changedFile(const QString &fileName)
 {
     const bool wasempty = d->m_changedFiles.isEmpty();
-    foreach (IFile *fileinterface, managedFiles(file))
-        d->m_changedFiles << fileinterface;
+
+    const QString &fixedName = fixFileName(fileName);
+    if (!d->m_changedFiles.contains(fixedName))
+        d->m_changedFiles.append(fixedName);
+
     if (wasempty && !d->m_changedFiles.isEmpty()) {
         QTimer::singleShot(200, this, SLOT(checkForReload()));
     }
@@ -563,36 +679,61 @@ void FileManager::mainWindowActivated()
 
 void FileManager::checkForReload()
 {
-    if (QApplication::activeWindow() == d->m_mainWindow &&
-        !d->m_blockActivated && !d->m_changedFiles.isEmpty()) {
-        d->m_blockActivated = true;
-        const QList<QPointer<IFile> > changed = d->m_changedFiles;
-        d->m_changedFiles.clear();
-        IFile::ReloadBehavior behavior = EditorManager::instance()->reloadBehavior();
-        foreach (IFile *f, changed) {
-            if (!f)
-                continue;
-            QFileInfo fi(f->fileName());
-            Internal::FileInfo info = d->m_managedFiles.value(f);
-            if (info.modified != fi.lastModified()
-                    || info.permissions != fi.permissions()) {
-                if (info.modified != fi.lastModified())
-                    f->modified(&behavior);
-                else {
-                    IFile::ReloadBehavior tempBeh =
-                        IFile::ReloadPermissions;
-                    f->modified(&tempBeh);
-                }
-                updateFileInfo(f);
+    if (QApplication::activeWindow() != d->m_mainWindow)
+        return;
 
-                // the file system watchers loses inodes when a file is removed/renamed. Work around it.
-                d->m_fileWatcher->removePath(f->fileName());
-                d->m_fileWatcher->addPath(f->fileName());
+    if (d->m_blockActivated)
+        return;
+
+    d->m_blockActivated = true;
+
+    IFile::ReloadBehavior behavior = EditorManager::instance()->reloadBehavior();
+
+    foreach(const QString &fileName, d->m_changedFiles) {
+        // Get the information from the filesystem
+        QFileInfo fi(fileName);
+        bool expected = false;
+        if (fi.lastModified() == d->m_states.value(fileName).expected.modified
+            && fi.permissions() == d->m_states.value(fileName).expected.permissions) {
+            expected = true;
+        }
+
+        const QMap<IFile *, Internal::FileStateItem> &lastUpdated =
+                d->m_states.value(fileName).lastUpdatedState;
+        QMap<IFile *, Internal::FileStateItem>::const_iterator it, end;
+        it = lastUpdated.constBegin();
+        end = lastUpdated.constEnd();
+
+        for ( ; it != end; ++it) {
+            // Compare
+            if (it.value().modified == fi.lastModified()
+                && it.value().permissions == fi.permissions()) {
+                // Already up to date
+            } else {
+                // Update IFile
+                if (expected) {
+                    IFile::ReloadBehavior tempBeh = IFile::ReloadUnmodified;
+                    it.key()->modified(&tempBeh);
+                } else {
+                    if (it.value().modified == fi.lastModified()) {
+                        // Only permission change
+                        IFile::ReloadBehavior tempBeh = IFile::ReloadPermissions;
+                        it.key()->modified(&tempBeh);
+                    } else {
+                        it.key()->modified(&behavior);
+                    }
+                }
+                updateFileInfo(it.key());
             }
+
         }
-        d->m_blockActivated = false;
-        checkForReload();
+
+        d->m_fileWatcher->removePath(fileName);
+        d->m_fileWatcher->addPath(fileName);
     }
+
+    d->m_changedFiles.clear();
+    d->m_blockActivated = false;
 }
 
 void FileManager::syncWithEditor(Core::IContext *context)
@@ -671,25 +812,6 @@ QString FileManager::currentFile() const
     return d->m_currentFile;
 }
 
-/*!
-    \fn QList<IFile*> FileManager::managedFiles(const QString &fileName) const
-
-    Returns the list one IFile's in the set that point to \a fileName.
-*/
-QList<IFile *> FileManager::managedFiles(const QString &fileName) const
-{
-    const QString fixedName = fixFileName(fileName);
-    QList<IFile *> result;
-    if (!fixedName.isEmpty()) {
-        const QMap<IFile*, Internal::FileInfo>::const_iterator cend =  d->m_managedFiles.constEnd();
-        for (QMap<IFile*, Internal::FileInfo>::const_iterator i = d->m_managedFiles.constBegin(); i != cend; ++i) {
-            if (i.value().fileName == fixedName)
-                result << i.key();
-        }
-    }
-    return result;
-}
-
 /*!
 
   Returns the initial directory for a new file dialog. If there is
@@ -789,33 +911,16 @@ void FileManager::notifyFilesChangedInternally(const QStringList &files)
 // -------------- FileChangeBlocker
 
 FileChangeBlocker::FileChangeBlocker(const QString &fileName)
-    : m_reload(false)
+    : m_fileName(fileName)
 {
     Core::FileManager *fm = Core::ICore::instance()->fileManager();
-    m_files = fm->managedFiles(fileName);
-    foreach (Core::IFile *file, m_files)
-        fm->blockFileChange(file);
+    fm->expectFileChange(fileName);
 }
 
 FileChangeBlocker::~FileChangeBlocker()
 {
-    Core::IFile::ReloadBehavior tempBehavior = Core::IFile::ReloadAll;
     Core::FileManager *fm = Core::ICore::instance()->fileManager();
-    foreach (Core::IFile *file, m_files) {
-        if (m_reload)
-            file->modified(&tempBehavior);
-        fm->unblockFileChange(file);
-    }
-}
-
-void FileChangeBlocker::setModifiedReload(bool b)
-{
-    m_reload = b;
-}
-
-bool FileChangeBlocker::modifiedReload() const
-{
-    return m_reload;
+    fm->unexpectFileChange(m_fileName);
 }
 
 } // namespace Core
diff --git a/src/plugins/coreplugin/filemanager.h b/src/plugins/coreplugin/filemanager.h
index 55dd392e409..8e9c830164a 100644
--- a/src/plugins/coreplugin/filemanager.h
+++ b/src/plugins/coreplugin/filemanager.h
@@ -61,12 +61,14 @@ public:
     bool addFile(IFile *file);
     bool removeFile(IFile *file);
     bool isFileManaged(const QString &fileName) const;
-    QList<IFile *> managedFiles(const QString &fileName) const;
     QList<IFile *> modifiedFiles() const;
 
     void blockFileChange(IFile *file);
     void unblockFileChange(IFile *file);
 
+    void expectFileChange(const QString &fileName);
+    void unexpectFileChange(const QString &fileName);
+
     // recent files
     void addToRecentFiles(const QString &fileName);
     QStringList recentFiles() const;
@@ -126,9 +128,14 @@ private slots:
     void syncWithEditor(Core::IContext *context);
 
 private:
+    void addFileInfo(IFile *file);
+    void removeFileInfo(IFile *file);
+    void removeFileInfo(const QString &fileName, IFile *file);
+
     void addWatch(const QString &filename);
     void removeWatch(const QString &filename);
     void updateFileInfo(IFile *file);
+    void updateExpectedState(const QString &fileName);
 
     QList<IFile *> saveModifiedFiles(const QList<IFile *> &files,
                                bool *cancelled, bool silently,
@@ -150,11 +157,8 @@ class CORE_EXPORT FileChangeBlocker
 public:
     FileChangeBlocker(const QString &fileName);
     ~FileChangeBlocker();
-    void setModifiedReload(bool reload);
-    bool modifiedReload() const;
 private:
-    QList<IFile *> m_files;
-    bool m_reload;
+    QString m_fileName;
     Q_DISABLE_COPY(FileChangeBlocker)
 };
 
diff --git a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp
index abd51592268..191e108437c 100644
--- a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp
+++ b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.cpp
@@ -187,12 +187,6 @@ bool FileManagerPrototype::isFileManaged(const QString &fileName) const
     return callee()->isFileManaged(fileName);
 }
 
-QList<Core::IFile *>
-FileManagerPrototype::managedFiles(const QString &fileName) const
-{
-    return callee()->managedFiles(fileName);
-}
-
 void FileManagerPrototype::blockFileChange(Core::IFile *file)
 {
     callee()->blockFileChange(file);
diff --git a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h
index 834a4e27c46..7028df13272 100644
--- a/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h
+++ b/src/plugins/coreplugin/scriptmanager/qworkbench_wrapper.h
@@ -117,7 +117,6 @@ public slots:
     QString getSaveAsFileName(Core::IFile *file);
 
     bool isFileManaged(const QString &fileName) const;
-    QList<Core::IFile *> managedFiles(const QString &fileName) const;
 
     void blockFileChange(Core::IFile *file);
     void unblockFileChange(Core::IFile *file);
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index ddb06bf1b09..b7d268da541 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -599,7 +599,6 @@ void CVSPlugin::revertCurrentFile()
     args << QLatin1String("update") << QLatin1String("-C") << state.relativeCurrentFile();
     const CVSResponse revertResponse = runCVS(state.currentFileTopLevel(), args, m_settings.timeOutMS(), true);
     if (revertResponse.result == CVSResponse::Ok) {
-        fcb.setModifiedReload(true);
         cvsVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
     }
 }
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index 1fe58493683..cdfd3a33879 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -490,7 +490,6 @@ void GitPlugin::undoFileChanges()
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return)
     Core::FileChangeBlocker fcb(state.currentFile());
-    fcb.setModifiedReload(true);
     m_gitClient->revert(QStringList(state.currentFile()));
 }
 
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index 8bf910188a1..548e8553fc3 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -495,7 +495,6 @@ void PerforcePlugin::revertCurrentFile()
         return;
 
     Core::FileChangeBlocker fcb(state.currentFile());
-    fcb.setModifiedReload(true);
     args.clear();
     args << QLatin1String("revert") << state.relativeCurrentFile();
     PerforceResponse result2 = runP4Cmd(state.currentFileTopLevel(), args,
diff --git a/src/plugins/qt4projectmanager/profileeditor.cpp b/src/plugins/qt4projectmanager/profileeditor.cpp
index 86a7f36bd7a..31d67295b0a 100644
--- a/src/plugins/qt4projectmanager/profileeditor.cpp
+++ b/src/plugins/qt4projectmanager/profileeditor.cpp
@@ -84,8 +84,7 @@ QString ProFileEditorEditable::id() const
 ProFileEditor::ProFileEditor(QWidget *parent, ProFileEditorFactory *factory, TextEditor::TextEditorActionHandler *ah)
     : BaseTextEditor(parent), m_factory(factory), m_ah(ah)
 {
-    Qt4Manager *manager = factory->qt4ProjectManager();
-    ProFileDocument *doc = new ProFileDocument(manager);
+    ProFileDocument *doc = new ProFileDocument();
     doc->setMimeType(QLatin1String(Qt4ProjectManager::Constants::PROFILE_MIMETYPE));
     setBaseTextDocument(doc);
 
@@ -126,20 +125,11 @@ void ProFileEditor::setFontSettings(const TextEditor::FontSettings &fs)
 // ProFileDocument
 //
 
-ProFileDocument::ProFileDocument(Qt4Manager *manager)
-        : TextEditor::BaseTextDocument(), m_manager(manager)
+ProFileDocument::ProFileDocument()
+        : TextEditor::BaseTextDocument()
 {
 }
 
-bool ProFileDocument::save(const QString &name)
-{
-    if (BaseTextDocument::save(name)) {
-        m_manager->notifyChanged(name);
-        return true;
-    }
-    return false;
-}
-
 QString ProFileDocument::defaultPath() const
 {
     QFileInfo fi(fileName());
diff --git a/src/plugins/qt4projectmanager/profileeditor.h b/src/plugins/qt4projectmanager/profileeditor.h
index 6756dc5b785..ee301fd13af 100644
--- a/src/plugins/qt4projectmanager/profileeditor.h
+++ b/src/plugins/qt4projectmanager/profileeditor.h
@@ -93,13 +93,9 @@ class ProFileDocument : public TextEditor::BaseTextDocument
     Q_OBJECT
 
 public:
-    ProFileDocument(Qt4Manager *manager);
-    bool save(const QString &name);
+    ProFileDocument();
     QString defaultPath() const;
     QString suggestedFileName() const;
-
-private:
-    Qt4Manager *m_manager;
 };
 
 } // namespace Internal
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index 95369b0fc28..ec7bc33b79a 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.cpp
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -226,8 +226,8 @@ Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, Qt4ProFileNode* qt4ProFileNo
           m_projectDir(QFileInfo(filePath).absolutePath())
 {
     Q_ASSERT(project);
-    Qt4PriFile *qt4PriFile = new Qt4PriFile(this);
-    Core::ICore::instance()->fileManager()->addFile(qt4PriFile);
+    m_qt4PriFile = new Qt4PriFile(this);
+    Core::ICore::instance()->fileManager()->addFile(m_qt4PriFile);
 
     setFolderName(QFileInfo(filePath).completeBaseName());
 
@@ -608,18 +608,13 @@ bool Qt4PriFileNode::priFileWritable(const QString &path)
     return true;
 }
 
-bool Qt4PriFileNode::saveModifiedEditors(const QString &path)
+bool Qt4PriFileNode::saveModifiedEditors()
 {
-    QList<Core::IFile*> allFileHandles;
     QList<Core::IFile*> modifiedFileHandles;
 
     Core::ICore *core = Core::ICore::instance();
 
-    foreach (Core::IFile *file, core->fileManager()->managedFiles(path)) {
-        allFileHandles << file;
-    }
-
-    foreach (Core::IEditor *editor, core->editorManager()->editorsForFileName(path)) {
+    foreach (Core::IEditor *editor, core->editorManager()->editorsForFileName(m_projectFilePath)) {
         if (Core::IFile *editorFile = editor->file()) {
             if (editorFile->isModified())
                 modifiedFileHandles << editorFile;
@@ -629,14 +624,12 @@ bool Qt4PriFileNode::saveModifiedEditors(const QString &path)
     if (!modifiedFileHandles.isEmpty()) {
         bool cancelled;
         core->fileManager()->saveModifiedFiles(modifiedFileHandles, &cancelled,
-                                         tr("There are unsaved changes for project file %1.").arg(path));
+                                         tr("There are unsaved changes for project file %1.").arg(m_projectFilePath));
         if (cancelled)
             return false;
-        // force instant reload
-        foreach (Core::IFile *fileHandle, allFileHandles) {
-            Core::IFile::ReloadBehavior reload = Core::IFile::ReloadAll;
-            fileHandle->modified(&reload);
-        }
+        // force instant reload of ourselves
+        ProFileCacheManager::instance()->discardFile(m_projectFilePath);
+        m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
     }
     return true;
 }
@@ -652,7 +645,7 @@ void Qt4PriFileNode::changeFiles(const FileType fileType,
     *notChanged = filePaths;
 
     // Check for modified editors
-    if (!saveModifiedEditors(m_projectFilePath))
+    if (!saveModifiedEditors())
         return;
 
     QStringList lines;
@@ -692,21 +685,23 @@ void Qt4PriFileNode::changeFiles(const FileType fileType,
     // save file
     save(lines);
 
+    // This is a hack
+    // We are savign twice in a very short timeframe, once the editor and once the ProFile
+    // So the modification time might not change between those two saves
+    // We manually tell each editor to reload it's file
+    // (The .pro files are notified by the file system watcher)
+    foreach (Core::IEditor *editor, Core::ICore::instance()->editorManager()->editorsForFileName(m_projectFilePath)) {
+        if (Core::IFile *editorFile = editor->file()) {
+            Core::IFile::ReloadBehavior b = Core::IFile::ReloadUnmodified;
+            editorFile->modified(&b);
+        }
+    }
+
     includeFile->deref();
 }
 
 void Qt4PriFileNode::save(const QStringList &lines)
 {
-    Core::ICore *core = Core::ICore::instance();
-    Core::FileManager *fileManager = core->fileManager();
-    QList<Core::IFile *> allFileHandles = fileManager->managedFiles(m_projectFilePath);
-    Core::IFile *modifiedFileHandle = 0;
-    foreach (Core::IFile *file, allFileHandles)
-        if (file->fileName() == m_projectFilePath)
-            modifiedFileHandle = file;
-
-    if (modifiedFileHandle)
-        fileManager->blockFileChange(modifiedFileHandle);
     QFile qfile(m_projectFilePath);
     if (qfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
         foreach (const QString &str, lines) {
@@ -715,14 +710,8 @@ void Qt4PriFileNode::save(const QStringList &lines)
         }
         qfile.close();
     }
-    m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
-    if (modifiedFileHandle)
-        fileManager->unblockFileChange(modifiedFileHandle);
 
-    Core::IFile::ReloadBehavior tempBehavior =
-            Core::IFile::ReloadAll;
-    foreach (Core::IFile *file, allFileHandles)
-        file->modified(&tempBehavior);
+    m_project->qt4ProjectManager()->notifyChanged(m_projectFilePath);
 }
 
 /*
diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h
index 0f7cf2fb0b5..4b2d673e890 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.h
+++ b/src/plugins/qt4projectmanager/qt4nodes.h
@@ -49,10 +49,6 @@ namespace Core {
 class ICore;
 }
 
-namespace ProjectExplorer {
-class FileWatcher;
-}
-
 namespace Designer {
 class FormWindowEditor;
 }
@@ -176,7 +172,7 @@ private slots:
 private:
     void save(const QStringList &lines);
     bool priFileWritable(const QString &path);
-    bool saveModifiedEditors(const QString &path);
+    bool saveModifiedEditors();
 
     Qt4Project *m_project;
     Qt4ProFileNode *m_qt4ProFileNode;
@@ -184,6 +180,7 @@ private:
     QString m_projectDir;
 
     QMap<QString, Qt4UiCodeModelSupport *> m_uiCodeModelSupport;
+    Qt4PriFile *m_qt4PriFile;
 
     // managed by Qt4ProFileNode
     friend class Qt4ProFileNode;
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 6354a2013de..f0f200d443f 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -634,7 +634,6 @@ void SubversionPlugin::revertCurrentFile()
 
     const SubversionResponse revertResponse = runSvn(state.currentFileTopLevel(), args, m_settings.timeOutMS(), true);
     if (!revertResponse.error) {
-        fcb.setModifiedReload(true);
         subVersionControl()->emitFilesChanged(QStringList(state.currentFile()));
     }
 }
-- 
GitLab