forked from qt-creator/qt-creator
Core: filepathify documentmanager guts
Change-Id: I2e01adb0fec592fd8401b60015e8a0464d3c8e4d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Eike Ziller <eike.ziller@qt.io> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -155,7 +155,7 @@ struct FileStateItem
|
|||||||
|
|
||||||
struct FileState
|
struct FileState
|
||||||
{
|
{
|
||||||
QString watchedFilePath;
|
FilePath watchedFilePath;
|
||||||
QMap<IDocument *, FileStateItem> lastUpdatedState;
|
QMap<IDocument *, FileStateItem> lastUpdatedState;
|
||||||
FileStateItem expected;
|
FileStateItem expected;
|
||||||
};
|
};
|
||||||
@@ -174,11 +174,11 @@ public:
|
|||||||
|
|
||||||
void registerSaveAllAction();
|
void registerSaveAllAction();
|
||||||
|
|
||||||
QMap<QString, FileState> m_states; // filePathKey -> FileState
|
QMap<FilePath, FileState> m_states; // filePathKey -> FileState
|
||||||
QSet<QString> m_changedFiles; // watched file paths collected from file watcher notifications
|
QSet<FilePath> m_changedFiles; // watched file paths collected from file watcher notifications
|
||||||
QList<IDocument *> m_documentsWithoutWatch;
|
QList<IDocument *> m_documentsWithoutWatch;
|
||||||
QMap<IDocument *, QStringList> m_documentsWithWatch; // document -> list of filePathKeys
|
QMap<IDocument *, FilePaths> m_documentsWithWatch; // document -> list of filePathKeys
|
||||||
QSet<Utils::FilePath> m_expectedFileNames; // set of file paths without normalization
|
QSet<FilePath> m_expectedFileNames; // set of file paths without normalization
|
||||||
|
|
||||||
QList<DocumentManager::RecentFile> m_recentFiles;
|
QList<DocumentManager::RecentFile> m_recentFiles;
|
||||||
|
|
||||||
@@ -303,14 +303,13 @@ DocumentManager *DocumentManager::instance()
|
|||||||
|
|
||||||
/* Only called from addFileInfo(IDocument *). Adds the document & state to various caches/lists,
|
/* Only called from addFileInfo(IDocument *). Adds the document & state to various caches/lists,
|
||||||
but does not actually add a watcher. */
|
but does not actually add a watcher. */
|
||||||
static void addFileInfo(IDocument *document, const QString &filePath, const QString &filePathKey)
|
static void addFileInfo(IDocument *document, const FilePath &filePath, const FilePath &filePathKey)
|
||||||
{
|
{
|
||||||
FileStateItem state;
|
FileStateItem state;
|
||||||
if (!filePath.isEmpty()) {
|
if (!filePath.isEmpty()) {
|
||||||
qCDebug(log) << "adding document for" << filePath << "(" << filePathKey << ")";
|
qCDebug(log) << "adding document for" << filePath << "(" << filePathKey << ")";
|
||||||
const QFileInfo fi(filePath);
|
state.modified = filePath.lastModified();
|
||||||
state.modified = fi.lastModified();
|
state.permissions = filePath.permissions();
|
||||||
state.permissions = fi.permissions();
|
|
||||||
// Add state if we don't have already
|
// Add state if we don't have already
|
||||||
if (!d->m_states.contains(filePathKey)) {
|
if (!d->m_states.contains(filePathKey)) {
|
||||||
FileState state;
|
FileState state;
|
||||||
@@ -328,27 +327,22 @@ static void addFileInfo(IDocument *document, const QString &filePath, const QStr
|
|||||||
(The added file names are guaranteed to be absolute and cleaned.) */
|
(The added file names are guaranteed to be absolute and cleaned.) */
|
||||||
static void addFileInfos(const QList<IDocument *> &documents)
|
static void addFileInfos(const QList<IDocument *> &documents)
|
||||||
{
|
{
|
||||||
QStringList pathsToWatch;
|
FilePaths pathsToWatch;
|
||||||
QStringList linkPathsToWatch;
|
FilePaths linkPathsToWatch;
|
||||||
for (IDocument *document : documents) {
|
for (IDocument *document : documents) {
|
||||||
const QString documentFilePath = document->filePath().toString();
|
const FilePath filePath = DocumentManager::filePathKey(document->filePath(),
|
||||||
const QString filePath = DocumentManager::cleanAbsoluteFilePath(documentFilePath,
|
|
||||||
DocumentManager::KeepLinks);
|
DocumentManager::KeepLinks);
|
||||||
const QString filePathKey = DocumentManager::filePathKey(documentFilePath,
|
const FilePath resolvedFilePath = filePath.canonicalPath();
|
||||||
DocumentManager::KeepLinks);
|
|
||||||
const QString resolvedFilePath
|
|
||||||
= DocumentManager::cleanAbsoluteFilePath(documentFilePath,
|
|
||||||
DocumentManager::ResolveLinks);
|
|
||||||
const QString resolvedFilePathKey
|
|
||||||
= DocumentManager::filePathKey(documentFilePath, DocumentManager::ResolveLinks);
|
|
||||||
const bool isLink = filePath != resolvedFilePath;
|
const bool isLink = filePath != resolvedFilePath;
|
||||||
addFileInfo(document, filePath, filePathKey);
|
addFileInfo(document, filePath, filePath);
|
||||||
if (isLink) {
|
if (isLink) {
|
||||||
addFileInfo(document, resolvedFilePath, resolvedFilePathKey);
|
addFileInfo(document, resolvedFilePath, resolvedFilePath);
|
||||||
linkPathsToWatch.append(d->m_states.value(filePathKey).watchedFilePath);
|
if (!filePath.needsDevice()) {
|
||||||
pathsToWatch.append(d->m_states.value(resolvedFilePathKey).watchedFilePath);
|
linkPathsToWatch.append(d->m_states.value(filePath).watchedFilePath);
|
||||||
} else {
|
pathsToWatch.append(d->m_states.value(resolvedFilePath).watchedFilePath);
|
||||||
pathsToWatch.append(d->m_states.value(filePathKey).watchedFilePath);
|
}
|
||||||
|
} else if (!filePath.needsDevice()) {
|
||||||
|
pathsToWatch.append(d->m_states.value(filePath).watchedFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add or update watcher on file path
|
// Add or update watcher on file path
|
||||||
@@ -356,11 +350,11 @@ static void addFileInfos(const QList<IDocument *> &documents)
|
|||||||
// update link targets, even if there are multiple documents registered for it
|
// update link targets, even if there are multiple documents registered for it
|
||||||
if (!pathsToWatch.isEmpty()) {
|
if (!pathsToWatch.isEmpty()) {
|
||||||
qCDebug(log) << "adding full watch for" << pathsToWatch;
|
qCDebug(log) << "adding full watch for" << pathsToWatch;
|
||||||
d->fileWatcher()->addPaths(pathsToWatch);
|
d->fileWatcher()->addPaths(Utils::transform(pathsToWatch, &FilePath::toString));
|
||||||
}
|
}
|
||||||
if (!linkPathsToWatch.isEmpty()) {
|
if (!linkPathsToWatch.isEmpty()) {
|
||||||
qCDebug(log) << "adding link watch for" << linkPathsToWatch;
|
qCDebug(log) << "adding link watch for" << linkPathsToWatch;
|
||||||
d->linkWatcher()->addPaths(linkPathsToWatch);
|
d->linkWatcher()->addPaths(Utils::transform(linkPathsToWatch, &FilePath::toString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,22 +403,27 @@ static void removeFileInfo(IDocument *document)
|
|||||||
{
|
{
|
||||||
if (!d->m_documentsWithWatch.contains(document))
|
if (!d->m_documentsWithWatch.contains(document))
|
||||||
return;
|
return;
|
||||||
foreach (const QString &fileName, d->m_documentsWithWatch.value(document)) {
|
foreach (const FilePath &filePath, d->m_documentsWithWatch.value(document)) {
|
||||||
if (!d->m_states.contains(fileName))
|
if (!d->m_states.contains(filePath))
|
||||||
continue;
|
continue;
|
||||||
qCDebug(log) << "removing document (" << fileName << ")";
|
qCDebug(log) << "removing document (" << filePath << ")";
|
||||||
d->m_states[fileName].lastUpdatedState.remove(document);
|
d->m_states[filePath].lastUpdatedState.remove(document);
|
||||||
if (d->m_states.value(fileName).lastUpdatedState.isEmpty()) {
|
if (d->m_states.value(filePath).lastUpdatedState.isEmpty()) {
|
||||||
const QString &watchedFilePath = d->m_states.value(fileName).watchedFilePath;
|
const FilePath &watchedFilePath = d->m_states.value(filePath).watchedFilePath;
|
||||||
if (d->m_fileWatcher && d->m_fileWatcher->files().contains(watchedFilePath)) {
|
if (!watchedFilePath.needsDevice()) {
|
||||||
qCDebug(log) << "removing watch for" << watchedFilePath;
|
const QString &localFilePath = watchedFilePath.path();
|
||||||
d->m_fileWatcher->removePath(watchedFilePath);
|
if (d->m_fileWatcher
|
||||||
|
&& d->m_fileWatcher->files().contains(localFilePath)) {
|
||||||
|
qCDebug(log) << "removing watch for" << localFilePath;
|
||||||
|
d->m_fileWatcher->removePath(localFilePath);
|
||||||
}
|
}
|
||||||
if (d->m_linkWatcher && d->m_linkWatcher->files().contains(watchedFilePath)) {
|
if (d->m_linkWatcher
|
||||||
qCDebug(log) << "removing watch for" << watchedFilePath;
|
&& d->m_linkWatcher->files().contains(localFilePath)) {
|
||||||
d->m_linkWatcher->removePath(watchedFilePath);
|
qCDebug(log) << "removing watch for" << localFilePath;
|
||||||
|
d->m_linkWatcher->removePath(localFilePath);
|
||||||
}
|
}
|
||||||
d->m_states.remove(fileName);
|
}
|
||||||
|
d->m_states.remove(filePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d->m_documentsWithWatch.remove(document);
|
d->m_documentsWithWatch.remove(document);
|
||||||
@@ -484,7 +483,7 @@ void DocumentManager::renamedFile(const Utils::FilePath &from, const Utils::File
|
|||||||
QList<IDocument *> documentsToRename;
|
QList<IDocument *> documentsToRename;
|
||||||
for (auto it = d->m_documentsWithWatch.cbegin(), end = d->m_documentsWithWatch.cend();
|
for (auto it = d->m_documentsWithWatch.cbegin(), end = d->m_documentsWithWatch.cend();
|
||||||
it != end; ++it) {
|
it != end; ++it) {
|
||||||
if (it.value().contains(fromKey.toString()))
|
if (it.value().contains(fromKey))
|
||||||
documentsToRename.append(it.key());
|
documentsToRename.append(it.key());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,14 +641,14 @@ void DocumentManager::expectFileChange(const Utils::FilePath &filePath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* only called from unblock and unexpect file change functions */
|
/* only called from unblock and unexpect file change functions */
|
||||||
static void updateExpectedState(const QString &filePathKey)
|
static void updateExpectedState(const FilePath &filePathKey)
|
||||||
{
|
{
|
||||||
if (filePathKey.isEmpty())
|
if (filePathKey.isEmpty())
|
||||||
return;
|
return;
|
||||||
if (d->m_states.contains(filePathKey)) {
|
if (d->m_states.contains(filePathKey)) {
|
||||||
QFileInfo fi(d->m_states.value(filePathKey).watchedFilePath);
|
const FilePath watched = d->m_states.value(filePathKey).watchedFilePath;
|
||||||
d->m_states[filePathKey].expected.modified = fi.lastModified();
|
d->m_states[filePathKey].expected.modified = watched.lastModified();
|
||||||
d->m_states[filePathKey].expected.permissions = fi.permissions();
|
d->m_states[filePathKey].expected.permissions = watched.permissions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,12 +667,11 @@ void DocumentManager::unexpectFileChange(const FilePath &filePath)
|
|||||||
if (filePath.isEmpty())
|
if (filePath.isEmpty())
|
||||||
return;
|
return;
|
||||||
d->m_expectedFileNames.remove(filePath);
|
d->m_expectedFileNames.remove(filePath);
|
||||||
const QString &fileName = filePath.toString();
|
const FilePath cleanAbsFilePath = filePathKey(filePath, KeepLinks);
|
||||||
const QString cleanAbsFilePath = cleanAbsoluteFilePath(fileName, KeepLinks);
|
updateExpectedState(filePathKey(filePath, KeepLinks));
|
||||||
updateExpectedState(filePathKey(fileName, KeepLinks));
|
const FilePath resolvedCleanAbsFilePath = cleanAbsFilePath.canonicalPath();
|
||||||
const QString resolvedCleanAbsFilePath = cleanAbsoluteFilePath(fileName, ResolveLinks);
|
|
||||||
if (cleanAbsFilePath != resolvedCleanAbsFilePath)
|
if (cleanAbsFilePath != resolvedCleanAbsFilePath)
|
||||||
updateExpectedState(filePathKey(fileName, ResolveLinks));
|
updateExpectedState(filePathKey(filePath, ResolveLinks));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
|
static bool saveModifiedFilesHelper(const QList<IDocument *> &documents,
|
||||||
@@ -1076,11 +1074,12 @@ QStringList DocumentManager::getOpenFileNames(const QString &filters,
|
|||||||
|
|
||||||
void DocumentManager::changedFile(const QString &fileName)
|
void DocumentManager::changedFile(const QString &fileName)
|
||||||
{
|
{
|
||||||
|
const FilePath filePath = FilePath::fromString(fileName);
|
||||||
const bool wasempty = d->m_changedFiles.isEmpty();
|
const bool wasempty = d->m_changedFiles.isEmpty();
|
||||||
|
|
||||||
if (d->m_states.contains(filePathKey(fileName, KeepLinks)))
|
if (d->m_states.contains(filePathKey(filePath, KeepLinks)))
|
||||||
d->m_changedFiles.insert(fileName);
|
d->m_changedFiles.insert(filePath);
|
||||||
qCDebug(log) << "file change notification for" << fileName;
|
qCDebug(log) << "file change notification for" << filePath;
|
||||||
|
|
||||||
if (wasempty && !d->m_changedFiles.isEmpty())
|
if (wasempty && !d->m_changedFiles.isEmpty())
|
||||||
QTimer::singleShot(200, this, &DocumentManager::checkForReload);
|
QTimer::singleShot(200, this, &DocumentManager::checkForReload);
|
||||||
@@ -1116,21 +1115,20 @@ void DocumentManager::checkForReload()
|
|||||||
QHash<IDocument*, QString> documentsToSave;
|
QHash<IDocument*, QString> documentsToSave;
|
||||||
|
|
||||||
// collect file information
|
// collect file information
|
||||||
QMap<QString, FileStateItem> currentStates;
|
QMap<FilePath, FileStateItem> currentStates;
|
||||||
QMap<QString, IDocument::ChangeType> changeTypes;
|
QMap<FilePath, IDocument::ChangeType> changeTypes;
|
||||||
QSet<IDocument *> changedIDocuments;
|
QSet<IDocument *> changedIDocuments;
|
||||||
foreach (const QString &fileName, d->m_changedFiles) {
|
foreach (const FilePath &filePath, d->m_changedFiles) {
|
||||||
const QString fileKey = filePathKey(fileName, KeepLinks);
|
const FilePath fileKey = filePathKey(filePath, KeepLinks);
|
||||||
qCDebug(log) << "handling file change for" << fileName << "(" << fileKey << ")";
|
qCDebug(log) << "handling file change for" << filePath << "(" << fileKey << ")";
|
||||||
IDocument::ChangeType type = IDocument::TypeContents;
|
IDocument::ChangeType type = IDocument::TypeContents;
|
||||||
FileStateItem state;
|
FileStateItem state;
|
||||||
QFileInfo fi(fileName);
|
if (!filePath.exists()) {
|
||||||
if (!fi.exists()) {
|
|
||||||
qCDebug(log) << "file was removed";
|
qCDebug(log) << "file was removed";
|
||||||
type = IDocument::TypeRemoved;
|
type = IDocument::TypeRemoved;
|
||||||
} else {
|
} else {
|
||||||
state.modified = fi.lastModified();
|
state.modified = filePath.lastModified();
|
||||||
state.permissions = fi.permissions();
|
state.permissions = filePath.permissions();
|
||||||
qCDebug(log) << "file was modified, time:" << state.modified
|
qCDebug(log) << "file was modified, time:" << state.modified
|
||||||
<< "permissions: " << state.permissions;
|
<< "permissions: " << state.permissions;
|
||||||
}
|
}
|
||||||
@@ -1148,14 +1146,13 @@ void DocumentManager::checkForReload()
|
|||||||
// we can't do the "resolving" already in expectFileChange, because
|
// we can't do the "resolving" already in expectFileChange, because
|
||||||
// if the resolved names are different when unexpectFileChange is called
|
// if the resolved names are different when unexpectFileChange is called
|
||||||
// we would end up with never-unexpected file names
|
// we would end up with never-unexpected file names
|
||||||
QSet<QString> expectedFileKeys;
|
QSet<FilePath> expectedFileKeys;
|
||||||
foreach (const Utils::FilePath &filePath, d->m_expectedFileNames) {
|
foreach (const FilePath &filePath, d->m_expectedFileNames) {
|
||||||
const QString &fileName = filePath.toString();
|
const FilePath cleanAbsFilePath = filePathKey(filePath, KeepLinks);
|
||||||
const QString cleanAbsFilePath = cleanAbsoluteFilePath(fileName, KeepLinks);
|
expectedFileKeys.insert(filePathKey(filePath, KeepLinks));
|
||||||
expectedFileKeys.insert(filePathKey(fileName, KeepLinks));
|
const FilePath resolvedCleanAbsFilePath = cleanAbsFilePath.canonicalPath();
|
||||||
const QString resolvedCleanAbsFilePath = cleanAbsoluteFilePath(fileName, ResolveLinks);
|
|
||||||
if (cleanAbsFilePath != resolvedCleanAbsFilePath)
|
if (cleanAbsFilePath != resolvedCleanAbsFilePath)
|
||||||
expectedFileKeys.insert(filePathKey(fileName, ResolveLinks));
|
expectedFileKeys.insert(filePathKey(filePath, ResolveLinks));
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the IDocuments
|
// handle the IDocuments
|
||||||
@@ -1168,7 +1165,7 @@ void DocumentManager::checkForReload()
|
|||||||
// find out the type & behavior from the two possible files
|
// find out the type & behavior from the two possible files
|
||||||
// behavior is internal if all changes are expected (and none removed)
|
// behavior is internal if all changes are expected (and none removed)
|
||||||
// type is "max" of both types (remove > contents > permissions)
|
// type is "max" of both types (remove > contents > permissions)
|
||||||
foreach (const QString &fileKey, d->m_documentsWithWatch.value(document)) {
|
foreach (const FilePath &fileKey, d->m_documentsWithWatch.value(document)) {
|
||||||
// was the file reported?
|
// was the file reported?
|
||||||
if (!currentStates.contains(fileKey))
|
if (!currentStates.contains(fileKey))
|
||||||
continue;
|
continue;
|
||||||
@@ -1355,9 +1352,9 @@ void DocumentManager::addToRecentFiles(const Utils::FilePath &filePath, Id edito
|
|||||||
{
|
{
|
||||||
if (filePath.isEmpty())
|
if (filePath.isEmpty())
|
||||||
return;
|
return;
|
||||||
const QString fileKey = filePathKey(filePath.toString(), KeepLinks);
|
const FilePath fileKey = filePathKey(filePath, KeepLinks);
|
||||||
Utils::erase(d->m_recentFiles, [fileKey](const RecentFile &file) {
|
Utils::erase(d->m_recentFiles, [fileKey](const RecentFile &file) {
|
||||||
return fileKey == filePathKey(file.first.toString(), DocumentManager::KeepLinks);
|
return fileKey == filePathKey(file.first, DocumentManager::KeepLinks);
|
||||||
});
|
});
|
||||||
while (d->m_recentFiles.count() >= EditorManagerPrivate::maxRecentFiles())
|
while (d->m_recentFiles.count() >= EditorManagerPrivate::maxRecentFiles())
|
||||||
d->m_recentFiles.removeLast();
|
d->m_recentFiles.removeLast();
|
||||||
|
Reference in New Issue
Block a user