From d6061a23e16bfa1f76cf9a153d3d5a923bb0fa59 Mon Sep 17 00:00:00 2001
From: con <qtc-committer@nokia.com>
Date: Fri, 19 Mar 2010 10:28:05 +0100
Subject: [PATCH] Refactor the externally modified file handling

Reviewed-by: dt
---
 src/libs/utils/reloadpromptutils.cpp          |  28 +++-
 src/libs/utils/reloadpromptutils.h            |   4 +
 src/plugins/bineditor/bineditorplugin.cpp     |  48 ++----
 src/plugins/bineditor/imageviewer.cpp         |  41 ++----
 src/plugins/bineditor/imageviewer.h           |   3 +-
 .../cmakeprojectmanager/cmakeproject.cpp      |  12 +-
 .../cmakeprojectmanager/cmakeproject.h        |   4 +-
 .../editormanager/editormanager.cpp           |  19 ++-
 .../coreplugin/editormanager/editormanager.h  |   4 +-
 src/plugins/coreplugin/filemanager.cpp        | 139 ++++++++++++++----
 src/plugins/coreplugin/generalsettings.cpp    |   4 +-
 src/plugins/coreplugin/generalsettings.ui     |   6 +-
 src/plugins/coreplugin/ifile.h                |  32 +++-
 src/plugins/designer/formwindowfile.cpp       |  47 ++----
 src/plugins/designer/formwindowfile.h         |   3 +-
 .../genericprojectmanager/genericproject.cpp  |  11 +-
 .../genericprojectmanager/genericproject.h    |   3 +-
 src/plugins/projectexplorer/session.cpp       |  14 +-
 .../qmlprojectmanager/qmlprojectfile.cpp      |  11 +-
 .../qmlprojectmanager/qmlprojectfile.h        |   3 +-
 src/plugins/qt4projectmanager/qt4nodes.cpp    |  18 ++-
 src/plugins/qt4projectmanager/qt4nodes.h      |   3 +-
 src/plugins/qt4projectmanager/qt4project.cpp  |  11 +-
 src/plugins/qt4projectmanager/qt4project.h    |   3 +-
 .../resourceeditor/resourceeditorw.cpp        |  48 ++----
 src/plugins/resourceeditor/resourceeditorw.h  |   3 +-
 src/plugins/texteditor/basetextdocument.cpp   |  46 ++----
 src/plugins/texteditor/basetextdocument.h     |   3 +-
 src/plugins/vcsbase/submiteditorfile.cpp      |  13 ++
 src/plugins/vcsbase/submiteditorfile.h        |   4 +-
 30 files changed, 365 insertions(+), 223 deletions(-)

diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp
index 2ef1689c73e..23678a9a418 100644
--- a/src/libs/utils/reloadpromptutils.cpp
+++ b/src/libs/utils/reloadpromptutils.cpp
@@ -29,9 +29,11 @@
 
 #include "reloadpromptutils.h"
 
-#include <QtGui/QMessageBox>
 #include <QtCore/QCoreApplication>
 #include <QtCore/QDir>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+#include <QtGui/QAbstractButton>
 
 using namespace Utils;
 
@@ -68,3 +70,27 @@ QTCREATOR_UTILS_EXPORT Utils::ReloadPromptAnswer
     }
     return ReloadNone;
 }
+
+QTCREATOR_UTILS_EXPORT Utils::FileDeletedPromptAnswer
+        Utils::fileDeletedPrompt(const QString &fileName, QWidget *parent)
+{
+    const QString title = QCoreApplication::translate("Utils::fileDeletedPrompt", "File has been removed");
+    QString msg;
+     msg = QCoreApplication::translate("Utils::fileDeletedPrompt",
+                                      "The file %1 has been removed outside Qt Creator. Do you want to save it under a different name, or close the editor?").arg(QDir::toNativeSeparators(fileName));
+    QMessageBox box(QMessageBox::Question, title, msg, QMessageBox::NoButton, parent);
+    QPushButton *close = box.addButton(QCoreApplication::translate("Utils::fileDeletedPrompt", "Close"), QMessageBox::RejectRole);
+    QPushButton *saveas = box.addButton(QCoreApplication::translate("Utils::fileDeletedPrompt", "Save as..."), QMessageBox::ActionRole);
+    QPushButton *save = box.addButton(QCoreApplication::translate("Utils::fileDeletedPrompt", "Save"), QMessageBox::AcceptRole);
+    box.setDefaultButton(saveas);
+    box.exec();
+    QAbstractButton *clickedbutton = box.clickedButton();
+    if (clickedbutton == close) {
+        return FileDeletedClose;
+    } else if (clickedbutton == saveas) {
+        return FileDeletedSaveAs;
+    } else if (clickedbutton == save) {
+        return FileDeletedSave;
+    }
+    return FileDeletedClose;
+}
diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h
index 72da183fc98..8f0d3ad258c 100644
--- a/src/libs/utils/reloadpromptutils.h
+++ b/src/libs/utils/reloadpromptutils.h
@@ -44,6 +44,10 @@ enum ReloadPromptAnswer { ReloadCurrent, ReloadAll, ReloadSkipCurrent, ReloadNon
 QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName, bool modified, QWidget *parent);
 QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, QWidget *parent);
 
