1 /* 2 * KDiff3 - Text Diff And Merge Tool 3 * 4 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 5 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 #ifndef MERGEFILEINFO_H 9 #define MERGEFILEINFO_H 10 11 #include "DirectoryInfo.h" 12 #include "diff.h" 13 #include "fileaccess.h" 14 15 #include <QString> 16 17 //class DirectoryInfo; 18 19 enum e_MergeOperation 20 { 21 eTitleId, 22 eNoOperation, 23 // Operations in sync mode (with only two directories): 24 eCopyAToB, 25 eCopyBToA, 26 eDeleteA, 27 eDeleteB, 28 eDeleteAB, 29 eMergeToA, 30 eMergeToB, 31 eMergeToAB, 32 33 // Operations in merge mode (with two or three directories) 34 eCopyAToDest, 35 eCopyBToDest, 36 eCopyCToDest, 37 eDeleteFromDest, 38 eMergeABCToDest, 39 eMergeABToDest, 40 eConflictingFileTypes, // Error 41 eChangedAndDeleted, // Error 42 eConflictingAges // Equal age but files are not! 43 }; 44 45 enum e_Age 46 { 47 eNew, 48 eMiddle, 49 eOld, 50 eNotThere, 51 eAgeEnd 52 }; 53 54 enum e_OperationStatus 55 { 56 eOpStatusNone, 57 eOpStatusDone, 58 eOpStatusError, 59 eOpStatusSkipped, 60 eOpStatusNotSaved, 61 eOpStatusInProgress, 62 eOpStatusToDo 63 }; 64 65 class DirectoryMergeWindow; 66 67 class MergeFileInfos 68 { 69 public: 70 MergeFileInfos(); 71 ~MergeFileInfos(); 72 73 Q_REQUIRED_RESULT QString subPath() const; 74 Q_REQUIRED_RESULT QString fileName() const; 75 isDirA()76 Q_REQUIRED_RESULT bool isDirA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isDir() : false; } isDirB()77 Q_REQUIRED_RESULT bool isDirB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isDir() : false; } isDirC()78 Q_REQUIRED_RESULT bool isDirC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isDir() : false; } hasDir()79 Q_REQUIRED_RESULT bool hasDir() const { return isDirA() || isDirB() || isDirC(); } 80 isLinkA()81 Q_REQUIRED_RESULT bool isLinkA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isSymLink() : false; } isLinkB()82 Q_REQUIRED_RESULT bool isLinkB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isSymLink() : false; } isLinkC()83 Q_REQUIRED_RESULT bool isLinkC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isSymLink() : false; } hasLink()84 Q_REQUIRED_RESULT bool hasLink() const { return isLinkA() || isLinkB() || isLinkC(); } 85 existsInA()86 Q_REQUIRED_RESULT bool existsInA() const { return m_pFileInfoA != nullptr; } existsInB()87 Q_REQUIRED_RESULT bool existsInB() const { return m_pFileInfoB != nullptr; } existsInC()88 Q_REQUIRED_RESULT bool existsInC() const { return m_pFileInfoC != nullptr; } 89 90 Q_REQUIRED_RESULT bool conflictingFileTypes() const; 91 92 void sort(Qt::SortOrder order); parent()93 Q_REQUIRED_RESULT inline MergeFileInfos* parent() const { return m_pParent; } setParent(MergeFileInfos * inParent)94 inline void setParent(MergeFileInfos* inParent) { m_pParent = inParent; } children()95 Q_REQUIRED_RESULT inline const QList<MergeFileInfos*>& children() const { return m_children; } addChild(MergeFileInfos * child)96 inline void addChild(MergeFileInfos* child) { m_children.push_back(child); } clear()97 inline void clear() { m_children.clear(); } 98 getFileInfoA()99 Q_REQUIRED_RESULT FileAccess* getFileInfoA() const { return m_pFileInfoA; } getFileInfoB()100 Q_REQUIRED_RESULT FileAccess* getFileInfoB() const { return m_pFileInfoB; } getFileInfoC()101 Q_REQUIRED_RESULT FileAccess* getFileInfoC() const { return m_pFileInfoC; } 102 setFileInfoA(FileAccess * newInfo)103 void setFileInfoA(FileAccess* newInfo) { m_pFileInfoA = newInfo; } setFileInfoB(FileAccess * newInfo)104 void setFileInfoB(FileAccess* newInfo) { m_pFileInfoB = newInfo; } setFileInfoC(FileAccess * newInfo)105 void setFileInfoC(FileAccess* newInfo) { m_pFileInfoC = newInfo; } 106 107 Q_REQUIRED_RESULT QString fullNameA() const; 108 Q_REQUIRED_RESULT QString fullNameB() const; 109 Q_REQUIRED_RESULT QString fullNameC() const; 110 Q_REQUIRED_RESULT QString fullNameDest() const; 111 getDirectoryInfo()112 Q_REQUIRED_RESULT static inline QSharedPointer<DirectoryInfo> getDirectoryInfo() { return gDirInfo; } 113 getDirNameA()114 Q_REQUIRED_RESULT inline QString getDirNameA() const { return getDirectoryInfo()->dirA().prettyAbsPath(); } getDirNameB()115 Q_REQUIRED_RESULT inline QString getDirNameB() const { return getDirectoryInfo()->dirB().prettyAbsPath(); } getDirNameC()116 Q_REQUIRED_RESULT inline QString getDirNameC() const { return getDirectoryInfo()->dirC().prettyAbsPath(); } getDirNameDest()117 Q_REQUIRED_RESULT inline QString getDirNameDest() const { return getDirectoryInfo()->destDir().prettyAbsPath(); } 118 diffStatus()119 Q_REQUIRED_RESULT inline TotalDiffStatus& diffStatus() { return m_totalDiffStatus; } 120 getOperation()121 Q_REQUIRED_RESULT inline e_MergeOperation getOperation() const { return m_eMergeOperation; } setOperation(const e_MergeOperation op)122 inline void setOperation(const e_MergeOperation op) { m_eMergeOperation = op; } 123 getOpStatus()124 Q_REQUIRED_RESULT inline e_OperationStatus getOpStatus() const { return m_eOpStatus; } setOpStatus(const e_OperationStatus eOpStatus)125 inline void setOpStatus(const e_OperationStatus eOpStatus) { m_eOpStatus = eOpStatus; } 126 getAgeA()127 Q_REQUIRED_RESULT inline e_Age getAgeA() const { return m_ageA; } getAgeB()128 Q_REQUIRED_RESULT inline e_Age getAgeB() const { return m_ageB; } getAgeC()129 Q_REQUIRED_RESULT inline e_Age getAgeC() const { return m_ageC; } 130 isEqualAB()131 Q_REQUIRED_RESULT inline bool isEqualAB() const { return m_bEqualAB; } isEqualAC()132 Q_REQUIRED_RESULT inline bool isEqualAC() const { return m_bEqualAC; } isEqualBC()133 Q_REQUIRED_RESULT inline bool isEqualBC() const { return m_bEqualBC; } 134 bool compareFilesAndCalcAges(QStringList& errors, QSharedPointer<Options> const &pOptions, DirectoryMergeWindow* pDMW); 135 136 void updateAge(); 137 138 void updateParents(); 139 140 void updateDirectoryOrLink(); startSimOp()141 inline void startSimOp() { m_bSimOpComplete = false; } isSimOpRunning()142 Q_REQUIRED_RESULT inline bool isSimOpRunning() const { return !m_bOperationComplete; } endSimOp()143 inline void endSimOp() { m_bSimOpComplete = true; } 144 startOperation()145 inline void startOperation() { m_bOperationComplete = false; }; isOperationRunning()146 Q_REQUIRED_RESULT inline bool isOperationRunning() const { return !m_bOperationComplete; } endOperation()147 inline void endOperation() { m_bOperationComplete = true; }; 148 isThreeWay()149 Q_REQUIRED_RESULT inline bool isThreeWay() const 150 { 151 if(getDirectoryInfo() == nullptr) return false; 152 return getDirectoryInfo()->dirC().isValid(); 153 } existsEveryWhere()154 Q_REQUIRED_RESULT inline bool existsEveryWhere() const { return existsInA() && existsInB() && (existsInC() || !isThreeWay()); } 155 existsCount()156 Q_REQUIRED_RESULT inline int existsCount() const { return (existsInA() ? 1 : 0) + (existsInB() ? 1 : 0) + (existsInC() ? 1 : 0); } 157 onlyInA()158 Q_REQUIRED_RESULT inline bool onlyInA() const { return existsInA() && !existsInB() && !existsInC(); } onlyInB()159 Q_REQUIRED_RESULT inline bool onlyInB() const { return !existsInA() && existsInB() && !existsInC(); } onlyInC()160 Q_REQUIRED_RESULT inline bool onlyInC() const { return !existsInA() && !existsInB() && existsInC(); } 161 conflictingAges()162 Q_REQUIRED_RESULT bool conflictingAges() const { return m_bConflictingAges; } 163 164 private: 165 bool fastFileComparison(FileAccess& fi1, FileAccess& fi2, bool& bError, QString& status, const QSharedPointer<const Options> &pOptions); setAgeA(const e_Age inAge)166 inline void setAgeA(const e_Age inAge) { m_ageA = inAge; } setAgeB(const e_Age inAge)167 inline void setAgeB(const e_Age inAge) { m_ageB = inAge; } setAgeC(const e_Age inAge)168 inline void setAgeC(const e_Age inAge) { m_ageC = inAge; } 169 170 MergeFileInfos* m_pParent; 171 QList<MergeFileInfos*> m_children; 172 173 FileAccess* m_pFileInfoA; 174 FileAccess* m_pFileInfoB; 175 FileAccess* m_pFileInfoC; 176 177 TotalDiffStatus m_totalDiffStatus; 178 179 e_MergeOperation m_eMergeOperation; 180 e_OperationStatus m_eOpStatus; 181 e_Age m_ageA; 182 e_Age m_ageB; 183 e_Age m_ageC; 184 185 bool m_bOperationComplete; 186 bool m_bSimOpComplete; 187 188 bool m_bEqualAB; 189 bool m_bEqualAC; 190 bool m_bEqualBC; 191 bool m_bConflictingAges; // Equal age but files are not! 192 }; 193 194 QTextStream& operator<<(QTextStream& ts, MergeFileInfos& mfi); 195 196 class MfiCompare 197 { 198 Qt::SortOrder mOrder; 199 200 public: MfiCompare(Qt::SortOrder order)201 explicit MfiCompare(Qt::SortOrder order) 202 { 203 mOrder = order; 204 } operator()205 bool operator()(MergeFileInfos* pMFI1, MergeFileInfos* pMFI2) 206 { 207 bool bDir1 = pMFI1->isDirA() || pMFI1->isDirB() || pMFI1->isDirC(); 208 bool bDir2 = pMFI2->isDirA() || pMFI2->isDirB() || pMFI2->isDirC(); 209 if(bDir1 == bDir2) 210 { 211 if(mOrder == Qt::AscendingOrder) 212 { 213 return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) < 0; 214 } 215 else 216 { 217 return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) > 0; 218 } 219 } 220 else 221 return bDir1; 222 } 223 }; 224 225 #endif // !MERGEFILEINFO_H 226