1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008 - TortoiseSVN
4 // Copyright (C) 2008-2011 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include ".\resource.h"
23 #include "GitStatusListCtrl.h"
26 // registry version number of column-settings of GitLogListBase
27 #define BLAME_COLUMN_VERSION 4
30 #define assert(x) ATLASSERT(x)
32 // assign property list
35 PropertyList::operator= (const char* rhs
)
37 // do you really want to replace the property list?
39 assert (properties
.empty());
42 // add all properties in the list
44 while ((rhs
!= NULL
) && (*rhs
!= 0))
46 const char* next
= strchr (rhs
, ' ');
48 CString
name (rhs
, static_cast<int>(next
== NULL
? strlen (rhs
) : next
- rhs
));
49 properties
.insert (std::make_pair (name
, CString()));
51 rhs
= next
== NULL
? NULL
: next
+1;
59 // collect property names in a set
61 void PropertyList::GetPropertyNames (std::set
<CString
>& names
)
63 for ( CIT iter
= properties
.begin(), end
= properties
.end()
67 names
.insert (iter
->first
);
71 // get a property value.
73 CString
PropertyList::operator[](const CString
& name
) const
75 CIT iter
= properties
.find (name
);
77 return iter
== properties
.end()
82 // set a property value.
84 CString
& PropertyList::operator[](const CString
& name
)
86 return properties
[name
];
89 /// check whether that property has been set on this item.
91 bool PropertyList::HasProperty (const CString
& name
) const
93 return properties
.find (name
) != properties
.end();
96 // due to frequent use: special check for svn:needs-lock
98 bool PropertyList::IsNeedsLockSet() const
100 static const CString svnNeedsLock
= _T("svn:needs-lock");
101 return HasProperty (svnNeedsLock
);
107 void ColumnManager::ReadSettings
108 ( DWORD defaultColumns
110 , const CString
& containerName
115 DWORD selectedStandardColumns
= defaultColumns
& ~hideColumns
;
116 m_dwDefaultColumns
= defaultColumns
& ~hideColumns
;
118 columns
.resize (maxsize
);
120 for (size_t i
= 0; i
< maxsize
; ++i
)
122 columns
[i
].index
= static_cast<int>(i
);
124 columns
[i
].width
= 0;
126 columns
[i
].width
= widthlist
[i
];
127 columns
[i
].visible
= true;
128 columns
[i
].relevant
= !(hideColumns
& power
);
132 // userProps.clear();
134 // where the settings are stored within the registry
136 registryPrefix
= _T("Software\\TortoiseGit\\StatusColumns\\") + containerName
;
138 // we accept settings of current version only
139 bool valid
= (DWORD
)CRegDWORD (registryPrefix
+ _T("Version"), 0xff) == BLAME_COLUMN_VERSION
;
142 // read (possibly different) column selection
144 selectedStandardColumns
= CRegDWORD (registryPrefix
, selectedStandardColumns
) & ~hideColumns
;
146 // read user-prop lists
148 CString userPropList
= CRegString (registryPrefix
+ _T("UserProps"));
149 CString shownUserProps
= CRegString (registryPrefix
+ _T("ShownUserProps"));
151 ParseUserPropSettings (userPropList
, shownUserProps
);
153 // read column widths
155 CString colWidths
= CRegString (registryPrefix
+ _T("_Width"));
157 ParseWidths (colWidths
);
160 // process old-style visibility setting
162 SetStandardColumnVisibility (selectedStandardColumns
);
164 // clear all previously set header columns
166 int c
= ((CHeaderCtrl
*)(control
->GetDlgItem(0)))->GetItemCount()-1;
168 control
->DeleteColumn(c
--);
172 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
173 control
->InsertColumn (i
, GetName(i
), LVCFMT_LEFT
, IsVisible(i
)&&IsRelevant(i
) ? -1 : GetVisibleWidth(i
, false));
175 // restore column ordering
178 ParseColumnOrder (CRegString (registryPrefix
+ _T("_Order")));
180 ParseColumnOrder (CString());
184 // auto-size the columns so we can see them while fetching status
185 // (seems the same values will not take affect in InsertColumn)
187 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
189 control
->SetColumnWidth (i
, GetVisibleWidth (i
, true));
192 void ColumnManager::WriteSettings() const
194 CRegDWORD
regVersion (registryPrefix
+ _T("Version"), 0, TRUE
);
195 regVersion
= BLAME_COLUMN_VERSION
;
197 // write (possibly different) column selection
199 CRegDWORD
regStandardColumns (registryPrefix
, 0, TRUE
);
200 regStandardColumns
= GetSelectedStandardColumns();
202 // write user-prop lists
204 CRegString
regUserProps (registryPrefix
+ _T("UserProps"), CString(), TRUE
);
205 regUserProps
= GetUserPropList();
207 CRegString
regShownUserProps (registryPrefix
+ _T("ShownUserProps"), CString(), TRUE
);
208 regShownUserProps
= GetShownUserProps();
210 // write column widths
212 CRegString
regWidths (registryPrefix
+ _T("_Width"), CString(), TRUE
);
213 regWidths
= GetWidthString();
215 // write column ordering
217 CRegString
regColumnOrder (registryPrefix
+ _T("_Order"), CString(), TRUE
);
218 regColumnOrder
= GetColumnOrderString();
221 // read column definitions
223 int ColumnManager::GetColumnCount() const
225 return static_cast<int>(columns
.size());
228 bool ColumnManager::IsVisible (int column
) const
230 size_t index
= static_cast<size_t>(column
);
231 assert (columns
.size() > index
);
233 return columns
[index
].visible
;
236 int ColumnManager::GetInvisibleCount() const
238 int invisibleCount
= 0;
239 for (std::vector
<ColumnInfo
>::const_iterator it
= columns
.begin(); it
!= columns
.end(); ++it
)
244 return invisibleCount
;
247 bool ColumnManager::IsRelevant (int column
) const
249 size_t index
= static_cast<size_t>(column
);
250 assert (columns
.size() > index
);
252 return columns
[index
].relevant
;
255 bool ColumnManager::IsUserProp (int column
) const
257 size_t index
= static_cast<size_t>(column
);
258 assert (columns
.size() > index
);
260 return columns
[index
].index
>= GITSLC_USERPROPCOLOFFSET
;
263 int ColumnManager::SetNames(UINT
* buffer
, int size
)
266 for(int i
=0;i
<size
;i
++)
267 itemName
.push_back(*buffer
++);
271 CString
ColumnManager::GetName (int column
) const
274 size_t index
= static_cast<size_t>(column
);
275 if (index
< itemName
.size())
278 result
.LoadString (itemName
[index
]);
284 // if (index < columns.size())
285 // return userProps[columns[index].index - SVNSLC_USERPROPCOLOFFSET].name;
292 int ColumnManager::GetWidth (int column
, bool useDefaults
) const
294 size_t index
= static_cast<size_t>(column
);
295 assert (columns
.size() > index
);
297 int width
= columns
[index
].width
;
298 if ((width
== 0) && useDefaults
)
299 width
= LVSCW_AUTOSIZE_USEHEADER
;
304 int ColumnManager::GetVisibleWidth (int column
, bool useDefaults
) const
306 return IsVisible (column
)
307 ? GetWidth (column
, useDefaults
)
311 // switch columns on and off
313 void ColumnManager::SetVisible
317 size_t index
= static_cast<size_t>(column
);
318 assert (index
< columns
.size());
320 if (columns
[index
].visible
!= visible
)
322 columns
[index
].visible
= visible
;
323 columns
[index
].relevant
|= visible
;
325 columns
[index
].width
= 0;
327 control
->SetColumnWidth (column
, GetVisibleWidth (column
, true));
330 control
->Invalidate (FALSE
);
334 // tracking column modifications
336 void ColumnManager::ColumnMoved (int column
, int position
)
338 // in front of what column has it been inserted?
340 int index
= columns
[column
].index
;
342 std::vector
<int> gridColumnOrder
= GetGridColumnOrder();
344 size_t visiblePosition
= static_cast<size_t>(position
);
345 size_t columnCount
= gridColumnOrder
.size();
347 for (; (visiblePosition
< columnCount
)
348 && !columns
[gridColumnOrder
[visiblePosition
]].visible
349 ; ++visiblePosition
)
354 if (visiblePosition
!= columnCount
)
356 next
= gridColumnOrder
[visiblePosition
];
359 // move logical column index just in front of that "next" column
361 columnOrder
.erase (std::find ( columnOrder
.begin(), columnOrder
.end(), index
));
362 columnOrder
.insert ( std::find ( columnOrder
.begin(), columnOrder
.end(), next
), index
);
364 // make sure, invisible columns are still put in front of all others
369 void ColumnManager::ColumnResized (int column
)
371 size_t index
= static_cast<size_t>(column
);
372 assert (index
< columns
.size());
373 assert (columns
[index
].visible
);
375 int width
= control
->GetColumnWidth (column
);
376 columns
[index
].width
= width
;
378 int propertyIndex
= columns
[index
].index
;
379 if (propertyIndex
>= GITSLC_USERPROPCOLOFFSET
)
380 userProps
[propertyIndex
- GITSLC_USERPROPCOLOFFSET
].width
= width
;
382 control
->Invalidate (FALSE
);
385 // call these to update the user-prop list
386 // (will also auto-insert /-remove new list columns)
388 void ColumnManager::UpdateUserPropList
389 (const std::vector
<FileEntry
*>& files
)
391 // collect all user-defined props
393 std::set
<CString
> aggregatedProps
;
394 for (size_t i
= 0, count
= files
.size(); i
< count
; ++i
)
395 files
[i
]->present_props
.GetPropertyNames (aggregatedProps
);
397 aggregatedProps
.erase (_T("svn:needs-lock"));
398 itemProps
= aggregatedProps
;
400 // add new ones to the internal list
402 std::set
<CString
> newProps
= aggregatedProps
;
403 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
404 newProps
.erase (userProps
[i
].name
);
406 while (newProps
.size() + userProps
.size()
407 > SVNSLC_MAXCOLUMNCOUNT
- SVNSLC_USERPROPCOLOFFSET
)
408 newProps
.erase (--newProps
.end());
410 typedef std::set
<CString
>::const_iterator CIT
;
411 for ( CIT iter
= newProps
.begin(), end
= newProps
.end()
415 int index
= static_cast<int>(userProps
.size())
416 + SVNSLC_USERPROPCOLOFFSET
;
417 columnOrder
.push_back (index
);
420 userProp
.name
= *iter
;
423 userProps
.push_back (userProp
);
426 // remove unused columns from control.
427 // remove used ones from the set of aggregatedProps.
429 for (size_t i
= columns
.size(); i
> 0; --i
)
430 if ((columns
[i
-1].index
>= SVNSLC_USERPROPCOLOFFSET
)
431 && (aggregatedProps
.erase (GetName ((int)i
-1)) == 0))
433 // this user-prop has not been set on any item
435 if (!columns
[i
-1].visible
)
437 control
->DeleteColumn (static_cast<int>(i
-1));
438 columns
.erase (columns
.begin() + i
-1);
442 // aggregatedProps now contains new columns only.
443 // we can't use newProps here because some props may have been used
444 // earlier but were not in the recent list of used props.
445 // -> they are neither in columns[] nor in newProps.
447 for ( CIT iter
= aggregatedProps
.begin(), end
= aggregatedProps
.end()
451 // get the logical column index / ID
455 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
456 if (userProps
[i
].name
== *iter
)
458 index
= static_cast<int>(i
) + SVNSLC_USERPROPCOLOFFSET
;
459 width
= userProps
[i
].width
;
463 assert (index
!= -1);
465 // find insertion position
467 std::vector
<ColumnInfo
>::iterator columnIter
= columns
.begin();
468 std::vector
<ColumnInfo
>::iterator end
= columns
.end();
469 for (; (columnIter
!= end
) && columnIter
->index
< index
; ++columnIter
);
470 int pos
= static_cast<int>(columnIter
- columns
.begin());
473 column
.index
= index
;
474 column
.width
= width
;
475 column
.visible
= false;
477 columns
.insert (columnIter
, column
);
481 int result
= control
->InsertColumn (pos
, *iter
, LVCFMT_LEFT
, GetVisibleWidth(pos
, false));
482 assert (result
!= -1);
483 UNREFERENCED_PARAMETER(result
);
486 // update column order
492 void ColumnManager::UpdateRelevance
493 ( const std::vector
<FileEntry
*>& files
494 , const std::vector
<size_t>& visibleFiles
)
496 // collect all user-defined props that belong to shown files
498 std::set
<CString
> aggregatedProps
;
499 for (size_t i
= 0, count
= visibleFiles
.size(); i
< count
; ++i
)
500 files
[visibleFiles
[i
]]->present_props
.GetPropertyNames (aggregatedProps
);
502 aggregatedProps
.erase (_T("svn:needs-lock"));
503 itemProps
= aggregatedProps
;
505 // invisible columns for unused props are not relevant
507 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
508 if (IsUserProp(i
) && !IsVisible(i
))
511 = aggregatedProps
.find (GetName(i
)) != aggregatedProps
.end();
516 // don't clutter the context menu with irrelevant prop info
518 bool ColumnManager::AnyUnusedProperties() const
520 return columns
.size() < userProps
.size() + itemName
.size();
523 void ColumnManager::RemoveUnusedProps()
525 // determine what column indexes / IDs to keep.
526 // map them onto new IDs (we may delete some IDs in between)
528 std::map
<int, int> validIndices
;
529 int userPropID
= GITSLC_USERPROPCOLOFFSET
;
531 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
533 int index
= columns
[i
].index
;
535 if (itemProps
.find (GetName((int)i
)) != itemProps
.end()
536 || columns
[i
].visible
537 || index
< GITSLC_USERPROPCOLOFFSET
)
539 validIndices
[index
] = index
< GITSLC_USERPROPCOLOFFSET
545 // remove everything else:
547 // remove from columns and control.
548 // also update index values in columns
550 for (size_t i
= columns
.size(); i
> 0; --i
)
552 std::map
<int, int>::const_iterator iter
553 = validIndices
.find (columns
[i
-1].index
);
555 if (iter
== validIndices
.end())
557 control
->DeleteColumn (static_cast<int>(i
-1));
558 columns
.erase (columns
.begin() + i
-1);
562 columns
[i
-1].index
= iter
->second
;
566 // remove from user props
568 for (size_t i
= userProps
.size(); i
> 0; --i
)
570 int index
= static_cast<int>(i
)-1 + GITSLC_USERPROPCOLOFFSET
;
571 if (validIndices
.find (index
) == validIndices
.end())
572 userProps
.erase (userProps
.begin() + i
-1);
575 // remove from and update column order
577 for (size_t i
= columnOrder
.size(); i
> 0; --i
)
579 std::map
<int, int>::const_iterator iter
580 = validIndices
.find (columnOrder
[i
-1]);
582 if (iter
== validIndices
.end())
583 columnOrder
.erase (columnOrder
.begin() + i
-1);
585 columnOrder
[i
-1] = iter
->second
;
589 // bring everything back to its "natural" order
591 void ColumnManager::ResetColumns (DWORD defaultColumns
)
593 // update internal data
595 std::sort (columnOrder
.begin(), columnOrder
.end());
597 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
599 columns
[i
].width
= 0;
600 columns
[i
].visible
= (i
< 32) && (((defaultColumns
>> i
) & 1) != 0);
603 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
604 userProps
[i
].width
= 0;
608 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
609 control
->SetColumnWidth (i
, GetVisibleWidth (i
, true));
613 control
->Invalidate (FALSE
);
616 // initialization utilities
618 void ColumnManager::ParseUserPropSettings(const CString
& userPropList
, const CString
& shownUserProps
)
620 assert (userProps
.empty());
622 static CString
delimiters (_T(" "));
624 // parse list of visible user-props
626 std::set
<CString
> visibles
;
629 CString name
= shownUserProps
.Tokenize (delimiters
, pos
);
630 while (!name
.IsEmpty())
632 visibles
.insert (name
);
633 name
= shownUserProps
.Tokenize (delimiters
, pos
);
636 // create list of all user-props
639 name
= userPropList
.Tokenize (delimiters
, pos
);
640 while (!name
.IsEmpty())
642 bool visible
= visibles
.find (name
) != visibles
.end();
645 newEntry
.name
= name
;
648 userProps
.push_back (newEntry
);
650 // auto-create columns for visible user-props
651 // (others may be added later)
655 ColumnInfo newColumn
;
657 newColumn
.visible
= true;
658 newColumn
.relevant
= true;
659 newColumn
.index
= static_cast<int>(userProps
.size())
660 + GITSLC_USERPROPCOLOFFSET
- 1;
662 columns
.push_back (newColumn
);
665 name
= userPropList
.Tokenize (delimiters
, pos
);
669 void ColumnManager::ParseWidths (const CString
& widths
)
671 for (int i
= 0, count
= widths
.GetLength() / 8; i
< count
; ++i
)
673 long width
= _tcstol (widths
.Mid (i
*8, 8), NULL
, 16);
674 if (i
< itemName
.size())
678 columns
[i
].width
= width
;
680 else if (i
>= GITSLC_USERPROPCOLOFFSET
)
682 // a user-prop column
684 size_t index
= static_cast<size_t>(i
- GITSLC_USERPROPCOLOFFSET
);
685 assert (index
< userProps
.size());
686 userProps
[index
].width
= width
;
688 for (size_t k
= 0, count
= columns
.size(); k
< count
; ++k
)
689 if (columns
[k
].index
== i
)
690 columns
[k
].width
= width
;
694 // there is no such column
701 void ColumnManager::SetStandardColumnVisibility
704 for (size_t i
= 0; i
< itemName
.size(); ++i
)
706 columns
[i
].visible
= (visibility
& 1) > 0;
711 void ColumnManager::ParseColumnOrder
712 (const CString
& widths
)
714 std::set
<int> alreadyPlaced
;
717 // place columns according to valid entries in orderString
719 int limit
= static_cast<int>(GITSLC_USERPROPCOLOFFSET
+ userProps
.size());
720 for (int i
= 0, count
= widths
.GetLength() / 2; i
< count
; ++i
)
722 int index
= _tcstol (widths
.Mid (i
*2, 2), NULL
, 16);
723 if ((index
< itemName
.size())
724 || ((index
>= GITSLC_USERPROPCOLOFFSET
) && (index
< limit
)))
726 alreadyPlaced
.insert (index
);
727 columnOrder
.push_back (index
);
731 // place the remaining colums behind it
733 for (int i
= 0; i
< itemName
.size(); ++i
)
734 if (alreadyPlaced
.find (i
) == alreadyPlaced
.end())
735 columnOrder
.push_back (i
);
737 for (int i
= GITSLC_USERPROPCOLOFFSET
; i
< limit
; ++i
)
738 if (alreadyPlaced
.find (i
) == alreadyPlaced
.end())
739 columnOrder
.push_back (i
);
742 // map internal column order onto visible column order
743 // (all invisibles in front)
745 std::vector
<int> ColumnManager::GetGridColumnOrder()
747 // extract order of used columns from order of all columns
749 std::vector
<int> result
;
750 result
.reserve (GITSLC_MAXCOLUMNCOUNT
+1);
752 size_t colCount
= columns
.size();
753 bool visible
= false;
757 // put invisible cols in front
759 for (size_t i
= 0, count
= columnOrder
.size(); i
< count
; ++i
)
761 int index
= columnOrder
[i
];
762 for (size_t k
= 0; k
< colCount
; ++k
)
764 const ColumnInfo
& column
= columns
[k
];
765 if ((column
.index
== index
) && (column
.visible
== visible
))
766 result
.push_back (static_cast<int>(k
));
777 void ColumnManager::ApplyColumnOrder()
779 // extract order of used columns from order of all columns
781 int order
[GITSLC_MAXCOLUMNCOUNT
+1];
782 SecureZeroMemory (order
, sizeof (order
));
784 std::vector
<int> gridColumnOrder
= GetGridColumnOrder();
785 std::copy (gridColumnOrder
.begin(), gridColumnOrder
.end(), stdext::checked_array_iterator
<int*>(&order
[0], sizeof(order
)));
787 // we must have placed all columns or something is really fishy ..
789 assert (gridColumnOrder
.size() == columns
.size());
790 assert (GetColumnCount() == ((CHeaderCtrl
*)(control
->GetDlgItem(0)))->GetItemCount());
792 // o.k., apply our column ordering
794 control
->SetColumnOrderArray (GetColumnCount(), order
);
797 // utilities used when writing data to the registry
799 DWORD
ColumnManager::GetSelectedStandardColumns() const
802 for (size_t i
= itemName
.size(); i
> 0; --i
)
803 result
= result
* 2 + (columns
[i
-1].visible
? 1 : 0);
808 CString
ColumnManager::GetUserPropList() const
812 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
813 result
+= userProps
[i
].name
+ _T(' ');
818 CString
ColumnManager::GetShownUserProps() const
822 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
824 size_t index
= static_cast<size_t>(columns
[i
].index
);
825 if (columns
[i
].visible
&& (index
>= GITSLC_USERPROPCOLOFFSET
))
826 result
+= userProps
[index
- GITSLC_USERPROPCOLOFFSET
].name
833 CString
ColumnManager::GetWidthString() const
840 for (size_t i
= 0; i
< itemName
.size(); ++i
)
842 _stprintf_s (buf
, 10, _T("%08X"), columns
[i
].width
);
846 // range with no column IDs
848 result
+= CString ('0', 8 * (GITSLC_USERPROPCOLOFFSET
- itemName
.size()));
852 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
854 _stprintf_s (buf
, 10, _T("%08X"), userProps
[i
].width
);
861 CString
ColumnManager::GetColumnOrderString() const
866 for (size_t i
= 0, count
= columnOrder
.size(); i
< count
; ++i
)
868 _stprintf_s (buf
, 3, _T("%02X"), columnOrder
[i
]);
875 // sorter utility class, only used by GitStatusList!
877 CSorter::CSorter ( ColumnManager
* columnManager
880 : columnManager (columnManager
)
881 , sortedColumn (sortedColumn
)
882 , ascending (ascending
)
886 bool CSorter::operator() (const CTGitPath
* entry1
, const CTGitPath
* entry2
) const
888 #define SGN(x) ((x)==0?0:((x)>0?1:-1))
891 switch (sortedColumn
)
897 // result = entry1->lock_comment.CompareNoCase(entry2->lock_comment);
898 result
= A2L(entry1
->m_StatDel
)-A2L(entry2
->m_StatDel
);
905 //result = entry1->lock_owner.CompareNoCase(entry2->lock_owner);
906 result
= A2L(entry1
->m_StatAdd
)-A2L(entry2
->m_StatAdd
);
914 result
= entry1
->GetActionName(entry1
->m_Action
).CompareNoCase(entry2
->GetActionName(entry2
->m_Action
));
921 result
= entry1
->GetFileExtension().CompareNoCase(entry2
->GetFileExtension());
928 result
= entry1
->GetFileOrDirectoryName().CompareNoCase(entry2
->GetFileOrDirectoryName());
931 case 0: // Full path column
935 result
= CTGitPath::Compare(entry1
->GetGitPathString(), entry2
->GetGitPathString());
939 if ((result
== 0) && (sortedColumn
> 0))
941 // N/A props are "less than" empty props
943 // const CString& propName = columnManager->GetName (sortedColumn);
945 // bool entry1HasProp = entry1->present_props.HasProperty (propName);
946 // bool entry2HasProp = entry2->present_props.HasProperty (propName);
948 // if (entry1HasProp)
950 // result = entry2HasProp
951 // ? entry1->present_props[propName].Compare
952 // (entry2->present_props[propName])
957 // result = entry2HasProp ? -1 : 0;
960 } // switch (m_nSortedColumn)