summaryrefslogtreecommitdiff
path: root/file_hierarchy.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:16:21 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:16:21 +0200
commit88a2d0007db222c339f0b6a17794a2014a241892 (patch)
tree75105ef49b3a52b7ee176a1ad480e7652e49825f /file_hierarchy.cpp
parent4.2 (diff)
downloadFreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.tar.gz
FreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.tar.bz2
FreeFileSync-88a2d0007db222c339f0b6a17794a2014a241892.zip
4.3
Diffstat (limited to 'file_hierarchy.cpp')
-rw-r--r--file_hierarchy.cpp227
1 files changed, 212 insertions, 15 deletions
diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp
index cfe1b6a0..39b789fd 100644
--- a/file_hierarchy.cpp
+++ b/file_hierarchy.cpp
@@ -5,6 +5,8 @@
// **************************************************************************
#include "file_hierarchy.h"
+#include <zen/i18n.h>
+#include <zen/utf8.h>
using namespace zen;
@@ -31,12 +33,12 @@ void HierarchyObject::removeEmptyRec()
std::for_each(refSubDirs().begin(), refSubDirs().end(), std::mem_fun_ref(&HierarchyObject::removeEmptyRec));
}
-
-SyncOperation FileSystemObject::getSyncOperation(
- CompareFilesResult cmpResult,
- bool selectedForSynchronization,
- SyncDirection syncDir,
- const std::wstring& syncDirConflict)
+namespace
+{
+SyncOperation proposedSyncOperation(CompareFilesResult cmpResult,
+ bool selectedForSynchronization,
+ SyncDirection syncDir,
+ const std::wstring& syncDirConflict)
{
if (!selectedForSynchronization)
return cmpResult == FILE_EQUAL ?
@@ -105,8 +107,6 @@ SyncOperation FileSystemObject::getSyncOperation(
}
-namespace
-{
template <class Predicate> inline
bool hasDirectChild(const HierarchyObject& hierObj, Predicate p)
{
@@ -117,6 +117,22 @@ bool hasDirectChild(const HierarchyObject& hierObj, Predicate p)
}
+SyncOperation FileSystemObject::testSyncOperation(SyncDirection testSyncDir) const
+{
+ return proposedSyncOperation(getCategory(), selectedForSynchronization, testSyncDir, syncDirConflict);
+}
+
+
+SyncOperation FileSystemObject::getSyncOperation() const
+{
+ return FileSystemObject::testSyncOperation(syncDir);
+ //no *not* make a virtual call to testSyncOperation()! See FileMapping::testSyncOperation()!
+}
+
+
+//SyncOperation DirMapping::testSyncOperation() const -> not required: we do NOT want to consider child elements when testing!
+
+
SyncOperation DirMapping::getSyncOperation() const
{
if (!syncOpUpToDate)
@@ -124,7 +140,7 @@ SyncOperation DirMapping::getSyncOperation() const
syncOpUpToDate = true;
//redetermine...
- //suggested operation for directory only
+ //suggested operation *not* considering child elements
syncOpBuffered = FileSystemObject::getSyncOperation();
//action for child elements may occassionally have to overwrite parent task:
@@ -132,6 +148,10 @@ SyncOperation DirMapping::getSyncOperation() const
{
case SO_OVERWRITE_LEFT:
case SO_OVERWRITE_RIGHT:
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_RIGHT_TARGET:
assert(false);
case SO_CREATE_NEW_LEFT:
case SO_CREATE_NEW_RIGHT:
@@ -149,19 +169,32 @@ SyncOperation DirMapping::getSyncOperation() const
//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;
+ if (hasDirectChild(*this,
+ [](const FileSystemObject& fsObj) -> bool { const SyncOperation op = fsObj.getSyncOperation(); return op == SO_CREATE_NEW_LEFT || op == SO_MOVE_LEFT_TARGET; }))
+ 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; }))
+ hasDirectChild(*this,
+ [](const FileSystemObject& fsObj) -> bool
+ {
+ if (fsObj.isEmpty()) return false; //fsObj may already be empty because it once contained a "move source"
+ const SyncOperation op = fsObj.getSyncOperation(); return op != SO_DELETE_RIGHT && op != SO_MOVE_RIGHT_SOURCE;
+ }))
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;
+ if (hasDirectChild(*this,
+ [](const FileSystemObject& fsObj) -> bool { const SyncOperation op = fsObj.getSyncOperation(); return op == SO_CREATE_NEW_RIGHT || op == SO_MOVE_RIGHT_TARGET; }))
+ syncOpBuffered = SO_CREATE_NEW_RIGHT;
else if (syncOpBuffered == SO_DELETE_LEFT &&
- hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() != SO_DELETE_LEFT; }))
+ hasDirectChild(*this,
+ [](const FileSystemObject& fsObj) -> bool
+ {
+ if (fsObj.isEmpty()) return false;
+ const SyncOperation op = fsObj.getSyncOperation();
+ return op != SO_DELETE_LEFT && op != SO_MOVE_LEFT_SOURCE;
+ }))
syncOpBuffered = SO_DO_NOTHING;
}
}
@@ -170,3 +203,167 @@ SyncOperation DirMapping::getSyncOperation() const
}
return syncOpBuffered;
}
+
+
+SyncOperation FileMapping::testSyncOperation(SyncDirection testSyncDir) const
+{
+ SyncOperation op = FileSystemObject::testSyncOperation(testSyncDir);
+
+ /*
+ check whether we can optimize "create + delete" via "move":
+ note: as long as we consider "create + delete" cases only, detection of renamed files, should be fine even for "binary" comparison variant!
+ */
+ if (const FileMapping* refFile = dynamic_cast<const FileMapping*>(FileSystemObject::retrieve(moveFileRef)))
+ {
+ SyncOperation opRef = refFile->FileSystemObject::getSyncOperation(); //do *not* make a virtual call!
+
+ if (op == SO_CREATE_NEW_LEFT &&
+ opRef == SO_DELETE_LEFT)
+ op = SO_MOVE_LEFT_TARGET;
+ else if (op == SO_DELETE_LEFT &&
+ opRef == SO_CREATE_NEW_LEFT)
+ op = SO_MOVE_LEFT_SOURCE;
+ else if (op == SO_CREATE_NEW_RIGHT &&
+ opRef == SO_DELETE_RIGHT)
+ op = SO_MOVE_RIGHT_TARGET;
+ else if (op == SO_DELETE_RIGHT &&
+ opRef == SO_CREATE_NEW_RIGHT)
+ op = SO_MOVE_RIGHT_SOURCE;
+ }
+ return op;
+}
+
+
+SyncOperation FileMapping::getSyncOperation() const
+{
+ return FileMapping::testSyncOperation(getSyncDir());
+}
+
+
+std::wstring zen::getCategoryDescription(CompareFilesResult cmpRes)
+{
+ switch (cmpRes)
+ {
+ case FILE_LEFT_SIDE_ONLY:
+ return _("File/folder exists on left side only");
+ case FILE_RIGHT_SIDE_ONLY:
+ return _("File/folder exists on right side only");
+ case FILE_LEFT_NEWER:
+ return _("Left file is newer");
+ case FILE_RIGHT_NEWER:
+ return _("Right file is newer");
+ case FILE_DIFFERENT:
+ return _("Files have different content");
+ case FILE_EQUAL:
+ return _("Both sides are equal");
+ case FILE_DIFFERENT_METADATA:
+ return _("Files/folders differ in attributes only");
+ case FILE_CONFLICT:
+ return _("Conflict/file cannot be categorized");
+ }
+ assert(false);
+ return std::wstring();
+}
+
+
+std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj)
+{
+ const CompareFilesResult cmpRes = fsObj.getCategory();
+ if (cmpRes == FILE_CONFLICT)
+ return fsObj.getCatConflict();
+
+ return getCategoryDescription(cmpRes);
+}
+
+
+std::wstring zen::getSyncOpDescription(SyncOperation op)
+{
+ switch (op)
+ {
+ case SO_CREATE_NEW_LEFT:
+ return _("Copy new file/folder to left");
+ case SO_CREATE_NEW_RIGHT:
+ return _("Copy new file/folder to right");
+ case SO_DELETE_LEFT:
+ return _("Delete left file/folder");
+ case SO_DELETE_RIGHT:
+ return _("Delete right file/folder");
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ return _("Move file on left");
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_RIGHT_TARGET:
+ return _("Move file on right");
+ case SO_OVERWRITE_LEFT:
+ return _("Overwrite left file/folder with right one");
+ case SO_OVERWRITE_RIGHT:
+ return _("Overwrite right file/folder with left one");
+ case SO_DO_NOTHING:
+ return _("Do nothing");
+ case SO_EQUAL:
+ return _("Both sides are equal");
+ case SO_COPY_METADATA_TO_LEFT:
+ return _("Copy file attributes only to left");
+ case SO_COPY_METADATA_TO_RIGHT:
+ return _("Copy file attributes only to right");
+ case SO_UNRESOLVED_CONFLICT: //not used on GUI, but in .csv
+ _("Conflict/file cannot be categorized");
+ }
+ assert(false);
+ return std::wstring();
+}
+
+
+std::wstring zen::getSyncOpDescription(const FileSystemObject& fsObj)
+{
+ const SyncOperation op = fsObj.getSyncOperation();
+ switch (op)
+ {
+ case SO_CREATE_NEW_LEFT:
+ case SO_CREATE_NEW_RIGHT:
+ case SO_DELETE_LEFT:
+ case SO_DELETE_RIGHT:
+ case SO_OVERWRITE_LEFT:
+ case SO_OVERWRITE_RIGHT:
+ case SO_DO_NOTHING:
+ case SO_EQUAL:
+ case SO_COPY_METADATA_TO_LEFT:
+ case SO_COPY_METADATA_TO_RIGHT:
+ return getSyncOpDescription(op); //use generic description
+
+ case SO_MOVE_LEFT_SOURCE:
+ case SO_MOVE_LEFT_TARGET:
+ case SO_MOVE_RIGHT_SOURCE:
+ case SO_MOVE_RIGHT_TARGET:
+ if (const FileMapping* sourceFile = dynamic_cast<const FileMapping*>(&fsObj))
+ if (const FileMapping* targetFile = dynamic_cast<const FileMapping*>(FileSystemObject::retrieve(sourceFile->getMoveRef())))
+ {
+ const bool onLeft = op == SO_MOVE_LEFT_SOURCE || op == SO_MOVE_LEFT_TARGET;
+ const bool isSource = op == SO_MOVE_LEFT_SOURCE || op == SO_MOVE_RIGHT_SOURCE;
+
+ if (!isSource)
+ std::swap(sourceFile, targetFile);
+
+ auto getRelName = [&](const FileSystemObject& fso, bool leftSide) { return leftSide ? fso.getRelativeName<LEFT_SIDE>() : fso.getRelativeName<RIGHT_SIDE>(); };
+
+ const Zstring relSource = getRelName(*sourceFile, onLeft);
+ const Zstring relTarget = getRelName(*targetFile, !onLeft);
+
+ return getSyncOpDescription(op) + L"\n" +
+ (EqualFilename()(beforeLast(relSource, FILE_NAME_SEPARATOR), beforeLast(relTarget, FILE_NAME_SEPARATOR)) ? //returns empty string if ch not found
+ //detected pure "rename"
+ L"\"" + utf8CvrtTo<std::wstring>(afterLast(relSource, FILE_NAME_SEPARATOR)) + L"\"" + L" ->\n" + //show short name only
+ L"\"" + utf8CvrtTo<std::wstring>(afterLast(relTarget, FILE_NAME_SEPARATOR)) + L"\"" :
+ //"move" or "move + rename"
+ L"\"" + utf8CvrtTo<std::wstring>(relSource) + L"\"" + L" ->\n" +
+ L"\"" + utf8CvrtTo<std::wstring>(relTarget) + L"\"");
+ //attention: ::SetWindowText() doesn't handle tab characters correctly in combination with certain file names, so don't use them
+ }
+ break;
+ case SO_UNRESOLVED_CONFLICT:
+ return fsObj.getSyncOpConflict();
+ }
+
+ assert(false);
+ return std::wstring();
+}
bgstack15