+enum FileDeletedPromptAnswer { FileDeletedClose, FileDeletedSaveAs, FileDeletedSave };
+
+QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer fileDeletedPrompt(const QString &fileName, QWidget *parent);
+
 } // namespace Utils
 
 #endif // RELOADPROMPTUTILS_H
diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp
index 012ac0bccd6..432df20a97a 100644
--- a/src/plugins/bineditor/bineditorplugin.cpp
+++ b/src/plugins/bineditor/bineditorplugin.cpp
@@ -47,6 +47,7 @@
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/editormanager/ieditor.h>
 #include <coreplugin/icore.h>
+#include <coreplugin/ifile.h>
 #include <coreplugin/mimedatabase.h>
 #include <coreplugin/uniqueidmanager.h>
 #include <extensionsystem/pluginmanager.h>
@@ -251,41 +252,24 @@ public:
 
     bool isSaveAsAllowed() const { return true; }
 
-    void modified(ReloadBehavior *behavior) {
-        const QString fileName = m_fileName;
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const {
+        if (type == TypePermissions)
+            return BehaviorSilent;
+        if (type == TypeContents) {
+            if (state == TriggerInternal && !isModified())
+                return BehaviorSilent;
+            return BehaviorAsk;
+        }
+        return BehaviorAsk;
+    }
 
-        switch (*behavior) {
-        case  Core::IFile::ReloadNone:
-            return;
-        case Core::IFile::ReloadUnmodified:
-            if (!isModified()) {
-                open(fileName);
-                return;
-            }
-            break;
-        case Core::IFile::ReloadAll:
-            open(fileName);
+    void reload(ReloadFlag flag, ChangeType type) {
+        if (flag == FlagIgnore)
             return;
-        case Core::IFile::ReloadPermissions:
+        if (type == TypePermissions) {
             emit changed();
-            return;
-        case Core::IFile::AskForReload:
-            break;
-        }
-
-        switch (Utils::reloadPrompt(fileName, isModified(), Core::ICore::instance()->mainWindow())) {
-        case Utils::ReloadCurrent:
-            open(fileName);
-            break;
-        case Utils::ReloadAll:
-            open(fileName);
-            *behavior = Core::IFile::ReloadAll;
-            break;
-        case Utils::ReloadSkipCurrent:
-            break;
-        case Utils::ReloadNone:
-            *behavior = Core::IFile::ReloadNone;
-            break;
+        } else {
+            open(m_fileName);
         }
     }
 
diff --git a/src/plugins/bineditor/imageviewer.cpp b/src/plugins/bineditor/imageviewer.cpp
index f465d5b8056..94adaef5876 100644
--- a/src/plugins/bineditor/imageviewer.cpp
+++ b/src/plugins/bineditor/imageviewer.cpp
@@ -114,34 +114,25 @@ ImageViewerFile::ImageViewerFile(ImageViewer *parent)
 
 }
 
-void ImageViewerFile::modified(ReloadBehavior * behavior)
+Core::IFile::ReloadBehavior ImageViewerFile::reloadBehavior(Core::IFile::ChangeTrigger state,
+                                                            Core::IFile::ChangeType type) const
 {
-    switch (*behavior) {
-    case  Core::IFile::ReloadNone:
-        return;
-    case Core::IFile::ReloadUnmodified:
-    case Core::IFile::ReloadAll:
-        m_editor->open(m_fileName);
-        return;
-    case Core::IFile::ReloadPermissions:
-        return;
-    case Core::IFile::AskForReload:
-        break;
-    }
+    if (type == TypePermissions)
+        return BehaviorSilent;
+    if (type == TypeContents && state == TriggerInternal)
+        return BehaviorSilent;
+    return BehaviorAsk;
+}
 
-    switch (Utils::reloadPrompt(m_fileName, isModified(), Core::ICore::instance()->mainWindow())) {
-    case Utils::ReloadCurrent:
-        m_editor->open(m_fileName);
-        break;
-    case Utils::ReloadAll:
+void ImageViewerFile::reload(Core::IFile::ReloadFlag flag,
+                             Core::IFile::ChangeType type)
+{
+    if (flag == FlagIgnore)
+        return;
+    if (type == TypePermissions) {
+        emit changed();
+    } else {
         m_editor->open(m_fileName);
-        *behavior = Core::IFile::ReloadAll;
-        break;
-    case Utils::ReloadSkipCurrent:
-        break;
-    case Utils::ReloadNone:
-        *behavior = Core::IFile::ReloadNone;
-        break;
     }
 }
 
diff --git a/src/plugins/bineditor/imageviewer.h b/src/plugins/bineditor/imageviewer.h
index c7cdbd81b5c..edaa9d86d37 100644
--- a/src/plugins/bineditor/imageviewer.h
+++ b/src/plugins/bineditor/imageviewer.h
@@ -80,7 +80,8 @@ public:
     bool isReadOnly() const { return true; }
     bool isSaveAsAllowed() const { return false; }
 
-    void modified(ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
     void checkPermissions() {}
 
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
index b4304bb60a0..0ef66e8f20e 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp
@@ -598,9 +598,17 @@ bool CMakeFile::isSaveAsAllowed() const
     return false;
 }
 
-void CMakeFile::modified(ReloadBehavior *behavior)
+Core::IFile::ReloadBehavior CMakeFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
-    Q_UNUSED(behavior)
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void CMakeFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
 }
 
 CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeProject *project)
diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h
index 3f4a148abf8..62612c0f7c7 100644
--- a/src/plugins/cmakeprojectmanager/cmakeproject.h
+++ b/src/plugins/cmakeprojectmanager/cmakeproject.h
@@ -193,7 +193,9 @@ public:
     bool isReadOnly() const;
     bool isSaveAsAllowed() const;
 
-    void modified(ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
+
 private:
     CMakeProject *m_project;
     QString m_fileName;
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
index 1242e4d4285..d78c62913a9 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.cpp
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -214,7 +214,7 @@ struct EditorManagerPrivate {
     OpenEditorsModel *m_editorModel;
     QString m_externalEditor;
 
-    IFile::ReloadBehavior m_reloadBehavior;
+    IFile::ReloadSetting m_reloadSetting;
 };
 }
 
@@ -235,7 +235,7 @@ EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
     m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)),
     m_windowPopup(0),
     m_coreListener(0),
-    m_reloadBehavior(IFile::AskForReload)
+    m_reloadSetting(IFile::AlwaysAsk)
 {
     m_editorModel = new OpenEditorsModel(parent);
 }
@@ -1716,7 +1716,7 @@ void EditorManager::saveSettings()
     SettingsDatabase *settings = m_d->m_core->settingsDatabase();
     settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates);
     settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor);
-    settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadBehavior);
+    settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadSetting);
 }
 
 void EditorManager::readSettings()
@@ -1741,7 +1741,7 @@ void EditorManager::readSettings()
         m_d->m_externalEditor = settings->value(QLatin1String(externalEditorKey)).toString();
 
     if (settings->contains(QLatin1String(reloadBehaviorKey)))
-        m_d->m_reloadBehavior = (IFile::ReloadBehavior)settings->value(QLatin1String(reloadBehaviorKey)).toInt();
+        m_d->m_reloadSetting = (IFile::ReloadSetting)settings->value(QLatin1String(reloadBehaviorKey)).toInt();
 }
 
 
@@ -1765,8 +1765,7 @@ void EditorManager::revertToSaved()
             return;
 
     }
-    IFile::ReloadBehavior temp = IFile::ReloadAll;
-    currEditor->file()->modified(&temp);
+    currEditor->file()->reload(IFile::FlagReload, IFile::TypeContents);
 }
 
 void EditorManager::showEditorInfoBar(const QString &id,
@@ -1899,14 +1898,14 @@ QString EditorManager::externalEditor() const
     return m_d->m_externalEditor;
 }
 
-void EditorManager::setReloadBehavior(IFile::ReloadBehavior behavior)
+void EditorManager::setReloadSetting(IFile::ReloadSetting behavior)
 {
-    m_d->m_reloadBehavior = behavior;
+    m_d->m_reloadSetting = behavior;
 }
 
-IFile::ReloadBehavior EditorManager::reloadBehavior() const
+IFile::ReloadSetting EditorManager::reloadSetting() const
 {
-    return m_d->m_reloadBehavior;
+    return m_d->m_reloadSetting;
 }
 
 Core::IEditor *EditorManager::duplicateEditor(Core::IEditor *editor)
diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h
index f3deeb6812e..a762364f6cc 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.h
+++ b/src/plugins/coreplugin/editormanager/editormanager.h
@@ -185,8 +185,8 @@ public:
     QString defaultExternalEditor() const;
     QString externalEditorHelpText() const;
 
-    void setReloadBehavior(IFile::ReloadBehavior behavior);
-    IFile::ReloadBehavior reloadBehavior() const;
+    void setReloadSetting(IFile::ReloadSetting behavior);
+    IFile::ReloadSetting reloadSetting() const;
 
     // Helper to display a message dialog when encountering a read-only
     // file, prompting the user about how to make it writeable.
diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp
index cc8068cd10f..d3f6a0b6eda 100644
--- a/src/plugins/coreplugin/filemanager.cpp
+++ b/src/plugins/coreplugin/filemanager.cpp
@@ -40,6 +40,7 @@
 
 #include <utils/qtcassert.h>
 #include <utils/pathchooser.h>
+#include <utils/reloadpromptutils.h>
 
 #include <QtCore/QSettings>
 #include <QtCore/QFileInfo>
@@ -227,8 +228,9 @@ void FileManager::addFileInfo(IFile *file)
 
     if (!d->m_states.contains(fixedname)) {
         d->m_states.insert(fixedname, Internal::FileState());
-        if (!fixedname.isEmpty())
+        if (!fixedname.isEmpty()) {
             d->m_fileWatcher->addPath(fixedname);
+        }
     }
 
     d->m_states[fixedname].lastUpdatedState.insert(file, item);
