Browse Source

Fixes #8 Fixes #7 - Scan all files using recursion

isundil 7 months ago
parent
commit
0e535fc582

+ 60 - 21
Engine/Engine.cpp

@@ -19,15 +19,19 @@ namespace craftlab::fakeraid
 		std::deque<std::string> GetCurrentDir() const override;
 		bool SetWorkingDirectory(const std::vector<std::string>& path) override;
 		FileAndSumListByRepositoryIndex ListFiles() override;
+		FileAndSumListByRepositoryIndex ListFilesRecur() override;
 		void Cd(const std::string& dirName) override;
 
+		std::string BuildCurrentDirPath(const std::string& root, const PathParts& pathParts) const override;
+		std::string BuildCurrentDirPath(const FileAndSum& file) const override;
+
 		void RemoveFiles(const std::vector<std::string>& paths) const override;
 		void RemoveDirs(const std::vector<std::string>& paths) const override;
 		void CopyItems(const std::vector<CopyInstruction>& itemsToCopy) const override;
 
 	private:
-		FileAndSumList ListFiles(const std::string& root, int repositoryIndex);
-		std::string BuildCurrentDirPath(const std::string& root ="") const;
+		void ListFiles(FileAndSumListByRepositoryIndex& result, const PathParts& currentDir);
+		FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex);
 
 		void CopyItem(const CopyInstruction& dst) const;
 
