File indexing completed on 2024-12-08 11:06:06
0001 // clang-format off 0002 /* 0003 * KDiff3 - Text Diff And Merge Tool 0004 * 0005 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 0006 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 // clang-format on 0010 #ifndef MERGEFILEINFO_H 0011 #define MERGEFILEINFO_H 0012 0013 #include "DirectoryInfo.h" 0014 #include "diff.h" 0015 #include "fileaccess.h" 0016 0017 #include <QSharedPointer> 0018 #include <QString> 0019 0020 enum e_MergeOperation 0021 { 0022 eTitleId, 0023 eNoOperation, 0024 // Operations in sync mode (with only two directories): 0025 eCopyAToB, 0026 eCopyBToA, 0027 eDeleteA, 0028 eDeleteB, 0029 eDeleteAB, 0030 eMergeToA, 0031 eMergeToB, 0032 eMergeToAB, 0033 0034 // Operations in merge mode (with two or three directories) 0035 eCopyAToDest, 0036 eCopyBToDest, 0037 eCopyCToDest, 0038 eDeleteFromDest, 0039 eMergeABCToDest, 0040 eMergeABToDest, 0041 eConflictingFileTypes, // Error 0042 eChangedAndDeleted, // Error 0043 eConflictingAges // Equal age but files are not! 0044 }; 0045 0046 enum e_Age 0047 { 0048 eNew, 0049 eMiddle, 0050 eOld, 0051 eNotThere, 0052 eAgeEnd 0053 }; 0054 0055 enum e_OperationStatus 0056 { 0057 eOpStatusNone, 0058 eOpStatusDone, 0059 eOpStatusError, 0060 eOpStatusSkipped, 0061 eOpStatusNotSaved, 0062 eOpStatusInProgress, 0063 eOpStatusToDo 0064 }; 0065 0066 class DirectoryMergeWindow; 0067 0068 class MergeFileInfos 0069 { 0070 public: 0071 MergeFileInfos(); 0072 ~MergeFileInfos(); 0073 0074 [[nodiscard]] QString subPath() const; 0075 [[nodiscard]] QString fileName() const; 0076 0077 [[nodiscard]] bool isDirA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isDir() : false; } 0078 [[nodiscard]] bool isDirB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isDir() : false; } 0079 [[nodiscard]] bool isDirC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isDir() : false; } 0080 [[nodiscard]] bool hasDir() const { return isDirA() || isDirB() || isDirC(); } 0081 0082 [[nodiscard]] bool isLinkA() const { return m_pFileInfoA != nullptr ? m_pFileInfoA->isSymLink() : false; } 0083 [[nodiscard]] bool isLinkB() const { return m_pFileInfoB != nullptr ? m_pFileInfoB->isSymLink() : false; } 0084 [[nodiscard]] bool isLinkC() const { return m_pFileInfoC != nullptr ? m_pFileInfoC->isSymLink() : false; } 0085 [[nodiscard]] bool hasLink() const { return isLinkA() || isLinkB() || isLinkC(); } 0086 0087 [[nodiscard]] bool existsInA() const { return m_pFileInfoA != nullptr; } 0088 [[nodiscard]] bool existsInB() const { return m_pFileInfoB != nullptr; } 0089 [[nodiscard]] bool existsInC() const { return m_pFileInfoC != nullptr; } 0090 0091 [[nodiscard]] bool conflictingFileTypes() const; 0092 0093 void sort(Qt::SortOrder order); 0094 [[nodiscard]] inline MergeFileInfos* parent() const { return m_pParent; } 0095 inline void setParent(MergeFileInfos* inParent) { m_pParent = inParent; } 0096 [[nodiscard]] inline const QList<MergeFileInfos*>& children() const { return m_children; } 0097 inline void addChild(MergeFileInfos* child) { m_children.push_back(child); } 0098 inline void clear() { m_children.clear(); } 0099 0100 [[nodiscard]] FileAccess* getFileInfoA() const { return m_pFileInfoA; } 0101 [[nodiscard]] FileAccess* getFileInfoB() const { return m_pFileInfoB; } 0102 [[nodiscard]] FileAccess* getFileInfoC() const { return m_pFileInfoC; } 0103 0104 void setFileInfoA(FileAccess* newInfo) { m_pFileInfoA = newInfo; } 0105 void setFileInfoB(FileAccess* newInfo) { m_pFileInfoB = newInfo; } 0106 void setFileInfoC(FileAccess* newInfo) { m_pFileInfoC = newInfo; } 0107 0108 [[nodiscard]] QString fullNameA() const; 0109 [[nodiscard]] QString fullNameB() const; 0110 [[nodiscard]] QString fullNameC() const; 0111 [[nodiscard]] QString fullNameDest() const; 0112 0113 [[nodiscard]] inline QString getDirNameA() const { return gDirInfo->dirA().prettyAbsPath(); } 0114 [[nodiscard]] inline QString getDirNameB() const { return gDirInfo->dirB().prettyAbsPath(); } 0115 [[nodiscard]] inline QString getDirNameC() const { return gDirInfo->dirC().prettyAbsPath(); } 0116 [[nodiscard]] inline QString getDirNameDest() const { return gDirInfo->destDir().prettyAbsPath(); } 0117 0118 [[nodiscard]] inline TotalDiffStatus& diffStatus() { return m_totalDiffStatus; } 0119 0120 [[nodiscard]] inline e_MergeOperation getOperation() const { return m_eMergeOperation; } 0121 inline void setOperation(const e_MergeOperation op) { m_eMergeOperation = op; } 0122 0123 [[nodiscard]] inline e_OperationStatus getOpStatus() const { return m_eOpStatus; } 0124 inline void setOpStatus(const e_OperationStatus eOpStatus) { m_eOpStatus = eOpStatus; } 0125 0126 [[nodiscard]] inline e_Age getAgeA() const { return m_ageA; } 0127 [[nodiscard]] inline e_Age getAgeB() const { return m_ageB; } 0128 [[nodiscard]] inline e_Age getAgeC() const { return m_ageC; } 0129 0130 [[nodiscard]] inline bool isEqualAB() const { return m_bEqualAB; } 0131 [[nodiscard]] inline bool isEqualAC() const { return m_bEqualAC; } 0132 [[nodiscard]] inline bool isEqualBC() const { return m_bEqualBC; } 0133 bool compareFilesAndCalcAges(QStringList& errors, DirectoryMergeWindow* pDMW); 0134 0135 void updateAge(); 0136 0137 void updateParents(); 0138 0139 void updateDirectoryOrLink(); 0140 inline void startSimOp() { m_bSimOpComplete = false; } 0141 [[nodiscard]] inline bool isSimOpRunning() const { return !m_bOperationComplete; } 0142 inline void endSimOp() { m_bSimOpComplete = true; } 0143 0144 inline void startOperation() { m_bOperationComplete = false; }; 0145 [[nodiscard]] inline bool isOperationRunning() const { return !m_bOperationComplete; } 0146 inline void endOperation() { m_bOperationComplete = true; }; 0147 0148 [[nodiscard]] inline static bool isThreeWay() 0149 { 0150 if(gDirInfo == nullptr) return false; 0151 return gDirInfo->dirC().isValid(); 0152 } 0153 [[nodiscard]] inline bool existsEveryWhere() const { return existsInA() && existsInB() && (existsInC() || !isThreeWay()); } 0154 0155 [[nodiscard]] inline qint32 existsCount() const { return (existsInA() ? 1 : 0) + (existsInB() ? 1 : 0) + (existsInC() ? 1 : 0); } 0156 0157 [[nodiscard]] inline bool onlyInA() const { return existsInA() && !existsInB() && !existsInC(); } 0158 [[nodiscard]] inline bool onlyInB() const { return !existsInA() && existsInB() && !existsInC(); } 0159 [[nodiscard]] inline bool onlyInC() const { return !existsInA() && !existsInB() && existsInC(); } 0160 0161 [[nodiscard]] bool conflictingAges() const { return m_bConflictingAges; } 0162 0163 private: 0164 [[nodiscard]] e_Age nextAgeValue(e_Age age) 0165 { 0166 switch(age) 0167 { 0168 case eNew: 0169 return eMiddle; 0170 case eMiddle: 0171 return eOld; 0172 case eOld: 0173 return eNotThere; 0174 case eNotThere: 0175 return eAgeEnd; 0176 case eAgeEnd: 0177 assert(false); 0178 } 0179 return age; 0180 } 0181 0182 bool fastFileComparison(FileAccess& fi1, FileAccess& fi2, bool& bError, QString& status); 0183 inline void setAgeA(const e_Age inAge) { m_ageA = inAge; } 0184 inline void setAgeB(const e_Age inAge) { m_ageB = inAge; } 0185 inline void setAgeC(const e_Age inAge) { m_ageC = inAge; } 0186 0187 MergeFileInfos* m_pParent = nullptr; 0188 QList<MergeFileInfos*> m_children; 0189 0190 FileAccess* m_pFileInfoA = nullptr; 0191 FileAccess* m_pFileInfoB = nullptr; 0192 FileAccess* m_pFileInfoC = nullptr; 0193 0194 TotalDiffStatus m_totalDiffStatus; 0195 0196 e_MergeOperation m_eMergeOperation = eNoOperation; 0197 e_OperationStatus m_eOpStatus = eOpStatusNone; 0198 e_Age m_ageA = eNotThere; 0199 e_Age m_ageB = eNotThere; 0200 e_Age m_ageC = eNotThere; 0201 0202 bool m_bOperationComplete = false; 0203 bool m_bSimOpComplete = false; 0204 0205 bool m_bEqualAB = false; 0206 bool m_bEqualAC = false; 0207 bool m_bEqualBC = false; 0208 bool m_bConflictingAges = false; // Equal age but files are not! 0209 }; 0210 0211 QTextStream& operator<<(QTextStream& ts, MergeFileInfos& mfi); 0212 0213 class MfiCompare 0214 { 0215 Qt::SortOrder mOrder; 0216 0217 public: 0218 explicit MfiCompare(Qt::SortOrder order) 0219 { 0220 mOrder = order; 0221 } 0222 bool operator()(MergeFileInfos* pMFI1, MergeFileInfos* pMFI2) 0223 { 0224 bool bDir1 = pMFI1->isDirA() || pMFI1->isDirB() || pMFI1->isDirC(); 0225 bool bDir2 = pMFI2->isDirA() || pMFI2->isDirB() || pMFI2->isDirC(); 0226 if(bDir1 == bDir2) 0227 { 0228 if(mOrder == Qt::AscendingOrder) 0229 { 0230 return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) < 0; 0231 } 0232 else 0233 { 0234 return pMFI1->fileName().compare(pMFI2->fileName(), Qt::CaseInsensitive) > 0; 0235 } 0236 } 0237 else 0238 return bDir1; 0239 } 0240 }; 0241 0242 #endif // !MERGEFILEINFO_H