Pārlūkot izejas kodu

Refs #8 Display loading bar when

isundil 7 mēneši atpakaļ
vecāks
revīzija
99f48ce7d6

+ 78 - 15
Engine/Engine.cpp

@@ -19,7 +19,8 @@ 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 ListFilesRecur(FileAndSumListByRepositoryIndex*, bool* threadStopping) override;
+		size_t CountFilesRecur() override;
 		void Cd(const std::string& dirName) override;
 
 		std::string BuildCurrentDirPath(const std::string& root, const PathParts& pathParts) const override;
@@ -30,8 +31,8 @@ namespace craftlab::fakeraid
 		void CopyItems(const std::vector<CopyInstruction>& itemsToCopy) const override;
 
 	private:
-		void ListFiles(FileAndSumListByRepositoryIndex& result, const PathParts& currentDir);
-		FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex);
+		void ListFiles(FileAndSumListByRepositoryIndex& result, const PathParts& currentDir, bool* threadStopping =nullptr);
+		FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex, bool* threadStopping =nullptr);
 
 		void CopyItem(const CopyInstruction& dst) const;
 
@@ -113,41 +114,66 @@ void Engine::Cd(const std::string& dirName)
 	currentDir.push_back(dirName);
 }
 
-FileAndSumList Engine::ListFiles(const std::string& root, const std::deque<std::string>& wd, int repositoryIndex)
+FileAndSumList Engine::ListFiles(const std::string& root, const std::deque<std::string>& wd, int repositoryIndex, bool* threadStopping)
 {
-	FileAndSumList result;
+	FileAndSumList result {};
 	const std::string path = BuildCurrentDirPath(root, wd);
 	Crypto cryptoEngine;
-	for (const std::filesystem::directory_entry& file : std::filesystem::directory_iterator(path))
+
+	std::filesystem::directory_iterator directoryIterator;
+	try
+	{
+		directoryIterator = std::filesystem::directory_iterator(path);
+	}
+	catch (std::exception& e)
 	{
-		if (file.is_directory() || file.is_regular_file())
+		return result; // FIXME
+	}
+	for (const std::filesystem::directory_entry& file : directoryIterator)
+	{
+		bool isDirectory = false;
+		bool isFile = false;
+		try
+		{
+			isDirectory = file.is_directory();
+			isFile = file.is_regular_file();
+		}
+		catch (std::exception& e)
+		{}
+		if (isDirectory || isFile)
 		{
 			FileAndSum fileInfos;
 			fileInfos.fileName = file.path().filename().string();
 			fileInfos.isDir = file.is_directory();
 			fileInfos.directory = wd;
 			fileInfos.repositoryIndex = repositoryIndex;
+
 			try
 			{
 				cryptoEngine.Compute(path, fileInfos);
 			}
 			catch (std::runtime_error&)
-			{}
+			{
+			}
 			result.push_back(fileInfos);
 		}
+		if (threadStopping && *threadStopping)
+			return result;
 	}
 	return result;
 }
 
-void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir)
+void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir, bool* threadStopping)
 {
 	int index = 0;
 	for (const auto& i : rootPaths)
 	{
-		const FileAndSumList files = ListFiles(i, currentDir, index++);
+		const FileAndSumList files = ListFiles(i, currentDir, index++, threadStopping);
 		result.FileAndSumListByRepositoryIndex.push_back(files);
 		for (const FileAndSum& file : files)
 			result.FileList[BuildCurrentDirPath(file)] = file;
+		if (threadStopping && *threadStopping)
+			return;
 	}
 }
 
@@ -158,21 +184,20 @@ FileAndSumListByRepositoryIndex Engine::ListFiles()
 	return result;
 }
 
