OSDN Git Service

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