OSDN Git Service

Keep hidden items (#1377)
[winmerge-jp/winmerge-jp.git] / Src / DiffItem.cpp
1 /**
2  *  @file DiffItem.cpp
3  *
4  *  @brief Implementation of DIFFITEM
5  */ 
6
7 #include "pch.h"
8 #include "DiffItem.h"
9 #include "paths.h"
10 #include "DebugNew.h"
11
12 DIFFITEM DIFFITEM::emptyitem;
13
14 /** @brief DIFFITEM's destructor */
15 DIFFITEM::~DIFFITEM()
16 {
17         RemoveChildren();
18         assert(children == nullptr);
19 }
20
21 /** @brief Return path to left/right file, including all but file name */
22 String DIFFITEM::getFilepath(int nIndex, const String &sRoot) const
23 {
24         if (diffcode.exists(nIndex))
25         {
26                 return paths::ConcatPath(sRoot, diffFileInfo[nIndex].path);
27         }
28         return _T("");
29 }
30
31 /** @brief Return the relative path to file/folder including the item name*/
32 String DIFFITEM::getItemRelativePath() const
33 {
34         String resp = _T("");
35         int compareIndex ;
36
37         //determine what is the trees contain the item to be hidden
38         for (compareIndex = 0; (compareIndex < 3) && (diffFileInfo[compareIndex].size == -1); compareIndex++);
39
40         if (compareIndex < 3) 
41         {
42                 resp = paths::ConcatPath(diffFileInfo[compareIndex].path, diffFileInfo[compareIndex].filename);
43         }
44
45         return resp; 
46 }
47 /** @brief Return depth of path */
48 int DIFFITEM::GetDepth() const
49 {
50         const DIFFITEM *cur;
51         int depth;
52         for (depth = 0, cur = parent; cur->parent != nullptr; depth++, cur = cur->parent)
53                 ;
54         return depth;
55 }
56
57 /**
58  * @brief Return whether the specified item is an ancestor of the current item
59  */
60 bool DIFFITEM::IsAncestor(const DIFFITEM *pdi) const
61 {
62         const DIFFITEM *cur;
63         for (cur = this; cur->parent != nullptr; cur = cur->parent)
64         {
65                 if (cur->parent == pdi)
66                         return true;
67         }
68         return false;
69 }
70
71 /**
72  * @brief Return all ancestors of the current item.
73  */
74 std::vector<const DIFFITEM*> DIFFITEM::GetAncestors() const
75 {
76         int depth = GetDepth();
77         std::vector<const DIFFITEM*> ancestors(depth);
78
79         const DIFFITEM* cur;
80         int i;
81         for (i = 0, cur = parent; cur->parent != nullptr; i++, cur = cur->parent)
82         {
83                 assert(depth - i - 1 >= 0 && depth - i - 1 < depth);
84                 ancestors[depth - i - 1] = cur;
85         }
86         return ancestors;
87 }
88
89 /** @brief Remove and delete all children DIFFITEM entries */
90 void DIFFITEM::RemoveChildren()
91 {
92         DIFFITEM *pRem = children;
93         while (pRem != nullptr)
94         {
95                 assert(pRem->parent == this);
96                 DIFFITEM *pNext = pRem->Flink;
97                 delete pRem;
98                 pRem = pNext;
99         }
100         children = nullptr;
101 }
102
103 /** @brief Swap two items in `diffFileInfo[]`.  Used when swapping GUI panes. */
104 void DIFFITEM::Swap(int idx1, int idx2)
105 {
106         std::swap(diffFileInfo[idx1], diffFileInfo[idx2]);
107         diffcode.swap(idx1, idx2);
108         if (HasChildren())
109         {
110                 for (DIFFITEM *p = children; p != nullptr; p = p->Flink)
111                         p->Swap(idx1, idx2);
112         }
113 }
114
115 void DIFFITEM::ClearAllAdditionalProperties()
116 {
117         const int n = ((diffcode.diffcode & DIFFCODE::THREEWAY) != 0) ? 3 : 2;
118         for (int i = 0; i < n; ++i)
119                 diffFileInfo[i].m_pAdditionalProperties.reset();
120         if (HasChildren())
121         {
122                 for (DIFFITEM *p = children; p != nullptr; p = p->Flink)
123                         p->ClearAllAdditionalProperties();
124         }
125
126 }
127
128 /* static */
129 DIFFITEM *DIFFITEM::GetEmptyItem()  
130
131         // TODO: It would be better if there were individual items
132         // (for whatever these special items are?) because here we 
133         // have to *hope* client does not modify this static (shared) item
134
135         assert(emptyitem.parent == nullptr);
136         assert(emptyitem.Flink == nullptr);
137         assert(emptyitem.Blink == nullptr);
138         assert(emptyitem.children == nullptr);
139         assert(emptyitem.nidiffs == -1);
140         assert(emptyitem.nsdiffs == -1);
141         assert(emptyitem.customFlags == ViewCustomFlags::INVALID_CODE);
142         assert(emptyitem.diffcode.diffcode == 0);
143
144         return &emptyitem; 
145 }
146
147  
148 /**
149 * @brief Add Sibling item
150 * @param [in] p The item to be added
151 */
152 void DIFFITEM::AppendSibling(DIFFITEM *p)
153 {
154         assert(parent->children == this);
155
156         // Two situations
157
158         if (Blink == nullptr)
159         {
160                 // Insert first sibling (besides ourself)
161                 assert(Flink == nullptr);
162                 p->Flink = nullptr;
163                 p->Blink = this;
164                 Flink = p;
165         }
166         else
167         {
168                 // Insert additional siblings
169                 assert(Flink != nullptr);
170                 p->Flink = nullptr;
171                 p->Blink = Blink;
172                 Blink->Flink = p;
173         }
174         Blink = p;
175 }
176
177 void DIFFITEM::AddChildToParent(DIFFITEM *p)
178 {
179         p->parent = this;
180         if (children == nullptr)
181                 // First child
182                 children = p;
183         else
184                 // More siblings
185                 children->AppendSibling(p);
186 }
187
188 void DIFFITEM::DelinkFromSiblings()
189 {
190         if (parent != nullptr && parent->children != nullptr)
191         {
192                 // If `this` is at end of Sibling linkage, fix First Child's end link
193                 if (parent->children->Blink == this)
194                 {
195                         assert(Flink == nullptr);
196                         parent->children->Blink = Blink;
197                         if (Blink == this)
198                                 Blink = nullptr;
199                 }
200                 // If `this` is the First Child, link parent to next Sibling
201                 if (parent->children == this)
202                 {
203                         parent->children = Flink;
204                 }
205         }
206         if (Blink != nullptr && Blink->Flink != nullptr)
207                 Blink->Flink = Flink;
208         if (Flink != nullptr)
209                 Flink->Blink = Blink;
210         Flink = Blink = nullptr;
211 }
212
213 void DIFFCODE::swap(int idx1, int idx2)
214 {
215         bool e[3] = { false, false, false };
216         for (int i = 0; i < 3; ++i)
217                 e[i] = exists(i);
218         std::swap(e[idx1], e[idx2]);
219         setSideNone();
220         for (int i = 0; i < 3; ++i)
221                 if (e[i]) setSideFlag(i);
222         bool binflag1 = (diffcode & (BINSIDE1 << idx1));
223         bool binflag2 = (diffcode & (BINSIDE1 << idx2));
224         Set(BINSIDE1 << idx1, binflag2 ? (BINSIDE1 << idx1) : 0);
225         Set(BINSIDE1 << idx2, binflag1 ? (BINSIDE1 << idx2) : 0);
226         if ((diffcode & THREEWAY) != 0)
227         {
228                 int idx = -1;
229                 switch (diffcode & COMPAREFLAGS3WAY)
230                 {
231                 case DIFF1STONLY:
232                         if (idx1 == 0 || idx2 == 0)
233                                 idx = (idx1 == 0) ? idx2 : idx1;
234                         break;
235                 case DIFF2NDONLY:
236                         if (idx1 == 1 || idx2 == 1)
237                                 idx = (idx1 == 1) ? idx2 : idx1;
238                         break;
239                 case DIFF3RDONLY:
240                         if (idx1 == 2 || idx2 == 2)
241                                 idx = (idx1 == 2) ? idx2 : idx1;
242                         break;
243                 }
244                 if (idx == 0)
245                         Set(COMPAREFLAGS3WAY, DIFF1STONLY);
246                 else if (idx == 1)
247                         Set(COMPAREFLAGS3WAY, DIFF2NDONLY);
248                 else if (idx == 2)
249                         Set(COMPAREFLAGS3WAY, DIFF3RDONLY);
250         }
251 }