OSDN Git Service

Merge remote-tracking branch 'upstream/master' into jp
[winmerge-jp/winmerge-jp.git] / Src / DirActions.h
1 #pragma once
2
3 #include "UnicodeString.h"
4 #include "DiffContext.h"
5 #include "FileActionScript.h"
6 #include "paths.h"
7 #include "IntToIntMap.h"
8 #include <algorithm>
9 #include "FileTransform.h"
10
11 class CDiffContext;
12 class PathContext;
13 class PluginManager;
14 class FileActionScript;
15 class CTempPathContext;
16
17 /**
18  * @brief Folder compare icon indexes.
19  * This `enum` defines indexes for the imagelist used for folder/file compare icons.
20  * Note that this enum must be in synch with code in CDirView::OnInitialUpdate() and
21  * GetColImage(). Also remember that icons are in resource file...
22  */
23 enum
24 {
25         DIFFIMG_LUNIQUE,
26         DIFFIMG_MUNIQUE,
27         DIFFIMG_RUNIQUE,
28         DIFFIMG_LMISSING,
29         DIFFIMG_MMISSING,
30         DIFFIMG_RMISSING,
31         DIFFIMG_DIFF,
32         DIFFIMG_SAME,
33         DIFFIMG_FILE,
34         DIFFIMG_BINSAME,
35         DIFFIMG_BINDIFF,
36         DIFFIMG_LDIRUNIQUE,
37         DIFFIMG_MDIRUNIQUE,
38         DIFFIMG_RDIRUNIQUE,
39         DIFFIMG_LDIRMISSING,
40         DIFFIMG_MDIRMISSING,
41         DIFFIMG_RDIRMISSING,
42         DIFFIMG_SKIP,
43         DIFFIMG_DIRSKIP,
44         DIFFIMG_DIRDIFF,
45         DIFFIMG_DIRSAME,
46         DIFFIMG_DIR,
47         DIFFIMG_ERROR,
48         DIFFIMG_DIRUP,
49         DIFFIMG_DIRUP_DISABLE,
50         DIFFIMG_ABORT,
51         DIFFIMG_TEXTDIFF,
52         DIFFIMG_TEXTSAME,
53         DIFFIMG_IMAGEDIFF,
54         DIFFIMG_IMAGESAME,
55 };
56
57 typedef enum {
58         SIDE_LEFT = 1,
59         SIDE_MIDDLE,
60         SIDE_RIGHT
61 } SIDE_TYPE;
62
63 typedef enum {
64         SELECTIONTYPE_NORMAL,
65         SELECTIONTYPE_LEFT1LEFT2,
66         SELECTIONTYPE_RIGHT1RIGHT2,
67         SELECTIONTYPE_LEFT1RIGHT2,
68         SELECTIONTYPE_LEFT2RIGHT1
69 } SELECTIONTYPE;
70
71 typedef enum {
72         UPDATEITEM_NONE,
73         UPDATEITEM_UPDATE,
74         UPDATEITEM_REMOVE
75 } UPDATEITEM_TYPE;
76
77 struct AllowUpwardDirectory
78 {
79         enum ReturnCode
80         {
81                 Never,
82                 No,
83                 ParentIsRegularPath,
84                 ParentIsTempPath
85         };
86 };
87
88
89 struct DirViewFilterSettings
90 {
91         template<class GetOptionBool>
92         explicit DirViewFilterSettings(GetOptionBool getoptbool)
93         {
94                 show_skipped = getoptbool(OPT_SHOW_SKIPPED);
95                 show_unique_left = getoptbool(OPT_SHOW_UNIQUE_LEFT);
96                 show_unique_middle = getoptbool(OPT_SHOW_UNIQUE_MIDDLE);
97                 show_unique_right = getoptbool(OPT_SHOW_UNIQUE_RIGHT);
98                 show_binaries = getoptbool(OPT_SHOW_BINARIES);
99                 show_identical = getoptbool(OPT_SHOW_IDENTICAL);
100                 show_different = getoptbool(OPT_SHOW_DIFFERENT);
101                 show_different_left_only = getoptbool(OPT_SHOW_DIFFERENT_LEFT_ONLY);
102                 show_different_middle_only = getoptbool(OPT_SHOW_DIFFERENT_MIDDLE_ONLY);
103                 show_different_right_only = getoptbool(OPT_SHOW_DIFFERENT_RIGHT_ONLY);
104                 show_missing_left_only = getoptbool(OPT_SHOW_MISSING_LEFT_ONLY);
105                 show_missing_middle_only = getoptbool(OPT_SHOW_MISSING_MIDDLE_ONLY);
106                 show_missing_right_only = getoptbool(OPT_SHOW_MISSING_RIGHT_ONLY);
107                 tree_mode = getoptbool(OPT_TREE_MODE);
108         };
109         bool show_skipped;
110         bool show_unique_left;
111         bool show_unique_middle;
112         bool show_unique_right;
113         bool show_binaries;
114         bool show_identical;
115         bool show_different;
116         bool show_different_left_only;
117         bool show_different_middle_only;
118         bool show_different_right_only;
119         bool show_missing_left_only;
120         bool show_missing_middle_only;
121         bool show_missing_right_only;
122         bool tree_mode;
123 };
124
125 typedef std::map<String, bool> DirViewTreeState;
126
127 String NumToStr(int n);
128 String FormatFilesAffectedString(int nFilesAffected, int nFilesTotal);
129 String FormatMenuItemString(SIDE_TYPE src, int count, int total);
130 String FormatMenuItemString(SIDE_TYPE src, SIDE_TYPE dst, int count, int total);
131 String FormatMenuItemStringAll(int nDirs, int count, int total);
132 String FormatMenuItemString(const String& fmt1, const String& fmt2, int count, int total);
133 String FormatMenuItemStringTo(SIDE_TYPE src, int count, int total);
134 String FormatMenuItemStringAllTo(int nDirs, int count, int total);
135 String FormatMenuItemStringDifferencesTo(int count, int total);
136
137 void ConfirmActionList(const CDiffContext& ctxt, const FileActionScript & actionList);
138 UPDATEITEM_TYPE UpdateDiffAfterOperation(const FileActionItem & act, CDiffContext& ctxt, DIFFITEM &di);
139
140 DIFFITEM *FindItemFromPaths(const CDiffContext& ctxt, const PathContext& paths);
141
142 bool IsItemCopyable(const DIFFITEM &di, int index);
143 bool IsItemMovable(const DIFFITEM &di, int index);
144 bool IsItemDeletable(const DIFFITEM &di, int index);
145 bool IsItemDeletableOnBoth(const CDiffContext& ctxt, const DIFFITEM &di);
146 bool AreItemsOpenable(const CDiffContext& ctxt, SELECTIONTYPE selectionType, const DIFFITEM &di1, const DIFFITEM &di2, bool openableForDir = true);
147 bool AreItemsOpenable(const CDiffContext& ctxt, const DIFFITEM &di1, const DIFFITEM &di2, const DIFFITEM &di3, bool openableForDir = true);
148 bool IsItemOpenableOn(const DIFFITEM &di, int index);
149 bool IsItemOpenableOnWith(const DIFFITEM &di, int index);
150 bool IsItemCopyableToOn(const DIFFITEM &di, int index);
151 bool IsItemNavigableDiff(const CDiffContext& ctxt, const DIFFITEM &di);
152 bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM &di);
153 bool IsShowable(const CDiffContext& ctxt, const DIFFITEM &di, const DirViewFilterSettings& filter);
154
155 bool GetOpenOneItem(const CDiffContext& ctxt, DIFFITEM *pos1, const DIFFITEM *pdi[3],
156                 PathContext &paths, int & sel1, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
157 bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, DIFFITEM *pos1, DIFFITEM *pos2, const DIFFITEM *pdi[3],
158                 PathContext &paths, int & sel1, int & sel2, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
159 bool GetOpenThreeItems(const CDiffContext& ctxt, DIFFITEM *pos1, DIFFITEM *pos2, DIFFITEM *pos3, const DIFFITEM *pdi[3],
160                 PathContext &paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
161
162 void GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di, String& strLeft, String& strRight);
163 PathContext GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di);
164 String GetItemFileName(const CDiffContext& ctx, const DIFFITEM &di, int index);
165 int GetColImage(const DIFFITEM &di);
166
167 void SetDiffStatus(DIFFITEM& di, unsigned  diffcode, unsigned mask);
168 void SetDiffCompare(DIFFITEM& di, unsigned diffcode);
169 void CopyDiffSideAndProperties(DIFFITEM& di, int src, int dst);
170 void UnsetDiffSide(DIFFITEM& di, int index);
171 void UpdateStatusFromDisk(CDiffContext& ctxt, DIFFITEM& di, int index);
172 int UpdateCompareFlagsAfterSync(DIFFITEM& di, bool bRecursive);
173 void UpdatePaths(int nDirs, DIFFITEM& di);
174 void SetDiffCounts(DIFFITEM& di, unsigned diffs, unsigned ignored);
175 void SetItemViewFlag(DIFFITEM& di, unsigned flag, unsigned mask);
176 void SetItemViewFlag(CDiffContext& ctxt, unsigned flag, unsigned mask);
177 void MarkForRescan(DIFFITEM& di);
178
179 bool RenameOnSameDir(const String& szOldFileName, const String& szNewFileName);
180
181 void ExpandSubdirs(CDiffContext& ctxt, DIFFITEM& dip);
182 void ExpandAllSubdirs(CDiffContext &ctxt);
183 void ExpandDifferentSubdirs(CDiffContext &ctxt);
184 void ExpandIdenticalSubdirs(CDiffContext &ctxt);
185 void CollapseAllSubdirs(CDiffContext &ctxt);
186 DirViewTreeState *SaveTreeState(const CDiffContext& ctxt);
187 void RestoreTreeState(CDiffContext &ctxt, DirViewTreeState *pTreeState);
188
189 AllowUpwardDirectory::ReturnCode
190 CheckAllowUpwardDirectory(const CDiffContext& ctxt, const CTempPathContext *pTempPathContext, PathContext &pathsParent);
191
192 inline int SideToIndex(const CDiffContext& ctxt, SIDE_TYPE stype)
193 {
194         switch (stype)
195         {
196         case SIDE_MIDDLE: return ctxt.GetCompareDirs() == 3 ? 1 : -1;
197         case SIDE_RIGHT: return ctxt.GetCompareDirs() - 1;
198         default: return 0;
199         }
200 }
201
202 struct ConfirmationNeededException
203 {
204         String m_caption;
205         String m_question;
206         String m_fromText;
207         String m_toText;
208         String m_fromPath;
209         String m_toPath;
210 };
211
212 struct ContentsChangedException
213 {
214         explicit ContentsChangedException(const String& failpath);
215         String m_msg;
216 };
217
218 struct FileOperationException
219 {
220         explicit FileOperationException(const String& msg);
221         String m_msg;
222 };
223
224 struct DirActions
225 {
226         typedef bool (DirActions::*method_type2)(const DIFFITEM& di) const;
227         typedef FileActionScript *(DirActions::*method_type)(FileActionScript *, const std::pair<int, const DIFFITEM *>& it) const;
228
229         DirActions(const CDiffContext& ctxt, const bool RO[], method_type func = nullptr, method_type2 func2 = nullptr) : 
230                 m_ctxt(ctxt), m_RO(RO), m_cur_method(func), m_cur_method2(func2) {}
231
232         template <SIDE_TYPE src, SIDE_TYPE dst>
233         bool IsItemCopyableOnTo(const DIFFITEM& di) const
234         {
235                 return (di.diffcode.diffcode != 0 && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemCopyable(di, SideToIndex(m_ctxt, src)));
236         }
237
238         template <SIDE_TYPE src>
239         bool IsItemCopyableToOn(const DIFFITEM& di) const
240         {
241                 return (di.diffcode.diffcode != 0 && ::IsItemCopyableToOn(di, SideToIndex(m_ctxt, src)));
242         }
243
244         bool IsItemCopyableBothToOn(const DIFFITEM& di) const
245         {
246                 if (di.diffcode.diffcode != 0)
247                 {
248                         int i;
249                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
250                         {
251                                 if (!::IsItemCopyableToOn(di, i))
252                                         break;
253                         }
254                         return (i == m_ctxt.GetCompareDirs());
255                 }
256                 return false;
257         }
258
259         /**
260          * @brief Return whether the specified diff item is renamable.
261          * @param [in] di Diff item to check
262          * @return true if the specified diff item is renamable.
263          */
264         bool IsItemRenamable(const DIFFITEM& di) const
265         {
266                 int nDirs = m_ctxt.GetCompareDirs();
267                 for (int i = 0; i < nDirs; i++)
268                         if (di.diffcode.exists(i) && m_RO[i])
269                                 return false;
270                 return true;
271         }
272
273         template <SIDE_TYPE src, SIDE_TYPE dst>
274         bool IsItemMovableOnTo(const DIFFITEM& di) const
275         {
276                 const int idx = SideToIndex(m_ctxt, src);
277                 return (di.diffcode.diffcode != 0 && !m_RO[idx] && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemMovable(di, idx));
278         }
279
280         template <SIDE_TYPE src>
281         bool IsItemMovableToOn(const DIFFITEM& di) const
282         {
283                 const int idx = SideToIndex(m_ctxt, src);
284                 return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx) && ::IsItemCopyableToOn(di, idx));
285         }
286
287         template <SIDE_TYPE src>
288         bool IsItemDeletableOn(const DIFFITEM& di) const
289         { 
290                 const int idx = SideToIndex(m_ctxt, src);
291                 return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx));
292         }
293
294         bool IsItemDeletableOnBoth(const DIFFITEM& di) const
295         {
296                 if (di.diffcode.diffcode != 0)
297                 {
298                         int i;
299                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
300                         {
301                                 if (m_RO[i] || !IsItemDeletable(di, i))
302                                         break;
303                         }
304                         return (i == m_ctxt.GetCompareDirs());
305                 }
306                 return false;
307         }
308         bool IsItemDeletableOnEitherOrBoth(const DIFFITEM& di) const
309         {
310                 if (di.diffcode.diffcode != 0)
311                 {
312                         int i;
313                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
314                         {
315                                 if (!m_RO[i] && IsItemDeletable(di, i))
316                                         break;
317                         }
318                         return (i < m_ctxt.GetCompareDirs());
319                 }
320                 return false;
321         }
322
323         template <SIDE_TYPE src>
324         bool IsItemOpenableOn(const DIFFITEM& di) const
325         {
326                 return (di.diffcode.diffcode != 0 && ::IsItemOpenableOn(di, SideToIndex(m_ctxt, src)));
327         }
328
329         template <SIDE_TYPE src>
330         bool IsItemOpenableOnWith(const DIFFITEM& di) const
331         {
332                 return (di.diffcode.diffcode != 0 && ::IsItemOpenableOnWith(di, SideToIndex(m_ctxt, src)));
333         }
334
335         template <SIDE_TYPE src>
336         bool IsParentFolderOpenable(const DIFFITEM& di) const
337         {
338                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(SideToIndex(m_ctxt, src)));
339         }
340
341         bool IsItemFile(const DIFFITEM& di) const
342         {
343                 return (di.diffcode.diffcode != 0 && !di.diffcode.isDirectory());
344         }
345
346         template <SIDE_TYPE src>
347         bool IsItemExist(const DIFFITEM& di) const
348         {
349                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(SideToIndex(m_ctxt, src)));
350         }
351
352         template <SIDE_TYPE src>
353         bool IsItemEditableEncoding(const DIFFITEM& di) const
354         {
355                 const int index = SideToIndex(m_ctxt, src);
356                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(index) && di.diffFileInfo[index].IsEditableEncoding());
357         }
358
359         bool IsItemNavigableDiff(const DIFFITEM& di) const
360         {
361                 return ::IsItemNavigableDiff(m_ctxt, di);
362         }
363
364         FileActionScript *CopyItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src, SIDE_TYPE dst) const
365         {
366                 const DIFFITEM& di = *it.second;
367                 const int srcidx = SideToIndex(m_ctxt, src);
368                 const int dstidx = SideToIndex(m_ctxt, dst);
369                 if (di.diffcode.diffcode != 0 && !m_RO[dstidx] && IsItemCopyable(di, srcidx))
370                 {
371                         FileActionItem act;
372                         act.src  = GetItemFileName(m_ctxt, di, srcidx);
373                         act.dest = GetItemFileName(m_ctxt, di, dstidx);
374                         
375                         // We must check that paths still exists
376                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
377                                 throw ContentsChangedException(act.src);
378
379                         act.context = it.first;
380                         act.dirflag = di.diffcode.isDirectory();
381                         act.atype = FileAction::ACT_COPY;
382                         act.UIResult = FileActionItem::UI_SYNC;
383                         act.UIOrigin = srcidx;
384                         act.UIDestination = dstidx;
385                         pscript->AddActionItem(act);
386                 }
387                 return pscript;
388         }
389
390         template<SIDE_TYPE src, SIDE_TYPE to>
391         FileActionScript *Copy(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
392         {
393                 return CopyItem(pscript, it, src, to);
394         }
395
396         FileActionScript *MoveItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src, SIDE_TYPE dst) const
397         {
398                 const DIFFITEM& di = *it.second;
399                 const int srcidx = SideToIndex(m_ctxt, src);
400                 const int dstidx = SideToIndex(m_ctxt, dst);
401                 if (di.diffcode.diffcode != 0 && !m_RO[dstidx] && IsItemMovable(di, srcidx))
402                 {
403                         FileActionItem act;
404                         act.src  = GetItemFileName(m_ctxt, di, srcidx);
405                         act.dest = GetItemFileName(m_ctxt, di, dstidx);
406                         
407                         // We must check that paths still exists
408                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
409                                 throw ContentsChangedException(act.src);
410
411                         act.context = it.first;
412                         act.dirflag = di.diffcode.isDirectory();
413                         act.atype = FileAction::ACT_MOVE;
414                         act.UIResult = FileActionItem::UI_MOVE;
415                         act.UIOrigin = srcidx;
416                         act.UIDestination = dstidx;
417                         pscript->AddActionItem(act);
418                 }
419                 return pscript;
420         }
421
422         template<SIDE_TYPE src, SIDE_TYPE to>
423         FileActionScript *Move(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
424         {
425                 return MoveItem(pscript, it, src, to);
426         }
427
428         FileActionScript *DeleteItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src) const
429         {
430                 const DIFFITEM& di = *it.second;
431                 const int index = SideToIndex(m_ctxt, src);
432                 if (di.diffcode.diffcode != 0 && !m_RO[index] && IsItemDeletable(di, index))
433                 {
434                         FileActionItem act;
435                         act.src = GetItemFileName(m_ctxt, di, index);
436
437                         // We must check that path still exists
438                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
439                                 throw ContentsChangedException(act.src);
440
441                         act.context = it.first;
442                         act.dirflag = di.diffcode.isDirectory();
443                         act.atype = FileAction::ACT_DEL;
444                         act.UIOrigin = index;
445                         act.UIResult = FileActionItem::UI_DEL;
446                         pscript->AddActionItem(act);
447                 }
448                 return pscript;
449         }
450
451         template<SIDE_TYPE src>
452         FileActionScript *DeleteOn(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
453         {
454                 return DeleteItem(pscript, it, src);
455         }
456
457         FileActionScript *DeleteOnBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
458         {
459                 const DIFFITEM& di = *it.second;
460
461                 if (di.diffcode.diffcode != 0 && IsItemDeletableOnBoth(di) && 
462                         (std::count(m_RO, m_RO + m_ctxt.GetCompareDirs(), true) == 0))
463                 {
464                         for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
465                         {
466                                 FileActionItem act;
467                                 act.src = GetItemFileName(m_ctxt, di, i);
468                                 // We must first check that paths still exists
469                                 if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
470                                         throw ContentsChangedException(act.src);
471                                 act.context = it.first;
472                                 act.dirflag = di.diffcode.isDirectory();
473                                 act.atype = FileAction::ACT_DEL;
474                                 act.UIOrigin = i;
475                                 act.UIResult = FileActionItem::UI_DEL;
476                                 pscript->AddActionItem(act);
477                         }
478                 }
479                 return pscript;
480         }
481
482         FileActionScript *DeleteOnEitherOrBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
483         {
484                 const DIFFITEM& di = *it.second;
485                 if (di.diffcode.diffcode != 0)
486                 {
487                         for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
488                         {
489                                 if (IsItemDeletable(di, i) && !m_RO[i])
490                                 {
491                                         FileActionItem act;
492                                         act.src = GetItemFileName(m_ctxt, di, i);
493                                         // We must first check that paths still exists
494                                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
495                                                 throw ContentsChangedException(act.src);
496                                         act.UIResult = FileActionItem::UI_DEL;
497                                         act.dirflag = di.diffcode.isDirectory();
498                                         act.context = it.first;
499                                         act.UIOrigin = i;
500                                         act.atype = FileAction::ACT_DEL;
501                                         pscript->AddActionItem(act);
502                                 }
503                         }
504                 }
505                 return pscript;
506         }
507
508         FileActionScript *CopyOrMoveItemTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, FileAction::ACT_TYPE atype, SIDE_TYPE src) const
509         {
510                 const int index = SideToIndex(m_ctxt, src);
511                 const DIFFITEM& di = *it.second;
512
513                 if (di.diffcode.diffcode != 0 && di.diffcode.exists(index) &&
514                         (atype == FileAction::ACT_MOVE ? (!m_RO[index] && IsItemDeletable(di, index)) : true))
515                 {
516                         FileActionItem act;
517                         act.src = GetItemFileName(m_ctxt, di, index);
518                          
519                         // We must check that path still exists
520                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
521                                 throw ContentsChangedException(act.src);
522
523                         act.dest = paths::ConcatPath(pscript->m_destBase, di.diffFileInfo[index].GetFile());
524                         act.dirflag = di.diffcode.isDirectory();
525                         act.context = it.first;
526                         act.atype = atype;
527                         act.UIResult = (atype == FileAction::ACT_COPY) ? FileActionItem::UI_DONT_CARE : FileActionItem::UI_DEL;
528                         act.UIOrigin = index;
529                         pscript->AddActionItem(act);
530                 }
531                 return pscript;
532         }
533
534         template<SIDE_TYPE src>
535         FileActionScript *CopyTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
536         {
537                 return CopyOrMoveItemTo(pscript, it, FileAction::ACT_COPY, src);
538         }
539
540         template<SIDE_TYPE src>
541         FileActionScript *MoveTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
542         {
543                 return CopyOrMoveItemTo(pscript, it, FileAction::ACT_MOVE, src);
544         }
545
546         FileActionScript *operator()(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
547         {
548                 return ((*this).*m_cur_method)(pscript, it);
549         }
550
551         bool operator()(const DIFFITEM &di) const
552         {
553                 return ((*this).*m_cur_method2)(di);
554         }
555
556         method_type m_cur_method;
557         method_type2 m_cur_method2;
558         const CDiffContext& m_ctxt;
559         const bool *m_RO;
560 };
561
562 struct Counts {
563         Counts() : count(0), total(0) {}
564         Counts(int c, int t): count(c), total(t) {}
565         int count;
566         int total;
567 };
568
569 template<class InputIterator, class Predicate>
570 Counts Count(const InputIterator& begin, const InputIterator& end, const Predicate& pred) 
571 {
572         int count = 0, total = 0;
573         for (InputIterator it = begin; it != end; ++it)
574         {
575                 if (pred(*it))
576                         ++count;
577                 ++total;
578         }
579         return Counts(count, total);
580 }
581
582 /**
583  * @brief Rename selected item on both left and right sides.
584  *
585  * @param szNewItemName [in] New item name.
586  *
587  * @return true if at least one file was renamed successfully.
588  */
589 template<class InputIterator>
590 bool DoItemRename(InputIterator& it, const CDiffContext& ctxt, const String& szNewItemName)
591 {
592         PathContext paths;
593         int nDirs = ctxt.GetCompareDirs();
594
595         assert(it != InputIterator());
596
597         // We must check that paths still exists
598         DIFFITEM &di = *it;
599         paths = ::GetItemFileNames(ctxt, di);
600         for (int index = 0; index < nDirs; index++)
601         {
602                 if (di.diffcode.exists(index) && paths::DoesPathExist(paths[index]) == paths::DOES_NOT_EXIST)
603                         throw ContentsChangedException(paths[index]);
604         }
605
606         bool bRename[3] = {false};
607         for (int index = 0; index < nDirs; index++)
608         {
609                 if (di.diffcode.exists(index))
610                         bRename[index] = RenameOnSameDir(paths[index], szNewItemName);
611         }
612
613         if (std::count(bRename, bRename + nDirs, true) == 0)
614                 return false;
615         
616         di.diffcode.setSideNone();
617         for (int index = 0; index < nDirs; index++)
618         {
619                 di.diffFileInfo[index].filename = szNewItemName;
620                 bool bSetSideFlag = bRename[index];
621                 if (!bSetSideFlag)
622                 {
623                         paths::PATH_EXISTENCE pathExist = paths::DoesPathExist(GetItemFileName(ctxt, di, index));
624                         bool bIsDirectory = di.diffcode.isDirectory();
625                         if (((pathExist == paths::IS_EXISTING_DIR) && bIsDirectory) || ((pathExist == paths::IS_EXISTING_FILE) && !bIsDirectory))
626                                 bSetSideFlag = true;
627                 }
628                 if (bSetSideFlag)
629                         di.diffcode.setSideFlag(index);
630         }
631         return true;
632 }
633
634 template<class InputIterator, class OutputIterator>
635 OutputIterator CopyPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, SIDE_TYPE stype, const CDiffContext& ctxt)
636 {
637         const int index = SideToIndex(ctxt, stype);
638         for (InputIterator it = begin; it != end; ++it)
639         {
640                 const DIFFITEM& di = *it;
641                 if (di.diffcode.exists(index))
642                 {
643                         *result = GetItemFileName(ctxt, di, index);
644                         ++result;
645                 }
646         }
647         return result;
648 }
649
650 template<class InputIterator, class OutputIterator>
651 OutputIterator CopyBothPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
652 {
653         for (InputIterator it = begin; it != end; ++it)
654         {
655                 const DIFFITEM& di = *it;
656                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
657                 {
658                         if (di.diffcode.exists(i))
659                         {
660                                 *result = GetItemFileName(ctxt, di, i);
661                                 ++result;
662                         }
663                 }
664         }
665         return result;
666 }
667
668 template<class InputIterator, class OutputIterator>
669 OutputIterator CopyFilenames(const InputIterator& begin, const InputIterator& end, OutputIterator result)
670 {
671         for (InputIterator it = begin; it != end; ++it)
672         {
673                 const DIFFITEM& di = *it;
674                 if (!di.diffcode.isDirectory())
675                 {
676                         *result = di.diffFileInfo[0].filename;
677                         ++result;
678                 }
679         }
680         return result;
681 }
682
683 template<class InputIterator, class OutputIterator>
684 OutputIterator CopyPathnamesForDragAndDrop(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
685 {
686         for (InputIterator it = begin; it != end; ++it)
687         {
688                 const DIFFITEM& di = *it;
689
690                 // check for special items (e.g not "..")
691                 if (di.diffcode.diffcode == 0)
692                         continue;
693
694                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
695                 {
696                         if (di.diffcode.exists(i))
697                         {
698                                 *result = GetItemFileName(ctxt, di, i);
699                                 ++result;
700                         }
701                 }
702         }
703         return result;
704 }
705
706 template<class InputIterator, class BinaryFunction>
707 void ApplyFolderNameAndFileName(const InputIterator& begin, const InputIterator& end, SIDE_TYPE stype,
708         const CDiffContext& ctxt, BinaryFunction func)
709 {
710         int index = SideToIndex(ctxt, stype);
711         for (InputIterator it = begin; it != end; ++it)
712         {
713                 const DIFFITEM& di = *it;
714                 if (di.diffcode.diffcode == 0 /* Invalid value, this must be special item */ ||
715                     !di.diffcode.exists(index)) 
716                         continue;
717                 String filename = di.diffFileInfo[index].filename;
718                 String currentDir = di.getFilepath(index, ctxt.GetNormalizedPath(index));
719                 func(currentDir, filename);
720         }
721 }
722
723 /**
724  * @brief Apply specified setting for prediffing to all selected items
725  */
726 template<class InputIterator>
727 void ApplyPluginPipeline(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt, bool unpacker, const String& pluginPipeline)
728 {
729         // Unlike other group actions, here we don't build an action list
730         // to execute; we just apply this change directly
731         if( !ctxt.m_bPluginsEnabled || ctxt.m_piPluginInfos == nullptr )
732                 return;
733         for (InputIterator it = begin; it != end; ++it)
734         {
735                 const DIFFITEM& di = *it;
736                 if (!di.diffcode.isDirectory())
737                 {
738                         PackingInfo * infoUnpacker = nullptr;
739                         PrediffingInfo * infoPrediffer = nullptr;
740                         String filteredFilenames = ctxt.GetFilteredFilenames(di);
741                         const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer);
742                         if (unpacker)
743                                 infoUnpacker->SetPluginPipeline(pluginPipeline);
744                         else
745                                 infoPrediffer->SetPluginPipeline(pluginPipeline);
746                 }
747         }
748 }
749
750 /**
751  * @brief Updates just before displaying plugin context view in list
752  */
753 template<class InputIterator>
754 std::tuple<int, int, int> CountPluginNoneAutoOthers(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt, bool unpacker)
755 {
756         int nNone = 0;
757         int nAuto = 0;
758         int nOthers = 0;
759         if( !ctxt.m_bPluginsEnabled || ctxt.m_piPluginInfos == nullptr ) 
760                 return std::make_tuple(nNone, nAuto, nOthers);
761
762         for (InputIterator it = begin; it != end; ++it)
763         {
764                 const DIFFITEM& di = *it;
765                 if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
766                         continue;
767
768                 // note the prediffer flag for 'files present on both sides and not skipped'
769                 if (!di.diffcode.isDirectory() && !di.diffcode.isBin() && IsItemExistAll(ctxt, di)
770                         && !di.diffcode.isResultFiltered())
771                 {
772                         PackingInfo * infoUnpacker;
773                         PrediffingInfo * infoPrediffer;
774                         String filteredFilenames = ctxt.GetFilteredFilenames(di);
775                         const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer);
776                         String pluginPipeline = unpacker ? infoUnpacker->GetPluginPipeline() : infoPrediffer->GetPluginPipeline();
777                         if (pluginPipeline.empty())
778                                 nNone++;
779                         else if (pluginPipeline == _T("<Automatic>"))
780                                 nAuto++;
781                         else
782                                 nOthers++;
783                 }
784         }
785         return std::make_tuple(nNone, nAuto, nOthers);
786 }
787
788 template<class InputIterator>
789 IntToIntMap CountCodepages(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
790 {
791         IntToIntMap map;
792         for (InputIterator it = begin; it != end; ++it)
793         {
794                 const DIFFITEM& di = *it;
795                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
796                 {
797                         if (di.diffcode.diffcode != 0 && di.diffcode.exists(i))
798                                 map.Increment(di.diffFileInfo[i].encoding.m_codepage);
799                 }
800         }
801         return map;
802 }
803
804 template<class InputIterator>
805 void ApplyCodepage(const InputIterator& begin, const InputIterator& end, CDiffContext& ctxt, const bool affect[3], int nCodepage)
806 {
807         for (InputIterator it = begin; it != end; ++it)
808         {
809                 DIFFITEM& di = *it;
810                 if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
811                         continue;
812                 if (di.diffcode.isDirectory())
813                         continue;
814
815                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
816                 {
817                         // Does it exist on left? (ie, right or both)
818                         if (affect[i] && di.diffcode.exists(i) && di.diffFileInfo[i].IsEditableEncoding())
819                         {
820                                 di.diffFileInfo[i].encoding.SetCodepage(nCodepage);
821                         }
822                 }
823         }
824 }
825
826 /// get file name on specified side for first selected item
827 template<class InputIterator>
828 String GetSelectedFileName(InputIterator& it, SIDE_TYPE stype, const CDiffContext& ctxt)
829 {
830         if (it == InputIterator())
831                 return _T("");
832         return GetItemFileName(ctxt, *it, SideToIndex(ctxt, stype));
833 }