@@ -47,7 +51,7 @@ std::vector<std::string> Engine::GetRootPaths() const
 std::vector<std::string> Engine::GetPaths() const
 {
 	std::vector<std::string> paths;
-	const std::string workingDir = BuildCurrentDirPath();
+	const std::string workingDir = BuildCurrentDirPath("", currentDir);
 	std::transform(rootPaths.begin(), rootPaths.end(), std::back_inserter(paths), [&workingDir](const std::string& val)
 	{
 		return (std::filesystem::path(val) / std::filesystem::path(workingDir)).string();
@@ -60,20 +64,23 @@ std::deque<std::string> Engine::GetCurrentDir() const
 	return currentDir;
 }
 
-std::string Engine::BuildCurrentDirPath(const std::string& root) const
+std::string Engine::BuildCurrentDirPath(const std::string& root, const std::deque<std::string>& _currentDir) const
 {
-	std::stringstream ss;
-	ss << root;
-	bool written = !root.empty();
+	std::filesystem::path result(root);
 
-	for (const std::string& path : currentDir)
-	{
-		if (written)
-			ss << "/";
-		ss << path;
-		written = true;
-	}
-	return ss.str();
+	for (const std::string& path : _currentDir)
+		result = result / path;
+	return result.string();
+}
+
+std::string Engine::BuildCurrentDirPath(const FileAndSum& file) const
+{
+	std::filesystem::path result;
+
+	for (const std::string& path : file.directory)
+		result = result / path;
+	result = result / file.fileName;
+	return result.string();
 }
 
 bool vectorEquals(const std::vector<std::string>& a, const std::deque<std::string>& b)
@@ -106,10 +113,10 @@ void Engine::Cd(const std::string& dirName)
 	currentDir.push_back(dirName);
 }
 
-FileAndSumList Engine::ListFiles(const std::string& root, int repositoryIndex)
+FileAndSumList Engine::ListFiles(const std::string& root, const std::deque<std::string>& wd, int repositoryIndex)
 {
 	FileAndSumList result;
-	const std::string path = BuildCurrentDirPath(root);
+	const std::string path = BuildCurrentDirPath(root, wd);
 	Crypto cryptoEngine;
 	for (const std::filesystem::directory_entry& file : std::filesystem::directory_iterator(path))
 	{
@@ -118,6 +125,7 @@ FileAndSumList Engine::ListFiles(const std::string& root, int repositoryIndex)
 			FileAndSum fileInfos;
 			fileInfos.fileName = file.path().filename().string();
 			fileInfos.isDir = file.is_directory();
+			fileInfos.directory = wd;
 			fileInfos.repositoryIndex = repositoryIndex;
 			try
 			{
@@ -131,17 +139,48 @@ FileAndSumList Engine::ListFiles(const std::string& root, int repositoryIndex)
 	return result;
 }
 
-FileAndSumListByRepositoryIndex Engine::ListFiles()
+void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir)
 {
-	FileAndSumListByRepositoryIndex result;
 	int index = 0;
 	for (const auto& i : rootPaths)
 	{
-		const FileAndSumList files = ListFiles(i, index++);
+		const FileAndSumList files = ListFiles(i, currentDir, index++);
 		result.FileAndSumListByRepositoryIndex.push_back(files);
 		for (const FileAndSum& file : files)
-			result.FileList[file.fileName] = file;
+			result.FileList[BuildCurrentDirPath(file)] = file;
 	}
+}
+
+FileAndSumListByRepositoryIndex Engine::ListFiles()
+{
+	FileAndSumListByRepositoryIndex result;
+	ListFiles(result, currentDir);
+	return result;
+}
+
+FileAndSumListByRepositoryIndex Engine::ListFilesRecur()
+{
+	FileAndSumListByRepositoryIndex result;
+	std::deque<PathParts> itemsToDo { currentDir };
+
+	do
+	{
+		FileAndSumListByRepositoryIndex newItems;
+		const PathParts currentPath = itemsToDo.front();
+		ListFiles(newItems, currentPath);
+		itemsToDo.pop_front();
+		std::copy(newItems.FileAndSumListByRepositoryIndex.begin(), newItems.FileAndSumListByRepositoryIndex.end(), std::back_inserter(result.FileAndSumListByRepositoryIndex));
+		for (const auto& file : newItems.FileList)
+		{
+			result.FileList[file.first] = file.second;
+			if (file.second.isDir)
+			{
+				PathParts dirPath = currentPath;
+				dirPath.push_back(file.second.fileName);
+				itemsToDo.push_back(dirPath);
+			}
+		}
+	} while (!itemsToDo.empty());
 	return result;
 }
 

+ 3 - 0
Engine/IEngine.h

@@ -17,7 +17,10 @@ namespace craftlab::fakeraid
 		virtual std::deque<std::string> GetCurrentDir() const =0;
 		virtual bool SetWorkingDirectory(const std::vector<std::string>& path) =0;
 		virtual FileAndSumListByRepositoryIndex ListFiles() =0;
+		virtual FileAndSumListByRepositoryIndex ListFilesRecur() =0;
 		virtual void Cd(const std::string& dirName) =0;
+		virtual std::string BuildCurrentDirPath(const std::string& root, const PathParts& pathParts) const = 0;
+		virtual std::string BuildCurrentDirPath(const FileAndSum& file) const = 0;
 
 		struct CopyInstruction
 		{

+ 4 - 0
Engine/fileDefinition.h

@@ -3,6 +3,9 @@
 #include <map>
 #include <string>
 #include <vector>
+#include <deque>
+
+typedef std::deque<std::string> PathParts;
 
 namespace craftlab::fakeraid
 {
@@ -11,6 +14,7 @@ namespace craftlab::fakeraid
 	struct File
 	{
 		std::string fileName;
+		PathParts directory;
 		bool isDir;
 		int repositoryIndex;
 	};

+ 17 - 10
Engine/fileDiff.cpp

@@ -1,6 +1,7 @@
 #include <set>
 #include "pch.h"
 #include "FileDiff.h"
+#include "IEngine.h"
 
 using namespace craftlab::fakeraid;
 
@@ -12,16 +13,17 @@ FileDiff::~FileDiff()
 {
 }
 
-FileDiff::FileVersionList FileDiff::GroupBy(const FileAndSumListByRepositoryIndex& fileListsWithRepo, size_t indexCount)
+FileDiff::FileVersionList FileDiff::GroupBy(const IEngine& engine, const FileAndSumListByRepositoryIndex& fileListsWithRepo, size_t indexCount)
 {
 	FileVersionList result;
 	for (const FileAndSumList& fileLists : fileListsWithRepo.FileAndSumListByRepositoryIndex)
 	{
 		for (const FileAndSum& i : fileLists)
 		{
-			if (!result.contains(i.fileName))
-				result.emplace(i.fileName, std::vector<std::optional<FileAndSum>>(indexCount, std::nullopt));
-			result[i.fileName][i.repositoryIndex] = i;
+			const std::string fullPath = engine.BuildCurrentDirPath(i);
+			if (!result.contains(fullPath))
+				result.emplace(fullPath, std::vector<std::optional<FileAndSum>>(indexCount, std::nullopt));
+			result[fullPath][i.repositoryIndex] = i;
 		}
 	}
 	return result;
@@ -50,7 +52,7 @@ std::vector<int> FileDiff::computeVersionIds(const ListOfOptionalFileAndSum& ver
 	return result;
 }
 
-void FileDiff::CheckVersions(DiffResult& output, const std::string& fileName, const FileDiff::ListOfOptionalFileAndSum& versions)
+void FileDiff::CheckVersions(DiffResult& output, const std::string& fileKey, const FileDiff::ListOfOptionalFileAndSum& versions)
 {
 	const auto& firstVersionIter = std::find_if(versions.begin(), versions.end(), [](const OptionalFileAndSum& i) { return i.has_value(); });
 	const FileAndSum& firstVersion = firstVersionIter->value();
@@ -66,28 +68,33 @@ void FileDiff::CheckVersions(DiffResult& output, const std::string& fileName, co
 		}
 		if (firstVersion.checksum != i->checksum)
 		{
-			output.differentFiles.emplace(fileName, computeVersionIds(versions));
+			output.differentFiles.emplace(fileKey, computeVersionIds(versions));
 			return;
 		}
 	}
 	if (std::find(filePresent.begin(), filePresent.end(), false) != filePresent.end())
 	{
 		if (firstVersion.isDir)
-			output.missingDirs.emplace(fileName, filePresent);
+			output.missingDirs.emplace(fileKey, filePresent);
 		else
-			output.missingFiles.emplace(fileName, filePresent);
+			output.missingFiles.emplace(fileKey, filePresent);
 	}
 	else
 		output.correctFiles.push_back(firstVersion);
 }
 
-DiffResult FileDiff::Process(const FileAndSumListByRepositoryIndex& fileLists)
+DiffResult FileDiff::Process(const IEngine& engine, const FileAndSumListByRepositoryIndex& fileLists)
 {
 	DiffResult result;
-	const FileVersionList& fileAndVersionLists = GroupBy(fileLists, fileLists.FileAndSumListByRepositoryIndex.size());
+	const FileVersionList& fileAndVersionLists = GroupBy(engine, fileLists, engine.GetRootPaths().size());
 
 	for (const std::pair<std::string, ListOfOptionalFileAndSum>& key : fileAndVersionLists)
 		CheckVersions(result, key.first, key.second);
 	result.FileList = fileLists.FileList;
 	return result;
 }
+
+bool DiffResult::HasError() const
+{
+	return !differentFiles.empty() || !missingDirs.empty() || !missingFiles.empty();
+}

+ 7 - 3
Engine/fileDiff.h

@@ -6,6 +6,8 @@
 
 namespace craftlab::fakeraid
 {
+	class IEngine;
+
 	struct DiffResult
 	{
 		std::map<std::string, std::vector<bool>> missingDirs;
@@ -13,6 +15,8 @@ namespace craftlab::fakeraid
 		std::map<std::string, std::vector<int>> differentFiles; // fileName -> { versionId, versionId, versionId }
 		std::vector<File> correctFiles;
 		std::map<std::string, FileAndSum> FileList;
+
+		ENGINEAPI_EXPORT bool HasError() const;
 	};
 
 	class ENGINEAPI_EXPORT FileDiff
@@ -21,15 +25,15 @@ namespace craftlab::fakeraid
 		FileDiff();
 		~FileDiff();
 
-		DiffResult Process(const FileAndSumListByRepositoryIndex& fileList);
+		DiffResult Process(const IEngine& engine, const FileAndSumListByRepositoryIndex& fileList);
 
 	private:
 		typedef std::optional<FileAndSum> OptionalFileAndSum;
 		typedef std::vector<OptionalFileAndSum> ListOfOptionalFileAndSum;
 		typedef std::map<std::string, ListOfOptionalFileAndSum> FileVersionList;
 
-		FileVersionList GroupBy(const FileAndSumListByRepositoryIndex& fileList, size_t indexCount);
+		FileVersionList GroupBy(const IEngine& engine, const FileAndSumListByRepositoryIndex& fileList, size_t indexCount);
 		std::vector<int> computeVersionIds(const ListOfOptionalFileAndSum& versions);
-		void CheckVersions(DiffResult& output, const std::string& fileName, const ListOfOptionalFileAndSum& versions);
+		void CheckVersions(DiffResult& output, const std::string& fileKey, const ListOfOptionalFileAndSum& versions);
 	};
 }

+ 6 - 0
fakeRaid/MainWindow.ui

@@ -61,6 +61,7 @@
     </property>
     <addaction name="actionOuvrir"/>
     <addaction name="actionRefresh"/>
+    <addaction name="actionScan_for_errors"/>
    </widget>
    <addaction name="menuFichier"/>
   </widget>
@@ -74,6 +75,11 @@
     <string>Refresh</string>
    </property>
   </action>
+  <action name="actionScan_for_errors">
+   <property name="text">
+    <string>Scan for errors</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>

+ 15 - 10
fakeRaid/conflictItemWidget.cpp

@@ -8,14 +8,13 @@
 using namespace craftlab::fakeraid;
 using namespace craftlab::ui;
 
-ConflictItemWidget::ConflictItemWidget(QListWidget* parent, const QFile& file, const std::string& _fileName): QWidget(parent), filename(_fileName), ui(std::make_unique<Ui_ConflictItemWidget>())
+ConflictItemWidget::ConflictItemWidget(QListWidget* parent, const QFile& file, const std::string& _fileName, const std::string& _filekey, bool displayFullPath): QWidget(parent), filename(_fileName), fileKey(_filekey), ui(std::make_unique<Ui_ConflictItemWidget>())
 {
-	std::filesystem::path p(file.fileName().toStdString());
 	ui->setupUi(this);
 	ui->warningIcon->setPixmap(IconProvider::WarningIcon(*this));
 	ui->fileIcon->resize(ui->fileIcon->baseSize());
 	ui->fileIcon->setPixmap(IconProvider::FromFile(file, ui->fileIcon->baseSize()));
-	ui->filename->setText(p.filename().string().c_str());
+	ui->filename->setText(displayFullPath ? _filekey.c_str() : _fileName.c_str());
 
 	connect(ui->ddUseVersion, &CheckableComboBox::activated, this, [this]() { SetAction(Action::UseVersion); });
 	connect(ui->buttonCopy, &QPushButton::clicked, this, [this]() { SetAction(Action::Copy); });
@@ -37,7 +36,13 @@ void ConflictItemWidget::SetAction(Action&& action)
 }
 
 std::string ConflictItemWidget::GetFileName() const
-{ return filename; }
+{
+	return filename;
+}
+std::string ConflictItemWidget::GetFileKey() const
+{
+	return fileKey;
+}
 
 ConflictItemWidget::Action ConflictItemWidget::GetAction() const
 {
@@ -125,10 +130,10 @@ std::string mergePath(const std::string& a, const std::string& b)
 	return ss.str();
 }
 
-ConflictItemWidget* ConflictItemWidget::FromMissingFile(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<bool>& version)
+ConflictItemWidget* ConflictItemWidget::FromMissingFile(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<bool>& version)
 {
 	const std::string fullPathFirstFound = mergePath(rootPaths[std::distance(version.begin(), std::find(version.begin(), version.end(), true))], filename);
-	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename);
+	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename, filekey, displayFullPath);
 	result->ui->ddUseVersion->setVisible(false);
 	std::stringstream ss;
 	ss << "File " << HTMLFont(filename, FILE_STYLE) << " does not exists in every repositories: <ul>";
@@ -138,10 +143,10 @@ ConflictItemWidget* ConflictItemWidget::FromMissingFile(QListWidget* parent, con
 	return result;
 }
 
-ConflictItemWidget* ConflictItemWidget::FromMissingDir(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<bool>& version)
+ConflictItemWidget* ConflictItemWidget::FromMissingDir(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<bool>& version)
 {
 	const std::string fullPathFirstFound = mergePath(rootPaths[std::distance(version.begin(), std::find(version.begin(), version.end(), true))], filename);
-	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename);
+	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename, filekey, displayFullPath);
 	result->ui->ddUseVersion->setVisible(false);
 	std::stringstream ss;
 	ss << "Folder " << HTMLFont(filename, FILE_STYLE) << " does not exists in every repositories: <ul>";
@@ -151,10 +156,10 @@ ConflictItemWidget* ConflictItemWidget::FromMissingDir(QListWidget* parent, cons
 	return result;
 }
 
-ConflictItemWidget* ConflictItemWidget::FromConflict(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<int>& version)
+ConflictItemWidget* ConflictItemWidget::FromConflict(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<int>& version)
 {
 	const std::string fullPathFirstFound = mergePath(rootPaths[std::distance(version.begin(), std::find_if(version.begin(), version.end(), [](const int& val) { return val != 0; }))], filename);
-	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename);
+	ConflictItemWidget* result = new ConflictItemWidget(parent, QFile(fullPathFirstFound.c_str()), filename, filekey, displayFullPath);
 	const auto fileByVersion = groupFileByVersion(version);
 	for (const auto& i : fileByVersion)
 		if (i.first)

+ 6 - 4
fakeRaid/conflictItemWidget.h

@@ -22,26 +22,28 @@ namespace craftlab::fakeraid
 			Ignore,
 		};
 
