OSDN Git Service

3f0cbf2c6cafe252dc6d389f31ac31cd0b6496f5
[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 IsItemDeletable(const DIFFITEM &di, int index);
144 bool IsItemDeletableOnBoth(const CDiffContext& ctxt, const DIFFITEM &di);
145 bool AreItemsOpenable(const CDiffContext& ctxt, SELECTIONTYPE selectionType, const DIFFITEM &di1, const DIFFITEM &di2, bool openableForDir = true);
146 bool AreItemsOpenable(const CDiffContext& ctxt, const DIFFITEM &di1, const DIFFITEM &di2, const DIFFITEM &di3, bool openableForDir = true);
147 bool IsItemOpenableOn(const DIFFITEM &di, int index);
148 bool IsItemOpenableOnWith(const DIFFITEM &di, int index);
149 bool IsItemCopyableToOn(const DIFFITEM &di, int index);
150 bool IsItemNavigableDiff(const CDiffContext& ctxt, const DIFFITEM &di);
151 bool IsItemExistAll(const CDiffContext& ctxt, const DIFFITEM &di);
152 bool IsShowable(const CDiffContext& ctxt, const DIFFITEM &di, const DirViewFilterSettings& filter);
153
154 bool GetOpenOneItem(const CDiffContext& ctxt, DIFFITEM *pos1, const DIFFITEM *pdi[3],
155                 PathContext &paths, int & sel1, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
156 bool GetOpenTwoItems(const CDiffContext& ctxt, SELECTIONTYPE selectionType, DIFFITEM *pos1, DIFFITEM *pos2, const DIFFITEM *pdi[3],
157                 PathContext &paths, int & sel1, int & sel2, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
158 bool GetOpenThreeItems(const CDiffContext& ctxt, DIFFITEM *pos1, DIFFITEM *pos2, DIFFITEM *pos3, const DIFFITEM *pdi[3],
159                 PathContext &paths, int & sel1, int & sel2, int & sel3, bool & isDir, int nPane[3], FileTextEncoding encoding[3], String& errmsg, bool openableForDir = true);
160
161 void GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di, String& strLeft, String& strRight);
162 PathContext GetItemFileNames(const CDiffContext& ctxt, const DIFFITEM& di);
163 String GetItemFileName(const CDiffContext& ctx, const DIFFITEM &di, int index);
164 int GetColImage(const DIFFITEM &di);
165
166 void SetDiffStatus(DIFFITEM& di, unsigned  diffcode, unsigned mask);
167 void SetDiffCompare(DIFFITEM& di, unsigned diffcode);
168 void CopyDiffSide(DIFFITEM& di, int src, int dst);
169 void UnsetDiffSide(DIFFITEM& di, int index);
170 void UpdateStatusFromDisk(CDiffContext& ctxt, DIFFITEM& di, int index);
171 void SetDiffCounts(DIFFITEM& di, unsigned diffs, unsigned ignored);
172 void SetItemViewFlag(DIFFITEM& di, unsigned flag, unsigned mask);
173 void SetItemViewFlag(CDiffContext& ctxt, unsigned flag, unsigned mask);
174 void MarkForRescan(DIFFITEM& di);
175
176 bool RenameOnSameDir(const String& szOldFileName, const String& szNewFileName);
177
178 void ExpandSubdirs(CDiffContext& ctxt, DIFFITEM& dip);
179 void ExpandAllSubdirs(CDiffContext &ctxt);
180 void CollapseAllSubdirs(CDiffContext &ctxt);
181 DirViewTreeState *SaveTreeState(const CDiffContext& ctxt);
182 void RestoreTreeState(CDiffContext &ctxt, DirViewTreeState *pTreeState);
183
184 AllowUpwardDirectory::ReturnCode
185 CheckAllowUpwardDirectory(const CDiffContext& ctxt, const CTempPathContext *pTempPathContext, PathContext &pathsParent);
186
187 inline int SideToIndex(const CDiffContext& ctxt, SIDE_TYPE stype)
188 {
189         switch (stype)
190         {
191         case SIDE_MIDDLE: return ctxt.GetCompareDirs() == 3 ? 1 : -1;
192         case SIDE_RIGHT: return ctxt.GetCompareDirs() - 1;
193         default: return 0;
194         }
195 }
196
197 struct ConfirmationNeededException
198 {
199         String m_caption;
200         String m_question;
201         String m_fromText;
202         String m_toText;
203         String m_fromPath;
204         String m_toPath;
205 };
206
207 struct ContentsChangedException
208 {
209         explicit ContentsChangedException(const String& failpath);
210         String m_msg;
211 };
212
213 struct FileOperationException
214 {
215         explicit FileOperationException(const String& msg);
216         String m_msg;
217 };
218
219 struct DirActions
220 {
221         typedef bool (DirActions::*method_type2)(const DIFFITEM& di) const;
222         typedef FileActionScript *(DirActions::*method_type)(FileActionScript *, const std::pair<int, const DIFFITEM *>& it) const;
223
224         DirActions(const CDiffContext& ctxt, const bool RO[], method_type func = nullptr, method_type2 func2 = nullptr) : 
225                 m_ctxt(ctxt), m_RO(RO), m_cur_method(func), m_cur_method2(func2) {}
226
227         template <SIDE_TYPE src, SIDE_TYPE dst>
228         bool IsItemCopyableOnTo(const DIFFITEM& di) const
229         {
230                 return (di.diffcode.diffcode != 0 && !m_RO[SideToIndex(m_ctxt, dst)] && ::IsItemCopyable(di, SideToIndex(m_ctxt, src)));
231         }
232
233         template <SIDE_TYPE src>
234         bool IsItemCopyableToOn(const DIFFITEM& di) const
235         {
236                 return (di.diffcode.diffcode != 0 && ::IsItemCopyableToOn(di, SideToIndex(m_ctxt, src)));
237         }
238
239         bool IsItemCopyableBothToOn(const DIFFITEM& di) const
240         {
241                 if (di.diffcode.diffcode != 0)
242                 {
243                         int i;
244                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
245                         {
246                                 if (!::IsItemCopyableToOn(di, i))
247                                         break;
248                         }
249                         return (i == m_ctxt.GetCompareDirs());
250                 }
251                 return false;
252         }
253
254         template <SIDE_TYPE src>
255         bool IsItemMovableToOn(const DIFFITEM& di) const
256         {
257                 const int idx = SideToIndex(m_ctxt, src);
258                 return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx) && ::IsItemCopyableToOn(di, idx));
259         }
260
261         template <SIDE_TYPE src>
262         bool IsItemDeletableOn(const DIFFITEM& di) const
263         { 
264                 const int idx = SideToIndex(m_ctxt, src);
265                 return (di.diffcode.diffcode != 0 && !m_RO[idx] && IsItemDeletable(di, idx));
266         }
267
268         bool IsItemDeletableOnBoth(const DIFFITEM& di) const
269         {
270                 if (di.diffcode.diffcode != 0)
271                 {
272                         int i;
273                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
274                         {
275                                 if (m_RO[i] || !IsItemDeletable(di, i))
276                                         break;
277                         }
278                         return (i == m_ctxt.GetCompareDirs());
279                 }
280                 return false;
281         }
282         bool IsItemDeletableOnEitherOrBoth(const DIFFITEM& di) const
283         {
284                 if (di.diffcode.diffcode != 0)
285                 {
286                         int i;
287                         for (i = 0; i < m_ctxt.GetCompareDirs(); ++i)
288                         {
289                                 if (!m_RO[i] && IsItemDeletable(di, i))
290                                         break;
291                         }
292                         return (i < m_ctxt.GetCompareDirs());
293                 }
294                 return false;
295         }
296
297         template <SIDE_TYPE src>
298         bool IsItemOpenableOn(const DIFFITEM& di) const
299         {
300                 return (di.diffcode.diffcode != 0 && ::IsItemOpenableOn(di, SideToIndex(m_ctxt, src)));
301         }
302
303         template <SIDE_TYPE src>
304         bool IsItemOpenableOnWith(const DIFFITEM& di) const
305         {
306                 return (di.diffcode.diffcode != 0 && ::IsItemOpenableOnWith(di, SideToIndex(m_ctxt, src)));
307         }
308
309         template <SIDE_TYPE src>
310         bool IsParentFolderOpenable(const DIFFITEM& di) const
311         {
312                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(SideToIndex(m_ctxt, src)));
313         }
314
315         bool IsItemFile(const DIFFITEM& di) const
316         {
317                 return (di.diffcode.diffcode != 0 && !di.diffcode.isDirectory());
318         }
319
320         template <SIDE_TYPE src>
321         bool IsItemExist(const DIFFITEM& di) const
322         {
323                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(SideToIndex(m_ctxt, src)));
324         }
325
326         template <SIDE_TYPE src>
327         bool IsItemEditableEncoding(const DIFFITEM& di) const
328         {
329                 const int index = SideToIndex(m_ctxt, src);
330                 return (di.diffcode.diffcode != 0 && di.diffcode.exists(index) && di.diffFileInfo[index].IsEditableEncoding());
331         }
332
333         bool IsItemNavigableDiff(const DIFFITEM& di) const
334         {
335                 return ::IsItemNavigableDiff(m_ctxt, di);
336         }
337
338         FileActionScript *CopyItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src, SIDE_TYPE dst) const
339         {
340                 const DIFFITEM& di = *it.second;
341                 const int srcidx = SideToIndex(m_ctxt, src);
342                 const int dstidx = SideToIndex(m_ctxt, dst);
343                 if (di.diffcode.diffcode != 0 && !m_RO[dstidx] && IsItemCopyable(di, srcidx))
344                 {
345                         FileActionItem act;
346                         act.src  = GetItemFileName(m_ctxt, di, srcidx);
347                         act.dest = GetItemFileName(m_ctxt, di, dstidx);
348                         
349                         // We must check that paths still exists
350                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
351                                 throw ContentsChangedException(act.src);
352
353                         act.context = it.first;
354                         act.dirflag = di.diffcode.isDirectory();
355                         act.atype = FileAction::ACT_COPY;
356                         act.UIResult = FileActionItem::UI_SYNC;
357                         act.UIOrigin = srcidx;
358                         act.UIDestination = dstidx;
359                         pscript->AddActionItem(act);
360                 }
361                 return pscript;
362         }
363
364         template<SIDE_TYPE src, SIDE_TYPE to>
365         FileActionScript *Copy(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
366         {
367                 return CopyItem(pscript, it, src, to);
368         }
369
370         FileActionScript *DeleteItem(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, SIDE_TYPE src) const
371         {
372                 const DIFFITEM& di = *it.second;
373                 const int index = SideToIndex(m_ctxt, src);
374                 if (di.diffcode.diffcode != 0 && !m_RO[index] && IsItemDeletable(di, index))
375                 {
376                         FileActionItem act;
377                         act.src = GetItemFileName(m_ctxt, di, index);
378
379                         // We must check that path still exists
380                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
381                                 throw ContentsChangedException(act.src);
382
383                         act.context = it.first;
384                         act.dirflag = di.diffcode.isDirectory();
385                         act.atype = FileAction::ACT_DEL;
386                         act.UIOrigin = index;
387                         act.UIResult = FileActionItem::UI_DEL;
388                         pscript->AddActionItem(act);
389                 }
390                 return pscript;
391         }
392
393         template<SIDE_TYPE src>
394         FileActionScript *DeleteOn(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
395         {
396                 return DeleteItem(pscript, it, src);
397         }
398
399         FileActionScript *DeleteOnBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
400         {
401                 const DIFFITEM& di = *it.second;
402
403                 if (di.diffcode.diffcode != 0 && IsItemDeletableOnBoth(di) && 
404                         (std::count(m_RO, m_RO + m_ctxt.GetCompareDirs(), true) == 0))
405                 {
406                         for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
407                         {
408                                 FileActionItem act;
409                                 act.src = GetItemFileName(m_ctxt, di, i);
410                                 // We must first check that paths still exists
411                                 if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
412                                         throw ContentsChangedException(act.src);
413                                 act.context = it.first;
414                                 act.dirflag = di.diffcode.isDirectory();
415                                 act.atype = FileAction::ACT_DEL;
416                                 act.UIOrigin = i;
417                                 act.UIResult = FileActionItem::UI_DEL;
418                                 pscript->AddActionItem(act);
419                         }
420                 }
421                 return pscript;
422         }
423
424         FileActionScript *DeleteOnEitherOrBoth(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
425         {
426                 const DIFFITEM& di = *it.second;
427                 if (di.diffcode.diffcode != 0)
428                 {
429                         for (int i = 0; i < m_ctxt.GetCompareDirs(); ++i)
430                         {
431                                 if (IsItemDeletable(di, i) && !m_RO[i])
432                                 {
433                                         FileActionItem act;
434                                         act.src = GetItemFileName(m_ctxt, di, i);
435                                         // We must first check that paths still exists
436                                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
437                                                 throw ContentsChangedException(act.src);
438                                         act.UIResult = FileActionItem::UI_DEL;
439                                         act.dirflag = di.diffcode.isDirectory();
440                                         act.context = it.first;
441                                         act.UIOrigin = i;
442                                         act.atype = FileAction::ACT_DEL;
443                                         pscript->AddActionItem(act);
444                                 }
445                         }
446                 }
447                 return pscript;
448         }
449
450         FileActionScript *CopyOrMoveItemTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it, FileAction::ACT_TYPE atype, SIDE_TYPE src) const
451         {
452                 const int index = SideToIndex(m_ctxt, src);
453                 const DIFFITEM& di = *it.second;
454
455                 if (di.diffcode.diffcode != 0 && di.diffcode.exists(index) &&
456                         (atype == FileAction::ACT_MOVE ? (!m_RO[index] && IsItemDeletable(di, index)) : true))
457                 {
458                         FileActionItem act;
459                         act.src = GetItemFileName(m_ctxt, di, index);
460                          
461                         // We must check that path still exists
462                         if (paths::DoesPathExist(act.src) == paths::DOES_NOT_EXIST)
463                                 throw ContentsChangedException(act.src);
464
465                         act.dest = paths::ConcatPath(pscript->m_destBase, di.diffFileInfo[index].GetFile());
466                         act.dirflag = di.diffcode.isDirectory();
467                         act.context = it.first;
468                         act.atype = atype;
469                         act.UIResult = (atype == FileAction::ACT_COPY) ? FileActionItem::UI_DONT_CARE : FileActionItem::UI_DEL;
470                         act.UIOrigin = index;
471                         pscript->AddActionItem(act);
472                 }
473                 return pscript;
474         }
475
476         template<SIDE_TYPE src>
477         FileActionScript *CopyTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
478         {
479                 return CopyOrMoveItemTo(pscript, it, FileAction::ACT_COPY, src);
480         }
481
482         template<SIDE_TYPE src>
483         FileActionScript *MoveTo(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
484         {
485                 return CopyOrMoveItemTo(pscript, it, FileAction::ACT_MOVE, src);
486         }
487
488         FileActionScript *operator()(FileActionScript *pscript, const std::pair<int, const DIFFITEM *>& it) const
489         {
490                 return ((*this).*m_cur_method)(pscript, it);
491         }
492
493         bool operator()(const DIFFITEM &di) const
494         {
495                 return ((*this).*m_cur_method2)(di);
496         }
497
498         method_type m_cur_method;
499         method_type2 m_cur_method2;
500         const CDiffContext& m_ctxt;
501         const bool *m_RO;
502 };
503
504 struct Counts {
505         Counts() : count(0), total(0) {}
506         Counts(int c, int t): count(c), total(t) {}
507         int count;
508         int total;
509 };
510
511 template<class InputIterator, class Predicate>
512 Counts Count(const InputIterator& begin, const InputIterator& end, const Predicate& pred) 
513 {
514         int count = 0, total = 0;
515         for (InputIterator it = begin; it != end; ++it)
516         {
517                 if (pred(*it))
518                         ++count;
519                 ++total;
520         }
521         return Counts(count, total);
522 }
523
524 /**
525  * @brief Rename selected item on both left and right sides.
526  *
527  * @param szNewItemName [in] New item name.
528  *
529  * @return true if at least one file was renamed successfully.
530  */
531 template<class InputIterator>
532 bool DoItemRename(InputIterator& it, const CDiffContext& ctxt, const String& szNewItemName)
533 {
534         PathContext paths;
535         int nDirs = ctxt.GetCompareDirs();
536
537         assert(it != InputIterator());
538
539         // We must check that paths still exists
540         DIFFITEM &di = *it;
541         paths = ::GetItemFileNames(ctxt, di);
542         for (int index = 0; index < nDirs; index++)
543         {
544                 if (di.diffcode.exists(index) && paths::DoesPathExist(paths[index]) == paths::DOES_NOT_EXIST)
545                         throw ContentsChangedException(paths[index]);
546         }
547
548         bool bRename[3] = {false};
549         for (int index = 0; index < nDirs; index++)
550         {
551                 if (di.diffcode.exists(index))
552                         bRename[index] = RenameOnSameDir(paths[index], szNewItemName);
553         }
554
555         if (std::count(bRename, bRename + nDirs, true) == 0)
556                 return false;
557         
558         di.diffcode.setSideNone();
559         for (int index = 0; index < nDirs; index++)
560         {
561                 di.diffFileInfo[index].filename = szNewItemName;
562                 if (bRename[index] || paths::DoesPathExist(GetItemFileName(ctxt, di, index)))
563                         di.diffcode.setSideFlag(index);
564         }
565         return true;
566 }
567
568 template<class InputIterator, class OutputIterator>
569 OutputIterator CopyPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, SIDE_TYPE stype, const CDiffContext& ctxt)
570 {
571         const int index = SideToIndex(ctxt, stype);
572         for (InputIterator it = begin; it != end; ++it)
573         {
574                 const DIFFITEM& di = *it;
575                 if (di.diffcode.exists(index))
576                 {
577                         *result = GetItemFileName(ctxt, di, index);
578                         ++result;
579                 }
580         }
581         return result;
582 }
583
584 template<class InputIterator, class OutputIterator>
585 OutputIterator CopyBothPathnames(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
586 {
587         for (InputIterator it = begin; it != end; ++it)
588         {
589                 const DIFFITEM& di = *it;
590                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
591                 {
592                         if (di.diffcode.exists(i))
593                         {
594                                 *result = GetItemFileName(ctxt, di, i);
595                                 ++result;
596                         }
597                 }
598         }
599         return result;
600 }
601
602 template<class InputIterator, class OutputIterator>
603 OutputIterator CopyFilenames(const InputIterator& begin, const InputIterator& end, OutputIterator result)
604 {
605         for (InputIterator it = begin; it != end; ++it)
606         {
607                 const DIFFITEM& di = *it;
608                 if (!di.diffcode.isDirectory())
609                 {
610                         *result = di.diffFileInfo[0].filename;
611                         ++result;
612                 }
613         }
614         return result;
615 }
616
617 template<class InputIterator, class OutputIterator>
618 OutputIterator CopyPathnamesForDragAndDrop(const InputIterator& begin, const InputIterator& end, OutputIterator result, const CDiffContext& ctxt)
619 {
620         for (InputIterator it = begin; it != end; ++it)
621         {
622                 const DIFFITEM& di = *it;
623
624                 // check for special items (e.g not "..")
625                 if (di.diffcode.diffcode == 0)
626                         continue;
627
628                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
629                 {
630                         if (di.diffcode.exists(i))
631                         {
632                                 *result = GetItemFileName(ctxt, di, i);
633                                 ++result;
634                         }
635                 }
636         }
637         return result;
638 }
639
640 template<class InputIterator, class BinaryFunction>
641 void ApplyFolderNameAndFileName(const InputIterator& begin, const InputIterator& end, SIDE_TYPE stype,
642         const CDiffContext& ctxt, BinaryFunction func)
643 {
644         int index = SideToIndex(ctxt, stype);
645         for (InputIterator it = begin; it != end; ++it)
646         {
647                 const DIFFITEM& di = *it;
648                 if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
649                         continue;
650                 String filename = di.diffFileInfo[index].filename;
651                 String currentDir = di.getFilepath(index, ctxt.GetNormalizedPath(index));
652                 func(currentDir, filename);
653         }
654 }
655
656 /**
657  * @brief Apply specified setting for prediffing to all selected items
658  */
659 template<class InputIterator>
660 void ApplyPluginPrediffSetting(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt, PLUGIN_MODE newsetting)
661 {
662         // Unlike other group actions, here we don't build an action list
663         // to execute; we just apply this change directly
664         if( !ctxt.m_bPluginsEnabled || ctxt.m_piPluginInfos == nullptr )
665                 return;
666         for (InputIterator it = begin; it != end; ++it)
667         {
668                 const DIFFITEM& di = *it;
669                 if (!di.diffcode.isDirectory())
670                 {
671                         String filteredFilenames;
672                         for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
673                         {
674                                 if (di.diffcode.exists(i))
675                                 {
676                                         if (!filteredFilenames.empty()) filteredFilenames += _T("|");
677                                         filteredFilenames += ::GetItemFileName(ctxt, di, i);
678                                 }
679                         }
680                         PackingInfo * infoUnpacker = nullptr;
681                         PrediffingInfo * infoPrediffer = nullptr;
682                         const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &infoUnpacker, &infoPrediffer);
683                         infoPrediffer->Initialize(newsetting);
684                 }
685         }
686 }
687
688 /**
689  * @brief Updates just before displaying plugin context view in list
690  */
691 template<class InputIterator>
692 std::pair<int, int> CountPredifferYesNo(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
693 {
694         int nPredifferYes = 0;
695         int nPredifferNo = 0;
696         if( !ctxt.m_bPluginsEnabled || ctxt.m_piPluginInfos == nullptr ) 
697                 return std::make_pair(nPredifferYes, nPredifferNo);
698
699         for (InputIterator it = begin; it != end; ++it)
700         {
701                 const DIFFITEM& di = *it;
702                 if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
703                         continue;
704
705                 // note the prediffer flag for 'files present on both sides and not skipped'
706                 if (!di.diffcode.isDirectory() && !di.diffcode.isBin() && IsItemExistAll(ctxt, di)
707                         && !di.diffcode.isResultFiltered())
708                 {
709                         PathContext tFiles = GetItemFileNames(ctxt, di);
710                         String filteredFilenames = strutils::join(tFiles.begin(), tFiles.end(), _T("|"));
711                         PackingInfo * unpacker;
712                         PrediffingInfo * prediffer;
713                         const_cast<CDiffContext&>(ctxt).FetchPluginInfos(filteredFilenames, &unpacker, &prediffer);
714                         if (prediffer->m_PluginOrPredifferMode == PLUGIN_MODE::PLUGIN_AUTO || !prediffer->m_PluginName.empty())
715                                 nPredifferYes ++;
716                         else
717                                 nPredifferNo ++;
718                 }
719         }
720         return std::make_pair(nPredifferYes, nPredifferNo);
721 }
722
723 template<class InputIterator>
724 IntToIntMap CountCodepages(const InputIterator& begin, const InputIterator& end, const CDiffContext& ctxt)
725 {
726         IntToIntMap map;
727         for (InputIterator it = begin; it != end; ++it)
728         {
729                 const DIFFITEM& di = *it;
730                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
731                 {
732                         if (di.diffcode.diffcode != 0 && di.diffcode.exists(i))
733                                 map.Increment(di.diffFileInfo[i].encoding.m_codepage);
734                 }
735         }
736         return map;
737 }
738
739 template<class InputIterator>
740 void ApplyCodepage(const InputIterator& begin, const InputIterator& end, CDiffContext& ctxt, const bool affect[3], int nCodepage)
741 {
742         for (InputIterator it = begin; it != end; ++it)
743         {
744                 DIFFITEM& di = *it;
745                 if (di.diffcode.diffcode == 0) // Invalid value, this must be special item
746                         continue;
747                 if (di.diffcode.isDirectory())
748                         continue;
749
750                 for (int i = 0; i < ctxt.GetCompareDirs(); ++i)
751                 {
752                         // Does it exist on left? (ie, right or both)
753                         if (affect[i] && di.diffcode.exists(i) && di.diffFileInfo[i].IsEditableEncoding())
754                         {
755                                 di.diffFileInfo[i].encoding.SetCodepage(nCodepage);
756                         }
757                 }
758         }
759 }
760
761 /// get file name on specified side for first selected item
762 template<class InputIterator>
763 String GetSelectedFileName(InputIterator& it, SIDE_TYPE stype, const CDiffContext& ctxt)
764 {
765         if (it == InputIterator())
766                 return _T("");
767         return GetItemFileName(ctxt, *it, SideToIndex(ctxt, stype));
768 }