@@ -278,8 +280,9 @@ void FileManager::removeFileInfo(const QString &fileName, IFile *file)
 
     if (d->m_states.value(fixedName).lastUpdatedState.isEmpty()) {
         d->m_states.remove(fixedName);
-        if (!fixedName.isEmpty())
+        if (!fixedName.isEmpty()) {
             d->m_fileWatcher->removePath(fixedName);
+        }
     }
 }
 
@@ -341,7 +344,9 @@ void FileManager::checkForNewFileName()
 
     // check if the IFile is in the map
     if (d->m_states.value(fileName).lastUpdatedState.contains(file)) {
-        // Should checkForNewFileName also call updateFileInfo if the name didn't change?
+        // the file might have been deleted and written again, so guard against that
+        d->m_fileWatcher->removePath(fileName);
+        d->m_fileWatcher->addPath(fileName);
         updateFileInfo(file);
         return;
     }
@@ -718,17 +723,25 @@ void FileManager::checkForReload()
 
     d->m_blockActivated = true;
 
-    IFile::ReloadBehavior behavior = EditorManager::instance()->reloadBehavior();
+    IFile::ReloadSetting defaultBehavior = EditorManager::instance()->reloadSetting();
+    Utils::ReloadPromptAnswer previousAnswer = Utils::ReloadCurrent;
 
-    QStringList allFileNames;
-    foreach(const QString &fileName, d->m_changedFiles) {
-        allFileNames << fileName;
+    QList<IEditor*> editorsToClose;
+    QMap<IFile*, QString> filesToSave;
+    QStringList modifiedFileNames;
+    foreach (const QString &fileName, d->m_changedFiles) {
         // Get the information from the filesystem
+        IFile::ChangeTrigger behavior = IFile::TriggerExternal;
+        IFile::ChangeType type = IFile::TypeContents;
         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;
+        if (!fi.exists()) {
+            type = IFile::TypeRemoved;
+        } else {
+            modifiedFileNames << fileName;
+            if (fi.lastModified() == d->m_states.value(fileName).expected.modified
+                && fi.permissions() == d->m_states.value(fileName).expected.permissions) {
+                behavior = IFile::TriggerInternal;
+            }
         }
 
         const QMap<IFile *, Internal::FileStateItem> &lastUpdated =
@@ -736,35 +749,109 @@ void FileManager::checkForReload()
         QMap<IFile *, Internal::FileStateItem>::const_iterator it, end;
         it = lastUpdated.constBegin();
         end = lastUpdated.constEnd();
-
         for ( ; it != end; ++it) {
+            IFile *file = it.key();
             // Compare
             if (it.value().modified == fi.lastModified()
                 && it.value().permissions == fi.permissions()) {
                 // Already up to date
+                continue;
+            }
+            // we've got some modification
+            // check if it's contents or permissions:
+            if (it.value().modified == fi.lastModified()) {
+                // Only permission change
+                file->reload(IFile::FlagReload, IFile::TypePermissions);
+            // now we know it's a content change or file was removed
+            } else if (defaultBehavior == IFile::ReloadUnmodified
+                       && type == IFile::TypeContents && !file->isModified()) {
+                // content change, but unmodified (and settings say to reload in this case)
+                file->reload(IFile::FlagReload, type);
+            // file was removed or it's a content change and the default behavior for
+            // unmodified files didn't kick in
+            } else if (defaultBehavior == IFile::IgnoreAll) {
+                // content change or removed, but settings say ignore
+                file->reload(IFile::FlagIgnore, type);
+            // either the default behavior is to always ask,
+            // or the ReloadUnmodified default behavior didn't kick in,
+            // so do whatever the IFile wants us to do
             } 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);
+                // check if IFile wants us to ask
+                if (file->reloadBehavior(behavior, type) == IFile::BehaviorSilent) {
+                    // content change or removed, IFile wants silent handling
+                    file->reload(IFile::FlagReload, type);
+                // IFile wants us to ask
+                } else if (type == IFile::TypeContents) {
+                    // content change, IFile wants to ask user
+                    if (previousAnswer == Utils::ReloadNone) {
+                        // answer already given, ignore
+                        file->reload(IFile::FlagIgnore, IFile::TypeContents);
+                    } else if (previousAnswer == Utils::ReloadAll) {
+                        // answer already given, reload
+                        file->reload(IFile::FlagReload, IFile::TypeContents);
                     } else {
-                        it.key()->modified(&behavior);
+                        // Ask about content change
+                        previousAnswer = Utils::reloadPrompt(fileName, file->isModified(), QApplication::activeWindow());
+                        switch (previousAnswer) {
+                        case Utils::ReloadAll:
+                        case Utils::ReloadCurrent:
+                            file->reload(IFile::FlagReload, IFile::TypeContents);
+                            break;
+                        case Utils::ReloadSkipCurrent:
+                        case Utils::ReloadNone:
+                            file->reload(IFile::FlagIgnore, IFile::TypeContents);
+                            break;
+                        }
+                    }
+                // IFile wants us to ask, and it's the TypeRemoved case
+                } else {
+                    // Ask about removed file
+                    bool unhandled = true;
+                    while (unhandled) {
+                        switch (Utils::fileDeletedPrompt(fileName, QApplication::activeWindow())) {
+                        case Utils::FileDeletedSave:
+                            filesToSave.insert(file, fileName);
+                            unhandled = false;
+                            break;
+                        case Utils::FileDeletedSaveAs:
+                            {
+                                const QString &saveFileName = getSaveAsFileName(file);
+                                if (!saveFileName.isEmpty()) {
+                                    filesToSave.insert(file, saveFileName);
+                                    unhandled = false;
+                                }
+                                break;
+                            }
+                        case Utils::FileDeletedClose:
+                            editorsToClose << EditorManager::instance()->editorsForFile(file);
+                            unhandled = false;
+                            break;
+                        }
                     }
                 }
-                updateFileInfo(it.key());
             }
+
+            updateFileInfo(file);
         }
     }
