summaryrefslogtreecommitdiff
path: root/ui/grid_view.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
commitfbe76102e941b9f1edaf236788e42678f05fdf9a (patch)
treef5f538316019fa89be8dc478103490c3a826f3ac /ui/grid_view.cpp
parent3.8 (diff)
downloadFreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.gz
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.bz2
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.zip
3.9
Diffstat (limited to 'ui/grid_view.cpp')
-rw-r--r--ui/grid_view.cpp570
1 files changed, 570 insertions, 0 deletions
diff --git a/ui/grid_view.cpp b/ui/grid_view.cpp
new file mode 100644
index 00000000..24e558fc
--- /dev/null
+++ b/ui/grid_view.cpp
@@ -0,0 +1,570 @@
+// **************************************************************************
+// * 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) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+//
+#include "grid_view.h"
+#include "sorting.h"
+#include "../synchronization.h"
+#include <boost/bind.hpp>
+
+using namespace ffs3;
+
+
+GridView::StatusCmpResult::StatusCmpResult() :
+ existsLeftOnly(false),
+ existsRightOnly(false),
+ existsLeftNewer(false),
+ existsRightNewer(false),
+ existsDifferent(false),
+ existsEqual(false),
+ existsConflict(false),
+
+ filesOnLeftView(0),
+ foldersOnLeftView(0),
+ filesOnRightView(0),
+ foldersOnRightView(0) {}
+
+
+template <class StatusResult>
+void getNumbers(const FileSystemObject& fsObj, StatusResult& result)
+{
+ struct GetValues : public FSObjectVisitor
+ {
+ GetValues(StatusResult& res) : result_(res) {}
+
+ virtual void visit(const FileMapping& fileObj)
+ {
+ if (!fileObj.isEmpty<LEFT_SIDE>())
+ {
+ result_.filesizeLeftView += fileObj.getFileSize<LEFT_SIDE>();
+ ++result_.filesOnLeftView;
+ }
+ if (!fileObj.isEmpty<RIGHT_SIDE>())
+ {
+ result_.filesizeRightView += fileObj.getFileSize<RIGHT_SIDE>();
+ ++result_.filesOnRightView;
+ }
+ }
+
+ virtual void visit(const SymLinkMapping& linkObj)
+ {
+ if (!linkObj.isEmpty<LEFT_SIDE>())
+ ++result_.filesOnLeftView;
+
+ if (!linkObj.isEmpty<RIGHT_SIDE>())
+ ++result_.filesOnRightView;
+ }
+
+ virtual void visit(const DirMapping& dirObj)
+ {
+ if (!dirObj.isEmpty<LEFT_SIDE>())
+ ++result_.foldersOnLeftView;
+
+ if (!dirObj.isEmpty<RIGHT_SIDE>())
+ ++result_.foldersOnRightView;
+ }
+ StatusResult& result_;
+ } getVal(result);
+ fsObj.accept(getVal);
+}
+
+
+GridView::StatusCmpResult GridView::updateCmpResult(bool hideFiltered, //maps sortedRef to viewRef
+ bool leftOnlyFilesActive,
+ bool rightOnlyFilesActive,
+ bool leftNewerFilesActive,
+ bool rightNewerFilesActive,
+ bool differentFilesActive,
+ bool equalFilesActive,
+ bool conflictFilesActive)
+{
+ StatusCmpResult output;
+
+ viewRef.clear();
+
+ for (std::vector<RefIndex>::const_iterator j = sortedRef.begin(); j != sortedRef.end(); ++j)
+ {
+ const FileSystemObject* fsObj = getReferencedRow(*j);
+ if (fsObj)
+ {
+ //hide filtered row, if corresponding option is set
+ if (hideFiltered && !fsObj->isActive())
+ continue;
+
+ switch (fsObj->getCategory())
+ {
+ case FILE_LEFT_SIDE_ONLY:
+ output.existsLeftOnly = true;
+ if (!leftOnlyFilesActive) continue;
+ break;
+ case FILE_RIGHT_SIDE_ONLY:
+ output.existsRightOnly = true;
+ if (!rightOnlyFilesActive) continue;
+ break;
+ case FILE_LEFT_NEWER:
+ output.existsLeftNewer = true;
+ if (!leftNewerFilesActive) continue;
+ break;
+ case FILE_RIGHT_NEWER:
+ output.existsRightNewer = true;
+ if (!rightNewerFilesActive) continue;
+ break;
+ case FILE_DIFFERENT:
+ output.existsDifferent = true;
+ if (!differentFilesActive) continue;
+ break;
+ case FILE_EQUAL:
+ output.existsEqual = true;
+ if (!equalFilesActive) continue;
+ break;
+ case FILE_CONFLICT:
+ output.existsConflict = true;
+ if (!conflictFilesActive) continue;
+ break;
+ }
+
+ //calculate total number of bytes for each side
+ getNumbers(*fsObj, output);
+
+ viewRef.push_back(*j);
+ }
+ }
+
+ return output;
+}
+
+
+GridView::StatusSyncPreview::StatusSyncPreview() :
+ existsSyncCreateLeft(false),
+ existsSyncCreateRight(false),
+ existsSyncDeleteLeft(false),
+ existsSyncDeleteRight(false),
+ existsSyncDirLeft(false),
+ existsSyncDirRight(false),
+ existsSyncDirNone(false),
+ existsSyncEqual(false),
+ existsConflict(false),
+
+ filesOnLeftView(0),
+ foldersOnLeftView(0),
+ filesOnRightView(0),
+ foldersOnRightView(0) {}
+
+
+GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //maps sortedRef to viewRef
+ bool syncCreateLeftActive,
+ bool syncCreateRightActive,
+ bool syncDeleteLeftActive,
+ bool syncDeleteRightActive,
+ bool syncDirOverwLeftActive,
+ bool syncDirOverwRightActive,
+ bool syncDirNoneActive,
+ bool syncEqualActive,
+ bool conflictFilesActive)
+{
+ StatusSyncPreview output;
+
+ viewRef.clear();
+
+ for (std::vector<RefIndex>::const_iterator j = sortedRef.begin(); j != sortedRef.end(); ++j)
+ {
+ const FileSystemObject* fsObj = getReferencedRow(*j);
+ if (fsObj)
+ {
+ //hide filtered row, if corresponding option is set
+ if (hideFiltered && !fsObj->isActive())
+ continue;
+
+
+ switch (fsObj->getSyncOperation()) //evaluate comparison result and sync direction
+ {
+ case SO_CREATE_NEW_LEFT:
+ output.existsSyncCreateLeft = true;
+ if (!syncCreateLeftActive) continue;
+ break;
+ case SO_CREATE_NEW_RIGHT:
+ output.existsSyncCreateRight = true;
+ if (!syncCreateRightActive) continue;
+ break;
+ case SO_DELETE_LEFT:
+ output.existsSyncDeleteLeft = true;
+ if (!syncDeleteLeftActive) continue;
+ break;
+ case SO_DELETE_RIGHT:
+ output.existsSyncDeleteRight = true;
+ if (!syncDeleteRightActive) continue;
+ break;
+ case SO_OVERWRITE_RIGHT:
+ output.existsSyncDirRight = true;
+ if (!syncDirOverwRightActive) continue;
+ break;
+ case SO_OVERWRITE_LEFT:
+ output.existsSyncDirLeft = true;
+ if (!syncDirOverwLeftActive) continue;
+ break;
+ case SO_DO_NOTHING:
+ output.existsSyncDirNone = true;
+ if (!syncDirNoneActive) continue;
+ break;
+ case SO_EQUAL:
+ output.existsSyncEqual = true;
+ if (!syncEqualActive) continue;
+ break;
+ case SO_UNRESOLVED_CONFLICT:
+ output.existsConflict = true;
+ if (!conflictFilesActive) continue;
+ break;
+ }
+
+ //calculate total number of bytes for each side
+ getNumbers(*fsObj, output);
+
+ viewRef.push_back(*j);
+ }
+ }
+
+ return output;
+}
+
+
+void GridView::getAllFileRef(const std::set<size_t>& guiRows, std::vector<FileSystemObject*>& output)
+{
+ std::set<size_t>::const_iterator upperEnd = guiRows.lower_bound(rowsOnView()); //loop over valid rows only!
+
+ output.clear();
+ output.reserve(guiRows.size());
+ for (std::set<size_t>::const_iterator i = guiRows.begin(); i != upperEnd; ++i)
+ {
+ FileSystemObject* fsObj = getReferencedRow(viewRef[*i]);
+ if (fsObj)
+ output.push_back(fsObj);
+ }
+}
+
+
+inline
+bool GridView::isInvalidRow(const RefIndex& ref) const
+{
+ return getReferencedRow(ref) == NULL;
+}
+
+
+void GridView::removeInvalidRows()
+{
+ viewRef.clear();
+
+ //remove rows that have been deleted meanwhile
+ sortedRef.erase(std::remove_if(sortedRef.begin(), sortedRef.end(),
+ boost::bind(&GridView::isInvalidRow, this, _1)), sortedRef.end());
+}
+
+
+void GridView::clearAllRows()
+{
+ viewRef.clear();
+ sortedRef.clear();
+ folderCmp.clear();
+}
+
+
+class GridView::SerializeHierarchy
+{
+public:
+ SerializeHierarchy(std::vector<GridView::RefIndex>& sortedRef, size_t index) :
+ index_(index),
+ sortedRef_(sortedRef) {}
+
+ void execute(const HierarchyObject& hierObj)
+ {
+ //add file references
+ std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), *this);
+
+ //add symlink references
+ std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), *this);
+
+ //add dir references
+ std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), *this);
+ }
+
+ void operator()(const FileMapping& fileObj)
+ {
+ sortedRef_.push_back(RefIndex(index_, fileObj.getId()));
+ }
+
+ void operator()(const SymLinkMapping& linkObj)
+ {
+ sortedRef_.push_back(RefIndex(index_, linkObj.getId()));
+ }
+
+ void operator()(const DirMapping& dirObj)
+ {
+ sortedRef_.push_back(RefIndex(index_, dirObj.getId()));
+ execute(dirObj); //add recursion here to list sub-objects directly below parent!
+ }
+
+private:
+ size_t index_;
+ std::vector<GridView::RefIndex>& sortedRef_;
+};
+
+
+void GridView::setData(FolderComparison& newData)
+{
+ viewRef.clear();
+ sortedRef.clear();
+ folderCmp.swap(newData);
+
+ //fill sortedRef
+ for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j)
+ SerializeHierarchy(sortedRef, j - folderCmp.begin()).execute(*j);
+}
+
+
+//------------------------------------ SORTING TEMPLATES ------------------------------------------------
+template <bool ascending>
+class GridView::SortByDirectory : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ return ascending ?
+ a.folderIndex < b.folderIndex :
+ a.folderIndex > b.folderIndex;
+ }
+};
+
+
+template <bool ascending, ffs3::SelectedSide side>
+class GridView::SortByRelName : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByRelName(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ //presort by folder pair
+ if (a.folderIndex != b.folderIndex)
+ return ascending ?
+ a.folderIndex < b.folderIndex :
+ a.folderIndex > b.folderIndex;
+
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByRelativeName<ascending, side>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending, ffs3::SelectedSide side>
+class GridView::SortByFileName : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByFileName(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByFileName<ascending, side>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending, ffs3::SelectedSide side>
+class GridView::SortByFileSize : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByFileSize(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByFileSize<ascending, side>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending, ffs3::SelectedSide side>
+class GridView::SortByDate : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByDate(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByDate<ascending, side>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending, ffs3::SelectedSide side>
+class GridView::SortByExtension : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByExtension(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByExtension<ascending, side>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending>
+class GridView::SortByCmpResult : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortByCmpResult(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortByCmpResult<ascending>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+
+template <bool ascending>
+class GridView::SortBySyncDirection : public std::binary_function<RefIndex, RefIndex, bool>
+{
+public:
+ SortBySyncDirection(const GridView& view) : m_view(view) {}
+
+ bool operator()(const RefIndex a, const RefIndex b) const
+ {
+ const FileSystemObject* fsObjA = m_view.getReferencedRow(a);
+ const FileSystemObject* fsObjB = m_view.getReferencedRow(b);
+ if (fsObjA == NULL) //invalid rows shall appear at the end
+ return false;
+ else if (fsObjB == NULL)
+ return true;
+
+ return sortBySyncDirection<ascending>(*fsObjA, *fsObjB);
+ }
+private:
+ const GridView& m_view;
+};
+
+//-------------------------------------------------------------------------------------------------------
+bool GridView::getDefaultDirection(SortType type) //true: ascending; false: descending
+{
+ switch (type)
+ {
+ case SORT_BY_FILESIZE:
+ case SORT_BY_DATE:
+ return false;
+
+ case SORT_BY_REL_NAME:
+ case SORT_BY_FILENAME:
+ case SORT_BY_EXTENSION:
+ case SORT_BY_CMP_RESULT:
+ case SORT_BY_DIRECTORY:
+ case SORT_BY_SYNC_DIRECTION:
+ return true;
+ }
+ assert(false);
+ return true;
+}
+
+
+void GridView::sortView(SortType type, bool onLeft, bool ascending)
+{
+ viewRef.clear();
+
+ switch (type)
+ {
+ case SORT_BY_REL_NAME:
+ if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName<true, LEFT_SIDE>(*this));
+ else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName<true, RIGHT_SIDE>(*this));
+ else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName<false, LEFT_SIDE >(*this));
+ else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName<false, RIGHT_SIDE>(*this));
+ break;
+ case SORT_BY_FILENAME:
+ if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName<true, LEFT_SIDE >(*this));
+ else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName<true, RIGHT_SIDE>(*this));
+ else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName<false, LEFT_SIDE >(*this));
+ else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName<false, RIGHT_SIDE>(*this));
+ break;
+ case SORT_BY_FILESIZE:
+ if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize<true, LEFT_SIDE >(*this));
+ else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize<true, RIGHT_SIDE>(*this));
+ else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize<false, LEFT_SIDE >(*this));
+ else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize<false, RIGHT_SIDE>(*this));
+ break;
+ case SORT_BY_DATE:
+ if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate<true, LEFT_SIDE >(*this));
+ else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate<true, RIGHT_SIDE>(*this));
+ else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate<false, LEFT_SIDE >(*this));
+ else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate<false, RIGHT_SIDE>(*this));
+ break;
+ case SORT_BY_EXTENSION:
+ if ( ascending && onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension<true, LEFT_SIDE >(*this));
+ else if ( ascending && !onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension<true, RIGHT_SIDE>(*this));
+ else if (!ascending && onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension<false, LEFT_SIDE >(*this));
+ else if (!ascending && !onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension<false, RIGHT_SIDE>(*this));
+ break;
+ case SORT_BY_CMP_RESULT:
+ if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByCmpResult<true >(*this));
+ else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByCmpResult<false>(*this));
+ break;
+ case SORT_BY_SYNC_DIRECTION:
+ if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortBySyncDirection<true >(*this));
+ else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortBySyncDirection<false>(*this));
+ break;
+ case SORT_BY_DIRECTORY:
+ if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByDirectory<true>());
+ else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByDirectory<false>());
+ break;
+ }
+}
+
bgstack15