1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include ".\resource.h"
22 #include "GitStatusListCtrl.h"
24 // assign property list
26 CGitStatusListCtrl::PropertyList
&
27 CGitStatusListCtrl::PropertyList::operator= (const char* rhs
)
29 // do you really want to replace the property list?
31 assert (properties
.empty());
34 // add all properties in the list
36 while ((rhs
!= NULL
) && (*rhs
!= 0))
38 const char* next
= strchr (rhs
, ' ');
40 CString
name (rhs
, static_cast<int>(next
== NULL
? strlen (rhs
) : next
- rhs
));
41 properties
.insert (std::make_pair (name
, CString()));
43 rhs
= next
== NULL
? NULL
: next
+1;
51 // collect property names in a set
53 void CGitStatusListCtrl::PropertyList::GetPropertyNames (std::set
<CString
>& names
)
55 for ( CIT iter
= properties
.begin(), end
= properties
.end()
59 names
.insert (iter
->first
);
63 // get a property value.
65 CString
CGitStatusListCtrl::PropertyList::operator[](const CString
& name
) const
67 CIT iter
= properties
.find (name
);
69 return iter
== properties
.end()
74 // set a property value.
76 CString
& CGitStatusListCtrl::PropertyList::operator[](const CString
& name
)
78 return properties
[name
];
81 /// check whether that property has been set on this item.
83 bool CGitStatusListCtrl::PropertyList::HasProperty (const CString
& name
) const
85 return properties
.find (name
) != properties
.end();
88 // due to frequent use: special check for svn:needs-lock
90 bool CGitStatusListCtrl::PropertyList::IsNeedsLockSet() const
92 static const CString svnNeedsLock
= _T("svn:needs-lock");
93 return HasProperty (svnNeedsLock
);
99 void CGitStatusListCtrl::ColumnManager::ReadSettings
100 ( DWORD defaultColumns
101 , const CString
& containerName
)
105 DWORD selectedStandardColumns
= defaultColumns
;
107 columns
.resize (SVNSLC_NUMCOLUMNS
);
108 for (size_t i
= 0; i
< SVNSLC_NUMCOLUMNS
; ++i
)
110 columns
[i
].index
= static_cast<int>(i
);
111 columns
[i
].width
= 0;
112 columns
[i
].visible
= true;
113 columns
[i
].relevant
= true;
116 // userProps.clear();
118 // where the settings are stored within the registry
121 = _T("Software\\TortoiseGit\\StatusColumns\\") + containerName
;
123 // we accept settings version 2 only
124 // (version 1 used different placement of hidden columns)
126 bool valid
= (DWORD
)CRegDWORD (registryPrefix
+ _T("Version"), 0xff) == 2;
129 // read (possibly different) column selection
131 selectedStandardColumns
132 = CRegDWORD (registryPrefix
, selectedStandardColumns
);
134 // read user-prop lists
137 = CRegString (registryPrefix
+ _T("UserProps"));
138 CString shownUserProps
139 = CRegString (registryPrefix
+ _T("ShownUserProps"));
141 ParseUserPropSettings (userPropList
, shownUserProps
);
143 // read column widths
146 = CRegString (registryPrefix
+ _T("_Width"));
148 ParseWidths (colWidths
);
151 // process old-style visibility setting
153 SetStandardColumnVisibility (selectedStandardColumns
);
155 // clear all previously set header columns
157 int c
= ((CHeaderCtrl
*)(control
->GetDlgItem(0)))->GetItemCount()-1;
159 control
->DeleteColumn(c
--);
163 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
164 control
->InsertColumn (i
, GetName(i
), LVCFMT_LEFT
, IsVisible(i
) ? -1 : GetVisibleWidth(i
, false));
166 // restore column ordering
169 ParseColumnOrder (CRegString (registryPrefix
+ _T("_Order")));
171 ParseColumnOrder (CString());
175 // auto-size the columns so we can see them while fetching status
176 // (seems the same values will not take affect in InsertColumn)
178 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
180 control
->SetColumnWidth (i
, GetVisibleWidth (i
, true));
183 void CGitStatusListCtrl::ColumnManager::WriteSettings() const
187 CRegDWORD
regVersion (registryPrefix
+ _T("Version"), 0, TRUE
);
190 // write (possibly different) column selection
192 CRegDWORD
regStandardColumns (registryPrefix
, 0, TRUE
);
193 regStandardColumns
= GetSelectedStandardColumns();
195 // write user-prop lists
197 CRegString
regUserProps (registryPrefix
+ _T("UserProps"), CString(), TRUE
);
198 regUserProps
= GetUserPropList();
200 CRegString
regShownUserProps (registryPrefix
+ _T("ShownUserProps"), CString(), TRUE
);
201 regShownUserProps
= GetShownUserProps();
203 // write column widths
205 CRegString
regWidths (registryPrefix
+ _T("_Width"), CString(), TRUE
);
206 regWidths
= GetWidthString();
208 // write column ordering
210 CRegString
regColumnOrder (registryPrefix
+ _T("_Order"), CString(), TRUE
);
211 regColumnOrder
= GetColumnOrderString();
214 // read column definitions
216 int CGitStatusListCtrl::ColumnManager::GetColumnCount() const
218 return static_cast<int>(columns
.size());
221 bool CGitStatusListCtrl::ColumnManager::IsVisible (int column
) const
223 size_t index
= static_cast<size_t>(column
);
224 assert (columns
.size() > index
);
226 return columns
[index
].visible
;
229 int CGitStatusListCtrl::ColumnManager::GetInvisibleCount() const
231 int invisibleCount
= 0;
232 for (std::vector
<ColumnInfo
>::const_iterator it
= columns
.begin(); it
!= columns
.end(); ++it
)
237 return invisibleCount
;
240 bool CGitStatusListCtrl::ColumnManager::IsRelevant (int column
) const
242 size_t index
= static_cast<size_t>(column
);
243 assert (columns
.size() > index
);
245 return columns
[index
].relevant
;
248 bool CGitStatusListCtrl::ColumnManager::IsUserProp (int column
) const
250 size_t index
= static_cast<size_t>(column
);
251 assert (columns
.size() > index
);
253 return columns
[index
].index
>= SVNSLC_USERPROPCOLOFFSET
;
256 CString
CGitStatusListCtrl::ColumnManager::GetName (int column
) const
258 static const UINT standardColumnNames
[SVNSLC_NUMCOLUMNS
]
259 = { IDS_STATUSLIST_COLFILE
261 , IDS_STATUSLIST_COLFILENAME
262 , IDS_STATUSLIST_COLEXT
263 , IDS_STATUSLIST_COLSTATUS
265 // , IDS_STATUSLIST_COLREMOTESTATUS
266 , IDS_STATUSLIST_COLTEXTSTATUS
267 , IDS_STATUSLIST_COLPROPSTATUS
269 // , IDS_STATUSLIST_COLREMOTETEXTSTATUS
270 // , IDS_STATUSLIST_COLREMOTEPROPSTATUS
271 // , IDS_STATUSLIST_COLURL
273 // , IDS_STATUSLIST_COLLOCK
274 // , IDS_STATUSLIST_COLLOCKCOMMENT
275 , IDS_STATUSLIST_COLAUTHOR
277 , IDS_STATUSLIST_COLREVISION
278 // , IDS_STATUSLIST_COLREMOTEREVISION
279 , IDS_STATUSLIST_COLDATE
280 // , IDS_STATUSLIST_COLSVNLOCK
282 // , IDS_STATUSLIST_COLCOPYFROM
283 , IDS_STATUSLIST_COLMODIFICATIONDATE
284 , IDS_STATUSLIST_COLADD
285 , IDS_STATUSLIST_COLDEL
290 size_t index
= static_cast<size_t>(column
);
291 if (index
< SVNSLC_NUMCOLUMNS
)
294 result
.LoadString (standardColumnNames
[index
]);
300 // if (index < columns.size())
301 // return userProps[columns[index].index - SVNSLC_USERPROPCOLOFFSET].name;
308 int CGitStatusListCtrl::ColumnManager::GetWidth (int column
, bool useDefaults
) const
310 size_t index
= static_cast<size_t>(column
);
311 assert (columns
.size() > index
);
313 int width
= columns
[index
].width
;
314 if ((width
== 0) && useDefaults
)
315 width
= LVSCW_AUTOSIZE_USEHEADER
;
320 int CGitStatusListCtrl::ColumnManager::GetVisibleWidth (int column
, bool useDefaults
) const
322 return IsVisible (column
)
323 ? GetWidth (column
, useDefaults
)
327 // switch columns on and off
329 void CGitStatusListCtrl::ColumnManager::SetVisible
333 size_t index
= static_cast<size_t>(column
);
334 assert (index
< columns
.size());
336 if (columns
[index
].visible
!= visible
)
338 columns
[index
].visible
= visible
;
339 columns
[index
].relevant
|= visible
;
341 columns
[index
].width
= 0;
343 control
->SetColumnWidth (column
, GetVisibleWidth (column
, true));
346 control
->Invalidate (FALSE
);
350 // tracking column modifications
352 void CGitStatusListCtrl::ColumnManager::ColumnMoved (int column
, int position
)
354 // in front of what column has it been inserted?
356 int index
= columns
[column
].index
;
358 std::vector
<int> gridColumnOrder
= GetGridColumnOrder();
360 size_t visiblePosition
= static_cast<size_t>(position
);
361 size_t columnCount
= gridColumnOrder
.size();
363 for (; (visiblePosition
< columnCount
)
364 && !columns
[gridColumnOrder
[visiblePosition
]].visible
365 ; ++visiblePosition
)
369 int next
= visiblePosition
== columnCount
371 : gridColumnOrder
[visiblePosition
];
373 // move logical column index just in front of that "next" column
375 columnOrder
.erase (std::find ( columnOrder
.begin()
378 columnOrder
.insert ( std::find ( columnOrder
.begin()
383 // make sure, invisible columns are still put in front of all others
388 void CGitStatusListCtrl::ColumnManager::ColumnResized (int column
)
390 size_t index
= static_cast<size_t>(column
);
391 assert (index
< columns
.size());
392 assert (columns
[index
].visible
);
394 int width
= control
->GetColumnWidth (column
);
395 columns
[index
].width
= width
;
397 int propertyIndex
= columns
[index
].index
;
398 if (propertyIndex
>= SVNSLC_USERPROPCOLOFFSET
)
399 userProps
[propertyIndex
- SVNSLC_USERPROPCOLOFFSET
].width
= width
;
401 control
->Invalidate (FALSE
);
404 // call these to update the user-prop list
405 // (will also auto-insert /-remove new list columns)
407 void CGitStatusListCtrl::ColumnManager::UpdateUserPropList
408 (const std::vector
<FileEntry
*>& files
)
410 // collect all user-defined props
412 std::set
<CString
> aggregatedProps
;
413 for (size_t i
= 0, count
= files
.size(); i
< count
; ++i
)
414 files
[i
]->present_props
.GetPropertyNames (aggregatedProps
);
416 aggregatedProps
.erase (_T("svn:needs-lock"));
417 itemProps
= aggregatedProps
;
419 // add new ones to the internal list
421 std::set
<CString
> newProps
= aggregatedProps
;
422 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
423 newProps
.erase (userProps
[i
].name
);
425 while ( newProps
.size() + userProps
.size()
426 > SVNSLC_MAXCOLUMNCOUNT
- SVNSLC_USERPROPCOLOFFSET
)
427 newProps
.erase (--newProps
.end());
429 typedef std::set
<CString
>::const_iterator CIT
;
430 for ( CIT iter
= newProps
.begin(), end
= newProps
.end()
434 int index
= static_cast<int>(userProps
.size())
435 + SVNSLC_USERPROPCOLOFFSET
;
436 columnOrder
.push_back (index
);
439 userProp
.name
= *iter
;
442 userProps
.push_back (userProp
);
445 // remove unused columns from control.
446 // remove used ones from the set of aggregatedProps.
448 for (size_t i
= columns
.size(); i
> 0; --i
)
449 if ( (columns
[i
-1].index
>= SVNSLC_USERPROPCOLOFFSET
)
450 && (aggregatedProps
.erase (GetName ((int)i
-1)) == 0))
452 // this user-prop has not been set on any item
454 if (!columns
[i
-1].visible
)
456 control
->DeleteColumn (static_cast<int>(i
-1));
457 columns
.erase (columns
.begin() + i
-1);
461 // aggregatedProps now contains new columns only.
462 // we can't use newProps here because some props may have been used
463 // earlier but were not in the recent list of used props.
464 // -> they are neither in columns[] nor in newProps.
466 for ( CIT iter
= aggregatedProps
.begin(), end
= aggregatedProps
.end()
470 // get the logical column index / ID
474 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
475 if (userProps
[i
].name
== *iter
)
477 index
= static_cast<int>(i
) + SVNSLC_USERPROPCOLOFFSET
;
478 width
= userProps
[i
].width
;
482 assert (index
!= -1);
484 // find insertion position
486 std::vector
<ColumnInfo
>::iterator columnIter
= columns
.begin();
487 std::vector
<ColumnInfo
>::iterator end
= columns
.end();
488 for (; (columnIter
!= end
) && columnIter
->index
< index
; ++columnIter
);
489 int pos
= static_cast<int>(columnIter
- columns
.begin());
492 column
.index
= index
;
493 column
.width
= width
;
494 column
.visible
= false;
496 columns
.insert (columnIter
, column
);
500 int result
= control
->InsertColumn (pos
, *iter
, LVCFMT_LEFT
, GetVisibleWidth(pos
, false));
501 assert (result
!= -1);
502 UNREFERENCED_PARAMETER(result
);
505 // update column order
513 void CGitStatusListCtrl::ColumnManager::UpdateRelevance
514 ( const std::vector
<FileEntry
*>& files
515 , const std::vector
<size_t>& visibleFiles
)
517 // collect all user-defined props that belong to shown files
519 std::set
<CString
> aggregatedProps
;
520 for (size_t i
= 0, count
= visibleFiles
.size(); i
< count
; ++i
)
521 files
[visibleFiles
[i
]]->present_props
.GetPropertyNames (aggregatedProps
);
523 aggregatedProps
.erase (_T("svn:needs-lock"));
524 itemProps
= aggregatedProps
;
526 // invisible columns for unused props are not relevant
528 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
529 if (IsUserProp(i
) && !IsVisible(i
))
532 = aggregatedProps
.find (GetName(i
)) != aggregatedProps
.end();
537 // don't clutter the context menu with irrelevant prop info
539 bool CGitStatusListCtrl::ColumnManager::AnyUnusedProperties() const
541 return columns
.size() < userProps
.size() + SVNSLC_NUMCOLUMNS
;
544 void CGitStatusListCtrl::ColumnManager::RemoveUnusedProps()
546 // determine what column indexes / IDs to keep.
547 // map them onto new IDs (we may delete some IDs in between)
549 std::map
<int, int> validIndices
;
550 int userPropID
= SVNSLC_USERPROPCOLOFFSET
;
552 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
554 int index
= columns
[i
].index
;
556 if ( itemProps
.find (GetName((int)i
)) != itemProps
.end()
557 || columns
[i
].visible
558 || index
< SVNSLC_USERPROPCOLOFFSET
)
560 validIndices
[index
] = index
< SVNSLC_USERPROPCOLOFFSET
566 // remove everything else:
568 // remove from columns and control.
569 // also update index values in columns
571 for (size_t i
= columns
.size(); i
> 0; --i
)
573 std::map
<int, int>::const_iterator iter
574 = validIndices
.find (columns
[i
-1].index
);
576 if (iter
== validIndices
.end())
578 control
->DeleteColumn (static_cast<int>(i
-1));
579 columns
.erase (columns
.begin() + i
-1);
583 columns
[i
-1].index
= iter
->second
;
587 // remove from user props
589 for (size_t i
= userProps
.size(); i
> 0; --i
)
591 int index
= static_cast<int>(i
)-1 + SVNSLC_USERPROPCOLOFFSET
;
592 if (validIndices
.find (index
) == validIndices
.end())
593 userProps
.erase (userProps
.begin() + i
-1);
596 // remove from and update column order
598 for (size_t i
= columnOrder
.size(); i
> 0; --i
)
600 std::map
<int, int>::const_iterator iter
601 = validIndices
.find (columnOrder
[i
-1]);
603 if (iter
== validIndices
.end())
604 columnOrder
.erase (columnOrder
.begin() + i
-1);
606 columnOrder
[i
-1] = iter
->second
;
610 // bring everything back to its "natural" order
612 void CGitStatusListCtrl::ColumnManager::ResetColumns (DWORD defaultColumns
)
614 // update internal data
616 std::sort (columnOrder
.begin(), columnOrder
.end());
618 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
620 columns
[i
].width
= 0;
621 columns
[i
].visible
= (i
< 32) && (((defaultColumns
>> i
) & 1) != 0);
624 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
625 userProps
[i
].width
= 0;
629 for (int i
= 0, count
= GetColumnCount(); i
< count
; ++i
)
630 control
->SetColumnWidth (i
, GetVisibleWidth (i
, true));
634 control
->Invalidate (FALSE
);
637 // initialization utilities
639 void CGitStatusListCtrl::ColumnManager::ParseUserPropSettings
640 ( const CString
& userPropList
641 , const CString
& shownUserProps
)
643 assert (userProps
.empty());
645 static CString
delimiters (_T(" "));
647 // parse list of visible user-props
649 std::set
<CString
> visibles
;
652 CString name
= shownUserProps
.Tokenize (delimiters
, pos
);
653 while (!name
.IsEmpty())
655 visibles
.insert (name
);
656 name
= shownUserProps
.Tokenize (delimiters
, pos
);
659 // create list of all user-props
662 name
= userPropList
.Tokenize (delimiters
, pos
);
663 while (!name
.IsEmpty())
665 bool visible
= visibles
.find (name
) != visibles
.end();
668 newEntry
.name
= name
;
671 userProps
.push_back (newEntry
);
673 // auto-create columns for visible user-props
674 // (others may be added later)
678 ColumnInfo newColumn
;
680 newColumn
.visible
= true;
681 newColumn
.relevant
= true;
682 newColumn
.index
= static_cast<int>(userProps
.size())
683 + SVNSLC_USERPROPCOLOFFSET
- 1;
685 columns
.push_back (newColumn
);
688 name
= userPropList
.Tokenize (delimiters
, pos
);
692 void CGitStatusListCtrl::ColumnManager::ParseWidths (const CString
& widths
)
694 for (int i
= 0, count
= widths
.GetLength() / 8; i
< count
; ++i
)
696 long width
= _tcstol (widths
.Mid (i
*8, 8), NULL
, 16);
697 if (i
< SVNSLC_NUMCOLUMNS
)
701 columns
[i
].width
= width
;
703 else if (i
>= SVNSLC_USERPROPCOLOFFSET
)
705 // a user-prop column
707 size_t index
= static_cast<size_t>(i
- SVNSLC_USERPROPCOLOFFSET
);
708 assert (index
< userProps
.size());
709 userProps
[index
].width
= width
;
711 for (size_t k
= 0, count
= columns
.size(); k
< count
; ++k
)
712 if (columns
[k
].index
== i
)
713 columns
[k
].width
= width
;
717 // there is no such column
724 void CGitStatusListCtrl::ColumnManager::SetStandardColumnVisibility
727 for (size_t i
= 0; i
< SVNSLC_NUMCOLUMNS
; ++i
)
729 columns
[i
].visible
= (visibility
& 1) > 0;
734 void CGitStatusListCtrl::ColumnManager::ParseColumnOrder
735 (const CString
& widths
)
737 std::set
<int> alreadyPlaced
;
740 // place columns according to valid entries in orderString
742 int limit
= static_cast<int>(SVNSLC_USERPROPCOLOFFSET
+ userProps
.size());
743 for (int i
= 0, count
= widths
.GetLength() / 2; i
< count
; ++i
)
745 int index
= _tcstol (widths
.Mid (i
*2, 2), NULL
, 16);
746 if ( (index
< SVNSLC_NUMCOLUMNS
)
747 || ((index
>= SVNSLC_USERPROPCOLOFFSET
) && (index
< limit
)))
749 alreadyPlaced
.insert (index
);
750 columnOrder
.push_back (index
);
754 // place the remaining colums behind it
756 for (int i
= 0; i
< SVNSLC_NUMCOLUMNS
; ++i
)
757 if (alreadyPlaced
.find (i
) == alreadyPlaced
.end())
758 columnOrder
.push_back (i
);
760 for (int i
= SVNSLC_USERPROPCOLOFFSET
; i
< limit
; ++i
)
761 if (alreadyPlaced
.find (i
) == alreadyPlaced
.end())
762 columnOrder
.push_back (i
);
765 // map internal column order onto visible column order
766 // (all invisibles in front)
768 std::vector
<int> CGitStatusListCtrl::ColumnManager::GetGridColumnOrder()
770 // extract order of used columns from order of all columns
772 std::vector
<int> result
;
773 result
.reserve (SVNSLC_MAXCOLUMNCOUNT
+1);
775 size_t colCount
= columns
.size();
776 bool visible
= false;
780 // put invisible cols in front
782 for (size_t i
= 0, count
= columnOrder
.size(); i
< count
; ++i
)
784 int index
= columnOrder
[i
];
785 for (size_t k
= 0; k
< colCount
; ++k
)
787 const ColumnInfo
& column
= columns
[k
];
788 if ((column
.index
== index
) && (column
.visible
== visible
))
789 result
.push_back (static_cast<int>(k
));
800 void CGitStatusListCtrl::ColumnManager::ApplyColumnOrder()
802 // extract order of used columns from order of all columns
804 int order
[SVNSLC_MAXCOLUMNCOUNT
+1];
805 SecureZeroMemory (order
, sizeof (order
));
807 std::vector
<int> gridColumnOrder
= GetGridColumnOrder();
808 std::copy (gridColumnOrder
.begin(), gridColumnOrder
.end(), stdext::checked_array_iterator
<int*>(&order
[0], sizeof(order
)));
810 // we must have placed all columns or something is really fishy ..
812 assert (gridColumnOrder
.size() == columns
.size());
813 assert (GetColumnCount() == ((CHeaderCtrl
*)(control
->GetDlgItem(0)))->GetItemCount());
815 // o.k., apply our column ordering
817 control
->SetColumnOrderArray (GetColumnCount(), order
);
820 // utilities used when writing data to the registry
822 DWORD
CGitStatusListCtrl::ColumnManager::GetSelectedStandardColumns() const
825 for (size_t i
= SVNSLC_NUMCOLUMNS
; i
> 0; --i
)
826 result
= result
* 2 + (columns
[i
-1].visible
? 1 : 0);
831 CString
CGitStatusListCtrl::ColumnManager::GetUserPropList() const
835 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
836 result
+= userProps
[i
].name
+ _T(' ');
841 CString
CGitStatusListCtrl::ColumnManager::GetShownUserProps() const
845 for (size_t i
= 0, count
= columns
.size(); i
< count
; ++i
)
847 size_t index
= static_cast<size_t>(columns
[i
].index
);
848 if (columns
[i
].visible
&& (index
>= SVNSLC_USERPROPCOLOFFSET
))
849 result
+= userProps
[index
- SVNSLC_USERPROPCOLOFFSET
].name
856 CString
CGitStatusListCtrl::ColumnManager::GetWidthString() const
863 for (size_t i
= 0; i
< SVNSLC_NUMCOLUMNS
; ++i
)
865 _stprintf_s (buf
, 10, _T("%08X"), columns
[i
].width
);
869 // range with no column IDs
871 result
+= CString ('0', 8 * (SVNSLC_USERPROPCOLOFFSET
- SVNSLC_NUMCOLUMNS
));
875 for (size_t i
= 0, count
= userProps
.size(); i
< count
; ++i
)
877 _stprintf_s (buf
, 10, _T("%08X"), userProps
[i
].width
);
884 CString
CGitStatusListCtrl::ColumnManager::GetColumnOrderString() const
889 for (size_t i
= 0, count
= columnOrder
.size(); i
< count
; ++i
)
891 _stprintf_s (buf
, 3, _T("%02X"), columnOrder
[i
]);
898 // sorter utility class
900 CGitStatusListCtrl::CSorter::CSorter ( ColumnManager
* columnManager
903 : columnManager (columnManager
)
904 , sortedColumn (sortedColumn
)
905 , ascending (ascending
)
909 bool CGitStatusListCtrl::CSorter::operator()
910 ( const CTGitPath
* entry1
911 , const CTGitPath
* entry2
) const
913 #define SGN(x) ((x)==0?0:((x)>0?1:-1))
916 switch (sortedColumn
)
922 __int64 writetime1
= entry1
->GetLastWriteTime();
923 __int64 writetime2
= entry2
->GetLastWriteTime();
925 FILETIME
* filetime1
= (FILETIME
*)(__int64
*)&writetime1
;
926 FILETIME
* filetime2
= (FILETIME
*)(__int64
*)&writetime2
;
928 result
= CompareFileTime(filetime1
,filetime2
);
935 // result = entry1->copyfrom_url.CompareNoCase(entry2->copyfrom_url);
942 // result = SGN(entry1->needslock - entry2->needslock);
949 // result = SGN(entry1->last_commit_date - entry2->last_commit_date);
956 // result = entry1->remoterev - entry2->remoterev;
963 // result = entry1->last_commit_rev - entry2->last_commit_rev;
970 // result = entry1->last_commit_author.CompareNoCase(entry2->last_commit_author);
973 case 11: //Del Number
977 // result = entry1->lock_comment.CompareNoCase(entry2->lock_comment);
978 result
= A2L(entry1
->m_StatDel
)-A2L(entry2
->m_StatDel
);
981 case 10: //Add Number
985 //result = entry1->lock_owner.CompareNoCase(entry2->lock_owner);
986 result
= A2L(entry1
->m_StatAdd
)-A2L(entry2
->m_StatAdd
);
989 case 9: //Modification Data
993 // result = entry1->url.CompareNoCase(entry2->url);
1000 // result = entry1->remotepropstatus - entry2->remotepropstatus;
1007 // result = entry1->remotetextstatus - entry2->remotetextstatus;
1014 // result = entry1->propstatus - entry2->propstatus;
1017 case 5: //Prop Status
1021 // result = entry1->textstatus - entry2->textstatus;
1024 case 4: //Text Status
1028 // result = entry1->remotestatus - entry2->remotestatus;
1035 result
= entry1
->GetActionName(entry1
->m_Action
).CompareNoCase(entry2
->GetActionName(entry2
->m_Action
));
1042 result
= entry1
->GetFileExtension().CompareNoCase(entry2
->GetFileExtension());
1045 case 1: // File name
1049 result
= entry1
->GetFileOrDirectoryName().CompareNoCase(entry2
->GetFileOrDirectoryName());
1052 case 0: // Full path column
1056 result
= CTGitPath::Compare(entry1
->GetGitPathString(), entry2
->GetGitPathString());
1060 if ((result
== 0) && (sortedColumn
> 0))
1062 // N/A props are "less than" empty props
1064 const CString
& propName
= columnManager
->GetName (sortedColumn
);
1066 // bool entry1HasProp = entry1->present_props.HasProperty (propName);
1067 // bool entry2HasProp = entry2->present_props.HasProperty (propName);
1069 // if (entry1HasProp)
1071 // result = entry2HasProp
1072 // ? entry1->present_props[propName].Compare
1073 // (entry2->present_props[propName])
1078 // result = entry2HasProp ? -1 : 0;
1081 } // switch (m_nSortedColumn)