summaryrefslogtreecommitdiff
path: root/file_hierarchy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'file_hierarchy.cpp')
-rw-r--r--file_hierarchy.cpp409
1 files changed, 0 insertions, 409 deletions
diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp
deleted file mode 100644
index 780f05de..00000000
--- a/file_hierarchy.cpp
+++ /dev/null
@@ -1,409 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#include "file_hierarchy.h"
-#include <zen/i18n.h>
-#include <zen/utf.h>
-#include <zen/file_error.h>
-
-using namespace zen;
-
-
-void HierarchyObject::removeEmptyRec()
-{
- bool emptyExisting = false;
- auto isEmpty = [&](const FileSystemObject& fsObj) -> bool
- {
- const bool objEmpty = fsObj.isEmpty();
- if (objEmpty)
- emptyExisting = true;
- return objEmpty;
- };
-
- refSubFiles().remove_if(isEmpty);
- refSubLinks().remove_if(isEmpty);
- refSubDirs ().remove_if(isEmpty);
-
- if (emptyExisting) //notify if actual deletion happened
- notifySyncCfgChanged(); //mustn't call this in ~FileSystemObject(), since parent, usually a DirPair, is already partially destroyed and existing as a pure HierarchyObject!
-
- for (DirPair& subDir : refSubDirs())
- subDir.removeEmptyRec(); //recurse
-}
-
-namespace
-{
-SyncOperation getIsolatedSyncOperation(CompareFilesResult cmpResult,
- bool selectedForSynchronization,
- SyncDirection syncDir,
- bool hasDirConflict) //perf: std::wstring was wasteful here
-{
- assert(!hasDirConflict || syncDir == SyncDirection::NONE);
-
- if (!selectedForSynchronization)
- return cmpResult == FILE_EQUAL ?
- SO_EQUAL :
- SO_DO_NOTHING;
-
- switch (cmpResult)
- {
- case FILE_LEFT_SIDE_ONLY:
- switch (syncDir)
- {
- case SyncDirection::LEFT:
- return SO_DELETE_LEFT; //delete files on left
- case SyncDirection::RIGHT:
- return SO_CREATE_NEW_RIGHT; //copy files to right
- case SyncDirection::NONE:
- return hasDirConflict ? SO_UNRESOLVED_CONFLICT : SO_DO_NOTHING;
- }
- break;
-
- case FILE_RIGHT_SIDE_ONLY:
- switch (syncDir)
- {
- case SyncDirection::LEFT:
- return SO_CREATE_NEW_LEFT; //copy files to left
- case SyncDirection::RIGHT:
- return SO_DELETE_RIGHT; //delete files on right
- case SyncDirection::NONE:
- return hasDirConflict ? SO_UNRESOLVED_CONFLICT : SO_DO_NOTHING;
- }
- break;
-
- case FILE_LEFT_NEWER:
- case FILE_RIGHT_NEWER:
- case FILE_DIFFERENT:
- case FILE_CONFLICT:
- switch (syncDir)
- {
- case SyncDirection::LEFT:
- return SO_OVERWRITE_LEFT; //copy from right to left
- case SyncDirection::RIGHT:
- return SO_OVERWRITE_RIGHT; //copy from left to right
- case SyncDirection::NONE:
- return hasDirConflict ? SO_UNRESOLVED_CONFLICT : SO_DO_NOTHING;
- }
- break;
-
- case FILE_DIFFERENT_METADATA:
- switch (syncDir)
- {
- case SyncDirection::LEFT:
- return SO_COPY_METADATA_TO_LEFT;
- case SyncDirection::RIGHT:
- return SO_COPY_METADATA_TO_RIGHT;
- case SyncDirection::NONE:
- return hasDirConflict ? SO_UNRESOLVED_CONFLICT : SO_DO_NOTHING;
- }
- break;
-
- case FILE_EQUAL:
- assert(syncDir == SyncDirection::NONE);
- return SO_EQUAL;
- }
-
- assert(false);
- return SO_DO_NOTHING; //dummy
-}
-
-
-template <class Predicate> inline
-bool hasDirectChild(const HierarchyObject& hierObj, Predicate p)
-{
- return std::any_of(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), p) ||
- std::any_of(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), p) ||
- std::any_of(hierObj.refSubDirs(). begin(), hierObj.refSubDirs(). end(), p);
-}
-}
-
-
-SyncOperation FileSystemObject::testSyncOperation(SyncDirection testSyncDir) const //semantics: "what if"! assumes "active, no conflict, no recursion (directory)!
-{
- return getIsolatedSyncOperation(getCategory(), true, testSyncDir, false);
-}
-
-
-SyncOperation FileSystemObject::getSyncOperation() const
-{
- return getIsolatedSyncOperation(getCategory(), selectedForSynchronization, getSyncDir(), syncDirConflict.get() != nullptr);
- //no *not* make a virtual call to testSyncOperation()! See FilePair::testSyncOperation()! <- better not implement one in terms of the other!!!
-}
-
-
-//SyncOperation DirPair::testSyncOperation() const -> no recursion: we do NOT want to consider child elements when testing!
-
-
-SyncOperation DirPair::getSyncOperation() const
-{
- if (!syncOpUpToDate)
- {
- syncOpUpToDate = true;
- //redetermine...
-
- //suggested operation *not* considering child elements
- syncOpBuffered = FileSystemObject::getSyncOperation();
-
- //action for child elements may occassionally have to overwrite parent task:
- switch (syncOpBuffered)
- {
- 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:
- 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) -> 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) -> 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) -> 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) -> 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;
- }
- break;
- }
- }
- return syncOpBuffered;
-}
-
-
-inline //it's private!
-SyncOperation FilePair::applyMoveOptimization(SyncOperation op) const
-{
- /*
- 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 (moveFileRef)
- if (auto refFile = dynamic_cast<const FilePair*>(FileSystemObject::retrieve(moveFileRef))) //we expect a "FilePair", but only need a "FileSystemObject"
- {
- 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 FilePair::testSyncOperation(SyncDirection testSyncDir) const
-{
- return applyMoveOptimization(FileSystemObject::testSyncOperation(testSyncDir));
-}
-
-
-SyncOperation FilePair::getSyncOperation() const
-{
- return applyMoveOptimization(FileSystemObject::getSyncOperation());
-}
-
-
-std::wstring zen::getCategoryDescription(CompareFilesResult cmpRes)
-{
- switch (cmpRes)
- {
- case FILE_LEFT_SIDE_ONLY:
- return _("Item exists on left side only");
- case FILE_RIGHT_SIDE_ONLY:
- return _("Item exists on right side only");
- case FILE_LEFT_NEWER:
- return _("Left side is newer");
- case FILE_RIGHT_NEWER:
- return _("Right side is newer");
- case FILE_DIFFERENT:
- return _("Items have different content");
- case FILE_EQUAL:
- return _("Both sides are equal");
- case FILE_DIFFERENT_METADATA:
- return _("Items differ in attributes only");
- case FILE_CONFLICT:
- return _("Conflict/item cannot be categorized");
- }
- assert(false);
- return std::wstring();
-}
-
-
-std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj)
-{
- const CompareFilesResult cmpRes = fsObj.getCategory();
- if (cmpRes == FILE_CONFLICT ||
- cmpRes == FILE_DIFFERENT_METADATA)
- return fsObj.getCatExtraDescription();
-
- return getCategoryDescription(cmpRes);
-}
-
-
-std::wstring zen::getSyncOpDescription(SyncOperation op)
-{
- switch (op)
- {
- case SO_CREATE_NEW_LEFT:
- return _("Copy new item to left");
- case SO_CREATE_NEW_RIGHT:
- return _("Copy new item to right");
- case SO_DELETE_LEFT:
- return _("Delete left item");
- case SO_DELETE_RIGHT:
- return _("Delete right item");
- case SO_MOVE_LEFT_SOURCE:
- case SO_MOVE_LEFT_TARGET:
- return _("Move file on left"); //move only supported for files
- case SO_MOVE_RIGHT_SOURCE:
- case SO_MOVE_RIGHT_TARGET:
- return _("Move file on right");
- case SO_OVERWRITE_LEFT:
- return _("Overwrite left item");
- case SO_OVERWRITE_RIGHT:
- return _("Overwrite right item");
- case SO_DO_NOTHING:
- return _("Do nothing");
- case SO_EQUAL:
- return _("Both sides are equal");
- case SO_COPY_METADATA_TO_LEFT:
- return _("Update attributes on left");
- case SO_COPY_METADATA_TO_RIGHT:
- return _("Update attributes on right");
- case SO_UNRESOLVED_CONFLICT: //not used on GUI, but in .csv
- return _("Conflict/item 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:
- return getSyncOpDescription(op); //use generic description
-
- case SO_COPY_METADATA_TO_LEFT:
- case SO_COPY_METADATA_TO_RIGHT:
- //harmonize with synchronization.cpp::SynchronizeFolderPair::synchronizeFileInt, ect!!
- {
- Zstring shortNameOld = fsObj.getShortName<RIGHT_SIDE>();
- Zstring shortNameNew = fsObj.getShortName<LEFT_SIDE >();
- if (op == SO_COPY_METADATA_TO_LEFT)
- std::swap(shortNameOld, shortNameNew);
-
- if (shortNameOld != shortNameNew) //detected change in case
- return getSyncOpDescription(op) + L"\n" +
- fmtFileName(shortNameOld) + L" ->\n" + //show short name only
- fmtFileName(shortNameNew);
- }
- //fallback:
- return getSyncOpDescription(op);
-
- case SO_MOVE_LEFT_SOURCE:
- case SO_MOVE_LEFT_TARGET:
- case SO_MOVE_RIGHT_SOURCE:
- case SO_MOVE_RIGHT_TARGET:
- if (const FilePair* sourceFile = dynamic_cast<const FilePair*>(&fsObj))
- if (const FilePair* targetFile = dynamic_cast<const FilePair*>(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"
- fmtFileName(afterLast(relSource, FILE_NAME_SEPARATOR)) + L" ->\n" + //show short name only
- fmtFileName(afterLast(relTarget, FILE_NAME_SEPARATOR)) :
- //"move" or "move + rename"
- fmtFileName(relSource) + L" ->\n" +
- fmtFileName(relTarget));
- //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