OSDN Git Service

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