-    if (!allFileNames.isEmpty()) {
-        d->m_fileWatcher->removePaths(allFileNames);
-        d->m_fileWatcher->addPaths(allFileNames);
+
+    // cleanup
+    if (!modifiedFileNames.isEmpty()) {
+        d->m_fileWatcher->removePaths(modifiedFileNames);
+        d->m_fileWatcher->addPaths(modifiedFileNames);
     }
     d->m_changedFiles.clear();
+
+    // handle deleted files
+    EditorManager::instance()->closeEditors(editorsToClose, false);
+    QMapIterator<IFile *, QString> it(filesToSave);
+    while (it.hasNext()) {
+        it.next();
+        blockFileChange(it.key());
+        it.key()->save(it.value());
+        unblockFileChange(it.key());
+    }
+
     d->m_blockActivated = false;
 }
 
diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp
index 8abfe9a36bd..da2c7d59c70 100644
--- a/src/plugins/coreplugin/generalsettings.cpp
+++ b/src/plugins/coreplugin/generalsettings.cpp
@@ -124,7 +124,7 @@ QWidget *GeneralSettings::createPage(QWidget *parent)
     fillLanguageBox();
     m_page->colorButton->setColor(StyleHelper::requestedBaseColor());
     m_page->externalEditorEdit->setText(EditorManager::instance()->externalEditor());
-    m_page->reloadBehavior->setCurrentIndex(EditorManager::instance()->reloadBehavior());
+    m_page->reloadBehavior->setCurrentIndex(EditorManager::instance()->reloadSetting());
 #ifdef Q_OS_UNIX
     m_page->terminalEdit->setText(ConsoleProcess::terminalEmulator(settings));
 #else
@@ -182,7 +182,7 @@ void GeneralSettings::apply()
     // Apply the new base color if accepted
     StyleHelper::setBaseColor(m_page->colorButton->color());
     EditorManager::instance()->setExternalEditor(m_page->externalEditorEdit->text());
-    EditorManager::instance()->setReloadBehavior(IFile::ReloadBehavior(m_page->reloadBehavior->currentIndex()));
+    EditorManager::instance()->setReloadSetting(IFile::ReloadSetting(m_page->reloadBehavior->currentIndex()));
 #ifdef Q_OS_UNIX
 	ConsoleProcess::setTerminalEmulator(Core::ICore::instance()->settings(),
                                         m_page->terminalEdit->text());
diff --git a/src/plugins/coreplugin/generalsettings.ui b/src/plugins/coreplugin/generalsettings.ui
index 18d9dd2d0be..a143b0eddd2 100644
--- a/src/plugins/coreplugin/generalsettings.ui
+++ b/src/plugins/coreplugin/generalsettings.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>487</width>
-    <height>319</height>
+    <width>492</width>
+    <height>339</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
@@ -234,7 +234,7 @@
           </item>
           <item>
            <property name="text">
-            <string>Reload all modified files</string>
+            <string>Reload all unmodified files</string>
            </property>
           </item>
           <item>
diff --git a/src/plugins/coreplugin/ifile.h b/src/plugins/coreplugin/ifile.h
index 59d37bf49d9..575cac9488c 100644
--- a/src/plugins/coreplugin/ifile.h
+++ b/src/plugins/coreplugin/ifile.h
@@ -44,12 +44,31 @@ class CORE_EXPORT IFile : public QObject
 public:
     // This enum must match the indexes of the reloadBehavior widget
     // in generalsettings.ui
