2 * @file DirViewColItems.cpp
4 * @brief Code for individual columns in the DirView
6 * @date Created: 2003-08-19
8 // ID line follows -- this is updated by SVN
9 // $Id: DirViewColItems.cpp 7063 2009-12-27 15:28:16Z kimmov $
10 #include "DirViewColItems.h"
12 #include <Poco/Timestamp.h>
13 #include "UnicodeString.h"
15 #include "DiffContext.h"
20 using Poco::Timestamp;
23 #define countof(x) sizeof(x)/sizeof((x)[0])
30 * @name Constants for short sizes.
33 static const unsigned KILO = 1024;
34 static const unsigned MEGA = 1024 * KILO;
35 static const unsigned GIGA = 1024 * MEGA;
36 static const int64_t TERA = 1024 * (int64_t) GIGA;
43 const char *COLHDR_FILENAME = N_("Filename");
44 const char *COLHDR_DIR = N_("Folder");
45 const char *COLHDR_RESULT = N_("Comparison result");
46 const char *COLHDR_LTIMEM = N_("Left Date");
47 const char *COLHDR_RTIMEM = N_("Right Date");
48 const char *COLHDR_MTIMEM = N_("Middle Date");
49 const char *COLHDR_EXTENSION = N_("Extension");
50 const char *COLHDR_LSIZE = N_("Left Size");
51 const char *COLHDR_RSIZE = N_("Right Size");
52 const char *COLHDR_MSIZE = N_("Middle Size");
53 const char *COLHDR_RSIZE_SHORT = N_("Right Size (Short)");
54 const char *COLHDR_LSIZE_SHORT = N_("Left Size (Short)");
55 const char *COLHDR_MSIZE_SHORT = N_("Middle Size (Short)");
56 const char *COLHDR_LTIMEC = N_("Left Creation Time");
57 const char *COLHDR_RTIMEC = N_("Right Creation Time");
58 const char *COLHDR_MTIMEC = N_("Middle Creation Time");
59 const char *COLHDR_NEWER = N_("Newer File");
60 const char *COLHDR_LVERSION = N_("Left File Version");
61 const char *COLHDR_RVERSION = N_("Right File Version");
62 const char *COLHDR_MVERSION = N_("Middle File Version");
63 const char *COLHDR_RESULT_ABBR = N_("Short Result");
64 const char *COLHDR_LATTRIBUTES = N_("Left Attributes");
65 const char *COLHDR_RATTRIBUTES = N_("Right Attributes");
66 const char *COLHDR_MATTRIBUTES = N_("Middle Attributes");
67 const char *COLHDR_LEOL_TYPE = N_("Left EOL");
68 const char *COLHDR_MEOL_TYPE = N_("Middle EOL");
69 const char *COLHDR_REOL_TYPE = N_("Right EOL");
70 const char *COLHDR_LENCODING = N_("Left Encoding");
71 const char *COLHDR_RENCODING = N_("Right Encoding");
72 const char *COLHDR_MENCODING = N_("Middle Encoding");
73 const char *COLHDR_NIDIFFS = N_("Ignored Diff.");
74 const char *COLHDR_NSDIFFS = N_("Differences");
75 const char *COLHDR_BINARY = N_("Binary");
77 const char *COLDESC_FILENAME = N_("Filename or folder name.");
78 const char *COLDESC_DIR = N_("Subfolder name when subfolders are included.");
79 const char *COLDESC_RESULT = N_("Comparison result, long form.");
80 const char *COLDESC_LTIMEM = N_("Left side modification date.");
81 const char *COLDESC_RTIMEM = N_("Right side modification date.");
82 const char *COLDESC_MTIMEM = N_("Middle side modification date.");
83 const char *COLDESC_EXTENSION = N_("File's extension.");
84 const char *COLDESC_LSIZE = N_("Left file size in bytes.");
85 const char *COLDESC_RSIZE = N_("Right file size in bytes.");
86 const char *COLDESC_MSIZE = N_("Middle file size in bytes.");
87 const char *COLDESC_LSIZE_SHORT = N_("Left file size abbreviated.");
88 const char *COLDESC_RSIZE_SHORT = N_("Right file size abbreviated.");
89 const char *COLDESC_MSIZE_SHORT = N_("Middle file size abbreviated.");
90 const char *COLDESC_LTIMEC = N_("Left side creation time.");
91 const char *COLDESC_RTIMEC = N_("Right side creation time.");
92 const char *COLDESC_MTIMEC = N_("Middle side creation time.");
93 const char *COLDESC_NEWER = N_("Tells which side has newer modification date.");
94 const char *COLDESC_LVERSION = N_("Left side file version, only for some filetypes.");
95 const char *COLDESC_RVERSION = N_("Right side file version, only for some filetypes.");
96 const char *COLDESC_MVERSION = N_("Middle side file version, only for some filetypes.");
97 const char *COLDESC_RESULT_ABBR = N_("Short comparison result.");
98 const char *COLDESC_LATTRIBUTES = N_("Left side attributes.");
99 const char *COLDESC_RATTRIBUTES = N_("Right side attributes.");
100 const char *COLDESC_MATTRIBUTES = N_("Middle side attributes.");
101 const char *COLDESC_LEOL_TYPE = N_("Left side file EOL type");
102 const char *COLDESC_REOL_TYPE = N_("Right side file EOL type");
103 const char *COLDESC_MEOL_TYPE = N_("Middle side file EOL type");
104 const char *COLDESC_LENCODING = N_("Left side encoding.");
105 const char *COLDESC_RENCODING = N_("Right side encoding.");
106 const char *COLDESC_MENCODING = N_("Middle side encoding.");
107 const char *COLDESC_NIDIFFS = N_("Number of ignored differences in file. These differences are ignored by WinMerge and cannot be merged.");
108 const char *COLDESC_NSDIFFS = N_("Number of differences in file. This number does not include ignored differences.");
109 const char *COLDESC_BINARY = N_("Shows an asterisk (*) if the file is binary.");
113 * @brief Function to compare two int64_t's for a sort
115 static int cmp64(int64_t i1, int64_t i2)
117 if (i1==i2) return 0;
118 return i1>i2 ? 1 : -1;
121 * @brief Convert int64_t to int sign
123 static int sign64(int64_t val)
126 if (val<0) return -1;
130 * @brief Function to compare two diffcodes for a sort
131 * @todo How shall we order diff statuses?
133 static unsigned cmpdiffcode(unsigned diffcode1, unsigned diffcode2)
135 // Lower priority of the same items (FIXME:)
136 if (((diffcode1 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::SAME) && ((diffcode2 & DIFFCODE::COMPAREFLAGS) != DIFFCODE::SAME))
138 if (((diffcode1 & DIFFCODE::COMPAREFLAGS) != DIFFCODE::SAME) && ((diffcode2 & DIFFCODE::COMPAREFLAGS) == DIFFCODE::SAME))
140 if ((diffcode1 & DIFFCODE::DIR) && !(diffcode2 & DIFFCODE::DIR))
142 if (!(diffcode1 & DIFFCODE::DIR) && (diffcode2 & DIFFCODE::DIR))
144 return diffcode1-diffcode2;
147 * @brief Function to compare two doubles for a sort
149 static int cmpfloat(double v1, double v2)
158 * @brief Formats a size as a short string.
160 * MakeShortSize(500) = "500b"
161 * MakeShortSize(1024) = "1Kb"
162 * MakeShortSize(12000) = "1.7Kb"
163 * MakeShortSize(200000) = "195Kb"
164 * @param [in] size File's size to convert.
165 * @return Size string with localized suffix.
166 * @note Localized suffix strings are read from resource.
167 * @todo Can't handle > terabyte filesizes.
169 static String MakeShortSize(int64_t size)
171 #pragma warning(disable:4244) // warning C4244: '=' : conversion from 'int64_t' to 'double', possible loss of data
173 #pragma warning(default:4244) // warning C4244: '=' : conversion from 'int64_t' to 'double', possible loss of data
183 else if (size < MEGA)
185 number = fsize / KILO;
187 if (size < KILO * 10)
191 else if (size < KILO * 100)
196 else if (size < GIGA)
198 number = fsize / (MEGA);
200 if (size < MEGA * 10)
204 else if (size < MEGA * 100)
209 else if (size < (int64_t)TERA)
211 number = fsize / ((int64_t)GIGA);
213 if (size < (int64_t)GIGA * 10)
217 else if (size < (int64_t)GIGA * 100)
224 // overflow (?) -- show ">TB"
231 return locality::GetLocaleStr(string_to_str(number).c_str(), ndigits) + suffix;
235 * @name Functions to format content of each type of column.
236 * These functions all receive two parameters, a pointer to CDiffContext.
237 * which contains general compare information. And a void pointer whose type
238 * depends on column to format. Function to call for each column, and
239 * parameter for the function are defined in static DirColInfo f_cols table.
243 * @brief Format Filename column data.
244 * @param [in] p Pointer to DIFFITEM.
245 * @return String to show in the column.
248 static Type ColFileNameGet(const CDiffContext *, const void *p) //sfilename
250 const boost::flyweight<String> &lfilename = static_cast<const DIFFITEM*>(p)->diffFileInfo[0].filename;
251 const boost::flyweight<String> &rfilename = static_cast<const DIFFITEM*>(p)->diffFileInfo[1].filename;
252 if (lfilename.get().empty())
254 else if (rfilename.get().empty() || lfilename == rfilename)
257 return static_cast<Type>(lfilename.get() + _T("|") + rfilename.get());
261 * @brief Format Extension column data.
262 * @param [in] p Pointer to DIFFITEM.
263 * @return String to show in the column.
265 static String ColExtGet(const CDiffContext *, const void *p) //sfilename
267 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
268 // We don't show extension for folder names
269 if (di.diffcode.isDirectory())
271 const String &r = di.diffFileInfo[0].filename;
272 String s = paths_FindExtension(r);
273 return s.c_str() + _tcsspn(s.c_str(), _T("."));
277 * @brief Format Folder column data.
278 * @param [in] p Pointer to DIFFITEM.
279 * @return String to show in the column.
281 static String ColPathGet(const CDiffContext *, const void *p)
283 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
284 String s = di.diffFileInfo[1].path;
285 const String &t = di.diffFileInfo[0].path;
287 // If we have unique path, just print the existing path name
288 if (s.length() == 0 || t.length() == 0)
299 const TCHAR *pi = _tcschr(s.c_str() + i, '\\');
300 const TCHAR *pj = _tcschr(t.c_str() + j, '\\');
301 int i_ahead = pi ? pi - s.c_str() : std::string::npos;
302 int j_ahead = pj ? pj - t.c_str() : std::string::npos;
303 int length_s = (i_ahead != std::string::npos ? i_ahead : s.length()) - i;
304 int length_t = (j_ahead != std::string::npos ? j_ahead : t.length()) - j;
305 if (length_s != length_t ||
306 memcmp(s.c_str() + i, t.c_str() + j, length_s) != 0)
308 String u(t.c_str() + j, length_t + 1);
310 s.insert(i, u.c_str());
311 i_ahead += u.length();
322 * @brief Format Result column data.
323 * @param [in] pCtxt Pointer to compare context.
324 * @param [in] p Pointer to DIFFITEM.
325 * @return String to show in the column.
327 static String ColStatusGet(const CDiffContext *pCtxt, const void *p)
329 const DIFFITEM &di = *static_cast<const DIFFITEM*>(p);
330 int nDirs = pCtxt->GetCompareDirs();
331 // Note that order of items does matter. We must check for
332 // skipped items before unique items, for example, so that
333 // skipped unique items are labeled as skipped, not unique.
335 if (di.diffcode.isResultError())
337 s = _("Unable to compare files");
339 else if (di.diffcode.isResultAbort())
341 s = _("Item aborted");
343 else if (di.diffcode.isResultFiltered())
345 if (di.diffcode.isDirectory())
346 s = _("Folder skipped");
348 s = _("File skipped");
350 else if (di.diffcode.isSideFirstOnly())
352 s = string_format_string1(_("Left only: %1"),
353 di.getFilepath(0, pCtxt->GetNormalizedLeft()));
355 else if (di.diffcode.isSideSecondOnly())
359 s = string_format_string1(_("Right only: %1"),
360 di.getFilepath(1, pCtxt->GetNormalizedRight()));
364 s = string_format_string1(_("Middle only: %1"),
365 di.getFilepath(1, pCtxt->GetNormalizedMiddle()));
368 else if (di.diffcode.isSideThirdOnly())
370 s = string_format_string1(_("Right only: %1"),
371 di.getFilepath(2, pCtxt->GetNormalizedRight()));
373 else if (nDirs > 2 && !di.diffcode.existsFirst())
375 s = string_format_string1(_("Does not exist in %1"),
376 pCtxt->GetNormalizedLeft());
378 else if (nDirs > 2 && !di.diffcode.existsSecond())
380 s = string_format_string1(_("Does not exist in %1"),
381 pCtxt->GetNormalizedMiddle());
383 else if (nDirs > 2 && !di.diffcode.existsThird())
385 s = string_format_string1(_("Does not exist in %1"),
386 pCtxt->GetNormalizedRight());
388 else if (di.diffcode.isResultSame())
390 if (di.diffcode.isText())
391 s = _("Text files are identical");
392 else if (di.diffcode.isBin())
393 s = _("Binary files are identical");
397 else if (di.diffcode.isResultDiff()) // diff
399 if (di.diffcode.isText())
400 s = _("Text files are different");
401 else if (di.diffcode.isBin())
402 s = _("Binary files are different");
403 else if (di.diffcode.isDirectory())
404 s = _("Folders are different");
406 s = _("Files are different");
412 * @brief Format Date column data.
413 * @param [in] p Pointer to integer (seconds since 1.1.1970).
414 * @return String to show in the column.
416 static String ColTimeGet(const CDiffContext *, const void *p)
418 const int64_t r = *static_cast<const int64_t*>(p) / Timestamp::resolution();
420 return locality::TimeString(&r);
426 * @brief Format Sizw column data.
427 * @param [in] p Pointer to integer containing size in bytes.
428 * @return String to show in the column.
430 static String ColSizeGet(const CDiffContext *, const void *p)
432 const int64_t &r = *static_cast<const int64_t*>(p);
436 s = locality::NumToLocaleStr(r);
442 * @brief Format Folder column data.
443 * @param [in] p Pointer to DIFFITEM.
444 * @return String to show in the column.
446 static String ColSizeShortGet(const CDiffContext *, const void *p)
448 const int64_t &r = *static_cast<const int64_t*>(p);
452 s = MakeShortSize(r);
458 * @brief Format Difference cout column data.
459 * @param [in] p Pointer to integer having count of differences.
460 * @return String to show in the column.
462 static String ColDiffsGet(const CDiffContext *, const void *p)
464 const int &r = *static_cast<const int*>(p);
466 if (r == CDiffContext::DIFFS_UNKNOWN_QUICKCOMPARE)
467 { // QuickCompare, unknown
470 else if (r == CDiffContext::DIFFS_UNKNOWN)
476 s = locality::NumToLocaleStr(r);
482 * @brief Format Newer/Older column data.
483 * @param [in] p Pointer to DIFFITEM.
484 * @return String to show in the column.
486 static String ColNewerGet(const CDiffContext *pCtxt, const void *p)
488 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
489 if (pCtxt->GetCompareDirs() < 3)
491 if (di.diffcode.isSideFirstOnly())
495 if (di.diffcode.isSideSecondOnly())
499 if (di.diffFileInfo[0].mtime != 0 && di.diffFileInfo[1].mtime != 0)
501 if (di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime)
505 if (di.diffFileInfo[0].mtime < di.diffFileInfo[1].mtime)
516 int sortno[3] = {0, 1, 2};
517 Timestamp sorttime[3] = {di.diffFileInfo[0].mtime, di.diffFileInfo[1].mtime, di.diffFileInfo[2].mtime};
518 for (int i = 0; i < 3; i++)
520 for (int j = i; j < 3; j++)
522 if (sorttime[i] < sorttime[j])
524 swap(sorttime[i], sorttime[j]);
525 swap(sortno[i], sortno[j]);
529 res = _T("LMR")[sortno[0]];
530 res += sorttime[0] == sorttime[1] ? _T("==") : _T("<<");
531 res += _T("LMR")[sortno[1]];
532 res += sorttime[1] == sorttime[2] ? _T("==") : _T("<<");
533 res += _T("LMR")[sortno[2]];
539 * @brief Format Version info to string.
540 * @param [in] pCtxt Pointer to compare context.
541 * @param [in] pdi Pointer to DIFFITEM.
542 * @param [in] bLeft Is the item left-size item?
543 * @return String proper to show in the GUI.
545 static String GetVersion(const CDiffContext * pCtxt, const DIFFITEM * pdi, int nIndex)
547 DIFFITEM & di = const_cast<DIFFITEM &>(*pdi);
548 DiffFileInfo & dfi = di.diffFileInfo[nIndex];
549 if (dfi.version.IsCleared())
551 pCtxt->UpdateVersion(di, nIndex);
553 return dfi.version.GetFileVersionString();
557 * @brief Format Version column data (for left-side).
558 * @param [in] pCtxt Pointer to compare context.
559 * @param [in] p Pointer to DIFFITEM.
560 * @return String to show in the column.
562 static String ColLversionGet(const CDiffContext * pCtxt, const void *p)
564 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
565 return GetVersion(pCtxt, &di, 0);
569 * @brief Format Version column data (for right-side).
570 * @param [in] pCtxt Pointer to compare context.
571 * @param [in] p Pointer to DIFFITEM.
572 * @return String to show in the column.
574 static String ColRversionGet(const CDiffContext * pCtxt, const void *p)
576 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
577 return GetVersion(pCtxt, &di, 1);
581 * @brief Format Short Result column data.
582 * @param [in] p Pointer to DIFFITEM.
583 * @return String to show in the column.
585 static String ColStatusAbbrGet(const CDiffContext *pCtxt, const void *p)
587 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
589 int nDirs = pCtxt->GetCompareDirs();
591 // Note that order of items does matter. We must check for
592 // skipped items before unique items, for example, so that
593 // skipped unique items are labeled as skipped, not unique.
594 if (di.diffcode.isResultError())
598 else if (di.diffcode.isResultAbort())
600 id = N_("Item aborted");
602 else if (di.diffcode.isResultFiltered())
604 if (di.diffcode.isDirectory())
605 id = N_("Folder skipped");
607 id = N_("File skipped");
609 else if (di.diffcode.isSideFirstOnly())
611 id = N_("Left Only");
613 else if (di.diffcode.isSideSecondOnly())
616 id = N_("Left Only");
618 id = N_("Middle Only");
620 else if (di.diffcode.isSideThirdOnly())
622 id = N_("Right Only");
624 else if (nDirs > 2 && !di.diffcode.existsFirst())
626 id = N_("No item in left");
628 else if (nDirs > 2 && !di.diffcode.existsSecond())
630 id = N_("No item in middle");
632 else if (nDirs > 2 && !di.diffcode.existsThird())
634 id = N_("No item in right");
636 else if (di.diffcode.isResultSame())
638 id = N_("No item in right");
640 else if (di.diffcode.isResultDiff())
642 id = N_("Different");
645 return id ? tr(id) : _T("");
649 * @brief Format Binary column data.
650 * @param [in] p Pointer to DIFFITEM.
651 * @return String to show in the column.
653 static String ColBinGet(const CDiffContext *, const void *p)
655 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
657 if (di.diffcode.isBin())
664 * @brief Format File Attributes column data.
665 * @param [in] p Pointer to file flags class.
666 * @return String to show in the column.
668 static String ColAttrGet(const CDiffContext *, const void *p)
670 const FileFlags &r = *static_cast<const FileFlags *>(p);
675 * @brief Format File Encoding column data.
676 * @param [in] p Pointer to file information.
677 * @return String to show in the column.
679 static String ColEncodingGet(const CDiffContext *, const void *p)
681 const DiffFileInfo &r = *static_cast<const DiffFileInfo *>(p);
682 return r.encoding.GetName();
686 * @brief Format EOL type to string.
687 * @param [in] p Pointer to DIFFITEM.
688 * @param [in] bLeft Are we formatting left-side file's data?
689 * @return EOL type as as string.
691 static String GetEOLType(const CDiffContext *, const void *p, int index)
693 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
694 const DiffFileInfo & dfi = di.diffFileInfo[index];
695 const FileTextStats &stats = dfi.m_textStats;
697 if (stats.ncrlfs == 0 && stats.ncrs == 0 && stats.nlfs == 0)
701 if (di.diffcode.isBin())
707 if (stats.ncrlfs > 0 && stats.ncrs == 0 && stats.nlfs == 0)
711 else if (stats.ncrlfs == 0 && stats.ncrs > 0 && stats.nlfs == 0)
715 else if (stats.ncrlfs == 0 && stats.ncrs == 0 && stats.nlfs > 0)
721 return string_format(_T("%s:%d/%d/%d"),
723 stats.ncrlfs, stats.ncrs, stats.nlfs);
730 * @brief Format EOL type column data (for left-side file).
731 * @param [in] pCtxt Pointer to compare context.
732 * @param [in] p Pointer to DIFFITEM.
733 * @return String to show in the column.
735 static String ColLEOLTypeGet(const CDiffContext * pCtxt, const void *p)
737 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
738 return GetEOLType(pCtxt, &di, 0);
742 * @brief Format EOL type column data (for right-side file).
743 * @param [in] pCtxt Pointer to compare context.
744 * @param [in] p Pointer to DIFFITEM.
745 * @return String to show in the column.
747 static String ColMEOLTypeGet(const CDiffContext * pCtxt, const void *p)
749 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
750 return GetEOLType(pCtxt, &di, 1);
753 static String ColREOLTypeGet(const CDiffContext * pCtxt, const void *p)
755 const DIFFITEM &di = *static_cast<const DIFFITEM *>(p);
756 return GetEOLType(pCtxt, &di, pCtxt->GetCompareDirs() < 3 ? 1 : 2);
764 * @name Functions to sort each type of column info.
765 * These functions are used to sort information in folder compare GUI. Each
766 * column info (type) has its own function to compare the data. Each
767 * function receives three parameters:
768 * - pointer to compare context
769 * - two parameters for data to compare (type varies)
770 * Return value is -1, 0, or 1, where 0 means datas are identical.
774 * @brief Compare file names.
775 * @param [in] pCtxt Pointer to compare context.
776 * @param [in] p Pointer to DIFFITEM having first name to compare.
777 * @param [in] q Pointer to DIFFITEM having second name to compare.
778 * @return Compare result.
780 static int ColFileNameSort(const CDiffContext *pCtxt, const void *p, const void *q)
782 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
783 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
784 if (ldi.diffcode.isDirectory() && !rdi.diffcode.isDirectory())
786 if (!ldi.diffcode.isDirectory() && rdi.diffcode.isDirectory())
788 return string_compare_nocase(ColFileNameGet<boost::flyweight<String> >(pCtxt, p), ColFileNameGet<boost::flyweight<String> >(pCtxt, q));
792 * @brief Compare file name extensions.
793 * @param [in] pCtxt Pointer to compare context.
794 * @param [in] p First file name extension to compare.
795 * @param [in] q Second file name extension to compare.
796 * @return Compare result.
798 static int ColExtSort(const CDiffContext *pCtxt, const void *p, const void *q)
800 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
801 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
802 if (ldi.diffcode.isDirectory() && !rdi.diffcode.isDirectory())
804 if (!ldi.diffcode.isDirectory() && rdi.diffcode.isDirectory())
806 return string_compare_nocase(ColExtGet(pCtxt, p), ColExtGet(pCtxt, q));
810 * @brief Compare folder names.
811 * @param [in] pCtxt Pointer to compare context.
812 * @param [in] p Pointer to DIFFITEM having first folder name to compare.
813 * @param [in] q Pointer to DIFFITEM having second folder name to compare.
814 * @return Compare result.
816 static int ColPathSort(const CDiffContext *pCtxt, const void *p, const void *q)
818 return string_compare_nocase(ColPathGet(pCtxt, p), ColPathGet(pCtxt, q));
822 * @brief Compare compare results.
823 * @param [in] p Pointer to DIFFITEM having first result to compare.
824 * @param [in] q Pointer to DIFFITEM having second result to compare.
825 * @return Compare result.
827 static int ColStatusSort(const CDiffContext *, const void *p, const void *q)
829 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
830 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
831 return cmpdiffcode(rdi.diffcode.diffcode, ldi.diffcode.diffcode);
835 * @brief Compare file times.
836 * @param [in] p First time to compare.
837 * @param [in] q Second time to compare.
838 * @return Compare result.
840 static int ColTimeSort(const CDiffContext *, const void *p, const void *q)
842 const int64_t &r = *static_cast<const int64_t*>(p);
843 const int64_t &s = *static_cast<const int64_t*>(q);
848 * @brief Compare file sizes.
849 * @param [in] p First size to compare.
850 * @param [in] q Second size to compare.
851 * @return Compare result.
853 static int ColSizeSort(const CDiffContext *, const void *p, const void *q)
855 const int64_t &r = *static_cast<const int64_t*>(p);
856 const int64_t &s = *static_cast<const int64_t*>(q);
861 * @brief Compare difference counts.
862 * @param [in] p First count to compare.
863 * @param [in] q Second count to compare.
864 * @return Compare result.
866 static int ColDiffsSort(const CDiffContext *, const void *p, const void *q)
868 const int &r = *static_cast<const int*>(p);
869 const int &s = *static_cast<const int*>(q);
874 * @brief Compare newer/older statuses.
875 * @param [in] pCtxt Pointer to compare context.
876 * @param [in] p Pointer to DIFFITEM having first status to compare.
877 * @param [in] q Pointer to DIFFITEM having second status to compare.
878 * @return Compare result.
880 static int ColNewerSort(const CDiffContext *pCtxt, const void *p, const void *q)
882 return ColNewerGet(pCtxt, p) == ColNewerGet(pCtxt, q);
886 * @brief Compare left-side file versions.
887 * @param [in] pCtxt Pointer to compare context.
888 * @param [in] p Pointer to DIFFITEM having first version to compare.
889 * @param [in] q Pointer to DIFFITEM having second version to compare.
890 * @return Compare result.
892 static int ColLversionSort(const CDiffContext *pCtxt, const void *p, const void *q)
894 return ColLversionGet(pCtxt, p) == ColLversionGet(pCtxt, q);
898 * @brief Compare right-side file versions.
899 * @param [in] pCtxt Pointer to compare context.
900 * @param [in] p Pointer to DIFFITEM having first version to compare.
901 * @param [in] q Pointer to DIFFITEM having second version to compare.
902 * @return Compare result.
904 static int ColRversionSort(const CDiffContext *pCtxt, const void *p, const void *q)
906 return ColRversionGet(pCtxt, p) == ColRversionGet(pCtxt, q);
910 * @brief Compare binary statuses.
911 * This function returns a comparison of binary results.
912 * @param [in] p Pointer to DIFFITEM having first status to compare.
913 * @param [in] q Pointer to DIFFITEM having second status to compare.
914 * @return Compare result:
915 * - if both items are text files or binary files: 0
916 * - if left is text and right is binary: -1
917 * - if left is binary and right is text: 1
919 static int ColBinSort(const CDiffContext *, const void *p, const void *q)
921 const DIFFITEM &ldi = *static_cast<const DIFFITEM *>(p);
922 const DIFFITEM &rdi = *static_cast<const DIFFITEM *>(q);
923 const bool i = ldi.diffcode.isBin();
924 const bool j = rdi.diffcode.isBin();
937 * @brief Compare file flags.
938 * @param [in] p Pointer to first flag structure to compare.
939 * @param [in] q Pointer to second flag structure to compare.
940 * @return Compare result.
942 static int ColAttrSort(const CDiffContext *, const void *p, const void *q)
944 const FileFlags &r = *static_cast<const FileFlags *>(p);
945 const FileFlags &s = *static_cast<const FileFlags *>(q);
946 return r.ToString() == s.ToString();
950 * @brief Compare file encodings.
951 * @param [in] p Pointer to first structure to compare.
952 * @param [in] q Pointer to second structure to compare.
953 * @return Compare result.
955 static int ColEncodingSort(const CDiffContext *, const void *p, const void *q)
957 const DiffFileInfo &r = *static_cast<const DiffFileInfo *>(p);
958 const DiffFileInfo &s = *static_cast<const DiffFileInfo *>(q);
959 return FileTextEncoding::Collate(r.encoding, s.encoding);
964 * @brief All existing folder compare columns.
966 * This table has information for all folder compare columns. Fields are
969 * - name resource ID: column's name shown in header
970 * - description resource ID: columns description text
971 * - custom function for getting column data
972 * - custom function for sorting column data
973 * - parameter for custom functions: DIFFITEM (if NULL) or one of its fields
974 * - default column order number, -1 if not shown by default
975 * - ascending (TRUE) or descending (FALSE) default sort order
976 * - alignment of column contents: numbers are usually right-aligned
978 static DirColInfo f_cols[] =
980 { _T("Name"), COLHDR_FILENAME, COLDESC_FILENAME, &ColFileNameGet<String>, &ColFileNameSort, 0, 0, true, DirColInfo::ALIGN_LEFT },
981 { _T("Path"), COLHDR_DIR, COLDESC_DIR, &ColPathGet, &ColPathSort, 0, 1, true, DirColInfo::ALIGN_LEFT },
982 { _T("Status"), COLHDR_RESULT, COLDESC_RESULT, &ColStatusGet, &ColStatusSort, 0, 2, true, DirColInfo::ALIGN_LEFT },
983 { _T("Lmtime"), COLHDR_LTIMEM, COLDESC_LTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].mtime), 3, false, DirColInfo::ALIGN_LEFT },
984 { _T("Rmtime"), COLHDR_RTIMEM, COLDESC_RTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].mtime), 4, false, DirColInfo::ALIGN_LEFT },
985 { _T("Lctime"), COLHDR_LTIMEC, COLDESC_LTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].ctime), -1, false, DirColInfo::ALIGN_LEFT },
986 { _T("Rctime"), COLHDR_RTIMEC, COLDESC_RTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].ctime), -1, false, DirColInfo::ALIGN_LEFT },
987 { _T("Ext"), COLHDR_EXTENSION, COLDESC_EXTENSION, &ColExtGet, &ColExtSort, 0, 5, true, DirColInfo::ALIGN_LEFT },
988 { _T("Lsize"), COLHDR_LSIZE, COLDESC_LSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
989 { _T("Rsize"), COLHDR_RSIZE, COLDESC_RSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
990 { _T("LsizeShort"), COLHDR_LSIZE_SHORT, COLDESC_LSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
991 { _T("RsizeShort"), COLHDR_RSIZE_SHORT, COLDESC_RSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
992 { _T("Newer"), COLHDR_NEWER, COLDESC_NEWER, &ColNewerGet, &ColNewerSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
993 { _T("Lversion"), COLHDR_LVERSION, COLDESC_LVERSION, &ColLversionGet, &ColLversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
994 { _T("Rversion"), COLHDR_RVERSION, COLDESC_RVERSION, &ColRversionGet, &ColRversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
995 { _T("StatusAbbr"), COLHDR_RESULT_ABBR, COLDESC_RESULT_ABBR, &ColStatusAbbrGet, &ColStatusSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
996 { _T("Binary"), COLHDR_BINARY, COLDESC_BINARY, &ColBinGet, &ColBinSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
997 { _T("Lattr"), COLHDR_LATTRIBUTES, COLDESC_LATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].flags), -1, true, DirColInfo::ALIGN_LEFT },
998 { _T("Rattr"), COLHDR_RATTRIBUTES, COLDESC_RATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].flags), -1, true, DirColInfo::ALIGN_LEFT },
999 { _T("Lencoding"), COLHDR_LENCODING, COLDESC_LENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0]), -1, true, DirColInfo::ALIGN_LEFT },
1000 { _T("Rencoding"), COLHDR_RENCODING, COLDESC_RENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1]), -1, true, DirColInfo::ALIGN_LEFT },
1001 { _T("Snsdiffs"), COLHDR_NSDIFFS, COLDESC_NSDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nsdiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1002 { _T("Snidiffs"), COLHDR_NIDIFFS, COLDESC_NIDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nidiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1003 { _T("Leoltype"), COLHDR_LEOL_TYPE, COLDESC_LEOL_TYPE, &ColLEOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1004 { _T("Reoltype"), COLHDR_REOL_TYPE, COLDESC_REOL_TYPE, &ColREOLTypeGet, 0, 0, -1, true, DirColInfo::ALIGN_LEFT },
1006 static DirColInfo f_cols3[] =
1008 { _T("Name"), COLHDR_FILENAME, COLDESC_FILENAME, &ColFileNameGet<String>, &ColFileNameSort, 0, 0, true, DirColInfo::ALIGN_LEFT },
1009 { _T("Path"), COLHDR_DIR, COLDESC_DIR, &ColPathGet, &ColPathSort, 0, 1, true, DirColInfo::ALIGN_LEFT },
1010 { _T("Status"), COLHDR_RESULT, COLDESC_RESULT, &ColStatusGet, &ColStatusSort, 0, 2, true, DirColInfo::ALIGN_LEFT },
1011 { _T("Lmtime"), COLHDR_LTIMEM, COLDESC_LTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].mtime), 3, false, DirColInfo::ALIGN_LEFT },
1012 { _T("Mmtime"), COLHDR_MTIMEM, COLDESC_MTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].mtime), 4, false, DirColInfo::ALIGN_LEFT },
1013 { _T("Rmtime"), COLHDR_RTIMEM, COLDESC_RTIMEM, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].mtime), 5, false, DirColInfo::ALIGN_LEFT },
1014 { _T("Lctime"), COLHDR_LTIMEC, COLDESC_LTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1015 { _T("Mctime"), COLHDR_MTIMEC, COLDESC_MTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1016 { _T("Rctime"), COLHDR_RTIMEC, COLDESC_RTIMEC, &ColTimeGet, &ColTimeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].ctime), -1, false, DirColInfo::ALIGN_LEFT },
1017 { _T("Ext"), COLHDR_EXTENSION, COLDESC_EXTENSION, &ColExtGet, &ColExtSort, 0, 6, true, DirColInfo::ALIGN_LEFT },
1018 { _T("Lsize"), COLHDR_LSIZE, COLDESC_LSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1019 { _T("Msize"), COLHDR_MSIZE, COLDESC_MSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1020 { _T("Rsize"), COLHDR_RSIZE, COLDESC_RSIZE, &ColSizeGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].size), -1, false, DirColInfo::ALIGN_RIGHT },
1021 { _T("LsizeShort"), COLHDR_LSIZE_SHORT, COLDESC_LSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].size), -1, false, DirColInfo::ALIGN_RIGHT },
1022 { _T("MsizeShort"), COLHDR_MSIZE_SHORT, COLDESC_MSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].size), -1, false, DirColInfo::ALIGN_RIGHT },
1023 { _T("RsizeShort"), COLHDR_RSIZE_SHORT, COLDESC_RSIZE_SHORT, &ColSizeShortGet, &ColSizeSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].size), -1, false, DirColInfo::ALIGN_RIGHT },
1024 { _T("Newer"), COLHDR_NEWER, COLDESC_NEWER, &ColNewerGet, &ColNewerSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1025 { _T("Lversion"), COLHDR_LVERSION, COLDESC_LVERSION, &ColLversionGet, &ColLversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1026 { _T("Mversion"), COLHDR_MVERSION, COLDESC_MVERSION, &ColRversionGet, &ColRversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1027 { _T("Rversion"), COLHDR_RVERSION, COLDESC_RVERSION, &ColRversionGet, &ColRversionSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1028 { _T("StatusAbbr"), COLHDR_RESULT_ABBR, COLDESC_RESULT_ABBR, &ColStatusAbbrGet, &ColStatusSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1029 { _T("Binary"), COLHDR_BINARY, COLDESC_BINARY, &ColBinGet, &ColBinSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1030 { _T("Lattr"), COLHDR_LATTRIBUTES, COLDESC_LATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0].flags), -1, true, DirColInfo::ALIGN_LEFT },
1031 { _T("Mattr"), COLHDR_MATTRIBUTES, COLDESC_MATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1].flags), -1, true, DirColInfo::ALIGN_LEFT },
1032 { _T("Rattr"), COLHDR_RATTRIBUTES, COLDESC_RATTRIBUTES, &ColAttrGet, &ColAttrSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2].flags), -1, true, DirColInfo::ALIGN_LEFT },
1033 { _T("Lencoding"), COLHDR_LENCODING, COLDESC_LENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[0]), -1, true, DirColInfo::ALIGN_LEFT },
1034 { _T("Mencoding"), COLHDR_MENCODING, COLDESC_MENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[1]), -1, true, DirColInfo::ALIGN_LEFT },
1035 { _T("Rencoding"), COLHDR_RENCODING, COLDESC_RENCODING, &ColEncodingGet, &ColEncodingSort, FIELD_OFFSET(DIFFITEM, diffFileInfo[2]), -1, true, DirColInfo::ALIGN_LEFT },
1036 { _T("Snsdiffs"), COLHDR_NSDIFFS, COLDESC_NSDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nsdiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1037 { _T("Snidiffs"), COLHDR_NIDIFFS, COLDESC_NIDIFFS, ColDiffsGet, ColDiffsSort, FIELD_OFFSET(DIFFITEM, nidiffs), -1, false, DirColInfo::ALIGN_RIGHT },
1038 { _T("Leoltype"), COLHDR_LEOL_TYPE, COLDESC_LEOL_TYPE, &ColLEOLTypeGet, &ColAttrSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1039 { _T("Meoltype"), COLHDR_MEOL_TYPE, COLDESC_MEOL_TYPE, &ColMEOLTypeGet, &ColAttrSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1040 { _T("Reoltype"), COLHDR_REOL_TYPE, COLDESC_REOL_TYPE, &ColREOLTypeGet, &ColAttrSort, 0, -1, true, DirColInfo::ALIGN_LEFT },
1044 * @brief Count of all known columns
1046 const int g_ncols = countof(f_cols);
1047 const int g_ncols3 = countof(f_cols3);
1050 * @brief Registry base value name for saving/loading info for this column
1053 DirViewColItems::GetColRegValueNameBase(int col) const
1057 assert(col>=0 && col<countof(f_cols));
1058 return string_format(_T("WDirHdr_%s"), f_cols[col].regName);
1062 assert(col>=0 && col<countof(f_cols3));
1063 return string_format(_T("WDirHdr_%s"), f_cols3[col].regName);
1068 * @brief Get default physical order for specified logical column
1071 DirViewColItems::GetColDefaultOrder(int col) const
1075 assert(col>=0 && col<countof(f_cols));
1076 return f_cols[col].physicalIndex;
1080 assert(col>=0 && col<countof(f_cols3));
1081 return f_cols3[col].physicalIndex;
1086 * @brief Return the info about the specified physical column
1089 DirViewColItems::GetDirColInfo(int col) const
1093 if (col < 0 || col >= countof(f_cols))
1095 assert(0); // fix caller, should not ask for nonexistent columns
1098 return &f_cols[col];
1102 if (col < 0 || col >= countof(f_cols3))
1104 assert(0); // fix caller, should not ask for nonexistent columns
1107 return &f_cols3[col];
1112 * @brief Check if specified physical column has specified resource id name
1115 DirViewColItems::IsColById(int col, const char *idname) const
1117 int nDirs = m_nDirs;
1120 if (col < 0 || col >= countof(f_cols))
1122 assert(0); // fix caller, should not ask for nonexistent columns
1125 return f_cols[col].idName == idname;
1129 if (col < 0 || col >= sizeof(f_cols3)/sizeof(f_cols3[0]))
1131 assert(0); // fix caller, should not ask for nonexistent columns
1134 return f_cols3[col].idName == idname;
1139 * @brief Is specified physical column the name column?
1142 DirViewColItems::IsColName(int col) const
1144 return IsColById(col, COLHDR_FILENAME);
1147 * @brief Is specified physical column the left modification time column?
1150 DirViewColItems::IsColLmTime(int col) const
1152 return IsColById(col, COLHDR_LTIMEM);
1155 * @brief Is specified physical column the middle modification time column?
1158 DirViewColItems::IsColMmTime(int col) const
1160 return IsColById(col, COLHDR_MTIMEM);
1163 * @brief Is specified physical column the right modification time column?
1166 DirViewColItems::IsColRmTime(int col) const
1168 return IsColById(col, COLHDR_RTIMEM);
1171 * @brief Is specified physical column the full status (result) column?
1174 DirViewColItems::IsColStatus(int col) const
1176 return IsColById(col, COLHDR_RESULT);
1179 * @brief Is specified physical column the full status (result) column?
1182 DirViewColItems::IsColStatusAbbr(int col) const
1184 return IsColById(col, COLHDR_RESULT_ABBR);
1188 * @brief return whether column normally sorts ascending (dates do not)
1191 DirViewColItems::IsDefaultSortAscending(int col) const
1193 const DirColInfo * pColInfo = GetDirColInfo(col);
1196 assert(0); // fix caller, should not ask for nonexistent columns
1199 return pColInfo->defSortUp;
1203 * @brief Return display name of column
1206 DirViewColItems::GetColDisplayName(int col) const
1208 const DirColInfo * colinfo = GetDirColInfo(col);
1209 return tr(colinfo->idName);
1213 * @brief Return description of column
1216 DirViewColItems::GetColDescription(int col) const
1218 const DirColInfo * colinfo = GetDirColInfo(col);
1219 return tr(colinfo->idDesc);
1223 * @brief Return total number of known columns
1226 DirViewColItems::GetColCount() const
1235 * @brief Get text for specified column.
1236 * This function retrieves the text for the specified colum. Text is
1237 * retrieved by using column-specific handler functions.
1238 * @param [in] pCtxt Compare context.
1239 * @param [in] col Column number.
1240 * @param [in] di Difference data.
1241 * @return Text for the specified column.
1244 DirViewColItems::ColGetTextToDisplay(const CDiffContext *pCtxt, int col,
1245 const DIFFITEM & di) const
1247 // Custom properties have custom get functions
1248 const DirColInfo * pColInfo = GetDirColInfo(col);
1251 assert(0); // fix caller, should not ask for nonexistent columns
1254 ColGetFncPtrType fnc = pColInfo->getfnc;
1255 size_t offset = pColInfo->offset;
1256 String s = (*fnc)(pCtxt, reinterpret_cast<const char *>(&di) + offset);
1258 // Add '*' to newer time field
1261 if (di.diffFileInfo[0].mtime != 0 || di.diffFileInfo[1].mtime != 0)
1265 IsColLmTime(col) && di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime // Left modification time
1266 || IsColRmTime(col) && di.diffFileInfo[0].mtime < di.diffFileInfo[1].mtime // Right modification time
1269 s.insert(0, _T("* "));
1275 if (di.diffFileInfo[0].mtime != 0 || di.diffFileInfo[1].mtime != 0 || di.diffFileInfo[2].mtime != 0)
1279 IsColLmTime(col) && di.diffFileInfo[0].mtime > di.diffFileInfo[1].mtime && di.diffFileInfo[0].mtime > di.diffFileInfo[2].mtime // Left modification time
1280 || IsColMmTime(col) && di.diffFileInfo[1].mtime > di.diffFileInfo[0].mtime && di.diffFileInfo[1].mtime > di.diffFileInfo[2].mtime // Middle modification time
1281 || IsColRmTime(col) && di.diffFileInfo[2].mtime > di.diffFileInfo[0].mtime && di.diffFileInfo[2].mtime > di.diffFileInfo[1].mtime // Right modification time
1284 s.insert(0, _T("* "));
1294 * @brief Sort two items on specified column.
1295 * This function determines order of two items in specified column. Order
1296 * is determined by column-specific functions.
1297 * @param [in] pCtxt Compare context.
1298 * @param [in] col Column number to sort.
1299 * @param [in] ldi Left difference item data.
1300 * @param [in] rdi Right difference item data.
1301 * @return Order of items.
1304 DirViewColItems::ColSort(const CDiffContext *pCtxt, int col, const DIFFITEM & ldi,
1305 const DIFFITEM & rdi, bool bTreeMode) const
1307 // Custom properties have custom sort functions
1308 const DirColInfo * pColInfo = GetDirColInfo(col);
1311 assert(0); // fix caller, should not ask for nonexistent columns
1314 size_t offset = pColInfo->offset;
1319 int lLevel = ldi.GetDepth();
1320 int rLevel = rdi.GetDepth();
1321 const DIFFITEM *lcur = &ldi, *rcur = &rdi;
1322 if (lLevel < rLevel)
1324 for (; lLevel != rLevel; rLevel--)
1325 rcur = rcur->parent;
1327 else if (rLevel < lLevel)
1329 for (; lLevel != rLevel; lLevel--)
1330 lcur = lcur->parent;
1332 while (lcur->parent != rcur->parent)
1334 lcur = lcur->parent;
1335 rcur = rcur->parent;
1337 arg1 = reinterpret_cast<const char *>(lcur) + offset;
1338 arg2 = reinterpret_cast<const char *>(rcur) + offset;
1342 arg1 = reinterpret_cast<const char *>(&ldi) + offset;
1343 arg2 = reinterpret_cast<const char *>(&rdi) + offset;
1345 if (ColSortFncPtrType fnc = pColInfo->sortfnc)
1347 return (*fnc)(pCtxt, arg1, arg2);
1349 if (ColGetFncPtrType fnc = pColInfo->getfnc)
1351 String p = (*fnc)(pCtxt, arg1);
1352 String q = (*fnc)(pCtxt, arg2);
1353 return string_compare_nocase(p, q);
1358 void DirViewColItems::SetColumnOrdering(const int colorder[])
1361 for (int i = 0; i < m_numcols; ++i)
1363 m_colorder[i] = colorder[i];
1364 int phy = m_colorder[i];
1368 m_invcolorder[phy] = i;
1373 * @brief Sanity check column ordering
1375 void DirViewColItems::ValidateColumnOrdering()
1379 assert(m_invcolorder[0]>=0);
1380 assert(m_numcols == GetColCount());
1381 // Check that any logical->physical mapping is reversible
1382 for (int i=0; i<m_numcols; ++i)
1384 int phy = m_colorder[i];
1387 int log = m_invcolorder[phy];
1391 // Bail out if header doesn't exist yet
1392 // int hdrcnt = GetListCtrl().GetHeaderCtrl()->GetItemCount();
1395 // ASSERT(hdrcnt == m_dispcols);
1402 * @brief Set column ordering to default initial order
1404 void DirViewColItems::ResetColumnOrdering()
1406 ClearColumnOrders();
1408 for (int i=0; i<m_numcols; ++i)
1410 int phy = GetColDefaultOrder(i);
1411 m_colorder[i] = phy;
1414 m_invcolorder[phy] = i;
1418 ValidateColumnOrdering();
1422 * @brief Reset all current column ordering information
1424 void DirViewColItems::ClearColumnOrders()
1426 m_colorder.resize(m_numcols);
1427 m_invcolorder.resize(m_numcols);
1428 for (int i=0; i<m_numcols; ++i)
1431 m_invcolorder[i] = -1;
1436 * @brief Remove any windows reordering of columns (params are physical columns)
1438 void DirViewColItems::MoveColumn(int psrc, int pdest)
1440 // actually moved column
1441 m_colorder[m_invcolorder[psrc]] = pdest;
1442 // shift all other affected columns
1443 int dir = psrc > pdest ? +1 : -1;
1445 for (i=pdest; i!=psrc; i += dir)
1447 m_colorder[m_invcolorder[i]] = i+dir;
1449 // fix inverse mapping
1450 for (i=0; i<m_numcols; ++i)
1452 if (m_colorder[i] >= 0)
1453 m_invcolorder[m_colorder[i]] = i;
1455 ValidateColumnOrdering();
1459 * @brief Resets column widths to defaults.
1461 String DirViewColItems::ResetColumnWidths(int defcolwidth)
1464 for (int i = 0; i < m_numcols; i++)
1466 if (!result.empty()) result += ' ';
1467 result += string_to_str(defcolwidth);
1473 * @brief Load column orders from registry
1475 void DirViewColItems::LoadColumnOrders(String colorders)
1477 assert(m_numcols == -1);
1478 m_numcols = GetColCount();
1479 ClearColumnOrders();
1481 std::basic_istringstream<TCHAR> ss(colorders);
1483 // Load column orders
1484 // Break out if one is missing
1485 // Break out & mark failure (m_dispcols == -1) if one is invalid
1487 for (i=0; i<m_numcols; ++i)
1491 if (ord<-1 || ord >= m_numcols)
1493 m_colorder[i] = ord;
1497 if (m_invcolorder[ord] != -1)
1502 m_invcolorder[ord] = i;
1505 // Check that a contiguous range was set
1506 for (i=0; i<m_dispcols; ++i)
1508 if (m_invcolorder[i] < 0)
1514 // Must have at least one column
1517 ResetColumnOrdering();
1520 ValidateColumnOrdering();
1523 /// store current column orders into registry
1524 String DirViewColItems::SaveColumnOrders()
1526 assert(m_colorder.size() == m_numcols);
1527 assert(m_invcolorder.size() == m_numcols);
1528 return string_join<String (*)(int)>(m_colorder.begin(), m_colorder.end(), _T(" "), string_to_str);