diff options
Diffstat (limited to 'file_hierarchy.cpp')
-rw-r--r-- | file_hierarchy.cpp | 222 |
1 files changed, 101 insertions, 121 deletions
diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp index 3b0f5a04..b3264c31 100644 --- a/file_hierarchy.cpp +++ b/file_hierarchy.cpp @@ -9,102 +9,35 @@ using namespace zen; -namespace -{ -struct LowerID -{ - bool operator()(const FileSystemObject& a, HierarchyObject::ObjectID b) const - { - return a.getId() < b; - } - - bool operator()(const FileSystemObject& a, const FileSystemObject& b) const //used by VC++ - { - return a.getId() < b.getId(); - } - bool operator()(HierarchyObject::ObjectID a, const FileSystemObject& b) const - { - return a < b.getId(); - } -}; -} - - -const FileSystemObject* HierarchyObject::retrieveById(ObjectID id) const //returns NULL if object is not found +void HierarchyObject::removeEmptyRec() { - //ATTENTION: HierarchyObject::retrieveById() can only work correctly if the following conditions are fulfilled: - //1. on each level, files are added first, symlinks, then directories (=> file id < link id < dir id) - //2. when a directory is added, all subdirectories must be added immediately (recursion) before the next dir on this level is added - //3. entries may be deleted but NEVER new ones inserted!!! - //=> this allows for a quasi-binary search by id! - - //See MergeSides::execute()! - - - //search within sub-files - SubFileMapping::const_iterator i = std::lower_bound(subFiles.begin(), subFiles.end(), id, LowerID()); //binary search! - if (i != subFiles.end()) + bool haveEmpty = false; + auto isEmpty = [&](const FileSystemObject& fsObj) -> bool { - //id <= i - if (LowerID()(id, *i)) - return NULL; // --i < id < i - else //id found - return &(*i); - } - - //search within sub-symlinks - SubLinkMapping::const_iterator j = std::lower_bound(subLinks.begin(), subLinks.end(), id, LowerID()); //binary search! - if (j != subLinks.end()) - { - //id <= i - if (LowerID()(id, *j)) - return NULL; // --i < id < i - else //id found - return &(*j); - } - - //search within sub-directories - SubDirMapping::const_iterator k = std::lower_bound(subDirs.begin(), subDirs.end(), id, LowerID()); //binary search! - if (k != subDirs.end() && !LowerID()(id, *k)) //id == j - return &(*k); - else if (k == subDirs.begin()) //either begin() == end() or id < begin() - return NULL; - else - return (--k)->retrieveById(id); //j != begin() and id < j -} - + bool objEmpty = fsObj.isEmpty(); + if (objEmpty) + haveEmpty = true; + return objEmpty; + }; -template <class V, class Predicate> inline -void vector_remove_if(V& vec, Predicate p) -{ - vec.erase(std::remove_if(vec.begin(), vec.end(), p), vec.end()); -} - - -void removeEmptyRec(HierarchyObject& hierObj) -{ - auto isEmpty = [](const FileSystemObject& fsObj) { return fsObj.isEmpty(); }; + refSubFiles().remove_if(isEmpty); + refSubLinks().remove_if(isEmpty); + refSubDirs ().remove_if(isEmpty); - vector_remove_if(hierObj.refSubFiles(), isEmpty); - vector_remove_if(hierObj.refSubLinks(), isEmpty); - vector_remove_if(hierObj.refSubDirs (), isEmpty); + if (haveEmpty) //notify if actual deletion happened + notifySyncCfgChanged(); //mustn't call this in ~FileSystemObject(), since parent, usually a DirMapping, is already partially destroyed and existing as a pure HierarchyObject! //recurse - std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), removeEmptyRec); -} - - -void BaseDirMapping::removeEmpty(BaseDirMapping& baseDir) -{ - removeEmptyRec(baseDir); + std::for_each(refSubDirs().begin(), refSubDirs().end(), std::mem_fun_ref(&HierarchyObject::removeEmptyRec)); } SyncOperation FileSystemObject::getSyncOperation( CompareFilesResult cmpResult, bool selectedForSynchronization, - SyncDirectionIntern syncDir) + SyncDirection syncDir, + const std::wstring& syncDirConflict) { if (!selectedForSynchronization) return cmpResult == FILE_EQUAL ? @@ -116,78 +49,125 @@ SyncOperation FileSystemObject::getSyncOperation( case FILE_LEFT_SIDE_ONLY: switch (syncDir) { - case SYNC_DIR_INT_LEFT: + case SYNC_DIR_LEFT: return SO_DELETE_LEFT; //delete files on left - case SYNC_DIR_INT_RIGHT: + case SYNC_DIR_RIGHT: return SO_CREATE_NEW_RIGHT; //copy files to right - case SYNC_DIR_INT_NONE: - return SO_DO_NOTHING; - case SYNC_DIR_INT_CONFLICT: - return SO_UNRESOLVED_CONFLICT; + case SYNC_DIR_NONE: + return syncDirConflict.empty() ? SO_DO_NOTHING : SO_UNRESOLVED_CONFLICT; } break; case FILE_RIGHT_SIDE_ONLY: switch (syncDir) { - case SYNC_DIR_INT_LEFT: + case SYNC_DIR_LEFT: return SO_CREATE_NEW_LEFT; //copy files to left - case SYNC_DIR_INT_RIGHT: + case SYNC_DIR_RIGHT: return SO_DELETE_RIGHT; //delete files on right - case SYNC_DIR_INT_NONE: - return SO_DO_NOTHING; - case SYNC_DIR_INT_CONFLICT: - return SO_UNRESOLVED_CONFLICT; + case SYNC_DIR_NONE: + return syncDirConflict.empty() ? SO_DO_NOTHING : SO_UNRESOLVED_CONFLICT; } break; case FILE_LEFT_NEWER: case FILE_RIGHT_NEWER: case FILE_DIFFERENT: - switch (syncDir) - { - case SYNC_DIR_INT_LEFT: - return SO_OVERWRITE_LEFT; //copy from right to left - case SYNC_DIR_INT_RIGHT: - return SO_OVERWRITE_RIGHT; //copy from left to right - case SYNC_DIR_INT_NONE: - return SO_DO_NOTHING; - case SYNC_DIR_INT_CONFLICT: - return SO_UNRESOLVED_CONFLICT; - } - break; - case FILE_CONFLICT: switch (syncDir) { - case SYNC_DIR_INT_LEFT: + case SYNC_DIR_LEFT: return SO_OVERWRITE_LEFT; //copy from right to left - case SYNC_DIR_INT_RIGHT: + case SYNC_DIR_RIGHT: return SO_OVERWRITE_RIGHT; //copy from left to right - case SYNC_DIR_INT_NONE: - case SYNC_DIR_INT_CONFLICT: - return SO_UNRESOLVED_CONFLICT; + case SYNC_DIR_NONE: + return syncDirConflict.empty() ? SO_DO_NOTHING : SO_UNRESOLVED_CONFLICT; } break; case FILE_DIFFERENT_METADATA: switch (syncDir) { - case SYNC_DIR_INT_LEFT: + case SYNC_DIR_LEFT: return SO_COPY_METADATA_TO_LEFT; - case SYNC_DIR_INT_RIGHT: + case SYNC_DIR_RIGHT: return SO_COPY_METADATA_TO_RIGHT; - case SYNC_DIR_INT_NONE: - return SO_DO_NOTHING; - case SYNC_DIR_INT_CONFLICT: - return SO_UNRESOLVED_CONFLICT; + case SYNC_DIR_NONE: + return syncDirConflict.empty() ? SO_DO_NOTHING : SO_UNRESOLVED_CONFLICT; } break; case FILE_EQUAL: - assert(syncDir == SYNC_DIR_INT_NONE); + assert(syncDir == SYNC_DIR_NONE); return SO_EQUAL; } return SO_DO_NOTHING; //dummy -}
\ No newline at end of file +} + + +namespace +{ +template <class Predicate> inline +bool hasDirectChild(const HierarchyObject& hierObj, Predicate p) +{ + return std::find_if(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), p) != hierObj.refSubFiles().end() || + std::find_if(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), p) != hierObj.refSubLinks().end() || + std::find_if(hierObj.refSubDirs(). begin(), hierObj.refSubDirs(). end(), p) != hierObj.refSubDirs ().end(); +} +} + + +SyncOperation DirMapping::getSyncOperation() const +{ + if (!syncOpUpToDate) + { + syncOpUpToDate = true; + //redetermine... + + //suggested operation for directory only + syncOpBuffered = FileSystemObject::getSyncOperation(); + + //action for child elements may occassionally have to overwrite parent task: + switch (syncOpBuffered) + { + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + assert(false); + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + case SO_EQUAL: + break; //take over suggestion, no problem for child-elements + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + case SO_DO_NOTHING: + case SO_UNRESOLVED_CONFLICT: + { + if (isEmpty<LEFT_SIDE>()) + { + //1. if at least one child-element is to be created, make sure parent folder is created also + //note: this automatically fulfills "create parent folders even if excluded"; + //see http://sourceforge.net/tracker/index.php?func=detail&aid=2628943&group_id=234430&atid=1093080 + if (hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() == SO_CREATE_NEW_LEFT; })) + syncOpBuffered = SO_CREATE_NEW_LEFT; + //2. cancel parent deletion if only a single child is not also scheduled for deletion + else if (syncOpBuffered == SO_DELETE_RIGHT && + hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() != SO_DELETE_RIGHT; })) + syncOpBuffered = SO_DO_NOTHING; + } + else if (isEmpty<RIGHT_SIDE>()) + { + if (hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() == SO_CREATE_NEW_RIGHT; })) + syncOpBuffered = SO_CREATE_NEW_RIGHT; + else if (syncOpBuffered == SO_DELETE_LEFT && + hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() != SO_DELETE_LEFT; })) + syncOpBuffered = SO_DO_NOTHING; + } + } + break; + } + } + return syncOpBuffered; +} |