-		static ConflictItemWidget* FromMissingFile(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<bool>& version);
-		static ConflictItemWidget* FromMissingDir(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<bool>& version);
-		static ConflictItemWidget* FromConflict(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::vector<int>& version);
+		static ConflictItemWidget* FromMissingFile(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<bool>& version);
+		static ConflictItemWidget* FromMissingDir(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<bool>& version);
+		static ConflictItemWidget* FromConflict(QListWidget* parent, const std::vector<std::string>& rootPaths, const std::string& filename, const std::string& filekey, bool displayFullPath, const std::vector<int>& version);
 
 		Action GetAction() const;
 		void SetAction(Action&& action);
 		std::string GetFileName() const;
+		std::string GetFileKey() const;
 		int GetVersionToUse() const;
 
 	signals:
 		void ActionChanged();
 
 	private:
-		ConflictItemWidget(QListWidget* parent, const QFile& fullPath, const std::string& filename);
+		ConflictItemWidget(QListWidget* parent, const QFile& fullPath, const std::string& filename, const std::string& fileKey, bool displayFullPath);
 
 		static void listRepositories(const std::vector<int>& repo, std::stringstream& stream);
 		static std::map<int, std::vector<int>> groupFileByVersion(const std::vector<int>& versions);
 		static std::vector<int> versionExistsToVersionNumber(const std::vector<bool> exists);
 		static void populateListStream(const std::map<int, std::vector<int>>& repoByVersion, std::stringstream& stream);
 
