// ************************************************************************** // * 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 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 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()) { result_.filesizeLeftView += fileObj.getFileSize(); ++result_.filesOnLeftView; } if (!fileObj.isEmpty()) { result_.filesizeRightView += fileObj.getFileSize(); ++result_.filesOnRightView; } } virtual void visit(const SymLinkMapping& linkObj) { if (!linkObj.isEmpty()) ++result_.filesOnLeftView; if (!linkObj.isEmpty()) ++result_.filesOnRightView; } virtual void visit(const DirMapping& dirObj) { if (!dirObj.isEmpty()) ++result_.foldersOnLeftView; if (!dirObj.isEmpty()) ++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::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::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& guiRows, std::vector& output) { std::set::const_iterator upperEnd = guiRows.lower_bound(rowsOnView()); //loop over valid rows only! output.clear(); output.reserve(guiRows.size()); for (std::set::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& 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& 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 class GridView::SortByDirectory : public std::binary_function { public: bool operator()(const RefIndex a, const RefIndex b) const { return ascending ? a.folderIndex < b.folderIndex : a.folderIndex > b.folderIndex; } }; template class GridView::SortByRelName : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortByFileName : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortByFileSize : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortByDate : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortByExtension : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortByCmpResult : public std::binary_function { 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(*fsObjA, *fsObjB); } private: const GridView& m_view; }; template class GridView::SortBySyncDirection : public std::binary_function { 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(*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(*this)); else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName(*this)); else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName(*this)); else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByRelName(*this)); break; case SORT_BY_FILENAME: if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName(*this)); else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName(*this)); else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName(*this)); else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileName(*this)); break; case SORT_BY_FILESIZE: if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize(*this)); else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize(*this)); else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize(*this)); else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByFileSize(*this)); break; case SORT_BY_DATE: if ( ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate(*this)); else if ( ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate(*this)); else if (!ascending && onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate(*this)); else if (!ascending && !onLeft) std::sort(sortedRef.begin(), sortedRef.end(), SortByDate(*this)); break; case SORT_BY_EXTENSION: if ( ascending && onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension(*this)); else if ( ascending && !onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension(*this)); else if (!ascending && onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension(*this)); else if (!ascending && !onLeft) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByExtension(*this)); break; case SORT_BY_CMP_RESULT: if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByCmpResult(*this)); else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByCmpResult(*this)); break; case SORT_BY_SYNC_DIRECTION: if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortBySyncDirection(*this)); else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortBySyncDirection(*this)); break; case SORT_BY_DIRECTORY: if ( ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByDirectory()); else if (!ascending) std::stable_sort(sortedRef.begin(), sortedRef.end(), SortByDirectory()); break; } }