summaryrefslogtreecommitdiff
path: root/FreeFileSync.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'FreeFileSync.cpp')
-rw-r--r--FreeFileSync.cpp830
1 files changed, 479 insertions, 351 deletions
diff --git a/FreeFileSync.cpp b/FreeFileSync.cpp
index d0927ae8..d7f398df 100644
--- a/FreeFileSync.cpp
+++ b/FreeFileSync.cpp
@@ -19,7 +19,78 @@
using namespace globalFunctions;
-const wxString FreeFileSync::FfsLastConfigFile = wxT("LastRun.ffs_gui");
+
+MainConfiguration::MainConfiguration() :
+ compareVar(CMP_BY_TIME_SIZE),
+ filterIsActive(false), //do not filter by default
+ includeFilter(wxT("*")), //include all files/folders
+ excludeFilter(wxEmptyString), //exclude nothing
+ useRecycleBin(FreeFileSync::recycleBinExists()), //enable if OS supports it; else user will have to activate first and then get an error message
+ continueOnError(false)
+{}
+
+
+struct FileInfo
+{
+ wxULongLong fileSize; //unit: bytes!
+ wxString lastWriteTime;
+ wxULongLong lastWriteTimeRaw; //unit: seconds!
+};
+
+
+//some special file functions
+void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusHandler* updateClass = 0);
+void getFileInformation(FileInfo& output, const wxString& filename);
+
+
+//Note: the following lines are a performance optimization for deleting elements from a vector. It is incredibly faster to create a new
+//vector and leave specific elements out than to delete row by row and force recopying of most elements for each single deletion (linear vs quadratic runtime)
+template <class T>
+void removeRowsFromVector(vector<T>& grid, const set<int>& rowsToRemove)
+{
+ vector<T> temp;
+ int rowToSkip = -1; //keep it an INT!
+
+ set<int>::iterator rowToSkipIndex = rowsToRemove.begin();
+
+ if (rowToSkipIndex != rowsToRemove.end())
+ rowToSkip = *rowToSkipIndex;
+
+ for (int i = 0; i < int(grid.size()); ++i)
+ {
+ if (i != rowToSkip)
+ temp.push_back(grid[i]);
+ else
+ {
+ ++rowToSkipIndex;
+ if (rowToSkipIndex != rowsToRemove.end())
+ rowToSkip = *rowToSkipIndex;
+ }
+ }
+ grid.swap(temp);
+}
+
+
+class GetAllFilesFull : public wxDirTraverser
+{
+public:
+ GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusHandler* updateClass = 0);
+
+ wxDirTraverseResult OnFile(const wxString& filename);
+
+ wxDirTraverseResult OnDir(const wxString& dirname);
+
+ wxDirTraverseResult OnOpenError(const wxString& openerrorname);
+
+private:
+ DirectoryDescrType& m_output;
+ wxString directory;
+ int prefixLength;
+ FileInfo currentFileInfo;
+ FileDescrLine fileDescr;
+ StatusHandler* statusUpdater;
+};
+
inline
wxString formatTime(unsigned int number)
@@ -46,7 +117,7 @@ wxString formatTime(unsigned int number)
}
-void FreeFileSync::getFileInformation(FileInfo& output, const wxString& filename)
+void getFileInformation(FileInfo& output, const wxString& filename)
{
#ifdef FFS_WIN
WIN32_FIND_DATA winFileInfo;
@@ -159,7 +230,7 @@ bool filesHaveSameContent(const wxString& filename1, const wxString& filename2)
}
-void FreeFileSync::generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusUpdater* updateClass)
+void generateFileAndFolderDescriptions(DirectoryDescrType& output, const wxString& directory, StatusHandler* updateClass)
{
assert (updateClass);
@@ -168,17 +239,17 @@ void FreeFileSync::generateFileAndFolderDescriptions(DirectoryDescrType& output,
output.clear();
//get all files and folders from directory (and subdirectories) + information
- GetAllFilesFull traverser(output, getFormattedDirectoryName(directory), updateClass);
+ GetAllFilesFull traverser(output, FreeFileSync::getFormattedDirectoryName(directory), updateClass);
wxDir dir(directory);
if (dir.Traverse(traverser) != (size_t)-1)
break; //traversed successfully
else
{
- int rv = updateClass->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + directory + wxT("\""));
- if (rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = updateClass->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + directory + wxT("\""));
+ if (rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -217,7 +288,7 @@ private:
};
-bool filesHaveSameContentMultithreaded(const wxString& filename1, const wxString& filename2, StatusUpdater* updateClass)
+bool filesHaveSameContentMultithreaded(const wxString& filename1, const wxString& filename2, StatusHandler* updateClass)
{
static UpdateWhileComparing cmpAndUpdate; //single instantiation: thread enters wait phase after each execution
@@ -304,7 +375,7 @@ public:
delete i->directoryDesc;
}
- const DirectoryDescrType* getDirectoryDescription(const wxString& directory, StatusUpdater* statusUpdater)
+ const DirectoryDescrType* getDirectoryDescription(const wxString& directory, StatusHandler* statusUpdater)
{
DescrBufferLine bufferEntry;
bufferEntry.directoryName = directory;
@@ -319,9 +390,9 @@ public:
{
//entry not found; create new one
bufferEntry.directoryDesc = new DirectoryDescrType;
- FreeFileSync::generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, statusUpdater);
- buffer.insert(bufferEntry);
+ buffer.insert(bufferEntry); //exception safety: insert into buffer right after creation!
+ generateFileAndFolderDescriptions(*bufferEntry.directoryDesc, directory, statusUpdater); //exceptions may be thrown!
return bufferEntry.directoryDesc;
}
}
@@ -331,169 +402,92 @@ private:
};
-void FreeFileSync::startCompareProcess(FileCompareResult& output,
- const vector<FolderPair>& directoryPairsFormatted,
+void FreeFileSync::startCompareProcess(const vector<FolderPair>& directoryPairsFormatted,
const CompareVariant cmpVar,
- StatusUpdater* statusUpdater)
+ FileCompareResult& output,
+ StatusHandler* statusUpdater)
{
#ifndef __WXDEBUG__
- wxLogNull dummy; //hide wxWidgets log messages in release build
+ wxLogNull noWxLogs; //hide wxWidgets log messages in release build
#endif
-
assert (statusUpdater);
//################################################################################################################################################
- //inform about the total amount of data that will be processed from now on
- statusUpdater->initNewProcess(-1, 0, FreeFileSync::scanningFilesProcess); //it's not known how many files will be scanned => -1 objects
-
- FileCompareResult output_tmp; //write to output not before END of process!
- set<int> delayedContentCompare; //compare of file content happens AFTER finding corresponding files
- //in order to separate into two processes (needed by progress indicators)
-
- //buffer accesses to the same directories; useful when multiple folder pairs are used
- DirectoryDescrBuffer descriptionBuffer;
+ FileCompareResult output_tmp; //write to output not before END of process!
try
{
- //process one folder pair after each other
- for (vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
- {
- //unsigned int startTime = GetTickCount();
-
- //retrieve sets of files (with description data)
- const DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, statusUpdater);
- const DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, statusUpdater);
+ //inform about the total amount of data that will be processed from now on
+ statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime));
- statusUpdater->forceUiRefresh();
+ //do basis scan: only result lines of type FILE_UNDEFINED need to be determined
+ FreeFileSync::performBaseComparison(directoryPairsFormatted,
+ output_tmp,
+ statusUpdater);
- FileCompareLine newline;
-
- //find files/folders that exist in left file model but not in right model
- for (DirectoryDescrType::iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i)
- if (directoryRight->find(*i) == directoryRight->end())
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = FileDescrLine();
- newline.fileDescrRight.directory = pair->rightDirectory;
- newline.cmpResult = FILE_LEFT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
-
- for (DirectoryDescrType::iterator j = directoryRight->begin(); j != directoryRight->end(); ++j)
+ if (cmpVar == CMP_BY_TIME_SIZE)
+ {
+ for (FileCompareResult::iterator i = output_tmp.begin(); i != output_tmp.end(); ++i)
{
- DirectoryDescrType::iterator i;
-
- //find files/folders that exist in right file model but not in left model
- if ((i = directoryLeft->find(*j)) == directoryLeft->end())
+ if (i->cmpResult == FILE_UNDEFINED)
{
- newline.fileDescrLeft = FileDescrLine();
- newline.fileDescrLeft.directory = pair->leftDirectory; //directory info is needed when creating new directories
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
- //find files that exist in left and right file model
- else
- { //objType != TYPE_NOTHING
- if (i->objType == TYPE_DIRECTORY && j->objType == TYPE_DIRECTORY)
+ //last write time may differ by up to 2 seconds (NTFS vs FAT32)
+ bool sameWriteTime;
+ if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw)
+ sameWriteTime = (i->fileDescrRight.lastWriteTimeRaw - i->fileDescrLeft.lastWriteTimeRaw <= 2);
+ else
+ sameWriteTime = (i->fileDescrLeft.lastWriteTimeRaw - i->fileDescrRight.lastWriteTimeRaw <= 2);
+
+ if (sameWriteTime)
{
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_EQUAL;
- output_tmp.push_back(newline);
- }
- //if we have a nameclash between a file and a directory: split into separate rows
- else if (i->objType != j->objType)
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = FileDescrLine();
- newline.fileDescrRight.directory = pair->rightDirectory;
- newline.cmpResult = FILE_LEFT_SIDE_ONLY;
- output_tmp.push_back(newline);
-
- newline.fileDescrLeft = FileDescrLine();
- newline.fileDescrLeft.directory = pair->leftDirectory;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
- output_tmp.push_back(newline);
- }
- else if (cmpVar == CMP_BY_TIME_SIZE)
- { //check files that exist in left and right model but have different properties
-
- //last write time may differ by up to 2 seconds (NTFS vs FAT32)
- bool sameWriteTime;
- if (i->lastWriteTimeRaw < j->lastWriteTimeRaw)
- sameWriteTime = (j->lastWriteTimeRaw - i->lastWriteTimeRaw <= 2);
- else
- sameWriteTime = (i->lastWriteTimeRaw - j->lastWriteTimeRaw <= 2);
-
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- if (sameWriteTime)
- {
- if (i->fileSize == j->fileSize)
- newline.cmpResult = FILE_EQUAL;
- else
- newline.cmpResult = FILE_DIFFERENT;
- }
+ if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize)
+ i->cmpResult = FILE_EQUAL;
else
- {
- if (i->lastWriteTimeRaw < j->lastWriteTimeRaw)
- newline.cmpResult = FILE_RIGHT_NEWER;
- else
- newline.cmpResult = FILE_LEFT_NEWER;
- }
- output_tmp.push_back(newline);
+ i->cmpResult = FILE_DIFFERENT;
}
- else if (cmpVar == CMP_BY_CONTENT)
- { //check files that exist in left and right model but have different content
-
- //check filesize first!
- if (i->fileSize == j->fileSize)
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_INVALID; //not yet determined
- output_tmp.push_back(newline);
-
- //compare by content is only needed if filesizes are the same
- delayedContentCompare.insert(output_tmp.size() - 1); //save index of row, to calculate cmpResult later
- }
+ else
+ {
+ if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw)
+ i->cmpResult = FILE_RIGHT_NEWER;
else
- {
- newline.fileDescrLeft = *i;
- newline.fileDescrRight = *j;
- newline.cmpResult = FILE_DIFFERENT;
- output_tmp.push_back(newline);
- }
+ i->cmpResult = FILE_LEFT_NEWER;
}
- else assert (false);
}
}
}
-
//################################################################################################################################################
+ else if (cmpVar == CMP_BY_CONTENT)
+ {
+ set<int> rowsToCompareBytewise; //compare of file content happens AFTER finding corresponding files
+ //in order to separate into two processes (scanning and comparing)
- //compare file contents and set value "cmpResult"
+ //pre-check: files have different content if they have a different filesize
+ for (FileCompareResult::iterator i = output_tmp.begin(); i != output_tmp.end(); ++i)
+ {
+ if (i->cmpResult == FILE_UNDEFINED)
+ {
+ if (i->fileDescrLeft.fileSize != i->fileDescrRight.fileSize)
+ i->cmpResult = FILE_DIFFERENT;
+ else
+ rowsToCompareBytewise.insert(i - output_tmp.begin());
+ }
+ }
- //unsigned int startTime3 = GetTickCount();
- if (cmpVar == CMP_BY_CONTENT)
- {
int objectsTotal = 0;
double dataTotal = 0;
- calcTotalDataForCompare(objectsTotal, dataTotal, output_tmp, delayedContentCompare);
+ calcTotalDataForCompare(objectsTotal, dataTotal, output_tmp, rowsToCompareBytewise);
- statusUpdater->initNewProcess(objectsTotal, dataTotal, FreeFileSync::compareFileContentProcess);
+ statusUpdater->initNewProcess(objectsTotal, dataTotal, StatusHandler::PROCESS_COMPARING_CONTENT);
set<int> rowsToDelete; //if errors occur during file access and user skips, these rows need to be deleted from result
- for (set<int>::iterator i = delayedContentCompare.begin(); i != delayedContentCompare.end(); ++i)
+ //compair files (that have same size) bytewise...
+ for (set<int>::iterator i = rowsToCompareBytewise.begin(); i != rowsToCompareBytewise.end(); ++i)
{
FileCompareLine& gridline = output_tmp[*i];
- statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + wxT("\"") + gridline.fileDescrLeft.relFilename + wxT("\""));
+ statusUpdater->updateStatusText(wxString(_("Comparing content of files ")) + wxT("\"") + gridline.fileDescrLeft.relativeName + wxT("\""));
//check files that exist in left and right model but have different content
while (true)
@@ -503,24 +497,23 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
try
{
- if (filesHaveSameContentMultithreaded(gridline.fileDescrLeft.filename, gridline.fileDescrRight.filename, statusUpdater))
+ if (filesHaveSameContentMultithreaded(gridline.fileDescrLeft.fullName, gridline.fileDescrRight.fullName, statusUpdater))
gridline.cmpResult = FILE_EQUAL;
else
gridline.cmpResult = FILE_DIFFERENT;
- statusUpdater->updateProcessedData(2, (gridline.fileDescrLeft.fileSize + gridline.fileDescrRight.fileSize).ToDouble());
+ statusUpdater->updateProcessedData(2, (gridline.fileDescrLeft.fileSize * 2).ToDouble());
break;
}
catch (FileError& error)
{
- //if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if (rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
+ if (rv == ErrorHandler::CONTINUE_NEXT)
{
rowsToDelete.insert(*i);
break;
}
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -532,7 +525,8 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
if (rowsToDelete.size() > 0)
removeRowsFromVector(output_tmp, rowsToDelete);
}
- //wxMessageBox(numberToWxString(unsigned(GetTickCount()) - startTime3));
+ else assert(false);
+
statusUpdater->requestUiRefresh();
}
@@ -541,12 +535,99 @@ void FreeFileSync::startCompareProcess(FileCompareResult& output,
wxMessageBox(theException.show(), _("An exception occured!"), wxOK | wxICON_ERROR);
return;
}
+ catch (std::bad_alloc& e)
+ {
+ wxMessageBox(wxString(_("System out of memory!")) + wxT(" ") + wxString::From8BitData(e.what()), _("An exception occured!"), wxOK | wxICON_ERROR);
+ return;
+ }
- //only if everything was processed correctly output is written to!
+//only if everything was processed correctly output is written to!
output_tmp.swap(output);
}
+void FreeFileSync::performBaseComparison(const vector<FolderPair>& directoryPairsFormatted,
+ FileCompareResult& output,
+ StatusHandler* statusUpdater)
+{
+ //buffer accesses to the same directories; useful when multiple folder pairs are used
+ DirectoryDescrBuffer descriptionBuffer;
+
+ //process one folder pair after each other
+ for (vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair)
+ {
+ //retrieve sets of files (with description data)
+ const DirectoryDescrType* directoryLeft = descriptionBuffer.getDirectoryDescription(pair->leftDirectory, statusUpdater);
+ const DirectoryDescrType* directoryRight = descriptionBuffer.getDirectoryDescription(pair->rightDirectory, statusUpdater);
+
+ statusUpdater->forceUiRefresh();
+ FileCompareLine newline;
+
+ //find files/folders that exist in left file model but not in right model
+ for (DirectoryDescrType::iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i)
+ if (directoryRight->find(*i) == directoryRight->end())
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = FileDescrLine();
+ newline.fileDescrRight.directory = pair->rightDirectory;
+ newline.cmpResult = FILE_LEFT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+
+ for (DirectoryDescrType::iterator j = directoryRight->begin(); j != directoryRight->end(); ++j)
+ {
+ DirectoryDescrType::iterator i;
+
+ //find files/folders that exist in right file model but not in left model
+ if ((i = directoryLeft->find(*j)) == directoryLeft->end())
+ {
+ newline.fileDescrLeft = FileDescrLine();
+ newline.fileDescrLeft.directory = pair->leftDirectory; //directory info is needed when creating new directories
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+ //find files/folders that exist in left and right file model
+ else
+ { //files...
+ if (i->objType == FileDescrLine::TYPE_FILE && j->objType == FileDescrLine::TYPE_FILE)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_UNDEFINED; //not yet determined!
+ output.push_back(newline);
+ }
+ //directories...
+ else if (i->objType == FileDescrLine::TYPE_DIRECTORY && j->objType == FileDescrLine::TYPE_DIRECTORY)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_EQUAL;
+ output.push_back(newline);
+ }
+ //if we have a nameclash between a file and a directory: split into two separate rows
+ else if (i->objType != j->objType)
+ {
+ newline.fileDescrLeft = *i;
+ newline.fileDescrRight = FileDescrLine();
+ newline.fileDescrRight.directory = pair->rightDirectory;
+ newline.cmpResult = FILE_LEFT_SIDE_ONLY;
+ output.push_back(newline);
+
+ newline.fileDescrLeft = FileDescrLine();
+ newline.fileDescrLeft.directory = pair->leftDirectory;
+ newline.fileDescrRight = *j;
+ newline.cmpResult = FILE_RIGHT_SIDE_ONLY;
+ output.push_back(newline);
+ }
+ else assert (false);
+ }
+ }
+ }
+ statusUpdater->requestUiRefresh();
+}
+
+
void FreeFileSync::swapGrids(FileCompareResult& grid)
{
FileDescrLine tmp;
@@ -571,7 +652,7 @@ void FreeFileSync::swapGrids(FileCompareResult& grid)
}
-GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusUpdater* updateClass)
+GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsSearched, StatusHandler* updateClass)
: m_output(output), directory(dirThatIsSearched), statusUpdater(updateClass)
{
assert(updateClass);
@@ -581,23 +662,23 @@ GetAllFilesFull::GetAllFilesFull(DirectoryDescrType& output, wxString dirThatIsS
wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
{
- fileDescr.filename = filename;
- fileDescr.directory = directory;
- fileDescr.relFilename = filename.Mid(prefixLength, wxSTRING_MAXLEN);
+ fileDescr.fullName = filename;
+ fileDescr.directory = directory;
+ fileDescr.relativeName = filename.Mid(prefixLength, wxSTRING_MAXLEN);
while (true)
{
try
{
- FreeFileSync::getFileInformation(currentFileInfo, filename);
+ getFileInformation(currentFileInfo, filename);
break;
}
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
return wxDIR_CONTINUE;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -607,13 +688,13 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
fileDescr.fileSize = currentFileInfo.fileSize;
- fileDescr.objType = TYPE_FILE;
+ fileDescr.objType = FileDescrLine::TYPE_FILE;
m_output.insert(fileDescr);
//update UI/commandline status information
- statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + filename + wxT("\"")); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + filename + wxT("\"")); //NO performance issue at all
//add 1 element to the progress indicator
- statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
+ statusUpdater->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
statusUpdater->requestUiRefresh();
@@ -624,43 +705,24 @@ wxDirTraverseResult GetAllFilesFull::OnFile(const wxString& filename)
wxDirTraverseResult GetAllFilesFull::OnDir(const wxString& dirname)
{
#ifdef FFS_WIN
- if (dirname.EndsWith(wxT("\\RECYCLER")) ||
+ if ( dirname.EndsWith(wxT("\\RECYCLER")) ||
dirname.EndsWith(wxT("\\System Volume Information")))
return wxDIR_IGNORE;
#endif // FFS_WIN
- fileDescr.filename = dirname;
- fileDescr.directory = directory;
- fileDescr.relFilename = dirname.Mid(prefixLength, wxSTRING_MAXLEN);
- while (true)
- {
- try
- {
- FreeFileSync::getFileInformation(currentFileInfo, dirname);
- break;
- }
- catch (FileError& error)
- {
- //if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
- return wxDIR_IGNORE;
- else if (rv == StatusUpdater::retry)
- ; //continue with loop
- else
- assert (false);
- }
- }
- fileDescr.lastWriteTime = currentFileInfo.lastWriteTime;
- fileDescr.lastWriteTimeRaw = currentFileInfo.lastWriteTimeRaw;
- fileDescr.fileSize = wxULongLong(0); //currentFileInfo.fileSize should be "0" as well, but just to be sure... currently used by getBytesToTransfer
- fileDescr.objType = TYPE_DIRECTORY;
+ fileDescr.fullName = dirname;
+ fileDescr.directory = directory;
+ fileDescr.relativeName = dirname.Mid(prefixLength, wxSTRING_MAXLEN);
+ fileDescr.lastWriteTime = wxEmptyString; //irrelevant for directories
+ fileDescr.lastWriteTimeRaw = wxULongLong(0); //irrelevant for directories
+ fileDescr.fileSize = wxULongLong(0); //currently used by getBytesToTransfer
+ fileDescr.objType = FileDescrLine::TYPE_DIRECTORY;
m_output.insert(fileDescr);
//update UI/commandline status information
- statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + dirname + wxT("\"")); // NO performance issue at all
+ statusUpdater->updateStatusText(wxString(_("Scanning ")) + wxT("\"") + dirname + wxT("\"")); //NO performance issue at all
//add 1 element to the progress indicator
- statusUpdater->updateProcessedData(1, 0); // NO performance issue at all
+ statusUpdater->updateProcessedData(1, 0); //NO performance issue at all
//trigger display refresh
statusUpdater->requestUiRefresh();
@@ -682,19 +744,19 @@ class GetAllFilesSimple : public wxDirTraverser
{
public:
GetAllFilesSimple(wxArrayString& files, wxArrayString& subDirectories) :
- allFiles(files),
- subdirs(subDirectories)
+ m_files(files),
+ m_dirs(subDirectories)
{}
wxDirTraverseResult OnDir(const wxString& dirname)
{
- subdirs.Add(dirname);
+ m_dirs.Add(dirname);
return wxDIR_CONTINUE;
}
wxDirTraverseResult OnFile(const wxString& filename)
{
- allFiles.Add(filename);
+ m_files.Add(filename);
return wxDIR_CONTINUE;
}
@@ -705,8 +767,8 @@ public:
}
private:
- wxArrayString& allFiles;
- wxArrayString& subdirs;
+ wxArrayString& m_files;
+ wxArrayString& m_dirs;
};
@@ -747,7 +809,7 @@ public:
fileOp.lpszProgressTitle = NULL;
if (SHFileOperation(&fileOp //pointer to an SHFILEOPSTRUCT structure that contains information the function needs to carry out
- ) != 0 || fileOp.fAnyOperationsAborted) throw FileError(wxString(_("Error moving file to recycle bin: ")) + wxT("\"") + filename + wxT("\""));
+ ) != 0 || fileOp.fAnyOperationsAborted) throw FileError(wxString(_("Error moving to recycle bin: ")) + wxT("\"") + filename + wxT("\""));
#endif // FFS_WIN
}
@@ -760,11 +822,11 @@ RecycleBin FreeFileSync::recycler;
inline
-void FreeFileSync::removeFile(const wxString& filename)
+void FreeFileSync::removeFile(const wxString& filename, const bool useRecycleBin)
{
if (!wxFileExists(filename)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinShouldBeUsed)
+ if (useRecycleBin)
{
recycler.moveToRecycleBin(filename);
return;
@@ -782,11 +844,11 @@ void FreeFileSync::removeFile(const wxString& filename)
}
-void FreeFileSync::removeDirectory(const wxString& directory)
+void FreeFileSync::removeDirectory(const wxString& directory, const bool useRecycleBin)
{
if (!wxDirExists(directory)) return; //this is NOT an error situation: the manual deletion relies on it!
- if (recycleBinShouldBeUsed)
+ if (useRecycleBin)
{
recycler.moveToRecycleBin(directory);
return;
@@ -805,7 +867,7 @@ void FreeFileSync::removeDirectory(const wxString& directory)
}
for (unsigned int j = 0; j < fileList.GetCount(); ++j)
- removeFile(fileList[j]);
+ removeFile(fileList[j], useRecycleBin);
dirList.Insert(directory, 0); //this directory will be deleted last
@@ -829,7 +891,7 @@ void FreeFileSync::createDirectory(const wxString& directory, int level)
if (wxDirExists(directory))
return;
- if (level == 50) //catch endless loop
+ if (level == 50) //catch endless loop
return;
//try to create directory
@@ -909,15 +971,10 @@ private:
success = true;
}
-
-#ifndef __WXDEBUG__
- //prevent wxWidgets logging
- wxLogNull noWxLogs;
-#endif
};
-void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString& target, StatusUpdater* updateClass)
+void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString& target, StatusHandler* updateClass)
{
static UpdateWhileCopying copyAndUpdate; //single instantiation: after each execution thread enters wait phase
@@ -935,12 +992,6 @@ void FreeFileSync::copyfileMultithreaded(const wxString& source, const wxString&
}
-FreeFileSync::FreeFileSync(bool useRecycleBin) :
- recycleBinShouldBeUsed(useRecycleBin) {}
-
-FreeFileSync::~FreeFileSync() {}
-
-
bool FreeFileSync::recycleBinExists()
{
return recycler.recycleBinExists();
@@ -948,7 +999,7 @@ bool FreeFileSync::recycleBinExists()
inline
-SyncDirection getSyncDirection(const CompareFilesResult cmpResult, const SyncConfiguration& config)
+SyncConfiguration::Direction getSyncDirection(const CompareFilesResult cmpResult, const SyncConfiguration& config)
{
switch (cmpResult)
{
@@ -975,7 +1026,7 @@ SyncDirection getSyncDirection(const CompareFilesResult cmpResult, const SyncCon
default:
assert (false);
}
- return SYNC_DIR_NONE;
+ return SyncConfiguration::SYNC_DIR_NONE;
}
@@ -1003,15 +1054,15 @@ bool getBytesToTransfer(int& objectsToCreate,
//get data to process
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //delete file on left
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete file on left
dataToProcess = 0;
objectsToDelete = 1;
break;
- case SYNC_DIR_RIGHT: //copy from left to right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
dataToProcess = fileCmpLine.fileDescrLeft.fileSize.ToDouble();
objectsToCreate = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1019,15 +1070,15 @@ bool getBytesToTransfer(int& objectsToCreate,
case FILE_RIGHT_SIDE_ONLY:
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
dataToProcess = fileCmpLine.fileDescrRight.fileSize.ToDouble();;
objectsToCreate = 1;
break;
- case SYNC_DIR_RIGHT: //delete file on right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete file on right
dataToProcess = 0;
objectsToDelete = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1038,15 +1089,15 @@ bool getBytesToTransfer(int& objectsToCreate,
//get data to process
switch (getSyncDirection(fileCmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
dataToProcess = fileCmpLine.fileDescrRight.fileSize.ToDouble();
objectsToOverwrite = 1;
break;
- case SYNC_DIR_RIGHT: //copy from left to right
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
dataToProcess = fileCmpLine.fileDescrLeft.fileSize.ToDouble();
objectsToOverwrite = 1;
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
}
break;
@@ -1092,32 +1143,32 @@ void FreeFileSync::calcTotalBytesToSync(int& objectsToCreate,
}
-bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater)
+bool FreeFileSync::synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater)
{ //false if nothing was to be done
assert (statusUpdater);
- if (!filename.selectedForSynchronization) return false;
+ if (!cmpLine.selectedForSynchronization) return false;
wxString target;
//synchronize file:
- switch (filename.cmpResult)
+ switch (cmpLine.cmpResult)
{
case FILE_LEFT_SIDE_ONLY:
switch (config.exLeftSideOnly)
{
- case SYNC_DIR_LEFT: //delete files on left
- statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
- removeFile(filename.fileDescrLeft.filename);
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete files on left
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
+ removeFile(cmpLine.fileDescrLeft.fullName, useRecycleBin);
break;
- case SYNC_DIR_RIGHT: //copy files to right
- target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\"") +
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy files to right
+ target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName;
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") +
_(" to ") + wxT("\"") + target + wxT("\""));
- copyfileMultithreaded(filename.fileDescrLeft.filename, target, statusUpdater);
+ copyfileMultithreaded(cmpLine.fileDescrLeft.fullName, target, statusUpdater);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1127,18 +1178,18 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
case FILE_RIGHT_SIDE_ONLY:
switch (config.exRightSideOnly)
{
- case SYNC_DIR_LEFT: //copy files to left
- target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\"") +
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy files to left
+ target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName;
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") +
_(" to ") + wxT("\"") + target + wxT("\""));
- copyfileMultithreaded(filename.fileDescrRight.filename, target, statusUpdater);
+ copyfileMultithreaded(cmpLine.fileDescrRight.fullName, target, statusUpdater);
break;
- case SYNC_DIR_RIGHT: //delete files on right
- statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
- removeFile(filename.fileDescrRight.filename);
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete files on right
+ statusUpdater->updateStatusText(wxString(_("Deleting file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
+ removeFile(cmpLine.fileDescrRight.fullName, useRecycleBin);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1148,23 +1199,23 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
case FILE_LEFT_NEWER:
case FILE_RIGHT_NEWER:
case FILE_DIFFERENT:
- switch (getSyncDirection(filename.cmpResult, config))
+ switch (getSyncDirection(cmpLine.cmpResult, config))
{
- case SYNC_DIR_LEFT: //copy from right to left
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\"") +
- _(" overwriting ") + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
+ case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\"") +
+ _(" overwriting ") + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
- removeFile(filename.fileDescrLeft.filename); //only used if switch activated by user, else file is simply deleted
- copyfileMultithreaded(filename.fileDescrRight.filename, filename.fileDescrLeft.filename, statusUpdater);
+ removeFile(cmpLine.fileDescrLeft.fullName, useRecycleBin); //only used if switch activated by user, else file is simply deleted
+ copyfileMultithreaded(cmpLine.fileDescrRight.fullName, cmpLine.fileDescrLeft.fullName, statusUpdater);
break;
- case SYNC_DIR_RIGHT: //copy from left to right
- statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\"") +
- _(" overwriting ") + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
+ case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right
+ statusUpdater->updateStatusText(wxString(_("Copying file ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\"") +
+ _(" overwriting ") + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
- removeFile(filename.fileDescrRight.filename); //only used if switch activated by user, else file is simply deleted
- copyfileMultithreaded(filename.fileDescrLeft.filename, filename.fileDescrRight.filename, statusUpdater);
+ removeFile(cmpLine.fileDescrRight.fullName, useRecycleBin); //only used if switch activated by user, else file is simply deleted
+ copyfileMultithreaded(cmpLine.fileDescrLeft.fullName, cmpLine.fileDescrRight.fullName, statusUpdater);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1181,34 +1232,34 @@ bool FreeFileSync::synchronizeFile(const FileCompareLine& filename, const SyncCo
}
-bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const SyncConfiguration& config, StatusUpdater* statusUpdater)
+bool FreeFileSync::synchronizeFolder(const FileCompareLine& cmpLine, const SyncConfiguration& config, const bool useRecycleBin, StatusHandler* statusUpdater)
{ //false if nothing was to be done
assert (statusUpdater);
- if (!filename.selectedForSynchronization) return false;
+ if (!cmpLine.selectedForSynchronization) return false;
wxString target;
//synchronize folders:
- switch (filename.cmpResult)
+ switch (cmpLine.cmpResult)
{
case FILE_LEFT_SIDE_ONLY:
switch (config.exLeftSideOnly)
{
- case SYNC_DIR_LEFT: //delete folders on left
- statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
- removeDirectory(filename.fileDescrLeft.filename);
+ case SyncConfiguration::SYNC_DIR_LEFT: //delete folders on left
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
+ removeDirectory(cmpLine.fileDescrLeft.fullName, useRecycleBin);
break;
- case SYNC_DIR_RIGHT: //create folders on right
- target = filename.fileDescrRight.directory + filename.fileDescrLeft.relFilename;
+ case SyncConfiguration::SYNC_DIR_RIGHT: //create folders on right
+ target = cmpLine.fileDescrRight.directory + cmpLine.fileDescrLeft.relativeName;
statusUpdater->updateStatusText(wxString(_("Creating folder ")) + wxT("\"") + target + wxT("\""));
//some check to catch the error that directory on source has been deleted externally after the "compare"...
- if (!wxDirExists(filename.fileDescrLeft.filename))
- throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + filename.fileDescrLeft.filename + wxT("\""));
+ if (!wxDirExists(cmpLine.fileDescrLeft.fullName))
+ throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrLeft.fullName + wxT("\""));
createDirectory(target);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1218,20 +1269,20 @@ bool FreeFileSync::synchronizeFolder(const FileCompareLine& filename, const Sync
case FILE_RIGHT_SIDE_ONLY:
switch (config.exRightSideOnly)
{
- case SYNC_DIR_LEFT: //create folders on left
- target = filename.fileDescrLeft.directory + filename.fileDescrRight.relFilename;
+ case SyncConfiguration::SYNC_DIR_LEFT: //create folders on left
+ target = cmpLine.fileDescrLeft.directory + cmpLine.fileDescrRight.relativeName;
statusUpdater->updateStatusText(wxString(_("Creating folder ")) + wxT("\"") + target + wxT("\""));
//some check to catch the error that directory on source has been deleted externally after the "compare"...
- if (!wxDirExists(filename.fileDescrRight.filename))
- throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
+ if (!wxDirExists(cmpLine.fileDescrRight.fullName))
+ throw FileError(wxString(_("Error: Source directory does not exist anymore: ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
createDirectory(target);
break;
- case SYNC_DIR_RIGHT: //delete folders on right
- statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + filename.fileDescrRight.filename + wxT("\""));
- removeDirectory(filename.fileDescrRight.filename);
+ case SyncConfiguration::SYNC_DIR_RIGHT: //delete folders on right
+ statusUpdater->updateStatusText(wxString(_("Deleting folder ")) + wxT("\"") + cmpLine.fileDescrRight.fullName + wxT("\""));
+ removeDirectory(cmpLine.fileDescrRight.fullName, useRecycleBin);
break;
- case SYNC_DIR_NONE:
+ case SyncConfiguration::SYNC_DIR_NONE:
return false;
default:
assert (false);
@@ -1333,10 +1384,10 @@ wxString FreeFileSync::formatFilesizeToShortString(const double filesize)
}
-vector<wxString> FreeFileSync::compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter)
+void compoundStringToTable(const wxString& compoundInput, const wxChar* delimiter, vector<wxString>& output)
{
+ output.clear();
wxString input(compoundInput);
- vector<wxString> output;
//make sure input ends with delimiter - no problem with empty strings here
if (!input.EndsWith(delimiter))
@@ -1358,8 +1409,6 @@ vector<wxString> FreeFileSync::compoundStringToTable(const wxString& compoundInp
}
indexStart = indexEnd + 1;
}
-
- return output;
}
@@ -1401,30 +1450,34 @@ void mergeVectors(vector<wxString>& changing, const vector<wxString>& input)
}
-void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter)
+vector<wxString> FreeFileSync::compoundStringToFilter(const wxString& filterString)
{
- //load filters into vectors
//delimiters may be ';' or '\n'
- vector<wxString> includeList;
- vector<wxString> includePreProcessing = compoundStringToTable(includeFilter, wxT(";"));
- for (vector<wxString>::const_iterator i = includePreProcessing.begin(); i != includePreProcessing.end(); ++i)
- {
- vector<wxString> newEntries = compoundStringToTable(*i, wxT("\n"));
- mergeVectors(includeList, newEntries);
- }
+ vector<wxString> filterList;
+ vector<wxString> filterPreProcessing;
+ compoundStringToTable(filterString, wxT(";"), filterPreProcessing);
- vector<wxString> excludeList;
- vector<wxString> excludePreProcessing = compoundStringToTable(excludeFilter, wxT(";"));
- for (vector<wxString>::const_iterator i = excludePreProcessing.begin(); i != excludePreProcessing.end(); ++i)
+ for (vector<wxString>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i)
{
- vector<wxString> newEntries = compoundStringToTable(*i, wxT("\n"));
- mergeVectors(excludeList, newEntries);
+ vector<wxString> newEntries;
+ compoundStringToTable(*i, wxT("\n"), newEntries);
+ mergeVectors(filterList, newEntries);
}
+ return filterList;
+}
+
+
+void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter)
+{
+ //load filter into vectors of strings
+ //delimiters may be ';' or '\n'
+ vector<wxString> includeList = FreeFileSync::compoundStringToFilter(includeFilter);
+ vector<wxString> excludeList = FreeFileSync::compoundStringToFilter(excludeFilter);
+
//format entries
for (vector<wxString>::iterator i = includeList.begin(); i != includeList.end(); ++i)
formatFilterString(*i);
-
for (vector<wxString>::iterator i = excludeList.begin(); i != excludeList.end(); ++i)
formatFilterString(*i);
@@ -1433,14 +1486,14 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
//filter currentGridData
for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i)
{
- wxString filenameLeft = i->fileDescrLeft.filename;
- wxString filenameRight = i->fileDescrRight.filename;
+ wxString filenameLeft = i->fileDescrLeft.fullName;
+ wxString filenameRight = i->fileDescrRight.fullName;
formatFilenameString(filenameLeft);
formatFilenameString(filenameRight);
//process include filters
- if (i->fileDescrLeft.objType != TYPE_NOTHING)
+ if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING)
{
bool includedLeft = false;
for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j)
@@ -1457,7 +1510,7 @@ void FreeFileSync::filterCurrentGridData(FileCompareResult& currentGridData, con
}
}
- if (i->fileDescrRight.objType != TYPE_NOTHING)
+ if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING)
{
bool includedRight = false;
for (vector<wxString>::const_iterator j = includeList.begin(); j != includeList.end(); ++j)
@@ -1524,22 +1577,22 @@ wxString FreeFileSync::getFormattedDirectoryName(const wxString& dirname)
inline
bool deletionImminent(const FileCompareLine& line, const SyncConfiguration& config)
{ //test if current sync-line will result in deletion of files -> used to avoid disc space bottlenecks
- if ((line.cmpResult == FILE_LEFT_SIDE_ONLY && config.exLeftSideOnly == SYNC_DIR_LEFT) ||
- (line.cmpResult == FILE_RIGHT_SIDE_ONLY && config.exRightSideOnly == SYNC_DIR_RIGHT))
+ if ( (line.cmpResult == FILE_LEFT_SIDE_ONLY && config.exLeftSideOnly == SyncConfiguration::SYNC_DIR_LEFT) ||
+ (line.cmpResult == FILE_RIGHT_SIDE_ONLY && config.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT))
return true;
else
return false;
}
-class AlwaysWriteResult //this class ensures, that the result of the method below is ALWAYS written on exit, even if exceptions are thrown!
+class AlwaysWriteToGrid //this class ensures, that the result of the method below is ALWAYS written on exit, even if exceptions are thrown!
{
public:
- AlwaysWriteResult(FileCompareResult& grid) :
+ AlwaysWriteToGrid(FileCompareResult& grid) :
gridToWrite(grid)
{}
- ~AlwaysWriteResult()
+ ~AlwaysWriteToGrid()
{
removeRowsFromVector(gridToWrite, rowsProcessed);
}
@@ -1556,11 +1609,15 @@ private:
//synchronizes while processing rows in grid and returns all rows that have not been synced
-void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusUpdater* statusUpdater, bool useRecycleBin)
+void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const SyncConfiguration& config, StatusHandler* statusUpdater, const bool useRecycleBin)
{
assert (statusUpdater);
- AlwaysWriteResult writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
+#ifndef __WXDEBUG__
+ wxLogNull noWxLogs; //prevent wxWidgets logging
+#endif
+
+ AlwaysWriteToGrid writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
//inform about the total amount of data that will be processed from now on
int objectsToCreate = 0;
@@ -1574,12 +1631,10 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
grid,
config);
- statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, dataToProcess, FreeFileSync::synchronizeFilesProcess);
+ statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, dataToProcess, StatusHandler::PROCESS_SYNCHRONIZING);
try
{
- FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
-
// it should never happen, that a directory on left side has same name as file on right side. startCompareProcess() should take care of this
// and split into two "exists on one side only" cases
// Note: this case is not handled by this tool as this is considered to be a bug and must be solved by the user
@@ -1587,15 +1642,17 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
//synchronize folders:
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
{
- if (i->fileDescrLeft.objType == TYPE_DIRECTORY || i->fileDescrRight.objType == TYPE_DIRECTORY)
+ if ( i->fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY ||
+ i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
{
+
while (true)
{ //trigger display refresh
statusUpdater->requestUiRefresh();
try
{
- if (fileSyncObject.synchronizeFolder(*i, config, statusUpdater))
+ if (FreeFileSync::synchronizeFolder(*i, config, useRecycleBin, statusUpdater))
//progress indicator update
//indicator is updated only if directory is synched correctly (and if some sync was done)!
statusUpdater->updateProcessedData(1, 0); //each call represents one processed file/directory
@@ -1606,11 +1663,11 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -1627,7 +1684,8 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
{
- if (i->fileDescrLeft.objType == TYPE_FILE || i->fileDescrRight.objType == TYPE_FILE)
+ if ( i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE ||
+ i->fileDescrRight.objType == FileDescrLine::TYPE_FILE)
{
if (deleteLoop && deletionImminent(*i, config) ||
!deleteLoop && !deletionImminent(*i, config))
@@ -1638,7 +1696,7 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
try
{
- if (fileSyncObject.synchronizeFile(*i, config, statusUpdater))
+ if (FreeFileSync::synchronizeFile(*i, config, useRecycleBin, statusUpdater))
{
//progress indicator update
//indicator is updated only if file is sync'ed correctly (and if some sync was done)!
@@ -1662,11 +1720,11 @@ void FreeFileSync::startSynchronizationProcess(FileCompareResult& grid, const Sy
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = statusUpdater->reportError(error.show());
- if ( rv == StatusUpdater::continueNext)
+ if ( rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue with loop
else
assert (false);
@@ -1690,27 +1748,26 @@ void FreeFileSync::addSubElements(set<int>& subElements, const FileCompareResult
{
wxString relevantDirectory;
- if (relevantRow.fileDescrLeft.objType == TYPE_DIRECTORY)
- relevantDirectory = relevantRow.fileDescrLeft.relFilename;
+ if (relevantRow.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
+ relevantDirectory = relevantRow.fileDescrLeft.relativeName + GlobalResources::fileNameSeparator; //fileNameSeparator needed to exclude subfile/dirs only
- else if (relevantRow.fileDescrRight.objType == TYPE_DIRECTORY)
- relevantDirectory = relevantRow.fileDescrRight.relFilename;
+ else if (relevantRow.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
+ relevantDirectory = relevantRow.fileDescrRight.relativeName + GlobalResources::fileNameSeparator;
else
return;
for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i)
- if ( i->fileDescrLeft.relFilename.StartsWith(relevantDirectory) ||
- i->fileDescrRight.relFilename.StartsWith(relevantDirectory))
+ if ( i->fileDescrLeft.relativeName.StartsWith(relevantDirectory) ||
+ i->fileDescrRight.relativeName.StartsWith(relevantDirectory))
subElements.insert(i - grid.begin());
}
-void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, StatusUpdater* statusUpdater, bool useRecycleBin)
+void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& rowsToDelete, ErrorHandler* errorHandler, const bool useRecycleBin)
{
- FreeFileSync fileSyncObject(useRecycleBin); //currently only needed for recycle bin and wxLog suppression => do NOT declare static!
-
- set<int> rowsToDeleteInGrid;
+ //remove deleted rows from grid
+ AlwaysWriteToGrid writeOutput(grid); //ensure that grid is always written to, even if method is exitted via exceptions
//remove from hd
for (set<int>::iterator i = rowsToDelete.begin(); i != rowsToDelete.end(); ++i)
@@ -1721,45 +1778,44 @@ void FreeFileSync::deleteOnGridAndHD(FileCompareResult& grid, const set<int>& ro
{
try
{
- if (currentCmpLine.fileDescrLeft.objType == TYPE_FILE)
- fileSyncObject.removeFile(currentCmpLine.fileDescrLeft.filename);
- else if (currentCmpLine.fileDescrLeft.objType == TYPE_DIRECTORY)
- fileSyncObject.removeDirectory(currentCmpLine.fileDescrLeft.filename);
+ if (currentCmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE)
+ FreeFileSync::removeFile(currentCmpLine.fileDescrLeft.fullName, useRecycleBin);
+ else if (currentCmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
+ FreeFileSync::removeDirectory(currentCmpLine.fileDescrLeft.fullName, useRecycleBin);
+
+ if (currentCmpLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE)
+ FreeFileSync::removeFile(currentCmpLine.fileDescrRight.fullName, useRecycleBin);
+ else if (currentCmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
+ FreeFileSync::removeDirectory(currentCmpLine.fileDescrRight.fullName, useRecycleBin);
+
+ //remove deleted row from grid
+ writeOutput.rowProcessedSuccessfully(*i);
- if (currentCmpLine.fileDescrRight.objType == TYPE_FILE)
- fileSyncObject.removeFile(currentCmpLine.fileDescrRight.filename);
- else if (currentCmpLine.fileDescrRight.objType == TYPE_DIRECTORY)
- fileSyncObject.removeDirectory(currentCmpLine.fileDescrRight.filename);
+ //retrieve all files and subfolder gridlines that are dependent from this deleted entry
+ set<int> additionalRowsToDelete;
+ addSubElements(additionalRowsToDelete, grid, grid[*i]);
+
+ //...and remove them also
+ for (set<int>::iterator j = additionalRowsToDelete.begin(); j != additionalRowsToDelete.end(); ++j)
+ writeOutput.rowProcessedSuccessfully(*j);
- rowsToDeleteInGrid.insert(*i);
break;
}
catch (FileError& error)
{
//if (updateClass) -> is mandatory
- int rv = statusUpdater->reportError(error.show());
+ ErrorHandler::Response rv = errorHandler->reportError(error.show());
- if (rv == StatusUpdater::continueNext)
+ if (rv == ErrorHandler::CONTINUE_NEXT)
break;
- else if (rv == StatusUpdater::retry)
+ else if (rv == ErrorHandler::RETRY)
; //continue in loop
else
assert (false);
}
}
}
-
- //retrieve all files and subfolder gridlines that are dependent from deleted directories and add them to the list
- set<int> additionalRowsToDelete;
- for (set<int>::iterator i = rowsToDeleteInGrid.begin(); i != rowsToDeleteInGrid.end(); ++i)
- addSubElements(additionalRowsToDelete, grid, grid[*i]);
-
- for (set<int>::iterator i = additionalRowsToDelete.begin(); i != additionalRowsToDelete.end(); ++i)
- rowsToDeleteInGrid.insert(*i);
-
- //remove deleted rows from grid
- removeRowsFromVector(grid, rowsToDeleteInGrid);
}
@@ -1780,12 +1836,12 @@ bool FreeFileSync::foldersAreValidForComparison(const vector<FolderPair>& folder
//check if folder exists
if (!wxDirExists(leftFolderName))
{
- errorMessage = wxString(_("Directory does not exist. Please select a new one: ")) + wxT("\"") + leftFolderName + wxT("\"");
+ errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + leftFolderName + wxT("\"");
return false;
}
if (!wxDirExists(rightFolderName))
{
- errorMessage = wxString(_("Directory does not exist. Please select a new one: ")) + wxT("\"") + rightFolderName + wxT("\"");
+ errorMessage = wxString(_("Directory does not exist: ")) + wxT("\"") + rightFolderName + wxT("\"");
return false;
}
}
@@ -1793,3 +1849,75 @@ bool FreeFileSync::foldersAreValidForComparison(const vector<FolderPair>& folder
}
+void FreeFileSync::adjustModificationTimes(const wxString& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler)
+{
+ if (timeInSeconds == 0)
+ return;
+
+ wxArrayString fileList;
+ wxArrayString dirList;
+
+ while (true) //own scope for directory access to not disturb file access!
+ {
+ fileList.Clear();
+ dirList.Clear();
+
+ //get all files and folders from directory (and subdirectories)
+ GetAllFilesSimple traverser(fileList, dirList);
+
+ wxDir dir(parentDirectory);
+ if (dir.Traverse(traverser) != (size_t)-1)
+ break; //traversed successfully
+ else
+ {
+ ErrorHandler::Response rv = errorHandler->reportError(wxString(_("Error traversing directory ")) + wxT("\"") + parentDirectory + wxT("\""));
+ if (rv == ErrorHandler::CONTINUE_NEXT)
+ break;
+ else if (rv == ErrorHandler::RETRY)
+ ; //continue with loop
+ else
+ assert (false);
+ }
+ }
+
+
+ //this part is only a bit slower than direct Windows API-access!
+ wxDateTime modTime;
+ for (unsigned int j = 0; j < fileList.GetCount(); ++j)
+ {
+ while (true) //own scope for directory access to not disturb file access!
+ {
+ try
+ {
+ wxFileName file(fileList[j]);
+ if (!file.GetTimes(NULL, &modTime, NULL)) //get modification time
+ throw FileError(wxString(_("Error changing modification time: ")) + wxT("\"") + fileList[j] + wxT("\""));
+
+ modTime.Add(wxTimeSpan(0, 0, timeInSeconds, 0));
+
+ if (!file.SetTimes(NULL, &modTime, NULL)) //get modification time
+ throw FileError(wxString(_("Error changing modification time: ")) + wxT("\"") + fileList[j] + wxT("\""));
+
+ break;
+ }
+ catch (const FileError& error)
+ {
+ ErrorHandler::Response rv = errorHandler->reportError(error.show());
+ if (rv == ErrorHandler::CONTINUE_NEXT)
+ break;
+ else if (rv == ErrorHandler::RETRY)
+ ; //continue with loop
+ else
+ assert (false);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
bgstack15