Fixed issue #440: Don't enable 'Apply' button until the data are ok in Settings/Git...
[TortoiseGit.git] / src / TortoiseProc / GitStatusListCtrlHelpers.cpp
blob15ef7adb1cd21e68ad6be7fa1b234b8d8c8affe8
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.
20 #include "stdafx.h"
21 #include ".\resource.h"
22 #include "GitStatusListCtrl.h"
23 #include <iterator>
24 // assign property list
25 #if 0
26 CGitStatusListCtrl::PropertyList&
27 CGitStatusListCtrl::PropertyList::operator= (const char* rhs)
29 // do you really want to replace the property list?
31 assert (properties.empty());
32 properties.clear();
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;
46 // done
48 return *this;
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()
56 ; iter != end
57 ; ++iter)
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()
70 ? CString()
71 : iter->second;
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);
96 #endif
97 // registry access
99 void CGitStatusListCtrl::ColumnManager::ReadSettings
100 ( DWORD defaultColumns
101 , const CString& containerName)
103 // defaults
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
120 registryPrefix
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;
127 if (valid)
129 // read (possibly different) column selection
131 selectedStandardColumns
132 = CRegDWORD (registryPrefix, selectedStandardColumns);
134 // read user-prop lists
136 CString userPropList
137 = CRegString (registryPrefix + _T("UserProps"));
138 CString shownUserProps
139 = CRegString (registryPrefix + _T("ShownUserProps"));
141 ParseUserPropSettings (userPropList, shownUserProps);
143 // read column widths
145 CString colWidths
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;
158 while (c>=0)
159 control->DeleteColumn(c--);
161 // create columns
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
168 if (valid)
169 ParseColumnOrder (CRegString (registryPrefix + _T("_Order")));
170 else
171 ParseColumnOrder (CString());
173 ApplyColumnOrder();
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)
179 if (IsVisible(i))
180 control->SetColumnWidth (i, GetVisibleWidth (i, true));
183 void CGitStatusListCtrl::ColumnManager::WriteSettings() const
185 // we are version 2
187 CRegDWORD regVersion (registryPrefix + _T("Version"), 0, TRUE);
188 regVersion = 2;
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)
234 if (!it->visible)
235 invisibleCount++;
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
288 // standard columns
290 size_t index = static_cast<size_t>(column);
291 if (index < SVNSLC_NUMCOLUMNS)
293 CString result;
294 result.LoadString (standardColumnNames[index]);
295 return result;
298 // user-prop columns
300 // if (index < columns.size())
301 // return userProps[columns[index].index - SVNSLC_USERPROPCOLOFFSET].name;
303 // default: empty
305 return CString();
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;
317 return width;
320 int CGitStatusListCtrl::ColumnManager::GetVisibleWidth (int column, bool useDefaults) const
322 return IsVisible (column)
323 ? GetWidth (column, useDefaults)
324 : 0;
327 // switch columns on and off
329 void CGitStatusListCtrl::ColumnManager::SetVisible
330 ( int column
331 , bool visible)
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;
340 if (!visible)
341 columns[index].width = 0;
343 control->SetColumnWidth (column, GetVisibleWidth (column, true));
344 ApplyColumnOrder();
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
370 ? -1
371 : gridColumnOrder[visiblePosition];
373 // move logical column index just in front of that "next" column
375 columnOrder.erase (std::find ( columnOrder.begin()
376 , columnOrder.end()
377 , index));
378 columnOrder.insert ( std::find ( columnOrder.begin()
379 , columnOrder.end()
380 , next)
381 , index);
383 // make sure, invisible columns are still put in front of all others
385 ApplyColumnOrder();
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)
406 #if 0
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()
431 ; iter != end
432 ; ++iter)
434 int index = static_cast<int>(userProps.size())
435 + SVNSLC_USERPROPCOLOFFSET;
436 columnOrder.push_back (index);
438 UserProp userProp;
439 userProp.name = *iter;
440 userProp.width = 0;
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()
467 ; iter != end
468 ; ++iter)
470 // get the logical column index / ID
472 int index = -1;
473 int width = 0;
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;
479 break;
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());
491 ColumnInfo column;
492 column.index = index;
493 column.width = width;
494 column.visible = false;
496 columns.insert (columnIter, column);
498 // update control
500 int result = control->InsertColumn (pos, *iter, LVCFMT_LEFT, GetVisibleWidth(pos, false));
501 assert (result != -1);
502 UNREFERENCED_PARAMETER(result);
505 // update column order
507 ApplyColumnOrder();
511 #endif
512 #if 0
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))
531 columns[i].relevant
532 = aggregatedProps.find (GetName(i)) != aggregatedProps.end();
536 #endif
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
561 ? index
562 : userPropID++;
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);
581 else
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);
605 else
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;
627 // update UI
629 for (int i = 0, count = GetColumnCount(); i < count; ++i)
630 control->SetColumnWidth (i, GetVisibleWidth (i, true));
632 ApplyColumnOrder();
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;
651 int pos = 0;
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
661 pos = 0;
662 name = userPropList.Tokenize (delimiters, pos);
663 while (!name.IsEmpty())
665 bool visible = visibles.find (name) != visibles.end();
667 UserProp newEntry;
668 newEntry.name = name;
669 newEntry.width = 0;
671 userProps.push_back (newEntry);
673 // auto-create columns for visible user-props
674 // (others may be added later)
676 if (visible)
678 ColumnInfo newColumn;
679 newColumn.width = 0;
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)
699 // a standard column
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;
715 else
717 // there is no such column
719 assert (width == 0);
724 void CGitStatusListCtrl::ColumnManager::SetStandardColumnVisibility
725 (DWORD visibility)
727 for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
729 columns[i].visible = (visibility & 1) > 0;
730 visibility /= 2;
734 void CGitStatusListCtrl::ColumnManager::ParseColumnOrder
735 (const CString& widths)
737 std::set<int> alreadyPlaced;
738 columnOrder.clear();
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));
793 visible = !visible;
795 while (visible);
797 return result;
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
824 DWORD result = 0;
825 for (size_t i = SVNSLC_NUMCOLUMNS; i > 0; --i)
826 result = result * 2 + (columns[i-1].visible ? 1 : 0);
828 return result;
831 CString CGitStatusListCtrl::ColumnManager::GetUserPropList() const
833 CString result;
835 for (size_t i = 0, count = userProps.size(); i < count; ++i)
836 result += userProps[i].name + _T(' ');
838 return result;
841 CString CGitStatusListCtrl::ColumnManager::GetShownUserProps() const
843 CString result;
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
850 + _T(' ');
853 return result;
856 CString CGitStatusListCtrl::ColumnManager::GetWidthString() const
858 CString result;
860 // regular columns
862 TCHAR buf[10];
863 for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
865 _stprintf_s (buf, 10, _T("%08X"), columns[i].width);
866 result += buf;
869 // range with no column IDs
871 result += CString ('0', 8 * (SVNSLC_USERPROPCOLOFFSET - SVNSLC_NUMCOLUMNS));
873 // user-prop columns
875 for (size_t i = 0, count = userProps.size(); i < count; ++i)
877 _stprintf_s (buf, 10, _T("%08X"), userProps[i].width);
878 result += buf;
881 return result;
884 CString CGitStatusListCtrl::ColumnManager::GetColumnOrderString() const
886 CString result;
888 TCHAR buf[3];
889 for (size_t i = 0, count = columnOrder.size(); i < count; ++i)
891 _stprintf_s (buf, 3, _T("%02X"), columnOrder[i]);
892 result += buf;
895 return result;
898 // sorter utility class
900 CGitStatusListCtrl::CSorter::CSorter ( ColumnManager* columnManager
901 , int sortedColumn
902 , bool ascending)
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))
915 int result = 0;
916 switch (sortedColumn)
918 case 18:
920 if (result == 0)
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);
931 case 17:
933 if (result == 0)
935 // result = entry1->copyfrom_url.CompareNoCase(entry2->copyfrom_url);
938 case 16:
940 if (result == 0)
942 // result = SGN(entry1->needslock - entry2->needslock);
945 case 15:
947 if (result == 0)
949 // result = SGN(entry1->last_commit_date - entry2->last_commit_date);
952 case 14:
954 if (result == 0)
956 // result = entry1->remoterev - entry2->remoterev;
959 case 13:
961 if (result == 0)
963 // result = entry1->last_commit_rev - entry2->last_commit_rev;
966 case 12:
968 if (result == 0)
970 // result = entry1->last_commit_author.CompareNoCase(entry2->last_commit_author);
973 case 11: //Del Number
975 if (result == 0)
977 // result = entry1->lock_comment.CompareNoCase(entry2->lock_comment);
978 result = A2L(entry1->m_StatDel)-A2L(entry2->m_StatDel);
981 case 10: //Add Number
983 if (result == 0)
985 //result = entry1->lock_owner.CompareNoCase(entry2->lock_owner);
986 result = A2L(entry1->m_StatAdd)-A2L(entry2->m_StatAdd);
989 case 9: //Modification Data
991 if (result == 0)
993 // result = entry1->url.CompareNoCase(entry2->url);
996 case 8: //Data
998 if (result == 0)
1000 // result = entry1->remotepropstatus - entry2->remotepropstatus;
1003 case 7: // Version
1005 if (result == 0)
1007 // result = entry1->remotetextstatus - entry2->remotetextstatus;
1010 case 6: // Author
1012 if (result == 0)
1014 // result = entry1->propstatus - entry2->propstatus;
1017 case 5: //Prop Status
1019 if (result == 0)
1021 // result = entry1->textstatus - entry2->textstatus;
1024 case 4: //Text Status
1026 if (result == 0)
1028 // result = entry1->remotestatus - entry2->remotestatus;
1031 case 3: // Status
1033 if (result == 0)
1035 result = entry1->GetActionName(entry1->m_Action).CompareNoCase(entry2->GetActionName(entry2->m_Action));
1038 case 2: //Ext file
1040 if (result == 0)
1042 result = entry1->GetFileExtension().CompareNoCase(entry2->GetFileExtension());
1045 case 1: // File name
1047 if (result == 0)
1049 result = entry1->GetFileOrDirectoryName().CompareNoCase(entry2->GetFileOrDirectoryName());
1052 case 0: // Full path column
1054 if (result == 0)
1056 result = CTGitPath::Compare(entry1->GetGitPathString(), entry2->GetGitPathString());
1059 default:
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)
1070 // {
1071 // result = entry2HasProp
1072 // ? entry1->present_props[propName].Compare
1073 // (entry2->present_props[propName])
1074 // : 1;
1075 // }
1076 // else
1077 // {
1078 // result = entry2HasProp ? -1 : 0;
1079 // }
1081 } // switch (m_nSortedColumn)
1082 if (!ascending)
1083 result = -result;
1085 return result < 0;