-    enum ReloadBehavior {
-        AskForReload = 0,
+    enum ReloadSetting {
+        AlwaysAsk = 0,
         ReloadUnmodified = 1,
-        ReloadNone = 2,
-        ReloadAll,
-        ReloadPermissions
+        IgnoreAll = 2
+    };
+
+    enum ChangeTrigger {
+        TriggerInternal,
+        TriggerExternal
+    };
+
+    enum ChangeType {
+        TypeContents,
+        TypePermissions,
+        TypeRemoved
+    };
+
+    enum ReloadBehavior {
+        BehaviorAsk,
+        BehaviorSilent
+    };
+
+    enum ReloadFlag {
+        FlagReload,
+        FlagIgnore
     };
 
     IFile(QObject *parent = 0) : QObject(parent) {}
@@ -66,7 +85,8 @@ public:
     virtual bool isReadOnly() const = 0;
     virtual bool isSaveAsAllowed() const = 0;
 
-    virtual void modified(ReloadBehavior *behavior) = 0;
+    virtual ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const = 0;
+    virtual void reload(ReloadFlag flag, ChangeType type) = 0;
 
     virtual void checkPermissions() {}
 
diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp
index 6851d5ed934..e95e4b92be2 100644
--- a/src/plugins/designer/formwindowfile.cpp
+++ b/src/plugins/designer/formwindowfile.cpp
@@ -111,43 +111,26 @@ bool FormWindowFile::isSaveAsAllowed() const
     return true;
 }
 
-void FormWindowFile::modified(Core::IFile::ReloadBehavior *behavior)
+Core::IFile::ReloadBehavior FormWindowFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
-    if (Designer::Constants::Internal::debug)
-        qDebug() << Q_FUNC_INFO << m_fileName << *behavior;
+    if (type == TypePermissions)
+        return BehaviorSilent;
+    if (type == TypeContents) {
+        if (state == TriggerInternal && !isModified())
+            return BehaviorSilent;
+        return BehaviorAsk;
+    }
+    return BehaviorAsk;
+}
 
-    switch (*behavior) {
-    case  Core::IFile::ReloadNone:
-        return;
-    case Core::IFile::ReloadUnmodified:
-        if (!isModified()) {
-            reload(m_fileName);
-            return;
-        }
-        break;
-    case Core::IFile::ReloadAll:
-        emit reload(m_fileName);
+void FormWindowFile::reload(ReloadFlag flag, ChangeType type)
+{
+    if (flag == FlagIgnore)
         return;
-    case Core::IFile::ReloadPermissions:
+    if (type == TypePermissions) {
         emit changed();
-        return;
-    case Core::IFile::AskForReload:
-        break;
-    }
-
-    switch (Utils::reloadPrompt(m_fileName, isModified(), Core::ICore::instance()->mainWindow())) {
-    case Utils::ReloadCurrent:
-        emit reload(m_fileName);
-        break;
-    case Utils::ReloadAll:
+    } else {
         emit reload(m_fileName);
-        *behavior = Core::IFile::ReloadAll;
-        break;
-    case Utils::ReloadSkipCurrent:
-        break;
-    case Utils::ReloadNone:
-        *behavior = Core::IFile::ReloadNone;
-        break;
     }
 }
 
diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h
index 5c08cc8b732..5ac62ac4f04 100644
--- a/src/plugins/designer/formwindowfile.h
+++ b/src/plugins/designer/formwindowfile.h
@@ -55,7 +55,8 @@ public:
     virtual bool isModified() const;
     virtual bool isReadOnly() const;
     virtual bool isSaveAsAllowed() const;
-    virtual void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
     virtual QString defaultPath() const;
     virtual QString suggestedFileName() const;
     virtual QString mimeType() const;
diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp
index ffbfa386304..88af20a68fe 100644
--- a/src/plugins/genericprojectmanager/genericproject.cpp
+++ b/src/plugins/genericprojectmanager/genericproject.cpp
@@ -579,6 +579,15 @@ bool GenericProjectFile::isSaveAsAllowed() const
     return false;
 }
 
-void GenericProjectFile::modified(ReloadBehavior *)
+Core::IFile::ReloadBehavior GenericProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void GenericProjectFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
 }
diff --git a/src/plugins/genericprojectmanager/genericproject.h b/src/plugins/genericprojectmanager/genericproject.h
index 1d44268c8fd..124ae9f1449 100644
--- a/src/plugins/genericprojectmanager/genericproject.h
+++ b/src/plugins/genericprojectmanager/genericproject.h
@@ -163,7 +163,8 @@ public:
     virtual bool isReadOnly() const;
     virtual bool isSaveAsAllowed() const;
 
-    virtual void modified(ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
 private:
     GenericProject *m_project;
diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp
index 54618da9b24..2f2c7340f76 100644
--- a/src/plugins/projectexplorer/session.cpp
+++ b/src/plugins/projectexplorer/session.cpp
@@ -89,7 +89,8 @@ public:
     bool isReadOnly() const;
     bool isSaveAsAllowed() const;
 
-    void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
 public slots:
     void sessionLoadingProgress();
@@ -320,8 +321,17 @@ bool SessionFile::isSaveAsAllowed() const
     return true;
 }
 
-void SessionFile::modified(Core::IFile::ReloadBehavior *)
+Core::IFile::ReloadBehavior SessionFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void SessionFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
 }
 
 QString SessionFile::defaultPath() const
diff --git a/src/plugins/qmlprojectmanager/qmlprojectfile.cpp b/src/plugins/qmlprojectmanager/qmlprojectfile.cpp
index 17c8681a0dd..3bc827879f2 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectfile.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectfile.cpp
@@ -83,8 +83,17 @@ bool QmlProjectFile::isSaveAsAllowed() const
     return false;
 }
 
