diff options
Diffstat (limited to 'structures.cpp')
-rw-r--r-- | structures.cpp | 284 |
1 files changed, 199 insertions, 85 deletions
diff --git a/structures.cpp b/structures.cpp index 0d16f735..98255700 100644 --- a/structures.cpp +++ b/structures.cpp @@ -8,6 +8,7 @@ #include "shared/i18n.h" #include <iterator> #include <stdexcept> +#include <ctime> using namespace zen; @@ -19,7 +20,7 @@ wxString zen::getVariantName(CompareVariant var) case CMP_BY_CONTENT: return _("File content"); case CMP_BY_TIME_SIZE: - return _("File size and date"); + return _("File time and size"); } assert(false); @@ -27,32 +28,32 @@ wxString zen::getVariantName(CompareVariant var) } -wxString zen::getVariantName(SyncConfig::Variant var) +wxString zen::getVariantName(DirectionConfig::Variant var) { switch (var) { - case SyncConfig::AUTOMATIC: + case DirectionConfig::AUTOMATIC: return _("<Automatic>"); - case SyncConfig::MIRROR: + case DirectionConfig::MIRROR: return _("Mirror ->>"); - case SyncConfig::UPDATE: + case DirectionConfig::UPDATE: return _("Update ->"); - case SyncConfig::CUSTOM: + case DirectionConfig::CUSTOM: return _("Custom"); } return _("Error"); } -DirectionSet zen::extractDirections(const SyncConfig& cfg) +DirectionSet zen::extractDirections(const DirectionConfig& cfg) { DirectionSet output; switch (cfg.var) { - case SyncConfig::AUTOMATIC: + case DirectionConfig::AUTOMATIC: throw std::logic_error("there are no predefined directions for automatic mode!"); - case SyncConfig::MIRROR: + case DirectionConfig::MIRROR: output.exLeftSideOnly = SYNC_DIR_RIGHT; output.exRightSideOnly = SYNC_DIR_RIGHT; output.leftNewer = SYNC_DIR_RIGHT; @@ -61,7 +62,7 @@ DirectionSet zen::extractDirections(const SyncConfig& cfg) output.conflict = SYNC_DIR_RIGHT; break; - case SyncConfig::UPDATE: + case DirectionConfig::UPDATE: output.exLeftSideOnly = SYNC_DIR_RIGHT; output.exRightSideOnly = SYNC_DIR_NONE; output.leftNewer = SYNC_DIR_RIGHT; @@ -70,7 +71,7 @@ DirectionSet zen::extractDirections(const SyncConfig& cfg) output.conflict = SYNC_DIR_NONE; break; - case SyncConfig::CUSTOM: + case DirectionConfig::CUSTOM: output = cfg.custom; break; } @@ -91,19 +92,39 @@ DirectionSet zen::getTwoWaySet() } -wxString MainConfiguration::getSyncVariantName() +wxString MainConfiguration::getCompVariantName() const { - const SyncConfig::Variant firstVariant = firstPair.altSyncConfig.get() ? - firstPair.altSyncConfig->syncConfiguration.var : - syncConfiguration.var; //fallback to main sync cfg + const CompareVariant firstVariant = firstPair.altCmpConfig.get() ? + firstPair.altCmpConfig->compareVar : + cmpConfig.compareVar; //fallback to main sync cfg //test if there's a deviating variant within the additional folder pairs - for (std::vector<FolderPairEnh>::const_iterator i = additionalPairs.begin(); i != additionalPairs.end(); ++i) + for (auto fp = additionalPairs.begin(); fp != additionalPairs.end(); ++fp) { - const SyncConfig::Variant thisVariant = i->altSyncConfig.get() ? - i->altSyncConfig->syncConfiguration.var : - syncConfiguration.var; + const CompareVariant thisVariant = fp->altCmpConfig.get() ? + fp->altCmpConfig->compareVar : + cmpConfig.compareVar; //fallback to main sync cfg + if (thisVariant != firstVariant) + return _("Multiple..."); + } + + //seems to be all in sync... + return getVariantName(firstVariant); +} + +wxString MainConfiguration::getSyncVariantName() const +{ + const DirectionConfig::Variant firstVariant = firstPair.altSyncConfig.get() ? + firstPair.altSyncConfig->directionCfg.var : + syncCfg.directionCfg.var; //fallback to main sync cfg + + //test if there's a deviating variant within the additional folder pairs + for (auto fp = additionalPairs.begin(); fp != additionalPairs.end(); ++fp) + { + const DirectionConfig::Variant thisVariant = fp->altSyncConfig.get() ? + fp->altSyncConfig->directionCfg.var : + syncCfg.directionCfg.var; if (thisVariant != firstVariant) return _("Multiple..."); } @@ -235,28 +256,75 @@ namespace assert_static(std::numeric_limits<zen:: Int64>::is_specialized); assert_static(std::numeric_limits<zen::UInt64>::is_specialized); + +int daysSinceBeginOfWeek(int dayOfWeek) //0-6, 0=Monday, 6=Sunday +{ + assert(0 <= dayOfWeek && dayOfWeek <= 6); +#ifdef FFS_WIN + DWORD firstDayOfWeek = 0; + if (::GetLocaleInfo(LOCALE_USER_DEFAULT, //__in LCID Locale, + LOCALE_IFIRSTDAYOFWEEK | // first day of week specifier, 0-6, 0=Monday, 6=Sunday + LOCALE_RETURN_NUMBER, //__in LCTYPE LCType, + reinterpret_cast<LPTSTR>(&firstDayOfWeek), //__out LPTSTR lpLCData, + sizeof(firstDayOfWeek) / sizeof(TCHAR)) != 0) //__in int cchData + { + assert(firstDayOfWeek <= 6); + return (dayOfWeek + (7 - firstDayOfWeek)) % 7; + } + else //default +#endif + return dayOfWeek; //let all weeks begin with monday +} + zen::Int64 resolve(size_t value, UnitTime unit, zen::Int64 defaultVal) { - double out = value; + const time_t utcTimeNow = ::time(NULL); + struct tm* localTimeFmt = ::localtime (&utcTimeNow); //utc to local + switch (unit) { case UTIME_NONE: return defaultVal; - case UTIME_SEC: - return zen::Int64(value); - case UTIME_MIN: - out *= 60; - break; - case UTIME_HOUR: - out *= 3600; - break; - case UTIME_DAY: - out *= 24 * 3600; - break; + + // case UTIME_LAST_X_HOURS: + // return Int64(utcTimeNow) - Int64(value) * 3600; + + case UTIME_TODAY: + localTimeFmt->tm_sec = 0; //0-61 + localTimeFmt->tm_min = 0; //0-59 + localTimeFmt->tm_hour = 0; //0-23 + return Int64(::mktime(localTimeFmt)); //convert local time back to UTC + + case UTIME_THIS_WEEK: + { + localTimeFmt->tm_sec = 0; //0-61 + localTimeFmt->tm_min = 0; //0-59 + localTimeFmt->tm_hour = 0; //0-23 + size_t timeFrom = ::mktime(localTimeFmt); + + int dayOfWeek = (localTimeFmt->tm_wday + 6) % 7; //tm_wday := days since Sunday 0-6 + // +6 == -1 in Z_7 + + return Int64(timeFrom) - daysSinceBeginOfWeek(dayOfWeek) * 24 * 3600; + } + case UTIME_THIS_MONTH: + localTimeFmt->tm_sec = 0; //0-61 + localTimeFmt->tm_min = 0; //0-59 + localTimeFmt->tm_hour = 0; //0-23 + localTimeFmt->tm_mday = 1; //1-31 + return Int64(::mktime(localTimeFmt)); //convert local time back to UTC + + case UTIME_THIS_YEAR: + localTimeFmt->tm_sec = 0; //0-61 + localTimeFmt->tm_min = 0; //0-59 + localTimeFmt->tm_hour = 0; //0-23 + localTimeFmt->tm_mday = 1; //1-31 + localTimeFmt->tm_mon = 0; //0-11 + return Int64(::mktime(localTimeFmt)); //convert local time back to UTC } - return out >= to<double>(std::numeric_limits<zen::Int64>::max()) ? //prevent overflow!!! - std::numeric_limits<zen::Int64>::max() : - zen::Int64(out); + + assert(false); + return utcTimeNow; } zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal) @@ -284,13 +352,13 @@ zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal) void zen::resolveUnits(size_t timeSpan, UnitTime unitTimeSpan, size_t sizeMin, UnitSize unitSizeMin, size_t sizeMax, UnitSize unitSizeMax, - zen::Int64& timeSpanSec, //unit: seconds - zen::UInt64& sizeMinBy, //unit: bytes - zen::UInt64& sizeMaxBy) //unit: bytes + zen::Int64& timeFrom, //unit: UTC time, seconds + zen::UInt64& sizeMinBy, //unit: bytes + zen::UInt64& sizeMaxBy) //unit: bytes { - timeSpanSec = resolve(timeSpan, unitTimeSpan, std::numeric_limits<zen::Int64>::max()); - sizeMinBy = resolve(sizeMin, unitSizeMin, 0U); - sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<zen::UInt64>::max()); + timeFrom = resolve(timeSpan, unitTimeSpan, std::numeric_limits<Int64>::min()); + sizeMinBy = resolve(sizeMin, unitSizeMin, 0U); + sizeMaxBy = resolve(sizeMax, unitSizeMax, std::numeric_limits<UInt64>::max()); } @@ -309,12 +377,6 @@ bool sameFilter(const std::vector<FolderPairEnh>& folderPairs) } -bool isEmpty(const FolderPairEnh& fp) -{ - return fp == FolderPairEnh(); -} - - FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& local) { FilterConfig out = local; @@ -330,28 +392,28 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l out.excludeFilter.Trim(true, false); //soft filter - zen::Int64 locTimeSpanSec; - zen::UInt64 locSizeMinBy; - zen::UInt64 locSizeMaxBy; - zen::resolveUnits(out.timeSpan, out.unitTimeSpan, - out.sizeMin, out.unitSizeMin, - out.sizeMax, out.unitSizeMax, - locTimeSpanSec, //unit: seconds - locSizeMinBy, //unit: bytes - locSizeMaxBy); //unit: bytes + Int64 loctimeFrom; + UInt64 locSizeMinBy; + UInt64 locSizeMaxBy; + resolveUnits(out.timeSpan, out.unitTimeSpan, + out.sizeMin, out.unitSizeMin, + out.sizeMax, out.unitSizeMax, + loctimeFrom, //unit: UTC time, seconds + locSizeMinBy, //unit: bytes + locSizeMaxBy); //unit: bytes //soft filter - zen::Int64 gloTimeSpanSec; - zen::UInt64 gloSizeMinBy; - zen::UInt64 gloSizeMaxBy; - zen::resolveUnits(global.timeSpan, global.unitTimeSpan, - global.sizeMin, global.unitSizeMin, - global.sizeMax, global.unitSizeMax, - gloTimeSpanSec, //unit: seconds - gloSizeMinBy, //unit: bytes - gloSizeMaxBy); //unit: bytes - - if (gloTimeSpanSec < locTimeSpanSec) + Int64 glotimeFrom; + UInt64 gloSizeMinBy; + UInt64 gloSizeMaxBy; + resolveUnits(global.timeSpan, global.unitTimeSpan, + global.sizeMin, global.unitSizeMin, + global.sizeMax, global.unitSizeMax, + glotimeFrom, + gloSizeMinBy, + gloSizeMaxBy); + + if (glotimeFrom > loctimeFrom) { out.timeSpan = global.timeSpan; out.unitTimeSpan = global.unitTimeSpan; @@ -368,60 +430,110 @@ FilterConfig mergeFilterConfig(const FilterConfig& global, const FilterConfig& l } return out; } + + +inline +bool isEmpty(const FolderPairEnh& fp) +{ + return fp == FolderPairEnh(); +} } -zen::MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs) +MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs) { assert(!mainCfgs.empty()); if (mainCfgs.empty()) - return zen::MainConfiguration(); + return MainConfiguration(); if (mainCfgs.size() == 1) //mergeConfigFilesImpl relies on this! return mainCfgs[0]; // //merge folder pair config std::vector<FolderPairEnh> fpMerged; - for (std::vector<MainConfiguration>::const_iterator i = mainCfgs.begin(); i != mainCfgs.end(); ++i) + for (std::vector<MainConfiguration>::const_iterator iterMain = mainCfgs.begin(); iterMain != mainCfgs.end(); ++iterMain) { std::vector<FolderPairEnh> fpTmp; //list non-empty local configurations - if (!isEmpty(i->firstPair)) fpTmp.push_back(i->firstPair); - std::remove_copy_if(i->additionalPairs.begin(), i->additionalPairs.end(), std::back_inserter(fpTmp), &isEmpty); + if (!isEmpty(iterMain->firstPair)) + fpTmp.push_back(iterMain->firstPair); + std::copy_if(iterMain->additionalPairs.begin(), iterMain->additionalPairs.end(), std::back_inserter(fpTmp), + [](const FolderPairEnh& fp) { return !isEmpty(fp); }); //move all configuration down to item level for (std::vector<FolderPairEnh>::iterator fp = fpTmp.begin(); fp != fpTmp.end(); ++fp) { + if (!fp->altCmpConfig.get()) + fp->altCmpConfig = std::make_shared<CompConfig>(iterMain->cmpConfig); + if (!fp->altSyncConfig.get()) - fp->altSyncConfig.reset( - new AlternateSyncConfig(i->syncConfiguration, - i->handleDeletion, - i->customDeletionDirectory)); + fp->altSyncConfig = std::make_shared<SyncConfig>(iterMain->syncCfg); - fp->localFilter = mergeFilterConfig(i->globalFilter, fp->localFilter); + fp->localFilter = mergeFilterConfig(iterMain->globalFilter, fp->localFilter); } fpMerged.insert(fpMerged.end(), fpTmp.begin(), fpTmp.end()); } if (fpMerged.empty()) - return zen::MainConfiguration(); + return MainConfiguration(); //optimization: remove redundant configuration - FilterConfig newGlobalFilter; + //######################################################################################################################## + //find out which comparison and synchronization setting are used most often and use them as new "header" + std::vector<std::pair<CompConfig, int>> cmpCfgStat; + std::vector<std::pair<SyncConfig, int>> syncCfgStat; + for (auto fp = fpMerged.begin(); fp != fpMerged.end(); ++fp) //rather inefficient algorithm, but it does not require a less-than operator! + { + { + const CompConfig& cmpCfg = *fp->altCmpConfig; + + auto iter = std::find_if(cmpCfgStat.begin(), cmpCfgStat.end(), + [&](const std::pair<CompConfig, int>& entry) { return entry.first == cmpCfg; }); + if (iter == cmpCfgStat.end()) + cmpCfgStat.push_back(std::make_pair(cmpCfg, 1)); + else + ++(iter->second); + } + { + const SyncConfig& syncCfg = *fp->altSyncConfig; + + auto iter = std::find_if(syncCfgStat.begin(), syncCfgStat.end(), + [&](const std::pair<SyncConfig, int>& entry) { return entry.first == syncCfg; }); + if (iter == syncCfgStat.end()) + syncCfgStat.push_back(std::make_pair(syncCfg, 1)); + else + ++(iter->second); + } + } + + //set most-used comparison and synchronization settions as new header options + const CompConfig cmpCfgHead = cmpCfgStat.empty() ? CompConfig() : + std::max_element(cmpCfgStat.begin(), cmpCfgStat.end(), + [](const std::pair<CompConfig, int>& lhs, const std::pair<CompConfig, int>& rhs) { return lhs.second < rhs.second; })->first; + + const SyncConfig syncCfgHead = syncCfgStat.empty() ? SyncConfig() : + std::max_element(syncCfgStat.begin(), syncCfgStat.end(), + [](const std::pair<SyncConfig, int>& lhs, const std::pair<SyncConfig, int>& rhs) { return lhs.second < rhs.second; })->first; + //######################################################################################################################## + + FilterConfig globalFilter; const bool equalFilters = sameFilter(fpMerged); if (equalFilters) - newGlobalFilter = fpMerged[0].localFilter; + globalFilter = fpMerged[0].localFilter; + //strip redundancy... for (std::vector<FolderPairEnh>::iterator fp = fpMerged.begin(); fp != fpMerged.end(); ++fp) { //if local config matches output global config we don't need local one + if (fp->altCmpConfig && + *fp->altCmpConfig == cmpCfgHead) + fp->altCmpConfig.reset(); + if (fp->altSyncConfig && - *fp->altSyncConfig == AlternateSyncConfig(mainCfgs[0].syncConfiguration, - mainCfgs[0].handleDeletion, - mainCfgs[0].customDeletionDirectory)) + *fp->altSyncConfig == syncCfgHead) fp->altSyncConfig.reset(); if (equalFilters) //use global filter in this case @@ -429,9 +541,11 @@ zen::MainConfiguration zen::merge(const std::vector<MainConfiguration>& mainCfgs } //final assembly - zen::MainConfiguration cfgOut = mainCfgs[0]; - cfgOut.globalFilter = newGlobalFilter; - cfgOut.firstPair = fpMerged[0]; + zen::MainConfiguration cfgOut; + cfgOut.cmpConfig = cmpCfgHead; + cfgOut.syncCfg = syncCfgHead; + cfgOut.globalFilter = globalFilter; + cfgOut.firstPair = fpMerged[0]; cfgOut.additionalPairs.assign(fpMerged.begin() + 1, fpMerged.end()); return cfgOut; |