OSDN Git Service

1055bb3ed57e7aa30ddf15cbd2577c4af000e030
[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         CString rename;\r
1446         rename.Format(_T("(from %s)"),GitPath->GetGitOldPathString());\r
1447         if(GitPath->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
1448                 entryname+=rename;\r
1449         \r
1450         InsertItem(index, entryname, icon_idx);\r
1451 \r
1452         this->SetItemData(index, (DWORD_PTR)GitPath);\r
1453         // SVNSLC_COLFILENAME\r
1454         SetItemText(index, nCol++, GitPath->GetFileOrDirectoryName());\r
1455         // SVNSLC_COLEXT\r
1456         SetItemText(index, nCol++, GitPath->GetFileExtension());\r
1457         // SVNSLC_COLSTATUS\r
1458         SetItemText(index, nCol++, GitPath->GetActionName());\r
1459 \r
1460         SetItemText(index, GetColumnIndex(SVNSLC_COLADD),GitPath->m_StatAdd);\r
1461         SetItemText(index, GetColumnIndex(SVNSLC_COLDEL),GitPath->m_StatDel);\r
1462 \r
1463 \r
1464         SetCheck(index, GitPath->m_Checked);\r
1465         if (GitPath->m_Checked)\r
1466                 m_nSelected++;\r
1467 \r
1468 \r
1469         if( GitPath->m_Action & CTGitPath::LOGACTIONS_IGNORE)\r
1470                 SetItemGroup(index, 2);\r
1471         else if( GitPath->m_Action & CTGitPath::LOGACTIONS_UNVER)\r
1472                 SetItemGroup(index,1);\r
1473         else\r
1474                 SetItemGroup(index,0);\r
1475         m_bBlock = FALSE;\r
1476 \r
1477 \r
1478 }\r
1479 #if 0\r
1480 void CGitStatusListCtrl::AddEntry(FileEntry * entry, WORD langID, int listIndex)\r
1481 {\r
1482         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
1483         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
1484 \r
1485         CString path = entry->GetPath().GetGitPathString();\r
1486         if ( m_mapFilenameToChecked.size()!=0 && m_mapFilenameToChecked.find(path) != m_mapFilenameToChecked.end() )\r
1487         {\r
1488                 // The user manually de-/selected an item. We now restore this status\r
1489                 // when refreshing.\r
1490                 entry->checked = m_mapFilenameToChecked[path];\r
1491         }\r
1492 \r
1493         m_bBlock = TRUE;\r
1494         TCHAR buf[100];\r
1495         int index = listIndex;\r
1496         int nCol = 1;\r
1497         CString entryname = entry->GetDisplayName();\r
1498         int icon_idx = 0;\r
1499         if (entry->isfolder)\r
1500                 icon_idx = m_nIconFolder;\r
1501         else\r
1502         {\r
1503                 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(entry->path);\r
1504         }\r
1505         // relative path\r
1506         InsertItem(index, entryname, icon_idx);\r
1507         // SVNSLC_COLFILENAME\r
1508         SetItemText(index, nCol++, entry->path.GetFileOrDirectoryName());\r
1509         // SVNSLC_COLEXT\r
1510         SetItemText(index, nCol++, entry->path.GetFileExtension());\r
1511         // SVNSLC_COLSTATUS\r
1512         if (entry->isNested)\r
1513         {\r
1514                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1515                 SetItemText(index, nCol++, sTemp);\r
1516         }\r
1517         else\r
1518         {\r
1519                 GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1520                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1521                         _tcscat_s(buf, 100, _T(" (+)"));\r
1522                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1523                         _tcscat_s(buf, 100, _T(" (s)"));\r
1524 #if 0\r
1525                 if ((entry->status == entry->propstatus)&&\r
1526                         (entry->status != git_wc_status_normal)&&\r
1527                         (entry->status != git_wc_status_unversioned)&&\r
1528                         (!GitStatus::IsImportant(entry->textstatus)))\r
1529                         _tcscat_s(buf, 100, ponly);\r
1530 #endif\r
1531                 SetItemText(index, nCol++, buf);\r
1532         }\r
1533         // SVNSLC_COLREMOTESTATUS\r
1534         if (entry->isNested)\r
1535         {\r
1536                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1537                 SetItemText(index, nCol++, sTemp);\r
1538         }\r
1539         else\r
1540         {\r
1541 #if 0\r
1542                 SVNStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1543                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1544                         _tcscat_s(buf, 100, _T(" (+)"));\r
1545                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1546                         _tcscat_s(buf, 100, _T(" (s)"));\r
1547                 if ((entry->remotestatus == entry->remotepropstatus)&&\r
1548                         (entry->remotestatus != git_wc_status_none)&&\r
1549                         (entry->remotestatus != git_wc_status_normal)&&\r
1550                         (entry->remotestatus != git_wc_status_unversioned)&&\r
1551                         (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
1552                         _tcscat_s(buf, 100, ponly);\r
1553 #endif\r
1554                 SetItemText(index, nCol++, buf);\r
1555         }\r
1556         // SVNSLC_COLTEXTSTATUS\r
1557         if (entry->isNested)\r
1558         {\r
1559                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1560                 SetItemText(index, nCol++, sTemp);\r
1561         }\r
1562         else\r
1563         {\r
1564 #if 0\r
1565                 SVNStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1566                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1567                         _tcscat_s(buf, 100, _T(" (+)"));\r
1568                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1569                         _tcscat_s(buf, 100, _T(" (s)"));\r
1570 #endif\r
1571                 SetItemText(index, nCol++, buf);\r
1572         }\r
1573         // SVNSLC_COLPROPSTATUS\r
1574         if (entry->isNested)\r
1575         {\r
1576                 SetItemText(index, nCol++, _T(""));\r
1577         }\r
1578         else\r
1579         {\r
1580 #if 0\r
1581                 SVNStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1582                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1583                         _tcscat_s(buf, 100, _T(" (+)"));\r
1584                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1585                         _tcscat_s(buf, 100, _T(" (s)"));\r
1586 #endif\r
1587                 SetItemText(index, nCol++, buf);\r
1588         }\r
1589         // SVNSLC_COLREMOTETEXT\r
1590         if (entry->isNested)\r
1591         {\r
1592                 SetItemText(index, nCol++, _T(""));\r
1593         }\r
1594         else\r
1595         {\r
1596 #if 0\r
1597                 SVNStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1598                 SetItemText(index, nCol++, buf);\r
1599 #endif\r
1600         }\r
1601         // SVNSLC_COLREMOTEPROP\r
1602         if (entry->isNested)\r
1603         {\r
1604                 SetItemText(index, nCol++, _T(""));\r
1605         }\r
1606         else\r
1607         {\r
1608 //              SVNStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1609                 SetItemText(index, nCol++, buf);\r
1610         }\r
1611         // SVNSLC_COLURL\r
1612 //      SetItemText(index, nCol++, entry->url);\r
1613         // SVNSLC_COLLOCK\r
1614 #if 0\r
1615         if (!m_HeadRev.IsHead())\r
1616         {\r
1617                 // we have contacted the repository\r
1618 \r
1619                 // decision-matrix\r
1620                 // wc           repository              text\r
1621                 // ""           ""                              ""\r
1622                 // ""           UID1                    owner\r
1623                 // UID1         UID1                    owner\r
1624                 // UID1         ""                              lock has been broken\r
1625                 // UID1         UID2                    lock has been stolen\r
1626                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
1627                 {\r
1628                         if (entry->lock_owner.IsEmpty())\r
1629                                 SetItemText(index, nCol++, entry->lock_remoteowner);\r
1630                         else\r
1631                                 SetItemText(index, nCol++, entry->lock_owner);\r
1632                 }\r
1633                 else if (entry->lock_remotetoken.IsEmpty())\r
1634                 {\r
1635                         // broken lock\r
1636                         CString temp(MAKEINTRESOURCE(IDS_STATUSLIST_LOCKBROKEN));\r
1637                         SetItemText(index, nCol++, temp);\r
1638                 }\r
1639                 else\r
1640                 {\r
1641                         // stolen lock\r
1642                         CString temp;\r
1643                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
1644                         SetItemText(index, nCol++, temp);\r
1645                 }\r
1646         }\r
1647         else\r
1648                 SetItemText(index, nCol++, entry->lock_owner);\r
1649         // SVNSLC_COLLOCKCOMMENT\r
1650         SetItemText(index, nCol++, entry->lock_comment);\r
1651         // SVNSLC_COLAUTHOR\r
1652         SetItemText(index, nCol++, entry->last_commit_author);\r
1653         // SVNSLC_COLREVISION\r
1654         CString temp;\r
1655         temp.Format(_T("%ld"), entry->last_commit_rev);\r
1656         if (entry->last_commit_rev > 0)\r
1657                 SetItemText(index, nCol++, temp);\r
1658         else\r
1659                 SetItemText(index, nCol++, _T(""));\r
1660         // SVNSLC_COLREMOTEREVISION\r
1661         temp.Format(_T("%ld"), entry->remoterev);\r
1662         if (entry->remoterev > 0)\r
1663                 SetItemText(index, nCol++, temp);\r
1664         else\r
1665                 SetItemText(index, nCol++, _T(""));\r
1666         // SVNSLC_COLDATE\r
1667         TCHAR datebuf[SVN_DATE_BUFFER];\r
1668         apr_time_t date = entry->last_commit_date;\r
1669         SVN::formatDate(datebuf, date, true);\r
1670         if (date)\r
1671                 SetItemText(index, nCol++, datebuf);\r
1672         else\r
1673                 SetItemText(index, nCol++, _T(""));\r
1674         // SVNSLC_COLSVNNEEDSLOCK\r
1675     BOOL bFoundSVNNeedsLock = entry->present_props.IsNeedsLockSet();\r
1676         CString strSVNNeedsLock = (bFoundSVNNeedsLock) ? _T("*") : _T("");\r
1677         SetItemText(index, nCol++, strSVNNeedsLock);\r
1678         // SVNSLC_COLCOPYFROM\r
1679         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
1680                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
1681         else\r
1682                 temp = entry->copyfrom_url;\r
1683         SetItemText(index, nCol++, temp);\r
1684         // SVNSLC_COLMODIFICATIONDATE\r
1685         __int64 filetime = entry->GetPath().GetLastWriteTime();\r
1686         if ( (filetime) && (entry->status!=git_wc_status_deleted) )\r
1687         {\r
1688                 FILETIME* f = (FILETIME*)(__int64*)&filetime;\r
1689                 TCHAR datebuf[SVN_DATE_BUFFER];\r
1690                 SVN::formatDate(datebuf,*f,true);\r
1691                 SetItemText(index, nCol++, datebuf);\r
1692         }\r
1693         else\r
1694         {\r
1695                 SetItemText(index, nCol++, _T(""));\r
1696         }\r
1697 \r
1698     // user-defined properties\r
1699     for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
1700         ; i < count\r
1701         ; ++i)\r
1702     {\r
1703         assert (i == nCol++);\r
1704         assert (m_ColumnManager.IsUserProp (i));\r
1705 \r
1706         CString name = m_ColumnManager.GetName(i);\r
1707         if (entry->present_props.HasProperty (name))\r
1708                 {\r
1709                         const CString& propVal = entry->present_props [name];\r
1710                         if (propVal.IsEmpty())\r
1711                                 SetItemText(index, i, m_sNoPropValueText);\r
1712                         else\r
1713                                 SetItemText(index, i, propVal);\r
1714                 }\r
1715                 else\r
1716             SetItemText(index, i, _T(""));\r
1717     }\r
1718 \r
1719         SetCheck(index, entry->checked);\r
1720         if (entry->checked)\r
1721                 m_nSelected++;\r
1722         if (m_changelists.find(entry->changelist) != m_changelists.end())\r
1723                 SetItemGroup(index, m_changelists[entry->changelist]);\r
1724         else\r
1725                 SetItemGroup(index, 0);\r
1726         m_bBlock = FALSE;\r
1727 #endif\r
1728 }\r
1729 #endif\r
1730 bool CGitStatusListCtrl::SetItemGroup(int item, int groupindex)\r
1731 {\r
1732         if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS) == NULL)\r
1733                 return false;\r
1734         if (groupindex < 0)\r
1735                 return false;\r
1736         LVITEM i = {0};\r
1737         i.mask = LVIF_GROUPID;\r
1738         i.iItem = item;\r
1739         i.iSubItem = 0;\r
1740         i.iGroupId = groupindex;\r
1741 \r
1742         return !!SetItem(&i);\r
1743 }\r
1744 \r
1745 void CGitStatusListCtrl::Sort()\r
1746 {\r
1747         Locker lock(m_critSec);\r
1748 \r
1749     CSorter predicate (&m_ColumnManager, m_nSortedColumn, m_bAscending);\r
1750 \r
1751         std::sort(m_arStatusArray.begin(), m_arStatusArray.end(), predicate);\r
1752         SaveColumnWidths();\r
1753         Show(m_dwShow, 0, m_bShowFolders);\r
1754 \r
1755 }\r
1756 \r
1757 void CGitStatusListCtrl::OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult)\r
1758 {\r
1759         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1760         *pResult = 0;\r
1761         if (m_bBlock)\r
1762                 return;\r
1763         m_bBlock = TRUE;\r
1764         if (m_nSortedColumn == phdr->iItem)\r
1765                 m_bAscending = !m_bAscending;\r
1766         else\r
1767                 m_bAscending = TRUE;\r
1768         m_nSortedColumn = phdr->iItem;\r
1769         m_mapFilenameToChecked.clear();\r
1770         Sort();\r
1771 \r
1772         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1773         HDITEM HeaderItem = {0};\r
1774         HeaderItem.mask = HDI_FORMAT;\r
1775         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1776         {\r
1777                 pHeader->GetItem(i, &HeaderItem);\r
1778                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1779                 pHeader->SetItem(i, &HeaderItem);\r
1780         }\r
1781         pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1782         HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1783         pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1784 \r
1785         // the checked state of the list control items must be restored\r
1786 \r
1787         for (int i=0; i<GetItemCount(); ++i)\r
1788         {\r
1789                 CTGitPath * entry = (CTGitPath*)GetItemData(i);\r
1790                 ASSERT(entry);\r
1791                 if(entry)\r
1792                         SetCheck(i, entry->m_Checked);\r
1793         }\r
1794 \r
1795         m_bBlock = FALSE;\r
1796 }\r
1797 \r
1798 void CGitStatusListCtrl::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
1799 {\r
1800         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1801         *pResult = 0;\r
1802 \r
1803 #define ISCHECKED(x) ((x) ? ((((x)&LVIS_STATEIMAGEMASK)>>12)-1) : FALSE)\r
1804         if ((m_bBlock)&&(m_bBlockUI))\r
1805         {\r
1806                 // if we're blocked, prevent changing of the check state\r
1807                 if ((!ISCHECKED(pNMLV->uOldState) && ISCHECKED(pNMLV->uNewState))||\r
1808                         (ISCHECKED(pNMLV->uOldState) && !ISCHECKED(pNMLV->uNewState)))\r
1809                         *pResult = TRUE;\r
1810         }\r
1811 }\r
1812 \r
1813 BOOL CGitStatusListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)\r
1814 {\r
1815         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1816         *pResult = 0;\r
1817         if ((pNMLV->uNewState==0)||(pNMLV->uNewState & LVIS_SELECTED)||(pNMLV->uNewState & LVIS_FOCUSED))\r
1818                 return FALSE;\r
1819 \r
1820         if (m_bBlock)\r
1821                 return FALSE;\r
1822 \r
1823         bool bSelected = !!(ListView_GetItemState(m_hWnd, pNMLV->iItem, LVIS_SELECTED) & LVIS_SELECTED);\r
1824         int nListItems = GetItemCount();\r
1825 \r
1826         m_bBlock = TRUE;\r
1827         // was the item checked?\r
1828         \r
1829         //CTGitPath *gitpath=(CTGitPath*)GetItemData(pNMLV->iItem);\r
1830         //gitpath->m_Checked=GetCheck(pNMLV->iItem);\r
1831 \r
1832         if (GetCheck(pNMLV->iItem))\r
1833         {\r
1834                 CheckEntry(pNMLV->iItem, nListItems);\r
1835                 if (bSelected)\r
1836                 {\r
1837                         POSITION pos = GetFirstSelectedItemPosition();\r
1838                         int index;\r
1839                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1840                         {\r
1841                                 if (index != pNMLV->iItem)\r
1842                                         CheckEntry(index, nListItems);\r
1843                         }\r
1844                 }\r
1845         }\r
1846         else\r
1847         {\r
1848                 UncheckEntry(pNMLV->iItem, nListItems);\r
1849                 if (bSelected)\r
1850                 {\r
1851                         POSITION pos = GetFirstSelectedItemPosition();\r
1852                         int index;\r
1853                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1854                         {\r
1855                                 if (index != pNMLV->iItem)\r
1856                                         UncheckEntry(index, nListItems);\r
1857                         }\r
1858                 }\r
1859         }\r
1860 \r
1861         GetStatisticsString();\r
1862         m_bBlock = FALSE;\r
1863         NotifyCheck();\r
1864 \r
1865         return FALSE;\r
1866 }\r
1867 \r
1868 void CGitStatusListCtrl::OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult)\r
1869 {\r
1870         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1871     if (   (header != NULL) \r
1872         && (header->iItem >= 0) \r
1873         && (header->iItem < m_ColumnManager.GetColumnCount()))\r
1874     {\r
1875         m_ColumnManager.ColumnResized (header->iItem);\r
1876     }\r
1877 \r
1878     *pResult = FALSE;\r
1879 }\r
1880 \r
1881 void CGitStatusListCtrl::OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult)\r
1882 {\r
1883         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1884         *pResult = TRUE;\r
1885     if (   (header != NULL) \r
1886         && (header->iItem >= 0) \r
1887         && (header->iItem < m_ColumnManager.GetColumnCount())\r
1888                 // only allow the reordering if the column was not moved left of the first\r
1889                 // visible item - otherwise the 'invisible' columns are not at the far left\r
1890                 // anymore and we get all kinds of redrawing problems.\r
1891                 && (header->pitem)\r
1892                 && (header->pitem->iOrder > m_ColumnManager.GetInvisibleCount()))\r
1893     {\r
1894         m_ColumnManager.ColumnMoved (header->iItem, header->pitem->iOrder);\r
1895                 *pResult = FALSE;\r
1896     }\r
1897 \r
1898     Invalidate(FALSE);\r
1899 }\r
1900 \r
1901 void CGitStatusListCtrl::CheckEntry(int index, int nListItems)\r
1902 {\r
1903         Locker lock(m_critSec);\r
1904         //FileEntry * entry = GetListEntry(index);\r
1905         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
1906         ASSERT(path != NULL);\r
1907         if (path == NULL)\r
1908                 return;\r
1909         SetCheck(index, TRUE);\r
1910         //entry = GetListEntry(index);\r
1911         // if an unversioned item was checked, then we need to check if\r
1912         // the parent folders are unversioned too. If the parent folders actually\r
1913         // are unversioned, then check those too.\r
1914 #if 0\r
1915         if (entry->status == git_wc_status_unversioned)\r
1916         {\r
1917                 // we need to check the parent folder too\r
1918                 const CTGitPath& folderpath = entry->path;\r
1919                 for (int i=0; i< nListItems; ++i)\r
1920                 {\r
1921                         FileEntry * testEntry = GetListEntry(i);\r
1922                         ASSERT(testEntry != NULL);\r
1923                         if (testEntry == NULL)\r
1924                                 continue;\r
1925                         if (!testEntry->checked)\r
1926                         {\r
1927                                 if (testEntry->path.IsAncestorOf(folderpath) && (!testEntry->path.IsEquivalentTo(folderpath)))\r
1928                                 {\r
1929                                         SetEntryCheck(testEntry,i,true);\r
1930                                         m_nSelected++;\r
1931                                 }\r
1932                         }\r
1933                 }\r
1934         }\r
1935         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
1936         if ( (entry->status == git_wc_status_deleted) || (m_bCheckChildrenWithParent) || (bShift) )\r
1937         {\r
1938                 // if a deleted folder gets checked, we have to check all\r
1939                 // children of that folder too.\r
1940                 if (entry->path.IsDirectory())\r
1941                 {\r
1942                         SetCheckOnAllDescendentsOf(entry, true);\r
1943                 }\r
1944 \r
1945                 // if a deleted file or folder gets checked, we have to\r
1946                 // check all parents of this item too.\r
1947                 for (int i=0; i<nListItems; ++i)\r
1948                 {\r
1949                         FileEntry * testEntry = GetListEntry(i);\r
1950                         ASSERT(testEntry != NULL);\r
1951                         if (testEntry == NULL)\r
1952                                 continue;\r
1953                         if (!testEntry->checked)\r
1954                         {\r
1955                                 if (testEntry->path.IsAncestorOf(entry->path) && (!testEntry->path.IsEquivalentTo(entry->path)))\r
1956                                 {\r
1957                                         if ((testEntry->status == git_wc_status_deleted)||(m_bCheckChildrenWithParent))\r
1958                                         {\r
1959                                                 SetEntryCheck(testEntry,i,true);\r
1960                                                 m_nSelected++;\r
1961                                                 // now we need to check all children of this parent folder\r
1962                                                 SetCheckOnAllDescendentsOf(testEntry, true);\r
1963                                         }\r
1964                                 }\r
1965                         }\r
1966                 }\r
1967         }\r
1968 #endif\r
1969         if ( !path->m_Checked )\r
1970         {\r
1971                 path->m_Checked = TRUE;\r
1972                 m_nSelected++;\r
1973         }\r
1974 }\r
1975 \r
1976 void CGitStatusListCtrl::UncheckEntry(int index, int nListItems)\r
1977 {\r
1978         Locker lock(m_critSec);\r
1979         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
1980         ASSERT(path != NULL);\r
1981         if (path == NULL)\r
1982                 return;\r
1983         SetCheck(index, FALSE);\r
1984         //entry = GetListEntry(index);\r
1985         // item was unchecked\r
1986 #if 0\r
1987         if (entry->path.IsDirectory())\r
1988         {\r
1989                 // disable all files within an unselected folder, except when unchecking a folder with property changes\r
1990                 bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
1991                 if ( (entry->status != git_wc_status_modified) || (bShift) )\r
1992                 {\r
1993                         SetCheckOnAllDescendentsOf(entry, false);\r
1994                 }\r
1995         }\r
1996         else if (entry->status == git_wc_status_deleted)\r
1997         {\r
1998                 // a "deleted" file was unchecked, so uncheck all parent folders\r
1999                 // and all children of those parents\r
2000                 for (int i=0; i<nListItems; i++)\r
2001                 {\r
2002                         FileEntry * testEntry = GetListEntry(i);\r
2003                         ASSERT(testEntry != NULL);\r
2004                         if (testEntry == NULL)\r
2005                                 continue;\r
2006                         if (testEntry->checked)\r
2007                         {\r
2008                                 if (testEntry->path.IsAncestorOf(entry->path))\r
2009                                 {\r
2010                                         if (testEntry->status == git_wc_status_deleted)\r
2011                                         {\r
2012                                                 SetEntryCheck(testEntry,i,false);\r
2013                                                 m_nSelected--;\r
2014 \r
2015                                                 SetCheckOnAllDescendentsOf(testEntry, false);\r
2016                                         }\r
2017                                 }\r
2018                         }\r
2019                 }\r
2020         }\r
2021 #endif\r
2022         if ( path->m_Checked )\r
2023         {\r
2024                 path->m_Checked  = FALSE;\r
2025                 m_nSelected--;\r
2026         }\r
2027 }\r
2028 #if 0\r
2029 bool CGitStatusListCtrl::EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2)\r
2030 {\r
2031         return pEntry1->path < pEntry2->path;\r
2032 }\r
2033 \r
2034 bool CGitStatusListCtrl::IsEntryVersioned(const FileEntry* pEntry1)\r
2035 {\r
2036         return pEntry1->status != git_wc_status_unversioned;\r
2037 }\r
2038 #endif\r
2039 bool CGitStatusListCtrl::BuildStatistics()\r
2040 {\r
2041 \r
2042         bool bRefetchStatus = false;\r
2043 \r
2044         // now gather some statistics\r
2045         m_nUnversioned = 0;\r
2046         m_nNormal = 0;\r
2047         m_nModified = 0;\r
2048         m_nAdded = 0;\r
2049         m_nDeleted = 0;\r
2050         m_nConflicted = 0;\r
2051         m_nTotal = 0;\r
2052         m_nSelected = 0;\r
2053         \r
2054         for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2055         {\r
2056                 int status=((CTGitPath*)m_arStatusArray[i])->m_Action;\r
2057 \r
2058                 if(status&CTGitPath::LOGACTIONS_ADDED)\r
2059                         m_nAdded++;\r
2060                 \r
2061                 if(status&CTGitPath::LOGACTIONS_DELETED)\r
2062                         m_nDeleted++;\r
2063                 \r
2064                 if(status&(CTGitPath::LOGACTIONS_REPLACED|CTGitPath::LOGACTIONS_MODIFIED))\r
2065                         m_nModified++;\r
2066                 \r
2067                 if(status&CTGitPath::LOGACTIONS_CONFLICT)\r
2068                         m_nConflicted++;\r
2069                 \r
2070                 if(status&(CTGitPath::LOGACTIONS_IGNORE|CTGitPath::LOGACTIONS_UNVER))\r
2071                         m_nUnversioned++;\r
2072         \r
2073         \r
2074 \r
2075 //                      } // switch (entry->status)\r
2076 //              } // if (entry)\r
2077         } // for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2078         return !bRefetchStatus;\r
2079 \r
2080         return FALSE;\r
2081 }\r
2082 \r
2083 void CGitStatusListCtrl::GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly)\r
2084 {\r
2085 #if 0\r
2086         Locker lock(m_critSec);\r
2087         rMin = LONG_MAX;\r
2088         rMax = 0;\r
2089 \r
2090         if ((bShownOnly)||(bCheckedOnly))\r
2091         {\r
2092                 for (int i=0; i<GetItemCount(); ++i)\r
2093                 {\r
2094                         const FileEntry * entry = GetListEntry(i);\r
2095 \r
2096                         if ((entry)&&(entry->last_commit_rev))\r
2097                         {\r
2098                                 if ((!bCheckedOnly)||(entry->IsChecked()))\r
2099                                 {\r
2100                                         if (entry->last_commit_rev >= 0)\r
2101                                         {\r
2102                                                 rMin = min(rMin, entry->last_commit_rev);\r
2103                                                 rMax = max(rMax, entry->last_commit_rev);\r
2104                                         }\r
2105                                 }\r
2106                         }\r
2107                 }\r
2108         }\r
2109         else\r
2110         {\r
2111                 for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2112                 {\r
2113                         const FileEntry * entry = m_arStatusArray[i];\r
2114                         if ((entry)&&(entry->last_commit_rev))\r
2115                         {\r
2116                                 if (entry->last_commit_rev >= 0)\r
2117                                 {\r
2118                                         rMin = min(rMin, entry->last_commit_rev);\r
2119                                         rMax = max(rMax, entry->last_commit_rev);\r
2120                                 }\r
2121                         }\r
2122                 }\r
2123         }\r
2124         if (rMin == LONG_MAX)\r
2125                 rMin = 0;\r
2126 #endif\r
2127 }\r
2128 \r
2129 int CGitStatusListCtrl::GetGroupFromPoint(POINT * ppt)\r
2130 {\r
2131         // the point must be relative to the upper left corner of the control\r
2132 \r
2133         if (ppt == NULL)\r
2134                 return -1;\r
2135         if (!IsGroupViewEnabled())\r
2136                 return -1;\r
2137 \r
2138         POINT pt = *ppt;\r
2139         pt.x = 10;\r
2140         UINT flags = 0;\r
2141         int nItem = -1;\r
2142         RECT rc;\r
2143         GetWindowRect(&rc);\r
2144         while (((flags & LVHT_BELOW) == 0)&&(pt.y < rc.bottom))\r
2145         {\r
2146                 nItem = HitTest(pt, &flags);\r
2147                 if ((flags & LVHT_ONITEM)||(flags & LVHT_EX_GROUP_HEADER))\r
2148                 {\r
2149                         // the first item below the point\r
2150 \r
2151                         // check if the point is too much right (i.e. if the point\r
2152                         // is farther to the right than the width of the item)\r
2153                         RECT r;\r
2154                         GetItemRect(nItem, &r, LVIR_LABEL);\r
2155                         if (ppt->x > r.right)\r
2156                                 return -1;\r
2157 \r
2158                         LVITEM lv = {0};\r
2159                         lv.mask = LVIF_GROUPID;\r
2160                         lv.iItem = nItem;\r
2161                         GetItem(&lv);\r
2162                         int groupID = lv.iGroupId;\r
2163                         // now we search upwards and check if the item above this one\r
2164                         // belongs to another group. If it belongs to the same group,\r
2165                         // we're not over a group header\r
2166                         while (pt.y >= 0)\r
2167                         {\r
2168                                 pt.y -= 2;\r
2169                                 nItem = HitTest(pt, &flags);\r
2170                                 if ((flags & LVHT_ONITEM)&&(nItem >= 0))\r
2171                                 {\r
2172                                         // the first item below the point\r
2173                                         LVITEM lv = {0};\r
2174                                         lv.mask = LVIF_GROUPID;\r
2175                                         lv.iItem = nItem;\r
2176                                         GetItem(&lv);\r
2177                                         if (lv.iGroupId != groupID)\r
2178                                                 return groupID;\r
2179                                         else\r
2180                                                 return -1;\r
2181                                 }\r
2182                         }\r
2183                         if (pt.y < 0)\r
2184                                 return groupID;\r
2185                         return -1;\r
2186                 }\r
2187                 pt.y += 2;\r
2188         };\r
2189         return -1;\r
2190 }\r
2191 \r
2192 void CGitStatusListCtrl::OnContextMenuGroup(CWnd * /*pWnd*/, CPoint point)\r
2193 {\r
2194         POINT clientpoint = point;\r
2195         ScreenToClient(&clientpoint);\r
2196         if ((IsGroupViewEnabled())&&(GetGroupFromPoint(&clientpoint) >= 0))\r
2197         {\r
2198                 CMenu popup;\r
2199                 if (popup.CreatePopupMenu())\r
2200                 {\r
2201                         CString temp;\r
2202                         temp.LoadString(IDS_STATUSLIST_CHECKGROUP);\r
2203                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CHECKGROUP, temp);\r
2204                         temp.LoadString(IDS_STATUSLIST_UNCHECKGROUP);\r
2205                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_UNCHECKGROUP, temp);\r
2206                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2207                         bool bCheck = false;\r
2208                         switch (cmd)\r
2209                         {\r
2210                         case IDSVNLC_CHECKGROUP:\r
2211                                 bCheck = true;\r
2212                                 // fall through here\r
2213                         case IDSVNLC_UNCHECKGROUP:\r
2214                                 {\r
2215                                         int group = GetGroupFromPoint(&clientpoint);\r
2216                                         // go through all items and check/uncheck those assigned to the group\r
2217                                         // but block the OnLvnItemChanged handler\r
2218                                         m_bBlock = true;\r
2219                                         LVITEM lv;\r
2220                                         for (int i=0; i<GetItemCount(); ++i)\r
2221                                         {\r
2222                                                 SecureZeroMemory(&lv, sizeof(LVITEM));\r
2223                                                 lv.mask = LVIF_GROUPID;\r
2224                                                 lv.iItem = i;\r
2225                                                 GetItem(&lv);\r
2226 #if 0\r
2227                                                 if (lv.iGroupId == group)\r
2228                                                 {\r
2229                                                         FileEntry * entry = GetListEntry(i);\r
2230                                                         if (entry)\r
2231                                                         {\r
2232                                                                 bool bOldCheck = !!GetCheck(i);\r
2233                                                                 //SetEntryCheck(entry, i, bCheck);\r
2234                                                                 if (bCheck != bOldCheck)\r
2235                                                                 {\r
2236                                                                         if (bCheck)\r
2237                                                                                 m_nSelected++;\r
2238                                                                         else\r
2239                                                                                 m_nSelected--;\r
2240                                                                 }\r
2241                                                         }\r
2242                                                 }\r
2243 #endif\r
2244                                         }\r
2245                                         GetStatisticsString();\r
2246                                         NotifyCheck();\r
2247                                         m_bBlock = false;\r
2248                                 }\r
2249                                 break;\r
2250                         }\r
2251                 }\r
2252         }\r
2253 }\r
2254 \r
2255 void CGitStatusListCtrl::OnContextMenuList(CWnd * pWnd, CPoint point)\r
2256 {\r
2257 \r
2258         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
2259 \r
2260         bool XPorLater = false;\r
2261         OSVERSIONINFOEX inf;\r
2262         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
2263         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
2264         GetVersionEx((OSVERSIONINFO *)&inf);\r
2265         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
2266         if (fullver >= 0x0501)\r
2267                 XPorLater = true;\r
2268         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
2269         CTGitPath * filepath;\r
2270 \r
2271         int selIndex = GetSelectionMark();\r
2272         if ((point.x == -1) && (point.y == -1))\r
2273         {\r
2274                 CRect rect;\r
2275                 GetItemRect(selIndex, &rect, LVIR_LABEL);\r
2276                 ClientToScreen(&rect);\r
2277                 point = rect.CenterPoint();\r
2278         }\r
2279         if ((GetSelectedCount() == 0)&&(XPorLater)&&(m_bHasCheckboxes))\r
2280         {\r
2281                 // nothing selected could mean the context menu is requested for\r
2282                 // a group header\r
2283                 OnContextMenuGroup(pWnd, point);\r
2284         }\r
2285         else if (selIndex >= 0)\r
2286         {\r
2287                 //FileEntry * entry = GetListEntry(selIndex);\r
2288 \r
2289                 filepath = (CTGitPath * )GetItemData(selIndex);\r
2290 \r
2291                 ASSERT(filepath != NULL);\r
2292                 if (filepath == NULL)\r
2293                         return;\r
2294 \r
2295                 //const CTGitPath& filepath = entry->path;\r
2296                 int wcStatus = filepath->m_Action;\r
2297                 // entry is selected, now show the popup menu\r
2298                 Locker lock(m_critSec);\r
2299                 CIconMenu popup;\r
2300                 CMenu changelistSubMenu;\r
2301                 CMenu ignoreSubMenu;\r
2302                 if (popup.CreatePopupMenu())\r
2303                 {\r
2304                         //Add Menu for verion controled file\r
2305                         if (!(wcStatus &CTGitPath::LOGACTIONS_UNVER))\r
2306                         {\r
2307                                 if (m_dwContextMenus & SVNSLC_POPCOMPAREWITHBASE)\r
2308                                 {\r
2309                                         popup.AppendMenuIcon(IDSVNLC_COMPARE, IDS_LOG_COMPAREWITHBASE, IDI_DIFF);\r
2310                                         popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2311                                 }\r
2312                                 //Select one items\r
2313                                 if (GetSelectedCount() == 1)\r
2314                                 {\r
2315                                         bool bEntryAdded = false;\r
2316                                         //if (entry->remotestatus <= git_wc_status_normal)\r
2317                                         //{\r
2318                                         //      if (wcStatus > git_wc_status_normal)\r
2319                                         //      {\r
2320                                         //              if ((m_dwContextMenus & SVNSLC_POPGNUDIFF)&&(wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing))\r
2321                                         //              {\r
2322                                         if(!g_Git.IsInitRepos())\r
2323                                                 popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2324 \r
2325                                         bEntryAdded = true;\r
2326                                         //              }\r
2327                                         //      }\r
2328                                         //\r
2329                                         //}\r
2330                                         //else if (wcStatus != git_wc_status_deleted)\r
2331                                         //{\r
2332                                         //      if (m_dwContextMenus & SVNSLC_POPCOMPARE)\r
2333                                         //      {\r
2334                                         //              popup.AppendMenuIcon(IDSVNLC_COMPAREWC, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
2335                                         //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2336                                         //              bEntryAdded = true;\r
2337                                         //      }\r
2338                                         //      if (m_dwContextMenus & SVNSLC_POPGNUDIFF)\r
2339                                         //      {\r
2340                                         //              popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2341                                         //              bEntryAdded = true;\r
2342                                         //      }\r
2343                                         //}\r
2344                                         if (bEntryAdded)\r
2345                                                 popup.AppendMenu(MF_SEPARATOR);\r
2346                                 }\r
2347                                 //else if (GetSelectedCount() > 1)  \r
2348                                 //{\r
2349                                 //      if (m_dwContextMenus & SVNSLC_POPCOMMIT)\r
2350                                 //      {\r
2351                                 //              popup.AppendMenuIcon(IDSVNLC_COMMIT, IDS_STATUSLIST_CONTEXT_COMMIT, IDI_COMMIT);\r
2352                                 //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2353                                 //      }\r
2354                                 //}\r
2355                         }\r
2356                         \r
2357                         ///Select Multi item\r
2358                         //if (GetSelectedCount() > 0)\r
2359                         //{\r
2360                         //      if ((GetSelectedCount() == 2)&&(m_dwContextMenus & SVNSLC_POPREPAIRMOVE))\r
2361                         //      {\r
2362                         //              POSITION pos = GetFirstSelectedItemPosition();\r
2363                         //              int index = GetNextSelectedItem(pos);\r
2364                         //              if (index >= 0)\r
2365                         //              {\r
2366                         //                      FileEntry * entry = GetListEntry(index);\r
2367                         //                      git_wc_status_kind status1 = git_wc_status_none;\r
2368                         //                      git_wc_status_kind status2 = git_wc_status_none;\r
2369                         //                      if (entry)\r
2370                         //                              status1 = entry->status;\r
2371                         //                      index = GetNextSelectedItem(pos);\r
2372                         //                      if (index >= 0)\r
2373                         //                      {\r
2374                         //                              entry = GetListEntry(index);\r
2375                         //                              if (entry)\r
2376                         //                                      status2 = entry->status;\r
2377                         //                              if ((status1 == git_wc_status_missing && status2 == git_wc_status_unversioned) ||\r
2378                         //                                      (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned))\r
2379                         //                              {\r
2380                         //                                      popup.AppendMenuIcon(IDSVNLC_REPAIRMOVE, IDS_STATUSLIST_CONTEXT_REPAIRMOVE);\r
2381                         //                              }\r
2382                         //                      }\r
2383                         //              }\r
2384                         //      }\r
2385                         //      if (wcStatus > git_wc_status_normal)\r
2386                         //      {\r
2387                         //              if (m_dwContextMenus & SVNSLC_POPREVERT)\r
2388                         //              {\r
2389                         //                      // reverting missing folders is not possible\r
2390                         //                      if (!entry->IsFolder() || (wcStatus != git_wc_status_missing))\r
2391                         //                      {\r
2392                         //                              popup.AppendMenuIcon(IDSVNLC_REVERT, IDS_MENUREVERT, IDI_REVERT);\r
2393                         //                      }\r
2394                         //              }\r
2395                         //      }\r
2396                         //      if (entry->remotestatus > git_wc_status_normal)\r
2397                         //      {\r
2398                         //              if (m_dwContextMenus & SVNSLC_POPUPDATE)\r
2399                         //              {\r
2400                         //                      popup.AppendMenuIcon(IDSVNLC_UPDATE, IDS_MENUUPDATE, IDI_UPDATE);\r
2401                         //              }\r
2402                         //      }\r
2403                         //}\r
2404                         if ((GetSelectedCount() == 1)&&(!wcStatus & CTGitPath::LOGACTIONS_UNVER)\r
2405                                 &&(!wcStatus & CTGitPath::LOGACTIONS_IGNORE))\r
2406                         {\r
2407                                 if (m_dwContextMenus & SVNSLC_POPSHOWLOG)\r
2408                                 {\r
2409                                         popup.AppendMenuIcon(IDSVNLC_LOG, IDS_REPOBROWSE_SHOWLOG, IDI_LOG);\r
2410                                 }\r
2411 //                              if (m_dwContextMenus & SVNSLC_POPBLAME)\r
2412 //                              {\r
2413 //                                      popup.AppendMenuIcon(IDSVNLC_BLAME, IDS_MENUBLAME, IDI_BLAME);\r
2414 //                              }\r
2415                         }\r
2416 //                      if ((wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing) && (GetSelectedCount() == 1))\r
2417 //                      {\r
2418                                 if (m_dwContextMenus & SVNSLC_POPOPEN)\r
2419                                 {\r
2420                                         popup.AppendMenuIcon(IDSVNLC_OPEN, IDS_REPOBROWSE_OPEN, IDI_OPEN);\r
2421                                         popup.AppendMenuIcon(IDSVNLC_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
2422                                 }\r
2423                                 if (m_dwContextMenus & SVNSLC_POPEXPLORE)\r
2424                                 {\r
2425                                         popup.AppendMenuIcon(IDSVNLC_EXPLORE, IDS_STATUSLIST_CONTEXT_EXPLORE, IDI_EXPLORER);\r
2426                                 }\r
2427 //                      }\r
2428                         if (GetSelectedCount() > 0)\r
2429                         {\r
2430 //                              if (((wcStatus == git_wc_status_unversioned)||(wcStatus == git_wc_status_ignored))&&(m_dwContextMenus & SVNSLC_POPDELETE))\r
2431 //                              {\r
2432 //                                      popup.AppendMenuIcon(IDSVNLC_DELETE, IDS_MENUREMOVE, IDI_DELETE);\r
2433 //                              }\r
2434 //                              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
2435 //                              {\r
2436 //                                      if (bShift)\r
2437 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVEKEEP, IDI_DELETE);\r
2438 //                                      else\r
2439 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVE, IDI_DELETE);\r
2440 //                              }\r
2441                                 if ((wcStatus & CTGitPath::LOGACTIONS_UNVER)/*||(wcStatus == git_wc_status_deleted)*/)\r
2442                                 {\r
2443                                         if (m_dwContextMenus & SVNSLC_POPADD)\r
2444                                         {\r
2445                                                 //if ( entry->IsFolder() )\r
2446                                                 //{\r
2447                                                 //      popup.AppendMenuIcon(IDSVNLC_ADD_RECURSIVE, IDS_STATUSLIST_CONTEXT_ADD_RECURSIVE, IDI_ADD);\r
2448                                                 //}\r
2449                                                 //else\r
2450                                                 {\r
2451                                                         popup.AppendMenuIcon(IDSVNLC_ADD, IDS_STATUSLIST_CONTEXT_ADD, IDI_ADD);\r
2452                                                 }\r
2453                                         }\r
2454                                 //}\r
2455                                 //if ( (wcStatus == git_wc_status_unversioned) || (wcStatus == git_wc_status_deleted) )\r
2456                                 //{\r
2457                                         if (m_dwContextMenus & SVNSLC_POPIGNORE)\r
2458                                         {\r
2459 \r
2460                                                 CTGitPathList ignorelist;\r
2461                                                 FillListOfSelectedItemPaths(ignorelist);\r
2462                                                 //check if all selected entries have the same extension\r
2463                                                 bool bSameExt = true;\r
2464                                                 CString sExt;\r
2465                                                 for (int i=0; i<ignorelist.GetCount(); ++i)\r
2466                                                 {\r
2467                                                         if (sExt.IsEmpty() && (i==0))\r
2468                                                                 sExt = ignorelist[i].GetFileExtension();\r
2469                                                         else if (sExt.CompareNoCase(ignorelist[i].GetFileExtension())!=0)\r
2470                                                                 bSameExt = false;\r
2471                                                 }\r
2472                                                 if (bSameExt)\r
2473                                                 {\r
2474                                                         if (ignoreSubMenu.CreateMenu())\r
2475                                                         {\r
2476                                                                 CString ignorepath;\r
2477                                                                 if (ignorelist.GetCount()==1)\r
2478                                                                         ignorepath = ignorelist[0].GetFileOrDirectoryName();\r
2479                                                                 else\r
2480                                                                         ignorepath.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2481                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNORE, ignorepath);\r
2482                                                                 ignorepath = _T("*")+sExt;\r
2483                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNOREMASK, ignorepath);\r
2484                                                                 CString temp;\r
2485                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2486                                                                 popup.InsertMenu((UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)ignoreSubMenu.m_hMenu, temp);\r
2487                                                         }\r
2488                                                 }\r
2489                                                 else\r
2490                                                 {\r
2491                                                         CString temp;\r
2492                                                         if (ignorelist.GetCount()==1)\r
2493                                                         {\r
2494                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2495                                                         }\r
2496                                                         else\r
2497                                                         {\r
2498                                                                 temp.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2499                                                         }\r
2500                                                         popup.AppendMenuIcon(IDSVNLC_IGNORE, temp, IDI_IGNORE);\r
2501                                                 }\r
2502                                         }\r
2503                                 }\r
2504                         }\r
2505 #if 0\r
2506                         if (((wcStatus == git_wc_status_conflicted)||(entry->isConflicted)))\r
2507                         {\r
2508                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)||(m_dwContextMenus & SVNSLC_POPRESOLVE))\r
2509                                         popup.AppendMenu(MF_SEPARATOR);\r
2510 \r
2511                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)&&(entry->textstatus == git_wc_status_conflicted))\r
2512                                 {\r
2513                                         popup.AppendMenuIcon(IDSVNLC_EDITCONFLICT, IDS_MENUCONFLICT, IDI_CONFLICT);\r
2514                                 }\r
2515                                 if (m_dwContextMenus & SVNSLC_POPRESOLVE)\r
2516                                 {\r
2517                                         popup.AppendMenuIcon(IDSVNLC_RESOLVECONFLICT, IDS_STATUSLIST_CONTEXT_RESOLVED, IDI_RESOLVE);\r
2518                                 }\r
2519                                 if ((m_dwContextMenus & SVNSLC_POPRESOLVE)&&(entry->textstatus == git_wc_status_conflicted))\r
2520                                 {\r
2521                                         popup.AppendMenuIcon(IDSVNLC_RESOLVETHEIRS, IDS_SVNPROGRESS_MENUUSETHEIRS, IDI_RESOLVE);\r
2522                                         popup.AppendMenuIcon(IDSVNLC_RESOLVEMINE, IDS_SVNPROGRESS_MENUUSEMINE, IDI_RESOLVE);\r
2523                                 }\r
2524                         }\r
2525 #endif\r
2526 #if 0                   \r
2527                         if (GetSelectedCount() > 0)\r
2528                         {\r
2529 \r
2530                                 if ((!entry->IsFolder())&&(wcStatus >= git_wc_status_normal)\r
2531                                         &&(wcStatus!=git_wc_status_missing)&&(wcStatus!=git_wc_status_deleted)\r
2532                                         &&(wcStatus!=git_wc_status_added))\r
2533                                 {\r
2534                                         popup.AppendMenu(MF_SEPARATOR);\r
2535                                         if ((entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2536                                         {\r
2537                                                 if (m_dwContextMenus & SVNSLC_POPLOCK)\r
2538                                                 {\r
2539                                                         popup.AppendMenuIcon(IDSVNLC_LOCK, IDS_MENU_LOCK, IDI_LOCK);\r
2540                                                 }\r
2541                                         }\r
2542                                         if ((!entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2543                                         {\r
2544                                                 if (m_dwContextMenus & SVNSLC_POPUNLOCK)\r
2545                                                 {\r
2546                                                         popup.AppendMenuIcon(IDSVNLC_UNLOCK, IDS_MENU_UNLOCK, IDI_UNLOCK);\r
2547                                                 }\r
2548                                         }\r
2549                                 }\r
2550 \r
2551                                 if ((!entry->IsFolder())&&((!entry->lock_token.IsEmpty())||(!entry->lock_remotetoken.IsEmpty())))\r
2552                                 {\r
2553                                         if (m_dwContextMenus & SVNSLC_POPUNLOCKFORCE)\r
2554                                         {\r
2555                                                 popup.AppendMenuIcon(IDSVNLC_UNLOCKFORCE, IDS_MENU_UNLOCKFORCE, IDI_UNLOCK);\r
2556                                         }\r
2557                                 }\r
2558 \r
2559                                 if (wcStatus != git_wc_status_missing && wcStatus != git_wc_status_deleted &&wcStatus!=git_wc_status_unversioned)\r
2560                                 {\r
2561                                         popup.AppendMenu(MF_SEPARATOR);\r
2562                                         popup.AppendMenuIcon(IDSVNLC_PROPERTIES, IDS_STATUSLIST_CONTEXT_PROPERTIES, IDI_PROPERTIES);\r
2563                                 }\r
2564                                 popup.AppendMenu(MF_SEPARATOR);\r
2565                                 popup.AppendMenuIcon(IDSVNLC_COPY, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);\r
2566                                 popup.AppendMenuIcon(IDSVNLC_COPYEXT, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);\r
2567                                 if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS)&&(XPorLater)\r
2568                                         &&(wcStatus != git_wc_status_unversioned)&&(wcStatus != git_wc_status_none))\r
2569                                 {\r
2570                                         popup.AppendMenu(MF_SEPARATOR);\r
2571                                         // changelist commands\r
2572                                         size_t numChangelists = GetNumberOfChangelistsInSelection();\r
2573                                         if (numChangelists > 0)\r
2574                                         {\r
2575                                                 popup.AppendMenuIcon(IDSVNLC_REMOVEFROMCS, IDS_STATUSLIST_CONTEXT_REMOVEFROMCS);\r
2576                                         }\r
2577                                         if ((!entry->IsFolder())&&(changelistSubMenu.CreateMenu()))\r
2578                                         {\r
2579                                                 CString temp;\r
2580                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_CREATECS);\r
2581                                                 changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATECS, temp);\r
2582 \r
2583                                                 if (entry->changelist.Compare(SVNSLC_IGNORECHANGELIST))\r
2584                                                 {\r
2585                                                         changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2586                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATEIGNORECS, SVNSLC_IGNORECHANGELIST);\r
2587                                                 }\r
2588 \r
2589                                                 if (m_changelists.size() > 0)\r
2590                                                 {\r
2591                                                         // find the changelist names\r
2592                                                         bool bNeedSeparator = true;\r
2593                                                         int cmdID = IDSVNLC_MOVETOCS;\r
2594                                                         for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
2595                                                         {\r
2596                                                                 if ((entry->changelist.Compare(it->first))&&(it->first.Compare(SVNSLC_IGNORECHANGELIST)))\r
2597                                                                 {\r
2598                                                                         if (bNeedSeparator)\r
2599                                                                         {\r
2600                                                                                 changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2601                                                                                 bNeedSeparator = false;\r
2602                                                                         }\r
2603                                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, cmdID, it->first);\r
2604                                                                         cmdID++;\r
2605                                                                 }\r
2606                                                         }\r
2607                                                 }\r
2608                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_MOVETOCS);\r
2609                                                 popup.AppendMenu(MF_POPUP|MF_STRING, (UINT_PTR)changelistSubMenu.GetSafeHmenu(), temp);\r
2610                                         }\r
2611                                 }\r
2612                         }\r
2613 #endif\r
2614                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2615 \r
2616                         m_bBlock = TRUE;\r
2617                         AfxGetApp()->DoWaitCursor(1);\r
2618                         int iItemCountBeforeMenuCmd = GetItemCount();\r
2619                         bool bForce = false;\r
2620                         switch (cmd)\r
2621                         {\r
2622                         case IDSVNLC_OPEN:\r
2623                                 {\r
2624                                         CString file;\r
2625                                         if(this->m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2626                                         {\r
2627                                                 file= filepath->GetWinPath();\r
2628                                         }else\r
2629                                         {\r
2630                                                 CString temppath;\r
2631                                                 GetTempPath(temppath);\r
2632                                                 file.Format(_T("%s%s_%s%s"),\r
2633                                                         temppath,                                               \r
2634                                                         filepath->GetBaseFilename(),\r
2635                                                         m_CurrentVersion.Left(6),\r
2636                                                         filepath->GetFileExtension());\r
2637 \r
2638                                         }\r
2639                                         int ret = (int)ShellExecute(this->m_hWnd, NULL,file, NULL, NULL, SW_SHOW);\r
2640                                         if (ret <= HINSTANCE_ERROR)\r
2641                                         {\r
2642                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
2643                                                 cmd += file;\r
2644                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
2645                                         }\r
2646                                 }\r
2647                                 break;\r
2648                         case IDSVNLC_OPENWITH:\r
2649                                 {\r
2650                                         CString file;\r
2651                                         if(m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2652                                         {\r
2653                                                 file= filepath->GetWinPath();\r
2654                                         }else\r
2655                                         {\r
2656                                                 CString temppath;\r
2657                                                 GetTempPath(temppath);\r
2658                                                 file.Format(_T("%s%s_%s%s"),\r
2659                                                         temppath,                                               \r
2660                                                         filepath->GetBaseFilename(),\r
2661                                                         m_CurrentVersion.Left(6),\r
2662                                                         filepath->GetFileExtension());\r
2663 \r
2664                                         }\r
2665 \r
2666                                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
2667                                         cmd += file + _T(" ");\r
2668                                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
2669                                 }\r
2670                                 break;\r
2671                         case IDSVNLC_EXPLORE:\r
2672                                 {\r
2673                                         ShellExecute(this->m_hWnd, _T("explore"), filepath->GetWinPath(), NULL, NULL, SW_SHOW);\r
2674                                 }\r
2675                                 break;\r
2676                         case IDSVNLC_COMPARE:\r
2677                                 {\r
2678                                         POSITION pos = GetFirstSelectedItemPosition();\r
2679                                         while ( pos )\r
2680                                         {\r
2681                                                 int index = GetNextSelectedItem(pos);\r
2682                                                 StartDiff(index);\r
2683                                         }\r
2684                                 }\r
2685                                 break;\r
2686                         case IDSVNLC_GNUDIFF1:\r
2687                                 {\r
2688                                 //      SVNDiff diff(NULL, this->m_hWnd, true);\r
2689                                 //\r
2690                                 //      if (entry->remotestatus <= git_wc_status_normal)\r
2691                                 //              CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_BASE, entry->path, SVNRev::REV_WC);\r
2692                                 //      else\r
2693                                 //              CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_WC, entry->path, SVNRev::REV_HEAD);\r
2694                                         if(m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2695                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd,*filepath,GitRev::GetWorkingCopy(),\r
2696                                                                                                                         *filepath,GitRev::GetHead());\r
2697                                         else\r
2698                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd,*filepath,m_CurrentVersion,\r
2699                                                                                                                         *filepath,m_CurrentVersion+_T("~1"));\r
2700                                 }\r
2701                                 break;\r
2702                         case IDSVNLC_ADD:\r
2703                                 {       // The add went ok, but we now need to run through the selected items again\r
2704                                         // and update their status\r
2705                                         POSITION pos = GetFirstSelectedItemPosition();\r
2706                                         int index;\r
2707                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
2708                                         {\r
2709                                                 CTGitPath * path=(CTGitPath*)GetItemData(index);\r
2710                                                 ASSERT(path);\r
2711                                                 if(path == NULL)\r
2712                                                         continue;\r
2713                                                 CString cmd;\r
2714                                                 cmd.Format(_T("git.exe add %s"),path->GetGitPathString());\r
2715                                                 CString output;\r
2716                                                 if(!g_Git.Run(cmd,&output))\r
2717                                                 {\r
2718                                                         path->m_Action = CTGitPath::LOGACTIONS_ADDED;\r
2719                                                         SetEntryCheck(path,index,true);\r
2720                                                         SetItemGroup(index,0);\r
2721                                                         this->m_StatusFileList.AddPath(*path);\r
2722                                                         this->m_UnRevFileList.RemoveItem(*path);\r
2723                                                         this->m_IgnoreFileList.RemoveItem(*path);\r
2724                                                         Show(this->m_dwShow,0,true,true);\r
2725                                                 }\r
2726                                         }\r
2727                                         \r
2728                                 }\r
2729                                 break;\r
2730 #if 0\r
2731                         case IDSVNLC_COPY:\r
2732                                 CopySelectedEntriesToClipboard(0);\r
2733                                 break;\r
2734                         case IDSVNLC_COPYEXT:\r
2735                                 CopySelectedEntriesToClipboard((DWORD)-1);\r
2736                                 break;\r
2737                         case IDSVNLC_PROPERTIES:\r
2738                                 {\r
2739                                         CTSVNPathList targetList;\r
2740                                         FillListOfSelectedItemPaths(targetList);\r
2741                                         CEditPropertiesDlg dlg;\r
2742                                         dlg.SetPathList(targetList);\r
2743                                         dlg.DoModal();\r
2744                                         if (dlg.HasChanged())\r
2745                                         {\r
2746                                                 // since the user might have changed/removed/added\r
2747                                                 // properties recursively, we don't really know\r
2748                                                 // which items have changed their status.\r
2749                                                 // So tell the parent to do a refresh.\r
2750                                                 CWnd* pParent = GetParent();\r
2751                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
2752                                                 {\r
2753                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
2754                                                 }\r
2755                                         }\r
2756                                 }\r
2757                                 break;\r
2758                         case IDSVNLC_COMMIT:\r
2759                                 {\r
2760                                         CTSVNPathList targetList;\r
2761                                         FillListOfSelectedItemPaths(targetList);\r
2762                                         CTSVNPath tempFile = CTempFiles::Instance().GetTempFilePath(false);\r
2763                                         VERIFY(targetList.WriteToFile(tempFile.GetWinPathString()));\r
2764                                         CString commandline = CPathUtils::GetAppDirectory();\r
2765                                         commandline += _T("TortoiseProc.exe /command:commit /pathfile:\"");\r
2766                                         commandline += tempFile.GetWinPathString();\r
2767                                         commandline += _T("\"");\r
2768                                         commandline += _T(" /deletepathfile");\r
2769                                         CAppUtils::LaunchApplication(commandline, NULL, false);\r
2770                                 }\r
2771                                 break;\r
2772                         case IDSVNLC_REVERT:\r
2773                                 {\r
2774                                         // If at least one item is not in the status "added"\r
2775                                         // we ask for a confirmation\r
2776                                         BOOL bConfirm = FALSE;\r
2777                                         POSITION pos = GetFirstSelectedItemPosition();\r
2778                                         int index;\r
2779                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
2780                                         {\r
2781                                                 FileEntry * fentry = GetListEntry(index);\r
2782                                                 if (fentry->textstatus != git_wc_status_added)\r
2783                                                 {\r
2784                                                         bConfirm = TRUE;\r
2785                                                         break;\r
2786                                                 }\r
2787                                         }       \r
2788 \r
2789                                         CString str;\r
2790                                         str.Format(IDS_PROC_WARNREVERT,GetSelectedCount());\r
2791 \r
2792                                         if (!bConfirm || CMessageBox::Show(this->m_hWnd, str, _T("TortoiseSVN"), MB_YESNO | MB_ICONQUESTION)==IDYES)\r
2793                                         {\r
2794                                                 CTSVNPathList targetList;\r
2795                                                 FillListOfSelectedItemPaths(targetList);\r
2796 \r
2797                                                 // make sure that the list is reverse sorted, so that\r
2798                                                 // children are removed before any parents\r
2799                                                 targetList.SortByPathname(true);\r
2800 \r
2801                                                 SVN git;\r
2802 \r
2803                                                 // put all reverted files in the trashbin, except the ones with 'added'\r
2804                                                 // status because they are not restored by the revert.\r
2805                                                 CTSVNPathList delList;\r
2806                                                 POSITION pos = GetFirstSelectedItemPosition();\r
2807                                                 int index;\r
2808                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
2809                                                 {\r
2810                                                         FileEntry * entry = GetListEntry(index);\r
2811                                                         if (entry->status != git_wc_status_added)\r
2812                                                                 delList.AddPath(entry->GetPath());\r
2813                                                 }\r
2814                                                 if (DWORD(CRegDWORD(_T("Software\\TortoiseGit\\RevertWithRecycleBin"), TRUE)))\r
2815                                                         delList.DeleteAllFiles(true);\r
2816 \r
2817                                                 if (!git.Revert(targetList, CStringArray(), FALSE))\r
2818                                                 {\r
2819                                                         CMessageBox::Show(this->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
2820                                                 }\r
2821                                                 else\r
2822                                                 {\r
2823                                                         // since the entries got reverted we need to remove\r
2824                                                         // them from the list too, if no remote changes are shown,\r
2825                                                         // if the unmodified files are not shown\r
2826                                                         // and if the item is not part of a changelist\r
2827                                                         POSITION pos;\r
2828                                                         SetRedraw(FALSE);\r
2829                                                         while ((pos = GetFirstSelectedItemPosition())!=0)\r
2830                                                         {\r
2831                                                                 int index;\r
2832                                                                 index = GetNextSelectedItem(pos);\r
2833                                                                 FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
2834                                                                 if ( fentry->IsFolder() )\r
2835                                                                 {\r
2836                                                                         // refresh!\r
2837                                                                         CWnd* pParent = GetParent();\r
2838                                                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
2839                                                                         {\r
2840                                                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
2841                                                                         }\r
2842                                                                         break;\r
2843                                                                 }\r
2844 \r
2845                                                                 BOOL bAdded = (fentry->textstatus == git_wc_status_added);\r
2846                                                                 fentry->status = git_wc_status_normal;\r
2847                                                                 fentry->propstatus = git_wc_status_normal;\r
2848                                                                 fentry->textstatus = git_wc_status_normal;\r
2849                                                                 fentry->copied = false;\r
2850                                                                 fentry->isConflicted = false;\r
2851                                                                 if ((fentry->GetChangeList().IsEmpty()&&(fentry->remotestatus <= git_wc_status_normal))||(m_dwShow & SVNSLC_SHOWNORMAL))\r
2852                                                                 {\r
2853                                                                         if ( bAdded )\r
2854                                                                         {\r
2855                                                                                 // reverting added items makes them unversioned, not 'normal'\r
2856                                                                                 if (fentry->IsFolder())\r
2857                                                                                         fentry->propstatus = git_wc_status_none;\r
2858                                                                                 else\r
2859                                                                                         fentry->propstatus = git_wc_status_unversioned;\r
2860                                                                                 fentry->status = git_wc_status_unversioned;\r
2861                                                                                 fentry->textstatus = git_wc_status_unversioned;\r
2862                                                                                 SetItemState(index, 0, LVIS_SELECTED);\r
2863                                                                                 SetEntryCheck(fentry, index, false);\r
2864                                                                         }\r
2865                                                                         else if ((fentry->switched)||(m_dwShow & SVNSLC_SHOWNORMAL))\r
2866                                                                         {\r
2867                                                                                 SetItemState(index, 0, LVIS_SELECTED);\r
2868                                                                         }\r
2869                                                                         else\r
2870                                                                         {\r
2871                                                                                 m_nTotal--;\r
2872                                                                                 if (GetCheck(index))\r
2873                                                                                         m_nSelected--;\r
2874                                                                                 RemoveListEntry(index);\r
2875                                                                                 Invalidate();\r
2876                                                                         }\r
2877                                                                 }\r
2878                                                                 else\r
2879                                                                 {\r
2880                                                                         SetItemState(index, 0, LVIS_SELECTED);\r
2881                                                                 }\r
2882                                                         }\r
2883                                                         SetRedraw(TRUE);\r
2884                                                         SaveColumnWidths();\r
2885                                                         Show(m_dwShow, 0, m_bShowFolders);\r
2886                                                         NotifyCheck();\r
2887                                                 }\r
2888                                         }\r
2889                                 }\r
2890                                 break;\r
2891                         case IDSVNLC_COMPARE:\r
2892                                 {\r
2893                                         POSITION pos = GetFirstSelectedItemPosition();\r
2894                                         while ( pos )\r
2895                                         {\r
2896                                                 int index = GetNextSelectedItem(pos);\r
2897                                                 StartDiff(index);\r
2898                                         }\r
2899                                 }\r
2900                                 break;\r
2901                         case IDSVNLC_COMPAREWC:\r
2902                                 {\r
2903                                         POSITION pos = GetFirstSelectedItemPosition();\r
2904                                         while ( pos )\r
2905                                         {\r
2906                                                 int index = GetNextSelectedItem(pos);\r
2907                                                 FileEntry * entry = GetListEntry(index);\r
2908                                                 ASSERT(entry != NULL);\r
2909                                                 if (entry == NULL)\r
2910                                                         continue;\r
2911                                                 SVNDiff diff(NULL, m_hWnd, true);\r
2912                                                 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
2913                                                 git_revnum_t baseRev = entry->Revision;\r
2914                                                 diff.DiffFileAgainstBase(\r
2915                                                         entry->path, baseRev, entry->textstatus, entry->propstatus);\r
2916                                         }\r
2917                                 }\r
2918                                 break;\r
2919                         case IDSVNLC_GNUDIFF1:\r
2920                                 {\r
2921                                         SVNDiff diff(NULL, this->m_hWnd, true);\r
2922 \r
2923                                         if (entry->remotestatus <= git_wc_status_normal)\r
2924                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_BASE, entry->path, SVNRev::REV_WC);\r
2925                                         else\r
2926                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_WC, entry->path, SVNRev::REV_HEAD);\r
2927                                 }\r
2928                                 break;\r
2929                         case IDSVNLC_UPDATE:\r
2930                                 {\r
2931                                         CTSVNPathList targetList;\r
2932                                         FillListOfSelectedItemPaths(targetList);\r
2933                                         bool bAllExist = true;\r
2934                                         for (int i=0; i<targetList.GetCount(); ++i)\r
2935                                         {\r
2936                                                 if (!targetList[i].Exists())\r
2937                                                 {\r
2938                                                         bAllExist = false;\r
2939                                                         break;\r
2940                                                 }\r
2941                                         }\r
2942                                         if (bAllExist)\r
2943                                         {\r
2944                                                 CSVNProgressDlg dlg;\r
2945                                                 dlg.SetCommand(CSVNProgressDlg::SVNProgress_Update);\r
2946                                                 dlg.SetPathList(targetList);\r
2947                                                 dlg.SetRevision(SVNRev::REV_HEAD);\r
2948                                                 dlg.DoModal();\r
2949                                         }\r
2950                                         else\r
2951                                         {\r
2952                                                 CString sTempFile = CTempFiles::Instance().GetTempFilePath(false).GetWinPathString();\r
2953                                                 targetList.WriteToFile(sTempFile, false);\r
2954                                                 CString sCmd;\r
2955                                                 sCmd.Format(_T("\"%s\" /command:update /rev /pathfile:\"%s\" /deletepathfile"),\r
2956                                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), (LPCTSTR)sTempFile);\r
2957 \r
2958                                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
2959                                         }\r
2960                                 }\r
2961                                 break;\r
2962                         case IDSVNLC_LOG:\r
2963                                 {\r
2964                                         CString sCmd;\r
2965                                         sCmd.Format(_T("\"%s\" /command:log /path:\"%s\""),\r
2966                                                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
2967 \r
2968                                         if (!filepath.IsUrl())\r
2969                                         {\r
2970                                                 sCmd += _T(" /propspath:\"");\r
2971                                                 sCmd += filepath.GetWinPathString();\r
2972                                                 sCmd += _T("\"");\r
2973                                         }       \r
2974 \r
2975                                         CAppUtils::LaunchApplication(sCmd, NULL, false);\r
2976                                 }\r
2977                                 break;\r
2978                         case IDSVNLC_BLAME:\r
2979                                 {\r
2980                                         CString sCmd;\r
2981                                         sCmd.Format(_T("\"%s\" /command:blame /path:\"%s\""),\r
2982                                                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
2983 \r
2984                                         if (!filepath.IsUrl())\r
2985                                         {\r
2986                                                 sCmd += _T(" /propspath:\"");\r
2987                                                 sCmd += filepath.GetWinPathString();\r
2988                                                 sCmd += _T("\"");\r
2989                                         }       \r
2990 \r
2991                                         CAppUtils::LaunchApplication(sCmd, NULL, false);\r
2992                                 }\r
2993                                 break;\r
2994                         case IDSVNLC_OPEN:\r
2995                                 {\r
2996                                         int ret = (int)ShellExecute(this->m_hWnd, NULL, filepath.GetWinPath(), NULL, NULL, SW_SHOW);\r
2997                                         if (ret <= HINSTANCE_ERROR)\r
2998                                         {\r
2999                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
3000                                                 cmd += filepath.GetWinPathString();\r
3001                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
3002                                         }\r
3003                                 }\r
3004                                 break;\r
3005                         case IDSVNLC_OPENWITH:\r
3006                                 {\r
3007                                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
3008                                         cmd += filepath.GetWinPathString() + _T(" ");\r
3009                                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
3010                                 }\r
3011                                 break;\r
3012                         case IDSVNLC_EXPLORE:\r
3013                                 {\r
3014                                         ShellExecute(this->m_hWnd, _T("explore"), filepath.GetDirectory().GetWinPath(), NULL, NULL, SW_SHOW);\r
3015                                 }\r
3016                                 break;\r
3017                         case IDSVNLC_REMOVE:\r
3018                                 {\r
3019                                         SVN git;\r
3020                                         CTSVNPathList itemsToRemove;\r
3021                                         FillListOfSelectedItemPaths(itemsToRemove);\r
3022 \r
3023                                         // We must sort items before removing, so that files are always removed\r
3024                                         // *before* their parents\r
3025                                         itemsToRemove.SortByPathname(true);\r
3026 \r
3027                                         bool bSuccess = false;\r
3028                                         if (git.Remove(itemsToRemove, FALSE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
3029                                         {\r
3030                                                 bSuccess = true;\r
3031                                         }\r
3032                                         else\r
3033                                         {\r
3034                                                 if ((git.Err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE) ||\r
3035                                                         (git.Err->apr_err == SVN_ERR_CLIENT_MODIFIED))\r
3036                                                 {\r
3037                                                         CString msg, yes, no, yestoall;\r
3038                                                         msg.Format(IDS_PROC_REMOVEFORCE, (LPCTSTR)git.GetLastErrorMessage());\r
3039                                                         yes.LoadString(IDS_MSGBOX_YES);\r
3040                                                         no.LoadString(IDS_MSGBOX_NO);\r
3041                                                         yestoall.LoadString(IDS_PROC_YESTOALL);\r
3042                                                         UINT ret = CMessageBox::Show(m_hWnd, msg, _T("TortoiseSVN"), 2, IDI_ERROR, yes, no, yestoall);\r
3043                                                         if ((ret == 1)||(ret==3))\r
3044                                                         {\r
3045                                                                 if (!git.Remove(itemsToRemove, TRUE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
3046                                                                 {\r
3047                                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3048                                                                 }\r
3049                                                                 else\r
3050                                                                         bSuccess = true;\r
3051                                                         }\r
3052                                                 }\r
3053                                                 else\r
3054                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3055                                         }\r
3056                                         if (bSuccess)\r
3057                                         {\r
3058                                                 // The remove went ok, but we now need to run through the selected items again\r
3059                                                 // and update their status\r
3060                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3061                                                 int index;\r
3062                                                 std::vector<int> entriesToRemove;\r
3063                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3064                                                 {\r
3065                                                         FileEntry * e = GetListEntry(index);\r
3066                                                         if (!bShift &&\r
3067                                                                 ((e->textstatus == git_wc_status_unversioned)||\r
3068                                                                 (e->textstatus == git_wc_status_none)||\r
3069                                                                 (e->textstatus == git_wc_status_ignored)))\r
3070                                                         {\r
3071                                                                 if (GetCheck(index))\r
3072                                                                         m_nSelected--;\r
3073                                                                 m_nTotal--;\r
3074                                                                 entriesToRemove.push_back(index);\r
3075                                                         }\r
3076                                                         else\r
3077                                                         {\r
3078                                                                 e->textstatus = git_wc_status_deleted;\r
3079                                                                 e->status = git_wc_status_deleted;\r
3080                                                                 SetEntryCheck(e,index,true);\r
3081                                                         }\r
3082                                                 }\r
3083                                                 for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
3084                                                 {\r
3085                                                         RemoveListEntry(*it);\r
3086                                                 }\r
3087                                         }\r
3088                                         SaveColumnWidths();\r
3089                                         Show(m_dwShow, 0, m_bShowFolders);\r
3090                                         NotifyCheck();\r
3091                                 }\r
3092                                 break;\r
3093                         case IDSVNLC_DELETE:\r
3094                                 {\r
3095                                         CTSVNPathList pathlist;\r
3096                                         FillListOfSelectedItemPaths(pathlist);\r
3097                                         pathlist.RemoveChildren();\r
3098                                         CString filelist;\r
3099                                         for (INT_PTR i=0; i<pathlist.GetCount(); ++i)\r
3100                                         {\r
3101                                                 filelist += pathlist[i].GetWinPathString();\r
3102                                                 filelist += _T("|");\r
3103                                         }\r
3104                                         filelist += _T("|");\r
3105                                         int len = filelist.GetLength();\r
3106                                         TCHAR * buf = new TCHAR[len+2];\r
3107                                         _tcscpy_s(buf, len+2, filelist);\r
3108                                         for (int i=0; i<len; ++i)\r
3109                                                 if (buf[i] == '|')\r
3110                                                         buf[i] = 0;\r
3111                                         SHFILEOPSTRUCT fileop;\r
3112                                         fileop.hwnd = this->m_hWnd;\r
3113                                         fileop.wFunc = FO_DELETE;\r
3114                                         fileop.pFrom = buf;\r
3115                                         fileop.pTo = NULL;\r
3116                                         fileop.fFlags = FOF_NO_CONNECTED_ELEMENTS | ((GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 0 : FOF_ALLOWUNDO);\r
3117                                         fileop.lpszProgressTitle = _T("deleting file");\r
3118                                         int result = SHFileOperation(&fileop);\r
3119                                         delete [] buf;\r
3120 \r
3121                                         if ( (result==0) && (!fileop.fAnyOperationsAborted) )\r
3122                                         {\r
3123                                                 SetRedraw(FALSE);\r
3124                                                 POSITION pos = NULL;\r
3125                                                 CTSVNPathList deletedlist;      // to store list of deleted folders\r
3126                                                 while ((pos = GetFirstSelectedItemPosition()) != 0)\r
3127                                                 {\r
3128                                                         int index = GetNextSelectedItem(pos);\r
3129                                                         if (GetCheck(index))\r
3130                                                                 m_nSelected--;\r
3131                                                         m_nTotal--;\r
3132                                                         FileEntry * fentry = GetListEntry(index);\r
3133                                                         if ((fentry)&&(fentry->isfolder))\r
3134                                                                 deletedlist.AddPath(fentry->path);\r
3135                                                         RemoveListEntry(index);\r
3136                                                 }\r
3137                                                 // now go through the list of deleted folders\r
3138                                                 // and remove all their children from the list too!\r
3139                                                 int nListboxEntries = GetItemCount();\r
3140                                                 for (int folderindex = 0; folderindex < deletedlist.GetCount(); ++folderindex)\r
3141                                                 {\r
3142                                                         CTSVNPath folderpath = deletedlist[folderindex];\r
3143                                                         for (int i=0; i<nListboxEntries; ++i)\r
3144                                                         {\r
3145                                                                 FileEntry * entry = GetListEntry(i);\r
3146                                                                 if (folderpath.IsAncestorOf(entry->path))\r
3147                                                                 {\r
3148                                                                         RemoveListEntry(i--);\r
3149                                                                         nListboxEntries--;\r
3150                                                                 }\r
3151                                                         }\r
3152                                                 }\r
3153                                                 SetRedraw(TRUE);\r
3154                                         }\r
3155                                 }\r
3156                                 break;\r
3157                         case IDSVNLC_IGNOREMASK:\r
3158                                 {\r
3159                                         CString name = _T("*")+filepath.GetFileExtension();\r
3160                                         CTSVNPathList ignorelist;\r
3161                                         FillListOfSelectedItemPaths(ignorelist, true);\r
3162                                         std::set<CTSVNPath> parentlist;\r
3163                                         for (int i=0; i<ignorelist.GetCount(); ++i)\r
3164                                         {\r
3165                                                 parentlist.insert(ignorelist[i].GetContainingDirectory());\r
3166                                         }\r
3167                                         std::set<CTSVNPath>::iterator it;\r
3168                                         std::vector<CString> toremove;\r
3169                                         SetRedraw(FALSE);\r
3170                                         for (it = parentlist.begin(); it != parentlist.end(); ++it)\r
3171                                         {\r
3172                                                 CTSVNPath parentFolder = (*it).GetDirectory();\r
3173                                                 SVNProperties props(parentFolder, SVNRev::REV_WC, false);\r
3174                                                 CStringA value;\r
3175                                                 for (int i=0; i<props.GetCount(); i++)\r
3176                                                 {\r
3177                                                         CString propname(props.GetItemName(i).c_str());\r
3178                                                         if (propname.CompareNoCase(_T("git:ignore"))==0)\r
3179                                                         {\r
3180                                                                 stdstring stemp;\r
3181                                                                 // treat values as normal text even if they're not\r
3182                                                                 value = (char *)props.GetItemValue(i).c_str();\r
3183                                                         }\r
3184                                                 }\r
3185                                                 if (value.IsEmpty())\r
3186                                                         value = name;\r
3187                                                 else\r
3188                                                 {\r
3189                                                         value = value.Trim("\n\r");\r
3190                                                         value += "\n";\r
3191                                                         value += name;\r
3192                                                         value.Remove('\r');\r
3193                                                 }\r
3194                                                 if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
3195                                                 {\r
3196                                                         CString temp;\r
3197                                                         temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
3198                                                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
3199                                                 }\r
3200                                                 else\r
3201                                                 {\r
3202                                                         CTSVNPath basepath;\r
3203                                                         int nListboxEntries = GetItemCount();\r
3204                                                         for (int i=0; i<nListboxEntries; ++i)\r
3205                                                         {\r
3206                                                                 FileEntry * entry = GetListEntry(i);\r
3207                                                                 ASSERT(entry != NULL);\r
3208                                                                 if (entry == NULL)\r
3209                                                                         continue;\r
3210                                                                 if (basepath.IsEmpty())\r
3211                                                                         basepath = entry->basepath;\r
3212                                                                 // since we ignored files with a mask (e.g. *.exe)\r
3213                                                                 // we have to find find all files in the same\r
3214                                                                 // folder (IsAncestorOf() returns TRUE for _all_ children,\r
3215                                                                 // not just the immediate ones) which match the\r
3216                                                                 // mask and remove them from the list too.\r
3217                                                                 if ((entry->status == git_wc_status_unversioned)&&(parentFolder.IsAncestorOf(entry->path)))\r
3218                                                                 {\r
3219                                                                         CString f = entry->path.GetSVNPathString();\r
3220                                                                         if (f.Mid(parentFolder.GetSVNPathString().GetLength()).Find('/')<=0)\r
3221                                                                         {\r
3222                                                                                 if (CStringUtils::WildCardMatch(name, f))\r
3223                                                                                 {\r
3224                                                                                         if (GetCheck(i))\r
3225                                                                                                 m_nSelected--;\r
3226                                                                                         m_nTotal--;\r
3227                                                                                         toremove.push_back(f);\r
3228                                                                                 }\r
3229                                                                         }\r
3230                                                                 }\r
3231                                                         }\r
3232                                                         if (!m_bIgnoreRemoveOnly)\r
3233                                                         {\r
3234                                                                 SVNStatus status;\r
3235                                                                 git_wc_status2_t * s;\r
3236                                                                 CTSVNPath gitPath;\r
3237                                                                 s = status.GetFirstFileStatus(parentFolder, gitPath, false, git_depth_empty);\r
3238                                                                 if (s!=0)\r
3239                                                                 {\r
3240                                                                         // first check if the folder isn't already present in the list\r
3241                                                                         bool bFound = false;\r
3242                                                                         for (int i=0; i<nListboxEntries; ++i)\r
3243                                                                         {\r
3244                                                                                 FileEntry * entry = GetListEntry(i);\r
3245                                                                                 if (entry->path.IsEquivalentTo(gitPath))\r
3246                                                                                 {\r
3247                                                                                         bFound = true;\r
3248                                                                                         break;\r
3249                                                                                 }\r
3250                                                                         }\r
3251                                                                         if (!bFound)\r
3252                                                                         {\r
3253                                                                                 FileEntry * entry = new FileEntry();\r
3254                                                                                 entry->path = gitPath;\r
3255                                                                                 entry->basepath = basepath;\r
3256                                                                                 entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
3257                                                                                 entry->textstatus = s->text_status;\r
3258                                                                                 entry->propstatus = s->prop_status;\r
3259                                                                                 entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
3260                                                                                 entry->remotetextstatus = s->repos_text_status;\r
3261                                                                                 entry->remotepropstatus = s->repos_prop_status;\r
3262                                                                                 entry->inunversionedfolder = false;\r
3263                                                                                 entry->checked = true;\r
3264                                                                                 entry->inexternal = false;\r
3265                                                                                 entry->direct = false;\r
3266                                                                                 entry->isfolder = true;\r
3267                                                                                 entry->last_commit_date = 0;\r
3268                                                                                 entry->last_commit_rev = 0;\r
3269                                                                                 entry->remoterev = 0;\r
3270                                                                                 if (s->entry)\r
3271                                                                                 {\r
3272                                                                                         if (s->entry->url)\r
3273                                                                                         {\r
3274                                                                                                 entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
3275                                                                                         }\r
3276                                                                                 }\r
3277                                                                                 if (s->entry && s->entry->present_props)\r
3278                                                                                 {\r
3279                                                                                         entry->present_props = s->entry->present_props;\r
3280                                                                                 }\r
3281                                                                                 m_arStatusArray.push_back(entry);\r
3282                                                                                 m_arListArray.push_back(m_arStatusArray.size()-1);\r
3283                                                                                 AddEntry(entry, langID, GetItemCount());\r
3284                                                                         }\r
3285                                                                 }\r
3286                                                         }\r
3287                                                 }\r
3288                                         }\r
3289                                         for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
3290                                         {\r
3291                                                 int nListboxEntries = GetItemCount();\r
3292                                                 for (int i=0; i<nListboxEntries; ++i)\r
3293                                                 {\r
3294                                                         if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
3295                                                         {\r
3296                                                                 RemoveListEntry(i);\r
3297                                                                 break;\r
3298                                                         }\r
3299                                                 }\r
3300                                         }\r
3301                                         SetRedraw(TRUE);\r
3302                                 }\r
3303                                 break;\r
3304                         case IDSVNLC_IGNORE:\r
3305                                 {\r
3306                                         CTSVNPathList ignorelist;\r
3307                                         std::vector<CString> toremove;\r
3308                                         FillListOfSelectedItemPaths(ignorelist, true);\r
3309                                         SetRedraw(FALSE);\r
3310                                         for (int j=0; j<ignorelist.GetCount(); ++j)\r
3311                                         {\r
3312                                                 int nListboxEntries = GetItemCount();\r
3313                                                 for (int i=0; i<nListboxEntries; ++i)\r
3314                                                 {\r
3315                                                         if (GetListEntry(i)->GetPath().IsEquivalentTo(ignorelist[j]))\r
3316                                                         {\r
3317                                                                 selIndex = i;\r
3318                                                                 break;\r
3319                                                         }\r
3320                                                 }\r
3321                                                 CString name = CPathUtils::PathPatternEscape(ignorelist[j].GetFileOrDirectoryName());\r
3322                                                 CTSVNPath parentfolder = ignorelist[j].GetContainingDirectory();\r
3323                                                 SVNProperties props(parentfolder, SVNRev::REV_WC, false);\r
3324                                                 CStringA value;\r
3325                                                 for (int i=0; i<props.GetCount(); i++)\r
3326                                                 {\r
3327                                                         CString propname(props.GetItemName(i).c_str());\r
3328                                                         if (propname.CompareNoCase(_T("git:ignore"))==0)\r
3329                                                         {\r
3330                                                                 stdstring stemp;\r
3331                                                                 // treat values as normal text even if they're not\r
3332                                                                 value = (char *)props.GetItemValue(i).c_str();\r
3333                                                         }\r
3334                                                 }\r
3335                                                 if (value.IsEmpty())\r
3336                                                         value = name;\r
3337                                                 else\r
3338                                                 {\r
3339                                                         value = value.Trim("\n\r");\r
3340                                                         value += "\n";\r
3341                                                         value += name;\r
3342                                                         value.Remove('\r');\r
3343                                                 }\r
3344                                                 if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
3345                                                 {\r
3346                                                         CString temp;\r
3347                                                         temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
3348                                                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
3349                                                         break;\r
3350                                                 }\r
3351                                                 if (GetCheck(selIndex))\r
3352                                                         m_nSelected--;\r
3353                                                 m_nTotal--;\r
3354 \r
3355                                                 // now, if we ignored a folder, remove all its children\r
3356                                                 if (ignorelist[j].IsDirectory())\r
3357                                                 {\r
3358                                                         for (int i=0; i<(int)m_arListArray.size(); ++i)\r
3359                                                         {\r
3360                                                                 FileEntry * entry = GetListEntry(i);\r
3361                                                                 if (entry->status == git_wc_status_unversioned)\r
3362                                                                 {\r
3363                                                                         if (!ignorelist[j].IsEquivalentTo(entry->GetPath())&&(ignorelist[j].IsAncestorOf(entry->GetPath())))\r
3364                                                                         {\r
3365                                                                                 entry->status = git_wc_status_ignored;\r
3366                                                                                 entry->textstatus = git_wc_status_ignored;\r
3367                                                                                 if (GetCheck(i))\r
3368                                                                                         m_nSelected--;\r
3369                                                                                 toremove.push_back(entry->GetPath().GetSVNPathString());\r
3370                                                                         }\r
3371                                                                 }\r
3372                                                         }\r
3373                                                 }\r
3374 \r
3375                                                 CTSVNPath basepath = m_arStatusArray[m_arListArray[selIndex]]->basepath;\r
3376 \r
3377                                                 FileEntry * entry = m_arStatusArray[m_arListArray[selIndex]];\r
3378                                                 if ( entry->status == git_wc_status_unversioned ) // keep "deleted" items\r
3379                                                         toremove.push_back(entry->GetPath().GetSVNPathString());\r
3380 \r
3381                                                 if (!m_bIgnoreRemoveOnly)\r
3382                                                 {\r
3383                                                         SVNStatus status;\r
3384                                                         git_wc_status2_t * s;\r
3385                                                         CTSVNPath gitPath;\r
3386                                                         s = status.GetFirstFileStatus(parentfolder, gitPath, false, git_depth_empty);\r
3387                                                         // first check if the folder isn't already present in the list\r
3388                                                         bool bFound = false;\r
3389                                                         nListboxEntries = GetItemCount();\r
3390                                                         for (int i=0; i<nListboxEntries; ++i)\r
3391                                                         {\r
3392                                                                 FileEntry * entry = GetListEntry(i);\r
3393                                                                 if (entry->path.IsEquivalentTo(gitPath))\r
3394                                                                 {\r
3395                                                                         bFound = true;\r
3396                                                                         break;\r
3397                                                                 }\r
3398                                                         }\r
3399                                                         if (!bFound)\r
3400                                                         {\r
3401                                                                 if (s!=0)\r
3402                                                                 {\r
3403                                                                         FileEntry * entry = new FileEntry();\r
3404                                                                         entry->path = gitPath;\r
3405                                                                         entry->basepath = basepath;\r
3406                                                                         entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
3407                                                                         entry->textstatus = s->text_status;\r
3408                                                                         entry->propstatus = s->prop_status;\r
3409                                                                         entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
3410                                                                         entry->remotetextstatus = s->repos_text_status;\r
3411                                                                         entry->remotepropstatus = s->repos_prop_status;\r
3412                                                                         entry->inunversionedfolder = FALSE;\r
3413                                                                         entry->checked = true;\r
3414                                                                         entry->inexternal = false;\r
3415                                                                         entry->direct = false;\r
3416                                                                         entry->isfolder = true;\r
3417                                                                         entry->last_commit_date = 0;\r
3418                                                                         entry->last_commit_rev = 0;\r
3419                                                                         entry->remoterev = 0;\r
3420                                                                         if (s->entry)\r
3421                                                                         {\r
3422                                                                                 if (s->entry->url)\r
3423                                                                                 {\r
3424                                                                                         entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
3425                                                                                 }\r
3426                                                                         }\r
3427                                                                         if (s->entry && s->entry->present_props)\r
3428                                                                         {\r
3429                                                                                 entry->present_props = s->entry->present_props;\r
3430                                                                         }\r
3431                                                                         m_arStatusArray.push_back(entry);\r
3432                                                                         m_arListArray.push_back(m_arStatusArray.size()-1);\r
3433                                                                         AddEntry(entry, langID, GetItemCount());\r
3434                                                                 }\r
3435                                                         }\r
3436                                                 }\r
3437                                         }\r
3438                                         for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
3439                                         {\r
3440                                                 int nListboxEntries = GetItemCount();\r
3441                                                 for (int i=0; i<nListboxEntries; ++i)\r
3442                                                 {\r
3443                                                         if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
3444                                                         {\r
3445                                                                 RemoveListEntry(i);\r
3446                                                                 break;\r
3447                                                         }\r
3448                                                 }\r
3449                                         }\r
3450                                         SetRedraw(TRUE);\r
3451                                 }\r
3452                                 break;\r
3453                         case IDSVNLC_EDITCONFLICT:\r
3454                                 SVNDiff::StartConflictEditor(filepath);\r
3455                                 break;\r
3456                         case IDSVNLC_RESOLVECONFLICT:\r
3457                         case IDSVNLC_RESOLVEMINE:\r
3458                         case IDSVNLC_RESOLVETHEIRS:\r
3459                                 {\r
3460                                         git_wc_conflict_choice_t result = git_wc_conflict_choose_merged;\r
3461                                         switch (cmd)\r
3462                                         {\r
3463                                         case IDSVNLC_RESOLVETHEIRS:\r
3464                                                 result = git_wc_conflict_choose_theirs_full;\r
3465                                                 break;\r
3466                                         case IDSVNLC_RESOLVEMINE:\r
3467                                                 result = git_wc_conflict_choose_mine_full;\r
3468                                                 break;\r
3469                                         case IDSVNLC_RESOLVECONFLICT:\r
3470                                                 result = git_wc_conflict_choose_merged;\r
3471                                                 break;\r
3472                                         }\r
3473                                         if (CMessageBox::Show(m_hWnd, IDS_PROC_RESOLVE, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO)==IDYES)\r
3474                                         {\r
3475                                                 SVN git;\r
3476                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3477                                                 while (pos != 0)\r
3478                                                 {\r
3479                                                         int index;\r
3480                                                         index = GetNextSelectedItem(pos);\r
3481                                                         FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
3482                                                         if (!git.Resolve(fentry->GetPath(), result, FALSE))\r
3483                                                         {\r
3484                                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3485                                                         }\r
3486                                                         else\r
3487                                                         {\r
3488                                                                 fentry->status = git_wc_status_modified;\r
3489                                                                 fentry->textstatus = git_wc_status_modified;\r
3490                                                                 fentry->isConflicted = false;\r
3491                                                         }\r
3492                                                 }\r
3493                                                 Show(m_dwShow, 0, m_bShowFolders);\r
3494                                         }\r
3495                                 }\r
3496                                 break;\r
3497                         case IDSVNLC_ADD:\r
3498                                 {\r
3499                                         SVN git;\r
3500                                         CTSVNPathList itemsToAdd;\r
3501                                         FillListOfSelectedItemPaths(itemsToAdd);\r
3502 \r
3503                                         // We must sort items before adding, so that folders are always added\r
3504                                         // *before* any of their children\r
3505                                         itemsToAdd.SortByPathname();\r
3506 \r
3507                                         ProjectProperties props;\r
3508                                         props.ReadPropsPathList(itemsToAdd);\r
3509                                         if (git.Add(itemsToAdd, &props, git_depth_empty, TRUE, TRUE, TRUE))\r
3510                                         {\r
3511                                                 // The add went ok, but we now need to run through the selected items again\r
3512                                                 // and update their status\r
3513                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3514                                                 int index;\r
3515                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3516                                                 {\r
3517                                                         FileEntry * e = GetListEntry(index);\r
3518                                                         e->textstatus = git_wc_status_added;\r
3519                                                         e->propstatus = git_wc_status_none;\r
3520                                                         e->status = git_wc_status_added;\r
3521                                                         SetEntryCheck(e,index,true);\r
3522                                                 }\r
3523                                         }\r
3524                                         else\r
3525                                         {\r
3526                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3527                                         }\r
3528                                         SaveColumnWidths();\r
3529                                         Show(m_dwShow, 0, m_bShowFolders);\r
3530                                         NotifyCheck();\r
3531                                 }\r
3532                                 break;\r
3533                         case IDSVNLC_ADD_RECURSIVE:\r
3534                                 {\r
3535                                         CTSVNPathList itemsToAdd;\r
3536                                         FillListOfSelectedItemPaths(itemsToAdd);\r
3537 \r
3538                                         CAddDlg dlg;\r
3539                                         dlg.m_pathList = itemsToAdd;\r
3540                                         if (dlg.DoModal() == IDOK)\r
3541                                         {\r
3542                                                 if (dlg.m_pathList.GetCount() == 0)\r
3543                                                         break;\r
3544                                                 CSVNProgressDlg progDlg;\r
3545                                                 progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Add);\r
3546                                                 progDlg.SetPathList(dlg.m_pathList);\r
3547                                                 ProjectProperties props;\r
3548                                                 props.ReadPropsPathList(dlg.m_pathList);\r
3549                                                 progDlg.SetProjectProperties(props);\r
3550                                                 progDlg.SetItemCount(dlg.m_pathList.GetCount());\r
3551                                                 progDlg.DoModal();\r
3552 \r
3553                                                 // refresh!\r
3554                                                 CWnd* pParent = GetParent();\r
3555                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3556                                                 {\r
3557                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3558                                                 }\r
3559                                         }\r
3560                                 }\r
3561                                 break;\r
3562                         case IDSVNLC_LOCK:\r
3563                                 {\r
3564                                         CTSVNPathList itemsToLock;\r
3565                                         FillListOfSelectedItemPaths(itemsToLock);\r
3566                                         CInputDlg inpDlg;\r
3567                                         inpDlg.m_sTitle.LoadString(IDS_MENU_LOCK);\r
3568                                         CStringUtils::RemoveAccelerators(inpDlg.m_sTitle);\r
3569                                         inpDlg.m_sHintText.LoadString(IDS_LOCK_MESSAGEHINT);\r
3570                                         inpDlg.m_sCheckText.LoadString(IDS_LOCK_STEALCHECK);\r
3571                                         ProjectProperties props;\r
3572                                         props.ReadPropsPathList(itemsToLock);\r
3573                                         props.nMinLogSize = 0;          // the lock message is optional, so no minimum!\r
3574                                         inpDlg.m_pProjectProperties = &props;\r
3575                                         if (inpDlg.DoModal()==IDOK)\r
3576                                         {\r
3577                                                 CSVNProgressDlg progDlg;\r
3578                                                 progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Lock);\r
3579                                                 progDlg.SetOptions(inpDlg.m_iCheck ? ProgOptLockForce : ProgOptNone);\r
3580                                                 progDlg.SetPathList(itemsToLock);\r
3581                                                 progDlg.SetCommitMessage(inpDlg.m_sInputText);\r
3582                                                 progDlg.DoModal();\r
3583                                                 // refresh!\r
3584                                                 CWnd* pParent = GetParent();\r
3585                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3586                                                 {\r
3587                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3588                                                 }\r
3589                                         }\r
3590                                 }\r
3591                                 break;\r
3592                         case IDSVNLC_UNLOCKFORCE:\r
3593                                 bForce = true;\r
3594                         case IDSVNLC_UNLOCK:\r
3595                                 {\r
3596                                         CTSVNPathList itemsToUnlock;\r
3597                                         FillListOfSelectedItemPaths(itemsToUnlock);\r
3598                                         CSVNProgressDlg progDlg;\r
3599                                         progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Unlock);\r
3600                                         progDlg.SetOptions(bForce ? ProgOptLockForce : ProgOptNone);\r
3601                                         progDlg.SetPathList(itemsToUnlock);\r
3602                                         progDlg.DoModal();\r
3603                                         // refresh!\r
3604                                         CWnd* pParent = GetParent();\r
3605                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3606                                         {\r
3607                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3608                                         }\r
3609                                 }\r
3610                                 break;\r
3611                         case IDSVNLC_REPAIRMOVE:\r
3612                                 {\r
3613                                         POSITION pos = GetFirstSelectedItemPosition();\r
3614                                         int index = GetNextSelectedItem(pos);\r
3615                                         FileEntry * entry1 = NULL;\r
3616                                         FileEntry * entry2 = NULL;\r
3617                                         if (index >= 0)\r
3618                                         {\r
3619                                                 entry1 = GetListEntry(index);\r
3620                                                 git_wc_status_kind status1 = git_wc_status_none;\r
3621                                                 git_wc_status_kind status2 = git_wc_status_none;\r
3622                                                 if (entry1)\r
3623                                                 {\r
3624                                                         status1 = entry1->status;\r
3625                                                         index = GetNextSelectedItem(pos);\r
3626                                                         if (index >= 0)\r
3627                                                         {\r
3628                                                                 entry2 = GetListEntry(index);\r
3629                                                                 if (entry2)\r
3630                                                                 {\r
3631                                                                         status2 = entry2->status;\r
3632                                                                         if (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned)\r
3633                                                                         {\r
3634                                                                                 FileEntry * tempentry = entry1;\r
3635                                                                                 entry1 = entry2;\r
3636                                                                                 entry2 = tempentry;\r
3637                                                                         }\r
3638                                                                         // entry1 was renamed to entry2 but outside of Subversion\r
3639                                                                         // fix this by moving entry2 back to entry1 first,\r
3640                                                                         // then do an git-move from entry1 to entry2\r
3641                                                                         if (MoveFile(entry2->GetPath().GetWinPath(), entry1->GetPath().GetWinPath()))\r
3642                                                                         {\r
3643                                                                                 SVN git;\r
3644                                                                                 if (!git.Move(CTSVNPathList(entry1->GetPath()), entry2->GetPath(), TRUE))\r
3645                                                                                 {\r
3646                                                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3647                                                                                 }\r
3648                                                                                 else\r
3649                                                                                 {\r
3650                                                                                         // check the previously unversioned item\r
3651                                                                                         entry1->checked = true;\r
3652                                                                                         // fixing the move was successful. We have to adjust the new status of the\r
3653                                                                                         // files.\r
3654                                                                                         // Since we don't know if the moved/renamed file had local modifications or not,\r
3655                                                                                         // we can't guess the new status. That means we have to refresh...\r
3656                                                                                         CWnd* pParent = GetParent();\r
3657                                                                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3658                                                                                         {\r
3659                                                                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3660                                                                                         }\r
3661                                                                                 }\r
3662                                                                         }\r
3663                                                                         else\r
3664                                                                         {\r
3665                                                                                 LPVOID lpMsgBuf;\r
3666                                                                                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
3667                                                                                         FORMAT_MESSAGE_FROM_SYSTEM | \r
3668                                                                                         FORMAT_MESSAGE_IGNORE_INSERTS,\r
3669                                                                                         NULL,\r
3670                                                                                         GetLastError(),\r
3671                                                                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
3672                                                                                         (LPTSTR) &lpMsgBuf,\r
3673                                                                                         0,\r
3674                                                                                         NULL \r
3675                                                                                         );\r
3676                                                                                 MessageBox((LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );\r
3677                                                                                 LocalFree( lpMsgBuf );\r
3678                                                                         }\r
3679                                                                 }\r
3680                                                         }\r
3681                                                 }\r
3682                                         }\r
3683                                 }\r
3684                                 break;\r
3685                         case IDSVNLC_REMOVEFROMCS:\r
3686                                 {\r
3687                                         CTSVNPathList changelistItems;\r
3688                                         FillListOfSelectedItemPaths(changelistItems);\r
3689                                         SVN git;\r
3690                                         SetRedraw(FALSE);\r
3691                                         if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
3692                                         {\r
3693                                                 // The changelists were removed, but we now need to run through the selected items again\r
3694                                                 // and update their changelist\r
3695                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3696                                                 int index;\r
3697                                                 std::vector<int> entriesToRemove;\r
3698                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3699                                                 {\r
3700                                                         FileEntry * e = GetListEntry(index);\r
3701                                                         if (e)\r
3702                                                         {\r
3703                                                                 e->changelist.Empty();\r
3704                                                                 if (e->status == git_wc_status_normal)\r
3705                                                                 {\r
3706                                                                         // remove the entry completely\r
3707                                                                         entriesToRemove.push_back(index);\r
3708                                                                 }\r
3709                                                                 else\r
3710                                                                         SetItemGroup(index, 0);\r
3711                                                         }\r
3712                                                 }\r
3713                                                 for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
3714                                                 {\r
3715                                                         RemoveListEntry(*it);\r
3716                                                 }\r
3717                                                 // TODO: Should we go through all entries here and check if we also could\r
3718                                                 // remove the changelist from m_changelists ?\r
3719                                         }\r
3720                                         else\r
3721                                         {\r
3722                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3723                                         }\r
3724                                         SetRedraw(TRUE);\r
3725                                 }\r
3726                                 break;\r
3727                         case IDSVNLC_CREATEIGNORECS:\r
3728                                 CreateChangeList(SVNSLC_IGNORECHANGELIST);\r
3729                                 break;\r
3730                         case IDSVNLC_CREATECS:\r
3731                                 {\r
3732                                         CCreateChangelistDlg dlg;\r
3733                                         if (dlg.DoModal() == IDOK)\r
3734                                         {\r
3735                                                 CreateChangeList(dlg.m_sName);\r
3736                                         }\r
3737                                 }\r
3738                                 break;\r
3739                         default:\r
3740                                 {\r
3741                                         if (cmd < IDSVNLC_MOVETOCS)\r
3742                                                 break;\r
3743                                         CTSVNPathList changelistItems;\r
3744                                         FillListOfSelectedItemPaths(changelistItems);\r
3745 \r
3746                                         // find the changelist name\r
3747                                         CString sChangelist;\r
3748                                         int cmdID = IDSVNLC_MOVETOCS;\r
3749                                         SetRedraw(FALSE);\r
3750                                         for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
3751                                         {\r
3752                                                 if ((it->first.Compare(SVNSLC_IGNORECHANGELIST))&&(entry->changelist.Compare(it->first)))\r
3753                                                 {\r
3754                                                         if (cmd == cmdID)\r
3755                                                         {\r
3756                                                                 sChangelist = it->first;\r
3757                                                         }\r
3758                                                         cmdID++;\r
3759                                                 }\r
3760                                         }\r
3761                                         if (!sChangelist.IsEmpty())\r
3762                                         {\r
3763                                                 SVN git;\r
3764                                                 if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
3765                                                 {\r
3766                                                         // The changelists were moved, but we now need to run through the selected items again\r
3767                                                         // and update their changelist\r
3768                                                         POSITION pos = GetFirstSelectedItemPosition();\r
3769                                                         int index;\r
3770                                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
3771                                                         {\r
3772                                                                 FileEntry * e = GetListEntry(index);\r
3773                                                                 e->changelist = sChangelist;\r
3774                                                                 if (!e->IsFolder())\r
3775                                                                 {\r
3776                                                                         if (m_changelists.find(e->changelist)!=m_changelists.end())\r
3777                                                                                 SetItemGroup(index, m_changelists[e->changelist]);\r
3778                                                                         else\r
3779                                                                                 SetItemGroup(index, 0);\r
3780                                                                 }\r
3781                                                         }\r
3782                                                 }\r
3783                                                 else\r
3784                                                 {\r
3785                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3786                                                 }\r
3787                                         }\r
3788                                         SetRedraw(TRUE);\r
3789                                 }\r
3790                                 break;\r
3791 #endif\r
3792 \r
3793                         } // switch (cmd)\r
3794                         m_bBlock = FALSE;\r
3795                         AfxGetApp()->DoWaitCursor(-1);\r
3796                         GetStatisticsString();\r
3797                         int iItemCountAfterMenuCmd = GetItemCount();\r
3798                         //if (iItemCountAfterMenuCmd != iItemCountBeforeMenuCmd)\r
3799                         //{\r
3800                         //      CWnd* pParent = GetParent();\r
3801                         //      if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3802                         //      {\r
3803                         //              pParent->SendMessage(SVNSLNM_ITEMCOUNTCHANGED);\r
3804                         //      }\r
3805                         //}\r
3806                 } // if (popup.CreatePopupMenu())\r
3807         } // if (selIndex >= 0)\r
3808 \r
3809 }\r
3810 \r
3811 void CGitStatusListCtrl::OnContextMenuHeader(CWnd * pWnd, CPoint point)\r
3812 {\r
3813         bool XPorLater = false;\r
3814         OSVERSIONINFOEX inf;\r
3815         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
3816         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
3817         GetVersionEx((OSVERSIONINFO *)&inf);\r
3818         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
3819         if (fullver >= 0x0501)\r
3820                 XPorLater = true;\r
3821 \r
3822         CHeaderCtrl * pHeaderCtrl = (CHeaderCtrl *)pWnd;\r
3823         if ((point.x == -1) && (point.y == -1))\r
3824         {\r
3825                 CRect rect;\r
3826                 pHeaderCtrl->GetItemRect(0, &rect);\r
3827                 ClientToScreen(&rect);\r
3828                 point = rect.CenterPoint();\r
3829         }\r
3830         Locker lock(m_critSec);\r
3831         CMenu popup;\r
3832         if (popup.CreatePopupMenu())\r
3833         {\r
3834                 int columnCount = m_ColumnManager.GetColumnCount();\r
3835 \r
3836                 CString temp;\r
3837                 UINT uCheckedFlags = MF_STRING | MF_ENABLED | MF_CHECKED;\r
3838                 UINT uUnCheckedFlags = MF_STRING | MF_ENABLED;\r
3839 \r
3840                 // build control menu\r
3841 \r
3842                 if (XPorLater)\r
3843                 {\r
3844                         temp.LoadString(IDS_STATUSLIST_SHOWGROUPS);\r
3845                         popup.AppendMenu(IsGroupViewEnabled() ? uCheckedFlags : uUnCheckedFlags, columnCount, temp);\r
3846                 }\r
3847 \r
3848                 if (m_ColumnManager.AnyUnusedProperties())\r
3849                 {\r
3850                         temp.LoadString(IDS_STATUSLIST_REMOVEUNUSEDPROPS);\r
3851                         popup.AppendMenu(uUnCheckedFlags, columnCount+1, temp);\r
3852                 }\r
3853 \r
3854                 temp.LoadString(IDS_STATUSLIST_RESETCOLUMNORDER);\r
3855                 popup.AppendMenu(uUnCheckedFlags, columnCount+2, temp);\r
3856                 popup.AppendMenu(MF_SEPARATOR);\r
3857 \r
3858                 // standard columns\r
3859 \r
3860                 for (int i = 1; i < SVNSLC_NUMCOLUMNS; ++i)\r
3861                 {\r
3862                         popup.AppendMenu ( m_ColumnManager.IsVisible(i) \r
3863                                 ? uCheckedFlags \r
3864                                 : uUnCheckedFlags\r
3865                                 , i\r
3866                                 , m_ColumnManager.GetName(i));\r
3867                 }\r
3868 \r
3869                 // user-prop columns:\r
3870                 // find relevant ones and sort 'em\r
3871 \r
3872                 std::map<CString, int> sortedProps;\r
3873                 for (int i = SVNSLC_NUMCOLUMNS; i < columnCount; ++i)\r
3874                         if (m_ColumnManager.IsRelevant(i))\r
3875                                 sortedProps[m_ColumnManager.GetName(i)] = i;\r
3876 \r
3877                 if (!sortedProps.empty())\r
3878                 {\r
3879                         // add 'em to the menu\r
3880 \r
3881                         popup.AppendMenu(MF_SEPARATOR);\r
3882 \r
3883                         typedef std::map<CString, int>::const_iterator CIT;\r
3884                         for ( CIT iter = sortedProps.begin(), end = sortedProps.end()\r
3885                                 ; iter != end\r
3886                                 ; ++iter)\r
3887                         {\r
3888                                 popup.AppendMenu ( m_ColumnManager.IsVisible(iter->second) \r
3889                                         ? uCheckedFlags \r
3890                                         : uUnCheckedFlags\r
3891                                         , iter->second\r
3892                                         , iter->first);\r
3893                         }\r
3894                 }\r
3895 \r
3896                 // show menu & let user pick an entry\r
3897 \r
3898                 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
3899                 if ((cmd >= 1)&&(cmd < columnCount))\r
3900                 {\r
3901                         m_ColumnManager.SetVisible (cmd, !m_ColumnManager.IsVisible(cmd));\r
3902                 } \r
3903                 else if (cmd == columnCount)\r
3904                 {\r
3905                         EnableGroupView(!IsGroupViewEnabled());\r
3906                 } \r
3907                 else if (cmd == columnCount+1)\r
3908                 {\r
3909                         m_ColumnManager.RemoveUnusedProps();\r
3910                 } \r
3911                 else if (cmd == columnCount+2)\r
3912                 {\r
3913                         m_ColumnManager.ResetColumns (m_dwDefaultColumns);\r
3914                 }\r
3915         }\r
3916 }\r
3917 \r
3918 void CGitStatusListCtrl::OnContextMenu(CWnd* pWnd, CPoint point)\r
3919 {\r
3920 \r
3921         if (pWnd == this)\r
3922         {\r
3923                 OnContextMenuList(pWnd, point);\r
3924         } // if (pWnd == this)\r
3925         else if (pWnd == GetHeaderCtrl())\r
3926         {\r
3927                 OnContextMenuHeader(pWnd, point);\r
3928         }\r
3929 }\r
3930 \r
3931 void CGitStatusListCtrl::CreateChangeList(const CString& name)\r
3932 {\r
3933 #if 0\r
3934         CTGitPathList changelistItems;\r
3935         FillListOfSelectedItemPaths(changelistItems);\r
3936         Git git;\r
3937         if (git.AddToChangeList(changelistItems, name, git_depth_empty))\r
3938         {\r
3939                 TCHAR groupname[1024];\r
3940                 LVGROUP grp = {0};\r
3941                 grp.cbSize = sizeof(LVGROUP);\r
3942                 grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
3943                 _tcsncpy_s(groupname, 1024, name, 1023);\r
3944                 grp.pszHeader = groupname;\r
3945                 grp.iGroupId = (int)m_changelists.size();\r
3946                 grp.uAlign = LVGA_HEADER_LEFT;\r
3947                 m_changelists[name] = InsertGroup(-1, &grp);\r
3948 \r
3949                 PrepareGroups(true);\r
3950 \r
3951                 POSITION pos = GetFirstSelectedItemPosition();\r
3952                 int index;\r
3953                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3954                 {\r
3955                         FileEntry * e = GetListEntry(index);\r
3956                         e->changelist = name;\r
3957                         SetEntryCheck(e, index, FALSE);\r
3958                 }\r
3959 \r
3960                 for (index = 0; index < GetItemCount(); ++index)\r
3961                 {\r
3962                         FileEntry * e = GetListEntry(index);\r
3963                         if (m_changelists.find(e->changelist)!=m_changelists.end())\r
3964                                 SetItemGroup(index, m_changelists[e->changelist]);\r
3965                         else\r
3966                                 SetItemGroup(index, 0);\r
3967                 }\r
3968         }\r
3969         else\r
3970         {\r
3971                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("Tortoisegit"), MB_ICONERROR);\r
3972         }\r
3973 #endif\r
3974 }\r
3975 \r
3976 void CGitStatusListCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)\r
3977 {\r
3978 \r
3979         Locker lock(m_critSec);\r
3980         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
3981         *pResult = 0;\r
3982         if (m_bBlock)\r
3983                 return;\r
3984 #if 0\r
3985         if (pNMLV->iItem < 0)\r
3986         {\r
3987                 if (!IsGroupViewEnabled())\r
3988                         return;\r
3989                 POINT pt;\r
3990                 DWORD ptW = GetMessagePos();\r
3991                 pt.x = GET_X_LPARAM(ptW);\r
3992                 pt.y = GET_Y_LPARAM(ptW);\r
3993                 ScreenToClient(&pt);\r
3994                 int group = GetGroupFromPoint(&pt);\r
3995                 if (group < 0)\r
3996                         return;\r
3997                 // check/uncheck the whole group depending on the check-state \r
3998                 // of the first item in the group\r
3999                 m_bBlock = true;\r
4000                 bool bCheck = false;\r
4001                 bool bFirst = false;\r
4002                 LVITEM lv;\r
4003                 for (int i=0; i<GetItemCount(); ++i)\r
4004                 {\r
4005                         SecureZeroMemory(&lv, sizeof(LVITEM));\r
4006                         lv.mask = LVIF_GROUPID;\r
4007                         lv.iItem = i;\r
4008                         GetItem(&lv);\r
4009                         if (lv.iGroupId == group)\r
4010                         {\r
4011                                 FileEntry * entry = GetListEntry(i);\r
4012                                 if (!bFirst)\r
4013                                 {\r
4014                                         bCheck = !GetCheck(i);\r
4015                                         bFirst = true;\r
4016                                 }\r
4017                                 if (entry)\r
4018                                 {\r
4019                                         bool bOldCheck = !!GetCheck(i);\r
4020                                         SetEntryCheck(entry, i, bCheck);\r
4021                                         if (bCheck != bOldCheck)\r
4022                                         {\r
4023                                                 if (bCheck)\r
4024                                                         m_nSelected++;\r
4025                                                 else\r
4026                                                         m_nSelected--;\r
4027                                         }\r
4028                                 }\r
4029                         }\r
4030                 }\r
4031                 GetStatisticsString();\r
4032                 m_bBlock = false;\r
4033                 NotifyCheck();\r
4034                 return;\r
4035         }\r
4036 #endif\r
4037 //      FileEntry * entry = GetListEntry(pNMLV->iItem);\r
4038 //      if (entry)\r
4039         {\r
4040 //              if (entry->isConflicted)\r
4041 //              {\r
4042 //                      gitDiff::StartConflictEditor(entry->GetPath());\r
4043 //              }\r
4044 //              else\r
4045                 {\r
4046                         StartDiff(pNMLV->iItem);\r
4047                 }\r
4048         }\r
4049 \r
4050 }\r
4051 \r
4052 void CGitStatusListCtrl::StartDiff(int fileindex)\r
4053 {\r
4054         if(fileindex<0)\r
4055                 return;\r
4056 \r
4057         CTGitPath file1=*(CTGitPath*)GetItemData(fileindex);\r
4058         CTGitPath file2;\r
4059         if(file1.m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
4060         {\r
4061                 file2.SetFromGit(file1.GetGitOldPathString());\r
4062         }else\r
4063         {\r
4064                 file2=file1;\r
4065         }\r
4066 \r
4067         if(this->m_CurrentVersion.IsEmpty() || m_CurrentVersion== GIT_REV_ZERO)\r
4068         {\r
4069                 if(!g_Git.IsInitRepos())\r
4070                         CGitDiff::Diff(&file1,&file2,\r
4071                                 CString(GIT_REV_ZERO),\r
4072                                         GitRev::GetHead());\r
4073                 else\r
4074                         CGitDiff::DiffNull((CTGitPath*)GetItemData(fileindex),\r
4075                                 CString(GIT_REV_ZERO));\r
4076         }else\r
4077         {\r
4078                 CGitDiff::Diff(&file1,&file2,\r
4079                                 m_CurrentVersion,\r
4080                                         m_CurrentVersion+_T("~1"));\r
4081         }\r
4082 #if 0\r
4083         if (fileindex < 0)\r
4084                 return;\r
4085         FileEntry * entry = GetListEntry(fileindex);\r
4086         ASSERT(entry != NULL);\r
4087         if (entry == NULL)\r
4088                 return;\r
4089         if (((entry->status == git_wc_status_normal)&&(entry->remotestatus <= git_wc_status_normal))||\r
4090                 (entry->status == git_wc_status_unversioned)||(entry->status == git_wc_status_none))\r
4091         {\r
4092                 int ret = (int)ShellExecute(this->m_hWnd, NULL, entry->path.GetWinPath(), NULL, NULL, SW_SHOW);\r
4093                 if (ret <= HINSTANCE_ERROR)\r
4094                 {\r
4095                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
4096                         cmd += entry->path.GetWinPathString();\r
4097                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
4098                 }\r
4099                 return;\r
4100         }\r
4101 \r
4102         GitDiff diff(NULL, m_hWnd, true);\r
4103         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
4104         diff.DiffWCFile(\r
4105                 entry->path, entry->textstatus, entry->propstatus,\r
4106                 entry->remotetextstatus, entry->remotepropstatus);\r
4107 #endif\r
4108 }\r
4109 \r
4110 CString CGitStatusListCtrl::GetStatisticsString()\r
4111 {\r
4112 \r
4113         CString sNormal, sAdded, sDeleted, sModified, sConflicted, sUnversioned;\r
4114         WORD langID = (WORD)(DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
4115         TCHAR buf[MAX_STATUS_STRING_LENGTH];\r
4116         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_normal, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4117         sNormal = buf;\r
4118         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_added, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4119         sAdded = buf;\r
4120         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_deleted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4121         sDeleted = buf;\r
4122         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_modified, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4123         sModified = buf;\r
4124         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_conflicted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4125         sConflicted = buf;\r
4126         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_unversioned, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4127         sUnversioned = buf;\r
4128         CString sToolTip;\r
4129         sToolTip.Format(_T("%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d"),\r
4130                 (LPCTSTR)sNormal, m_nNormal,\r
4131                 (LPCTSTR)sUnversioned, m_nUnversioned,\r
4132                 (LPCTSTR)sModified, m_nModified,\r
4133                 (LPCTSTR)sAdded, m_nAdded,\r
4134                 (LPCTSTR)sDeleted, m_nDeleted,\r
4135                 (LPCTSTR)sConflicted, m_nConflicted\r
4136                 );\r
4137         CString sStats;\r
4138         sStats.Format(IDS_COMMITDLG_STATISTICSFORMAT, m_nSelected, GetItemCount());\r
4139         if (m_pStatLabel)\r
4140         {\r
4141                 m_pStatLabel->SetWindowText(sStats);\r
4142         }\r
4143 \r
4144         if (m_pSelectButton)\r
4145         {\r
4146                 if (m_nSelected == 0)\r
4147                         m_pSelectButton->SetCheck(BST_UNCHECKED);\r
4148                 else if (m_nSelected != GetItemCount())\r
4149                         m_pSelectButton->SetCheck(BST_INDETERMINATE);\r
4150                 else\r
4151                         m_pSelectButton->SetCheck(BST_CHECKED);\r
4152         }\r
4153 \r
4154         if (m_pConfirmButton)\r
4155         {\r
4156                 m_pConfirmButton->EnableWindow(m_nSelected>0);\r
4157         }\r
4158 \r
4159         return sToolTip;\r
4160 \r
4161 \r
4162 }\r
4163 \r
4164 CString CGitStatusListCtrl::GetCommonDirectory(bool bStrict)\r
4165 {\r
4166         if (!bStrict)\r
4167         {\r
4168                 // not strict means that the selected folder has priority\r
4169                 if (!m_StatusFileList.GetCommonDirectory().IsEmpty())\r
4170                         return m_StatusFileList.GetCommonDirectory().GetWinPath();\r
4171         }\r
4172 \r
4173         CTGitPath commonBaseDirectory;\r
4174         int nListItems = GetItemCount();\r
4175         for (int i=0; i<nListItems; ++i)\r
4176         {\r
4177                 CTGitPath baseDirectory,*p= (CTGitPath*)this->GetItemData(i);\r
4178                 ASSERT(p);\r
4179                 if(p==NULL)\r
4180                         continue;\r
4181                 baseDirectory = p->GetDirectory();\r
4182 \r
4183                 if(commonBaseDirectory.IsEmpty())\r
4184                 {\r
4185                         commonBaseDirectory = baseDirectory;\r
4186                 }\r
4187                 else\r
4188                 {\r
4189                         if (commonBaseDirectory.GetWinPathString().GetLength() > baseDirectory.GetWinPathString().GetLength())\r
4190                         {\r
4191                                 if (baseDirectory.IsAncestorOf(commonBaseDirectory))\r
4192                                         commonBaseDirectory = baseDirectory;\r
4193                         }\r
4194                 }\r
4195         }\r
4196         return g_Git.m_CurrentDir+CString(_T("\\"))+commonBaseDirectory.GetWinPath();\r
4197 }\r
4198 \r
4199 CTGitPath CGitStatusListCtrl::GetCommonURL(bool bStrict)\r
4200 {\r
4201         CTGitPath commonBaseURL;\r
4202 #if 0\r
4203         \r
4204         if (!bStrict)\r
4205         {\r
4206                 // not strict means that the selected folder has priority\r
4207                 if (!m_StatusUrlList.GetCommonDirectory().IsEmpty())\r
4208                         return m_StatusUrlList.GetCommonDirectory();\r
4209         }\r
4210 \r
4211         int nListItems = GetItemCount();\r
4212         for (int i=0; i<nListItems; ++i)\r
4213         {\r
4214                 const CTGitPath& baseURL = CTGitPath(GetListEntry(i)->GetURL());\r
4215                 if (baseURL.IsEmpty())\r
4216                         continue;                       // item has no url\r
4217                 if(commonBaseURL.IsEmpty())\r
4218                 {\r
4219                         commonBaseURL = baseURL;\r
4220                 }\r
4221                 else\r
4222                 {\r
4223                         if (commonBaseURL.GetGitPathString().GetLength() > baseURL.GetGitPathString().GetLength())\r
4224                         {\r
4225                                 if (baseURL.IsAncestorOf(commonBaseURL))\r
4226                                         commonBaseURL = baseURL;\r
4227                         }\r
4228                 }\r
4229         }\r
4230         \r
4231 #endif\r
4232         return commonBaseURL;\r
4233 }\r
4234 \r
4235 void CGitStatusListCtrl::SelectAll(bool bSelect, bool bIncludeNoCommits)\r
4236 {\r
4237         CWaitCursor waitCursor;\r
4238         // block here so the LVN_ITEMCHANGED messages\r
4239         // get ignored\r
4240         m_bBlock = TRUE;\r
4241         SetRedraw(FALSE);\r
4242 \r
4243         int nListItems = GetItemCount();\r
4244         if (bSelect)\r
4245                 m_nSelected = nListItems;\r
4246         else\r
4247                 m_nSelected = 0;\r
4248 \r
4249         for (int i=0; i<nListItems; ++i)\r
4250         {\r
4251                 //FileEntry * entry = GetListEntry(i);\r
4252                 //ASSERT(entry != NULL);\r
4253                 CTGitPath *path = (CTGitPath *) GetItemData(i);\r
4254                 if (path == NULL)\r
4255                         continue;\r
4256                 //if ((bIncludeNoCommits)||(entry->GetChangeList().Compare(SVNSLC_IGNORECHANGELIST)))\r
4257                 SetEntryCheck(path,i,bSelect);\r
4258         }\r
4259 \r
4260         // unblock before redrawing\r
4261         m_bBlock = FALSE;\r
4262         SetRedraw(TRUE);\r
4263         GetStatisticsString();\r
4264         NotifyCheck();\r
4265 }\r
4266 \r
4267 void CGitStatusListCtrl::OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)\r
4268 {\r
4269         LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);\r
4270         *pResult = 0;\r
4271         if (m_bBlock)\r
4272                 return;\r
4273 #if 0\r
4274         if (GetListEntry(pGetInfoTip->iItem >= 0))\r
4275                 if (pGetInfoTip->cchTextMax > GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString().GetLength())\r
4276                 {\r
4277                         if (GetListEntry(pGetInfoTip->iItem)->GetRelativeGitPath().Compare(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString())!= 0)\r
4278                                 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
4279                         else if (GetStringWidth(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString()) > GetColumnWidth(pGetInfoTip->iItem))\r
4280                                 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
4281                 }\r
4282 #endif\r
4283 }\r
4284 \r
4285 void CGitStatusListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)\r
4286 {\r
4287         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
4288 \r
4289         // Take the default processing unless we set this to something else below.\r
4290         *pResult = CDRF_DODEFAULT;\r
4291 \r
4292         // First thing - check the draw stage. If it's the control's prepaint\r
4293         // stage, then tell Windows we want messages for every item.\r
4294 \r
4295         switch (pLVCD->nmcd.dwDrawStage)\r
4296         {\r
4297         case CDDS_PREPAINT:\r
4298                 *pResult = CDRF_NOTIFYITEMDRAW;\r
4299                 break;\r
4300         case CDDS_ITEMPREPAINT:\r
4301                 {\r
4302                         // This is the prepaint stage for an item. Here's where we set the\r
4303                         // item's text color. Our return value will tell Windows to draw the\r
4304                         // item itself, but it will use the new color we set here.\r
4305 \r
4306                         // Tell Windows to paint the control itself.\r
4307                         *pResult = CDRF_DODEFAULT;\r
4308                         if (m_bBlock)\r
4309                                 return;\r
4310 \r
4311                         COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
4312 \r
4313                         if (m_arStatusArray.size() > (DWORD_PTR)pLVCD->nmcd.dwItemSpec)\r
4314                         {\r
4315 \r
4316                                 //FileEntry * entry = GetListEntry((int)pLVCD->nmcd.dwItemSpec);\r
4317                                 CTGitPath *entry=(CTGitPath *)GetItemData((int)pLVCD->nmcd.dwItemSpec);\r
4318                                 if (entry == NULL)\r
4319                                         return;\r
4320 \r
4321                                 // coloring\r
4322                                 // ========\r
4323                                 // black  : unversioned, normal\r
4324                                 // purple : added\r
4325                                 // blue   : modified\r
4326                                 // brown  : missing, deleted, replaced\r
4327                                 // green  : merged (or potential merges)\r
4328                                 // red    : conflicts or sure conflicts\r
4329                                 if(entry->m_Action & CTGitPath::LOGACTIONS_CONFLICT)\r
4330                                 {\r
4331                                         crText = m_Colors.GetColor(CColors::Conflict);\r
4332 \r
4333                                 }else if(entry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
4334                                 {\r
4335                                         crText = m_Colors.GetColor(CColors::Modified);\r
4336 \r
4337                                 }else if(entry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
4338                                 {\r
4339                                         crText = m_Colors.GetColor(CColors::Added);\r
4340                                 }\r
4341                                 else if(entry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
4342                                 {\r
4343                                         crText = m_Colors.GetColor(CColors::DeletedNode);\r
4344                                 }\r
4345                                 else if(entry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
4346                                 {\r
4347                                         crText = m_Colors.GetColor(CColors::RenamedNode);\r
4348                                 }else\r
4349                                 {\r
4350                                         crText = GetSysColor(COLOR_WINDOWTEXT);\r
4351                                 }\r
4352                                 // Store the color back in the NMLVCUSTOMDRAW struct.\r
4353                                 pLVCD->clrText = crText;\r
4354                         }\r
4355                 }\r
4356                 break;\r
4357         }\r
4358 }\r
4359 \r
4360 BOOL CGitStatusListCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
4361 {\r
4362         if (pWnd != this)\r
4363                 return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
4364         if (!m_bBlock)\r
4365         {\r
4366                 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
4367                 SetCursor(hCur);\r
4368                 return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
4369         }\r
4370         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
4371         SetCursor(hCur);\r
4372         return TRUE;\r
4373 }\r
4374 \r
4375 void CGitStatusListCtrl::RemoveListEntry(int index)\r
4376 {\r
4377 #if 0\r
4378         Locker lock(m_critSec);\r
4379         DeleteItem(index);\r
4380         delete m_arStatusArray[m_arListArray[index]];\r
4381         m_arStatusArray.erase(m_arStatusArray.begin()+m_arListArray[index]);\r
4382         m_arListArray.erase(m_arListArray.begin()+index);\r
4383         for (int i=index; i< (int)m_arListArray.size(); ++i)\r
4384         {\r
4385                 m_arListArray[i]--;\r
4386         }\r
4387 #endif\r
4388 }\r
4389 \r
4390 ///< Set a checkbox on an entry in the listbox\r
4391 // NEVER, EVER call SetCheck directly, because you'll end-up with the checkboxes and the 'checked' flag getting out of sync\r
4392 void CGitStatusListCtrl::SetEntryCheck(CTGitPath* pEntry, int listboxIndex, bool bCheck)\r
4393 {\r
4394         pEntry->m_Checked = bCheck;\r
4395         SetCheck(listboxIndex, bCheck);\r
4396 }\r
4397 \r
4398 #if 0\r
4399 void CGitStatusListCtrl::SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck)\r
4400 {\r
4401 \r
4402         int nListItems = GetItemCount();\r
4403         for (int j=0; j< nListItems ; ++j)\r
4404         {\r
4405                 FileEntry * childEntry = GetListEntry(j);\r
4406                 ASSERT(childEntry != NULL);\r
4407                 if (childEntry == NULL || childEntry == parentEntry)\r
4408                         continue;\r
4409                 if (childEntry->checked != bCheck)\r
4410                 {\r
4411                         if (parentEntry->path.IsAncestorOf(childEntry->path))\r
4412                         {\r
4413                                 SetEntryCheck(childEntry,j,bCheck);\r
4414                                 if(bCheck)\r
4415                                 {\r
4416                                         m_nSelected++;\r
4417                                 }\r
4418                                 else\r
4419                                 {\r
4420                                         m_nSelected--;\r
4421                                 }\r
4422                         }\r
4423                 }\r
4424         }\r
4425 \r
4426 }\r
4427 #endif\r
4428 \r
4429 void CGitStatusListCtrl::WriteCheckedNamesToPathList(CTGitPathList& pathList)\r
4430 {\r
4431 #if 0\r
4432         pathList.Clear();\r
4433         int nListItems = GetItemCount();\r
4434         for (int i=0; i< nListItems; i++)\r
4435         {\r
4436                 const FileEntry* entry = GetListEntry(i);\r
4437                 ASSERT(entry != NULL);\r
4438                 if (entry->IsChecked())\r
4439                 {\r
4440                         pathList.AddPath(entry->path);\r
4441                 }\r
4442         }\r
4443         pathList.SortByPathname();\r
4444 #endif\r
4445 }\r
4446 \r
4447 \r
4448 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)\r
4449 void CGitStatusListCtrl::FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored)\r
4450 {\r
4451         pathList.Clear();\r
4452 \r
4453         POSITION pos = GetFirstSelectedItemPosition();\r
4454         int index;\r
4455         while ((index = GetNextSelectedItem(pos)) >= 0)\r
4456         {\r
4457                 CTGitPath * entry = (CTGitPath*)GetItemData(index);\r
4458                 //if ((bNoIgnored)&&(entry->status == git_wc_status_ignored))\r
4459                 //      continue;\r
4460                 pathList.AddPath(*entry);\r
4461         }\r
4462 }\r
4463 \r
4464 UINT CGitStatusListCtrl::OnGetDlgCode()\r
4465 {\r
4466         // we want to process the return key and not have that one\r
4467         // routed to the default pushbutton\r
4468         return CListCtrl::OnGetDlgCode() | DLGC_WANTALLKEYS;\r
4469 }\r
4470 \r
4471 void CGitStatusListCtrl::OnNMReturn(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
4472 {\r
4473         *pResult = 0;\r
4474         if (m_bBlock)\r
4475                 return;\r
4476         POSITION pos = GetFirstSelectedItemPosition();\r
4477         while ( pos )\r
4478         {\r
4479                 int index = GetNextSelectedItem(pos);\r
4480                 StartDiff(index);\r
4481         }\r
4482 }\r
4483 \r
4484 void CGitStatusListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\r
4485 {\r
4486         // Since we catch all keystrokes (to have the enter key processed here instead\r
4487         // of routed to the default pushbutton) we have to make sure that other\r
4488         // keys like Tab and Esc still do what they're supposed to do\r
4489         // Tab = change focus to next/previous control\r
4490         // Esc = quit the dialog\r
4491         switch (nChar)\r
4492         {\r
4493         case (VK_TAB):\r
4494                 {\r
4495                         ::PostMessage(GetParent()->GetSafeHwnd(), WM_NEXTDLGCTL, GetKeyState(VK_SHIFT)&0x8000, 0);\r
4496                         return;\r
4497                 }\r
4498                 break;\r
4499         case (VK_ESCAPE):\r
4500                 {\r
4501                         ::SendMessage(GetParent()->GetSafeHwnd(), WM_CLOSE, 0, 0);\r
4502                 }\r
4503                 break;\r
4504         }\r
4505 \r
4506         CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);\r
4507 }\r
4508 \r
4509 void CGitStatusListCtrl::PreSubclassWindow()\r
4510 {\r
4511         CListCtrl::PreSubclassWindow();\r
4512         EnableToolTips(TRUE);\r
4513         m_Theme.SetWindowTheme(GetSafeHwnd(), L"Explorer", NULL);\r
4514 }\r
4515 \r
4516 INT_PTR CGitStatusListCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const\r
4517 {\r
4518         int row, col;\r
4519         RECT cellrect;\r
4520         row = CellRectFromPoint(point, &cellrect, &col );\r
4521 \r
4522         if (row == -1)\r
4523                 return -1;\r
4524 \r
4525 \r
4526         pTI->hwnd = m_hWnd;\r
4527         pTI->uId = (UINT)((row<<10)+(col&0x3ff)+1);\r
4528         pTI->lpszText = LPSTR_TEXTCALLBACK;\r
4529 \r
4530         pTI->rect = cellrect;\r
4531 \r
4532         return pTI->uId;\r
4533 }\r
4534 \r
4535 int CGitStatusListCtrl::CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const\r
4536 {\r
4537         int colnum;\r
4538 \r
4539         // Make sure that the ListView is in LVS_REPORT\r
4540         if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)\r
4541                 return -1;\r
4542 \r
4543         // Get the top and bottom row visible\r
4544         int row = GetTopIndex();\r
4545         int bottom = row + GetCountPerPage();\r
4546         if (bottom > GetItemCount())\r
4547                 bottom = GetItemCount();\r
4548 \r
4549         // Get the number of columns\r
4550         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);\r
4551         int nColumnCount = pHeader->GetItemCount();\r
4552 \r
4553         // Loop through the visible rows\r
4554         for ( ;row <=bottom;row++)\r
4555         {\r
4556                 // Get bounding rect of item and check whether point falls in it.\r
4557                 CRect rect;\r
4558                 GetItemRect(row, &rect, LVIR_BOUNDS);\r
4559                 if (rect.PtInRect(point))\r
4560                 {\r
4561                         // Now find the column\r
4562                         for (colnum = 0; colnum < nColumnCount; colnum++)\r
4563                         {\r
4564                                 int colwidth = GetColumnWidth(colnum);\r
4565                                 if (point.x >= rect.left && point.x <= (rect.left + colwidth))\r
4566                                 {\r
4567                                         RECT rectClient;\r
4568                                         GetClientRect(&rectClient);\r
4569                                         if (col)\r
4570                                                 *col = colnum;\r
4571                                         rect.right = rect.left + colwidth;\r
4572 \r
4573                                         // Make sure that the right extent does not exceed\r
4574                                         // the client area\r
4575                                         if (rect.right > rectClient.right)\r
4576                                                 rect.right = rectClient.right;\r
4577                                         *cellrect = rect;\r
4578                                         return row;\r
4579                                 }\r
4580                                 rect.left += colwidth;\r
4581                         }\r
4582                 }\r
4583         }\r
4584         return -1;\r
4585 }\r
4586 \r
4587 BOOL CGitStatusListCtrl::OnToolTipText(UINT /*id*/, NMHDR *pNMHDR, LRESULT *pResult)\r
4588 {\r
4589 #if 0\r
4590         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;\r
4591         CString strTipText;\r
4592         UINT_PTR nID = pNMHDR->idFrom;\r
4593 \r
4594         if (nID == 0)\r
4595                 return FALSE;\r
4596 \r
4597         UINT_PTR row = ((nID-1) >> 10) & 0x3fffff;\r
4598         UINT_PTR col = (nID-1) & 0x3ff;\r
4599 \r
4600         if (col == 0)\r
4601                 return FALSE;   // no custom tooltip for the path, we use the infotip there!\r
4602 \r
4603         // get the internal column from the visible columns\r
4604         int internalcol = 0;\r
4605         UINT_PTR currentcol = 0;\r
4606     for (;    (currentcol != col) \r
4607            && (internalcol < m_ColumnManager.GetColumnCount()-1)\r
4608          ; ++internalcol)\r
4609         {\r
4610         if (m_ColumnManager.IsVisible (internalcol))\r
4611                         currentcol++;\r
4612         }\r
4613 \r
4614         AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();\r
4615         CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip;\r
4616         pToolTip->SendMessage(TTM_SETMAXTIPWIDTH, 0, 300);\r
4617 \r
4618         *pResult = 0;\r
4619         if ((internalcol == 2)||(internalcol == 4))\r
4620         {\r
4621                 FileEntry *fentry = GetListEntry(row);\r
4622                 if (fentry)\r
4623                 {\r
4624                         if (fentry->copied)\r
4625                         {\r
4626                                 CString url;\r
4627                                 url.Format(IDS_STATUSLIST_COPYFROM, (LPCTSTR)CPathUtils::PathUnescape(fentry->copyfrom_url), (LONG)fentry->copyfrom_rev);\r
4628                                 lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
4629                                 return TRUE;\r
4630                         }\r
4631                         if (fentry->switched)\r
4632                         {\r
4633                                 CString url;\r
4634                                 url.Format(IDS_STATUSLIST_SWITCHEDTO, (LPCTSTR)CPathUtils::PathUnescape(fentry->url));\r
4635                                 lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
4636                                 return TRUE;\r
4637                         }\r
4638                         if (fentry->keeplocal)\r
4639                         {\r
4640                                 lstrcpyn(pTTTW->szText, (LPCTSTR)CString(MAKEINTRESOURCE(IDS_STATUSLIST_KEEPLOCAL)), 80);\r
4641                                 return TRUE;\r
4642                         }\r
4643                 }\r
4644         }\r
4645 #endif\r
4646         return FALSE;\r
4647 }\r
4648 \r
4649 void CGitStatusListCtrl::OnPaint()\r
4650 {\r
4651         Default();\r
4652         if ((m_bBusy)||(m_bEmpty))\r
4653         {\r
4654                 CString str;\r
4655                 if (m_bBusy)\r
4656                 {\r
4657                         if (m_sBusy.IsEmpty())\r
4658                                 str.LoadString(IDS_STATUSLIST_BUSYMSG);\r
4659                         else\r
4660                                 str = m_sBusy;\r
4661                 }\r
4662                 else\r
4663                 {\r
4664                         if (m_sEmpty.IsEmpty())\r
4665                                 str.LoadString(IDS_STATUSLIST_EMPTYMSG);\r
4666                         else\r
4667                                 str = m_sEmpty;\r
4668                 }\r
4669                 COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);\r
4670                 COLORREF clrTextBk;\r
4671                 if (IsWindowEnabled())\r
4672                         clrTextBk = ::GetSysColor(COLOR_WINDOW);\r
4673                 else\r
4674                         clrTextBk = ::GetSysColor(COLOR_3DFACE);\r
4675 \r
4676                 CRect rc;\r
4677                 GetClientRect(&rc);\r
4678                 CHeaderCtrl* pHC;\r
4679                 pHC = GetHeaderCtrl();\r
4680                 if (pHC != NULL)\r
4681                 {\r
4682                         CRect rcH;\r
4683                         pHC->GetItemRect(0, &rcH);\r
4684                         rc.top += rcH.bottom;\r
4685                 }\r
4686                 CDC* pDC = GetDC();\r
4687                 {\r
4688                         CMyMemDC memDC(pDC, &rc);\r
4689 \r
4690                         memDC.SetTextColor(clrText);\r
4691                         memDC.SetBkColor(clrTextBk);\r
4692                         memDC.FillSolidRect(rc, clrTextBk);\r
4693                         rc.top += 10;\r
4694                         CGdiObject * oldfont = memDC.SelectStockObject(DEFAULT_GUI_FONT);\r
4695                         memDC.DrawText(str, rc, DT_CENTER | DT_VCENTER |\r
4696                                 DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);\r
4697                         memDC.SelectObject(oldfont);\r
4698                 }\r
4699                 ReleaseDC(pDC);\r
4700         }\r
4701 }\r
4702 \r
4703 // prevent users from extending our hidden (size 0) columns\r
4704 void CGitStatusListCtrl::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)\r
4705 {\r
4706         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
4707         *pResult = 0;\r
4708         if ((phdr->iItem < 0)||(phdr->iItem >= SVNSLC_NUMCOLUMNS))\r
4709                 return;\r
4710 \r
4711     if (m_ColumnManager.IsVisible (phdr->iItem))\r
4712         {\r
4713                 return;\r
4714         }\r
4715         *pResult = 1;\r
4716 }\r
4717 \r
4718 // prevent any function from extending our hidden (size 0) columns\r
4719 void CGitStatusListCtrl::OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
4720 {\r
4721         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
4722         *pResult = 0;\r
4723     if ((phdr->iItem < 0)||(phdr->iItem >= m_ColumnManager.GetColumnCount()))\r
4724         {\r
4725                 Default();\r
4726                 return;\r
4727         }\r
4728 \r
4729     // visible columns may be modified \r
4730 \r
4731     if (m_ColumnManager.IsVisible (phdr->iItem))\r
4732         {\r
4733                 Default();\r
4734                 return;\r
4735         }\r
4736 \r
4737     // columns already marked as "invisible" internally may be (re-)sized to 0\r
4738 \r
4739     if (   (phdr->pitem != NULL) \r
4740         && (phdr->pitem->mask == HDI_WIDTH)\r
4741         && (phdr->pitem->cxy == 0))\r
4742         {\r
4743                 Default();\r
4744                 return;\r
4745         }\r
4746 \r
4747         if (   (phdr->pitem != NULL) \r
4748                 && (phdr->pitem->mask != HDI_WIDTH))\r
4749         {\r
4750                 Default();\r
4751                 return;\r
4752         }\r
4753 \r
4754     *pResult = 1;\r
4755 }\r
4756 \r
4757 void CGitStatusListCtrl::OnDestroy()\r
4758 {\r
4759         SaveColumnWidths(true);\r
4760         CListCtrl::OnDestroy();\r
4761 }\r
4762 \r
4763 void CGitStatusListCtrl::OnBeginDrag(NMHDR* /*pNMHDR*/, LRESULT* pResult)\r
4764 {\r
4765 #if 0\r
4766         Locker lock(m_critSec);\r
4767         CDropFiles dropFiles; // class for creating DROPFILES struct\r
4768 \r
4769         int index;\r
4770         POSITION pos = GetFirstSelectedItemPosition();\r
4771         while ( (index = GetNextSelectedItem(pos)) >= 0 )\r
4772         {\r
4773                 FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
4774                 CTGitPath path = fentry->GetPath();\r
4775                 dropFiles.AddFile( path.GetWinPathString() );\r
4776         }\r
4777 \r
4778         if ( dropFiles.GetCount()>0 )\r
4779         {\r
4780                 m_bOwnDrag = true;\r
4781                 dropFiles.CreateStructure();\r
4782                 m_bOwnDrag = false;\r
4783         }\r
4784 #endif\r
4785         *pResult = 0;\r
4786 }\r
4787 \r
4788 void CGitStatusListCtrl::SaveColumnWidths(bool bSaveToRegistry /* = false */)\r
4789 {\r
4790         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
4791         for (int col = 0; col <= maxcol; col++)\r
4792         if (m_ColumnManager.IsVisible (col))\r
4793             m_ColumnManager.ColumnResized (col);\r
4794 \r
4795         if (bSaveToRegistry)\r
4796         m_ColumnManager.WriteSettings();\r
4797 }\r
4798 \r
4799 bool CGitStatusListCtrl::EnableFileDrop()\r
4800 {\r
4801         m_bFileDropsEnabled = true;\r
4802         return true;\r
4803 }\r
4804 \r
4805 bool CGitStatusListCtrl::HasPath(const CTGitPath& path)\r
4806 {\r
4807 #if 0\r
4808         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
4809         {\r
4810                 FileEntry * entry = m_arStatusArray[i];\r
4811                 if (entry->GetPath().IsEquivalentTo(path))\r
4812                         return true;\r
4813         }\r
4814 #endif\r
4815         return false;\r
4816 }\r
4817 \r
4818 bool CGitStatusListCtrl::IsPathShown(const CTGitPath& path)\r
4819 {\r
4820 #if 0\r
4821         int itemCount = GetItemCount();\r
4822         for (int i=0; i < itemCount; i++)\r
4823         {\r
4824                 FileEntry * entry = GetListEntry(i);\r
4825                 if (entry->GetPath().IsEquivalentTo(path))\r
4826                         return true;\r
4827         }\r
4828 #endif\r
4829         return false;\r
4830 }\r
4831 \r
4832 BOOL CGitStatusListCtrl::PreTranslateMessage(MSG* pMsg)\r
4833 {\r
4834         if (pMsg->message == WM_KEYDOWN)\r
4835         {\r
4836                 switch (pMsg->wParam)\r
4837                 {\r
4838                 case 'A':\r
4839                         {\r
4840                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
4841                                 {\r
4842                                         // select all entries\r
4843                                         for (int i=0; i<GetItemCount(); ++i)\r
4844                                         {\r
4845                                                 SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
4846                                         }\r
4847                                         return TRUE;\r
4848                                 }\r
4849                         }\r
4850                         break;\r
4851                 case 'C':\r
4852                 case VK_INSERT:\r
4853                         {\r
4854                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
4855                                 {\r
4856                                         // copy all selected paths to the clipboard\r
4857                                         if (GetAsyncKeyState(VK_SHIFT)&0x8000)\r
4858                                                 CopySelectedEntriesToClipboard(SVNSLC_COLSTATUS);\r
4859                                         else\r
4860                                                 CopySelectedEntriesToClipboard(0);\r
4861                                         return TRUE;\r
4862                                 }\r
4863                         }\r
4864                         break;\r
4865                 }\r
4866         }\r
4867 \r
4868         return CListCtrl::PreTranslateMessage(pMsg);\r
4869 }\r
4870 \r
4871 bool CGitStatusListCtrl::CopySelectedEntriesToClipboard(DWORD dwCols)\r
4872 {\r
4873 #if 0\r
4874         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
4875         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
4876         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
4877 \r
4878         CString sClipboard;\r
4879         CString temp;\r
4880         TCHAR buf[100];\r
4881         if (GetSelectedCount() == 0)\r
4882                 return false;\r
4883         // first add the column titles as the first line\r
4884         temp.LoadString(IDS_STATUSLIST_COLFILE);\r
4885         sClipboard = temp;\r
4886 \r
4887     DWORD selection = 0;\r
4888     for (int i = 0, count = m_ColumnManager.GetColumnCount(); i < count; ++i)\r
4889         if (   ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
4890             || ((dwCols != 1) && (i < 32) && ((dwCols & (1 << i)) != 0)))\r
4891         {\r
4892             sClipboard += _T("\t") + m_ColumnManager.GetName(i);\r
4893 \r
4894             if (i < 32)\r
4895                 selection += 1 << i;\r
4896         }\r
4897 \r
4898         sClipboard += _T("\r\n");\r
4899 \r
4900         POSITION pos = GetFirstSelectedItemPosition();\r
4901         int index;\r
4902         while ((index = GetNextSelectedItem(pos)) >= 0)\r
4903         {\r
4904                 FileEntry * entry = GetListEntry(index);\r
4905                 sClipboard += entry->GetDisplayName();\r
4906                 if (selection & SVNSLC_COLFILENAME)\r
4907                 {\r
4908                         sClipboard += _T("\t")+entry->path.GetFileOrDirectoryName();\r
4909                 }\r
4910                 if (selection & SVNSLC_COLEXT)\r
4911                 {\r
4912                         sClipboard += _T("\t")+entry->path.GetFileExtension();\r
4913                 }\r
4914                 if (selection & SVNSLC_COLSTATUS)\r
4915                 {\r
4916                         if (entry->isNested)\r
4917                         {\r
4918                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4919                         }\r
4920                         else\r
4921                         {\r
4922                                 GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4923                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4924                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4925                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4926                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4927                                 if ((entry->status == entry->propstatus)&&\r
4928                                         (entry->status != git_wc_status_normal)&&\r
4929                                         (entry->status != git_wc_status_unversioned)&&\r
4930                                         (!GitStatus::IsImportant(entry->textstatus)))\r
4931                                         _tcscat_s(buf, 100, ponly);\r
4932                                 temp = buf;\r
4933                         }\r
4934                         sClipboard += _T("\t")+temp;\r
4935                 }\r
4936                 if (selection & SVNSLC_COLTEXTSTATUS)\r
4937                 {\r
4938                         if (entry->isNested)\r
4939                         {\r
4940                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4941                         }\r
4942                         else\r
4943                         {\r
4944                                 GitStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4945                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4946                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4947                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4948                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4949                                 temp = buf;\r
4950                         }\r
4951                         sClipboard += _T("\t")+temp;\r
4952                 }\r
4953                 if (selection & SVNSLC_COLREMOTESTATUS)\r
4954                 {\r
4955                         if (entry->isNested)\r
4956                         {\r
4957                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4958                         }\r
4959                         else\r
4960                         {\r
4961                                 GitStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4962                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4963                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4964                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4965                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4966                                 if ((entry->remotestatus == entry->remotepropstatus)&&\r
4967                                         (entry->remotestatus != git_wc_status_none)&&\r
4968                                         (entry->remotestatus != git_wc_status_normal)&&\r
4969                                         (entry->remotestatus != git_wc_status_unversioned)&&\r
4970                                         (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
4971                                         _tcscat_s(buf, 100, ponly);\r
4972                                 temp = buf;\r
4973                         }\r
4974                         sClipboard += _T("\t")+temp;\r
4975                 }\r
4976                 if (selection & GitSLC_COLPROPSTATUS)\r
4977                 {\r
4978                         if (entry->isNested)\r
4979                         {\r
4980                                 temp.Empty();\r
4981                         }\r
4982                         else\r
4983                         {\r
4984                                 GitStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4985                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4986                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4987                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4988                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4989                                 temp = buf;\r
4990                         }\r
4991                         sClipboard += _T("\t")+temp;\r
4992                 }\r
4993                 if (selection & SVNSLC_COLREMOTETEXT)\r
4994                 {\r
4995                         if (entry->isNested)\r
4996                         {\r
4997                                 temp.Empty();\r
4998                         }\r
4999                         else\r
5000                         {\r
5001                                 GitStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
5002                                 temp = buf;\r
5003                         }\r
5004                         sClipboard += _T("\t")+temp;\r
5005                 }\r
5006                 if (selection & SVNSLC_COLREMOTEPROP)\r
5007                 {\r
5008                         // SVNSLC_COLREMOTEPROP\r
5009                         if (entry->isNested)\r
5010                         {\r
5011                                 temp.Empty();\r
5012                         }\r
5013                         else\r
5014                         {\r
5015                                 GitStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
5016                                 temp = buf;\r
5017                         }\r
5018                         sClipboard += _T("\t")+temp;\r
5019                 }\r
5020                 if (selection & SVNSLC_COLURL)\r
5021                         sClipboard += _T("\t")+entry->url;\r
5022                 if (selection & SVNSLC_COLLOCK)\r
5023                 {\r
5024                         if (!m_HeadRev.IsHead())\r
5025                         {\r
5026                                 // we have contacted the repository\r
5027 \r
5028                                 // decision-matrix\r
5029                                 // wc           repository              text\r
5030                                 // ""           ""                              ""\r
5031                                 // ""           UID1                    owner\r
5032                                 // UID1         UID1                    owner\r
5033                                 // UID1         ""                              lock has been broken\r
5034                                 // UID1         UID2                    lock has been stolen\r
5035                                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
5036                                 {\r
5037                                         if (entry->lock_owner.IsEmpty())\r
5038                                                 temp = entry->lock_remoteowner;\r
5039                                         else\r
5040                                                 temp = entry->lock_owner;\r
5041                                 }\r
5042                                 else if (entry->lock_remotetoken.IsEmpty())\r
5043                                 {\r
5044                                         // broken lock\r
5045                                         temp.LoadString(IDS_STATUSLIST_LOCKBROKEN);\r
5046                                 }\r
5047                                 else\r
5048                                 {\r
5049                                         // stolen lock\r
5050                                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
5051                                 }\r
5052                         }\r
5053                         else\r
5054                                 temp = entry->lock_owner;\r
5055                         sClipboard += _T("\t")+temp;\r
5056                 }\r
5057                 if (selection & SVNSLC_COLLOCKCOMMENT)\r
5058                         sClipboard += _T("\t")+entry->lock_comment;\r
5059                 if (selection & SVNSLC_COLAUTHOR)\r
5060                         sClipboard += _T("\t")+entry->last_commit_author;\r
5061                 if (selection & SVNSLC_COLREVISION)\r
5062                 {\r
5063                         temp.Format(_T("%ld"), entry->last_commit_rev);\r
5064                         if (entry->last_commit_rev == 0)\r
5065                                 temp.Empty();\r
5066                         sClipboard += _T("\t")+temp;\r
5067                 }\r
5068                 if (selection & SVNSLC_COLREMOTEREVISION)\r
5069                 {\r
5070                         temp.Format(_T("%ld"), entry->remoterev);\r
5071                         if (entry->remoterev == 0)\r
5072                                 temp.Empty();\r
5073                         sClipboard += _T("\t")+temp;\r
5074                 }\r
5075                 if (selection & SVNSLC_COLDATE)\r
5076                 {\r
5077                         TCHAR datebuf[SVN_DATE_BUFFER];\r
5078                         apr_time_t date = entry->last_commit_date;\r
5079                         SVN::formatDate(datebuf, date, true);\r
5080                         if (date)\r
5081                                 temp = datebuf;\r
5082                         else\r
5083                                 temp.Empty();\r
5084                         sClipboard += _T("\t")+temp;\r
5085                 }\r
5086                 if (selection & SVNSLC_COLCOPYFROM)\r
5087                 {\r
5088                         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
5089                                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
5090                         else\r
5091                                 temp = entry->copyfrom_url;\r
5092                         sClipboard += _T("\t")+temp;\r
5093                 }\r
5094 \r
5095         for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
5096             ; i < count\r
5097             ; ++i)\r
5098         {\r
5099             if ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
5100             {\r
5101                 CString value \r
5102                     = entry->present_props[m_ColumnManager.GetName(i)];\r
5103                 sClipboard += _T("\t") + value;\r
5104             }\r
5105         }\r
5106 \r
5107                 sClipboard += _T("\r\n");\r
5108         }\r
5109 \r
5110         return CStringUtils::WriteAsciiStringToClipboard(sClipboard);\r
5111 #endif\r
5112         return TRUE;\r
5113 \r
5114 }\r
5115 \r
5116 size_t CGitStatusListCtrl::GetNumberOfChangelistsInSelection()\r
5117 {\r
5118 #if 0\r
5119         std::set<CString> changelists;\r
5120         POSITION pos = GetFirstSelectedItemPosition();\r
5121         int index;\r
5122         while ((index = GetNextSelectedItem(pos)) >= 0)\r
5123         {\r
5124                 FileEntry * entry = GetListEntry(index);\r
5125                 if (!entry->changelist.IsEmpty())\r
5126                         changelists.insert(entry->changelist);\r
5127         }\r
5128         return changelists.size();\r
5129 #endif \r
5130         return 0;\r
5131 }\r
5132 \r
5133 bool CGitStatusListCtrl::PrepareGroups(bool bForce /* = false */)\r
5134 {\r
5135 \r
5136         bool bHasGroups=false;\r
5137         if ( this->m_UnRevFileList.GetCount()>0 || \r
5138                 this->m_IgnoreFileList.GetCount()>0 || bForce)\r
5139         {\r
5140                 bHasGroups = true;\r
5141         }\r
5142 \r
5143         RemoveAllGroups();\r
5144         EnableGroupView(bHasGroups);\r
5145         \r
5146         TCHAR groupname[1024];\r
5147         int groupindex = 0;\r
5148 \r
5149         if(bHasGroups);\r
5150         {\r
5151                 LVGROUP grp = {0};\r
5152                 grp.cbSize = sizeof(LVGROUP);\r
5153                 grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5154                 CString sUnassignedName(_T("Modified File"));\r
5155                 _tcsncpy_s(groupname, 1024, (LPCTSTR)sUnassignedName, 1023);\r
5156                 grp.pszHeader = groupname;\r
5157                 grp.iGroupId = groupindex;\r
5158                 grp.uAlign = LVGA_HEADER_LEFT;\r
5159                 InsertGroup(groupindex++, &grp);\r
5160 \r
5161                 //if(m_UnRevFileList.GetCount()>0)\r
5162                 {\r
5163                         _tcsncpy_s(groupname, 1024, (LPCTSTR)_T("No Version Control"), 1023);\r
5164                         grp.pszHeader = groupname;\r
5165                         grp.iGroupId = groupindex;\r
5166                         grp.uAlign = LVGA_HEADER_LEFT;\r
5167                         InsertGroup(groupindex++, &grp);\r
5168                 }\r
5169 \r
5170                 //if(m_IgnoreFileList.GetCount()>0)\r
5171                 {\r
5172                         _tcsncpy_s(groupname, 1024, (LPCTSTR)_T("Ignored File"), 1023);\r
5173                         grp.pszHeader = groupname;\r
5174                         grp.iGroupId = groupindex;\r
5175                         grp.uAlign = LVGA_HEADER_LEFT;\r
5176                         InsertGroup(groupindex++, &grp);\r
5177                 }\r
5178 \r
5179         }\r
5180 \r
5181 #if 0\r
5182         m_bHasIgnoreGroup = false;\r
5183 \r
5184         // now add the items which don't belong to a group\r
5185         LVGROUP grp = {0};\r
5186         grp.cbSize = sizeof(LVGROUP);\r
5187         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5188         CString sUnassignedName(MAKEINTRESOURCE(IDS_STATUSLIST_UNASSIGNED_CHANGESET));\r
5189         _tcsncpy_s(groupname, 1024, (LPCTSTR)sUnassignedName, 1023);\r
5190         grp.pszHeader = groupname;\r
5191         grp.iGroupId = groupindex;\r
5192         grp.uAlign = LVGA_HEADER_LEFT;\r
5193         InsertGroup(groupindex++, &grp);\r
5194 \r
5195         for (std::map<CString,int>::iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
5196         {\r
5197                 if (it->first.Compare(SVNSLC_IGNORECHANGELIST)!=0)\r
5198                 {\r
5199                         LVGROUP grp = {0};\r
5200                         grp.cbSize = sizeof(LVGROUP);\r
5201                         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5202                         _tcsncpy_s(groupname, 1024, it->first, 1023);\r
5203                         grp.pszHeader = groupname;\r
5204                         grp.iGroupId = groupindex;\r
5205                         grp.uAlign = LVGA_HEADER_LEFT;\r
5206                         it->second = InsertGroup(groupindex++, &grp);\r
5207                 }\r
5208                 else\r
5209                         m_bHasIgnoreGroup = true;\r
5210         }\r
5211 \r
5212         if (m_bHasIgnoreGroup)\r
5213         {\r
5214                 // and now add the group 'ignore-on-commit'\r
5215                 std::map<CString,int>::iterator it = m_changelists.find(SVNSLC_IGNORECHANGELIST);\r
5216                 if (it != m_changelists.end())\r
5217                 {\r
5218                         grp.cbSize = sizeof(LVGROUP);\r
5219                         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5220                         _tcsncpy_s(groupname, 1024, SVNSLC_IGNORECHANGELIST, 1023);\r
5221                         grp.pszHeader = groupname;\r
5222                         grp.iGroupId = groupindex;\r
5223                         grp.uAlign = LVGA_HEADER_LEFT;\r
5224                         it->second = InsertGroup(groupindex, &grp);\r
5225                 }\r
5226         }\r
5227 #endif\r
5228         return bHasGroups;\r
5229 }\r
5230 \r
5231 void CGitStatusListCtrl::NotifyCheck()\r
5232 {\r
5233         CWnd* pParent = GetParent();\r
5234         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
5235         {\r
5236                 pParent->SendMessage(SVNSLNM_CHECKCHANGED, m_nSelected);\r
5237         }\r
5238 }\r
5239 \r
5240 int CGitStatusListCtrl::UpdateFileList(git_revnum_t hash,CTGitPathList *list)\r
5241 {\r
5242         CString out;\r
5243         this->m_bBusy=TRUE;\r
5244         m_CurrentVersion=hash;\r
5245 \r
5246         if(hash == GIT_REV_ZERO)\r
5247         {\r
5248                 int count = 0;\r
5249                 if(list == NULL)\r
5250                         count = 1;\r
5251                 else\r
5252                         count = list->GetCount();\r
5253 \r
5254                 for(int i=0;i<count;i++)\r
5255                 {       \r
5256                         CString cmdout;\r
5257                         CString cmd;\r
5258                         if(list == NULL)\r
5259                                 cmd=(_T("git.exe diff-index --raw HEAD --numstat -C -M"));\r
5260                         else\r
5261                                 cmd.Format(_T("git.exe diff-index --raw HEAD --numstat -C -M -- \"%s\""),(*list)[i].GetGitPathString());\r
5262 \r
5263                         if(g_Git.Run(cmd,&cmdout))\r
5264                         {\r
5265                                 cmdout.Empty();\r
5266                                 if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout))\r
5267                                 {\r
5268                                         CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
5269                                         return -1;\r
5270                                 }\r
5271                                 if(cmdout.IsEmpty())\r
5272                                         break; //this is initial repositoyr, there are no any history\r
5273 \r
5274                                 CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
5275                                 return -1;\r
5276 \r
5277                         }\r
5278 \r
5279                         out+=cmdout;\r
5280                 }\r
5281 \r
5282 \r
5283                 this->m_StatusFileList.ParserFromLog(out);\r
5284         }else\r
5285         {\r
5286                 int count = 0;\r
5287                 if(list == NULL)\r
5288                         count = 1;\r
5289                 else\r
5290                         count = list->GetCount();\r
5291 \r
5292                 for(int i=0;i<count;i++)\r
5293                 {       \r
5294                         CString cmdout;\r
5295                         CString cmd;\r
5296                         if(list == NULL)\r
5297                                 cmd.Format(_T("git.exe diff-tree --raw --numstat -C -M %s"),hash);\r
5298                         else\r
5299                                 cmd.Format(_T("git.exe diff-tree --raw  --numstat -C -M %s -- \"%s\""),hash,(*list)[i].GetGitPathString());\r
5300 \r
5301                         g_Git.Run(cmd,&cmdout);\r
5302 \r
5303                         out+=cmdout;\r
5304                 }\r
5305                 this->m_StatusFileList.ParserFromLog(out);\r
5306 \r
5307         }\r
5308         for(int i=0;i<m_StatusFileList.GetCount();i++)\r
5309         {\r
5310                 CTGitPath * gitpatch=(CTGitPath*)&m_StatusFileList[i];\r
5311                 gitpatch->m_Checked = TRUE;\r
5312                 m_arStatusArray.push_back((CTGitPath*)&m_StatusFileList[i]);\r
5313         }\r
5314         this->m_bBusy=FALSE;\r
5315         return 0;\r
5316 }\r
5317 \r
5318 int CGitStatusListCtrl::UpdateWithGitPathList(CTGitPathList &list)\r
5319 {\r
5320         m_arStatusArray.clear();\r
5321         for(int i=0;i<list.GetCount();i++)\r
5322         {\r
5323                 CTGitPath * gitpatch=(CTGitPath*)&list[i];\r
5324                 gitpatch->m_Checked = TRUE;\r
5325                 m_arStatusArray.push_back((CTGitPath*)&list[i]);\r
5326         }\r
5327         return 0;\r
5328 }\r
5329 \r
5330 int CGitStatusListCtrl::UpdateUnRevFileList(CTGitPathList *List)\r
5331 {\r
5332         this->m_UnRevFileList.FillUnRev(CTGitPath::LOGACTIONS_UNVER,List);\r
5333         for(int i=0;i<m_UnRevFileList.GetCount();i++)\r
5334         {\r
5335                 CTGitPath * gitpatch=(CTGitPath*)&m_UnRevFileList[i];\r
5336                 gitpatch->m_Checked = FALSE;\r
5337                 m_arStatusArray.push_back((CTGitPath*)&m_UnRevFileList[i]);\r
5338         }\r
5339         return 0;\r
5340 }\r
5341 \r
5342 int CGitStatusListCtrl::UpdateIgnoreFileList(CTGitPathList *List)\r
5343 {\r
5344         this->m_IgnoreFileList.FillUnRev(CTGitPath::LOGACTIONS_UNVER|CTGitPath::LOGACTIONS_IGNORE,List);\r
5345         for(int i=0;i<m_IgnoreFileList.GetCount();i++)\r
5346         {\r
5347                 CTGitPath * gitpatch=(CTGitPath*)&m_IgnoreFileList[i];\r
5348                 gitpatch->m_Checked = FALSE;\r
5349                 m_arStatusArray.push_back((CTGitPath*)&m_IgnoreFileList[i]);\r
5350         }\r
5351         return 0;\r
5352 }\r
5353 int CGitStatusListCtrl::UpdateFileList(int mask,bool once,CTGitPathList *List)\r
5354 {\r
5355         if(mask&CGitStatusListCtrl::FILELIST_MODIFY)\r
5356         {\r
5357                 if(once || (!(m_FileLoaded&CGitStatusListCtrl::FILELIST_MODIFY)))\r
5358                 {\r
5359                         UpdateFileList(git_revnum_t(GIT_REV_ZERO),List);\r
5360                         m_FileLoaded|=CGitStatusListCtrl::FILELIST_MODIFY;\r
5361                 }\r
5362         }\r
5363         if(mask&CGitStatusListCtrl::FILELIST_UNVER)\r
5364         {\r
5365                 if(once || (!(m_FileLoaded&CGitStatusListCtrl::FILELIST_UNVER)))\r
5366                 {\r
5367                         UpdateUnRevFileList(List);\r
5368                         m_FileLoaded|=CGitStatusListCtrl::FILELIST_UNVER;\r
5369                 }\r
5370         }\r
5371         return 0;\r
5372 }\r
5373 //////////////////////////////////////////////////////////////////////////\r
5374 #if 0\r
5375 bool CGitStatusListCtrlDropTarget::OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt)\r
5376 {\r
5377         if(pFmtEtc->cfFormat == CF_HDROP && medium.tymed == TYMED_HGLOBAL)\r
5378         {\r
5379                 HDROP hDrop = (HDROP)GlobalLock(medium.hGlobal);\r
5380                 if(hDrop != NULL)\r
5381                 {\r
5382                         TCHAR szFileName[MAX_PATH];\r
5383 \r
5384                         UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);\r
5385 \r
5386                         POINT clientpoint;\r
5387                         clientpoint.x = pt.x;\r
5388                         clientpoint.y = pt.y;\r
5389                         ScreenToClient(m_hTargetWnd, &clientpoint);\r
5390                         if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
5391                         {\r
5392                                 CTSVNPathList changelistItems;\r
5393                                 for(UINT i = 0; i < cFiles; ++i)\r
5394                                 {\r
5395                                         DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
5396                                         changelistItems.AddPath(CTSVNPath(szFileName));\r
5397                                 }\r
5398                                 // find the changelist name\r
5399                                 CString sChangelist;\r
5400                                 LONG_PTR nGroup = m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint);\r
5401                                 for (std::map<CString, int>::iterator it = m_pSVNStatusListCtrl->m_changelists.begin(); it != m_pSVNStatusListCtrl->m_changelists.end(); ++it)\r
5402                                         if (it->second == nGroup)\r
5403                                                 sChangelist = it->first;\r
5404                                 if (!sChangelist.IsEmpty())\r
5405                                 {\r
5406                                         SVN git;\r
5407                                         if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
5408                                         {\r
5409                                                 for (int l=0; l<changelistItems.GetCount(); ++l)\r
5410                                                 {\r
5411                                                         int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
5412                                                         if (index >= 0)\r
5413                                                         {\r
5414                                                                 CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
5415                                                                 if (e)\r
5416                                                                 {\r
5417                                                                         e->changelist = sChangelist;\r
5418                                                                         if (!e->IsFolder())\r
5419                                                                         {\r
5420                                                                                 if (m_pSVNStatusListCtrl->m_changelists.find(e->changelist)!=m_pSVNStatusListCtrl->m_changelists.end())\r
5421                                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, m_pSVNStatusListCtrl->m_changelists[e->changelist]);\r
5422                                                                                 else\r
5423                                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
5424                                                                         }\r
5425                                                                 }\r
5426                                                         }\r
5427                                                         else\r
5428                                                         {\r
5429                                                                 HWND hParentWnd = GetParent(m_hTargetWnd);\r
5430                                                                 if (hParentWnd != NULL)\r
5431                                                                         ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
5432                                                         }\r
5433                                                 }\r
5434                                         }\r
5435                                         else\r
5436                                         {\r
5437                                                 CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
5438                                         }\r
5439                                 }\r
5440                                 else\r
5441                                 {\r
5442                                         SVN git;\r
5443                                         if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
5444                                         {\r
5445                                                 for (int l=0; l<changelistItems.GetCount(); ++l)\r
5446                                                 {\r
5447                                                         int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
5448                                                         if (index >= 0)\r
5449                                                         {\r
5450                                                                 CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
5451                                                                 if (e)\r
5452                                                                 {\r
5453                                                                         e->changelist = sChangelist;\r
5454                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
5455                                                                 }\r
5456                                                         }\r
5457                                                         else\r
5458                                                         {\r
5459                                                                 HWND hParentWnd = GetParent(m_hTargetWnd);\r
5460                                                                 if (hParentWnd != NULL)\r
5461                                                                         ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
5462                                                         }\r
5463                                                 }\r
5464                                         }\r
5465                                         else\r
5466                                         {\r
5467                                                 CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
5468                                         }\r
5469                                 }\r
5470                         }\r
5471                         else\r
5472                         {\r
5473                                 for(UINT i = 0; i < cFiles; ++i)\r
5474                                 {\r
5475                                         DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
5476                                         HWND hParentWnd = GetParent(m_hTargetWnd);\r
5477                                         if (hParentWnd != NULL)\r
5478                                                 ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)szFileName);\r
5479                                 }\r
5480                         }\r
5481                 }\r
5482                 GlobalUnlock(medium.hGlobal);\r
5483         }\r
5484         return true; //let base free the medium\r
5485 }\r
5486 HRESULT STDMETHODCALLTYPE CSVNStatusListCtrlDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect)\r
5487 {\r
5488         CIDropTarget::DragOver(grfKeyState, pt, pdwEffect);\r
5489         *pdwEffect = DROPEFFECT_COPY;\r
5490         if (m_pSVNStatusListCtrl)\r
5491         {\r
5492                 POINT clientpoint;\r
5493                 clientpoint.x = pt.x;\r
5494                 clientpoint.y = pt.y;\r
5495                 ScreenToClient(m_hTargetWnd, &clientpoint);\r
5496                 if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
5497                 {\r
5498                         *pdwEffect = DROPEFFECT_MOVE;\r
5499                 }\r
5500                 else if ((!m_pSVNStatusListCtrl->m_bFileDropsEnabled)||(m_pSVNStatusListCtrl->m_bOwnDrag))\r
5501                 {\r
5502                         *pdwEffect = DROPEFFECT_NONE;\r
5503                 }\r
5504         }\r
5505         return S_OK;\r
5506 }f\r
5507 \r
5508 #endif