-void QmlProjectFile::modified(ReloadBehavior *)
+Core::IFile::ReloadBehavior QmlProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void QmlProjectFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
 }
 
 } // namespace Internal
diff --git a/src/plugins/qmlprojectmanager/qmlprojectfile.h b/src/plugins/qmlprojectmanager/qmlprojectfile.h
index 81a54c89cb0..b01c4f76bd8 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectfile.h
+++ b/src/plugins/qmlprojectmanager/qmlprojectfile.h
@@ -57,7 +57,8 @@ public:
     virtual bool isReadOnly() const;
     virtual bool isSaveAsAllowed() const;
 
-    virtual void modified(ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
 private:
     QmlProject *m_project;
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index c13141e2bc0..fc705baeaed 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.cpp
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -207,12 +207,21 @@ bool Qt4PriFile::isSaveAsAllowed() const
     return false;
 }
 
-void Qt4PriFile::modified(Core::IFile::ReloadBehavior *behavior)
+Core::IFile::ReloadBehavior Qt4PriFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
-    Q_UNUSED(behavior);
-    m_priFile->scheduleUpdate();
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
 }
 
+void Qt4PriFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
+    if (type == TypePermissions)
+        return;
+    m_priFile->scheduleUpdate();
+}
 
 /*!
   \class Qt4PriFileNode
@@ -725,8 +734,7 @@ void Qt4PriFileNode::changeFiles(const FileType fileType,
     // (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);
+            editorFile->reload(Core::IFile::FlagReload, Core::IFile::TypeContents);
         }
     }
 
diff --git a/src/plugins/qt4projectmanager/qt4nodes.h b/src/plugins/qt4projectmanager/qt4nodes.h
index ea9216a617d..c48de9d0c7c 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.h
+++ b/src/plugins/qt4projectmanager/qt4nodes.h
@@ -113,7 +113,8 @@ public:
     virtual bool isReadOnly() const;
     virtual bool isSaveAsAllowed() const;
 
-    virtual void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
 private:
     Qt4PriFileNode *m_priFile;
diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp
index ae7ea1e62c8..536080086f5 100644
--- a/src/plugins/qt4projectmanager/qt4project.cpp
+++ b/src/plugins/qt4projectmanager/qt4project.cpp
@@ -216,8 +216,17 @@ bool Qt4ProjectFile::isSaveAsAllowed() const
     return false;
 }
 
-void Qt4ProjectFile::modified(Core::IFile::ReloadBehavior *)
+Core::IFile::ReloadBehavior Qt4ProjectFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void Qt4ProjectFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
 }
 
 /*!
diff --git a/src/plugins/qt4projectmanager/qt4project.h b/src/plugins/qt4projectmanager/qt4project.h
index 02f540bfaa5..0d85df22920 100644
--- a/src/plugins/qt4projectmanager/qt4project.h
+++ b/src/plugins/qt4projectmanager/qt4project.h
@@ -97,7 +97,8 @@ public:
     bool isReadOnly() const;
     bool isSaveAsAllowed() const;
 
-    void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
 
 private:
     const QString m_mimeType;
diff --git a/src/plugins/resourceeditor/resourceeditorw.cpp b/src/plugins/resourceeditor/resourceeditorw.cpp
index df993a58fa7..7fde0e20aef 100644
--- a/src/plugins/resourceeditor/resourceeditorw.cpp
+++ b/src/plugins/resourceeditor/resourceeditorw.cpp
@@ -185,42 +185,26 @@ bool ResourceEditorFile::isSaveAsAllowed() const
     return true;
 }
 
-void ResourceEditorFile::modified(Core::IFile::ReloadBehavior *behavior)
+Core::IFile::ReloadBehavior ResourceEditorFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
-    const QString fileName = m_parent->m_resourceEditor->fileName();
+    if (type == TypePermissions)
+        return BehaviorSilent;
+    if (type == TypeContents) {
+        if (state == TriggerInternal && !isModified())
+            return BehaviorSilent;
+        return BehaviorAsk;
+    }
+    return BehaviorAsk;
+}
 
-    switch (*behavior) {
-    case Core::IFile::ReloadNone:
-        return;
-    case Core::IFile::ReloadUnmodified:
-        if (!isModified()) {
-            m_parent->open(fileName);
-            return;
-        }
-        break;
-    case Core::IFile::ReloadAll:
-        m_parent->open(fileName);
+void ResourceEditorFile::reload(ReloadFlag flag, ChangeType type)
+{
+    if (flag == FlagIgnore)
         return;
-    case Core::IFile::ReloadPermissions:
+    if (type == TypePermissions) {
         emit changed();
-        return;
-    case Core::IFile::AskForReload:
-        break;
-    }
-
-    switch (Utils::reloadPrompt(fileName, isModified(), Core::ICore::instance()->mainWindow())) {
-    case Utils::ReloadCurrent:
-        m_parent->open(fileName);
-        break;
-    case Utils::ReloadAll:
-        m_parent->open(fileName);
-        *behavior = Core::IFile::ReloadAll;
-        break;
-    case Utils::ReloadSkipCurrent:
-        break;
-    case Utils::ReloadNone:
-        *behavior = Core::IFile::ReloadNone;
-        break;
+    } else {
+        m_parent->open(m_parent->m_resourceEditor->fileName());
     }
 }
 
diff --git a/src/plugins/resourceeditor/resourceeditorw.h b/src/plugins/resourceeditor/resourceeditorw.h
index f8b275d6ef0..e0a2e5f7b24 100644
--- a/src/plugins/resourceeditor/resourceeditorw.h
+++ b/src/plugins/resourceeditor/resourceeditorw.h
@@ -62,7 +62,8 @@ public:
     bool isModified() const;
     bool isReadOnly() const;
     bool isSaveAsAllowed() const;
-    void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
     QString defaultPath() const;
     QString suggestedFileName() const;
     virtual QString mimeType() const;
diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp
index 70997f5b024..e0377677407 100644
--- a/src/plugins/texteditor/basetextdocument.cpp
+++ b/src/plugins/texteditor/basetextdocument.cpp
@@ -248,40 +248,26 @@ void BaseTextDocument::reload()
         emit reloaded();
 }
 
-void BaseTextDocument::modified(Core::IFile::ReloadBehavior *behavior)
+Core::IFile::ReloadBehavior BaseTextDocument::reloadBehavior(ChangeTrigger state, ChangeType type) const
 {
-    switch (*behavior) {
-    case Core::IFile::ReloadNone:
-        return;
-    case Core::IFile::ReloadUnmodified:
-        if (!isModified()) {
-            reload();
-            return;
-        }
-        break;
-    case Core::IFile::ReloadAll:
-        reload();
-        return;
-    case Core::IFile::ReloadPermissions:
-        emit changed();
-        return;
-    case Core::IFile::AskForReload:
-        break;
+    if (type == TypePermissions)
+        return BehaviorSilent;
+    if (type == TypeContents) {
+        if (state == TriggerInternal && !isModified())
+            return BehaviorSilent;
+        return BehaviorAsk;
     }
+    return BehaviorAsk;
+}
 
-    switch (Utils::reloadPrompt(m_fileName, isModified(), QApplication::activeWindow())) {
-    case Utils::ReloadCurrent:
-        reload();
-        break;
-    case Utils::ReloadAll:
+void BaseTextDocument::reload(ReloadFlag flag, ChangeType type)
+{
+    if (flag == FlagIgnore)
+        return;
+    if (type == TypePermissions) {
+        emit changed();
+    } else {
         reload();
-        *behavior = Core::IFile::ReloadAll;
-        break;
-    case Utils::ReloadSkipCurrent:
-        break;
-    case Utils::ReloadNone:
-        *behavior = Core::IFile::ReloadNone;
-        break;
     }
 }
 
diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h
index 2b7852991d3..2958fc3805b 100644
--- a/src/plugins/texteditor/basetextdocument.h
+++ b/src/plugins/texteditor/basetextdocument.h
@@ -85,7 +85,8 @@ public:
     virtual bool isModified() const;
     virtual bool isSaveAsAllowed() const { return true; }
     virtual void checkPermissions();
-    virtual void modified(Core::IFile::ReloadBehavior *behavior);
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
     virtual QString mimeType() const;
     void setMimeType(const QString &mt);
 
diff --git a/src/plugins/vcsbase/submiteditorfile.cpp b/src/plugins/vcsbase/submiteditorfile.cpp
index a181256a39c..949e30c0d93 100644
--- a/src/plugins/vcsbase/submiteditorfile.cpp
+++ b/src/plugins/vcsbase/submiteditorfile.cpp
@@ -64,3 +64,16 @@ QString SubmitEditorFile::mimeType() const
 {
     return m_mimeType;
 }
+
+Core::IFile::ReloadBehavior SubmitEditorFile::reloadBehavior(ChangeTrigger state, ChangeType type) const
+{
+    Q_UNUSED(state)
+    Q_UNUSED(type)
+    return BehaviorSilent;
+}
+
+void SubmitEditorFile::reload(ReloadFlag flag, ChangeType type)
+{
+    Q_UNUSED(flag)
+    Q_UNUSED(type)
+}
diff --git a/src/plugins/vcsbase/submiteditorfile.h b/src/plugins/vcsbase/submiteditorfile.h
index 5e89ff53371..e5c489c8b53 100644
--- a/src/plugins/vcsbase/submiteditorfile.h
+++ b/src/plugins/vcsbase/submiteditorfile.h
@@ -52,7 +52,9 @@ public:
     bool isReadOnly() const { return false; }
     bool isSaveAsAllowed() const { return false; }
     bool save(const QString &fileName);
-    void modified(ReloadBehavior * /*behavior*/) { return; }
+    ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const;
+    void reload(ReloadFlag flag, ChangeType type);
+
 
     void setFileName(const QString name);
     void setModified(bool modified = true);
-- 
GitLab