diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/coreplugin/editormanager/editormanager.cpp | 4 | ||||
-rw-r--r-- | src/plugins/coreplugin/filemanager.cpp | 530 | ||||
-rw-r--r-- | src/plugins/coreplugin/filemanager.h | 11 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectexplorer.cpp | 2 |
4 files changed, 308 insertions, 239 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); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 027e399155..8ac905e9ce 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2262,7 +2262,7 @@ void ProjectExplorerPlugin::renameFile(Node *node, const QString &to) FileNode *fileNode = qobject_cast<FileNode *>(node); if (!fileNode) return; - QString orgFilePath = node->path(); + QString orgFilePath = QFileInfo(node->path()).absoluteFilePath(); QString dir = QFileInfo(orgFilePath).absolutePath(); QString newFilePath = dir + "/" + to; Core::ICore *core = Core::ICore::instance(); |