OSDN Git Service

Add rename delete revert repostatus command
[tortoisegit/TortoiseGitJp.git] / src / Git / GitStatusListCtrl.cpp
1 \r
2 \r
3 // TortoiseSVN - a Windows shell extension for easy version control\r
4 \r
5 // Copyright (C) 2003-2008 - TortoiseSVN\r
6 \r
7 // This program is free software; you can redistribute it and/or\r
8 // modify it under the terms of the GNU General Public License\r
9 // as published by the Free Software Foundation; either version 2\r
10 // of the License, or (at your option) any later version.\r
11 \r
12 // This program is distributed in the hope that it will be useful,\r
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 // GNU General Public License for more details.\r
16 \r
17 // You should have received a copy of the GNU General Public License\r
18 // along with this program; if not, write to the Free Software Foundation,\r
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
20 //\r
21 \r
22 #include "StdAfx.h"\r
23 #include "GitStatusListCtrl.h"\r
24 #include "resource.h"\r
25 #include "..\\TortoiseShell\resource.h"\r
26 #include "MessageBox.h"\r
27 #include "MyMemDC.h"\r
28 #include "UnicodeUtils.h"\r
29 #include "AppUtils.h"\r
30 #include "PathUtils.h"\r
31 #include "TempFile.h"\r
32 #include "StringUtils.h"\r
33 #include "DirFileEnum.h"\r
34 #include "GitConfig.h"\r
35 //#include "SVNProperties.h"\r
36 #include "Git.h"\r
37 #include "GitDiff.h"\r
38 //#include "LogDlg.h"\r
39 //#include "SVNProgressDlg.h"\r
40 #include "SysImageList.h"\r
41 //#include "Svnstatuslistctrl.h"\r
42 #include "TGitPath.h"\r
43 #include "Registry.h"\r
44 #include "GitStatus.h"\r
45 //#include "SVNHelpers.h"\r
46 #include "InputDlg.h"\r
47 #include "ShellUpdater.h"\r
48 #include "GitAdminDir.h"\r
49 //#include "DropFiles.h"\r
50 #include "IconMenu.h"\r
51 //#include "AddDlg.h"\r
52 //#include "EditPropertiesDlg.h"\r
53 //#include "CreateChangelistDlg.h"\r
54 #include "XPTheme.h"\r
55 \r
56 const UINT CGitStatusListCtrl::SVNSLNM_ITEMCOUNTCHANGED\r
57                                         = ::RegisterWindowMessage(_T("GITSLNM_ITEMCOUNTCHANGED"));\r
58 const UINT CGitStatusListCtrl::SVNSLNM_NEEDSREFRESH\r
59                                         = ::RegisterWindowMessage(_T("GITSLNM_NEEDSREFRESH"));\r
60 const UINT CGitStatusListCtrl::SVNSLNM_ADDFILE\r
61                                         = ::RegisterWindowMessage(_T("GITSLNM_ADDFILE"));\r
62 const UINT CGitStatusListCtrl::SVNSLNM_CHECKCHANGED\r
63                                         = ::RegisterWindowMessage(_T("GITSLNM_CHECKCHANGED"));\r
64 \r
65 #define IDSVNLC_REVERT                   1\r
66 #define IDSVNLC_COMPARE                  2\r
67 #define IDSVNLC_OPEN                     3\r
68 #define IDSVNLC_DELETE                   4\r
69 #define IDSVNLC_IGNORE                   5\r
70 #define IDSVNLC_GNUDIFF1                 6\r
71 #define IDSVNLC_UPDATE           7\r
72 #define IDSVNLC_LOG              8\r
73 #define IDSVNLC_EDITCONFLICT     9\r
74 #define IDSVNLC_IGNOREMASK          10\r
75 #define IDSVNLC_ADD                         11\r
76 #define IDSVNLC_RESOLVECONFLICT 12\r
77 #define IDSVNLC_LOCK                    13\r
78 #define IDSVNLC_LOCKFORCE               14\r
79 #define IDSVNLC_UNLOCK                  15\r
80 #define IDSVNLC_UNLOCKFORCE             16\r
81 #define IDSVNLC_OPENWITH                17\r
82 #define IDSVNLC_EXPLORE                 18\r
83 #define IDSVNLC_RESOLVETHEIRS   19\r
84 #define IDSVNLC_RESOLVEMINE             20\r
85 #define IDSVNLC_REMOVE                  21\r
86 #define IDSVNLC_COMMIT                  22\r
87 #define IDSVNLC_PROPERTIES              23\r
88 #define IDSVNLC_COPY                    24\r
89 #define IDSVNLC_COPYEXT                 25\r
90 #define IDSVNLC_REPAIRMOVE              26\r
91 #define IDSVNLC_REMOVEFROMCS    27\r
92 #define IDSVNLC_CREATECS                28\r
93 #define IDSVNLC_CREATEIGNORECS  29\r
94 #define IDSVNLC_CHECKGROUP              30\r
95 #define IDSVNLC_UNCHECKGROUP    31\r
96 #define IDSVNLC_ADD_RECURSIVE   32\r
97 #define IDSVNLC_COMPAREWC               33\r
98 #define IDSVNLC_BLAME                   34\r
99 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where \r
100 // the submenu items get command ID's sequent to this number\r
101 #define IDSVNLC_MOVETOCS                35\r
102 \r
103 \r
104 BEGIN_MESSAGE_MAP(CGitStatusListCtrl, CListCtrl)\r
105         ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHdnItemclick)\r
106         ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHdnItemclick)\r
107         ON_NOTIFY(HDN_ENDTRACK, 0, OnColumnResized)\r
108         ON_NOTIFY(HDN_ENDDRAG, 0, OnColumnMoved)\r
109         ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, OnLvnItemchanged)\r
110         ON_WM_CONTEXTMENU()\r
111         ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)\r
112         ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnLvnGetInfoTip)\r
113         ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)\r
114         ON_WM_SETCURSOR()\r
115         ON_WM_GETDLGCODE()\r
116         ON_NOTIFY_REFLECT(NM_RETURN, OnNMReturn)\r
117         ON_WM_KEYDOWN()\r
118         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)\r
119         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)\r
120         ON_WM_PAINT()\r
121         ON_NOTIFY(HDN_BEGINTRACKA, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
122         ON_NOTIFY(HDN_BEGINTRACKW, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
123         ON_NOTIFY(HDN_ITEMCHANGINGA, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
124         ON_NOTIFY(HDN_ITEMCHANGINGW, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
125         ON_WM_DESTROY()\r
126         ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBeginDrag)\r
127         ON_NOTIFY_REFLECT(LVN_ITEMCHANGING, &CGitStatusListCtrl::OnLvnItemchanging)\r
128 END_MESSAGE_MAP()\r
129 \r
130 \r
131 \r
132 CGitStatusListCtrl::CGitStatusListCtrl() : CListCtrl()\r
133         //, m_HeadRev(GitRev::REV_HEAD)\r
134         , m_pbCanceled(NULL)\r
135         , m_pStatLabel(NULL)\r
136         , m_pSelectButton(NULL)\r
137         , m_pConfirmButton(NULL)\r
138         , m_bBusy(false)\r
139         , m_bEmpty(false)\r
140         , m_bUnversionedRecurse(true)\r
141         , m_bShowIgnores(false)\r
142         , m_pDropTarget(NULL)\r
143         , m_bIgnoreRemoveOnly(false)\r
144         , m_bCheckChildrenWithParent(false)\r
145         , m_bUnversionedLast(true)\r
146         , m_bHasChangeLists(false)\r
147         , m_bHasLocks(false)\r
148         , m_bBlock(false)\r
149         , m_bBlockUI(false)\r
150         , m_bHasCheckboxes(false)\r
151         , m_bCheckIfGroupsExist(true)\r
152         , m_bFileDropsEnabled(false)\r
153         , m_bOwnDrag(false)\r
154     , m_dwDefaultColumns(0)\r
155     , m_ColumnManager(this)\r
156     , m_bAscending(false)\r
157     , m_nSortedColumn(-1)\r
158         , m_sNoPropValueText(MAKEINTRESOURCE(IDS_STATUSLIST_NOPROPVALUE))\r
159 {\r
160         m_FileLoaded=0;\r
161         m_critSec.Init();\r
162 }\r
163 \r
164 CGitStatusListCtrl::~CGitStatusListCtrl()\r
165 {\r
166         if (m_pDropTarget)\r
167                 delete m_pDropTarget;\r
168         ClearStatusArray();\r
169 }\r
170 \r
171 void CGitStatusListCtrl::ClearStatusArray()\r
172 {\r
173 #if 0\r
174         Locker lock(m_critSec);\r
175         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
176         {\r
177                 delete m_arStatusArray[i];\r
178         }\r
179         m_arStatusArray.clear();\r
180 #endif\r
181 }\r
182 \r
183 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(UINT_PTR index)\r
184 {\r
185 #if 0\r
186         if (index >= (UINT_PTR)m_arListArray.size())\r
187                 return NULL;\r
188         if (m_arListArray[index] >= m_arStatusArray.size())\r
189                 return NULL;\r
190         return m_arStatusArray[m_arListArray[index]];\r
191 #endif\r
192         return NULL;\r
193 }\r
194 \r
195 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetVisibleListEntry(const CTGitPath& path)\r
196 {\r
197         int itemCount = GetItemCount();\r
198         for (int i=0; i < itemCount; i++)\r
199         {\r
200                 FileEntry * entry = GetListEntry(i);\r
201                 if (entry->GetPath().IsEquivalentTo(path))\r
202                         return entry;\r
203         }\r
204         return NULL;\r
205 }\r
206 \r
207 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(const CTGitPath& path)\r
208 {\r
209 #if 0\r
210         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
211         {\r
212                 FileEntry * entry = m_arStatusArray[i];\r
213                 if (entry->GetPath().IsEquivalentTo(path))\r
214                         return entry;\r
215         }\r
216 #endif\r
217         return NULL;\r
218 }\r
219 \r
220 int CGitStatusListCtrl::GetIndex(const CTGitPath& path)\r
221 {\r
222         int itemCount = GetItemCount();\r
223         for (int i=0; i < itemCount; i++)\r
224         {\r
225                 FileEntry * entry = GetListEntry(i);\r
226                 if (entry->GetPath().IsEquivalentTo(path))\r
227                         return i;\r
228         }\r
229         return -1;\r
230 }\r
231 \r
232 void CGitStatusListCtrl::Init(DWORD dwColumns, const CString& sColumnInfoContainer, DWORD dwContextMenus /* = GitSLC_POPALL */, bool bHasCheckboxes /* = true */)\r
233 {\r
234         Locker lock(m_critSec);\r
235 \r
236     m_dwDefaultColumns = dwColumns | 1;\r
237     m_dwContextMenus = dwContextMenus;\r
238         m_bHasCheckboxes = bHasCheckboxes;\r
239 \r
240     // set the extended style of the listcontrol\r
241         // the style LVS_EX_FULLROWSELECT interferes with the background watermark image but it's more important to be able to select in the whole row.\r
242         CRegDWORD regFullRowSelect(_T("Software\\TortoiseGit\\FullRowSelect"), TRUE);\r
243         DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES;\r
244         if (DWORD(regFullRowSelect))\r
245                 exStyle |= LVS_EX_FULLROWSELECT;\r
246         exStyle |= (bHasCheckboxes ? LVS_EX_CHECKBOXES : 0);\r
247         SetRedraw(false);\r
248         SetExtendedStyle(exStyle);\r
249 \r
250         CXPTheme theme;\r
251         theme.SetWindowTheme(m_hWnd, L"Explorer", NULL);\r
252 \r
253         m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();\r
254         SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);\r
255 \r
256     m_ColumnManager.ReadSettings (m_dwDefaultColumns, sColumnInfoContainer);\r
257 \r
258         // enable file drops\r
259 #if 0\r
260         if (m_pDropTarget == NULL)\r
261         {\r
262                 m_pDropTarget = new CGitStatusListCtrlDropTarget(this);\r
263                 RegisterDragDrop(m_hWnd,m_pDropTarget);\r
264                 // create the supported formats:\r
265                 FORMATETC ftetc={0};\r
266                 ftetc.dwAspect = DVASPECT_CONTENT;\r
267                 ftetc.lindex = -1;\r
268                 ftetc.tymed = TYMED_HGLOBAL;\r
269                 ftetc.cfFormat=CF_HDROP;\r
270                 m_pDropTarget->AddSuportedFormat(ftetc);\r
271         }\r
272 #endif\r
273 \r
274         SetRedraw(true);\r
275 \r
276         m_bUnversionedRecurse = !!((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\UnversionedRecurse"), TRUE));\r
277 }\r
278 \r
279 bool CGitStatusListCtrl::SetBackgroundImage(UINT nID)\r
280 {\r
281         return CAppUtils::SetListCtrlBackgroundImage(GetSafeHwnd(), nID);\r
282 }\r
283 \r
284 BOOL CGitStatusListCtrl::GetStatus ( const CTGitPathList& pathList\r
285                                    , bool bUpdate /* = FALSE */\r
286                                    , bool bShowIgnores /* = false */\r
287                                                                    , bool bShowUnRev\r
288                                    , bool bShowUserProps /* = false */)\r
289 {\r
290         Locker lock(m_critSec);\r
291         int mask= CGitStatusListCtrl::FILELIST_MODIFY;\r
292         if(bShowIgnores)\r
293                 mask|= CGitStatusListCtrl::FILELIST_IGNORE;\r
294         if(bShowUnRev)\r
295                 mask|= CGitStatusListCtrl::FILELIST_UNVER;\r
296         this->UpdateFileList(mask,bUpdate,(CTGitPathList*)&pathList);\r
297 \r
298 #if 0\r
299         \r
300         int refetchcounter = 0;\r
301         BOOL bRet = TRUE;\r
302         Invalidate();\r
303         // force the cursor to change\r
304         POINT pt;\r
305         GetCursorPos(&pt);\r
306         SetCursorPos(pt.x, pt.y);\r
307 \r
308         m_mapFilenameToChecked.clear();\r
309         //m_StatusUrlList.Clear();\r
310         bool bHasChangelists = (m_changelists.size()>1 || (m_changelists.size()>0 && !m_bHasIgnoreGroup));\r
311         m_changelists.clear();\r
312         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
313         {\r
314                 FileEntry * entry = m_arStatusArray[i];\r
315                 if ( bHasChangelists && entry->checked)\r
316                 {\r
317                         // If change lists are present, remember all checked entries\r
318                         CString path = entry->GetPath().GetGitPathString();\r
319                         m_mapFilenameToChecked[path] = true;\r
320                 }\r
321                 if ( (entry->status==git_wc_status_unversioned || entry->status==git_wc_status_missing ) && entry->checked )\r
322                 {\r
323                         // The user manually selected an unversioned or missing file. We remember\r
324                         // this so that the selection can be restored when refreshing.\r
325                         CString path = entry->GetPath().GetGitPathString();\r
326                         m_mapFilenameToChecked[path] = true;\r
327                 }\r
328                 else if ( entry->status > git_wc_status_normal && !entry->checked )\r
329                 {\r
330                         // The user manually deselected a versioned file. We remember\r
331                         // this so that the deselection can be restored when refreshing.\r
332                         CString path = entry->GetPath().GetGitPathString();\r
333                         m_mapFilenameToChecked[path] = false;\r
334                 }\r
335         }\r
336 \r
337         // use a sorted path list to make sure we fetch the status of\r
338         // parent items first, *then* the child items (if any)\r
339         CTGitPathList sortedPathList = pathList;\r
340         sortedPathList.SortByPathname();\r
341         do\r
342         {\r
343                 bRet = TRUE;\r
344                 m_nTargetCount = 0;\r
345                 m_bHasExternalsFromDifferentRepos = FALSE;\r
346                 m_bHasExternals = FALSE;\r
347                 m_bHasUnversionedItems = FALSE;\r
348                 m_bHasLocks = false;\r
349                 m_bHasChangeLists = false;\r
350                 m_bShowIgnores = bShowIgnores;\r
351                 m_nSortedColumn = 0;\r
352                 m_bBlock = TRUE;\r
353                 m_bBusy = true;\r
354                 m_bEmpty = false;\r
355                 Invalidate();\r
356 \r
357                 // first clear possible status data left from\r
358                 // previous GetStatus() calls\r
359                 ClearStatusArray();\r
360 \r
361                 m_StatusFileList = sortedPathList;\r
362 \r
363                 // Since Git_client_status() returns all files, even those in\r
364                 // folders included with Git:externals we need to check if all\r
365                 // files we get here belongs to the same repository.\r
366                 // It is possible to commit changes in an external folder, as long\r
367                 // as the folder belongs to the same repository (but another path),\r
368                 // but it is not possible to commit all files if the externals are\r
369                 // from a different repository.\r
370                 //\r
371                 // To check if all files belong to the same repository, we compare the\r
372                 // UUID's - if they're identical then the files belong to the same\r
373                 // repository and can be committed. But if they're different, then\r
374                 // tell the user to commit all changes in the external folders\r
375                 // first and exit.\r
376                 CStringA sUUID;                                 // holds the repo UUID\r
377                 CTGitPathList arExtPaths;               // list of Git:external paths\r
378 \r
379                 GitConfig config;\r
380 \r
381                 m_sURL.Empty();\r
382 \r
383                 m_nTargetCount = sortedPathList.GetCount();\r
384 \r
385                 GitStatus status(m_pbCanceled);\r
386                 if(m_nTargetCount > 1 && sortedPathList.AreAllPathsFilesInOneDirectory())\r
387                 {\r
388                         // This is a special case, where we've been given a list of files\r
389                         // all from one folder\r
390                         // We handle them by setting a status filter, then requesting the Git status of\r
391                         // all the files in the directory, filtering for the ones we're interested in\r
392                         status.SetFilter(sortedPathList);\r
393 \r
394                         // if all selected entries are files, we don't do a recursive status\r
395                         // fetching. But if only one is a directory, we have to recurse.\r
396                         git_depth_t depth = git_depth_files;\r
397                         // We have set a filter. If all selected items were files or we fetch\r
398                         // the status not recursively, then we have to include\r
399                         // ignored items too - the user has selected them\r
400                         bool bShowIgnoresRight = true;\r
401                         for (int fcindex=0; fcindex<sortedPathList.GetCount(); ++fcindex)\r
402                         {\r
403                                 if (sortedPathList[fcindex].IsDirectory())\r
404                                 {\r
405                                         depth = git_depth_infinity;\r
406                                         bShowIgnoresRight = false;\r
407                                         break;\r
408                                 }\r
409                         }\r
410                         if(!FetchStatusForSingleTarget(config, status, sortedPathList.GetCommonDirectory(), bUpdate, sUUID, arExtPaths, true, depth, bShowIgnoresRight))\r
411                         {\r
412                                 bRet = FALSE;\r
413                         }\r
414                 }\r
415                 else\r
416                 {\r
417                         for(int nTarget = 0; nTarget < m_nTargetCount; nTarget++)\r
418                         {\r
419                                 // check whether the path we want the status for is already fetched due to status-fetching\r
420                                 // of a parent path.\r
421                                 // this check is only done for file paths, because folder paths could be included already\r
422                                 // but not recursively\r
423                                 if (sortedPathList[nTarget].IsDirectory() || GetListEntry(sortedPathList[nTarget]) == NULL)\r
424                                 {\r
425                                         if(!FetchStatusForSingleTarget(config, status, sortedPathList[nTarget], bUpdate, sUUID, \r
426                                                 arExtPaths, false, git_depth_infinity, bShowIgnores))\r
427                                         {\r
428                                                 bRet = FALSE;\r
429                                         }\r
430                                 }\r
431                         }\r
432                 }\r
433 \r
434                 // remove the 'helper' files of conflicted items from the list.\r
435                 // otherwise they would appear as unversioned files.\r
436                 for (INT_PTR cind = 0; cind < m_ConflictFileList.GetCount(); ++cind)\r
437                 {\r
438                         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
439                         {\r
440                                 if (m_arStatusArray[i]->GetPath().IsEquivalentTo(m_ConflictFileList[cind]))\r
441                                 {\r
442                                         delete m_arStatusArray[i];\r
443                                         m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
444                                         break;\r
445                                 }\r
446                         }\r
447                 }\r
448                 refetchcounter++;\r
449         } while(!BuildStatistics() && (refetchcounter < 2) && (*m_pbCanceled==false));\r
450 \r
451     if (bShowUserProps)\r
452         FetchUserProperties();\r
453 \r
454     m_ColumnManager.UpdateUserPropList (m_arStatusArray);\r
455 \r
456         m_bBlock = FALSE;\r
457         m_bBusy = false;\r
458         GetCursorPos(&pt);\r
459         SetCursorPos(pt.x, pt.y);\r
460         return bRet;\r
461 #endif \r
462         return TRUE;\r
463 }\r
464 \r
465 //\r
466 // Fetch all local properties for all elements in the status array\r
467 //\r
468 void CGitStatusListCtrl::FetchUserProperties()\r
469 {\r
470 #if 0\r
471         GitPool globalPool;\r
472 \r
473     for (size_t i = 0, count = m_arStatusArray.size(); i < count; ++i)\r
474     {\r
475         // local / temp pool to hold parameters and props for a single item\r
476 \r
477         GitPool localPool ((apr_pool_t*)globalPool);\r
478 \r
479         // open working copy for this path\r
480 \r
481         const char* path = m_arStatusArray[i]->path.GetGitApiPath (localPool);\r
482          \r
483             Git_wc_adm_access_t *adm_access = NULL;          \r
484         Git_error_t * error = Git_wc_adm_probe_open3 ( &adm_access\r
485                                                      , NULL\r
486                                                      , path\r
487                                                      , FALSE    // no write lock\r
488                                                                                                          , 0            // lock just the directory/file itself\r
489                                                      , NULL\r
490                                                                                                          , NULL\r
491                                                      , localPool);\r
492         if (error == NULL)\r
493         {\r
494             // get the props and add them to the status info\r
495 \r
496             apr_hash_t* props = NULL;\r
497             Git_error_t * error = Git_wc_prop_list ( &props\r
498                                                    , path\r
499                                                    , adm_access\r
500                                                    , localPool);\r
501             if (error == NULL)\r
502             {\r
503                 for ( apr_hash_index_t *index \r
504                         = apr_hash_first (localPool, props)\r
505                     ; index != NULL\r
506                     ; index = apr_hash_next (index))\r
507                 {\r
508                     // extract next entry from hash\r
509 \r
510                     const char* key = NULL;\r
511                     ptrdiff_t keyLen;\r
512                     const char** val = NULL;\r
513 \r
514                     apr_hash_this ( index\r
515                                   , reinterpret_cast<const void**>(&key)\r
516                                   , &keyLen\r
517                                   , reinterpret_cast<void**>(&val));\r
518 \r
519                     // decode / dispatch it\r
520 \r
521                         CString name = CUnicodeUtils::GetUnicode (key);\r
522                         CString value = CUnicodeUtils::GetUnicode (*val);\r
523 \r
524                     // store in property container (truncate it after ~100 chars)\r
525 \r
526                     m_arStatusArray[i]->present_props[name] \r
527                         = value.Left (GitSLC_MAXUSERPROPLENGTH);\r
528                 }\r
529             }\r
530             error = Git_wc_adm_close2 (adm_access, localPool);\r
531         }\r
532         Git_error_clear (error);\r
533     }\r
534 #endif\r
535 }\r
536 \r
537 \r
538 //\r
539 // Work on a single item from the list of paths which is provided to us\r
540 //\r
541 bool CGitStatusListCtrl::FetchStatusForSingleTarget(\r
542                                                         GitConfig& config,\r
543                                                         GitStatus& status,\r
544                                                         const CTGitPath& target,\r
545                                                         bool bFetchStatusFromRepository,\r
546                                                         CStringA& strCurrentRepositoryUUID,\r
547                                                         CTGitPathList& arExtPaths,\r
548                                                         bool bAllDirect,\r
549                                                         git_depth_t depth,\r
550                                                         bool bShowIgnores\r
551                                                         )\r
552 {\r
553 #if 0\r
554         config.GetDefaultIgnores();\r
555 \r
556         CTGitPath workingTarget(target);\r
557 \r
558         git_wc_status2_t * s;\r
559         CTGitPath GitPath;\r
560         s = status.GetFirstFileStatus(workingTarget, GitPath, bFetchStatusFromRepository, depth, bShowIgnores);\r
561 \r
562         m_HeadRev = SVNRev(status.headrev);\r
563         if (s!=0)\r
564         {\r
565                 Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
566 \r
567                 // This one fixes a problem with externals:\r
568                 // If a strLine is a file, Git:externals and its parent directory\r
569                 // will also be returned by GetXXXFileStatus. Hence, we skip all\r
570                 // status info until we find the one matching workingTarget.\r
571                 if (!workingTarget.IsDirectory())\r
572                 {\r
573                         if (!workingTarget.IsEquivalentTo(GitPath))\r
574                         {\r
575                                 while (s != 0)\r
576                                 {\r
577                                         s = status.GetNextFileStatus(GitPath);\r
578                                         if(workingTarget.IsEquivalentTo(GitPath))\r
579                                         {\r
580                                                 break;\r
581                                         }\r
582                                 }\r
583                                 if (s == 0)\r
584                                 {\r
585                                         m_sLastError = status.GetLastErrorMsg();\r
586                                         return false;\r
587                                 }\r
588                                 // Now, set working target to be the base folder of this item\r
589                                 workingTarget = workingTarget.GetDirectory();\r
590                         }\r
591                 }\r
592                 bool bEntryFromDifferentRepo = false;\r
593                 // Is this a versioned item with an associated repos UUID?\r
594                 if ((s->entry)&&(s->entry->uuid))\r
595                 {\r
596                         // Have we seen a repos UUID yet?\r
597                         if (strCurrentRepositoryUUID.IsEmpty())\r
598                         {\r
599                                 // This is the first repos UUID we've seen - record it\r
600                                 strCurrentRepositoryUUID = s->entry->uuid;\r
601                                 m_sUUID = strCurrentRepositoryUUID;\r
602                         }\r
603                         else\r
604                         {\r
605                                 if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
606                                 {\r
607                                         // This item comes from a different repository than our main one\r
608                                         m_bHasExternalsFromDifferentRepos = TRUE;\r
609                                         bEntryFromDifferentRepo = true;\r
610                                         if (s->entry->kind == Git_node_dir)\r
611                                                 arExtPaths.AddPath(workingTarget);\r
612                                 }\r
613                         }\r
614                 }\r
615                 else if (strCurrentRepositoryUUID.IsEmpty() && (s->text_status == Git_wc_status_added))\r
616                 {\r
617                         // An added entry doesn't have an UUID assigned to it yet.\r
618                         // So we fetch the status of the parent directory instead and\r
619                         // check if that one has an UUID assigned to it.\r
620                         Git_wc_status2_t * sparent;\r
621                         CTGitPath path = workingTarget;\r
622                         do\r
623                         {\r
624                                 CTGitPath GitParentPath;\r
625                                 GitStatus tempstatus;\r
626                                 sparent = tempstatus.GetFirstFileStatus(path.GetContainingDirectory(), GitParentPath, false, Git_depth_empty, false);\r
627                                 path = GitParentPath;\r
628                         } while ( (sparent) && (sparent->entry) && (!sparent->entry->uuid) && (sparent->text_status==Git_wc_status_added) );\r
629                         if (sparent && sparent->entry && sparent->entry->uuid)\r
630                         {\r
631                                 strCurrentRepositoryUUID = sparent->entry->uuid;\r
632                                 m_sUUID = strCurrentRepositoryUUID;\r
633                         }\r
634                 }\r
635 \r
636                 if ((wcFileStatus == Git_wc_status_unversioned)&& GitPath.IsDirectory())\r
637                 {\r
638                         // check if the unversioned folder is maybe versioned. This\r
639                         // could happen with nested layouts\r
640                         Git_wc_status_kind st = GitStatus::GetAllStatus(workingTarget);\r
641                         if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
642                         {\r
643                                 return true;    // ignore nested layouts\r
644                         }\r
645                 }\r
646                 if (status.IsExternal(GitPath))\r
647                 {\r
648                         m_bHasExternals = TRUE;\r
649                 }\r
650 \r
651                 AddNewFileEntry(s, GitPath, workingTarget, true, m_bHasExternals, bEntryFromDifferentRepo);\r
652 \r
653                 if (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none)||((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))) && GitPath.IsDirectory())\r
654                 {\r
655                         // we have an unversioned folder -> get all files in it recursively!\r
656                         AddUnversionedFolder(GitPath, workingTarget.GetContainingDirectory(), &config);\r
657                 }\r
658 \r
659                 // for folders, get all statuses inside it too\r
660                 if(workingTarget.IsDirectory())\r
661                 {\r
662                         ReadRemainingItemsStatus(status, workingTarget, strCurrentRepositoryUUID, arExtPaths, &config, bAllDirect);\r
663                 }\r
664 \r
665         } // if (s!=0)\r
666         else\r
667         {\r
668                 m_sLastError = status.GetLastErrorMsg();\r
669                 return false;\r
670         }\r
671 #endif\r
672         return true;\r
673 }\r
674 \r
675 const CGitStatusListCtrl::FileEntry*\r
676 CGitStatusListCtrl::AddNewFileEntry(\r
677                         const git_wc_status2_t* pGitStatus,  // The return from the Git GetStatus functions\r
678                         const CTGitPath& path,                          // The path of the item we're adding\r
679                         const CTGitPath& basePath,                      // The base directory for this status build\r
680                         bool bDirectItem,                                       // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call\r
681                         bool bInExternal,                                       // Are we in an 'external' folder\r
682                         bool bEntryfromDifferentRepo            // if the entry is from a different repository\r
683                         )\r
684 {\r
685         FileEntry * entry = new FileEntry();\r
686 #if 0\r
687         \r
688         entry->path = path;\r
689         entry->basepath = basePath;\r
690         entry->status = GitStatus::GetMoreImportant(pGitStatus->text_status, pGitStatus->prop_status);\r
691         entry->textstatus = pGitStatus->text_status;\r
692         entry->propstatus = pGitStatus->prop_status;\r
693 //      entry->remotestatus = GitStatus::GetMoreImportant(pGitStatus->repos_text_status, pGitStatus->repos_prop_status);\r
694 //      entry->remotetextstatus = pGitStatus->repos_text_status;\r
695 //      entry->remotepropstatus = pGitStatus->repos_prop_status;\r
696         entry->inexternal = bInExternal;\r
697         entry->differentrepo = bEntryfromDifferentRepo;\r
698         entry->direct = bDirectItem;\r
699 //      entry->copied = !!pGitStatus->copied;\r
700 //      entry->switched = !!pGitStatus->switched;\r
701 \r
702         entry->last_commit_date = pGitStatus->ood_last_cmt_date;\r
703         if ((entry->last_commit_date == NULL)&&(pGitStatus->entry))\r
704                 entry->last_commit_date = pGitStatus->entry->cmt_date;\r
705         entry->remoterev = pGitStatus->ood_last_cmt_rev;\r
706         if (pGitStatus->entry)\r
707                 entry->last_commit_rev = pGitStatus->entry->cmt_rev;\r
708         if (pGitStatus->ood_last_cmt_author)\r
709                 entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->ood_last_cmt_author);\r
710         if ((entry->last_commit_author.IsEmpty())&&(pGitStatus->entry)&&(pGitStatus->entry->cmt_author))\r
711                 entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->entry->cmt_author);\r
712 \r
713         if (pGitStatus->entry)\r
714                 entry->isConflicted = (pGitStatus->entry->conflict_wrk && PathFileExists(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk))) ? true : false;\r
715 \r
716         if ((entry->status == Git_wc_status_conflicted)||(entry->isConflicted))\r
717         {\r
718                 entry->isConflicted = true;\r
719                 if (pGitStatus->entry)\r
720                 {\r
721                         CTGitPath cpath;\r
722                         if (pGitStatus->entry->conflict_wrk)\r
723                         {\r
724                                 cpath = path.GetDirectory();\r
725                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk));\r
726                                 m_ConflictFileList.AddPath(cpath);\r
727                         }\r
728                         if (pGitStatus->entry->conflict_old)\r
729                         {\r
730                                 cpath = path.GetDirectory();\r
731                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_old));\r
732                                 m_ConflictFileList.AddPath(cpath);\r
733                         }\r
734                         if (pGitStatus->entry->conflict_new)\r
735                         {\r
736                                 cpath = path.GetDirectory();\r
737                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_new));\r
738                                 m_ConflictFileList.AddPath(cpath);\r
739                         }\r
740                         if (pGitStatus->entry->prejfile)\r
741                         {\r
742                                 cpath = path.GetDirectory();\r
743                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->prejfile));\r
744                                 m_ConflictFileList.AddPath(cpath);\r
745                         }\r
746                 }\r
747         }\r
748 \r
749         if (pGitStatus->entry)\r
750         {\r
751                 entry->isfolder = (pGitStatus->entry->kind == Git_node_dir);\r
752                 entry->Revision = pGitStatus->entry->revision;\r
753                 entry->keeplocal = !!pGitStatus->entry->keep_local;\r
754                 entry->working_size = pGitStatus->entry->working_size;\r
755                 entry->depth = pGitStatus->entry->depth;\r
756 \r
757                 if (pGitStatus->entry->url)\r
758                 {\r
759                         entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->url));\r
760                 }\r
761                 if (pGitStatus->entry->copyfrom_url)\r
762                 {\r
763                         entry->copyfrom_url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->copyfrom_url));\r
764                         entry->copyfrom_rev = pGitStatus->entry->copyfrom_rev;\r
765                 }\r
766                 else\r
767                         entry->copyfrom_rev = 0;\r
768 \r
769                 if(bDirectItem)\r
770                 {\r
771                         if (m_sURL.IsEmpty())\r
772                                 m_sURL = entry->url;\r
773                         else\r
774                                 m_sURL.LoadString(IDS_STATUSLIST_MULTIPLETARGETS);\r
775                         m_StatusUrlList.AddPath(CTGitPath(entry->url));\r
776                 }\r
777                 if (pGitStatus->entry->lock_owner)\r
778                         entry->lock_owner = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_owner);\r
779                 if (pGitStatus->entry->lock_token)\r
780                 {\r
781                         entry->lock_token = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_token);\r
782                         m_bHasLocks = true;\r
783                 }\r
784                 if (pGitStatus->entry->lock_comment)\r
785                         entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_comment);\r
786 \r
787                 if (pGitStatus->entry->present_props)\r
788                 {\r
789                         entry->present_props = pGitStatus->entry->present_props;\r
790                 }\r
791 \r
792                 if (pGitStatus->entry->changelist)\r
793                 {\r
794                         entry->changelist = CUnicodeUtils::GetUnicode(pGitStatus->entry->changelist);\r
795                         m_changelists[entry->changelist] = -1;\r
796                         m_bHasChangeLists = true;\r
797                 }\r
798                 entry->needslock = (pGitStatus->entry->present_props && (strstr(pGitStatus->entry->present_props, "Git:needs-lock")!=NULL) );\r
799         }\r
800         else\r
801         {\r
802                 if (pGitStatus->ood_kind == Git_node_none)\r
803                         entry->isfolder = path.IsDirectory();\r
804                 else\r
805                         entry->isfolder = (pGitStatus->ood_kind == Git_node_dir);\r
806         }\r
807         if (pGitStatus->repos_lock)\r
808         {\r
809                 if (pGitStatus->repos_lock->owner)\r
810                         entry->lock_remoteowner = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->owner);\r
811                 if (pGitStatus->repos_lock->token)\r
812                         entry->lock_remotetoken = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->token);\r
813                 if (pGitStatus->repos_lock->comment)\r
814                         entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->comment);\r
815         }\r
816 \r
817         // Pass ownership of the entry to the array\r
818         m_arStatusArray.push_back(entry);\r
819 #endif\r
820         return entry;\r
821 }\r
822 \r
823 void CGitStatusListCtrl::AddUnversionedFolder(const CTGitPath& folderName,\r
824                                                                                                 const CTGitPath& basePath,\r
825                                                                                                 GitConfig * config)\r
826 {\r
827 #if 0\r
828         if (!m_bUnversionedRecurse)\r
829                 return;\r
830         CSimpleFileFind filefinder(folderName.GetWinPathString());\r
831 \r
832         CTGitPath filename;\r
833         m_bHasUnversionedItems = TRUE;\r
834         while (filefinder.FindNextFileNoDots())\r
835         {\r
836                 filename.SetFromWin(filefinder.GetFilePath(), filefinder.IsDirectory());\r
837 \r
838                 bool bMatchIgnore = !!config->MatchIgnorePattern(filename.GetFileOrDirectoryName());\r
839                 bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(filename.GetGitPathString());\r
840                 if (((bMatchIgnore)&&(m_bShowIgnores))||(!bMatchIgnore))\r
841                 {\r
842                         FileEntry * entry = new FileEntry();\r
843                         entry->path = filename;\r
844                         entry->basepath = basePath;\r
845                         entry->inunversionedfolder = true;\r
846                         entry->isfolder = filefinder.IsDirectory();\r
847 \r
848                         m_arStatusArray.push_back(entry);\r
849                         if (entry->isfolder)\r
850                         {\r
851                                 if (!g_GitAdminDir.HasAdminDir(entry->path.GetWinPathString(), true))\r
852                                         AddUnversionedFolder(entry->path, basePath, config);\r
853                         }\r
854                 }\r
855         }\r
856 #endif\r
857 }\r
858 \r
859 \r
860 void CGitStatusListCtrl::ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& basePath,\r
861                                                                                   CStringA& strCurrentRepositoryUUID,\r
862                                                                                   CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect)\r
863 {\r
864 #if 0\r
865         git_wc_status2_t * s;\r
866 \r
867         CTGitPath lastexternalpath;\r
868         CTGitPath GitPath;\r
869         while ((s = status.GetNextFileStatus(GitPath)) != NULL)\r
870         {\r
871                 Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
872                 if ((wcFileStatus == Git_wc_status_unversioned) && (GitPath.IsDirectory()))\r
873                 {\r
874                         // check if the unversioned folder is maybe versioned. This\r
875                         // could happen with nested layouts\r
876                         Git_wc_status_kind st = GitStatus::GetAllStatus(GitPath);\r
877                         if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
878                         {\r
879                                 FileEntry * entry = new FileEntry();\r
880                                 entry->path = GitPath;\r
881                                 entry->basepath = basePath;\r
882                                 entry->inunversionedfolder = true;\r
883                                 entry->isfolder = true;\r
884                                 entry->isNested = true;\r
885                                 m_arStatusArray.push_back(entry);\r
886                                 continue;\r
887                         }\r
888                 }\r
889                 bool bDirectoryIsExternal = false;\r
890                 bool bEntryfromDifferentRepo = false;\r
891                 if (s->entry)\r
892                 {\r
893                         if (s->entry->uuid)\r
894                         {\r
895                                 if (strCurrentRepositoryUUID.IsEmpty())\r
896                                         strCurrentRepositoryUUID = s->entry->uuid;\r
897                                 else\r
898                                 {\r
899                                         if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
900                                         {\r
901                                                 bEntryfromDifferentRepo = true;\r
902                                                 if (GitStatus::IsImportant(wcFileStatus))\r
903                                                         m_bHasExternalsFromDifferentRepos = TRUE;\r
904                                                 if (s->entry->kind == Git_node_dir)\r
905                                                 {\r
906                                                         if ((lastexternalpath.IsEmpty())||(!lastexternalpath.IsAncestorOf(GitPath)))\r
907                                                         {\r
908                                                                 arExtPaths.AddPath(GitPath);\r
909                                                                 lastexternalpath = GitPath;\r
910                                                         }\r
911                                                 }\r
912                                         }\r
913                                 }\r
914                         }\r
915                         else\r
916                         {\r
917                                 // we don't have an UUID - maybe an added file/folder\r
918                                 if (!strCurrentRepositoryUUID.IsEmpty())\r
919                                 {\r
920                                         if ((!lastexternalpath.IsEmpty())&&\r
921                                                 (lastexternalpath.IsAncestorOf(GitPath)))\r
922                                         {\r
923                                                 bEntryfromDifferentRepo = true;\r
924                                                 m_bHasExternalsFromDifferentRepos = TRUE;\r
925                                         }\r
926                                 }\r
927                         }\r
928                 }\r
929                 else\r
930                 {\r
931                         // if unversioned items lie around in external\r
932                         // directories from different repos, we have to mark them\r
933                         // as such too.\r
934                         if (!strCurrentRepositoryUUID.IsEmpty())\r
935                         {\r
936                                 if ((!lastexternalpath.IsEmpty())&&\r
937                                         (lastexternalpath.IsAncestorOf(GitPath)))\r
938                                 {\r
939                                         bEntryfromDifferentRepo = true;\r
940                                 }\r
941                         }\r
942                 }\r
943                 if (status.IsExternal(GitPath))\r
944                 {\r
945                         arExtPaths.AddPath(GitPath);\r
946                         m_bHasExternals = TRUE;\r
947                 }\r
948                 if ((!bEntryfromDifferentRepo)&&(status.IsInExternal(GitPath)))\r
949                 {\r
950                         // if the externals are inside an unversioned folder (this happens if\r
951                         // the externals are specified with e.g. "ext\folder url" instead of just\r
952                         // "folder url"), then a commit won't succeed.\r
953                         // therefore, we treat those as if the externals come from a different\r
954                         // repository\r
955                         CTGitPath extpath = GitPath;\r
956                         while (basePath.IsAncestorOf(extpath))\r
957                         {\r
958                                 if (!extpath.HasAdminDir())\r
959                                 {\r
960                                         bEntryfromDifferentRepo = true;\r
961                                         break;\r
962                                 }\r
963                                 extpath = extpath.GetContainingDirectory();\r
964                         }\r
965                 }\r
966                 // Do we have any external paths?\r
967                 if(arExtPaths.GetCount() > 0)\r
968                 {\r
969                         // If do have external paths, we need to check if the current item belongs\r
970                         // to one of them\r
971                         for (int ix=0; ix<arExtPaths.GetCount(); ix++)\r
972                         {\r
973                                 if (arExtPaths[ix].IsAncestorOf(GitPath))\r
974                                 {\r
975                                         bDirectoryIsExternal = true;\r
976                                         break;\r
977                                 }\r
978                         }\r
979                 }\r
980 \r
981                 if ((wcFileStatus == Git_wc_status_unversioned)&&(!bDirectoryIsExternal))\r
982                         m_bHasUnversionedItems = TRUE;\r
983 \r
984                 const FileEntry* entry = AddNewFileEntry(s, GitPath, basePath, bAllDirect, bDirectoryIsExternal, bEntryfromDifferentRepo);\r
985 \r
986                 bool bMatchIgnore = !!config->MatchIgnorePattern(entry->path.GetFileOrDirectoryName());\r
987                 bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(entry->path.GetGitPathString());\r
988                 if ((((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(!bMatchIgnore))||\r
989                         ((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))||\r
990                         (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(bMatchIgnore)&&(m_bShowIgnores)))\r
991                 {\r
992                         if (entry->isfolder)\r
993                         {\r
994                                 // we have an unversioned folder -> get all files in it recursively!\r
995                                 AddUnversionedFolder(GitPath, basePath, config);\r
996                         }\r
997                 }\r
998         } // while ((s = status.GetNextFileStatus(GitPath)) != NULL) \r
999 #endif\r
1000 }\r
1001 \r
1002 // Get the show-flags bitmap value which corresponds to a particular Git status\r
1003 DWORD CGitStatusListCtrl::GetShowFlagsFromGitStatus(git_wc_status_kind status)\r
1004 {\r
1005         switch (status)\r
1006         {\r
1007         case git_wc_status_none:\r
1008         case git_wc_status_unversioned:\r
1009                 return SVNSLC_SHOWUNVERSIONED;\r
1010         case git_wc_status_ignored:\r
1011                 if (!m_bShowIgnores)\r
1012                         return SVNSLC_SHOWDIRECTS;\r
1013                 return SVNSLC_SHOWDIRECTS|SVNSLC_SHOWIGNORED;\r
1014         case git_wc_status_incomplete:\r
1015                 return SVNSLC_SHOWINCOMPLETE;\r
1016         case git_wc_status_normal:\r
1017                 return SVNSLC_SHOWNORMAL;\r
1018         case git_wc_status_external:\r
1019                 return SVNSLC_SHOWEXTERNAL;\r
1020         case git_wc_status_added:\r
1021                 return SVNSLC_SHOWADDED;\r
1022         case git_wc_status_missing:\r
1023                 return SVNSLC_SHOWMISSING;\r
1024         case git_wc_status_deleted:\r
1025                 return SVNSLC_SHOWREMOVED;\r
1026         case git_wc_status_replaced:\r
1027                 return SVNSLC_SHOWREPLACED;\r
1028         case git_wc_status_modified:\r
1029                 return SVNSLC_SHOWMODIFIED;\r
1030         case git_wc_status_merged:\r
1031                 return SVNSLC_SHOWMERGED;\r
1032         case git_wc_status_conflicted:\r
1033                 return SVNSLC_SHOWCONFLICTED;\r
1034         case git_wc_status_obstructed:\r
1035                 return SVNSLC_SHOWOBSTRUCTED;\r
1036         default:\r
1037                 // we should NEVER get here!\r
1038                 ASSERT(FALSE);\r
1039                 break;\r
1040         }\r
1041         return 0;\r
1042 }\r
1043 \r
1044 void CGitStatusListCtrl::Show(DWORD dwShow, DWORD dwCheck /*=0*/, bool bShowFolders /* = true */)\r
1045 {\r
1046         CWinApp * pApp = AfxGetApp();\r
1047         if (pApp)\r
1048                 pApp->DoWaitCursor(1);\r
1049 \r
1050         Locker lock(m_critSec);\r
1051         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
1052         \r
1053         //SetItemCount(listIndex);\r
1054         SetRedraw(FALSE);\r
1055         DeleteAllItems();\r
1056         PrepareGroups();\r
1057         m_nSelected = 0;\r
1058 \r
1059         for(int i=0;i<this->m_arStatusArray.size();i++)\r
1060         {\r
1061                 AddEntry((CTGitPath*)m_arStatusArray[i],langID,i);\r
1062         }\r
1063         \r
1064         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1065         for (int col = 0; col <= maxcol; col++)\r
1066         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1067 \r
1068     SetRedraw(TRUE);\r
1069         GetStatisticsString();\r
1070 \r
1071         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1072         HDITEM HeaderItem = {0};\r
1073         HeaderItem.mask = HDI_FORMAT;\r
1074         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1075         {\r
1076                 pHeader->GetItem(i, &HeaderItem);\r
1077                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1078                 pHeader->SetItem(i, &HeaderItem);\r
1079         }\r
1080         if (m_nSortedColumn)\r
1081         {\r
1082                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1083                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1084                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1085         }\r
1086 \r
1087 #if 0\r
1088         if (nSelectedEntry)\r
1089         {\r
1090                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1091                 EnsureVisible(nSelectedEntry, false);\r
1092         }\r
1093         else\r
1094         {\r
1095                 // Restore the item at the top of the list.\r
1096                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1097                 {\r
1098                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1099                         {\r
1100                                 break;\r
1101                         }\r
1102                 }\r
1103         }\r
1104 #endif\r
1105         if (pApp)\r
1106                 pApp->DoWaitCursor(-1);\r
1107 \r
1108         Invalidate();\r
1109 \r
1110 #if 0\r
1111 \r
1112         CWinApp * pApp = AfxGetApp();\r
1113         if (pApp)\r
1114                 pApp->DoWaitCursor(1);\r
1115         m_dwShow = dwShow;\r
1116         m_bShowFolders = bShowFolders;\r
1117         \r
1118         int nTopIndex = GetTopIndex();\r
1119         POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
1120         int nSelectedEntry = 0;\r
1121         if (posSelectedEntry)\r
1122                 nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
1123         SetRedraw(FALSE);\r
1124         DeleteAllItems();\r
1125 \r
1126         PrepareGroups();\r
1127 \r
1128         m_arListArray.clear();\r
1129 \r
1130         m_arListArray.reserve(m_arStatusArray.size());\r
1131         SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
1132 \r
1133         int listIndex = 0;\r
1134         for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
1135         {\r
1136                 FileEntry * entry = m_arStatusArray[i];\r
1137                 if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
1138                         continue;\r
1139                 if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
1140                         continue;\r
1141                 if (entry->IsFolder() && (!bShowFolders))\r
1142                         continue;       // don't show folders if they're not wanted.\r
1143 \r
1144 #if 0\r
1145                 git_wc_status_kind status = GitStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
1146                 DWORD showFlags = GetShowFlagsFromGitStatus(status);\r
1147                 if (entry->IsLocked())\r
1148                         showFlags |= SVNSLC_SHOWLOCKS;\r
1149                 if (entry->switched)\r
1150                         showFlags |= SVNSLC_SHOWSWITCHED;\r
1151                 if (!entry->changelist.IsEmpty())\r
1152                         showFlags |= SVNSLC_SHOWINCHANGELIST;\r
1153 #endif\r
1154                 bool bAllowCheck = ((entry->changelist.Compare(SVNSLC_IGNORECHANGELIST) != 0) \r
1155                         && (m_bCheckIfGroupsExist || (m_changelists.size()==0 || (m_changelists.size()==1 && m_bHasIgnoreGroup))));\r
1156 \r
1157                 // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
1158 #if 0\r
1159                 if (status != Git_wc_status_ignored || (entry->direct) || (dwShow & GitSLC_SHOWIGNORED))\r
1160                 {\r
1161                         if ((!entry->IsFolder()) && (status == Git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
1162                         {\r
1163                                 if (PathFileExists(entry->GetPath().GetWinPath()))\r
1164                                 {\r
1165                                         m_arListArray.push_back(i);\r
1166                                         if ((dwCheck & SVNSLC_SHOWREMOVEDANDPRESENT)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1167                                         {\r
1168                                                 if (bAllowCheck)\r
1169                                                         entry->checked = true;\r
1170                                         }\r
1171                                         AddEntry(entry, langID, listIndex++);\r
1172                                 }\r
1173                         }\r
1174                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
1175                         {\r
1176                                 m_arListArray.push_back(i);\r
1177                                 if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1178                                 {\r
1179                                         if (bAllowCheck)\r
1180                                                 entry->checked = true;\r
1181                                 }\r
1182                                 AddEntry(entry, langID, listIndex++);\r
1183                         }\r
1184                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
1185                         {\r
1186                                 m_arListArray.push_back(i);\r
1187                                 if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1188                                 {\r
1189                                         if (bAllowCheck)\r
1190                                                 entry->checked = true;\r
1191                                 }\r
1192                                 AddEntry(entry, langID, listIndex++);\r
1193                         }\r
1194                 }\r
1195 #endif\r
1196         }\r
1197 \r
1198         SetItemCount(listIndex);\r
1199 \r
1200     m_ColumnManager.UpdateRelevance (m_arStatusArray, m_arListArray);\r
1201 \r
1202         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1203         for (int col = 0; col <= maxcol; col++)\r
1204         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1205 \r
1206     SetRedraw(TRUE);\r
1207         GetStatisticsString();\r
1208 \r
1209         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1210         HDITEM HeaderItem = {0};\r
1211         HeaderItem.mask = HDI_FORMAT;\r
1212         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1213         {\r
1214                 pHeader->GetItem(i, &HeaderItem);\r
1215                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1216                 pHeader->SetItem(i, &HeaderItem);\r
1217         }\r
1218         if (m_nSortedColumn)\r
1219         {\r
1220                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1221                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1222                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1223         }\r
1224 \r
1225         if (nSelectedEntry)\r
1226         {\r
1227                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1228                 EnsureVisible(nSelectedEntry, false);\r
1229         }\r
1230         else\r
1231         {\r
1232                 // Restore the item at the top of the list.\r
1233                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1234                 {\r
1235                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1236                         {\r
1237                                 break;\r
1238                         }\r
1239                 }\r
1240         }\r
1241 \r
1242         if (pApp)\r
1243                 pApp->DoWaitCursor(-1);\r
1244 \r
1245         m_bEmpty = (GetItemCount() == 0);\r
1246         Invalidate();\r
1247 #endif\r
1248 \r
1249 }\r
1250 \r
1251 void CGitStatusListCtrl::Show(DWORD dwShow, const CTGitPathList& checkedList, bool bShowFolders /* = true */)\r
1252 {\r
1253         return ;\r
1254 #if 0\r
1255 \r
1256         Locker lock(m_critSec);\r
1257         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
1258 \r
1259         CWinApp * pApp = AfxGetApp();\r
1260         if (pApp)\r
1261                 pApp->DoWaitCursor(1);\r
1262         m_dwShow = dwShow;\r
1263         m_bShowFolders = bShowFolders;\r
1264         m_nSelected = 0;\r
1265         int nTopIndex = GetTopIndex();\r
1266         POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
1267         int nSelectedEntry = 0;\r
1268         if (posSelectedEntry)\r
1269                 nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
1270         SetRedraw(FALSE);\r
1271         DeleteAllItems();\r
1272 \r
1273         PrepareGroups();\r
1274 \r
1275         m_arListArray.clear();\r
1276 \r
1277         m_arListArray.reserve(m_arStatusArray.size());\r
1278         SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
1279 \r
1280         int listIndex = 0;\r
1281         for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
1282         {\r
1283                 FileEntry * entry = m_arStatusArray[i];\r
1284                 if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
1285                         continue;\r
1286                 if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
1287                         continue;\r
1288                 if (entry->IsFolder() && (!bShowFolders))\r
1289                         continue;       // don't show folders if they're not wanted.\r
1290 #if 0\r
1291                 git_wc_status_kind status = SVNStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
1292                 DWORD showFlags = GetShowFlagsFromSVNStatus(status);\r
1293                 if (entry->IsLocked())\r
1294                         showFlags |= SVNSLC_SHOWLOCKS;\r
1295                 if (!entry->changelist.IsEmpty())\r
1296                         showFlags |= SVNSLC_SHOWINCHANGELIST;\r
1297 \r
1298                 // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
1299                 if (status != git_wc_status_ignored || (entry->direct) || (dwShow & SVNSLC_SHOWIGNORED))\r
1300                 {\r
1301                         for (int npath = 0; npath < checkedList.GetCount(); ++npath)\r
1302                         {\r
1303                                 if (entry->GetPath().IsEquivalentTo(checkedList[npath]))\r
1304                                 {\r
1305                                         entry->checked = true;\r
1306                                         break;\r
1307                                 }\r
1308                         }\r
1309                         if ((!entry->IsFolder()) && (status == git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
1310                         {\r
1311                                 if (PathFileExists(entry->GetPath().GetWinPath()))\r
1312                                 {\r
1313                                         m_arListArray.push_back(i);\r
1314                                         AddEntry(entry, langID, listIndex++);\r
1315                                 }\r
1316                         }\r
1317                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
1318                         {\r
1319                                 m_arListArray.push_back(i);\r
1320                                 AddEntry(entry, langID, listIndex++);\r
1321                         }\r
1322                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
1323                         {\r
1324                                 m_arListArray.push_back(i);\r
1325                                 AddEntry(entry, langID, listIndex++);\r
1326                         }\r
1327                         else if (entry->switched)\r
1328                         {\r
1329                                 m_arListArray.push_back(i);\r
1330                                 AddEntry(entry, langID, listIndex++);\r
1331                         }\r
1332                 }\r
1333 #endif\r
1334         }\r
1335 \r
1336         SetItemCount(listIndex);\r
1337 \r
1338         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1339         for (int col = 0; col <= maxcol; col++)\r
1340         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1341 \r
1342     SetRedraw(TRUE);\r
1343         GetStatisticsString();\r
1344 \r
1345         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1346         HDITEM HeaderItem = {0};\r
1347         HeaderItem.mask = HDI_FORMAT;\r
1348         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1349         {\r
1350                 pHeader->GetItem(i, &HeaderItem);\r
1351                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1352                 pHeader->SetItem(i, &HeaderItem);\r
1353         }\r
1354         if (m_nSortedColumn)\r
1355         {\r
1356                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1357                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1358                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1359         }\r
1360 \r
1361         if (nSelectedEntry)\r
1362         {\r
1363                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1364                 EnsureVisible(nSelectedEntry, false);\r
1365         }\r
1366         else\r
1367         {\r
1368                 // Restore the item at the top of the list.\r
1369                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1370                 {\r
1371                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1372                         {\r
1373                                 break;\r
1374                         }\r
1375                 }\r
1376         }\r
1377 \r
1378         if (pApp)\r
1379                 pApp->DoWaitCursor(-1);\r
1380 \r
1381         m_bEmpty = (GetItemCount() == 0);\r
1382         Invalidate();\r
1383 #endif\r
1384 \r
1385 }\r
1386 void CGitStatusListCtrl::AddEntry(CTGitPath * GitPath, WORD langID, int listIndex)\r
1387 {\r
1388         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
1389         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
1390 \r
1391         CString path = GitPath->GetGitPathString();\r
1392 \r
1393         m_bBlock = TRUE;\r
1394         TCHAR buf[100];\r
1395         int index = listIndex;\r
1396         int nCol = 1;\r
1397         CString entryname = GitPath->GetGitPathString();\r
1398         int icon_idx = 0;\r
1399 //      if (entry->isfolder)\r
1400 //              icon_idx = m_nIconFolder;\r
1401 //      else\r
1402         {\r
1403                 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(*GitPath);\r
1404         }\r
1405         // relative path\r
1406         InsertItem(index, entryname, icon_idx);\r
1407 \r
1408         this->SetItemData(index, (DWORD_PTR)GitPath);\r
1409         // SVNSLC_COLFILENAME\r
1410         SetItemText(index, nCol++, GitPath->GetFileOrDirectoryName());\r
1411         // SVNSLC_COLEXT\r
1412         SetItemText(index, nCol++, GitPath->GetFileExtension());\r
1413         // SVNSLC_COLSTATUS\r
1414 //      if (entry->isNested)\r
1415 //      {\r
1416 //              CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1417 //              SetItemText(index, nCol++, sTemp);\r
1418 //      }\r
1419 //      else\r
1420         {\r
1421                 SetItemText(index, nCol++, GitPath->GetActionName());\r
1422         }\r
1423         // SVNSLC_COLREMOTESTATUS\r
1424 //      if (entry->isNested)\r
1425 //      {\r
1426 //              CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1427 //              SetItemText(index, nCol++, sTemp);\r
1428 //      }\r
1429 //      else\r
1430         {\r
1431                 //SetItemText(index, nCol++, buf);\r
1432         }\r
1433         // SVNSLC_COLTEXTSTATUS\r
1434 //      if (entry->isNested)\r
1435 //      {\r
1436 //              CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1437 //              SetItemText(index, nCol++, sTemp);\r
1438 //      }\r
1439 //      else\r
1440 //      {\r
1441 #if 0\r
1442                 SVNStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1443                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1444                         _tcscat_s(buf, 100, _T(" (+)"));\r
1445                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1446                         _tcscat_s(buf, 100, _T(" (s)"));\r
1447 #endif\r
1448 //              SetItemText(index, nCol++, buf);\r
1449 //      }\r
1450         // SVNSLC_COLPROPSTATUS\r
1451 //      if (entry->isNested)\r
1452 //      {\r
1453 //              SetItemText(index, nCol++, _T(""));\r
1454 //      }\r
1455 //      else\r
1456 //      {\r
1457 #if 0\r
1458                 SVNStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1459                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1460                         _tcscat_s(buf, 100, _T(" (+)"));\r
1461                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1462                         _tcscat_s(buf, 100, _T(" (s)"));\r
1463 #endif\r
1464 //              SetItemText(index, nCol++, buf);\r
1465 //      }\r
1466         // SVNSLC_COLREMOTETEXT\r
1467 //      if (entry->isNested)\r
1468 //      {\r
1469 //              SetItemText(index, nCol++, _T(""));\r
1470 //      }\r
1471 //      else\r
1472 //      {\r
1473 #if 0\r
1474                 SVNStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1475                 SetItemText(index, nCol++, buf);\r
1476 #endif\r
1477 //      }\r
1478         // SVNSLC_COLREMOTEPROP\r
1479 //      if (entry->isNested)\r
1480 //      {\r
1481 //              SetItemText(index, nCol++, _T(""));\r
1482 //      }\r
1483 //      else\r
1484 //      {\r
1485 //              SVNStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1486 //              SetItemText(index, nCol++, buf);\r
1487 //      }\r
1488         // SVNSLC_COLURL\r
1489 //      SetItemText(index, nCol++, entry->url);\r
1490         // SVNSLC_COLLOCK\r
1491 #if 0\r
1492         if (!m_HeadRev.IsHead())\r
1493         {\r
1494                 // we have contacted the repository\r
1495 \r
1496                 // decision-matrix\r
1497                 // wc           repository              text\r
1498                 // ""           ""                              ""\r
1499                 // ""           UID1                    owner\r
1500                 // UID1         UID1                    owner\r
1501                 // UID1         ""                              lock has been broken\r
1502                 // UID1         UID2                    lock has been stolen\r
1503                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
1504                 {\r
1505                         if (entry->lock_owner.IsEmpty())\r
1506                                 SetItemText(index, nCol++, entry->lock_remoteowner);\r
1507                         else\r
1508                                 SetItemText(index, nCol++, entry->lock_owner);\r
1509                 }\r
1510                 else if (entry->lock_remotetoken.IsEmpty())\r
1511                 {\r
1512                         // broken lock\r
1513                         CString temp(MAKEINTRESOURCE(IDS_STATUSLIST_LOCKBROKEN));\r
1514                         SetItemText(index, nCol++, temp);\r
1515                 }\r
1516                 else\r
1517                 {\r
1518                         // stolen lock\r
1519                         CString temp;\r
1520                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
1521                         SetItemText(index, nCol++, temp);\r
1522                 }\r
1523         }\r
1524         else\r
1525                 SetItemText(index, nCol++, entry->lock_owner);\r
1526         // SVNSLC_COLLOCKCOMMENT\r
1527         SetItemText(index, nCol++, entry->lock_comment);\r
1528         // SVNSLC_COLAUTHOR\r
1529         SetItemText(index, nCol++, entry->last_commit_author);\r
1530         // SVNSLC_COLREVISION\r
1531         CString temp;\r
1532         temp.Format(_T("%ld"), entry->last_commit_rev);\r
1533         if (entry->last_commit_rev > 0)\r
1534                 SetItemText(index, nCol++, temp);\r
1535         else\r
1536                 SetItemText(index, nCol++, _T(""));\r
1537         // SVNSLC_COLREMOTEREVISION\r
1538         temp.Format(_T("%ld"), entry->remoterev);\r
1539         if (entry->remoterev > 0)\r
1540                 SetItemText(index, nCol++, temp);\r
1541         else\r
1542                 SetItemText(index, nCol++, _T(""));\r
1543         // SVNSLC_COLDATE\r
1544         TCHAR datebuf[SVN_DATE_BUFFER];\r
1545         apr_time_t date = entry->last_commit_date;\r
1546         SVN::formatDate(datebuf, date, true);\r
1547         if (date)\r
1548                 SetItemText(index, nCol++, datebuf);\r
1549         else\r
1550                 SetItemText(index, nCol++, _T(""));\r
1551         // SVNSLC_COLSVNNEEDSLOCK\r
1552     BOOL bFoundSVNNeedsLock = entry->present_props.IsNeedsLockSet();\r
1553         CString strSVNNeedsLock = (bFoundSVNNeedsLock) ? _T("*") : _T("");\r
1554         SetItemText(index, nCol++, strSVNNeedsLock);\r
1555         // SVNSLC_COLCOPYFROM\r
1556         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
1557                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
1558         else\r
1559                 temp = entry->copyfrom_url;\r
1560         SetItemText(index, nCol++, temp);\r
1561         // SVNSLC_COLMODIFICATIONDATE\r
1562         __int64 filetime = entry->GetPath().GetLastWriteTime();\r
1563         if ( (filetime) && (entry->status!=git_wc_status_deleted) )\r
1564         {\r
1565                 FILETIME* f = (FILETIME*)(__int64*)&filetime;\r
1566                 TCHAR datebuf[SVN_DATE_BUFFER];\r
1567                 SVN::formatDate(datebuf,*f,true);\r
1568                 SetItemText(index, nCol++, datebuf);\r
1569         }\r
1570         else\r
1571         {\r
1572                 SetItemText(index, nCol++, _T(""));\r
1573         }\r
1574 \r
1575     // user-defined properties\r
1576     for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
1577         ; i < count\r
1578         ; ++i)\r
1579     {\r
1580         assert (i == nCol++);\r
1581         assert (m_ColumnManager.IsUserProp (i));\r
1582 \r
1583         CString name = m_ColumnManager.GetName(i);\r
1584         if (entry->present_props.HasProperty (name))\r
1585                 {\r
1586                         const CString& propVal = entry->present_props [name];\r
1587                         if (propVal.IsEmpty())\r
1588                                 SetItemText(index, i, m_sNoPropValueText);\r
1589                         else\r
1590                                 SetItemText(index, i, propVal);\r
1591                 }\r
1592                 else\r
1593             SetItemText(index, i, _T(""));\r
1594     }\r
1595 #endif\r
1596         SetCheck(index, GitPath->m_Checked);\r
1597         if (GitPath->m_Checked)\r
1598                 m_nSelected++;\r
1599 \r
1600 //#if 0\r
1601 //      if (m_changelists.find(entry->changelist) != m_changelists.end())\r
1602 //              SetItemGroup(index, m_changelists[entry->changelist]);\r
1603 //      else\r
1604         if( GitPath->m_Action & CTGitPath::LOGACTIONS_IGNORE)\r
1605                 SetItemGroup(index, 2);\r
1606         else if( GitPath->m_Action & CTGitPath::LOGACTIONS_UNVER)\r
1607                 SetItemGroup(index,1);\r
1608         else\r
1609                 SetItemGroup(index,0);\r
1610         m_bBlock = FALSE;\r
1611 //#endif\r
1612 \r
1613 }\r
1614 #if 0\r
1615 void CGitStatusListCtrl::AddEntry(FileEntry * entry, WORD langID, int listIndex)\r
1616 {\r
1617         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
1618         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
1619 \r
1620         CString path = entry->GetPath().GetGitPathString();\r
1621         if ( m_mapFilenameToChecked.size()!=0 && m_mapFilenameToChecked.find(path) != m_mapFilenameToChecked.end() )\r
1622         {\r
1623                 // The user manually de-/selected an item. We now restore this status\r
1624                 // when refreshing.\r
1625                 entry->checked = m_mapFilenameToChecked[path];\r
1626         }\r
1627 \r
1628         m_bBlock = TRUE;\r
1629         TCHAR buf[100];\r
1630         int index = listIndex;\r
1631         int nCol = 1;\r
1632         CString entryname = entry->GetDisplayName();\r
1633         int icon_idx = 0;\r
1634         if (entry->isfolder)\r
1635                 icon_idx = m_nIconFolder;\r
1636         else\r
1637         {\r
1638                 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(entry->path);\r
1639         }\r
1640         // relative path\r
1641         InsertItem(index, entryname, icon_idx);\r
1642         // SVNSLC_COLFILENAME\r
1643         SetItemText(index, nCol++, entry->path.GetFileOrDirectoryName());\r
1644         // SVNSLC_COLEXT\r
1645         SetItemText(index, nCol++, entry->path.GetFileExtension());\r
1646         // SVNSLC_COLSTATUS\r
1647         if (entry->isNested)\r
1648         {\r
1649                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1650                 SetItemText(index, nCol++, sTemp);\r
1651         }\r
1652         else\r
1653         {\r
1654                 GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1655                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1656                         _tcscat_s(buf, 100, _T(" (+)"));\r
1657                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1658                         _tcscat_s(buf, 100, _T(" (s)"));\r
1659 #if 0\r
1660                 if ((entry->status == entry->propstatus)&&\r
1661                         (entry->status != git_wc_status_normal)&&\r
1662                         (entry->status != git_wc_status_unversioned)&&\r
1663                         (!GitStatus::IsImportant(entry->textstatus)))\r
1664                         _tcscat_s(buf, 100, ponly);\r
1665 #endif\r
1666                 SetItemText(index, nCol++, buf);\r
1667         }\r
1668         // SVNSLC_COLREMOTESTATUS\r
1669         if (entry->isNested)\r
1670         {\r
1671                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1672                 SetItemText(index, nCol++, sTemp);\r
1673         }\r
1674         else\r
1675         {\r
1676 #if 0\r
1677                 SVNStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1678                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1679                         _tcscat_s(buf, 100, _T(" (+)"));\r
1680                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1681                         _tcscat_s(buf, 100, _T(" (s)"));\r
1682                 if ((entry->remotestatus == entry->remotepropstatus)&&\r
1683                         (entry->remotestatus != git_wc_status_none)&&\r
1684                         (entry->remotestatus != git_wc_status_normal)&&\r
1685                         (entry->remotestatus != git_wc_status_unversioned)&&\r
1686                         (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
1687                         _tcscat_s(buf, 100, ponly);\r
1688 #endif\r
1689                 SetItemText(index, nCol++, buf);\r
1690         }\r
1691         // SVNSLC_COLTEXTSTATUS\r
1692         if (entry->isNested)\r
1693         {\r
1694                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1695                 SetItemText(index, nCol++, sTemp);\r
1696         }\r
1697         else\r
1698         {\r
1699 #if 0\r
1700                 SVNStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1701                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1702                         _tcscat_s(buf, 100, _T(" (+)"));\r
1703                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1704                         _tcscat_s(buf, 100, _T(" (s)"));\r
1705 #endif\r
1706                 SetItemText(index, nCol++, buf);\r
1707         }\r
1708         // SVNSLC_COLPROPSTATUS\r
1709         if (entry->isNested)\r
1710         {\r
1711                 SetItemText(index, nCol++, _T(""));\r
1712         }\r
1713         else\r
1714         {\r
1715 #if 0\r
1716                 SVNStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1717                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1718                         _tcscat_s(buf, 100, _T(" (+)"));\r
1719                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1720                         _tcscat_s(buf, 100, _T(" (s)"));\r
1721 #endif\r
1722                 SetItemText(index, nCol++, buf);\r
1723         }\r
1724         // SVNSLC_COLREMOTETEXT\r
1725         if (entry->isNested)\r
1726         {\r
1727                 SetItemText(index, nCol++, _T(""));\r
1728         }\r
1729         else\r
1730         {\r
1731 #if 0\r
1732                 SVNStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1733                 SetItemText(index, nCol++, buf);\r
1734 #endif\r
1735         }\r
1736         // SVNSLC_COLREMOTEPROP\r
1737         if (entry->isNested)\r
1738         {\r
1739                 SetItemText(index, nCol++, _T(""));\r
1740         }\r
1741         else\r
1742         {\r
1743 //              SVNStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1744                 SetItemText(index, nCol++, buf);\r
1745         }\r
1746         // SVNSLC_COLURL\r
1747 //      SetItemText(index, nCol++, entry->url);\r
1748         // SVNSLC_COLLOCK\r
1749 #if 0\r
1750         if (!m_HeadRev.IsHead())\r
1751         {\r
1752                 // we have contacted the repository\r
1753 \r
1754                 // decision-matrix\r
1755                 // wc           repository              text\r
1756                 // ""           ""                              ""\r
1757                 // ""           UID1                    owner\r
1758                 // UID1         UID1                    owner\r
1759                 // UID1         ""                              lock has been broken\r
1760                 // UID1         UID2                    lock has been stolen\r
1761                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
1762                 {\r
1763                         if (entry->lock_owner.IsEmpty())\r
1764                                 SetItemText(index, nCol++, entry->lock_remoteowner);\r
1765                         else\r
1766                                 SetItemText(index, nCol++, entry->lock_owner);\r
1767                 }\r
1768                 else if (entry->lock_remotetoken.IsEmpty())\r
1769                 {\r
1770                         // broken lock\r
1771                         CString temp(MAKEINTRESOURCE(IDS_STATUSLIST_LOCKBROKEN));\r
1772                         SetItemText(index, nCol++, temp);\r
1773                 }\r
1774                 else\r
1775                 {\r
1776                         // stolen lock\r
1777                         CString temp;\r
1778                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
1779                         SetItemText(index, nCol++, temp);\r
1780                 }\r
1781         }\r
1782         else\r
1783                 SetItemText(index, nCol++, entry->lock_owner);\r
1784         // SVNSLC_COLLOCKCOMMENT\r
1785         SetItemText(index, nCol++, entry->lock_comment);\r
1786         // SVNSLC_COLAUTHOR\r
1787         SetItemText(index, nCol++, entry->last_commit_author);\r
1788         // SVNSLC_COLREVISION\r
1789         CString temp;\r
1790         temp.Format(_T("%ld"), entry->last_commit_rev);\r
1791         if (entry->last_commit_rev > 0)\r
1792                 SetItemText(index, nCol++, temp);\r
1793         else\r
1794                 SetItemText(index, nCol++, _T(""));\r
1795         // SVNSLC_COLREMOTEREVISION\r
1796         temp.Format(_T("%ld"), entry->remoterev);\r
1797         if (entry->remoterev > 0)\r
1798                 SetItemText(index, nCol++, temp);\r
1799         else\r
1800                 SetItemText(index, nCol++, _T(""));\r
1801         // SVNSLC_COLDATE\r
1802         TCHAR datebuf[SVN_DATE_BUFFER];\r
1803         apr_time_t date = entry->last_commit_date;\r
1804         SVN::formatDate(datebuf, date, true);\r
1805         if (date)\r
1806                 SetItemText(index, nCol++, datebuf);\r
1807         else\r
1808                 SetItemText(index, nCol++, _T(""));\r
1809         // SVNSLC_COLSVNNEEDSLOCK\r
1810     BOOL bFoundSVNNeedsLock = entry->present_props.IsNeedsLockSet();\r
1811         CString strSVNNeedsLock = (bFoundSVNNeedsLock) ? _T("*") : _T("");\r
1812         SetItemText(index, nCol++, strSVNNeedsLock);\r
1813         // SVNSLC_COLCOPYFROM\r
1814         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
1815                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
1816         else\r
1817                 temp = entry->copyfrom_url;\r
1818         SetItemText(index, nCol++, temp);\r
1819         // SVNSLC_COLMODIFICATIONDATE\r
1820         __int64 filetime = entry->GetPath().GetLastWriteTime();\r
1821         if ( (filetime) && (entry->status!=git_wc_status_deleted) )\r
1822         {\r
1823                 FILETIME* f = (FILETIME*)(__int64*)&filetime;\r
1824                 TCHAR datebuf[SVN_DATE_BUFFER];\r
1825                 SVN::formatDate(datebuf,*f,true);\r
1826                 SetItemText(index, nCol++, datebuf);\r
1827         }\r
1828         else\r
1829         {\r
1830                 SetItemText(index, nCol++, _T(""));\r
1831         }\r
1832 \r
1833     // user-defined properties\r
1834     for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
1835         ; i < count\r
1836         ; ++i)\r
1837     {\r
1838         assert (i == nCol++);\r
1839         assert (m_ColumnManager.IsUserProp (i));\r
1840 \r
1841         CString name = m_ColumnManager.GetName(i);\r
1842         if (entry->present_props.HasProperty (name))\r
1843                 {\r
1844                         const CString& propVal = entry->present_props [name];\r
1845                         if (propVal.IsEmpty())\r
1846                                 SetItemText(index, i, m_sNoPropValueText);\r
1847                         else\r
1848                                 SetItemText(index, i, propVal);\r
1849                 }\r
1850                 else\r
1851             SetItemText(index, i, _T(""));\r
1852     }\r
1853 \r
1854         SetCheck(index, entry->checked);\r
1855         if (entry->checked)\r
1856                 m_nSelected++;\r
1857         if (m_changelists.find(entry->changelist) != m_changelists.end())\r
1858                 SetItemGroup(index, m_changelists[entry->changelist]);\r
1859         else\r
1860                 SetItemGroup(index, 0);\r
1861         m_bBlock = FALSE;\r
1862 #endif\r
1863 }\r
1864 #endif\r
1865 bool CGitStatusListCtrl::SetItemGroup(int item, int groupindex)\r
1866 {\r
1867         if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS) == NULL)\r
1868                 return false;\r
1869         if (groupindex < 0)\r
1870                 return false;\r
1871         LVITEM i = {0};\r
1872         i.mask = LVIF_GROUPID;\r
1873         i.iItem = item;\r
1874         i.iSubItem = 0;\r
1875         i.iGroupId = groupindex;\r
1876 \r
1877         return !!SetItem(&i);\r
1878 }\r
1879 \r
1880 void CGitStatusListCtrl::Sort()\r
1881 {\r
1882         Locker lock(m_critSec);\r
1883 \r
1884     CSorter predicate (&m_ColumnManager, m_nSortedColumn, m_bAscending);\r
1885 \r
1886         std::sort(m_arStatusArray.begin(), m_arStatusArray.end(), predicate);\r
1887         SaveColumnWidths();\r
1888         Show(m_dwShow, 0, m_bShowFolders);\r
1889 \r
1890 }\r
1891 \r
1892 void CGitStatusListCtrl::OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult)\r
1893 {\r
1894         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1895         *pResult = 0;\r
1896         if (m_bBlock)\r
1897                 return;\r
1898         m_bBlock = TRUE;\r
1899         if (m_nSortedColumn == phdr->iItem)\r
1900                 m_bAscending = !m_bAscending;\r
1901         else\r
1902                 m_bAscending = TRUE;\r
1903         m_nSortedColumn = phdr->iItem;\r
1904         m_mapFilenameToChecked.clear();\r
1905         Sort();\r
1906 \r
1907         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1908         HDITEM HeaderItem = {0};\r
1909         HeaderItem.mask = HDI_FORMAT;\r
1910         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1911         {\r
1912                 pHeader->GetItem(i, &HeaderItem);\r
1913                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1914                 pHeader->SetItem(i, &HeaderItem);\r
1915         }\r
1916         pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1917         HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1918         pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1919 \r
1920         // the checked state of the list control items must be restored\r
1921 \r
1922         for (int i=0; i<GetItemCount(); ++i)\r
1923         {\r
1924                 CTGitPath * entry = (CTGitPath*)GetItemData(i);\r
1925                 SetCheck(i, entry->m_Checked);\r
1926         }\r
1927 \r
1928         m_bBlock = FALSE;\r
1929 }\r
1930 \r
1931 void CGitStatusListCtrl::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
1932 {\r
1933         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1934         *pResult = 0;\r
1935 \r
1936 #define ISCHECKED(x) ((x) ? ((((x)&LVIS_STATEIMAGEMASK)>>12)-1) : FALSE)\r
1937         if ((m_bBlock)&&(m_bBlockUI))\r
1938         {\r
1939                 // if we're blocked, prevent changing of the check state\r
1940                 if ((!ISCHECKED(pNMLV->uOldState) && ISCHECKED(pNMLV->uNewState))||\r
1941                         (ISCHECKED(pNMLV->uOldState) && !ISCHECKED(pNMLV->uNewState)))\r
1942                         *pResult = TRUE;\r
1943         }\r
1944 }\r
1945 \r
1946 BOOL CGitStatusListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)\r
1947 {\r
1948         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1949         *pResult = 0;\r
1950         if ((pNMLV->uNewState==0)||(pNMLV->uNewState & LVIS_SELECTED)||(pNMLV->uNewState & LVIS_FOCUSED))\r
1951                 return FALSE;\r
1952 \r
1953         if (m_bBlock)\r
1954                 return FALSE;\r
1955 \r
1956         bool bSelected = !!(ListView_GetItemState(m_hWnd, pNMLV->iItem, LVIS_SELECTED) & LVIS_SELECTED);\r
1957         int nListItems = GetItemCount();\r
1958 \r
1959         m_bBlock = TRUE;\r
1960         // was the item checked?\r
1961         \r
1962         //CTGitPath *gitpath=(CTGitPath*)GetItemData(pNMLV->iItem);\r
1963         //gitpath->m_Checked=GetCheck(pNMLV->iItem);\r
1964 \r
1965         if (GetCheck(pNMLV->iItem))\r
1966         {\r
1967                 CheckEntry(pNMLV->iItem, nListItems);\r
1968                 if (bSelected)\r
1969                 {\r
1970                         POSITION pos = GetFirstSelectedItemPosition();\r
1971                         int index;\r
1972                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1973                         {\r
1974                                 if (index != pNMLV->iItem)\r
1975                                         CheckEntry(index, nListItems);\r
1976                         }\r
1977                 }\r
1978         }\r
1979         else\r
1980         {\r
1981                 UncheckEntry(pNMLV->iItem, nListItems);\r
1982                 if (bSelected)\r
1983                 {\r
1984                         POSITION pos = GetFirstSelectedItemPosition();\r
1985                         int index;\r
1986                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1987                         {\r
1988                                 if (index != pNMLV->iItem)\r
1989                                         UncheckEntry(index, nListItems);\r
1990                         }\r
1991                 }\r
1992         }\r
1993 \r
1994         GetStatisticsString();\r
1995         m_bBlock = FALSE;\r
1996         NotifyCheck();\r
1997 \r
1998         return FALSE;\r
1999 }\r
2000 \r
2001 void CGitStatusListCtrl::OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult)\r
2002 {\r
2003         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
2004     if (   (header != NULL) \r
2005         && (header->iItem >= 0) \r
2006         && (header->iItem < m_ColumnManager.GetColumnCount()))\r
2007     {\r
2008         m_ColumnManager.ColumnResized (header->iItem);\r
2009     }\r
2010 \r
2011     *pResult = FALSE;\r
2012 }\r
2013 \r
2014 void CGitStatusListCtrl::OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult)\r
2015 {\r
2016         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
2017         *pResult = TRUE;\r
2018     if (   (header != NULL) \r
2019         && (header->iItem >= 0) \r
2020         && (header->iItem < m_ColumnManager.GetColumnCount())\r
2021                 // only allow the reordering if the column was not moved left of the first\r
2022                 // visible item - otherwise the 'invisible' columns are not at the far left\r
2023                 // anymore and we get all kinds of redrawing problems.\r
2024                 && (header->pitem)\r
2025                 && (header->pitem->iOrder > m_ColumnManager.GetInvisibleCount()))\r
2026     {\r
2027         m_ColumnManager.ColumnMoved (header->iItem, header->pitem->iOrder);\r
2028                 *pResult = FALSE;\r
2029     }\r
2030 \r
2031     Invalidate(FALSE);\r
2032 }\r
2033 \r
2034 void CGitStatusListCtrl::CheckEntry(int index, int nListItems)\r
2035 {\r
2036         Locker lock(m_critSec);\r
2037         //FileEntry * entry = GetListEntry(index);\r
2038         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
2039         ASSERT(path != NULL);\r
2040         if (path == NULL)\r
2041                 return;\r
2042         SetCheck(index, TRUE);\r
2043         //entry = GetListEntry(index);\r
2044         // if an unversioned item was checked, then we need to check if\r
2045         // the parent folders are unversioned too. If the parent folders actually\r
2046         // are unversioned, then check those too.\r
2047 #if 0\r
2048         if (entry->status == git_wc_status_unversioned)\r
2049         {\r
2050                 // we need to check the parent folder too\r
2051                 const CTGitPath& folderpath = entry->path;\r
2052                 for (int i=0; i< nListItems; ++i)\r
2053                 {\r
2054                         FileEntry * testEntry = GetListEntry(i);\r
2055                         ASSERT(testEntry != NULL);\r
2056                         if (testEntry == NULL)\r
2057                                 continue;\r
2058                         if (!testEntry->checked)\r
2059                         {\r
2060                                 if (testEntry->path.IsAncestorOf(folderpath) && (!testEntry->path.IsEquivalentTo(folderpath)))\r
2061                                 {\r
2062                                         SetEntryCheck(testEntry,i,true);\r
2063                                         m_nSelected++;\r
2064                                 }\r
2065                         }\r
2066                 }\r
2067         }\r
2068         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
2069         if ( (entry->status == git_wc_status_deleted) || (m_bCheckChildrenWithParent) || (bShift) )\r
2070         {\r
2071                 // if a deleted folder gets checked, we have to check all\r
2072                 // children of that folder too.\r
2073                 if (entry->path.IsDirectory())\r
2074                 {\r
2075                         SetCheckOnAllDescendentsOf(entry, true);\r
2076                 }\r
2077 \r
2078                 // if a deleted file or folder gets checked, we have to\r
2079                 // check all parents of this item too.\r
2080                 for (int i=0; i<nListItems; ++i)\r
2081                 {\r
2082                         FileEntry * testEntry = GetListEntry(i);\r
2083                         ASSERT(testEntry != NULL);\r
2084                         if (testEntry == NULL)\r
2085                                 continue;\r
2086                         if (!testEntry->checked)\r
2087                         {\r
2088                                 if (testEntry->path.IsAncestorOf(entry->path) && (!testEntry->path.IsEquivalentTo(entry->path)))\r
2089                                 {\r
2090                                         if ((testEntry->status == git_wc_status_deleted)||(m_bCheckChildrenWithParent))\r
2091                                         {\r
2092                                                 SetEntryCheck(testEntry,i,true);\r
2093                                                 m_nSelected++;\r
2094                                                 // now we need to check all children of this parent folder\r
2095                                                 SetCheckOnAllDescendentsOf(testEntry, true);\r
2096                                         }\r
2097                                 }\r
2098                         }\r
2099                 }\r
2100         }\r
2101 #endif\r
2102         if ( !path->m_Checked )\r
2103         {\r
2104                 path->m_Checked = TRUE;\r
2105                 m_nSelected++;\r
2106         }\r
2107 }\r
2108 \r
2109 void CGitStatusListCtrl::UncheckEntry(int index, int nListItems)\r
2110 {\r
2111         Locker lock(m_critSec);\r
2112         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
2113         ASSERT(path != NULL);\r
2114         if (path == NULL)\r
2115                 return;\r
2116         SetCheck(index, FALSE);\r
2117         //entry = GetListEntry(index);\r
2118         // item was unchecked\r
2119 #if 0\r
2120         if (entry->path.IsDirectory())\r
2121         {\r
2122                 // disable all files within an unselected folder, except when unchecking a folder with property changes\r
2123                 bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
2124                 if ( (entry->status != git_wc_status_modified) || (bShift) )\r
2125                 {\r
2126                         SetCheckOnAllDescendentsOf(entry, false);\r
2127                 }\r
2128         }\r
2129         else if (entry->status == git_wc_status_deleted)\r
2130         {\r
2131                 // a "deleted" file was unchecked, so uncheck all parent folders\r
2132                 // and all children of those parents\r
2133                 for (int i=0; i<nListItems; i++)\r
2134                 {\r
2135                         FileEntry * testEntry = GetListEntry(i);\r
2136                         ASSERT(testEntry != NULL);\r
2137                         if (testEntry == NULL)\r
2138                                 continue;\r
2139                         if (testEntry->checked)\r
2140                         {\r
2141                                 if (testEntry->path.IsAncestorOf(entry->path))\r
2142                                 {\r
2143                                         if (testEntry->status == git_wc_status_deleted)\r
2144                                         {\r
2145                                                 SetEntryCheck(testEntry,i,false);\r
2146                                                 m_nSelected--;\r
2147 \r
2148                                                 SetCheckOnAllDescendentsOf(testEntry, false);\r
2149                                         }\r
2150                                 }\r
2151                         }\r
2152                 }\r
2153         }\r
2154 #endif\r
2155         if ( path->m_Checked )\r
2156         {\r
2157                 path->m_Checked  = FALSE;\r
2158                 m_nSelected--;\r
2159         }\r
2160 }\r
2161 \r
2162 bool CGitStatusListCtrl::EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2)\r
2163 {\r
2164         return pEntry1->path < pEntry2->path;\r
2165 }\r
2166 \r
2167 bool CGitStatusListCtrl::IsEntryVersioned(const FileEntry* pEntry1)\r
2168 {\r
2169         return pEntry1->status != git_wc_status_unversioned;\r
2170 }\r
2171 \r
2172 bool CGitStatusListCtrl::BuildStatistics()\r
2173 {\r
2174 #if 0\r
2175         bool bRefetchStatus = false;\r
2176         FileEntryVector::iterator itFirstUnversionedEntry;\r
2177         itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
2178         if (m_bUnversionedLast)\r
2179         {\r
2180                 // We partition the list of items so that it's arrange with all the versioned items first\r
2181                 // then all the unversioned items afterwards.\r
2182                 // Then we sort the versioned part of this, so that we can do quick look-ups in it\r
2183                 std::sort(m_arStatusArray.begin(), itFirstUnversionedEntry, EntryPathCompareNoCase);\r
2184                 // Also sort the unversioned section, to make the list look nice...\r
2185                 std::sort(itFirstUnversionedEntry, m_arStatusArray.end(), EntryPathCompareNoCase);\r
2186         }\r
2187 \r
2188         // now gather some statistics\r
2189         m_nUnversioned = 0;\r
2190         m_nNormal = 0;\r
2191         m_nModified = 0;\r
2192         m_nAdded = 0;\r
2193         m_nDeleted = 0;\r
2194         m_nConflicted = 0;\r
2195         m_nTotal = 0;\r
2196         m_nSelected = 0;\r
2197         for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2198         {\r
2199                 const FileEntry * entry = m_arStatusArray[i];\r
2200                 if (entry)\r
2201                 {\r
2202                         switch (entry->status)\r
2203                         {\r
2204                         case git_wc_status_normal:\r
2205                                 m_nNormal++;\r
2206                                 break;\r
2207                         case git_wc_status_added:\r
2208                                 m_nAdded++;\r
2209                                 break;\r
2210                         case git_wc_status_missing:\r
2211                         case git_wc_status_deleted:\r
2212                                 m_nDeleted++;\r
2213                                 break;\r
2214                         case git_wc_status_replaced:\r
2215                         case git_wc_status_modified:\r
2216                         case git_wc_status_merged:\r
2217                                 m_nModified++;\r
2218                                 break;\r
2219                         case git_wc_status_conflicted:\r
2220                         case git_wc_status_obstructed:\r
2221                                 m_nConflicted++;\r
2222                                 break;\r
2223                         case git_wc_status_ignored:\r
2224                                 m_nUnversioned++;\r
2225                                 break;\r
2226                         default:\r
2227 #if 0\r
2228                                 {\r
2229                                         if (GitStatus::IsImportant(entry->remotestatus))\r
2230                                                 break;\r
2231                                         m_nUnversioned++;\r
2232                                         // If an entry is in an unversioned folder, we don't have to do an expensive array search\r
2233                                         // to find out if it got case-renamed: an unversioned folder can't have versioned files\r
2234                                         // But nested folders are also considered to be in unversioned folders, we have to do the\r
2235                                         // check in that case too, otherwise we would miss case-renamed folders - they show up\r
2236                                         // as nested folders.\r
2237                                         if (((!entry->inunversionedfolder)||(entry->isNested))&&(m_bUnversionedLast))\r
2238                                         {\r
2239                                                 // check if the unversioned item is just\r
2240                                                 // a file differing in case but still versioned\r
2241                                                 FileEntryVector::iterator itMatchingItem;\r
2242                                                 if(std::binary_search(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase))\r
2243                                                 {\r
2244                                                         // We've confirmed that there *is* a matching file\r
2245                                                         // Find its exact location\r
2246                                                         FileEntryVector::iterator itMatchingItem;\r
2247                                                         itMatchingItem = std::lower_bound(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase);\r
2248 \r
2249                                                         // adjust the case of the filename\r
2250                                                         if (MoveFileEx(entry->path.GetWinPath(), (*itMatchingItem)->path.GetWinPath(), MOVEFILE_REPLACE_EXISTING))\r
2251                                                         {\r
2252                                                                 // We successfully adjusted the case in the filename. But there is now a file with status 'missing'\r
2253                                                                 // in the array, because that's the status of the file before we adjusted the case.\r
2254                                                                 // We have to refetch the status of that file.\r
2255                                                                 // Since fetching the status of single files/directories is very expensive and there can be\r
2256                                                                 // multiple case-renames here, we just set a flag and refetch the status at the end from scratch.\r
2257                                                                 bRefetchStatus = true;\r
2258                                                                 DeleteItem(i);\r
2259                                                                 m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
2260                                                                 delete entry;\r
2261                                                                 i--;\r
2262                                                                 m_nUnversioned--;\r
2263                                                                 // now that we removed an unversioned item from the array, find the first unversioned item in the 'new'\r
2264                                                                 // list again.\r
2265                                                                 itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
2266                                                         }\r
2267                                                         break;\r
2268                                                 }\r
2269                                         }\r
2270                                 }\r
2271 #endif\r
2272                                 break;\r
2273                         } // switch (entry->status)\r
2274                 } // if (entry)\r
2275         } // for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2276         return !bRefetchStatus;\r
2277 #endif \r
2278         return FALSE;\r
2279 }\r
2280 \r
2281 void CGitStatusListCtrl::GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly)\r
2282 {\r
2283 #if 0\r
2284         Locker lock(m_critSec);\r
2285         rMin = LONG_MAX;\r
2286         rMax = 0;\r
2287 \r
2288         if ((bShownOnly)||(bCheckedOnly))\r
2289         {\r
2290                 for (int i=0; i<GetItemCount(); ++i)\r
2291                 {\r
2292                         const FileEntry * entry = GetListEntry(i);\r
2293 \r
2294                         if ((entry)&&(entry->last_commit_rev))\r
2295                         {\r
2296                                 if ((!bCheckedOnly)||(entry->IsChecked()))\r
2297                                 {\r
2298                                         if (entry->last_commit_rev >= 0)\r
2299                                         {\r
2300                                                 rMin = min(rMin, entry->last_commit_rev);\r
2301                                                 rMax = max(rMax, entry->last_commit_rev);\r
2302                                         }\r
2303                                 }\r
2304                         }\r
2305                 }\r
2306         }\r
2307         else\r
2308         {\r
2309                 for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2310                 {\r
2311                         const FileEntry * entry = m_arStatusArray[i];\r
2312                         if ((entry)&&(entry->last_commit_rev))\r
2313                         {\r
2314                                 if (entry->last_commit_rev >= 0)\r
2315                                 {\r
2316                                         rMin = min(rMin, entry->last_commit_rev);\r
2317                                         rMax = max(rMax, entry->last_commit_rev);\r
2318                                 }\r
2319                         }\r
2320                 }\r
2321         }\r
2322         if (rMin == LONG_MAX)\r
2323                 rMin = 0;\r
2324 #endif\r
2325 }\r
2326 \r
2327 int CGitStatusListCtrl::GetGroupFromPoint(POINT * ppt)\r
2328 {\r
2329         // the point must be relative to the upper left corner of the control\r
2330 \r
2331         if (ppt == NULL)\r
2332                 return -1;\r
2333         if (!IsGroupViewEnabled())\r
2334                 return -1;\r
2335 \r
2336         POINT pt = *ppt;\r
2337         pt.x = 10;\r
2338         UINT flags = 0;\r
2339         int nItem = -1;\r
2340         RECT rc;\r
2341         GetWindowRect(&rc);\r
2342         while (((flags & LVHT_BELOW) == 0)&&(pt.y < rc.bottom))\r
2343         {\r
2344                 nItem = HitTest(pt, &flags);\r
2345                 if ((flags & LVHT_ONITEM)||(flags & LVHT_EX_GROUP_HEADER))\r
2346                 {\r
2347                         // the first item below the point\r
2348 \r
2349                         // check if the point is too much right (i.e. if the point\r
2350                         // is farther to the right than the width of the item)\r
2351                         RECT r;\r
2352                         GetItemRect(nItem, &r, LVIR_LABEL);\r
2353                         if (ppt->x > r.right)\r
2354                                 return -1;\r
2355 \r
2356                         LVITEM lv = {0};\r
2357                         lv.mask = LVIF_GROUPID;\r
2358                         lv.iItem = nItem;\r
2359                         GetItem(&lv);\r
2360                         int groupID = lv.iGroupId;\r
2361                         // now we search upwards and check if the item above this one\r
2362                         // belongs to another group. If it belongs to the same group,\r
2363                         // we're not over a group header\r
2364                         while (pt.y >= 0)\r
2365                         {\r
2366                                 pt.y -= 2;\r
2367                                 nItem = HitTest(pt, &flags);\r
2368                                 if ((flags & LVHT_ONITEM)&&(nItem >= 0))\r
2369                                 {\r
2370                                         // the first item below the point\r
2371                                         LVITEM lv = {0};\r
2372                                         lv.mask = LVIF_GROUPID;\r
2373                                         lv.iItem = nItem;\r
2374                                         GetItem(&lv);\r
2375                                         if (lv.iGroupId != groupID)\r
2376                                                 return groupID;\r
2377                                         else\r
2378                                                 return -1;\r
2379                                 }\r
2380                         }\r
2381                         if (pt.y < 0)\r
2382                                 return groupID;\r
2383                         return -1;\r
2384                 }\r
2385                 pt.y += 2;\r
2386         };\r
2387         return -1;\r
2388 }\r
2389 \r
2390 void CGitStatusListCtrl::OnContextMenuGroup(CWnd * /*pWnd*/, CPoint point)\r
2391 {\r
2392         POINT clientpoint = point;\r
2393         ScreenToClient(&clientpoint);\r
2394         if ((IsGroupViewEnabled())&&(GetGroupFromPoint(&clientpoint) >= 0))\r
2395         {\r
2396                 CMenu popup;\r
2397                 if (popup.CreatePopupMenu())\r
2398                 {\r
2399                         CString temp;\r
2400                         temp.LoadString(IDS_STATUSLIST_CHECKGROUP);\r
2401                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CHECKGROUP, temp);\r
2402                         temp.LoadString(IDS_STATUSLIST_UNCHECKGROUP);\r
2403                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_UNCHECKGROUP, temp);\r
2404                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2405                         bool bCheck = false;\r
2406                         switch (cmd)\r
2407                         {\r
2408                         case IDSVNLC_CHECKGROUP:\r
2409                                 bCheck = true;\r
2410                                 // fall through here\r
2411                         case IDSVNLC_UNCHECKGROUP:\r
2412                                 {\r
2413                                         int group = GetGroupFromPoint(&clientpoint);\r
2414                                         // go through all items and check/uncheck those assigned to the group\r
2415                                         // but block the OnLvnItemChanged handler\r
2416                                         m_bBlock = true;\r
2417                                         LVITEM lv;\r
2418                                         for (int i=0; i<GetItemCount(); ++i)\r
2419                                         {\r
2420                                                 SecureZeroMemory(&lv, sizeof(LVITEM));\r
2421                                                 lv.mask = LVIF_GROUPID;\r
2422                                                 lv.iItem = i;\r
2423                                                 GetItem(&lv);\r
2424                                                 if (lv.iGroupId == group)\r
2425                                                 {\r
2426                                                         FileEntry * entry = GetListEntry(i);\r
2427                                                         if (entry)\r
2428                                                         {\r
2429                                                                 bool bOldCheck = !!GetCheck(i);\r
2430                                                                 //SetEntryCheck(entry, i, bCheck);\r
2431                                                                 if (bCheck != bOldCheck)\r
2432                                                                 {\r
2433                                                                         if (bCheck)\r
2434                                                                                 m_nSelected++;\r
2435                                                                         else\r
2436                                                                                 m_nSelected--;\r
2437                                                                 }\r
2438                                                         }\r
2439                                                 }\r
2440                                         }\r
2441                                         GetStatisticsString();\r
2442                                         NotifyCheck();\r
2443                                         m_bBlock = false;\r
2444                                 }\r
2445                                 break;\r
2446                         }\r
2447                 }\r
2448         }\r
2449 }\r
2450 \r
2451 void CGitStatusListCtrl::OnContextMenuList(CWnd * pWnd, CPoint point)\r
2452 {\r
2453 \r
2454         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
2455 \r
2456         bool XPorLater = false;\r
2457         OSVERSIONINFOEX inf;\r
2458         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
2459         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
2460         GetVersionEx((OSVERSIONINFO *)&inf);\r
2461         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
2462         if (fullver >= 0x0501)\r
2463                 XPorLater = true;\r
2464         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
2465         CTGitPath * filepath;\r
2466 \r
2467         int selIndex = GetSelectionMark();\r
2468         if ((point.x == -1) && (point.y == -1))\r
2469         {\r
2470                 CRect rect;\r
2471                 GetItemRect(selIndex, &rect, LVIR_LABEL);\r
2472                 ClientToScreen(&rect);\r
2473                 point = rect.CenterPoint();\r
2474         }\r
2475         if ((GetSelectedCount() == 0)&&(XPorLater)&&(m_bHasCheckboxes))\r
2476         {\r
2477                 // nothing selected could mean the context menu is requested for\r
2478                 // a group header\r
2479                 OnContextMenuGroup(pWnd, point);\r
2480         }\r
2481         else if (selIndex >= 0)\r
2482         {\r
2483                 //FileEntry * entry = GetListEntry(selIndex);\r
2484 \r
2485                 filepath = (CTGitPath * )GetItemData(selIndex);\r
2486 \r
2487                 ASSERT(filepath != NULL);\r
2488                 if (filepath == NULL)\r
2489                         return;\r
2490 \r
2491                 //const CTGitPath& filepath = entry->path;\r
2492                 int wcStatus = filepath->m_Action;\r
2493                 // entry is selected, now show the popup menu\r
2494                 Locker lock(m_critSec);\r
2495                 CIconMenu popup;\r
2496                 CMenu changelistSubMenu;\r
2497                 CMenu ignoreSubMenu;\r
2498                 if (popup.CreatePopupMenu())\r
2499                 {\r
2500                         //Add Menu for verion controled file\r
2501                         if (!(wcStatus &CTGitPath::LOGACTIONS_UNVER))\r
2502                         {\r
2503                                 if (m_dwContextMenus & SVNSLC_POPCOMPAREWITHBASE)\r
2504                                 {\r
2505                                         popup.AppendMenuIcon(IDSVNLC_COMPARE, IDS_LOG_COMPAREWITHBASE, IDI_DIFF);\r
2506                                         popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2507                                 }\r
2508                                 //Select one items\r
2509                                 if (GetSelectedCount() == 1)\r
2510                                 {\r
2511                                         bool bEntryAdded = false;\r
2512                                         //if (entry->remotestatus <= git_wc_status_normal)\r
2513                                         //{\r
2514                                         //      if (wcStatus > git_wc_status_normal)\r
2515                                         //      {\r
2516                                         //              if ((m_dwContextMenus & SVNSLC_POPGNUDIFF)&&(wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing))\r
2517                                         //              {\r
2518                                         popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2519                                         bEntryAdded = true;\r
2520                                         //              }\r
2521                                         //      }\r
2522                                         //\r
2523                                         //}\r
2524                                         //else if (wcStatus != git_wc_status_deleted)\r
2525                                         //{\r
2526                                         //      if (m_dwContextMenus & SVNSLC_POPCOMPARE)\r
2527                                         //      {\r
2528                                         //              popup.AppendMenuIcon(IDSVNLC_COMPAREWC, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
2529                                         //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2530                                         //              bEntryAdded = true;\r
2531                                         //      }\r
2532                                         //      if (m_dwContextMenus & SVNSLC_POPGNUDIFF)\r
2533                                         //      {\r
2534                                         //              popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2535                                         //              bEntryAdded = true;\r
2536                                         //      }\r
2537                                         //}\r
2538                                         if (bEntryAdded)\r
2539                                                 popup.AppendMenu(MF_SEPARATOR);\r
2540                                 }\r
2541                                 //else if (GetSelectedCount() > 1)  \r
2542                                 //{\r
2543                                 //      if (m_dwContextMenus & SVNSLC_POPCOMMIT)\r
2544                                 //      {\r
2545                                 //              popup.AppendMenuIcon(IDSVNLC_COMMIT, IDS_STATUSLIST_CONTEXT_COMMIT, IDI_COMMIT);\r
2546                                 //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2547                                 //      }\r
2548                                 //}\r
2549                         }\r
2550                         \r
2551                         ///Select Multi item\r
2552                         //if (GetSelectedCount() > 0)\r
2553                         //{\r
2554                         //      if ((GetSelectedCount() == 2)&&(m_dwContextMenus & SVNSLC_POPREPAIRMOVE))\r
2555                         //      {\r
2556                         //              POSITION pos = GetFirstSelectedItemPosition();\r
2557                         //              int index = GetNextSelectedItem(pos);\r
2558                         //              if (index >= 0)\r
2559                         //              {\r
2560                         //                      FileEntry * entry = GetListEntry(index);\r
2561                         //                      git_wc_status_kind status1 = git_wc_status_none;\r
2562                         //                      git_wc_status_kind status2 = git_wc_status_none;\r
2563                         //                      if (entry)\r
2564                         //                              status1 = entry->status;\r
2565                         //                      index = GetNextSelectedItem(pos);\r
2566                         //                      if (index >= 0)\r
2567                         //                      {\r
2568                         //                              entry = GetListEntry(index);\r
2569                         //                              if (entry)\r
2570                         //                                      status2 = entry->status;\r
2571                         //                              if ((status1 == git_wc_status_missing && status2 == git_wc_status_unversioned) ||\r
2572                         //                                      (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned))\r
2573                         //                              {\r
2574                         //                                      popup.AppendMenuIcon(IDSVNLC_REPAIRMOVE, IDS_STATUSLIST_CONTEXT_REPAIRMOVE);\r
2575                         //                              }\r
2576                         //                      }\r
2577                         //              }\r
2578                         //      }\r
2579                         //      if (wcStatus > git_wc_status_normal)\r
2580                         //      {\r
2581                         //              if (m_dwContextMenus & SVNSLC_POPREVERT)\r
2582                         //              {\r
2583                         //                      // reverting missing folders is not possible\r
2584                         //                      if (!entry->IsFolder() || (wcStatus != git_wc_status_missing))\r
2585                         //                      {\r
2586                         //                              popup.AppendMenuIcon(IDSVNLC_REVERT, IDS_MENUREVERT, IDI_REVERT);\r
2587                         //                      }\r
2588                         //              }\r
2589                         //      }\r
2590                         //      if (entry->remotestatus > git_wc_status_normal)\r
2591                         //      {\r
2592                         //              if (m_dwContextMenus & SVNSLC_POPUPDATE)\r
2593                         //              {\r
2594                         //                      popup.AppendMenuIcon(IDSVNLC_UPDATE, IDS_MENUUPDATE, IDI_UPDATE);\r
2595                         //              }\r
2596                         //      }\r
2597                         //}\r
2598                         if ((GetSelectedCount() == 1)&&(!wcStatus & CTGitPath::LOGACTIONS_UNVER)\r
2599                                 &&(!wcStatus & CTGitPath::LOGACTIONS_IGNORE))\r
2600                         {\r
2601                                 if (m_dwContextMenus & SVNSLC_POPSHOWLOG)\r
2602                                 {\r
2603                                         popup.AppendMenuIcon(IDSVNLC_LOG, IDS_REPOBROWSE_SHOWLOG, IDI_LOG);\r
2604                                 }\r
2605 //                              if (m_dwContextMenus & SVNSLC_POPBLAME)\r
2606 //                              {\r
2607 //                                      popup.AppendMenuIcon(IDSVNLC_BLAME, IDS_MENUBLAME, IDI_BLAME);\r
2608 //                              }\r
2609                         }\r
2610 //                      if ((wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing) && (GetSelectedCount() == 1))\r
2611 //                      {\r
2612                                 if (m_dwContextMenus & SVNSLC_POPOPEN)\r
2613                                 {\r
2614                                         popup.AppendMenuIcon(IDSVNLC_OPEN, IDS_REPOBROWSE_OPEN, IDI_OPEN);\r
2615                                         popup.AppendMenuIcon(IDSVNLC_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
2616                                 }\r
2617                                 if (m_dwContextMenus & SVNSLC_POPEXPLORE)\r
2618                                 {\r
2619                                         popup.AppendMenuIcon(IDSVNLC_EXPLORE, IDS_STATUSLIST_CONTEXT_EXPLORE, IDI_EXPLORER);\r
2620                                 }\r
2621 //                      }\r
2622                         if (GetSelectedCount() > 0)\r
2623                         {\r
2624 //                              if (((wcStatus == git_wc_status_unversioned)||(wcStatus == git_wc_status_ignored))&&(m_dwContextMenus & SVNSLC_POPDELETE))\r
2625 //                              {\r
2626 //                                      popup.AppendMenuIcon(IDSVNLC_DELETE, IDS_MENUREMOVE, IDI_DELETE);\r
2627 //                              }\r
2628 //                              if ((wcStatus != Git_wc_status_unversioned)&&(wcStatus != git_wc_status_ignored)&&(wcStatus != Git_wc_status_deleted)&&(wcStatus != Git_wc_status_added)&&(m_dwContextMenus & GitSLC_POPDELETE))\r
2629 //                              {\r
2630 //                                      if (bShift)\r
2631 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVEKEEP, IDI_DELETE);\r
2632 //                                      else\r
2633 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVE, IDI_DELETE);\r
2634 //                              }\r
2635                                 if ((wcStatus & CTGitPath::LOGACTIONS_UNVER)/*||(wcStatus == git_wc_status_deleted)*/)\r
2636                                 {\r
2637                                         if (m_dwContextMenus & SVNSLC_POPADD)\r
2638                                         {\r
2639                                                 //if ( entry->IsFolder() )\r
2640                                                 //{\r
2641                                                 //      popup.AppendMenuIcon(IDSVNLC_ADD_RECURSIVE, IDS_STATUSLIST_CONTEXT_ADD_RECURSIVE, IDI_ADD);\r
2642                                                 //}\r
2643                                                 //else\r
2644                                                 {\r
2645                                                         popup.AppendMenuIcon(IDSVNLC_ADD, IDS_STATUSLIST_CONTEXT_ADD, IDI_ADD);\r
2646                                                 }\r
2647                                         }\r
2648                                 //}\r
2649                                 //if ( (wcStatus == git_wc_status_unversioned) || (wcStatus == git_wc_status_deleted) )\r
2650                                 //{\r
2651                                         if (m_dwContextMenus & SVNSLC_POPIGNORE)\r
2652                                         {\r
2653 \r
2654                                                 CTGitPathList ignorelist;\r
2655                                                 FillListOfSelectedItemPaths(ignorelist);\r
2656                                                 //check if all selected entries have the same extension\r
2657                                                 bool bSameExt = true;\r
2658                                                 CString sExt;\r
2659                                                 for (int i=0; i<ignorelist.GetCount(); ++i)\r
2660                                                 {\r
2661                                                         if (sExt.IsEmpty() && (i==0))\r
2662                                                                 sExt = ignorelist[i].GetFileExtension();\r
2663                                                         else if (sExt.CompareNoCase(ignorelist[i].GetFileExtension())!=0)\r
2664                                                                 bSameExt = false;\r
2665                                                 }\r
2666                                                 if (bSameExt)\r
2667                                                 {\r
2668                                                         if (ignoreSubMenu.CreateMenu())\r
2669                                                         {\r
2670                                                                 CString ignorepath;\r
2671                                                                 if (ignorelist.GetCount()==1)\r
2672                                                                         ignorepath = ignorelist[0].GetFileOrDirectoryName();\r
2673                                                                 else\r
2674                                                                         ignorepath.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2675                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNORE, ignorepath);\r
2676                                                                 ignorepath = _T("*")+sExt;\r
2677                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNOREMASK, ignorepath);\r
2678                                                                 CString temp;\r
2679                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2680                                                                 popup.InsertMenu((UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)ignoreSubMenu.m_hMenu, temp);\r
2681                                                         }\r
2682                                                 }\r
2683                                                 else\r
2684                                                 {\r
2685                                                         CString temp;\r
2686                                                         if (ignorelist.GetCount()==1)\r
2687                                                         {\r
2688                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2689                                                         }\r
2690                                                         else\r
2691                                                         {\r
2692                                                                 temp.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2693                                                         }\r
2694                                                         popup.AppendMenuIcon(IDSVNLC_IGNORE, temp, IDI_IGNORE);\r
2695                                                 }\r
2696                                         }\r
2697                                 }\r
2698                         }\r
2699 #if 0\r
2700                         if (((wcStatus == git_wc_status_conflicted)||(entry->isConflicted)))\r
2701                         {\r
2702                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)||(m_dwContextMenus & SVNSLC_POPRESOLVE))\r
2703                                         popup.AppendMenu(MF_SEPARATOR);\r
2704 \r
2705                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)&&(entry->textstatus == git_wc_status_conflicted))\r
2706                                 {\r
2707                                         popup.AppendMenuIcon(IDSVNLC_EDITCONFLICT, IDS_MENUCONFLICT, IDI_CONFLICT);\r
2708                                 }\r
2709                                 if (m_dwContextMenus & SVNSLC_POPRESOLVE)\r
2710                                 {\r
2711                                         popup.AppendMenuIcon(IDSVNLC_RESOLVECONFLICT, IDS_STATUSLIST_CONTEXT_RESOLVED, IDI_RESOLVE);\r
2712                                 }\r
2713                                 if ((m_dwContextMenus & SVNSLC_POPRESOLVE)&&(entry->textstatus == git_wc_status_conflicted))\r
2714                                 {\r
2715                                         popup.AppendMenuIcon(IDSVNLC_RESOLVETHEIRS, IDS_SVNPROGRESS_MENUUSETHEIRS, IDI_RESOLVE);\r
2716                                         popup.AppendMenuIcon(IDSVNLC_RESOLVEMINE, IDS_SVNPROGRESS_MENUUSEMINE, IDI_RESOLVE);\r
2717                                 }\r
2718                         }\r
2719 #endif\r
2720 #if 0                   \r
2721                         if (GetSelectedCount() > 0)\r
2722                         {\r
2723 \r
2724                                 if ((!entry->IsFolder())&&(wcStatus >= git_wc_status_normal)\r
2725                                         &&(wcStatus!=git_wc_status_missing)&&(wcStatus!=git_wc_status_deleted)\r
2726                                         &&(wcStatus!=git_wc_status_added))\r
2727                                 {\r
2728                                         popup.AppendMenu(MF_SEPARATOR);\r
2729                                         if ((entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2730                                         {\r
2731                                                 if (m_dwContextMenus & SVNSLC_POPLOCK)\r
2732                                                 {\r
2733                                                         popup.AppendMenuIcon(IDSVNLC_LOCK, IDS_MENU_LOCK, IDI_LOCK);\r
2734                                                 }\r
2735                                         }\r
2736                                         if ((!entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2737                                         {\r
2738                                                 if (m_dwContextMenus & SVNSLC_POPUNLOCK)\r
2739                                                 {\r
2740                                                         popup.AppendMenuIcon(IDSVNLC_UNLOCK, IDS_MENU_UNLOCK, IDI_UNLOCK);\r
2741                                                 }\r
2742                                         }\r
2743                                 }\r
2744 \r
2745                                 if ((!entry->IsFolder())&&((!entry->lock_token.IsEmpty())||(!entry->lock_remotetoken.IsEmpty())))\r
2746                                 {\r
2747                                         if (m_dwContextMenus & SVNSLC_POPUNLOCKFORCE)\r
2748                                         {\r
2749                                                 popup.AppendMenuIcon(IDSVNLC_UNLOCKFORCE, IDS_MENU_UNLOCKFORCE, IDI_UNLOCK);\r
2750                                         }\r
2751                                 }\r
2752 \r
2753                                 if (wcStatus != git_wc_status_missing && wcStatus != git_wc_status_deleted &&wcStatus!=git_wc_status_unversioned)\r
2754                                 {\r
2755                                         popup.AppendMenu(MF_SEPARATOR);\r
2756                                         popup.AppendMenuIcon(IDSVNLC_PROPERTIES, IDS_STATUSLIST_CONTEXT_PROPERTIES, IDI_PROPERTIES);\r
2757                                 }\r
2758                                 popup.AppendMenu(MF_SEPARATOR);\r
2759                                 popup.AppendMenuIcon(IDSVNLC_COPY, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);\r
2760                                 popup.AppendMenuIcon(IDSVNLC_COPYEXT, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);\r
2761                                 if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS)&&(XPorLater)\r
2762                                         &&(wcStatus != git_wc_status_unversioned)&&(wcStatus != git_wc_status_none))\r
2763                                 {\r
2764                                         popup.AppendMenu(MF_SEPARATOR);\r
2765                                         // changelist commands\r
2766                                         size_t numChangelists = GetNumberOfChangelistsInSelection();\r
2767                                         if (numChangelists > 0)\r
2768                                         {\r
2769                                                 popup.AppendMenuIcon(IDSVNLC_REMOVEFROMCS, IDS_STATUSLIST_CONTEXT_REMOVEFROMCS);\r
2770                                         }\r
2771                                         if ((!entry->IsFolder())&&(changelistSubMenu.CreateMenu()))\r
2772                                         {\r
2773                                                 CString temp;\r
2774                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_CREATECS);\r
2775                                                 changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATECS, temp);\r
2776 \r
2777                                                 if (entry->changelist.Compare(SVNSLC_IGNORECHANGELIST))\r
2778                                                 {\r
2779                                                         changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2780                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATEIGNORECS, SVNSLC_IGNORECHANGELIST);\r
2781                                                 }\r
2782 \r
2783                                                 if (m_changelists.size() > 0)\r
2784                                                 {\r
2785                                                         // find the changelist names\r
2786                                                         bool bNeedSeparator = true;\r
2787                                                         int cmdID = IDSVNLC_MOVETOCS;\r
2788                                                         for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
2789                                                         {\r
2790                                                                 if ((entry->changelist.Compare(it->first))&&(it->first.Compare(SVNSLC_IGNORECHANGELIST)))\r
2791                                                                 {\r
2792                                                                         if (bNeedSeparator)\r
2793                                                                         {\r
2794                                                                                 changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2795                                                                                 bNeedSeparator = false;\r
2796                                                                         }\r
2797                                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, cmdID, it->first);\r
2798                                                                         cmdID++;\r
2799                                                                 }\r
2800                                                         }\r
2801                                                 }\r
2802                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_MOVETOCS);\r
2803                                                 popup.AppendMenu(MF_POPUP|MF_STRING, (UINT_PTR)changelistSubMenu.GetSafeHmenu(), temp);\r
2804                                    &n