-FileAndSumListByRepositoryIndex Engine::ListFilesRecur()
+void Engine::ListFilesRecur(FileAndSumListByRepositoryIndex* result, bool* threadStopping)
 {
-	FileAndSumListByRepositoryIndex result;
 	std::deque<PathParts> itemsToDo { currentDir };
 
 	do
 	{
 		FileAndSumListByRepositoryIndex newItems;
 		const PathParts currentPath = itemsToDo.front();
-		ListFiles(newItems, currentPath);
+		ListFiles(newItems, currentPath, threadStopping);
 		itemsToDo.pop_front();
-		std::copy(newItems.FileAndSumListByRepositoryIndex.begin(), newItems.FileAndSumListByRepositoryIndex.end(), std::back_inserter(result.FileAndSumListByRepositoryIndex));
+		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;
+			result->FileList[file.first] = file.second;
 			if (file.second.isDir)
 			{
 				PathParts dirPath = currentPath;
@@ -180,6 +205,44 @@ FileAndSumListByRepositoryIndex Engine::ListFilesRecur()
 				itemsToDo.push_back(dirPath);
 			}
 		}
+	} while (!itemsToDo.empty() && !*threadStopping);
+}
+
+size_t Engine::CountFilesRecur()
+{
+	size_t result =0;
+	std::deque<std::filesystem::path> itemsToDo;
+
+	for (const auto& i: rootPaths)
+		itemsToDo.push_back(i);
+
+	do
+	{
+		std::filesystem::directory_iterator directoryIterator;
+		try
+		{
+			directoryIterator = std::filesystem::directory_iterator(itemsToDo.front());
+		}
+		catch (std::exception& e)
+		{
+			itemsToDo.pop_front();
+			continue;
+		}
+		for (const std::filesystem::directory_entry& file : directoryIterator)
+		{
+			try {
+				if (file.is_regular_file())
+					++result;
+				else if (file.is_directory())
+				{
+					itemsToDo.push_back(file.path());
+					++result;
+				}
+			}
+			catch (std::exception)
+			{}
+		}
+		itemsToDo.pop_front();
 	} while (!itemsToDo.empty());
 	return result;
 }

+ 2 - 1
Engine/IEngine.h

@@ -17,7 +17,8 @@ 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 ListFilesRecur(FileAndSumListByRepositoryIndex*, bool* threadStopping) =0;
+		virtual size_t CountFilesRecur() =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;

+ 3 - 0
Engine/fileDefinition.h

@@ -4,6 +4,7 @@
 #include <string>
 #include <vector>
 #include <deque>
+#include "exports.h"
 
 typedef std::deque<std::string> PathParts;
 
@@ -30,5 +31,7 @@ namespace craftlab::fakeraid
 	{
 		std::vector<FileAndSumList> FileAndSumListByRepositoryIndex;
 		std::map<std::string, FileAndSum> FileList;
+
+		ENGINEAPI_EXPORT size_t ExistingFileCount() const;
 	};
 }

+ 8 - 0
Engine/fileDiff.cpp

@@ -98,3 +98,11 @@ bool DiffResult::HasError() const
 {
 	return !differentFiles.empty() || !missingDirs.empty() || !missingFiles.empty();
 }
+
+size_t FileAndSumListByRepositoryIndex::ExistingFileCount() const
+{
+	size_t result {};
+	for (const auto& i : FileAndSumListByRepositoryIndex)
+		result += i.size();
+	return result;
+}

+ 2 - 0
fakeRaid.vcxproj

@@ -14,6 +14,7 @@
     <ClCompile Include="fakeRaid\browseModal.cpp" />
     <ClCompile Include="fakeRaid\conflictItemWidget.cpp" />
     <ClCompile Include="fakeRaid\conflictModal.cpp" />
+    <ClCompile Include="fakeRaid\deepScanThread.cpp" />
     <ClCompile Include="fakeRaid\fileItem.cpp" />
     <ClCompile Include="fakeRaid\iconProvider.cpp" />
     <ClCompile Include="fakeRaid\main.cpp" />
@@ -32,6 +33,7 @@
     <ClInclude Include="fakeRaid\browseModal.h" />
     <QtMoc Include="fakeRaid\conflictItemWidget.h" />
     <QtMoc Include="fakeRaid\conflictModal.h" />
+    <QtMoc Include="fakeRaid\deepScanThread.h" />
     <ClInclude Include="fakeRaid\exports.h" />
     <ClInclude Include="fakeRaid\fileItem.h" />
     <ClInclude Include="fakeRaid\htmlFont.hh" />

+ 6 - 0
fakeRaid.vcxproj.filters

