summaryrefslogtreecommitdiff
path: root/file_hierarchy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'file_hierarchy.cpp')
-rw-r--r--file_hierarchy.cpp222
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;
+}
bgstack15