OSDN Git Service

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