@@ -44,6 +44,9 @@
     <ClCompile Include="fakeRaid\fileItem.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="fakeRaid\deepScanThread.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <QtUic Include="fakeRaid\MainWindow.ui">
@@ -69,6 +72,9 @@
     <QtMoc Include="fakeRaid\conflictModal.h">
       <Filter>Header Files</Filter>
     </QtMoc>
+    <QtMoc Include="fakeRaid\deepScanThread.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="fakeRaid\exports.h">

+ 2 - 2
fakeRaid.vcxproj.user

@@ -2,10 +2,10 @@
 <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
-    <LocalDebuggerCommandArguments>C:\Users\isund\projects\fakeRaid\test\A C:\Users\isund\projects\fakeRaid\test\B</LocalDebuggerCommandArguments>
+    <LocalDebuggerCommandArguments>C:\Users\isund\AppData\Roaming C:\Users\isund\AppData\Roaming</LocalDebuggerCommandArguments>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-    <LocalDebuggerCommandArguments>C:\Users\isund\projects\fakeRaid\test\A C:\Users\isund\projects\fakeRaid\test\B</LocalDebuggerCommandArguments>
+    <LocalDebuggerCommandArguments>C:\Users\isund\AppData\Roaming C:\Users\isund\AppData\Roaming</LocalDebuggerCommandArguments>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
   <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+ 49 - 6
fakeRaid/mainWindow.cpp

@@ -2,13 +2,16 @@
 #include <QDesktopServices>
 #include <QFile>
 #include <QDir>
+#include <QProgressDialog>
 #include "ui_MainWindow.h"
 #include "mainWindow.h"
 #include "conflictModal.h"
 #include "browseModal.h"
 #include "fileDiff.h"
 #include "fileItem.h"
+#include "deepScanThread.h"
 
+using namespace craftlab::fakeraid;
 using namespace craftlab::fakeraid::ui;
 
 std::string mergePath(const std::string& a, const std::string& b);
@@ -49,14 +52,54 @@ MainWindow::~MainWindow()
 void MainWindow::RequestDeepScan()
 {
 	assert(nullptr != engine);
+	QProgressDialog* dialog = new QProgressDialog(this->window.get());
+	DeepScanThread* thread = new DeepScanThread(engine.get());
 
-	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");
+	window->setEnabled(false);
+	dialog->setMinimum(0);
+	dialog->setMaximum(0);
+	dialog->setModal(true);
+	dialog->setWindowFlag(Qt::WindowCloseButtonHint, false);
+	dialog->setAttribute(Qt::WA_DeleteOnClose);
+	dialog->setEnabled(true);
 
-	ListFiles(true);
+	connect(thread, &DeepScanThread::FileCountComputed, this, [dialog, thread](size_t fileCount) {
+		if (thread->isRunning())
+			dialog->setMaximum((int) fileCount);
+	});
+	connect(thread, &DeepScanThread::Ping, this, [dialog, thread](size_t fileCount){
+		if (thread->isRunning())
+		{
+			dialog->setValue((int)fileCount);
+			///dialog->setLabelText();
+		}
+	});
+	connect(thread, &DeepScanThread::finished, this, [this, thread, dialog](){
+		DiffResult* allResults = thread->GetResult();
+
+		dialog->close();
+		if (allResults != nullptr) // interrupted
+		{
+			if (allResults->HasError())
+			{
+				currentDiffResult = std::make_unique<DiffResult>(ConflictModal::Display(*engine, *allResults, true));
+				ListFiles(true);
+			}
+			else
+				QMessageBox::information(window.get(), window->windowTitle(), "Folders are identical");
+		}
+		thread->deleteLater();
+		window->setEnabled(true);
+	});
+	connect(dialog, &QProgressDialog::canceled, this, [thread, this]() {
+		QApplication::setOverrideCursor(Qt::WaitCursor);
+		thread->Terminate();
+		thread->deleteLater();
+		window->setEnabled(true);
+		QApplication::restoreOverrideCursor();
+	});
+	dialog->show();
+	thread->start();
 }
 
 void MainWindow::FileListItemEntered(const QModelIndex& index)