1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 #include ".\resource.h"
\r
22 #include "GitStatusListCtrl.h"
\r
24 // assign property list
\r
26 CGitStatusListCtrl::PropertyList&
\r
27 CGitStatusListCtrl::PropertyList::operator= (const char* rhs)
\r
29 // do you really want to replace the property list?
\r
31 assert (properties.empty());
\r
34 // add all properties in the list
\r
36 while ((rhs != NULL) && (*rhs != 0))
\r
38 const char* next = strchr (rhs, ' ');
\r
40 CString name (rhs, static_cast<int>(next == NULL ? strlen (rhs) : next - rhs));
\r
41 properties.insert (std::make_pair (name, CString()));
\r
43 rhs = next == NULL ? NULL : next+1;
\r
51 // collect property names in a set
\r
53 void CGitStatusListCtrl::PropertyList::GetPropertyNames (std::set<CString>& names)
\r
55 for ( CIT iter = properties.begin(), end = properties.end()
\r
59 names.insert (iter->first);
\r
63 // get a property value.
\r
65 CString CGitStatusListCtrl::PropertyList::operator[](const CString& name) const
\r
67 CIT iter = properties.find (name);
\r
69 return iter == properties.end()
\r
74 // set a property value.
\r
76 CString& CGitStatusListCtrl::PropertyList::operator[](const CString& name)
\r
78 return properties[name];
\r
81 /// check whether that property has been set on this item.
\r
83 bool CGitStatusListCtrl::PropertyList::HasProperty (const CString& name) const
\r
85 return properties.find (name) != properties.end();
\r
88 // due to frequent use: special check for svn:needs-lock
\r
90 bool CGitStatusListCtrl::PropertyList::IsNeedsLockSet() const
\r
92 static const CString svnNeedsLock = _T("svn:needs-lock");
\r
93 return HasProperty (svnNeedsLock);
\r
99 void CGitStatusListCtrl::ColumnManager::ReadSettings
\r
100 ( DWORD defaultColumns
\r
101 , const CString& containerName)
\r
105 DWORD selectedStandardColumns = defaultColumns;
\r
107 columns.resize (SVNSLC_NUMCOLUMNS);
\r
108 for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
\r
110 columns[i].index = static_cast<int>(i);
\r
111 columns[i].width = 0;
\r
112 columns[i].visible = true;
\r
113 columns[i].relevant = true;
\r
116 // userProps.clear();
\r
118 // where the settings are stored within the registry
\r
121 = _T("Software\\TortoiseGit\\StatusColumns\\") + containerName;
\r
123 // we accept settings version 2 only
\r
124 // (version 1 used different placement of hidden columns)
\r
126 bool valid = (DWORD)CRegDWORD (registryPrefix + _T("Version"), 0xff) == 2;
\r
129 // read (possibly different) column selection
\r
131 selectedStandardColumns
\r
132 = CRegDWORD (registryPrefix, selectedStandardColumns);
\r
134 // read user-prop lists
\r
136 CString userPropList
\r
137 = CRegString (registryPrefix + _T("UserProps"));
\r
138 CString shownUserProps
\r
139 = CRegString (registryPrefix + _T("ShownUserProps"));
\r
141 ParseUserPropSettings (userPropList, shownUserProps);
\r
143 // read column widths
\r
146 = CRegString (registryPrefix + _T("_Width"));
\r
148 ParseWidths (colWidths);
\r
151 // process old-style visibility setting
\r
153 SetStandardColumnVisibility (selectedStandardColumns);
\r
155 // clear all previously set header columns
\r
157 int c = ((CHeaderCtrl*)(control->GetDlgItem(0)))->GetItemCount()-1;
\r
159 control->DeleteColumn(c--);
\r
163 for (int i = 0, count = GetColumnCount(); i < count; ++i)
\r
164 control->InsertColumn (i, GetName(i), LVCFMT_LEFT, IsVisible(i) ? -1 : GetVisibleWidth(i, false));
\r
166 // restore column ordering
\r
169 ParseColumnOrder (CRegString (registryPrefix + _T("_Order")));
\r
171 ParseColumnOrder (CString());
\r
173 ApplyColumnOrder();
\r
175 // auto-size the columns so we can see them while fetching status
\r
176 // (seems the same values will not take affect in InsertColumn)
\r
178 for (int i = 0, count = GetColumnCount(); i < count; ++i)
\r
180 control->SetColumnWidth (i, GetVisibleWidth (i, true));
\r
183 void CGitStatusListCtrl::ColumnManager::WriteSettings() const
\r
185 // we are version 2
\r
187 CRegDWORD regVersion (registryPrefix + _T("Version"), 0, TRUE);
\r
190 // write (possibly different) column selection
\r
192 CRegDWORD regStandardColumns (registryPrefix, 0, TRUE);
\r
193 regStandardColumns = GetSelectedStandardColumns();
\r
195 // write user-prop lists
\r
197 CRegString regUserProps (registryPrefix + _T("UserProps"), CString(), TRUE);
\r
198 regUserProps = GetUserPropList();
\r
200 CRegString regShownUserProps (registryPrefix + _T("ShownUserProps"), CString(), TRUE);
\r
201 regShownUserProps = GetShownUserProps();
\r
203 // write column widths
\r
205 CRegString regWidths (registryPrefix + _T("_Width"), CString(), TRUE);
\r
206 regWidths = GetWidthString();
\r
208 // write column ordering
\r
210 CRegString regColumnOrder (registryPrefix + _T("_Order"), CString(), TRUE);
\r
211 regColumnOrder = GetColumnOrderString();
\r
214 // read column definitions
\r
216 int CGitStatusListCtrl::ColumnManager::GetColumnCount() const
\r
218 return static_cast<int>(columns.size());
\r
221 bool CGitStatusListCtrl::ColumnManager::IsVisible (int column) const
\r
223 size_t index = static_cast<size_t>(column);
\r
224 assert (columns.size() > index);
\r
226 return columns[index].visible;
\r
229 int CGitStatusListCtrl::ColumnManager::GetInvisibleCount() const
\r
231 int invisibleCount = 0;
\r
232 for (std::vector<ColumnInfo>::const_iterator it = columns.begin(); it != columns.end(); ++it)
\r
237 return invisibleCount;
\r
240 bool CGitStatusListCtrl::ColumnManager::IsRelevant (int column) const
\r
242 size_t index = static_cast<size_t>(column);
\r
243 assert (columns.size() > index);
\r
245 return columns[index].relevant;
\r
248 bool CGitStatusListCtrl::ColumnManager::IsUserProp (int column) const
\r
250 size_t index = static_cast<size_t>(column);
\r
251 assert (columns.size() > index);
\r
253 return columns[index].index >= SVNSLC_USERPROPCOLOFFSET;
\r
256 CString CGitStatusListCtrl::ColumnManager::GetName (int column) const
\r
258 static const UINT standardColumnNames[SVNSLC_NUMCOLUMNS]
\r
259 = { IDS_STATUSLIST_COLFILE
\r
261 , IDS_STATUSLIST_COLFILENAME
\r
262 , IDS_STATUSLIST_COLEXT
\r
263 , IDS_STATUSLIST_COLSTATUS
\r
265 // , IDS_STATUSLIST_COLREMOTESTATUS
\r
266 , IDS_STATUSLIST_COLTEXTSTATUS
\r
267 // , IDS_STATUSLIST_COLPROPSTATUS
\r
269 // , IDS_STATUSLIST_COLREMOTETEXTSTATUS
\r
270 // , IDS_STATUSLIST_COLREMOTEPROPSTATUS
\r
271 // , IDS_STATUSLIST_COLURL
\r
273 // , IDS_STATUSLIST_COLLOCK
\r
274 // , IDS_STATUSLIST_COLLOCKCOMMENT
\r
275 , IDS_STATUSLIST_COLAUTHOR
\r
277 , IDS_STATUSLIST_COLREVISION
\r
278 // , IDS_STATUSLIST_COLREMOTEREVISION
\r
279 , IDS_STATUSLIST_COLDATE
\r
280 // , IDS_STATUSLIST_COLSVNLOCK
\r
282 // , IDS_STATUSLIST_COLCOPYFROM
\r
283 , IDS_STATUSLIST_COLMODIFICATIONDATE
\r
286 // standard columns
\r
288 size_t index = static_cast<size_t>(column);
\r
289 if (index < SVNSLC_NUMCOLUMNS)
\r
292 result.LoadString (standardColumnNames[index]);
\r
296 // user-prop columns
\r
298 // if (index < columns.size())
\r
299 // return userProps[columns[index].index - SVNSLC_USERPROPCOLOFFSET].name;
\r
306 int CGitStatusListCtrl::ColumnManager::GetWidth (int column, bool useDefaults) const
\r
308 size_t index = static_cast<size_t>(column);
\r
309 assert (columns.size() > index);
\r
311 int width = columns[index].width;
\r
312 if ((width == 0) && useDefaults)
\r
313 width = LVSCW_AUTOSIZE_USEHEADER;
\r
318 int CGitStatusListCtrl::ColumnManager::GetVisibleWidth (int column, bool useDefaults) const
\r
320 return IsVisible (column)
\r
321 ? GetWidth (column, useDefaults)
\r
325 // switch columns on and off
\r
327 void CGitStatusListCtrl::ColumnManager::SetVisible
\r
331 size_t index = static_cast<size_t>(column);
\r
332 assert (index < columns.size());
\r
334 if (columns[index].visible != visible)
\r
336 columns[index].visible = visible;
\r
337 columns[index].relevant |= visible;
\r
339 columns[index].width = 0;
\r
341 control->SetColumnWidth (column, GetVisibleWidth (column, true));
\r
342 ApplyColumnOrder();
\r
344 control->Invalidate (FALSE);
\r
348 // tracking column modifications
\r
350 void CGitStatusListCtrl::ColumnManager::ColumnMoved (int column, int position)
\r
352 // in front of what column has it been inserted?
\r
354 int index = columns[column].index;
\r
356 std::vector<int> gridColumnOrder = GetGridColumnOrder();
\r
358 size_t visiblePosition = static_cast<size_t>(position);
\r
359 size_t columnCount = gridColumnOrder.size();
\r
361 for (; (visiblePosition < columnCount)
\r
362 && !columns[gridColumnOrder[visiblePosition]].visible
\r
363 ; ++visiblePosition )
\r
367 int next = visiblePosition == columnCount
\r
369 : gridColumnOrder[visiblePosition];
\r
371 // move logical column index just in front of that "next" column
\r
373 columnOrder.erase (std::find ( columnOrder.begin()
\r
374 , columnOrder.end()
\r
376 columnOrder.insert ( std::find ( columnOrder.begin()
\r
377 , columnOrder.end()
\r
381 // make sure, invisible columns are still put in front of all others
\r
383 ApplyColumnOrder();
\r
386 void CGitStatusListCtrl::ColumnManager::ColumnResized (int column)
\r
388 size_t index = static_cast<size_t>(column);
\r
389 assert (index < columns.size());
\r
390 assert (columns[index].visible);
\r
392 int width = control->GetColumnWidth (column);
\r
393 columns[index].width = width;
\r
395 int propertyIndex = columns[index].index;
\r
396 if (propertyIndex >= SVNSLC_USERPROPCOLOFFSET)
\r
397 userProps[propertyIndex - SVNSLC_USERPROPCOLOFFSET].width = width;
\r
399 control->Invalidate (FALSE);
\r
402 // call these to update the user-prop list
\r
403 // (will also auto-insert /-remove new list columns)
\r
405 void CGitStatusListCtrl::ColumnManager::UpdateUserPropList
\r
406 (const std::vector<FileEntry*>& files)
\r
408 // collect all user-defined props
\r
410 std::set<CString> aggregatedProps;
\r
411 for (size_t i = 0, count = files.size(); i < count; ++i)
\r
412 files[i]->present_props.GetPropertyNames (aggregatedProps);
\r
414 aggregatedProps.erase (_T("svn:needs-lock"));
\r
415 itemProps = aggregatedProps;
\r
417 // add new ones to the internal list
\r
419 std::set<CString> newProps = aggregatedProps;
\r
420 for (size_t i = 0, count = userProps.size(); i < count; ++i)
\r
421 newProps.erase (userProps[i].name);
\r
423 while ( newProps.size() + userProps.size()
\r
424 > SVNSLC_MAXCOLUMNCOUNT - SVNSLC_USERPROPCOLOFFSET)
\r
425 newProps.erase (--newProps.end());
\r
427 typedef std::set<CString>::const_iterator CIT;
\r
428 for ( CIT iter = newProps.begin(), end = newProps.end()
\r
432 int index = static_cast<int>(userProps.size())
\r
433 + SVNSLC_USERPROPCOLOFFSET;
\r
434 columnOrder.push_back (index);
\r
437 userProp.name = *iter;
\r
438 userProp.width = 0;
\r
440 userProps.push_back (userProp);
\r
443 // remove unused columns from control.
\r
444 // remove used ones from the set of aggregatedProps.
\r
446 for (size_t i = columns.size(); i > 0; --i)
\r
447 if ( (columns[i-1].index >= SVNSLC_USERPROPCOLOFFSET)
\r
448 && (aggregatedProps.erase (GetName ((int)i-1)) == 0))
\r
450 // this user-prop has not been set on any item
\r
452 if (!columns[i-1].visible)
\r
454 control->DeleteColumn (static_cast<int>(i-1));
\r
455 columns.erase (columns.begin() + i-1);
\r
459 // aggregatedProps now contains new columns only.
\r
460 // we can't use newProps here because some props may have been used
\r
461 // earlier but were not in the recent list of used props.
\r
462 // -> they are neither in columns[] nor in newProps.
\r
464 for ( CIT iter = aggregatedProps.begin(), end = aggregatedProps.end()
\r
468 // get the logical column index / ID
\r
472 for (size_t i = 0, count = userProps.size(); i < count; ++i)
\r
473 if (userProps[i].name == *iter)
\r
475 index = static_cast<int>(i) + SVNSLC_USERPROPCOLOFFSET;
\r
476 width = userProps[i].width;
\r
480 assert (index != -1);
\r
482 // find insertion position
\r
484 std::vector<ColumnInfo>::iterator columnIter = columns.begin();
\r
485 std::vector<ColumnInfo>::iterator end = columns.end();
\r
486 for (; (columnIter != end) && columnIter->index < index; ++columnIter);
\r
487 int pos = static_cast<int>(columnIter - columns.begin());
\r
490 column.index = index;
\r
491 column.width = width;
\r
492 column.visible = false;
\r
494 columns.insert (columnIter, column);
\r
498 int result = control->InsertColumn (pos, *iter, LVCFMT_LEFT, GetVisibleWidth(pos, false));
\r
499 assert (result != -1);
\r
500 UNREFERENCED_PARAMETER(result);
\r
503 // update column order
\r
505 ApplyColumnOrder();
\r
510 void CGitStatusListCtrl::ColumnManager::UpdateRelevance
\r
511 ( const std::vector<FileEntry*>& files
\r
512 , const std::vector<size_t>& visibleFiles)
\r
514 // collect all user-defined props that belong to shown files
\r
516 std::set<CString> aggregatedProps;
\r
517 for (size_t i = 0, count = visibleFiles.size(); i < count; ++i)
\r
518 files[visibleFiles[i]]->present_props.GetPropertyNames (aggregatedProps);
\r
520 aggregatedProps.erase (_T("svn:needs-lock"));
\r
521 itemProps = aggregatedProps;
\r
523 // invisible columns for unused props are not relevant
\r
525 for (int i = 0, count = GetColumnCount(); i < count; ++i)
\r
526 if (IsUserProp(i) && !IsVisible(i))
\r
528 columns[i].relevant
\r
529 = aggregatedProps.find (GetName(i)) != aggregatedProps.end();
\r
534 // don't clutter the context menu with irrelevant prop info
\r
536 bool CGitStatusListCtrl::ColumnManager::AnyUnusedProperties() const
\r
538 return columns.size() < userProps.size() + SVNSLC_NUMCOLUMNS;
\r
541 void CGitStatusListCtrl::ColumnManager::RemoveUnusedProps()
\r
543 // determine what column indexes / IDs to keep.
\r
544 // map them onto new IDs (we may delete some IDs in between)
\r
546 std::map<int, int> validIndices;
\r
547 int userPropID = SVNSLC_USERPROPCOLOFFSET;
\r
549 for (size_t i = 0, count = columns.size(); i < count; ++i)
\r
551 int index = columns[i].index;
\r
553 if ( itemProps.find (GetName((int)i)) != itemProps.end()
\r
554 || columns[i].visible
\r
555 || index < SVNSLC_USERPROPCOLOFFSET)
\r
557 validIndices[index] = index < SVNSLC_USERPROPCOLOFFSET
\r
563 // remove everything else:
\r
565 // remove from columns and control.
\r
566 // also update index values in columns
\r
568 for (size_t i = columns.size(); i > 0; --i)
\r
570 std::map<int, int>::const_iterator iter
\r
571 = validIndices.find (columns[i-1].index);
\r
573 if (iter == validIndices.end())
\r
575 control->DeleteColumn (static_cast<int>(i-1));
\r
576 columns.erase (columns.begin() + i-1);
\r
580 columns[i-1].index = iter->second;
\r
584 // remove from user props
\r
586 for (size_t i = userProps.size(); i > 0; --i)
\r
588 int index = static_cast<int>(i)-1 + SVNSLC_USERPROPCOLOFFSET;
\r
589 if (validIndices.find (index) == validIndices.end())
\r
590 userProps.erase (userProps.begin() + i-1);
\r
593 // remove from and update column order
\r
595 for (size_t i = columnOrder.size(); i > 0; --i)
\r
597 std::map<int, int>::const_iterator iter
\r
598 = validIndices.find (columnOrder[i-1]);
\r
600 if (iter == validIndices.end())
\r
601 columnOrder.erase (columnOrder.begin() + i-1);
\r
603 columnOrder[i-1] = iter->second;
\r
607 // bring everything back to its "natural" order
\r
609 void CGitStatusListCtrl::ColumnManager::ResetColumns (DWORD defaultColumns)
\r
611 // update internal data
\r
613 std::sort (columnOrder.begin(), columnOrder.end());
\r
615 for (size_t i = 0, count = columns.size(); i < count; ++i)
\r
617 columns[i].width = 0;
\r
618 columns[i].visible = (i < 32) && (((defaultColumns >> i) & 1) != 0);
\r
621 for (size_t i = 0, count = userProps.size(); i < count; ++i)
\r
622 userProps[i].width = 0;
\r
626 for (int i = 0, count = GetColumnCount(); i < count; ++i)
\r
627 control->SetColumnWidth (i, GetVisibleWidth (i, true));
\r
629 ApplyColumnOrder();
\r
631 control->Invalidate (FALSE);
\r
634 // initialization utilities
\r
636 void CGitStatusListCtrl::ColumnManager::ParseUserPropSettings
\r
637 ( const CString& userPropList
\r
638 , const CString& shownUserProps)
\r
640 assert (userProps.empty());
\r
642 static CString delimiters (_T(" "));
\r
644 // parse list of visible user-props
\r
646 std::set<CString> visibles;
\r
649 CString name = shownUserProps.Tokenize (delimiters, pos);
\r
650 while (!name.IsEmpty())
\r
652 visibles.insert (name);
\r
653 name = shownUserProps.Tokenize (delimiters, pos);
\r
656 // create list of all user-props
\r
659 name = userPropList.Tokenize (delimiters, pos);
\r
660 while (!name.IsEmpty())
\r
662 bool visible = visibles.find (name) != visibles.end();
\r
665 newEntry.name = name;
\r
666 newEntry.width = 0;
\r
668 userProps.push_back (newEntry);
\r
670 // auto-create columns for visible user-props
\r
671 // (others may be added later)
\r
675 ColumnInfo newColumn;
\r
676 newColumn.width = 0;
\r
677 newColumn.visible = true;
\r
678 newColumn.relevant = true;
\r
679 newColumn.index = static_cast<int>(userProps.size())
\r
680 + SVNSLC_USERPROPCOLOFFSET - 1;
\r
682 columns.push_back (newColumn);
\r
685 name = userPropList.Tokenize (delimiters, pos);
\r
689 void CGitStatusListCtrl::ColumnManager::ParseWidths (const CString& widths)
\r
691 for (int i = 0, count = widths.GetLength() / 8; i < count; ++i)
\r
693 long width = _tcstol (widths.Mid (i*8, 8), NULL, 16);
\r
694 if (i < SVNSLC_NUMCOLUMNS)
\r
696 // a standard column
\r
698 columns[i].width = width;
\r
700 else if (i >= SVNSLC_USERPROPCOLOFFSET)
\r
702 // a user-prop column
\r
704 size_t index = static_cast<size_t>(i - SVNSLC_USERPROPCOLOFFSET);
\r
705 assert (index < userProps.size());
\r
706 userProps[index].width = width;
\r
708 for (size_t k = 0, count = columns.size(); k < count; ++k)
\r
709 if (columns[k].index == i)
\r
710 columns[k].width = width;
\r
714 // there is no such column
\r
716 assert (width == 0);
\r
721 void CGitStatusListCtrl::ColumnManager::SetStandardColumnVisibility
\r
724 for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
\r
726 columns[i].visible = (visibility & 1) > 0;
\r
731 void CGitStatusListCtrl::ColumnManager::ParseColumnOrder
\r
732 (const CString& widths)
\r
734 std::set<int> alreadyPlaced;
\r
735 columnOrder.clear();
\r
737 // place columns according to valid entries in orderString
\r
739 int limit = static_cast<int>(SVNSLC_USERPROPCOLOFFSET + userProps.size());
\r
740 for (int i = 0, count = widths.GetLength() / 2; i < count; ++i)
\r
742 int index = _tcstol (widths.Mid (i*2, 2), NULL, 16);
\r
743 if ( (index < SVNSLC_NUMCOLUMNS)
\r
744 || ((index >= SVNSLC_USERPROPCOLOFFSET) && (index < limit)))
\r
746 alreadyPlaced.insert (index);
\r
747 columnOrder.push_back (index);
\r
751 // place the remaining colums behind it
\r
753 for (int i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
\r
754 if (alreadyPlaced.find (i) == alreadyPlaced.end())
\r
755 columnOrder.push_back (i);
\r
757 for (int i = SVNSLC_USERPROPCOLOFFSET; i < limit; ++i)
\r
758 if (alreadyPlaced.find (i) == alreadyPlaced.end())
\r
759 columnOrder.push_back (i);
\r
762 // map internal column order onto visible column order
\r
763 // (all invisibles in front)
\r
765 std::vector<int> CGitStatusListCtrl::ColumnManager::GetGridColumnOrder()
\r
767 // extract order of used columns from order of all columns
\r
769 std::vector<int> result;
\r
770 result.reserve (SVNSLC_MAXCOLUMNCOUNT+1);
\r
772 size_t colCount = columns.size();
\r
773 bool visible = false;
\r
777 // put invisible cols in front
\r
779 for (size_t i = 0, count = columnOrder.size(); i < count; ++i)
\r
781 int index = columnOrder[i];
\r
782 for (size_t k = 0; k < colCount; ++k)
\r
784 const ColumnInfo& column = columns[k];
\r
785 if ((column.index == index) && (column.visible == visible))
\r
786 result.push_back (static_cast<int>(k));
\r
790 visible = !visible;
\r
797 void CGitStatusListCtrl::ColumnManager::ApplyColumnOrder()
\r
799 // extract order of used columns from order of all columns
\r
801 int order[SVNSLC_MAXCOLUMNCOUNT+1];
\r
802 SecureZeroMemory (order, sizeof (order));
\r
804 std::vector<int> gridColumnOrder = GetGridColumnOrder();
\r
805 std::copy (gridColumnOrder.begin(), gridColumnOrder.end(), stdext::checked_array_iterator<int*>(&order[0], sizeof(order)));
\r
807 // we must have placed all columns or something is really fishy ..
\r
809 assert (gridColumnOrder.size() == columns.size());
\r
810 assert (GetColumnCount() == ((CHeaderCtrl*)(control->GetDlgItem(0)))->GetItemCount());
\r
812 // o.k., apply our column ordering
\r
814 control->SetColumnOrderArray (GetColumnCount(), order);
\r
817 // utilities used when writing data to the registry
\r
819 DWORD CGitStatusListCtrl::ColumnManager::GetSelectedStandardColumns() const
\r
822 for (size_t i = SVNSLC_NUMCOLUMNS; i > 0; --i)
\r
823 result = result * 2 + (columns[i-1].visible ? 1 : 0);
\r
828 CString CGitStatusListCtrl::ColumnManager::GetUserPropList() const
\r
832 for (size_t i = 0, count = userProps.size(); i < count; ++i)
\r
833 result += userProps[i].name + _T(' ');
\r
838 CString CGitStatusListCtrl::ColumnManager::GetShownUserProps() const
\r
842 for (size_t i = 0, count = columns.size(); i < count; ++i)
\r
844 size_t index = static_cast<size_t>(columns[i].index);
\r
845 if (columns[i].visible && (index >= SVNSLC_USERPROPCOLOFFSET))
\r
846 result += userProps[index - SVNSLC_USERPROPCOLOFFSET].name
\r
853 CString CGitStatusListCtrl::ColumnManager::GetWidthString() const
\r
860 for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)
\r
862 _stprintf_s (buf, 10, _T("%08X"), columns[i].width);
\r
866 // range with no column IDs
\r
868 result += CString ('0', 8 * (SVNSLC_USERPROPCOLOFFSET - SVNSLC_NUMCOLUMNS));
\r
870 // user-prop columns
\r
872 for (size_t i = 0, count = userProps.size(); i < count; ++i)
\r
874 _stprintf_s (buf, 10, _T("%08X"), userProps[i].width);
\r
881 CString CGitStatusListCtrl::ColumnManager::GetColumnOrderString() const
\r
886 for (size_t i = 0, count = columnOrder.size(); i < count; ++i)
\r
888 _stprintf_s (buf, 3, _T("%02X"), columnOrder[i]);
\r
895 // sorter utility class
\r
897 CGitStatusListCtrl::CSorter::CSorter ( ColumnManager* columnManager
\r
900 : columnManager (columnManager)
\r
901 , sortedColumn (sortedColumn)
\r
902 , ascending (ascending)
\r
906 bool CGitStatusListCtrl::CSorter::operator()
\r
907 ( const CTGitPath* entry1
\r
908 , const CTGitPath* entry2) const
\r
910 #define SGN(x) ((x)==0?0:((x)>0?1:-1))
\r
913 switch (sortedColumn)
\r
919 __int64 writetime1 = entry1->GetLastWriteTime();
\r
920 __int64 writetime2 = entry2->GetLastWriteTime();
\r
922 FILETIME* filetime1 = (FILETIME*)(__int64*)&writetime1;
\r
923 FILETIME* filetime2 = (FILETIME*)(__int64*)&writetime2;
\r
925 result = CompareFileTime(filetime1,filetime2);
\r
932 // result = entry1->copyfrom_url.CompareNoCase(entry2->copyfrom_url);
\r
939 // result = SGN(entry1->needslock - entry2->needslock);
\r
946 // result = SGN(entry1->last_commit_date - entry2->last_commit_date);
\r
953 // result = entry1->remoterev - entry2->remoterev;
\r
960 // result = entry1->last_commit_rev - entry2->last_commit_rev;
\r
967 // result = entry1->last_commit_author.CompareNoCase(entry2->last_commit_author);
\r
974 // result = entry1->lock_comment.CompareNoCase(entry2->lock_comment);
\r
981 // result = entry1->lock_owner.CompareNoCase(entry2->lock_owner);
\r
988 // result = entry1->url.CompareNoCase(entry2->url);
\r
995 // result = entry1->remotepropstatus - entry2->remotepropstatus;
\r
1002 // result = entry1->remotetextstatus - entry2->remotetextstatus;
\r
1009 // result = entry1->propstatus - entry2->propstatus;
\r
1016 // result = entry1->textstatus - entry2->textstatus;
\r
1023 // result = entry1->remotestatus - entry2->remotestatus;
\r
1030 // result = entry1->status - entry2->status;
\r
1037 result = entry1->GetFileExtension().CompareNoCase(entry2->GetFileExtension());
\r
1044 result = entry1->GetFileOrDirectoryName().CompareNoCase(entry2->GetFileOrDirectoryName());
\r
1047 case 0: // path column
\r
1051 result = CTGitPath::Compare(entry1->GetGitPathString(), entry2->GetGitPathString());
\r
1055 if ((result == 0) && (sortedColumn > 0))
\r
1057 // N/A props are "less than" empty props
\r
1059 const CString& propName = columnManager->GetName (sortedColumn);
\r
1061 // bool entry1HasProp = entry1->present_props.HasProperty (propName);
\r
1062 // bool entry2HasProp = entry2->present_props.HasProperty (propName);
\r
1064 // if (entry1HasProp)
\r
1066 // result = entry2HasProp
\r
1067 // ? entry1->present_props[propName].Compare
\r
1068 // (entry2->present_props[propName])
\r
1073 // result = entry2HasProp ? -1 : 0;
\r
1076 } // switch (m_nSortedColumn)
\r
1080 return result < 0;
\r