+		const std::string fileKey;
 		const std::string filename;
 		Action currentAction = Action::Undefined;
 		std::unique_ptr<Ui_ConflictItemWidget> ui;

+ 19 - 19
fakeRaid/conflictModal.cpp

@@ -9,16 +9,16 @@ using namespace craftlab::fakeraid;
 
 std::string mergePath(const std::string& a, const std::string& b);
 
-ConflictModal::ConflictModal(const std::vector<std::string>& _rootPaths, const DiffResult& _diffResult): rootPaths(_rootPaths), diffResult(std::make_unique<DiffResult>(_diffResult)), ui(std::make_unique<Ui_ConflictModal>())
+ConflictModal::ConflictModal(const std::vector<std::string>& _rootPaths, const DiffResult& _diffResult, bool displayFullPath): rootPaths(_rootPaths), diffResult(std::make_unique<DiffResult>(_diffResult)), ui(std::make_unique<Ui_ConflictModal>())
 {
 	ui->setupUi(this);
 
 	for (const std::pair<std::string, std::vector<bool>>& i : diffResult->missingFiles)
-		AddConflictingFile(ConflictItemWidget::FromMissingFile(ui->listWidget, rootPaths, i.first, i.second));
+		AddConflictingFile(ConflictItemWidget::FromMissingFile(ui->listWidget, rootPaths, diffResult->FileList[i.first].fileName, i.first, displayFullPath, i.second));
 	for (const std::pair<std::string, std::vector<bool>>& i : diffResult->missingDirs)
-		AddConflictingFile(ConflictItemWidget::FromMissingDir(ui->listWidget, rootPaths, i.first, i.second));
+		AddConflictingFile(ConflictItemWidget::FromMissingDir(ui->listWidget, rootPaths, diffResult->FileList[i.first].fileName, i.first, displayFullPath, i.second));
 	for (const std::pair<std::string, std::vector<int>>& i : diffResult->differentFiles)
-		AddConflictingFile(ConflictItemWidget::FromConflict(ui->listWidget, rootPaths, i.first, i.second));
+		AddConflictingFile(ConflictItemWidget::FromConflict(ui->listWidget, rootPaths, diffResult->FileList[i.first].fileName, i.first, displayFullPath, i.second));
 	setModal(true);
 	ui->buttonProcess->setEnabled(false);
 	connect(ui->buttonIgnoreAll, &QPushButton::clicked, this, &ConflictModal::IgnoreAllAndProcess);
@@ -106,41 +106,41 @@ DiffResult ConflictModal::ComputeOutcome(const std::vector<std::string>& rootPat
 	result.FileList = diffResult->FileList;
 	for (const ConflictItemWidget* i : conflicts)
 	{
-		FileAndSum originalFile = diffResult->FileList.at(i->GetFileName());
+		FileAndSum originalFile = diffResult->FileList.at(i->GetFileKey());
 		if (i->GetAction() == ConflictItemWidget::Action::Copy)
 		{
 			result.correctFiles.push_back(originalFile);
 			std::vector<int> versions;
-			if (diffResult->missingFiles.find(originalFile.fileName) != diffResult->missingFiles.end())
-				std::transform(diffResult->missingFiles[originalFile.fileName].begin(),
-					diffResult->missingFiles[originalFile.fileName].end(),
+			if (diffResult->missingFiles.find(i->GetFileKey()) != diffResult->missingFiles.end())
+				std::transform(diffResult->missingFiles[i->GetFileKey()].begin(),
+					diffResult->missingFiles[i->GetFileKey()].end(),
 					std::back_inserter(versions),
 					[](bool v) { return v ? 0 : 1; });
 			else
-				std::transform(diffResult->missingDirs[originalFile.fileName].begin(),
-					diffResult->missingDirs[originalFile.fileName].end(),
+				std::transform(diffResult->missingDirs[i->GetFileKey()].begin(),
+					diffResult->missingDirs[i->GetFileKey()].end(),
 					std::back_inserter(versions),
 					[](bool v) { return v ? 0 : 1; });
-			ComputeCopyProcess(originalFile.fileName, versions, i->GetVersionToUse());
+			ComputeCopyProcess(i->GetFileKey(), versions, i->GetVersionToUse());
 		}
 		else if (i->GetAction() == ConflictItemWidget::Action::UseVersion)
 		{
 			result.correctFiles.push_back(originalFile);
-			ComputeCopyProcess(originalFile.fileName, diffResult->differentFiles[originalFile.fileName], i->GetVersionToUse());
+			ComputeCopyProcess(i->GetFileKey(), diffResult->differentFiles[i->GetFileKey()], i->GetVersionToUse());
 		}
 		else if (i->GetAction() == ConflictItemWidget::Action::Remove)
 		{
-			ComputeRemovalProcess(originalFile.fileName);
+			ComputeRemovalProcess(i->GetFileKey());
 		}
 		else if (i->GetAction() == ConflictItemWidget::Action::Ignore ||
 			i->GetAction() == ConflictItemWidget::Action::Undefined)
 		{
-			if (diffResult->differentFiles.find(i->GetFileName()) != diffResult->differentFiles.end())
-				result.differentFiles[i->GetFileName()] = diffResult->differentFiles.at(i->GetFileName());
+			if (diffResult->differentFiles.find(i->GetFileKey()) != diffResult->differentFiles.end())
+				result.differentFiles[i->GetFileKey()] = diffResult->differentFiles.at(i->GetFileKey());
 			else if (originalFile.isDir)
-				result.missingDirs[i->GetFileName()] = diffResult->missingDirs.at(i->GetFileName());
+				result.missingDirs[i->GetFileKey()] = diffResult->missingDirs.at(i->GetFileKey());
 			else
-				result.missingFiles[i->GetFileName()] = diffResult->missingFiles.at(i->GetFileName());
+				result.missingFiles[i->GetFileKey()] = diffResult->missingFiles.at(i->GetFileKey());
 		}
 	}
 	return result;
@@ -154,9 +154,9 @@ void ConflictModal::reject()
 		return IgnoreAllAndProcess();
 }
 
-DiffResult ConflictModal::Display(const IEngine& engine, const DiffResult& diffResult)
+DiffResult ConflictModal::Display(const IEngine& engine, const DiffResult& diffResult, bool displayFullPath)
 {
-	ConflictModal dialog(engine.GetRootPaths(), diffResult);
+	ConflictModal dialog(engine.GetRootPaths(), diffResult, displayFullPath);
 	dialog.exec();
 	const auto result = dialog.ComputeOutcome(engine.GetPaths());
 

+ 2 - 2
fakeRaid/conflictModal.h

@@ -16,7 +16,7 @@ namespace craftlab::fakeraid
 	public:
 		~ConflictModal();
 
-		static DiffResult Display(const IEngine& engine, const DiffResult& diffResult);
+		static DiffResult Display(const IEngine& engine, const DiffResult& diffResult, bool displayFullPath);
 		DiffResult ComputeOutcome(const std::vector<std::string>& rootPaths);
 
 		void reject() override;
@@ -30,7 +30,7 @@ namespace craftlab::fakeraid
 
 	private:
 		ConflictModal() =delete;
-		ConflictModal(const std::vector<std::string>& rootPaths, const DiffResult& diffResult);
+		ConflictModal(const std::vector<std::string>& rootPaths, const DiffResult& diffResult, bool displayFullPath);
 
 		void AddConflictingFile(ConflictItemWidget* widget);
 		void ComputeRemovalProcess(const std::string& fileName);

+ 37 - 26
fakeRaid/mainWindow.cpp

@@ -11,6 +11,8 @@
 
 using namespace craftlab::fakeraid::ui;
 
+std::string mergePath(const std::string& a, const std::string& b);
+
 MainWindow::MainWindow(const std::vector<std::string>& dirList)
 	: fileListItemModel(std::make_unique<QStandardItemModel>(this)),
 	ui(std::make_unique<Ui_MainWindow>()),
@@ -25,7 +27,8 @@ MainWindow::MainWindow(const std::vector<std::string>& dirList)
 	ui->breadcrumb->setFixedHeight(36);
 
 	connect(ui->actionOuvrir, &QAction::triggered, this, &MainWindow::MenuBarActionTrigerred);
-	connect(ui->actionRefresh, &QAction::triggered, this, &MainWindow::OnEngineUpdated);
+	connect(ui->actionRefresh, &QAction::triggered, this, &MainWindow::OnPathChanged);
+	connect(ui->actionScan_for_errors, &QAction::triggered, this, &MainWindow::RequestDeepScan);
 	connect(ui->listView, &QListView::doubleClicked, this, &MainWindow::FileListItemEntered);
 	connect(ui->breadcrumb, &craftlab::ui::Breadcrumb::SelectionChanged, this, &MainWindow::OnBreadcrumbSelection);
 	ui->listView->addAction("Open", [this]() { FileListItemEntered(ui->listView->currentIndex()); });
@@ -43,6 +46,19 @@ MainWindow::~MainWindow()
 	fileWatcher->deleteLater();
 }
 
+void MainWindow::RequestDeepScan()
+{
+	assert(nullptr != engine);
+
+	DiffResult allResults= FileDiff().Process(*engine, engine->ListFilesRecur());
+	if (allResults.HasError())
+		currentDiffResult = std::make_unique<DiffResult>(ConflictModal::Display(*engine, allResults, true));
+	else
+		QMessageBox::information(window.get(), window->windowTitle(), "Folders are identical");
+
+	ListFiles(true);
+}
+
 void MainWindow::FileListItemEntered(const QModelIndex& index)
 {
 	if (index.isValid() && currentDiffResult)
@@ -96,11 +112,10 @@ void MainWindow::OnBreadcrumbSelection(int index)
 	std::vector<std::string> path;
 	const std::deque<std::string> currenPath = engine->GetCurrentDir();
 
-	window->setEnabled(false);
 	for (int i = 1; i <= index; ++i)
 		path.push_back(currenPath[i -1]);
 	if (engine->SetWorkingDirectory(path))
-		OnEngineUpdated();
+		OnPathChanged();
 }
 
 void MainWindow::UpdateBreadcrumb()
@@ -115,6 +130,7 @@ void MainWindow::UpdateBreadcrumb()
 void MainWindow::UpdateFileList()
 {
 	fileListItemModel->clear();
+	std::sort(currentDiffResult->correctFiles.begin(), currentDiffResult->correctFiles.end(), [](const File& a, const File& b) { return a.fileName < b.fileName; });
 	for (const File& file : currentDiffResult->correctFiles)
 		fileListItemModel->appendRow(new FileItem(*ui->listView, engine->GetRootPaths(), file));
 	std::vector<std::string> allFilenames;
@@ -126,20 +142,15 @@ void MainWindow::UpdateFileList()
 		fileListItemModel->appendRow(new FileItem(*ui->listView, engine->GetRootPaths(), currentDiffResult->FileList[file], false));
 }
 
-void MainWindow::ListFiles(bool ignoreAll)
+void MainWindow::ListFiles(bool ignoreErrors)
 {
-	if (!engine)
-		return;
-	currentDiffResult = std::make_unique<DiffResult>(FileDiff().Process(engine->ListFiles()));
-	if (!ignoreAll && (!currentDiffResult->differentFiles.empty() || !currentDiffResult->missingDirs.empty() || !currentDiffResult->missingFiles.empty()))
-		currentDiffResult = std::make_unique<DiffResult>(ConflictModal::Display(*engine, *currentDiffResult));
-	std::sort(currentDiffResult->correctFiles.begin(), currentDiffResult->correctFiles.end(), [](const File& a, const File& b) { return a.fileName < b.fileName; });
-
+	assert(nullptr != engine);
+	currentDiffResult = std::make_unique<DiffResult>(FileDiff().Process(*engine, engine->ListFiles()));
+	if (!ignoreErrors && currentDiffResult->HasError())
+		currentDiffResult = std::make_unique<DiffResult>(ConflictModal::Display(*engine, *currentDiffResult, false));
 	UpdateFileList();
 }
 
-std::string mergePath(const std::string& a, const std::string& b);
-
 void MainWindow::FileEdit(const File& file)
 {
 	assert(nullptr != engine);
@@ -168,7 +179,7 @@ void MainWindow::OnListViewDoubleClick(const FileAndSum& file)
 			if (engine)
 			{
 				engine->Cd(file.fileName);
-				OnEngineUpdated();
+				OnPathChanged();
 			}
 		}
 		else
@@ -180,26 +191,26 @@ void MainWindow::OnListViewDoubleClick(const FileAndSum& file)
 	if (!engine)
 		return;
 	DiffResult askConflict;
-	bool missingFile = currentDiffResult->missingFiles.find(file.fileName) != currentDiffResult->missingFiles.end();
-	bool missingDir = currentDiffResult->missingDirs.find(file.fileName) != currentDiffResult->missingDirs.end();
-	askConflict.FileList[file.fileName] = file;
+	bool missingFile = currentDiffResult->missingFiles.find(engine->BuildCurrentDirPath(file)) != currentDiffResult->missingFiles.end();
+	bool missingDir = currentDiffResult->missingDirs.find(engine->BuildCurrentDirPath(file)) != currentDiffResult->missingDirs.end();
+	askConflict.FileList[engine->BuildCurrentDirPath(file)] = file;
 	if (missingFile)
-		askConflict.missingFiles[file.fileName] = currentDiffResult->missingFiles[file.fileName];
+		askConflict.missingFiles[engine->BuildCurrentDirPath(file)] = currentDiffResult->missingFiles[engine->BuildCurrentDirPath(file)];
 	else if (missingDir)
-		askConflict.missingDirs[file.fileName] = currentDiffResult->missingDirs[file.fileName];
+		askConflict.missingDirs[engine->BuildCurrentDirPath(file)] = currentDiffResult->missingDirs[engine->BuildCurrentDirPath(file)];
 	else
-		askConflict.differentFiles[file.fileName] = currentDiffResult->differentFiles[file.fileName];
-	const DiffResult& result = ConflictModal::Display(*engine, askConflict);
+		askConflict.differentFiles[engine->BuildCurrentDirPath(file)] = currentDiffResult->differentFiles[engine->BuildCurrentDirPath(file)];
+	const DiffResult& result = ConflictModal::Display(*engine, askConflict, false);
 	if (result.missingDirs.empty() && result.missingFiles.empty() && result.differentFiles.empty())
 	{
 		if (!result.correctFiles.empty())
 			currentDiffResult->correctFiles.push_back(file);
 		if (missingFile)
-			currentDiffResult->missingFiles.erase(currentDiffResult->missingFiles.find(file.fileName));
+			currentDiffResult->missingFiles.erase(currentDiffResult->missingFiles.find(engine->BuildCurrentDirPath(file)));
 		else if (missingDir)
-			currentDiffResult->missingDirs.erase(currentDiffResult->missingDirs.find(file.fileName));
+			currentDiffResult->missingDirs.erase(currentDiffResult->missingDirs.find(engine->BuildCurrentDirPath(file)));
 		else
-			currentDiffResult->differentFiles.erase(currentDiffResult->differentFiles.find(file.fileName));
+			currentDiffResult->differentFiles.erase(currentDiffResult->differentFiles.find(engine->BuildCurrentDirPath(file)));
 		UpdateFileList();
 	}
 }
@@ -209,7 +220,7 @@ void MainWindow::OnFileWatcherTrigger(const QString& path)
 	ListFiles(true);
 }
 
-void MainWindow::OnEngineUpdated()
+void MainWindow::OnPathChanged()
 {
 	window->setEnabled(false);
 	fileWatcher->deleteLater();
@@ -231,7 +242,7 @@ bool MainWindow::TryOpenningDir(const std::vector<std::string>& folders)
 		return false;
 	}
 	engine.reset(newEngine);
-	OnEngineUpdated();
+	OnPathChanged();
 	return true;
 }
 

+ 3 - 2
fakeRaid/mainWindow.h

@@ -33,11 +33,12 @@ namespace craftlab::fakeraid::ui
 		void FileListItemEntered(const QModelIndex& index);
 		void OpenContainingFolders(const QModelIndex& index);
 		void OnFileWatcherTrigger(const QString& path);
+		void RequestDeepScan();
 
 	private:
 		bool PathExists(const IEngine& engine) const;
-		void OnEngineUpdated();
-		void ListFiles(bool ignoreAll =false);
+		void OnPathChanged();
+		void ListFiles(bool ignoreErrors =false);
 		void OnListViewDoubleClick(const FileAndSum& filename);
 		void OpenContainingFolders(const File& filename);
 		void FileEdit(const File& f);