2 * @file DirViewColItems.cpp
4 * @brief Code for individual columns in the DirView
6 * @date Created: 2003-08-19
10 #include "DirViewColItems.h"
11 #include <Poco/Timestamp.h>
13 #include "UnicodeString.h"
15 #include "DiffContext.h"
19 #include "FileTransform.h"
22 using Poco::Timestamp;
28 const char *COLHDR_FILENAME = N_("Filename");
29 const char *COLHDR_DIR = NC_("DirView|ColumnHeader", "Folder");
30 const char *COLHDR_RESULT = N_("Comparison result");
31 const char *COLHDR_LTIMEM = N_("Left Date");
32 const char *COLHDR_RTIMEM = N_("Right Date");
33 const char *COLHDR_MTIMEM = N_("Middle Date");
34 const char *COLHDR_EXTENSION = N_("Extension");
35 const char *COLHDR_LSIZE = N_("Left Size");
36 const char *COLHDR_RSIZE = N_("Right Size");
37 const char *COLHDR_MSIZE = N_("Middle Size");
38 const char *COLHDR_RSIZE_SHORT = N_("Right Size (Short)");
39 const char *COLHDR_LSIZE_SHORT = N_("Left Size (Short)");
40 const char *COLHDR_MSIZE_SHORT = N_("Middle Size (Short)");
41 const char *COLHDR_LTIMEC = N_("Left Creation Time");
42 const char *COLHDR_RTIMEC = N_("Right Creation Time");
43 const char *COLHDR_MTIMEC = N_("Middle Creation Time");
44 const char *COLHDR_NEWER = N_("Newer File");
45 const char *COLHDR_LVERSION = N_("Left File Version");
46 const char *COLHDR_RVERSION = N_("Right File Version");
47 const char *COLHDR_MVERSION = N_("Middle File Version");
48 const char *COLHDR_RESULT_ABBR = N_("Short Result");
49 const char *COLHDR_LATTRIBUTES = N_("Left Attributes");
50 const char *COLHDR_RATTRIBUTES = N_("Right Attributes");
51 const char *COLHDR_MATTRIBUTES = N_("Middle Attributes");
52 const char *COLHDR_LEOL_TYPE = N_("Left EOL");
53 const char *COLHDR_MEOL_TYPE = N_("Middle EOL");
54 const char *COLHDR_REOL_TYPE = N_("Right EOL");
55 const char *COLHDR_LENCODING = N_("Left Encoding");
56 const char *COLHDR_RENCODING = N_("Right Encoding");
57 const char *COLHDR_MENCODING = N_("Middle Encoding");
58 const char *COLHDR_NIDIFFS = N_("Ignored Diff");
59 const char *COLHDR_NSDIFFS = N_("Differences");
60 const char *COLHDR_BINARY = NC_("DirView|ColumnHeader", "Binary");
61 const char *COLHDR_UNPACKER = N_("Unpacker");
62 const char *COLHDR_PREDIFFER = N_("Prediffer");
64 const char *COLDESC_FILENAME = N_("Filename or folder name.");
65 const char *COLDESC_DIR = N_("Subfolder name when subfolders are included.");
66 const char *COLDESC_RESULT = N_("Comparison result, long form.");
67 const char *COLDESC_LTIMEM = N_("Left side modification date.");
68 const char *COLDESC_RTIMEM = N_("Right side modification date.");
69 const char *COLDESC_MTIMEM = N_("Middle side modification date.");
70 const char *COLDESC_EXTENSION = N_("File's extension.");
71 const char *COLDESC_LSIZE = N_("Left file size in bytes.");
72 const char *COLDESC_RSIZE = N_("Right file size in bytes.");
73 const char *COLDESC_MSIZE = N_("Middle file size in bytes.");
74 const char *COLDESC_LSIZE_SHORT = N_("Left file size abbreviated.");
75 const char *COLDESC_RSIZE_SHORT = N_("Right file size abbreviated.");
76 const char *COLDESC_MSIZE_SHORT = N_("Middle file size abbreviated.");
77 const char *COLDESC_LTIMEC = N_("Left side creation time.");
78 const char *COLDESC_RTIMEC = N_("Right side creation time.");
79 const char *COLDESC_MTIMEC = N_("Middle side creation time.");
80 const char *COLDESC_NEWER = N_("Tells which side has newer modification date.");
81 const char *COLDESC_LVERSION = N_("Left side file version, only for some filetypes.");
82 const char *COLDESC_RVERSION = N_("Right side file version, only for some filetypes.");
83 const char *COLDESC_MVERSION = N_("Middle side file version, only for some filetypes.");
84 const char *COLDESC_RESULT_ABBR = N_("Short comparison result.");
85 const char *COLDESC_LATTRIBUTES = N_("Left side attributes.");
86 const char *COLDESC_RATTRIBUTES = N_("Right side attributes.");
87 const char *COLDESC_MATTRIBUTES = N_("Middle side attributes.");
88 const char *COLDESC_LEOL_TYPE = N_("Left side file EOL type.");
89 const char *COLDESC_REOL_TYPE = N_("Right side file EOL type.");
90 const char *COLDESC_MEOL_TYPE = N_("Middle side file EOL type.");
91 const char *COLDESC_LENCODING = N_("Left side encoding.");
92 const char *COLDESC_RENCODING = N_("Right side encoding.");
93 const char *COLDESC_MENCODING = N_("Middle side encoding.");
94 const char *COLDESC_NIDIFFS = N_("Number of ignored differences in file. These differences are ignored by WinMerge and cannot be merged.");
95 const char *COLDESC_NSDIFFS = N_("Number of differences in file. This number does not include ignored differences.");
96 const char *COLDESC_BINARY = N_("Shows an asterisk (*) if the file is binary.");
97 const char *COLDESC_UNPACKER = N_("Unpacker plugin name or pipeline.");
98 const char *COLDESC_PREDIFFER = N_("Prediffer plugin name or pipeline.");
102 * @brief Function to compare two int64_t's for a sort
104 static int cmp64(int64_t i1, int64_t i2)
106 if (i1==i2) return 0;
107 return i1>i2 ? 1 : -1;
111 * @brief Function to compare two uint64_t's for a sort
113 static int cmpu64(uint64_t i1, uint64_t i2)
115 if (i1==i2) return 0;
116 return i1>i2 ? 1 : -1;
119 * @brief Convert int64_t to int sign
121 static int sign64(int64_t val)
124 if (val<0) return -1;
128 * @brief Function to compare two diffcodes for a sort
129 * @todo How shall we order diff statuses?
131 static int cmpdiffcode(unsigned diffcode1, unsigned diffcode2)
133 return diffcode1-diffcode2;
136 * @brief Function to compare two doubles for a sort
138 static int cmpfloat(double v1, double v2)
147 * @brief Formats a size as a short string.
149 * MakeShortSize(500) = "500b"
150 * MakeShortSize(1024) = "1Kb"
151 * MakeShortSize(12000) = "1.7Kb"
152 * MakeShortSize(200000) = "195Kb"
153 * @param [in] size File's size to convert.
154 * @return Size string with localized suffix.
155 * @note Localized suffix strings are read from resource.
156 * @todo Can't handle > terabyte filesizes.
158 static String MakeShortSize(int64_t size)
162 return strutils::format(_T("%d B"), static_cast<int>(size));
164 StrFormatByteSize64(size, buffer, static_cast<unsigned>(std::size(buffer)));
169 * @name Functions to format content of each type of column.
170 * These functions all receive two parameters, a pointer to CDiffContext.
171 * which contains general compare information. And a void pointer whose type
172 * depends on column to format. Function to call for each column, and
173 * parameter for the function are defined in static DirColInfo f_cols table.
177 * @brief Format Filename column data.
178 * @param [in] p Pointer to DIFFITEM.
179 * @return String to show in the column.
182 static Type ColFileNameGet(const CDiffContext *, const void *p) //sfilename
184 const boost::flyweight<String> &lfilename = static_cast<const DIFFITEM*>(p)->diffFileInfo[0].filename;
185 const boost::flyweight<String> &rfilename = static_cast<const DIFFITEM*>(p)->diffFileInfo[1].filename;
186 if (lfilename.get().empty())
188 else if (rfilename.get().empty() || lfilename == rfilename)
191 return static_cast<Type>(lfilename.get() + _T("|") + rfilename.get());
195 * @brief Format Extension column data.
196 * @param [in] p Pointer to DIFFITEM.
197 * @return String to show in the column.
199 static String ColExtGet(const CDiffContext *, const void *p) //sfilename
201 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
202 // We don't show extension for folder names
203 if (di.diffcode.isDirectory())
205 const String &r = di.diffFileInfo[0].filename;
206 String s = paths::FindExtension(r);
207 return s.c_str() + _tcsspn(s.c_str(), _T("."));
211 * @brief Format Folder column data.
212 * @param [in] p Pointer to DIFFITEM.
213 * @return String to show in the column.
215 static String ColPathGet(const CDiffContext *, const void *p)
217 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
218 String s = di.diffFileInfo[1].path;
219 const String &t = di.diffFileInfo[0].path;
221 // If we have unique path, just print the existing path name
222 if (s.length() == 0 || t.length() == 0)
233 const TCHAR *pi = _tcschr(s.c_str() + i, '\\');
234 const TCHAR *pj = _tcschr(t.c_str() + j, '\\');
235 size_t i_ahead = (pi != nullptr ? pi - s.c_str() : std::string::npos);
236 size_t j_ahead = (pj != nullptr ? pj - t.c_str() : std::string::npos);
237 size_t length_s = ((i_ahead != std::string::npos ? i_ahead : s.length()) - i);
238 size_t length_t = ((j_ahead != std::string::npos ? j_ahead : t.length()) - j);
239 if (length_s != length_t ||
240 memcmp(s.c_str() + i, t.c_str() + j, length_s) != 0)
242 String u(t.c_str() + j, length_t + 1);
245 i_ahead += u.length();
256 * @brief Format Result column data.
257 * @param [in] pCtxt Pointer to compare context.
258 * @param [in] p Pointer to DIFFITEM.
259 * @return String to show in the column.
261 static String ColStatusGet(const CDiffContext *pCtxt, const void *p)
263 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
264 int nDirs = pCtxt->GetCompareDirs();
265 // Note that order of items does matter. We must check for
266 // skipped items before unique items, for example, so that
267 // skipped unique items are labeled as skipped, not unique.
269 if (di.diffcode.isResultError())
271 s = _("Unable to compare files");
273 else if (di.diffcode.isResultAbort())
275 s = _("Item aborted");
277 else if (di.diffcode.isResultFiltered())
279 if (di.diffcode.isDirectory())
280 s = _("Folder skipped");
282 s = _("File skipped");
284 else if (di.diffcode.isSideFirstOnly())
286 s = strutils::format_string1(_("Left only: %1"),
287 di.getFilepath(0, pCtxt->GetNormalizedLeft()));
289 else if (di.diffcode.isSideSecondOnly())
293 s = strutils::format_string1(_("Right only: %1"),
294 di.getFilepath(1, pCtxt->GetNormalizedRight()));
298 s = strutils::format_string1(_("Middle only: %1"),
299 di.getFilepath(1, pCtxt->GetNormalizedMiddle()));
302 else if (di.diffcode.isSideThirdOnly())
304 s = strutils::format_string1(_("Right only: %1"),
305 di.getFilepath(2, pCtxt->GetNormalizedRight()));
307 else if (nDirs > 2 && !di.diffcode.existsFirst())
309 s = strutils::format_string1(_("Does not exist in %1"),
310 pCtxt->GetNormalizedLeft());
312 else if (nDirs > 2 && !di.diffcode.existsSecond())
314 s = strutils::format_string1(_("Does not exist in %1"),
315 pCtxt->GetNormalizedMiddle());
317 else if (nDirs > 2 && !di.diffcode.existsThird())
319 s = strutils::format_string1(_("Does not exist in %1"),
320 pCtxt->GetNormalizedRight());
322 else if (di.diffcode.isResultSame())
324 if (di.diffcode.isText())
325 s = _("Text files are identical");
326 else if (di.diffcode.isBin())
327 s = _("Binary files are identical");
328 else if (di.diffcode.isImage())
329 s = _("Image files are identical");
333 else if (di.diffcode.isResultDiff()) // diff
335 if (di.diffcode.isText())
336 s = _("Text files are different");
337 else if (di.diffcode.isBin())
338 s = _("Binary files are different");
339 else if (di.diffcode.isImage())
340 s = _("Image files are different");
341 else if (di.diffcode.isDirectory())
342 s = _("Folders are different");
344 s = _("Files are different");
347 switch (di.diffcode.diffcode & DIFFCODE::COMPAREFLAGS3WAY)
349 case DIFFCODE::DIFF1STONLY: s += _("(Middle and right are identical)"); break;
350 case DIFFCODE::DIFF2NDONLY: s += _("(Left and right are identical)"); break;
351 case DIFFCODE::DIFF3RDONLY: s += _("(Left and middle are identical)"); break;
359 * @brief Format Date column data.
360 * @param [in] p Pointer to integer (seconds since 1.1.1970).
361 * @return String to show in the column.
363 static String ColTimeGet(const CDiffContext *, const void *p)
365 const int64_t r = *static_cast<const int64_t*>(p) / Timestamp::resolution();
367 return locality::TimeString(&r);
373 * @brief Format Sizw column data.
374 * @param [in] p Pointer to integer containing size in bytes.
375 * @return String to show in the column.
377 static String ColSizeGet(const CDiffContext *, const void *p)
379 const int64_t &r = *static_cast<const int64_t*>(p);
383 s = locality::NumToLocaleStr(r);
389 * @brief Format Folder column data.
390 * @param [in] p Pointer to DIFFITEM.
391 * @return String to show in the column.
393 static String ColSizeShortGet(const CDiffContext *, const void *p)
395 const int64_t &r = *static_cast<const int64_t*>(p);
399 s = MakeShortSize(r);
405 * @brief Format Difference cout column data.
406 * @param [in] p Pointer to integer having count of differences.
407 * @return String to show in the column.
409 static String ColDiffsGet(const CDiffContext *, const void *p)
411 const int &r = *static_cast<const int*>(p);
413 if (r == CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE)
414 { // QuickCompare, unknown
417 else if (r == CDiffContext::DIFFS_UNKNOWN)
423 s = locality::NumToLocaleStr(r);
429 * @brief Format Newer/Older column data.
430 * @param [in] p Pointer to DIFFITEM.
431 * @return String to show in the column.
433 static String ColNewerGet(const CDiffContext *pCtxt, const void *p)
435 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
436 if (pCtxt->GetCompareDirs() < 3)
438 if (di.diffcode.isSideFirstOnly())
442 if (di.diffcode.isSideSecondOnly())
446 if (di.diffFileInfo[0].mtime != 0 && di.diffFileInfo[1].mtime != 0)
448 if (di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime)
452 if (di.diffFileInfo[0].mtime < di.diffFileInfo[1].mtime)
463 int sortno[3] = {0, 1, 2};
464 Timestamp sorttime[3] = {di.diffFileInfo[0].mtime, di.diffFileInfo[1].mtime, di.diffFileInfo[2].mtime};
465 for (int i = 0; i < 3; i++)
467 for (int j = i; j < 3; j++)
469 if (sorttime[i] < sorttime[j])
471 swap(sorttime[i], sorttime[j]);
472 swap(sortno[i], sortno[j]);
476 res = _T("LMR")[sortno[0]];
477 res += sorttime[0] == sorttime[1] ? _T("==") : _T("<-");
478 res += _T("LMR")[sortno[1]];
479 res += sorttime[1] == sorttime[2] ? _T("==") : _T("<-");
480 res += _T("LMR")[sortno[2]];
486 * @brief Format Version info to string.
487 * @param [in] pCtxt Pointer to compare context.
488 * @param [in] pdi Pointer to DIFFITEM.
489 * @param [in] bLeft Is the item left-size item?
490 * @return String proper to show in the GUI.
492 static String GetVersion(const CDiffContext * pCtxt, const DIFFITEM *pdi, int nIndex)
494 DIFFITEM &di = const_cast<DIFFITEM &>(*pdi);
495 DiffFileInfo & dfi = di.diffFileInfo[nIndex];
496 if (dfi.version.IsCleared())
498 pCtxt->UpdateVersion(di, nIndex);
500 return dfi.version.GetFileVersionString();
503 static uint64_t GetVersionQWORD(const CDiffContext * pCtxt, const DIFFITEM *pdi, int nIndex)
505 DIFFITEM &di = const_cast<DIFFITEM &>(*pdi);
506 DiffFileInfo & dfi = di.diffFileInfo[nIndex];
507 if (dfi.version.IsCleared())
509 pCtxt->UpdateVersion(di, nIndex);
511 return dfi.version.GetFileVersionQWORD();
515 * @brief Format Version column data (for left-side).
516 * @param [in] pCtxt Pointer to compare context.
517 * @param [in] p Pointer to DIFFITEM.
518 * @return String to show in the column.
520 static String ColLversionGet(const CDiffContext * pCtxt, const void *p)
522 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
523 return GetVersion(pCtxt, &di, 0);
527 * @brief Format Version column data (for middle-side).
528 * @param [in] pCtxt Pointer to compare context.
529 * @param [in] p Pointer to DIFFITEM.
530 * @return String to show in the column.
532 static String ColMversionGet(const CDiffContext * pCtxt, const void *p)
534 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
535 return GetVersion(pCtxt, &di, 1);
539 * @brief Format Version column data (for right-side).
540 * @param [in] pCtxt Pointer to compare context.
541 * @param [in] p Pointer to DIFFITEM.
542 * @return String to show in the column.
544 static String ColRversionGet(const CDiffContext * pCtxt, const void *p)
546 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
547 return GetVersion(pCtxt, &di, pCtxt->GetCompareDirs() < 3 ? 1 : 2);
551 * @brief Format Short Result column data.
552 * @param [in] p Pointer to DIFFITEM.
553 * @return String to show in the column.
555 static String ColStatusAbbrGet(const CDiffContext *pCtxt, const void *p)
557 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
559 int nDirs = pCtxt->GetCompareDirs();
561 // Note that order of items does matter. We must check for
562 // skipped items before unique items, for example, so that
563 // skipped unique items are labeled as skipped, not unique.
564 if (di.diffcode.isResultError())
568 else if (di.diffcode.isResultAbort())
570 id = N_("Item aborted");
572 else if (di.diffcode.isResultFiltered())
574 if (di.diffcode.isDirectory())
575 id = N_("Folder skipped");
577 id = N_("File skipped");
579 else if (di.diffcode.isSideFirstOnly())
581 id = N_("Left Only");
583 else if (di.diffcode.isSideSecondOnly())
586 id = N_("Right Only");
588 id = N_("Middle Only");
590 else if (di.diffcode.isSideThirdOnly())
592 id = N_("Right Only");
594 else if (nDirs > 2 && !di.diffcode.existsFirst())
596 id = N_("No item in left");
598 else if (nDirs > 2 && !di.diffcode.existsSecond())
600 id = N_("No item in middle");
602 else if (nDirs > 2 && !di.diffcode.existsThird())
604 id = N_("No item in right");
606 else if (di.diffcode.isResultSame())
608 id = N_("Identical");
610 else if (di.diffcode.isResultDiff())
612 id = N_("Different");
615 return id ? tr(id) : _T("");
619 * @brief Format Binary column data.
620 * @param [in] p Pointer to DIFFITEM.
621 * @return String to show in the column.
623 static String ColBinGet(const CDiffContext *, const void *p)
625 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
627 if (di.diffcode.isBin())
634 * @brief Format File Attributes column data.
635 * @param [in] p Pointer to file flags class.
636 * @return String to show in the column.
638 static String ColAttrGet(const CDiffContext *, const void *p)
640 const FileFlags &r = *static_cast<const FileFlags *>(p);
645 * @brief Format File Encoding column data.
646 * @param [in] p Pointer to file information.
647 * @return String to show in the column.
649 static String ColEncodingGet(const CDiffContext *, const void *p)
651 const DiffFileInfo &r = *static_cast<const DiffFileInfo *>(p);
652 return r.encoding.GetName();
656 * @brief Format EOL type to string.
657 * @param [in] p Pointer to DIFFITEM.
658 * @param [in] bLeft Are we formatting left-side file's data?
659 * @return EOL type as as string.
661 static String GetEOLType(const CDiffContext *, const void *p, int index)
663 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
664 const DiffFileInfo & dfi = di.diffFileInfo[index];
665 const FileTextStats &stats = dfi.m_textStats;
667 if (stats.ncrlfs == 0 && stats.ncrs == 0 && stats.nlfs == 0)
671 if (di.diffcode.isBin())
673 return tr("EOL Type", "Binary");
677 if (stats.ncrlfs > 0 && stats.ncrs == 0 && stats.nlfs == 0)
681 else if (stats.ncrlfs == 0 && stats.ncrs > 0 && stats.nlfs == 0)
685 else if (stats.ncrlfs == 0 && stats.ncrs == 0 && stats.nlfs > 0)
691 return strutils::format(_T("%s:%d/%d/%d"),
693 stats.ncrlfs, stats.ncrs, stats.nlfs);
700 * @brief Format EOL type column data (for left-side file).
701 * @param [in] pCtxt Pointer to compare context.
702 * @param [in] p Pointer to DIFFITEM.
703 * @return String to show in the column.
705 static String ColLEOLTypeGet(const CDiffContext * pCtxt, const void *p)
707 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
708 return GetEOLType(pCtxt, &di, 0);
712 * @brief Format EOL type column data (for right-side file).
713 * @param [in] pCtxt Pointer to compare context.
714 * @param [in] p Pointer to DIFFITEM.
715 * @return String to show in the column.
717 static String ColMEOLTypeGet(const CDiffContext * pCtxt, const void *p)
719 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
720 return GetEOLType(pCtxt, &di, 1);
723 static String ColREOLTypeGet(const CDiffContext * pCtxt, const void *p)
725 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
726 return GetEOLType(pCtxt, &di, pCtxt->GetCompareDirs() < 3 ? 1 : 2);
729 static String GetPluginPipeline(const CDiffContext* pCtxt, const DIFFITEM& di, bool unpacker)
731 if (di.diffcode.isDirectory())
733 PackingInfo* pInfoUnpacker = nullptr;
734 PrediffingInfo * pInfoPrediffer = nullptr;
735 String filteredFilenames = pCtxt->GetFilteredFilenames(di);
736 const_cast<CDiffContext *>(pCtxt)->FetchPluginInfos(filteredFilenames, &pInfoUnpacker, &pInfoPrediffer);
738 return pInfoUnpacker ? pInfoUnpacker->GetPluginPipeline() : _T("");
740 return pInfoPrediffer ? pInfoPrediffer->GetPluginPipeline() : _T("");
743 static String ColUnpackerGet(const CDiffContext * pCtxt, const void *p)
745 return GetPluginPipeline(pCtxt, *static_cast<const DIFFITEM *>(p), true);
748 static String ColPredifferGet(const CDiffContext * pCtxt, const void *p)
750 return GetPluginPipeline(pCtxt, *static_cast<const DIFFITEM *>(p), false);
758 * @name Functions to sort each type of column info.
759 * These functions are used to sort information in folder compare GUI. Each
760 * column info (type) has its own function to compare the data. Each
761 * function receives three parameters:
762 * - pointer to compare context
763 * - two parameters for data to compare (type varies)
764 * Return value is -1, 0, or 1, where 0 means datas are identical.
768 * @brief Compare file names.
769 * @param [in] pCtxt Pointer to compare context.
770 * @param [in] p Pointer to DIFFITEM having first name to compare.
771 * @param [in] q Pointer to DIFFITEM having second name to compare.
772 * @return Compare result.
774 static int ColFileNameSort(const CDiffContext *pCtxt, const void *p, const void *q)
776 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
777 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
778 if (ldi.diffcode.isDirectory() && !rdi.diffcode.isDirectory())
780 if (!ldi.diffcode.isDirectory() && rdi.diffcode.isDirectory())
782 return strutils::compare_nocase(ColFileNameGet<boost::flyweight<String> >(pCtxt, p), ColFileNameGet<boost::flyweight<String> >(pCtxt, q));
786 * @brief Compare file name extensions.
787 * @param [in] pCtxt Pointer to compare context.
788 * @param [in] p First file name extension to compare.
789 * @param [in] q Second file name extension to compare.
790 * @return Compare result.
792 static int ColExtSort(const CDiffContext *pCtxt, const void *p, const void *q)
794 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
795 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
796 if (ldi.diffcode.isDirectory() && !rdi.diffcode.isDirectory())
798 if (!ldi.diffcode.isDirectory() && rdi.diffcode.isDirectory())
800 return strutils::compare_nocase(ColExtGet(pCtxt, p), ColExtGet(pCtxt, q));
804 * @brief Compare folder names.
805 * @param [in] pCtxt Pointer to compare context.
806 * @param [in] p Pointer to DIFFITEM having first folder name to compare.
807 * @param [in] q Pointer to DIFFITEM having second folder name to compare.
808 * @return Compare result.
810 static int ColPathSort(const CDiffContext *pCtxt, const void *p, const void *q)
812 return strutils::compare_nocase(ColPathGet(pCtxt, p), ColPathGet(pCtxt, q));
816 * @brief Compare compare results.
817 * @param [in] p Pointer to DIFFITEM having first result to compare.
818 * @param [in] q Pointer to DIFFITEM having second result to compare.
819 * @return Compare result.
821 static int ColStatusSort(const CDiffContext *, const void *p, const void *q)
823 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
824 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
825 return cmpdiffcode(rdi.diffcode.diffcode, ldi.diffcode.diffcode);
829 * @brief Compare file times.
830 * @param [in] p First time to compare.
831 * @param [in] q Second time to compare.
832 * @return Compare result.
834 static int ColTimeSort(const CDiffContext *, const void *p, const void *q)
836 const int64_t &r = *static_cast<const int64_t*>(p);
837 const int64_t &s = *static_cast<const int64_t*>(q);
842 * @brief Compare file sizes.
843 * @param [in] p First size to compare.
844 * @param [in] q Second size to compare.
845 * @return Compare result.
847 static int ColSizeSort(const CDiffContext *, const void *p, const void *q)
849 const int64_t &r = *static_cast<const int64_t*>(p);
850 const int64_t &s = *static_cast<const int64_t*>(q);
855 * @brief Compare difference counts.
856 * @param [in] p First count to compare.
857 * @param [in] q Second count to compare.
858 * @return Compare result.
860 static int ColDiffsSort(const CDiffContext *, const void *p, const void *q)
862 const int &r = *static_cast<const int*>(p);
863 const int &s = *static_cast<const int*>(q);
868 * @brief Compare newer/older statuses.
869 * @param [in] pCtxt Pointer to compare context.
870 * @param [in] p Pointer to DIFFITEM having first status to compare.
871 * @param [in] q Pointer to DIFFITEM having second status to compare.
872 * @return Compare result.
874 static int ColNewerSort(const CDiffContext *pCtxt, const void *p, const void *q)
876 return ColNewerGet(pCtxt, p).compare(ColNewerGet(pCtxt, q));
880 * @brief Compare left-side file versions.
881 * @param [in] pCtxt Pointer to compare context.
882 * @param [in] p Pointer to DIFFITEM having first version to compare.
883 * @param [in] q Pointer to DIFFITEM having second version to compare.
884 * @return Compare result.
886 static int ColLversionSort(const CDiffContext *pCtxt, const void *p, const void *q)
888 return cmpu64(GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(p), 0), GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(q), 0));
892 * @brief Compare middle-side file versions.
893 * @param [in] pCtxt Pointer to compare context.
894 * @param [in] p Pointer to DIFFITEM having first version to compare.
895 * @param [in] q Pointer to DIFFITEM having second version to compare.
896 * @return Compare result.
898 static int ColMversionSort(const CDiffContext *pCtxt, const void *p, const void *q)
900 return cmpu64(GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(p), 1), GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(q), 1));
904 * @brief Compare right-side file versions.
905 * @param [in] pCtxt Pointer to compare context.
906 * @param [in] p Pointer to DIFFITEM having first version to compare.
907 * @param [in] q Pointer to DIFFITEM having second version to compare.
908 * @return Compare result.
910 static int ColRversionSort(const CDiffContext *pCtxt, const void *p, const void *q)
912 const int i = pCtxt->GetCompareDirs() < 3 ? 1 : 2;
913 return cmpu64(GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(p), i), GetVersionQWORD(pCtxt, reinterpret_cast<const DIFFITEM *>(q), i));
917 * @brief Compare binary statuses.
918 * This function returns a comparison of binary results.
919 * @param [in] p Pointer to DIFFITEM having first status to compare.
920 * @param [in] q Pointer to DIFFITEM having second status to compare.
921 * @return Compare result:
922 * - if both items are text files or binary files: 0
923 * - if left is text and right is binary: -1
924 * - if left is binary and right is text: 1
926 static int ColBinSort(const CDiffContext *, const void *p, const void *q)
928 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
929 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
930 const bool i = ldi.diffcode.isBin();
931 const bool j = rdi.diffcode.isBin();
944 * @brief Compare file flags.
945 * @param [in] p Pointer to first flag structure to compare.
946 * @param [in] q Pointer to second flag structure to compare.
947 * @return Compare result.
949 static int ColAttrSort(const CDiffContext *, const void *p, const void *q)
951 const FileFlags &r = *static_cast<const FileFlags *>(p);
952 const FileFlags &s = *static_cast<const FileFlags *>(q);
953 if (r.attributes == s.attributes)
955 return r.attributes < s.attributes ? -1 : 1;
959 * @brief Compare file encodings.
960 * @param [in] p Pointer to first structure to compare.
961 * @param [in] q Pointer to second structure to compare.
962 * @return Compare result.
964 static int ColEncodingSort(const CDiffContext *, const void *p, const void *q)
966 const DiffFileInfo &r = *static_cast<const DiffFileInfo *>(p);
967 const DiffFileInfo &s = *static_cast<const DiffFileInfo *>(q);
968 return FileTextEncoding::Collate(r.encoding, s.encoding);
972 #undef FIELD_OFFSET // incorrect for Win32 as defined in WinNT.h
973 #define FIELD_OFFSET(type, field) ((size_t)(LONG_PTR)&(((type *)nullptr)->field))
976 * @brief All existing folder compare columns.
978 * This table has information for all folder compare columns. Fields are
981 * - name resource ID: column's name shown in header
982 * - description resource ID: columns description text
983 * - custom function for getting column data
984 * - custom function for sorting column data
985 * - parameter for custom functions: DIFFITEM (if `nullptr`) or one of its fields
986 * - default column order number, -1 if not shown by default
987 * - ascending (`true`) or descending (`false`) default sort order
988 * - alignment of column contents: numbers are usually right-aligned
990 static DirColInfo f_cols[] =
992 { _T("Name"), nullptr, COLHDR_FILENAME, COLDESC_FILENAME, &ColFileNameGet<String>, &ColFileNameSort, 0, 0, true, DirColInfo::ALIGN_LEFT },
993 { _T("Path"), "DirView|ColumnHeader", COLHDR_DIR, COLDESC_DIR, &ColPathGet, &ColPathSort, 0, 1, true, DirColInfo::ALIGN_LEFT },
994 { _T("Status"), nullptr, COLHDR_RESULT, COLDESC_RESULT, &ColStatusGet, &ColStatusSort, 0, 2, true, DirColInfo::ALIGN_LEFT },
995 { _T("Lmtime"), nullptr, COLHDR_LTIMEM, COLDESC_LTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].mtime), 3, false, DirColInfo::ALIGN_LEFT },
996 { _T("Rmtime"), nullptr, COLHDR_RTIMEM, COLDESC_RTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].mtime), 4, false, DirColInfo::ALIGN_LEFT },
997 { _T("Lctime"), nullptr, COLHDR_LTIMEC, COLDESC_LTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].ctime), -1, false, DirColInfo::ALIGN_LEFT },
998 { _T("Rctime"), nullptr, COLHDR_RTIMEC, COLDESC_RTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].ctime), -1, false, DirColInfo::ALIGN_LEFT },
999 { _T("Ext"), nullptr, COLHDR_EXTENSION, COLDESC_EXTENSION, &ColExtGet, &ColExtSort, 0, 5, true, DirColInfo::ALIGN_LEFT },
1000 { _T("Lsize"), nullptr, COLHDR_LSIZE, COLDESC_LSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1001 { _T("Rsize"), nullptr, COLHDR_RSIZE, COLDESC_RSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1002 { _T("LsizeShort"), nullptr, COLHDR_LSIZE_SHORT, COLDESC_LSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1003 { _T("RsizeShort"), nullptr, COLHDR_RSIZE_SHORT, COLDESC_RSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1004 { _T("Newer"), nullptr, COLHDR_NEWER, COLDESC_NEWER, &ColNewerGet, &ColNewerSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1005 { _T("Lversion"), nullptr, COLHDR_LVERSION, COLDESC_LVERSION, &ColLversionGet, &ColLversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1006 { _T("Rversion"), nullptr, COLHDR_RVERSION, COLDESC_RVERSION, &ColRversionGet, &ColRversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1007 { _T("StatusAbbr"), nullptr, COLHDR_RESULT_ABBR, COLDESC_RESULT_ABBR, &ColStatusAbbrGet, &ColStatusSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1008 { _T("Binary"), "DirView|ColumnHeader", COLHDR_BINARY, COLDESC_BINARY, &ColBinGet, &ColBinSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1009 { _T("Lattr"), nullptr, COLHDR_LATTRIBUTES, COLDESC_LATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].flags), -1, true, DirColInfo::ALIGN_LEFT },
1010 { _T("Rattr"), nullptr, COLHDR_RATTRIBUTES, COLDESC_RATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].flags), -1, true, DirColInfo::ALIGN_LEFT },
1011 { _T("Lencoding"), nullptr, COLHDR_LENCODING, COLDESC_LENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0]), -1, true, DirColInfo::ALIGN_LEFT },
1012 { _T("Rencoding"), nullptr, COLHDR_RENCODING, COLDESC_RENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1]), -1, true, DirColInfo::ALIGN_LEFT },
1013 { _T("Snsdiffs"), nullptr, COLHDR_NSDIFFS, COLDESC_NSDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nsdiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1014 { _T("Snidiffs"), nullptr, COLHDR_NIDIFFS, COLDESC_NIDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nidiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1015 { _T("Leoltype"), nullptr, COLHDR_LEOL_TYPE, COLDESC_LEOL_TYPE, &ColLEOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1016 { _T("Reoltype"), nullptr, COLHDR_REOL_TYPE, COLDESC_REOL_TYPE, &ColREOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1017 { _T("Unpacker"), nullptr, COLHDR_UNPACKER, COLDESC_UNPACKER, &ColUnpackerGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1018 { _T("Prediffer"), nullptr, COLHDR_PREDIFFER, COLDESC_PREDIFFER, &ColPredifferGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1020 static DirColInfo f_cols3[] =
1022 { _T("Name"), nullptr, COLHDR_FILENAME, COLDESC_FILENAME, &ColFileNameGet<String>, &ColFileNameSort, 0, 0, true, DirColInfo::ALIGN_LEFT },
1023 { _T("Path"), "DirView|ColumnHeader", COLHDR_DIR, COLDESC_DIR, &ColPathGet, &ColPathSort, 0, 1, true, DirColInfo::ALIGN_LEFT },
1024 { _T("Status"), nullptr, COLHDR_RESULT, COLDESC_RESULT, &ColStatusGet, &ColStatusSort, 0, 2, true, DirColInfo::ALIGN_LEFT },
1025 { _T("Lmtime"), nullptr, COLHDR_LTIMEM, COLDESC_LTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].mtime), 3, false, DirColInfo::ALIGN_LEFT },
1026 { _T("Mmtime"), nullptr, COLHDR_MTIMEM, COLDESC_MTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].mtime), 4, false, DirColInfo::ALIGN_LEFT },
1027 { _T("Rmtime"), nullptr, COLHDR_RTIMEM, COLDESC_RTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].mtime), 5, false, DirColInfo::ALIGN_LEFT },
1028 { _T("Lctime"), nullptr, COLHDR_LTIMEC, COLDESC_LTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1029 { _T("Mctime"), nullptr, COLHDR_MTIMEC, COLDESC_MTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1030 { _T("Rctime"), nullptr, COLHDR_RTIMEC, COLDESC_RTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1031 { _T("Ext"), nullptr, COLHDR_EXTENSION, COLDESC_EXTENSION, &ColExtGet, &ColExtSort, 0, 6, true, DirColInfo::ALIGN_LEFT },
1032 { _T("Lsize"), nullptr, COLHDR_LSIZE, COLDESC_LSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1033 { _T("Msize"), nullptr, COLHDR_MSIZE, COLDESC_MSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1034 { _T("Rsize"), nullptr, COLHDR_RSIZE, COLDESC_RSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].size), -1, false, DirColInfo::ALIGN_RIGHT },
1035 { _T("LsizeShort"), nullptr, COLHDR_LSIZE_SHORT, COLDESC_LSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1036 { _T("MsizeShort"), nullptr, COLHDR_MSIZE_SHORT, COLDESC_MSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1037 { _T("RsizeShort"), nullptr, COLHDR_RSIZE_SHORT, COLDESC_RSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].size), -1, false, DirColInfo::ALIGN_RIGHT },
1038 { _T("Newer"), nullptr, COLHDR_NEWER, COLDESC_NEWER, &ColNewerGet, &ColNewerSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1039 { _T("Lversion"), nullptr, COLHDR_LVERSION, COLDESC_LVERSION, &ColLversionGet, &ColLversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1040 { _T("Mversion"), nullptr, COLHDR_MVERSION, COLDESC_MVERSION, &ColMversionGet, &ColMversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1041 { _T("Rversion"), nullptr, COLHDR_RVERSION, COLDESC_RVERSION, &ColRversionGet, &ColRversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1042 { _T("StatusAbbr"), nullptr, COLHDR_RESULT_ABBR, COLDESC_RESULT_ABBR, &ColStatusAbbrGet, &ColStatusSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1043 { _T("Binary"), "DirView|ColumnHeader", COLHDR_BINARY, COLDESC_BINARY, &ColBinGet, &ColBinSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1044 { _T("Lattr"), nullptr, COLHDR_LATTRIBUTES, COLDESC_LATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].flags), -1, true, DirColInfo::ALIGN_LEFT },
1045 { _T("Mattr"), nullptr, COLHDR_MATTRIBUTES, COLDESC_MATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].flags), -1, true, DirColInfo::ALIGN_LEFT },
1046 { _T("Rattr"), nullptr, COLHDR_RATTRIBUTES, COLDESC_RATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].flags), -1, true, DirColInfo::ALIGN_LEFT },
1047 { _T("Lencoding"), nullptr, COLHDR_LENCODING, COLDESC_LENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0]), -1, true, DirColInfo::ALIGN_LEFT },
1048 { _T("Mencoding"), nullptr, COLHDR_MENCODING, COLDESC_MENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1]), -1, true, DirColInfo::ALIGN_LEFT },
1049 { _T("Rencoding"), nullptr, COLHDR_RENCODING, COLDESC_RENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2]), -1, true, DirColInfo::ALIGN_LEFT },
1050 { _T("Snsdiffs"), nullptr, COLHDR_NSDIFFS, COLDESC_NSDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nsdiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1051 { _T("Snidiffs"), nullptr, COLHDR_NIDIFFS, COLDESC_NIDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nidiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1052 { _T("Leoltype"), nullptr, COLHDR_LEOL_TYPE, COLDESC_LEOL_TYPE, &ColLEOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1053 { _T("Meoltype"), nullptr, COLHDR_MEOL_TYPE, COLDESC_MEOL_TYPE, &ColMEOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1054 { _T("Reoltype"), nullptr, COLHDR_REOL_TYPE, COLDESC_REOL_TYPE, &ColREOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1055 { _T("Unpacker"), nullptr, COLHDR_UNPACKER, COLDESC_UNPACKER, &ColUnpackerGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1056 { _T("Prediffer"), nullptr, COLHDR_PREDIFFER, COLDESC_PREDIFFER, &ColPredifferGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1060 * @brief Count of all known columns
1062 const int g_ncols = static_cast<int>(std::size(f_cols));
1063 const int g_ncols3 = static_cast<int>(std::size(f_cols3));
1066 * @brief Registry base value name for saving/loading info for this column
1069 DirViewColItems::GetColRegValueNameBase(int col) const
1073 assert(col>=0 && col<static_cast<int>(std::size(f_cols)));
1074 return strutils::format(_T("WDirHdr_%s"), f_cols[col].regName);
1078 assert(col>=0 && col<static_cast<int>(std::size(f_cols3)));
1079 return strutils::format(_T("WDirHdr_%s"), f_cols3[col].regName);
1084 * @brief Get default physical order for specified logical column
1087 DirViewColItems::GetColDefaultOrder(int col) const
1091 assert(col>=0 && col<static_cast<int>(std::size(f_cols)));
1092 return f_cols[col].physicalIndex;
1096 assert(col>=0 && col<static_cast<int>(std::size(f_cols3)));
1097 return f_cols3[col].physicalIndex;
1102 * @brief Return the info about the specified physical column
1105 DirViewColItems::GetDirColInfo(int col) const
1109 if (col < 0 || col >= static_cast<int>(std::size(f_cols)))
1111 assert(false); // fix caller, should not ask for nonexistent columns
1114 return &f_cols[col];
1118 if (col < 0 || col >= static_cast<int>(std::size(f_cols3)))
1120 assert(false); // fix caller, should not ask for nonexistent columns
1123 return &f_cols3[col];
1128 * @brief Check if specified physical column has specified resource id name
1131 DirViewColItems::IsColById(int col, const char *idname) const
1133 int nDirs = m_nDirs;
1136 if (col < 0 || col >= static_cast<int>(std::size(f_cols)))
1138 assert(false); // fix caller, should not ask for nonexistent columns
1141 return f_cols[col].idName == idname;
1145 if (col < 0 || col >= sizeof(f_cols3)/sizeof(f_cols3[0]))
1147 assert(false); // fix caller, should not ask for nonexistent columns
1150 return f_cols3[col].idName == idname;
1155 * @brief Is specified physical column the name column?
1158 DirViewColItems::IsColName(int col) const
1160 return IsColById(col, COLHDR_FILENAME);
1163 * @brief Is specified physical column the left modification time column?
1166 DirViewColItems::IsColLmTime(int col) const
1168 return IsColById(col, COLHDR_LTIMEM);
1171 * @brief Is specified physical column the middle modification time column?
1174 DirViewColItems::IsColMmTime(int col) const
1176 return IsColById(col, COLHDR_MTIMEM);
1179 * @brief Is specified physical column the right modification time column?
1182 DirViewColItems::IsColRmTime(int col) const
1184 return IsColById(col, COLHDR_RTIMEM);
1187 * @brief Is specified physical column the full status (result) column?
1190 DirViewColItems::IsColStatus(int col) const
1192 return IsColById(col, COLHDR_RESULT);
1195 * @brief Is specified physical column the full status (result) column?
1198 DirViewColItems::IsColStatusAbbr(int col) const
1200 return IsColById(col, COLHDR_RESULT_ABBR);
1204 * @brief return whether column normally sorts ascending (dates do not)
1207 DirViewColItems::IsDefaultSortAscending(int col) const
1209 const DirColInfo * pColInfo = GetDirColInfo(col);
1210 if (pColInfo == nullptr)
1212 assert(false); // fix caller, should not ask for nonexistent columns
1215 return pColInfo->defSortUp;
1219 * @brief Return display name of column
1222 DirViewColItems::GetColDisplayName(int col) const
1224 const DirColInfo * colinfo = GetDirColInfo(col);
1225 return tr(colinfo->idNameContext, colinfo->idName);
1229 * @brief Return description of column
1232 DirViewColItems::GetColDescription(int col) const
1234 const DirColInfo * colinfo = GetDirColInfo(col);
1235 return tr(colinfo->idDesc);
1239 * @brief Return total number of known columns
1242 DirViewColItems::GetColCount() const
1251 * @brief Get text for specified column.
1252 * This function retrieves the text for the specified colum. Text is
1253 * retrieved by using column-specific handler functions.
1254 * @param [in] pCtxt Compare context.
1255 * @param [in] col Column number.
1256 * @param [in] di Difference data.
1257 * @return Text for the specified column.
1260 DirViewColItems::ColGetTextToDisplay(const CDiffContext *pCtxt, int col,
1261 const DIFFITEM &di) const
1263 // Custom properties have custom get functions
1264 const DirColInfo * pColInfo = GetDirColInfo(col);
1265 if (pColInfo == nullptr)
1267 assert(false); // fix caller, should not ask for nonexistent columns
1270 ColGetFncPtrType fnc = pColInfo->getfnc;
1271 size_t offset = pColInfo->offset;
1272 String s = (*fnc)(pCtxt, reinterpret_cast<const char *>(&di) + offset);
1274 // Add '*' to newer time field
1275 if (IsColLmTime(col) || IsColMmTime(col) || IsColRmTime(col))
1279 if (di.diffFileInfo[0].mtime != 0 || di.diffFileInfo[1].mtime != 0)
1283 IsColLmTime(col) && di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime // Left modification time
1284 || IsColRmTime(col) && di.diffFileInfo[0].mtime < di.diffFileInfo[1].mtime // Right modification time
1287 s.insert(0, _T("* "));
1291 s.insert(0, _T(" ")); // Looks best with a fixed-font, but not too bad otherwise
1293 // GreyMerlin (14 Nov 2009) - the flagging of Date needs to be done with
1294 // something not involving extra characters. Perhaps <red> for oldest,
1295 // <green> for newest. Note (20 March 2017): the introduction of 3-Way
1296 // Merge and the yellow difference highlighting adds to the design
1297 // difficulty of any changes. So maybe this "* "/" " scheme is good enough.
1303 if (di.diffFileInfo[0].mtime != 0 || di.diffFileInfo[1].mtime != 0 || di.diffFileInfo[2].mtime != 0)
1307 IsColLmTime(col) && di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime && di.diffFileInfo[0].mtime > di.diffFileInfo[2].mtime // Left modification time
1308 || IsColMmTime(col) && di.diffFileInfo[1].mtime > di.diffFileInfo[0].mtime && di.diffFileInfo[1].mtime > di.diffFileInfo[2].mtime // Middle modification time
1309 || IsColRmTime(col) && di.diffFileInfo[2].mtime > di.diffFileInfo[0].mtime && di.diffFileInfo[2].mtime > di.diffFileInfo[1].mtime // Right modification time
1312 s.insert(0, _T("* "));
1316 s.insert(0, _T(" ")); // Looks best with a fixed-font, but not too bad otherwise
1318 // GreyMerlin (14 Nov 2009) - See note above.
1329 * @brief Sort two items on specified column.
1330 * This function determines order of two items in specified column. Order
1331 * is determined by column-specific functions.
1332 * @param [in] pCtxt Compare context.
1333 * @param [in] col Column number to sort.
1334 * @param [in] ldi Left difference item data.
1335 * @param [in] rdi Right difference item data.
1336 * @return Order of items.
1339 DirViewColItems::ColSort(const CDiffContext *pCtxt, int col, const DIFFITEM &ldi,
1340 const DIFFITEM &rdi, bool bTreeMode) const
1342 // Custom properties have custom sort functions
1343 const DirColInfo * pColInfo = GetDirColInfo(col);
1344 if (pColInfo == nullptr)
1346 assert(false); // fix caller, should not ask for nonexistent columns
1349 size_t offset = pColInfo->offset;
1354 int lLevel = ldi.GetDepth();
1355 int rLevel = rdi.GetDepth();
1356 const DIFFITEM *lcur = &ldi, *rcur = &rdi;
1357 if (lLevel < rLevel)
1359 for (; lLevel != rLevel; rLevel--)
1360 rcur = rcur->GetParentLink();
1362 else if (rLevel < lLevel)
1364 for (; lLevel != rLevel; lLevel--)
1365 lcur = lcur->GetParentLink();
1367 while (lcur->GetParentLink() != rcur->GetParentLink())
1369 lcur = lcur->GetParentLink();
1370 rcur = rcur->GetParentLink();
1372 arg1 = reinterpret_cast<const char *>(lcur) + offset;
1373 arg2 = reinterpret_cast<const char *>(rcur) + offset;
1377 arg1 = reinterpret_cast<const char *>(&ldi) + offset;
1378 arg2 = reinterpret_cast<const char *>(&rdi) + offset;
1380 if (ColSortFncPtrType fnc = pColInfo->sortfnc)
1382 return (*fnc)(pCtxt, arg1, arg2);
1384 if (ColGetFncPtrType fnc = pColInfo->getfnc)
1386 String p = (*fnc)(pCtxt, arg1);
1387 String q = (*fnc)(pCtxt, arg2);
1388 return strutils::compare_nocase(p, q);
1393 void DirViewColItems::SetColumnOrdering(const int colorder[])
1396 for (int i = 0; i < m_numcols; ++i)
1398 m_colorder[i] = colorder[i];
1399 int phy = m_colorder[i];
1403 m_invcolorder[phy] = i;
1409 * @brief Set column ordering to default initial order
1411 void DirViewColItems::ResetColumnOrdering()
1413 ClearColumnOrders();
1415 for (int i=0; i<m_numcols; ++i)
1417 int phy = GetColDefaultOrder(i);
1418 m_colorder[i] = phy;
1421 m_invcolorder[phy] = i;
1428 * @brief Reset all current column ordering information
1430 void DirViewColItems::ClearColumnOrders()
1432 m_colorder.resize(m_numcols);
1433 m_invcolorder.resize(m_numcols);
1434 for (int i=0; i<m_numcols; ++i)
1437 m_invcolorder[i] = -1;
1442 * @brief Remove any windows reordering of columns (params are physical columns)
1444 void DirViewColItems::MoveColumn(int psrc, int pdest)
1446 // actually moved column
1447 m_colorder[m_invcolorder[psrc]] = pdest;
1448 // shift all other affected columns
1449 int dir = psrc > pdest ? +1 : -1;
1451 for (i=pdest; i!=psrc; i += dir)
1453 m_colorder[m_invcolorder[i]] = i+dir;
1455 // fix inverse mapping
1456 for (i=0; i<m_numcols; ++i)
1458 if (m_colorder[i] >= 0)
1459 m_invcolorder[m_colorder[i]] = i;
1464 * @brief Resets column widths to defaults.
1466 String DirViewColItems::ResetColumnWidths(int defcolwidth)
1469 for (int i = 0; i < m_numcols; i++)
1471 if (!result.empty()) result += ' ';
1472 result += strutils::to_str(defcolwidth);
1478 * @brief Load column orders from registry
1480 void DirViewColItems::LoadColumnOrders(String colorders)
1482 assert(m_numcols == -1);
1483 m_numcols = GetColCount();
1484 ClearColumnOrders();
1486 std::basic_istringstream<TCHAR> ss(colorders);
1488 // Load column orders
1489 // Break out if one is missing
1490 // Break out & mark failure (m_dispcols == -1) if one is invalid
1492 for (i=0; i<m_numcols; ++i)
1496 if (ord<-1 || ord >= m_numcols)
1498 m_colorder[i] = ord;
1502 if (m_invcolorder[ord] != -1)
1507 m_invcolorder[ord] = i;
1510 // Check that a contiguous range was set
1511 for (i=0; i<m_dispcols; ++i)
1513 if (m_invcolorder[i] < 0)
1519 // Must have at least one column
1522 ResetColumnOrdering();
1526 /// store current column orders into registry
1527 String DirViewColItems::SaveColumnOrders()
1529 assert(static_cast<int>(m_colorder.size()) == m_numcols);
1530 assert(static_cast<int>(m_invcolorder.size()) == m_numcols);
1531 return strutils::join<String (*)(int)>(m_colorder.begin(), m_colorder.end(), _T(" "), strutils::to_str);