summaryrefslogtreecommitdiff
path: root/src/plugins/coreplugin
diff options
context:
space:
mode:
authorcon <qtc-committer@nokia.com>2010-11-23 12:47:45 +0100
committercon <qtc-committer@nokia.com>2010-11-30 13:10:03 +0100
commit14a71bc770641e28c8e960318791df4485ddb2c9 (patch)
tree6032f7770224110fda436c94688b03fe23bb952d /src/plugins/coreplugin
parent4b7d826daad17593b44a7c0a3925f6c7ec1e9d29 (diff)
downloadqt-creator-14a71bc770641e28c8e960318791df4485ddb2c9.tar.gz
Support symbolic links in the file manager.
We didn't watch the symbolic link itself before, only the final link target. We are watching the symbolic link and the final link target now. Ugly hack: We need to work around QTBUG-15522. The inotify and kqueue based file system watcher engines (Linux + Mac) don't report changes to symbolic links. The workaround is to use the polling engine *only for the links themselves*. The only way to force the use of the polling engine is by using the auto test hook in QFileSystemWatcher.
Diffstat (limited to 'src/plugins/coreplugin')
-rw-r--r--src/plugins/coreplugin/editormanager/editormanager.cpp4
-rw-r--r--src/plugins/coreplugin/filemanager.cpp530
-rw-r--r--src/plugins/coreplugin/filemanager.h11
3 files changed, 307 insertions, 238 deletions
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
index 15008a72cc..8e06c85175 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.cpp
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -578,9 +578,9 @@ Core::Internal::EditorView *EditorManager::currentEditorView() const
QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
{
QList<IEditor *> found;
- QString fixedname = FileManager::fixFileName(filename);
+ QString fixedname = FileManager::fixFileName(filename, FileManager::KeepLinks);
foreach (IEditor *editor, openedEditors()) {
- if (fixedname == FileManager::fixFileName(editor->file()->fileName()))
+ if (fixedname == FileManager::fixFileName(editor->file()->fileName(), FileManager::KeepLinks))
found << editor;
}
return found;
diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp
index ba9c520697..d7f18179d9 100644
--- a/src/plugins/coreplugin/filemanager.cpp
+++ b/src/plugins/coreplugin/filemanager.cpp
@@ -112,6 +112,7 @@ struct FileManagerPrivate {
QMap<QString, FileState> m_states;
QStringList m_changedFiles;
QList<IFile *> m_filesWithoutWatch;
+ QMap<IFile *, QStringList> m_filesWithWatch;
QStringList m_recentFiles;
static const int m_maxRecentFiles = 7;
@@ -120,6 +121,7 @@ struct FileManagerPrivate {
QMainWindow *m_mainWindow;
QFileSystemWatcher *m_fileWatcher;
+ QFileSystemWatcher *m_linkWatcher;
bool m_blockActivated;
QString m_lastVisitedDirectory;
QString m_projectsDirectory;
@@ -143,6 +145,16 @@ FileManagerPrivate::FileManagerPrivate(QObject *q, QMainWindow *mw) :
#endif
m_blockedIFile(0)
{
+ q->connect(m_fileWatcher, SIGNAL(fileChanged(QString)),
+ q, SLOT(changedFile(QString)));
+#ifdef Q_OS_UNIX
+ m_linkWatcher = new QFileSystemWatcher(q);
+ m_linkWatcher->setObjectName(QLatin1String("_qt_autotest_force_engine_poller"));
+ q->connect(m_linkWatcher, SIGNAL(fileChanged(QString)),
+ q, SLOT(changedFile(QString)));
+#else
+ m_linkWatcher = m_fileWatcher;
+#endif
}
} // namespace Internal
@@ -152,8 +164,6 @@ FileManager::FileManager(QMainWindow *mw)
d(new Internal::FileManagerPrivate(this, mw))
{
Core::ICore *core = Core::ICore::instance();
- connect(d->m_fileWatcher, SIGNAL(fileChanged(QString)),
- this, SLOT(changedFile(QString)));
connect(d->m_mainWindow, SIGNAL(windowActivated()),
this, SLOT(mainWindowActivated()));
connect(core, SIGNAL(contextChanged(Core::IContext*,Core::Context)),
@@ -173,148 +183,167 @@ FileManager::~FileManager()
Adds a list of IFile's to the collection. If \a addWatcher is true (the default),
the files are added to a file system watcher that notifies the file manager
about file changes.
-
- Returns true if the file specified by \a files have not been yet part of the file list.
*/
void FileManager::addFiles(const QList<IFile *> &files, bool addWatcher)
{
if (!addWatcher) {
// We keep those in a separate list
- foreach(IFile *file, files)
- connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
-
- d->m_filesWithoutWatch.append(files);
+ foreach(IFile *file, files) {
+ if (file && !d->m_filesWithoutWatch.contains(file)) {
+ connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
+ d->m_filesWithoutWatch.append(file);
+ }
+ }
return;
}
foreach (IFile *file, files) {
- 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 *)));
-
- addFileInfo(file);
+ if (file && !d->m_filesWithWatch.contains(file)) {
+ connect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
+ connect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
+ addFileInfo(file);
+ }
}
}
+/* Adds the IFile's file and possibly it's final link target to both m_states
+ (if it's file name is not empty), and the m_filesWithWatch list,
+ and adds a file watcher for each if not already done.
+ (The added file names are guaranteed to be absolute and cleaned.) */
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();
- }
+ const QString fixedName = fixFileName(file->fileName(), KeepLinks);
+ const QString fixedResolvedName = fixFileName(file->fileName(), ResolveLinks);
+ addFileInfo(fixedResolvedName, file, false);
+ if (fixedName != fixedResolvedName)
+ addFileInfo(fixedName, file, true);
+}
- if (!d->m_states.contains(fixedname)) {
- d->m_states.insert(fixedname, Internal::FileState());
- if (!fixedname.isEmpty()) {
- d->m_fileWatcher->addPath(fixedname);
+/* only called from addFileInfo(IFile *) */
+void FileManager::addFileInfo(const QString &fileName, IFile *file, bool isLink)
+{
+ Internal::FileStateItem state;
+ if (!fileName.isEmpty()) {
+ const QFileInfo fi(fileName);
+ state.modified = fi.lastModified();
+ state.permissions = fi.permissions();
+ // Add watcher if we don't have that already
+ if (!d->m_states.contains(fileName)) {
+ d->m_states.insert(fileName, Internal::FileState());
+
+ if (isLink)
+ d->m_linkWatcher->addPath(fileName);
+ else
+ d->m_fileWatcher->addPath(fileName);
}
+ d->m_states[fileName].lastUpdatedState.insert(file, state);
}
-
- d->m_states[fixedname].lastUpdatedState.insert(file, item);
+ d->m_filesWithWatch[file].append(fileName); // inserts a new QStringList if not already there
}
+/* Updates the time stamp and permission information of the files
+ registered for this IFile (in m_filesWithWatch; can be the IFile's file + final link target) */
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();
-
- if (d->m_states.contains(fixedname) && d->m_states.value(fixedname).lastUpdatedState.contains(file))
- d->m_states[fixedname].lastUpdatedState.insert(file, item);
+ foreach (const QString &fileName, d->m_filesWithWatch.value(file)) {
+ // If the filename is empty there's nothing to do
+ if (fileName.isEmpty())
+ continue;
+ const QFileInfo fi(fileName);
+ Internal::FileStateItem item;
+ item.modified = fi.lastModified();
+ item.permissions = fi.permissions();
+ QTC_ASSERT(d->m_states.contains(fileName), continue);
+ QTC_ASSERT(d->m_states.value(fileName).lastUpdatedState.contains(file), continue);
+ d->m_states[fileName].lastUpdatedState.insert(file, item);
+ }
}
/// Dumps the state of the file manager's map
/// For debugging purposes
void FileManager::dump()
{
+ qDebug() << "======== dumping state map";
QMap<QString, Internal::FileState>::const_iterator it, end;
it = d->m_states.constBegin();
end = d->m_states.constEnd();
for (; it != end; ++it) {
- qDebug()<<" ";
qDebug() << it.key();
- qDebug() << it.value().expected.modified;
+ qDebug() << " expected:" << it.value().expected.modified;
QMap<IFile *, Internal::FileStateItem>::const_iterator jt, jend;
jt = it.value().lastUpdatedState.constBegin();
jend = it.value().lastUpdatedState.constEnd();
for (; jt != jend; ++jt) {
- qDebug() << jt.key() << jt.value().modified;
+ qDebug() << " " << jt.key()->fileName() << jt.value().modified;
}
}
+ qDebug() << "------- dumping files with watch list";
+ foreach (IFile *key, d->m_filesWithWatch.keys()) {
+ qDebug() << key->fileName() << d->m_filesWithWatch.value(key);
+ }
+ qDebug() << "------- dumping watch list";
+ qDebug() << d->m_fileWatcher->files();
+ qDebug() << "------- dumping link watch list";
+ qDebug() << d->m_linkWatcher->files();
}
+/*!
+ \fn void FileManager::renamedFile(const QString &from, QString &to)
+ \brief Tells the file manager that a file has been renamed on disk from within Qt Creator.
+
+ Needs to be called right after the actual renaming on disk (i.e. before the file system
+ watcher can report the event during the next event loop run). \a from needs to be an absolute file path.
+ This will notify all IFile objects pointing to that file of the rename
+ by calling IFile::rename, and update the cached time and permission
+ information to avoid annoying the user with "file has been removed"
+ popups.
+*/
void FileManager::renamedFile(const QString &from, QString &to)
{
- QString fixedFrom = fixFileName(from);
- QString fixedTo = fixFileName(to);
- if (d->m_states.contains(fixedFrom)) {
- QTC_ASSERT(!d->m_states.contains(to), return);
- d->m_states.insert(fixedTo, d->m_states.value(fixedFrom));
- d->m_states.remove(fixedFrom);
- QFileInfo fi(to);
- d->m_states[fixedTo].expected.modified = fi.lastModified();
- d->m_states[fixedTo].expected.permissions = fi.permissions();
-
- d->m_fileWatcher->removePath(fixedFrom);
- d->m_fileWatcher->addPath(fixedTo);
-
- QMap<IFile *, Internal::FileStateItem>::iterator it, end;
- it = d->m_states[fixedTo].lastUpdatedState.begin();
- end = d->m_states[fixedTo].lastUpdatedState.end();
-
- for ( ; it != end; ++it) {
- d->m_blockedIFile = it.key();
- it.key()->rename(to);
- d->m_blockedIFile = it.key();
- it.value().modified = fi.lastModified();
- }
- }
-}
+ const QString &fixedFrom = fixFileName(from, KeepLinks);
-///
-/// Does not use file->fileName, as such is save to use
-/// with renamed files and deleted files
-void FileManager::removeFileInfo(IFile *file)
-{
- 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)) {
- removeFileInfo(it.key(), file);
- break;
- }
+ // gather the list of IFiles
+ QList<IFile *> filesToRename;
+ QMapIterator<IFile *, QStringList> it(d->m_filesWithWatch);
+ while (it.hasNext()) {
+ it.next();
+ if (it.value().contains(fixedFrom))
+ filesToRename.append(it.key());
}
+ // rename the IFiles
+ foreach (IFile *file, filesToRename) {
+ d->m_blockedIFile = file;
+ removeFileInfo(file);
+ file->rename(to);
+ addFileInfo(file);
+ d->m_blockedIFile = 0;
+ }
}
-/* only called from removeFileInfo(IFile*) */
-void FileManager::removeFileInfo(const QString &fileName, IFile *file)
+/* Removes all occurrances of the IFile from m_filesWithWatch and m_states.
+ If that results in a file no longer being referenced by any IFile, this
+ also removes the file watcher.
+*/
+void FileManager::removeFileInfo(IFile *file)
{
- QTC_ASSERT(d->m_states.value(fileName).lastUpdatedState.contains(file), return);
- d->m_states[fileName].lastUpdatedState.remove(file);
- if (d->m_states.value(fileName).lastUpdatedState.isEmpty()) {
- if (!fileName.isEmpty())
- d->m_fileWatcher->removePath(fileName);
- d->m_states.remove(fileName); // this deletes fileName
+ if (!d->m_filesWithWatch.contains(file))
+ return;
+ foreach (const QString &fileName, d->m_filesWithWatch.value(file)) {
+ if (!d->m_states.contains(fileName))
+ continue;
+ d->m_states[fileName].lastUpdatedState.remove(file);
+ if (d->m_states.value(fileName).lastUpdatedState.isEmpty()) {
+ if (d->m_fileWatcher->files().contains(fileName))
+ d->m_fileWatcher->removePath(fileName);
+ if (d->m_linkWatcher->files().contains(fileName))
+ d->m_linkWatcher->removePath(fileName);
+ d->m_states.remove(fileName);
+ }
}
+ d->m_filesWithWatch.remove(file);
}
/*!
@@ -323,8 +352,6 @@ void FileManager::removeFileInfo(const QString &fileName, IFile *file)
Adds a IFile object to the collection. If \a addWatcher is true (the default),
the file is added to a file system watcher that notifies the file manager
about file changes.
-
- Returns true if the file specified by \a file has not been yet part of the file list.
*/
void FileManager::addFile(IFile *file, bool addWatcher)
{
@@ -333,7 +360,6 @@ void FileManager::addFile(IFile *file, bool addWatcher)
void FileManager::fileDestroyed(QObject *obj)
{
- // removeFileInfo works even if the file does not really exist anymore
IFile *file = static_cast<IFile*>(obj);
// Check the special unwatched first:
if (d->m_filesWithoutWatch.contains(file)) {
@@ -352,8 +378,7 @@ void FileManager::fileDestroyed(QObject *obj)
*/
void FileManager::removeFile(IFile *file)
{
- if (!file)
- return;
+ QTC_ASSERT(file, return);
// Special casing unwatched files
if (d->m_filesWithoutWatch.contains(file)) {
@@ -362,12 +387,13 @@ void FileManager::removeFile(IFile *file)
return;
}
+ removeFileInfo(file);
disconnect(file, SIGNAL(changed()), this, SLOT(checkForNewFileName()));
disconnect(file, SIGNAL(destroyed(QObject *)), this, SLOT(fileDestroyed(QObject *)));
-
- removeFileInfo(file);
}
+/* Slot reacting on IFile::changed. We need to check if the signal was sent
+ because the file was saved under different name. */
void FileManager::checkForNewFileName()
{
IFile *file = qobject_cast<IFile *>(sender());
@@ -376,32 +402,33 @@ void FileManager::checkForNewFileName()
if (file == d->m_blockedIFile)
return;
QTC_ASSERT(file, return);
- const QString &fileName = fixFileName(file->fileName());
-
- // check if the IFile is in the map
- if (d->m_states.value(fileName).lastUpdatedState.contains(file)) {
- // 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;
- }
+ QTC_ASSERT(d->m_filesWithWatch.contains(file), return);
- // Probably the name has changed...
+ // Maybe the name has changed or file has been deleted and created again ...
// This also updates the state to the on disk state
removeFileInfo(file);
addFileInfo(file);
}
-// TODO Rename to nativeFileName
-QString FileManager::fixFileName(const QString &fileName)
+/*!
+ \fn QString FileManager::fixFileName(const QString &fileName, FixMode fixmode)
+ Returns a guaranteed cleaned path in native form. If the file exists,
+ it will either be a cleaned absolute file path (fixmode == KeepLinks), or
+ a cleaned canonical file path (fixmode == ResolveLinks).
+*/
+QString FileManager::fixFileName(const QString &fileName, FixMode fixmode)
{
QString s = fileName;
QFileInfo fi(s);
- if (!fi.exists())
- s = QDir::toNativeSeparators(s);
- else
- s = QDir::toNativeSeparators(fi.canonicalFilePath());
+ if (fi.exists()) {
+ if (fixmode == ResolveLinks)
+ s = fi.canonicalFilePath();
+ else
+ s = QDir::cleanPath(fi.absoluteFilePath());
+ } else {
+ s = QDir::cleanPath(s);
+ }
+ s = QDir::toNativeSeparators(s);
#ifdef Q_OS_WIN
s = s.toLower();
#endif
@@ -417,16 +444,11 @@ QList<IFile *> FileManager::modifiedFiles() const
{
QList<IFile *> modifiedFiles;
- 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).lastUpdatedState.constBegin();
- jend = (*it).lastUpdatedState.constEnd();
- for( ; jt != jend; ++jt)
- if (jt.key()->isModified())
- modifiedFiles << jt.key();
+ foreach (IFile *file, d->m_filesWithWatch.keys()) {
+ if (file->isModified())
+ modifiedFiles << file;
}
+
foreach(IFile *file, d->m_filesWithoutWatch) {
if (file->isModified())
modifiedFiles << file;
@@ -464,7 +486,8 @@ void FileManager::unblockFileChange(IFile *file)
// If so then it's a expected change
updateFileInfo(file);
- updateExpectedState(fixFileName(file->fileName()));
+ foreach (const QString &fileName, d->m_filesWithWatch.value(file))
+ updateExpectedState(fileName);
}
/*!
@@ -494,18 +517,24 @@ void FileManager::unexpectFileChange(const QString &fileName)
// is the same as the saved one here
// If so then it's a expected change
- updateExpectedState(fileName);
+ if (fileName.isEmpty())
+ return;
+ const QString fixedName = fixFileName(fileName, KeepLinks);
+ updateExpectedState(fixedName);
+ const QString fixedResolvedName = fixFileName(fileName, ResolveLinks);
+ if (fixedName != fixedResolvedName)
+ updateExpectedState(fixedResolvedName);
}
+/* only called from unblock and unexpect file change methods */
void FileManager::updateExpectedState(const QString &fileName)
{
- const QString &fixedName = fixFileName(fileName);
- if (fixedName.isEmpty())
+ if (fileName.isEmpty())
return;
- QFileInfo fi(fixedName);
- if (d->m_states.contains(fixedName)) {
- d->m_states[fixedName].expected.modified = fi.lastModified();
- d->m_states[fixedName].expected.permissions = fi.permissions();
+ if (d->m_states.contains(fileName)) {
+ QFileInfo fi(fileName);
+ d->m_states[fileName].expected.modified = fi.lastModified();
+ d->m_states[fileName].expected.permissions = fi.permissions();
}
}
@@ -769,9 +798,8 @@ void FileManager::changedFile(const QString &fileName)
{
const bool wasempty = d->m_changedFiles.isEmpty();
- const QString &fixedName = fixFileName(fileName);
- if (!d->m_changedFiles.contains(fixedName))
- d->m_changedFiles.append(fixedName);
+ if (!d->m_changedFiles.contains(fileName) && d->m_states.contains(fileName))
+ d->m_changedFiles.append(fileName);
if (wasempty && !d->m_changedFiles.isEmpty()) {
QTimer::singleShot(200, this, SLOT(checkForReload()));
@@ -788,6 +816,8 @@ void FileManager::mainWindowActivated()
void FileManager::checkForReload()
{
+ if (d->m_changedFiles.isEmpty())
+ return;
if (QApplication::activeWindow() != d->m_mainWindow)
return;
@@ -801,120 +831,154 @@ void FileManager::checkForReload()
QList<IEditor*> editorsToClose;
QMap<IFile*, QString> filesToSave;
- QStringList modifiedFileNames;
+
+ // collect file information
+ QMap<QString, Internal::FileStateItem> currentStates;
+ QMap<QString, IFile::ChangeType> changeTypes;
+ QSet<IFile *> changedIFiles;
foreach (const QString &fileName, d->m_changedFiles) {
- // Get the information from the filesystem
- IFile::ChangeTrigger behavior = IFile::TriggerExternal;
IFile::ChangeType type = IFile::TypeContents;
+ Internal::FileStateItem state;
QFileInfo fi(fileName);
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;
- }
+ state.modified = fi.lastModified();
+ state.permissions = fi.permissions();
}
+ currentStates.insert(fileName, state);
+ changeTypes.insert(fileName, type);
+ foreach (IFile *file, d->m_states.value(fileName).lastUpdatedState.keys())
+ changedIFiles.insert(file);
+ }
+
+ // handle the IFiles
+ foreach (IFile *file, changedIFiles) {
+ IFile::ChangeTrigger behavior = IFile::TriggerInternal;
+ IFile::ChangeType type = IFile::TypePermissions;
+ bool changed = false;
+ // find out the type & behavior from the two possible files
+ // behavior is internal if all changes are expected (and none removed)
+ // type is "max" of both types (remove > contents > permissions)
+ foreach (const QString & fileName, d->m_filesWithWatch.value(file)) {
+ // was the file reported?
+ if (!currentStates.contains(fileName))
+ continue;
- 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) {
- IFile *file = it.key();
- d->m_blockedIFile = file;
- // Compare
- if (it.value().modified == fi.lastModified()
- && it.value().permissions == fi.permissions()) {
- // Already up to date
+ Internal::FileStateItem currentState = currentStates.value(fileName);
+ Internal::FileStateItem expectedState = d->m_states.value(fileName).expected;
+ Internal::FileStateItem lastState = d->m_states.value(fileName).lastUpdatedState.value(file);
+ // did the file actually change?
+ if (lastState.modified == currentState.modified && lastState.permissions == currentState.permissions)
continue;
+ changed = true;
+
+ // was it only a permission change?
+ if (lastState.modified == currentState.modified)
+ continue;
+
+ // was the change unexpected?
+ if (currentState.modified != expectedState.modified || currentState.permissions != expectedState.permissions) {
+ behavior = IFile::TriggerExternal;
}
- // 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)
+
+ // find out the type
+ IFile::ChangeType fileChange = changeTypes.value(fileName);
+ if (fileChange == IFile::TypeRemoved) {
+ type = IFile::TypeRemoved;
+ behavior = IFile::TriggerExternal; // removed files always trigger externally
+ } else if (fileChange == IFile::TypeContents && type == IFile::TypePermissions) {
+ type = IFile::TypeContents;
+ }
+ }
+
+ if (!changed) // probably because the change was blocked with (un)blockFileChange
+ continue;
+
+ // handle it!
+ d->m_blockedIFile = file;
+
+ // we've got some modification
+ // check if it's contents or permissions:
+ if (type == IFile::TypePermissions) {
+ // 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 {
+ // 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);
- // 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 {
- // 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
+ // 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 {
+ // Ask about content change
+ previousAnswer = Utils::reloadPrompt(file->fileName(), file->isModified(), QApplication::activeWindow());
+ switch (previousAnswer) {
+ case Utils::ReloadAll:
+ case Utils::ReloadCurrent:
file->reload(IFile::FlagReload, IFile::TypeContents);
- } else {
- // 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;
- }
+ 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);
+ }
+ // IFile wants us to ask, and it's the TypeRemoved case
+ } else {
+ // Ask about removed file
+ bool unhandled = true;
+ while (unhandled) {
+ switch (Utils::fileDeletedPrompt(file->fileName(), QApplication::activeWindow())) {
+ case Utils::FileDeletedSave:
+ filesToSave.insert(file, file->fileName());
+ unhandled = false;
+ break;
+ case Utils::FileDeletedSaveAs:
+ {
+ const QString &saveFileName = getSaveAsFileName(file);
+ if (!saveFileName.isEmpty()) {
+ filesToSave.insert(file, saveFileName);
unhandled = false;
- break;
}
+ break;
+ }
+ case Utils::FileDeletedClose:
+ editorsToClose << EditorManager::instance()->editorsForFile(file);
+ unhandled = false;
+ break;
}
}
}
-
- updateFileInfo(file);
- d->m_blockedIFile = 0;
}
- }
- // cleanup
- if (!modifiedFileNames.isEmpty()) {
- d->m_fileWatcher->removePaths(modifiedFileNames);
- d->m_fileWatcher->addPaths(modifiedFileNames);
+ // update file info, also handling if e.g. link target has changed
+ removeFileInfo(file);
+ addFileInfo(file);
+ d->m_blockedIFile = 0;
}
+
+ // clean up
d->m_changedFiles.clear();
// handle deleted files
@@ -929,6 +993,8 @@ void FileManager::checkForReload()
}
d->m_blockActivated = false;
+
+// dump();
}
void FileManager::syncWithEditor(Core::IContext *context)
@@ -951,10 +1017,10 @@ void FileManager::addToRecentFiles(const QString &fileName)
{
if (fileName.isEmpty())
return;
- QString unifiedForm(fixFileName(fileName));
+ QString unifiedForm(fixFileName(fileName, KeepLinks));
QMutableStringListIterator it(d->m_recentFiles);
while (it.hasNext()) {
- QString recentUnifiedForm(fixFileName(it.next()));
+ QString recentUnifiedForm(fixFileName(it.next(), KeepLinks));
if (unifiedForm == recentUnifiedForm)
it.remove();
}
diff --git a/src/plugins/coreplugin/filemanager.h b/src/plugins/coreplugin/filemanager.h
index c6e827e3c1..5db7453282 100644
--- a/src/plugins/coreplugin/filemanager.h
+++ b/src/plugins/coreplugin/filemanager.h
@@ -53,6 +53,11 @@ class CORE_EXPORT FileManager : public QObject
{
Q_OBJECT
public:
+ enum FixMode {
+ ResolveLinks,
+ KeepLinks
+ };
+
explicit FileManager(QMainWindow *ew);
virtual ~FileManager();
@@ -80,7 +85,7 @@ public:
QString currentFile() const;
// helper methods
- static QString fixFileName(const QString &fileName);
+ static QString fixFileName(const QString &fileName, FixMode fixmode);
QStringList getOpenFileNames(const QString &filters,
const QString path = QString(),
@@ -134,11 +139,9 @@ private:
void readSettings();
void dump();
void addFileInfo(IFile *file);
+ void addFileInfo(const QString &fileName, IFile *file, bool isLink);
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);