diff options
Diffstat (limited to 'algorithm.cpp')
-rw-r--r-- | algorithm.cpp | 346 |
1 files changed, 85 insertions, 261 deletions
diff --git a/algorithm.cpp b/algorithm.cpp index 00357e9d..c595bdd3 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -3,6 +3,10 @@ #include <cmath> #include <wx/log.h> #include "library/resources.h" +#include "library/globalFunctions.h" +#include "library/statusHandler.h" +#include "library/fileHandling.h" +#include <wx/msgdlg.h> #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -15,36 +19,47 @@ using namespace FreeFileSync; -wxString FreeFileSync::formatFilesizeToShortString(const wxULongLong& filesize) +wxString FreeFileSync::formatFilesizeToShortString(const wxLongLong& filesize) { - return formatFilesizeToShortString(filesize.ToDouble()); + return FreeFileSync::formatFilesizeToShortString(filesize.ToDouble()); } +wxString FreeFileSync::formatFilesizeToShortString(const wxULongLong& filesize) +{ + return FreeFileSync::formatFilesizeToShortString(filesize.ToDouble()); +}; + + wxString FreeFileSync::formatFilesizeToShortString(const double filesize) { + if (filesize < 0) + return _("Error"); + double nrOfBytes = filesize; + bool unitByte = true; wxString unit = _(" Byte"); if (nrOfBytes > 999) { - nrOfBytes/= 1024; + unitByte = false; + nrOfBytes /= 1024; unit = _(" kB"); if (nrOfBytes > 999) { - nrOfBytes/= 1024; + nrOfBytes /= 1024; unit = _(" MB"); if (nrOfBytes > 999) { - nrOfBytes/= 1024; + nrOfBytes /= 1024; unit = _(" GB"); if (nrOfBytes > 999) { - nrOfBytes/= 1024; + nrOfBytes /= 1024; unit = _(" TB"); if (nrOfBytes > 999) { - nrOfBytes/= 1024; + nrOfBytes /= 1024; unit = _(" PB"); } } @@ -53,7 +68,7 @@ wxString FreeFileSync::formatFilesizeToShortString(const double filesize) } wxString temp; - if (unit == _(" Byte")) //no decimal places in case of bytes + if (unitByte) //no decimal places in case of bytes { double integer = 0; modf(nrOfBytes, &integer); //get integer part of nrOfBytes @@ -67,9 +82,7 @@ wxString FreeFileSync::formatFilesizeToShortString(const double filesize) temp = globalFunctions::numberToWxString(int(integer)); - int length = temp.Len(); - - switch (length) + switch (temp.length()) { case 0: return _("Error"); @@ -116,22 +129,28 @@ Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) } -void FreeFileSync::swapGrids(FileCompareResult& grid) +void FreeFileSync::swapGrids(FolderComparison& folderCmp) { - for (FileCompareResult::iterator i = grid.begin(); i != grid.end(); ++i) + for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) { - //swap compare result - if (i->cmpResult == FILE_LEFT_SIDE_ONLY) - i->cmpResult = FILE_RIGHT_SIDE_ONLY; - else if (i->cmpResult == FILE_RIGHT_SIDE_ONLY) - i->cmpResult = FILE_LEFT_SIDE_ONLY; - else if (i->cmpResult == FILE_RIGHT_NEWER) - i->cmpResult = FILE_LEFT_NEWER; - else if (i->cmpResult == FILE_LEFT_NEWER) - i->cmpResult = FILE_RIGHT_NEWER; - - //swap file descriptors - std::swap(i->fileDescrLeft, i->fileDescrRight); + std::swap(j->syncPair.leftDirectory, j->syncPair.rightDirectory); + + FileComparison& fileCmp = j->fileCmp; + for (FileComparison::iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) + { + //swap compare result + if (i->cmpResult == FILE_LEFT_SIDE_ONLY) + i->cmpResult = FILE_RIGHT_SIDE_ONLY; + else if (i->cmpResult == FILE_RIGHT_SIDE_ONLY) + i->cmpResult = FILE_LEFT_SIDE_ONLY; + else if (i->cmpResult == FILE_RIGHT_NEWER) + i->cmpResult = FILE_LEFT_NEWER; + else if (i->cmpResult == FILE_LEFT_NEWER) + i->cmpResult = FILE_RIGHT_NEWER; + + //swap file descriptors + std::swap(i->fileDescrLeft, i->fileDescrRight); + } } } @@ -201,232 +220,40 @@ void FreeFileSync::adjustModificationTimes(const Zstring& parentDirectory, const } */ -void compoundStringToTable(const Zstring& compoundInput, const DefaultChar* delimiter, std::vector<Zstring>& output) -{ - output.clear(); - Zstring input(compoundInput); - - //make sure input ends with delimiter - no problem with empty strings here - if (!input.EndsWith(delimiter)) - input += delimiter; - - unsigned int indexStart = 0; - unsigned int indexEnd = 0; - while ((indexEnd = input.find(delimiter, indexStart)) != Zstring::npos) - { - if (indexStart != indexEnd) //do not add empty strings - { - Zstring newEntry = input.substr(indexStart, indexEnd - indexStart); - - newEntry.Trim(true); //remove whitespace characters from right - newEntry.Trim(false); //remove whitespace characters from left - - if (!newEntry.empty()) - output.push_back(newEntry); - } - indexStart = indexEnd + 1; - } -} - - -inline -void mergeVectors(std::vector<Zstring>& changing, const std::vector<Zstring>& input) -{ - for (std::vector<Zstring>::const_iterator i = input.begin(); i != input.end(); ++i) - changing.push_back(*i); -} - - -std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) -{ - //delimiters may be ';' or '\n' - std::vector<Zstring> filterList; - std::vector<Zstring> filterPreProcessing; - compoundStringToTable(filterString, wxT(";"), filterPreProcessing); - for (std::vector<Zstring>::const_iterator i = filterPreProcessing.begin(); i != filterPreProcessing.end(); ++i) - { - std::vector<Zstring> newEntries; - compoundStringToTable(*i, wxT("\n"), newEntries); - mergeVectors(filterList, newEntries); - } - - return filterList; -} - - -inline -void formatFilterString(Zstring& filter) -{ -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - filter.MakeLower(); -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case -//nothing to do here -#else - adapt; -#endif -} - - -void FreeFileSync::filterGridData(FileCompareResult& currentGridData, const wxString& includeFilter, const wxString& excludeFilter) +//add(!) all files and subfolder gridlines that are dependent from the directory +void FreeFileSync::addSubElements(const FileComparison& fileCmp, const FileCompareLine& relevantRow, std::set<int>& subElements) { - //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!! - - //load filter into vectors of strings - //delimiters may be ';' or '\n' - std::vector<Zstring> includeList = compoundStringToFilter(includeFilter.c_str()); - std::vector<Zstring> excludeList = compoundStringToFilter(excludeFilter.c_str()); - - //format entries - for (std::vector<Zstring>::iterator i = includeList.begin(); i != includeList.end(); ++i) - formatFilterString(*i); - for (std::vector<Zstring>::iterator i = excludeList.begin(); i != excludeList.end(); ++i) - formatFilterString(*i); + const FileDescrLine& relFileDescrLeft = relevantRow.fileDescrLeft; + const FileDescrLine& relFileDescrRight = relevantRow.fileDescrRight; + + Zstring relevantDirectory; + if (relFileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) + relevantDirectory = Zstring(relFileDescrLeft.relativeName.c_str(), relFileDescrLeft.relativeName.length()); + else if (relFileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) + relevantDirectory = Zstring(relFileDescrRight.relativeName.c_str(), relFileDescrRight.relativeName.length()); + else + return; -//############################################################## + relevantDirectory += GlobalResources::FILE_NAME_SEPARATOR; //FILE_NAME_SEPARATOR needed to exclude subfile/dirs only - //filter currentGridData - for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) + for (FileComparison::const_iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) { - Zstring filenameLeft = i->fileDescrLeft.fullName; - Zstring filenameRight = i->fileDescrRight.fullName; - - formatFilterString(filenameLeft); - formatFilterString(filenameRight); - - //process include filters if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) { - bool includedLeft = false; - for (std::vector<Zstring>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) - if (filenameLeft.Matches(*j)) - { - includedLeft = true; - break; - } - - if (!includedLeft) - { - i->selectedForSynchronization = false; - continue; - } + if (i->fileDescrLeft.relativeName.StartsWith(relevantDirectory)) + subElements.insert(i - fileCmp.begin()); } - - if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) + //"else if": no need to do a redundant check on both sides: relative names should be the same! + else if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) { - bool includedRight = false; - for (std::vector<Zstring>::const_iterator j = includeList.begin(); j != includeList.end(); ++j) - if (filenameRight.Matches(*j)) - { - includedRight = true; - break; - } - - if (!includedRight) - { - i->selectedForSynchronization = false; - continue; - } - } - - //process exclude filters - if (i->fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) - { - bool excluded = false; - for (std::vector<Zstring>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) - if (filenameLeft.Matches(*j)) - { - excluded = true; - break; - } - - if (excluded) - { - i->selectedForSynchronization = false; - continue; - } - } - - if (i->fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) - { - bool excluded = false; - for (std::vector<Zstring>::const_iterator j = excludeList.begin(); j != excludeList.end(); ++j) - if (filenameRight.Matches(*j)) - { - excluded = true; - break; - } - - if (excluded) - { - i->selectedForSynchronization = false; - continue; - } - } - - i->selectedForSynchronization = true; - } -} - - -void FreeFileSync::includeAllRowsOnGrid(FileCompareResult& currentGridData) -{ - //remove all filters on currentGridData - for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) - i->selectedForSynchronization = true; -} - - -void FreeFileSync::excludeAllRowsOnGrid(FileCompareResult& currentGridData) -{ - //exclude all rows on currentGridData - for (FileCompareResult::iterator i = currentGridData.begin(); i != currentGridData.end(); ++i) - i->selectedForSynchronization = false; -} - - -//add(!) all files and subfolder gridlines that are dependent from the directory -template <bool searchLeftSide> -void addSubElementsOneSide(const FileCompareResult& grid, const FileCompareLine& relevantRow, std::set<int>& subElements) -{ - const FileDescrLine* fileDescr = NULL; //get descriptor for file to be deleted; evaluated at compile time - if (searchLeftSide) - fileDescr = &relevantRow.fileDescrLeft; - else - fileDescr = &relevantRow.fileDescrRight; - - if (fileDescr->objType == FileDescrLine::TYPE_DIRECTORY) - { - Zstring relevantDirectory(fileDescr->relativeName.c_str(), fileDescr->relativeName.length()); - relevantDirectory += GlobalResources::FILE_NAME_SEPARATOR; //FILE_NAME_SEPARATOR needed to exclude subfile/dirs only - - for (FileCompareResult::const_iterator i = grid.begin(); i != grid.end(); ++i) - { - if (searchLeftSide) //evaluated at compile time - { - if (i->fileDescrLeft.relativeName.StartsWith(relevantDirectory)) - subElements.insert(i - grid.begin()); - } - else - { - if (i->fileDescrRight.relativeName.StartsWith(relevantDirectory)) - subElements.insert(i - grid.begin()); - } + if (i->fileDescrRight.relativeName.StartsWith(relevantDirectory)) + subElements.insert(i - fileCmp.begin()); } } } -//add(!) all files and subfolder gridlines that are dependent from the directory -void FreeFileSync::addSubElements(const FileCompareResult& grid, const FileCompareLine& relevantRow, std::set<int>& subElements) -{ - addSubElementsOneSide<true>(grid, relevantRow, subElements); - addSubElementsOneSide<false>(grid, relevantRow, subElements); -} - - //############################################################################################################ struct SortedFileName { @@ -441,7 +268,7 @@ struct SortedFileName //assemble message containing all files to be deleted -wxString FreeFileSync::deleteFromGridAndHDPreview(const FileCompareResult& grid, +wxString FreeFileSync::deleteFromGridAndHDPreview(const FileComparison& fileCmp, const std::set<int>& rowsToDeleteOnLeft, const std::set<int>& rowsToDeleteOnRight, const bool deleteOnBothSides) @@ -456,7 +283,7 @@ wxString FreeFileSync::deleteFromGridAndHDPreview(const FileCompareResult& grid, wxString filesToDelete; for (std::set<int>::const_iterator i = rowsToDelete.begin(); i != rowsToDelete.end(); ++i) { - const FileCompareLine& currentCmpLine = grid[*i]; + const FileCompareLine& currentCmpLine = fileCmp[*i]; if (currentCmpLine.fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) filesToDelete += (currentCmpLine.fileDescrLeft.fullName + wxT("\n")).c_str(); @@ -476,7 +303,7 @@ wxString FreeFileSync::deleteFromGridAndHDPreview(const FileCompareResult& grid, SortedFileName newEntry; for (std::set<int>::const_iterator i = rowsToDeleteOnLeft.begin(); i != rowsToDeleteOnLeft.end(); ++i) { - const FileCompareLine& currentCmpLine = grid[*i]; + const FileCompareLine& currentCmpLine = fileCmp[*i]; if (currentCmpLine.fileDescrLeft.objType != FileDescrLine::TYPE_NOTHING) { @@ -488,7 +315,7 @@ wxString FreeFileSync::deleteFromGridAndHDPreview(const FileCompareResult& grid, for (std::set<int>::const_iterator i = rowsToDeleteOnRight.begin(); i != rowsToDeleteOnRight.end(); ++i) { - const FileCompareLine& currentCmpLine = grid[*i]; + const FileCompareLine& currentCmpLine = fileCmp[*i]; if (currentCmpLine.fileDescrRight.objType != FileDescrLine::TYPE_NOTHING) { @@ -510,8 +337,8 @@ wxString FreeFileSync::deleteFromGridAndHDPreview(const FileCompareResult& grid, class RemoveAtExit //this class ensures, that the result of the method below is ALWAYS written on exit, even if exceptions are thrown! { public: - RemoveAtExit(FileCompareResult& grid) : - gridToWrite(grid) {} + RemoveAtExit(FileComparison& fileCmp) : + gridToWrite(fileCmp) {} ~RemoveAtExit() { @@ -524,7 +351,7 @@ public: } private: - FileCompareResult& gridToWrite; + FileComparison& gridToWrite; std::set<int> rowsProcessed; }; @@ -533,8 +360,8 @@ template <bool leftSide> //update compareGrid row information after deletion fro inline void updateCmpLineAfterDeletion(FileCompareLine& relevantRow, const int rowNr, RemoveAtExit& markForRemoval) { - FileDescrLine* fileDescr = NULL; //get descriptor for file to be deleted; evaluated at compile time - FileDescrLine* fileDescrPartner = NULL; //file descriptor for "other side" + FileDescrLine* fileDescr; //get descriptor for file to be deleted; evaluated at compile time + FileDescrLine* fileDescrPartner; //file descriptor for "other side" if (leftSide) { fileDescr = &relevantRow.fileDescrLeft; @@ -553,9 +380,7 @@ void updateCmpLineAfterDeletion(FileCompareLine& relevantRow, const int rowNr, R else { //initialize fileDescr for deleted file/folder - const Zstring saveDir = fileDescr->directory; *fileDescr = FileDescrLine(); - fileDescr->directory = saveDir; //adapt the compare result if (leftSide) //again evaluated at compile time @@ -567,7 +392,7 @@ void updateCmpLineAfterDeletion(FileCompareLine& relevantRow, const int rowNr, R template <bool leftSide> -void deleteFromGridAndHDOneSide(FileCompareResult& grid, +void deleteFromGridAndHDOneSide(FileComparison& fileCmp, const std::set<int>& rowsToDeleteOneSide, const bool useRecycleBin, RemoveAtExit& markForRemoval, @@ -575,7 +400,7 @@ void deleteFromGridAndHDOneSide(FileCompareResult& grid, { for (std::set<int>::iterator i = rowsToDeleteOneSide.begin(); i != rowsToDeleteOneSide.end(); ++i) { - FileCompareLine& currentCmpLine = grid[*i]; + FileCompareLine& currentCmpLine = fileCmp[*i]; FileDescrLine* fileDescr = NULL; //get descriptor for file to be deleted; evaluated at compile time if (leftSide) @@ -602,17 +427,16 @@ void deleteFromGridAndHDOneSide(FileCompareResult& grid, //retrieve all files and subfolder gridlines that are dependent from this deleted entry std::set<int> rowsToDelete; rowsToDelete.insert(*i); - addSubElementsOneSide<leftSide>(grid, grid[*i], rowsToDelete); + FreeFileSync::addSubElements(fileCmp, currentCmpLine, rowsToDelete); - //remove deleted entries from grid (or adapt it if deleted from one side only) + //remove deleted entries from fileCmp (or adapt it if deleted from one side only) for (std::set<int>::iterator j = rowsToDelete.begin(); j != rowsToDelete.end(); ++j) - updateCmpLineAfterDeletion<leftSide>(grid[*j], *j, markForRemoval); + updateCmpLineAfterDeletion<leftSide>(fileCmp[*j], *j, markForRemoval); break; } catch (const FileError& error) { - //if (updateClass) -> is mandatory ErrorHandler::Response rv = errorHandler->reportError(error.show()); if (rv == ErrorHandler::IGNORE_ERROR) @@ -628,15 +452,15 @@ void deleteFromGridAndHDOneSide(FileCompareResult& grid, } -void FreeFileSync::deleteFromGridAndHD(FileCompareResult& grid, +void FreeFileSync::deleteFromGridAndHD(FileComparison& fileCmp, const std::set<int>& rowsToDeleteOnLeft, const std::set<int>& rowsToDeleteOnRight, const bool deleteOnBothSides, const bool useRecycleBin, ErrorHandler* errorHandler) { - //remove deleted rows from grid (AFTER all rows to be deleted are known: consider row references! - RemoveAtExit markForRemoval(grid); //ensure that grid is always written to, even if method is exitted via exceptions + //remove deleted rows from fileCmp (AFTER all rows to be deleted are known: consider row references! + RemoveAtExit markForRemoval(fileCmp); //ensure that fileCmp is always written to, even if method is exitted via exceptions if (deleteOnBothSides) { @@ -645,13 +469,13 @@ void FreeFileSync::deleteFromGridAndHD(FileCompareResult& grid, for (std::set<int>::const_iterator i = rowsToDeleteOnRight.begin(); i != rowsToDeleteOnRight.end(); ++i) rowsToDeleteBothSides.insert(*i); - deleteFromGridAndHDOneSide<true>(grid, + deleteFromGridAndHDOneSide<true>(fileCmp, rowsToDeleteBothSides, useRecycleBin, markForRemoval, errorHandler); - deleteFromGridAndHDOneSide<false>(grid, + deleteFromGridAndHDOneSide<false>(fileCmp, rowsToDeleteBothSides, useRecycleBin, markForRemoval, @@ -659,13 +483,13 @@ void FreeFileSync::deleteFromGridAndHD(FileCompareResult& grid, } else { - deleteFromGridAndHDOneSide<true>(grid, + deleteFromGridAndHDOneSide<true>(fileCmp, rowsToDeleteOnLeft, useRecycleBin, markForRemoval, errorHandler); - deleteFromGridAndHDOneSide<false>(grid, + deleteFromGridAndHDOneSide<false>(fileCmp, rowsToDeleteOnRight, useRecycleBin, markForRemoval, |