OSDN Git Service

9fb6a377eb5447eb9c18de05236ae02bda4d6583
[tortoisegit/TortoiseGitJp.git] / src / Git / GitStatusListCtrl.cpp
1 \r
2 \r
3 // TortoiseSVN - a Windows shell extension for easy version control\r
4 \r
5 // Copyright (C) 2003-2008 - TortoiseSVN\r
6 \r
7 // This program is free software; you can redistribute it and/or\r
8 // modify it under the terms of the GNU General Public License\r
9 // as published by the Free Software Foundation; either version 2\r
10 // of the License, or (at your option) any later version.\r
11 \r
12 // This program is distributed in the hope that it will be useful,\r
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 // GNU General Public License for more details.\r
16 \r
17 // You should have received a copy of the GNU General Public License\r
18 // along with this program; if not, write to the Free Software Foundation,\r
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
20 //\r
21 \r
22 #include "StdAfx.h"\r
23 #include "GitStatusListCtrl.h"\r
24 #include "resource.h"\r
25 #include "..\\TortoiseShell\resource.h"\r
26 #include "MessageBox.h"\r
27 #include "MyMemDC.h"\r
28 #include "UnicodeUtils.h"\r
29 #include "AppUtils.h"\r
30 #include "PathUtils.h"\r
31 #include "TempFile.h"\r
32 #include "StringUtils.h"\r
33 #include "DirFileEnum.h"\r
34 #include "GitConfig.h"\r
35 //#include "SVNProperties.h"\r
36 #include "Git.h"\r
37 #include "GitDiff.h"\r
38 //#include "LogDlg.h"\r
39 //#include "SVNProgressDlg.h"\r
40 #include "SysImageList.h"\r
41 //#include "Svnstatuslistctrl.h"\r
42 #include "TGitPath.h"\r
43 #include "Registry.h"\r
44 #include "GitStatus.h"\r
45 //#include "SVNHelpers.h"\r
46 #include "InputDlg.h"\r
47 #include "ShellUpdater.h"\r
48 #include "GitAdminDir.h"\r
49 //#include "DropFiles.h"\r
50 #include "IconMenu.h"\r
51 //#include "AddDlg.h"\r
52 //#include "EditPropertiesDlg.h"\r
53 //#include "CreateChangelistDlg.h"\r
54 #include "XPTheme.h"\r
55 \r
56 const UINT CGitStatusListCtrl::SVNSLNM_ITEMCOUNTCHANGED\r
57                                         = ::RegisterWindowMessage(_T("GITSLNM_ITEMCOUNTCHANGED"));\r
58 const UINT CGitStatusListCtrl::SVNSLNM_NEEDSREFRESH\r
59                                         = ::RegisterWindowMessage(_T("GITSLNM_NEEDSREFRESH"));\r
60 const UINT CGitStatusListCtrl::SVNSLNM_ADDFILE\r
61                                         = ::RegisterWindowMessage(_T("GITSLNM_ADDFILE"));\r
62 const UINT CGitStatusListCtrl::SVNSLNM_CHECKCHANGED\r
63                                         = ::RegisterWindowMessage(_T("GITSLNM_CHECKCHANGED"));\r
64 \r
65 #define IDSVNLC_REVERT                   1\r
66 #define IDSVNLC_COMPARE                  2\r
67 #define IDSVNLC_OPEN                     3\r
68 #define IDSVNLC_DELETE                   4\r
69 #define IDSVNLC_IGNORE                   5\r
70 #define IDSVNLC_GNUDIFF1                 6\r
71 #define IDSVNLC_UPDATE           7\r
72 #define IDSVNLC_LOG              8\r
73 #define IDSVNLC_EDITCONFLICT     9\r
74 #define IDSVNLC_IGNOREMASK          10\r
75 #define IDSVNLC_ADD                         11\r
76 #define IDSVNLC_RESOLVECONFLICT 12\r
77 #define IDSVNLC_LOCK                    13\r
78 #define IDSVNLC_LOCKFORCE               14\r
79 #define IDSVNLC_UNLOCK                  15\r
80 #define IDSVNLC_UNLOCKFORCE             16\r
81 #define IDSVNLC_OPENWITH                17\r
82 #define IDSVNLC_EXPLORE                 18\r
83 #define IDSVNLC_RESOLVETHEIRS   19\r
84 #define IDSVNLC_RESOLVEMINE             20\r
85 #define IDSVNLC_REMOVE                  21\r
86 #define IDSVNLC_COMMIT                  22\r
87 #define IDSVNLC_PROPERTIES              23\r
88 #define IDSVNLC_COPY                    24\r
89 #define IDSVNLC_COPYEXT                 25\r
90 #define IDSVNLC_REPAIRMOVE              26\r
91 #define IDSVNLC_REMOVEFROMCS    27\r
92 #define IDSVNLC_CREATECS                28\r
93 #define IDSVNLC_CREATEIGNORECS  29\r
94 #define IDSVNLC_CHECKGROUP              30\r
95 #define IDSVNLC_UNCHECKGROUP    31\r
96 #define IDSVNLC_ADD_RECURSIVE   32\r
97 #define IDSVNLC_COMPAREWC               33\r
98 #define IDSVNLC_BLAME                   34\r
99 // the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where \r
100 // the submenu items get command ID's sequent to this number\r
101 #define IDSVNLC_MOVETOCS                35\r
102 \r
103 \r
104 BEGIN_MESSAGE_MAP(CGitStatusListCtrl, CListCtrl)\r
105         ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHdnItemclick)\r
106         ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHdnItemclick)\r
107         ON_NOTIFY(HDN_ENDTRACK, 0, OnColumnResized)\r
108         ON_NOTIFY(HDN_ENDDRAG, 0, OnColumnMoved)\r
109         ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, OnLvnItemchanged)\r
110         ON_WM_CONTEXTMENU()\r
111         ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)\r
112         ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnLvnGetInfoTip)\r
113         ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)\r
114         ON_WM_SETCURSOR()\r
115         ON_WM_GETDLGCODE()\r
116         ON_NOTIFY_REFLECT(NM_RETURN, OnNMReturn)\r
117         ON_WM_KEYDOWN()\r
118         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)\r
119         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)\r
120         ON_WM_PAINT()\r
121         ON_NOTIFY(HDN_BEGINTRACKA, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
122         ON_NOTIFY(HDN_BEGINTRACKW, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
123         ON_NOTIFY(HDN_ITEMCHANGINGA, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
124         ON_NOTIFY(HDN_ITEMCHANGINGW, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
125         ON_WM_DESTROY()\r
126         ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBeginDrag)\r
127         ON_NOTIFY_REFLECT(LVN_ITEMCHANGING, &CGitStatusListCtrl::OnLvnItemchanging)\r
128 END_MESSAGE_MAP()\r
129 \r
130 \r
131 \r
132 CGitStatusListCtrl::CGitStatusListCtrl() : CListCtrl()\r
133         //, m_HeadRev(GitRev::REV_HEAD)\r
134         , m_pbCanceled(NULL)\r
135         , m_pStatLabel(NULL)\r
136         , m_pSelectButton(NULL)\r
137         , m_pConfirmButton(NULL)\r
138         , m_bBusy(false)\r
139         , m_bEmpty(false)\r
140         , m_bUnversionedRecurse(true)\r
141         , m_bShowIgnores(false)\r
142         , m_pDropTarget(NULL)\r
143         , m_bIgnoreRemoveOnly(false)\r
144         , m_bCheckChildrenWithParent(false)\r
145         , m_bUnversionedLast(true)\r
146         , m_bHasChangeLists(false)\r
147         , m_bHasLocks(false)\r
148         , m_bBlock(false)\r
149         , m_bBlockUI(false)\r
150         , m_bHasCheckboxes(false)\r
151         , m_bCheckIfGroupsExist(true)\r
152         , m_bFileDropsEnabled(false)\r
153         , m_bOwnDrag(false)\r
154     , m_dwDefaultColumns(0)\r
155     , m_ColumnManager(this)\r
156     , m_bAscending(false)\r
157     , m_nSortedColumn(-1)\r
158         , m_sNoPropValueText(MAKEINTRESOURCE(IDS_STATUSLIST_NOPROPVALUE))\r
159 {\r
160         m_FileLoaded=0;\r
161         m_critSec.Init();\r
162 }\r
163 \r
164 CGitStatusListCtrl::~CGitStatusListCtrl()\r
165 {\r
166         if (m_pDropTarget)\r
167                 delete m_pDropTarget;\r
168         ClearStatusArray();\r
169 }\r
170 \r
171 void CGitStatusListCtrl::ClearStatusArray()\r
172 {\r
173 #if 0\r
174         Locker lock(m_critSec);\r
175         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
176         {\r
177                 delete m_arStatusArray[i];\r
178         }\r
179         m_arStatusArray.clear();\r
180 #endif\r
181 }\r
182 #if 0\r
183 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(UINT_PTR index)\r
184 {\r
185 \r
186         if (index >= (UINT_PTR)m_arListArray.size())\r
187                 return NULL;\r
188         if (m_arListArray[index] >= m_arStatusArray.size())\r
189                 return NULL;\r
190         return m_arStatusArray[m_arListArray[index]];\r
191 \r
192         return NULL;\r
193 }\r
194 #endif\r
195 #if 0\r
196 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetVisibleListEntry(const CTGitPath& path)\r
197 {\r
198         int itemCount = GetItemCount();\r
199         for (int i=0; i < itemCount; i++)\r
200         {\r
201                 FileEntry * entry = GetListEntry(i);\r
202                 if (entry->GetPath().IsEquivalentTo(path))\r
203                         return entry;\r
204         }\r
205         return NULL;\r
206 }\r
207 #endif\r
208 #if 0\r
209 CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(const CTGitPath& path)\r
210 {\r
211 \r
212         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
213         {\r
214                 FileEntry * entry = m_arStatusArray[i];\r
215                 if (entry->GetPath().IsEquivalentTo(path))\r
216                         return entry;\r
217         }\r
218 \r
219         return NULL;\r
220 }\r
221 #endif\r
222 \r
223 #if 0\r
224 int CGitStatusListCtrl::GetIndex(const CTGitPath& path)\r
225 {\r
226         int itemCount = GetItemCount();\r
227         for (int i=0; i < itemCount; i++)\r
228         {\r
229                 FileEntry * entry = GetListEntry(i);\r
230                 if (entry->GetPath().IsEquivalentTo(path))\r
231                         return i;\r
232         }\r
233         return -1;\r
234 }\r
235 #endif \r
236 \r
237 void CGitStatusListCtrl::Init(DWORD dwColumns, const CString& sColumnInfoContainer, DWORD dwContextMenus /* = GitSLC_POPALL */, bool bHasCheckboxes /* = true */)\r
238 {\r
239         Locker lock(m_critSec);\r
240 \r
241     m_dwDefaultColumns = dwColumns | 1;\r
242     m_dwContextMenus = dwContextMenus;\r
243         m_bHasCheckboxes = bHasCheckboxes;\r
244 \r
245     // set the extended style of the listcontrol\r
246         // the style LVS_EX_FULLROWSELECT interferes with the background watermark image but it's more important to be able to select in the whole row.\r
247         CRegDWORD regFullRowSelect(_T("Software\\TortoiseGit\\FullRowSelect"), TRUE);\r
248         DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES;\r
249         if (DWORD(regFullRowSelect))\r
250                 exStyle |= LVS_EX_FULLROWSELECT;\r
251         exStyle |= (bHasCheckboxes ? LVS_EX_CHECKBOXES : 0);\r
252         SetRedraw(false);\r
253         SetExtendedStyle(exStyle);\r
254 \r
255         CXPTheme theme;\r
256         theme.SetWindowTheme(m_hWnd, L"Explorer", NULL);\r
257 \r
258         m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();\r
259         SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);\r
260 \r
261     m_ColumnManager.ReadSettings (m_dwDefaultColumns, sColumnInfoContainer);\r
262 \r
263         // enable file drops\r
264 #if 0\r
265         if (m_pDropTarget == NULL)\r
266         {\r
267                 m_pDropTarget = new CGitStatusListCtrlDropTarget(this);\r
268                 RegisterDragDrop(m_hWnd,m_pDropTarget);\r
269                 // create the supported formats:\r
270                 FORMATETC ftetc={0};\r
271                 ftetc.dwAspect = DVASPECT_CONTENT;\r
272                 ftetc.lindex = -1;\r
273                 ftetc.tymed = TYMED_HGLOBAL;\r
274                 ftetc.cfFormat=CF_HDROP;\r
275                 m_pDropTarget->AddSuportedFormat(ftetc);\r
276         }\r
277 #endif\r
278 \r
279         SetRedraw(true);\r
280 \r
281         m_bUnversionedRecurse = !!((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\UnversionedRecurse"), TRUE));\r
282 }\r
283 \r
284 bool CGitStatusListCtrl::SetBackgroundImage(UINT nID)\r
285 {\r
286         return CAppUtils::SetListCtrlBackgroundImage(GetSafeHwnd(), nID);\r
287 }\r
288 \r
289 BOOL CGitStatusListCtrl::GetStatus ( const CTGitPathList& pathList\r
290                                    , bool bUpdate /* = FALSE */\r
291                                    , bool bShowIgnores /* = false */\r
292                                                                    , bool bShowUnRev\r
293                                    , bool bShowUserProps /* = false */)\r
294 {\r
295         Locker lock(m_critSec);\r
296         int mask= CGitStatusListCtrl::FILELIST_MODIFY;\r
297         if(bShowIgnores)\r
298                 mask|= CGitStatusListCtrl::FILELIST_IGNORE;\r
299         if(bShowUnRev)\r
300                 mask|= CGitStatusListCtrl::FILELIST_UNVER;\r
301         this->UpdateFileList(mask,bUpdate,(CTGitPathList*)&pathList);\r
302 \r
303 #if 0\r
304         \r
305         int refetchcounter = 0;\r
306         BOOL bRet = TRUE;\r
307         Invalidate();\r
308         // force the cursor to change\r
309         POINT pt;\r
310         GetCursorPos(&pt);\r
311         SetCursorPos(pt.x, pt.y);\r
312 \r
313         m_mapFilenameToChecked.clear();\r
314         //m_StatusUrlList.Clear();\r
315         bool bHasChangelists = (m_changelists.size()>1 || (m_changelists.size()>0 && !m_bHasIgnoreGroup));\r
316         m_changelists.clear();\r
317         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
318         {\r
319                 FileEntry * entry = m_arStatusArray[i];\r
320                 if ( bHasChangelists && entry->checked)\r
321                 {\r
322                         // If change lists are present, remember all checked entries\r
323                         CString path = entry->GetPath().GetGitPathString();\r
324                         m_mapFilenameToChecked[path] = true;\r
325                 }\r
326                 if ( (entry->status==git_wc_status_unversioned || entry->status==git_wc_status_missing ) && entry->checked )\r
327                 {\r
328                         // The user manually selected an unversioned or missing file. We remember\r
329                         // this so that the selection can be restored when refreshing.\r
330                         CString path = entry->GetPath().GetGitPathString();\r
331                         m_mapFilenameToChecked[path] = true;\r
332                 }\r
333                 else if ( entry->status > git_wc_status_normal && !entry->checked )\r
334                 {\r
335                         // The user manually deselected a versioned file. We remember\r
336                         // this so that the deselection can be restored when refreshing.\r
337                         CString path = entry->GetPath().GetGitPathString();\r
338                         m_mapFilenameToChecked[path] = false;\r
339                 }\r
340         }\r
341 \r
342         // use a sorted path list to make sure we fetch the status of\r
343         // parent items first, *then* the child items (if any)\r
344         CTGitPathList sortedPathList = pathList;\r
345         sortedPathList.SortByPathname();\r
346         do\r
347         {\r
348                 bRet = TRUE;\r
349                 m_nTargetCount = 0;\r
350                 m_bHasExternalsFromDifferentRepos = FALSE;\r
351                 m_bHasExternals = FALSE;\r
352                 m_bHasUnversionedItems = FALSE;\r
353                 m_bHasLocks = false;\r
354                 m_bHasChangeLists = false;\r
355                 m_bShowIgnores = bShowIgnores;\r
356                 m_nSortedColumn = 0;\r
357                 m_bBlock = TRUE;\r
358                 m_bBusy = true;\r
359                 m_bEmpty = false;\r
360                 Invalidate();\r
361 \r
362                 // first clear possible status data left from\r
363                 // previous GetStatus() calls\r
364                 ClearStatusArray();\r
365 \r
366                 m_StatusFileList = sortedPathList;\r
367 \r
368                 // Since Git_client_status() returns all files, even those in\r
369                 // folders included with Git:externals we need to check if all\r
370                 // files we get here belongs to the same repository.\r
371                 // It is possible to commit changes in an external folder, as long\r
372                 // as the folder belongs to the same repository (but another path),\r
373                 // but it is not possible to commit all files if the externals are\r
374                 // from a different repository.\r
375                 //\r
376                 // To check if all files belong to the same repository, we compare the\r
377                 // UUID's - if they're identical then the files belong to the same\r
378                 // repository and can be committed. But if they're different, then\r
379                 // tell the user to commit all changes in the external folders\r
380                 // first and exit.\r
381                 CStringA sUUID;                                 // holds the repo UUID\r
382                 CTGitPathList arExtPaths;               // list of Git:external paths\r
383 \r
384                 GitConfig config;\r
385 \r
386                 m_sURL.Empty();\r
387 \r
388                 m_nTargetCount = sortedPathList.GetCount();\r
389 \r
390                 GitStatus status(m_pbCanceled);\r
391                 if(m_nTargetCount > 1 && sortedPathList.AreAllPathsFilesInOneDirectory())\r
392                 {\r
393                         // This is a special case, where we've been given a list of files\r
394                         // all from one folder\r
395                         // We handle them by setting a status filter, then requesting the Git status of\r
396                         // all the files in the directory, filtering for the ones we're interested in\r
397                         status.SetFilter(sortedPathList);\r
398 \r
399                         // if all selected entries are files, we don't do a recursive status\r
400                         // fetching. But if only one is a directory, we have to recurse.\r
401                         git_depth_t depth = git_depth_files;\r
402                         // We have set a filter. If all selected items were files or we fetch\r
403                         // the status not recursively, then we have to include\r
404                         // ignored items too - the user has selected them\r
405                         bool bShowIgnoresRight = true;\r
406                         for (int fcindex=0; fcindex<sortedPathList.GetCount(); ++fcindex)\r
407                         {\r
408                                 if (sortedPathList[fcindex].IsDirectory())\r
409                                 {\r
410                                         depth = git_depth_infinity;\r
411                                         bShowIgnoresRight = false;\r
412                                         break;\r
413                                 }\r
414                         }\r
415                         if(!FetchStatusForSingleTarget(config, status, sortedPathList.GetCommonDirectory(), bUpdate, sUUID, arExtPaths, true, depth, bShowIgnoresRight))\r
416                         {\r
417                                 bRet = FALSE;\r
418                         }\r
419                 }\r
420                 else\r
421                 {\r
422                         for(int nTarget = 0; nTarget < m_nTargetCount; nTarget++)\r
423                         {\r
424                                 // check whether the path we want the status for is already fetched due to status-fetching\r
425                                 // of a parent path.\r
426                                 // this check is only done for file paths, because folder paths could be included already\r
427                                 // but not recursively\r
428                                 if (sortedPathList[nTarget].IsDirectory() || GetListEntry(sortedPathList[nTarget]) == NULL)\r
429                                 {\r
430                                         if(!FetchStatusForSingleTarget(config, status, sortedPathList[nTarget], bUpdate, sUUID, \r
431                                                 arExtPaths, false, git_depth_infinity, bShowIgnores))\r
432                                         {\r
433                                                 bRet = FALSE;\r
434                                         }\r
435                                 }\r
436                         }\r
437                 }\r
438 \r
439                 // remove the 'helper' files of conflicted items from the list.\r
440                 // otherwise they would appear as unversioned files.\r
441                 for (INT_PTR cind = 0; cind < m_ConflictFileList.GetCount(); ++cind)\r
442                 {\r
443                         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
444                         {\r
445                                 if (m_arStatusArray[i]->GetPath().IsEquivalentTo(m_ConflictFileList[cind]))\r
446                                 {\r
447                                         delete m_arStatusArray[i];\r
448                                         m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
449                                         break;\r
450                                 }\r
451                         }\r
452                 }\r
453                 refetchcounter++;\r
454         } while(!BuildStatistics() && (refetchcounter < 2) && (*m_pbCanceled==false));\r
455 \r
456     if (bShowUserProps)\r
457         FetchUserProperties();\r
458 \r
459     m_ColumnManager.UpdateUserPropList (m_arStatusArray);\r
460 \r
461         m_bBlock = FALSE;\r
462         m_bBusy = false;\r
463         GetCursorPos(&pt);\r
464         SetCursorPos(pt.x, pt.y);\r
465         return bRet;\r
466 #endif \r
467         return TRUE;\r
468 }\r
469 \r
470 //\r
471 // Fetch all local properties for all elements in the status array\r
472 //\r
473 void CGitStatusListCtrl::FetchUserProperties()\r
474 {\r
475 #if 0\r
476         GitPool globalPool;\r
477 \r
478     for (size_t i = 0, count = m_arStatusArray.size(); i < count; ++i)\r
479     {\r
480         // local / temp pool to hold parameters and props for a single item\r
481 \r
482         GitPool localPool ((apr_pool_t*)globalPool);\r
483 \r
484         // open working copy for this path\r
485 \r
486         const char* path = m_arStatusArray[i]->path.GetGitApiPath (localPool);\r
487          \r
488             Git_wc_adm_access_t *adm_access = NULL;          \r
489         Git_error_t * error = Git_wc_adm_probe_open3 ( &adm_access\r
490                                                      , NULL\r
491                                                      , path\r
492                                                      , FALSE    // no write lock\r
493                                                                                                          , 0            // lock just the directory/file itself\r
494                                                      , NULL\r
495                                                                                                          , NULL\r
496                                                      , localPool);\r
497         if (error == NULL)\r
498         {\r
499             // get the props and add them to the status info\r
500 \r
501             apr_hash_t* props = NULL;\r
502             Git_error_t * error = Git_wc_prop_list ( &props\r
503                                                    , path\r
504                                                    , adm_access\r
505                                                    , localPool);\r
506             if (error == NULL)\r
507             {\r
508                 for ( apr_hash_index_t *index \r
509                         = apr_hash_first (localPool, props)\r
510                     ; index != NULL\r
511                     ; index = apr_hash_next (index))\r
512                 {\r
513                     // extract next entry from hash\r
514 \r
515                     const char* key = NULL;\r
516                     ptrdiff_t keyLen;\r
517                     const char** val = NULL;\r
518 \r
519                     apr_hash_this ( index\r
520                                   , reinterpret_cast<const void**>(&key)\r
521                                   , &keyLen\r
522                                   , reinterpret_cast<void**>(&val));\r
523 \r
524                     // decode / dispatch it\r
525 \r
526                         CString name = CUnicodeUtils::GetUnicode (key);\r
527                         CString value = CUnicodeUtils::GetUnicode (*val);\r
528 \r
529                     // store in property container (truncate it after ~100 chars)\r
530 \r
531                     m_arStatusArray[i]->present_props[name] \r
532                         = value.Left (GitSLC_MAXUSERPROPLENGTH);\r
533                 }\r
534             }\r
535             error = Git_wc_adm_close2 (adm_access, localPool);\r
536         }\r
537         Git_error_clear (error);\r
538     }\r
539 #endif\r
540 }\r
541 \r
542 \r
543 //\r
544 // Work on a single item from the list of paths which is provided to us\r
545 //\r
546 bool CGitStatusListCtrl::FetchStatusForSingleTarget(\r
547                                                         GitConfig& config,\r
548                                                         GitStatus& status,\r
549                                                         const CTGitPath& target,\r
550                                                         bool bFetchStatusFromRepository,\r
551                                                         CStringA& strCurrentRepositoryUUID,\r
552                                                         CTGitPathList& arExtPaths,\r
553                                                         bool bAllDirect,\r
554                                                         git_depth_t depth,\r
555                                                         bool bShowIgnores\r
556                                                         )\r
557 {\r
558 #if 0\r
559         config.GetDefaultIgnores();\r
560 \r
561         CTGitPath workingTarget(target);\r
562 \r
563         git_wc_status2_t * s;\r
564         CTGitPath GitPath;\r
565         s = status.GetFirstFileStatus(workingTarget, GitPath, bFetchStatusFromRepository, depth, bShowIgnores);\r
566 \r
567         m_HeadRev = SVNRev(status.headrev);\r
568         if (s!=0)\r
569         {\r
570                 Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
571 \r
572                 // This one fixes a problem with externals:\r
573                 // If a strLine is a file, Git:externals and its parent directory\r
574                 // will also be returned by GetXXXFileStatus. Hence, we skip all\r
575                 // status info until we find the one matching workingTarget.\r
576                 if (!workingTarget.IsDirectory())\r
577                 {\r
578                         if (!workingTarget.IsEquivalentTo(GitPath))\r
579                         {\r
580                                 while (s != 0)\r
581                                 {\r
582                                         s = status.GetNextFileStatus(GitPath);\r
583                                         if(workingTarget.IsEquivalentTo(GitPath))\r
584                                         {\r
585                                                 break;\r
586                                         }\r
587                                 }\r
588                                 if (s == 0)\r
589                                 {\r
590                                         m_sLastError = status.GetLastErrorMsg();\r
591                                         return false;\r
592                                 }\r
593                                 // Now, set working target to be the base folder of this item\r
594                                 workingTarget = workingTarget.GetDirectory();\r
595                         }\r
596                 }\r
597                 bool bEntryFromDifferentRepo = false;\r
598                 // Is this a versioned item with an associated repos UUID?\r
599                 if ((s->entry)&&(s->entry->uuid))\r
600                 {\r
601                         // Have we seen a repos UUID yet?\r
602                         if (strCurrentRepositoryUUID.IsEmpty())\r
603                         {\r
604                                 // This is the first repos UUID we've seen - record it\r
605                                 strCurrentRepositoryUUID = s->entry->uuid;\r
606                                 m_sUUID = strCurrentRepositoryUUID;\r
607                         }\r
608                         else\r
609                         {\r
610                                 if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
611                                 {\r
612                                         // This item comes from a different repository than our main one\r
613                                         m_bHasExternalsFromDifferentRepos = TRUE;\r
614                                         bEntryFromDifferentRepo = true;\r
615                                         if (s->entry->kind == Git_node_dir)\r
616                                                 arExtPaths.AddPath(workingTarget);\r
617                                 }\r
618                         }\r
619                 }\r
620                 else if (strCurrentRepositoryUUID.IsEmpty() && (s->text_status == Git_wc_status_added))\r
621                 {\r
622                         // An added entry doesn't have an UUID assigned to it yet.\r
623                         // So we fetch the status of the parent directory instead and\r
624                         // check if that one has an UUID assigned to it.\r
625                         Git_wc_status2_t * sparent;\r
626                         CTGitPath path = workingTarget;\r
627                         do\r
628                         {\r
629                                 CTGitPath GitParentPath;\r
630                                 GitStatus tempstatus;\r
631                                 sparent = tempstatus.GetFirstFileStatus(path.GetContainingDirectory(), GitParentPath, false, Git_depth_empty, false);\r
632                                 path = GitParentPath;\r
633                         } while ( (sparent) && (sparent->entry) && (!sparent->entry->uuid) && (sparent->text_status==Git_wc_status_added) );\r
634                         if (sparent && sparent->entry && sparent->entry->uuid)\r
635                         {\r
636                                 strCurrentRepositoryUUID = sparent->entry->uuid;\r
637                                 m_sUUID = strCurrentRepositoryUUID;\r
638                         }\r
639                 }\r
640 \r
641                 if ((wcFileStatus == Git_wc_status_unversioned)&& GitPath.IsDirectory())\r
642                 {\r
643                         // check if the unversioned folder is maybe versioned. This\r
644                         // could happen with nested layouts\r
645                         Git_wc_status_kind st = GitStatus::GetAllStatus(workingTarget);\r
646                         if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
647                         {\r
648                                 return true;    // ignore nested layouts\r
649                         }\r
650                 }\r
651                 if (status.IsExternal(GitPath))\r
652                 {\r
653                         m_bHasExternals = TRUE;\r
654                 }\r
655 \r
656                 AddNewFileEntry(s, GitPath, workingTarget, true, m_bHasExternals, bEntryFromDifferentRepo);\r
657 \r
658                 if (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none)||((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))) && GitPath.IsDirectory())\r
659                 {\r
660                         // we have an unversioned folder -> get all files in it recursively!\r
661                         AddUnversionedFolder(GitPath, workingTarget.GetContainingDirectory(), &config);\r
662                 }\r
663 \r
664                 // for folders, get all statuses inside it too\r
665                 if(workingTarget.IsDirectory())\r
666                 {\r
667                         ReadRemainingItemsStatus(status, workingTarget, strCurrentRepositoryUUID, arExtPaths, &config, bAllDirect);\r
668                 }\r
669 \r
670         } // if (s!=0)\r
671         else\r
672         {\r
673                 m_sLastError = status.GetLastErrorMsg();\r
674                 return false;\r
675         }\r
676 #endif\r
677         return true;\r
678 }\r
679 #if 0\r
680 const CGitStatusListCtrl::FileEntry*\r
681 CGitStatusListCtrl::AddNewFileEntry(\r
682                         const git_wc_status2_t* pGitStatus,  // The return from the Git GetStatus functions\r
683                         const CTGitPath& path,                          // The path of the item we're adding\r
684                         const CTGitPath& basePath,                      // The base directory for this status build\r
685                         bool bDirectItem,                                       // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call\r
686                         bool bInExternal,                                       // Are we in an 'external' folder\r
687                         bool bEntryfromDifferentRepo            // if the entry is from a different repository\r
688                         )\r
689 {\r
690         FileEntry * entry = new FileEntry();\r
691 \r
692         \r
693         entry->path = path;\r
694         entry->basepath = basePath;\r
695         entry->status = GitStatus::GetMoreImportant(pGitStatus->text_status, pGitStatus->prop_status);\r
696         entry->textstatus = pGitStatus->text_status;\r
697         entry->propstatus = pGitStatus->prop_status;\r
698 //      entry->remotestatus = GitStatus::GetMoreImportant(pGitStatus->repos_text_status, pGitStatus->repos_prop_status);\r
699 //      entry->remotetextstatus = pGitStatus->repos_text_status;\r
700 //      entry->remotepropstatus = pGitStatus->repos_prop_status;\r
701         entry->inexternal = bInExternal;\r
702         entry->differentrepo = bEntryfromDifferentRepo;\r
703         entry->direct = bDirectItem;\r
704 //      entry->copied = !!pGitStatus->copied;\r
705 //      entry->switched = !!pGitStatus->switched;\r
706 \r
707         entry->last_commit_date = pGitStatus->ood_last_cmt_date;\r
708         if ((entry->last_commit_date == NULL)&&(pGitStatus->entry))\r
709                 entry->last_commit_date = pGitStatus->entry->cmt_date;\r
710         entry->remoterev = pGitStatus->ood_last_cmt_rev;\r
711         if (pGitStatus->entry)\r
712                 entry->last_commit_rev = pGitStatus->entry->cmt_rev;\r
713         if (pGitStatus->ood_last_cmt_author)\r
714                 entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->ood_last_cmt_author);\r
715         if ((entry->last_commit_author.IsEmpty())&&(pGitStatus->entry)&&(pGitStatus->entry->cmt_author))\r
716                 entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->entry->cmt_author);\r
717 \r
718         if (pGitStatus->entry)\r
719                 entry->isConflicted = (pGitStatus->entry->conflict_wrk && PathFileExists(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk))) ? true : false;\r
720 \r
721         if ((entry->status == Git_wc_status_conflicted)||(entry->isConflicted))\r
722         {\r
723                 entry->isConflicted = true;\r
724                 if (pGitStatus->entry)\r
725                 {\r
726                         CTGitPath cpath;\r
727                         if (pGitStatus->entry->conflict_wrk)\r
728                         {\r
729                                 cpath = path.GetDirectory();\r
730                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk));\r
731                                 m_ConflictFileList.AddPath(cpath);\r
732                         }\r
733                         if (pGitStatus->entry->conflict_old)\r
734                         {\r
735                                 cpath = path.GetDirectory();\r
736                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_old));\r
737                                 m_ConflictFileList.AddPath(cpath);\r
738                         }\r
739                         if (pGitStatus->entry->conflict_new)\r
740                         {\r
741                                 cpath = path.GetDirectory();\r
742                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_new));\r
743                                 m_ConflictFileList.AddPath(cpath);\r
744                         }\r
745                         if (pGitStatus->entry->prejfile)\r
746                         {\r
747                                 cpath = path.GetDirectory();\r
748                                 cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->prejfile));\r
749                                 m_ConflictFileList.AddPath(cpath);\r
750                         }\r
751                 }\r
752         }\r
753 \r
754         if (pGitStatus->entry)\r
755         {\r
756                 entry->isfolder = (pGitStatus->entry->kind == Git_node_dir);\r
757                 entry->Revision = pGitStatus->entry->revision;\r
758                 entry->keeplocal = !!pGitStatus->entry->keep_local;\r
759                 entry->working_size = pGitStatus->entry->working_size;\r
760                 entry->depth = pGitStatus->entry->depth;\r
761 \r
762                 if (pGitStatus->entry->url)\r
763                 {\r
764                         entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->url));\r
765                 }\r
766                 if (pGitStatus->entry->copyfrom_url)\r
767                 {\r
768                         entry->copyfrom_url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->copyfrom_url));\r
769                         entry->copyfrom_rev = pGitStatus->entry->copyfrom_rev;\r
770                 }\r
771                 else\r
772                         entry->copyfrom_rev = 0;\r
773 \r
774                 if(bDirectItem)\r
775                 {\r
776                         if (m_sURL.IsEmpty())\r
777                                 m_sURL = entry->url;\r
778                         else\r
779                                 m_sURL.LoadString(IDS_STATUSLIST_MULTIPLETARGETS);\r
780                         m_StatusUrlList.AddPath(CTGitPath(entry->url));\r
781                 }\r
782                 if (pGitStatus->entry->lock_owner)\r
783                         entry->lock_owner = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_owner);\r
784                 if (pGitStatus->entry->lock_token)\r
785                 {\r
786                         entry->lock_token = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_token);\r
787                         m_bHasLocks = true;\r
788                 }\r
789                 if (pGitStatus->entry->lock_comment)\r
790                         entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_comment);\r
791 \r
792                 if (pGitStatus->entry->present_props)\r
793                 {\r
794                         entry->present_props = pGitStatus->entry->present_props;\r
795                 }\r
796 \r
797                 if (pGitStatus->entry->changelist)\r
798                 {\r
799                         entry->changelist = CUnicodeUtils::GetUnicode(pGitStatus->entry->changelist);\r
800                         m_changelists[entry->changelist] = -1;\r
801                         m_bHasChangeLists = true;\r
802                 }\r
803                 entry->needslock = (pGitStatus->entry->present_props && (strstr(pGitStatus->entry->present_props, "Git:needs-lock")!=NULL) );\r
804         }\r
805         else\r
806         {\r
807                 if (pGitStatus->ood_kind == Git_node_none)\r
808                         entry->isfolder = path.IsDirectory();\r
809                 else\r
810                         entry->isfolder = (pGitStatus->ood_kind == Git_node_dir);\r
811         }\r
812         if (pGitStatus->repos_lock)\r
813         {\r
814                 if (pGitStatus->repos_lock->owner)\r
815                         entry->lock_remoteowner = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->owner);\r
816                 if (pGitStatus->repos_lock->token)\r
817                         entry->lock_remotetoken = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->token);\r
818                 if (pGitStatus->repos_lock->comment)\r
819                         entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->comment);\r
820         }\r
821 \r
822         // Pass ownership of the entry to the array\r
823         m_arStatusArray.push_back(entry);\r
824 \r
825         return entry;\r
826 }\r
827 #endif\r
828 \r
829 void CGitStatusListCtrl::AddUnversionedFolder(const CTGitPath& folderName,\r
830                                                                                                 const CTGitPath& basePath,\r
831                                                                                                 GitConfig * config)\r
832 {\r
833 #if 0\r
834         if (!m_bUnversionedRecurse)\r
835                 return;\r
836         CSimpleFileFind filefinder(folderName.GetWinPathString());\r
837 \r
838         CTGitPath filename;\r
839         m_bHasUnversionedItems = TRUE;\r
840         while (filefinder.FindNextFileNoDots())\r
841         {\r
842                 filename.SetFromWin(filefinder.GetFilePath(), filefinder.IsDirectory());\r
843 \r
844                 bool bMatchIgnore = !!config->MatchIgnorePattern(filename.GetFileOrDirectoryName());\r
845                 bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(filename.GetGitPathString());\r
846                 if (((bMatchIgnore)&&(m_bShowIgnores))||(!bMatchIgnore))\r
847                 {\r
848                         FileEntry * entry = new FileEntry();\r
849                         entry->path = filename;\r
850                         entry->basepath = basePath;\r
851                         entry->inunversionedfolder = true;\r
852                         entry->isfolder = filefinder.IsDirectory();\r
853 \r
854                         m_arStatusArray.push_back(entry);\r
855                         if (entry->isfolder)\r
856                         {\r
857                                 if (!g_GitAdminDir.HasAdminDir(entry->path.GetWinPathString(), true))\r
858                                         AddUnversionedFolder(entry->path, basePath, config);\r
859                         }\r
860                 }\r
861         }\r
862 #endif\r
863 }\r
864 \r
865 \r
866 void CGitStatusListCtrl::ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& basePath,\r
867                                                                                   CStringA& strCurrentRepositoryUUID,\r
868                                                                                   CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect)\r
869 {\r
870 #if 0\r
871         git_wc_status2_t * s;\r
872 \r
873         CTGitPath lastexternalpath;\r
874         CTGitPath GitPath;\r
875         while ((s = status.GetNextFileStatus(GitPath)) != NULL)\r
876         {\r
877                 Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
878                 if ((wcFileStatus == Git_wc_status_unversioned) && (GitPath.IsDirectory()))\r
879                 {\r
880                         // check if the unversioned folder is maybe versioned. This\r
881                         // could happen with nested layouts\r
882                         Git_wc_status_kind st = GitStatus::GetAllStatus(GitPath);\r
883                         if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
884                         {\r
885                                 FileEntry * entry = new FileEntry();\r
886                                 entry->path = GitPath;\r
887                                 entry->basepath = basePath;\r
888                                 entry->inunversionedfolder = true;\r
889                                 entry->isfolder = true;\r
890                                 entry->isNested = true;\r
891                                 m_arStatusArray.push_back(entry);\r
892                                 continue;\r
893                         }\r
894                 }\r
895                 bool bDirectoryIsExternal = false;\r
896                 bool bEntryfromDifferentRepo = false;\r
897                 if (s->entry)\r
898                 {\r
899                         if (s->entry->uuid)\r
900                         {\r
901                                 if (strCurrentRepositoryUUID.IsEmpty())\r
902                                         strCurrentRepositoryUUID = s->entry->uuid;\r
903                                 else\r
904                                 {\r
905                                         if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
906                                         {\r
907                                                 bEntryfromDifferentRepo = true;\r
908                                                 if (GitStatus::IsImportant(wcFileStatus))\r
909                                                         m_bHasExternalsFromDifferentRepos = TRUE;\r
910                                                 if (s->entry->kind == Git_node_dir)\r
911                                                 {\r
912                                                         if ((lastexternalpath.IsEmpty())||(!lastexternalpath.IsAncestorOf(GitPath)))\r
913                                                         {\r
914                                                                 arExtPaths.AddPath(GitPath);\r
915                                                                 lastexternalpath = GitPath;\r
916                                                         }\r
917                                                 }\r
918                                         }\r
919                                 }\r
920                         }\r
921                         else\r
922                         {\r
923                                 // we don't have an UUID - maybe an added file/folder\r
924                                 if (!strCurrentRepositoryUUID.IsEmpty())\r
925                                 {\r
926                                         if ((!lastexternalpath.IsEmpty())&&\r
927                                                 (lastexternalpath.IsAncestorOf(GitPath)))\r
928                                         {\r
929                                                 bEntryfromDifferentRepo = true;\r
930                                                 m_bHasExternalsFromDifferentRepos = TRUE;\r
931                                         }\r
932                                 }\r
933                         }\r
934                 }\r
935                 else\r
936                 {\r
937                         // if unversioned items lie around in external\r
938                         // directories from different repos, we have to mark them\r
939                         // as such too.\r
940                         if (!strCurrentRepositoryUUID.IsEmpty())\r
941                         {\r
942                                 if ((!lastexternalpath.IsEmpty())&&\r
943                                         (lastexternalpath.IsAncestorOf(GitPath)))\r
944                                 {\r
945                                         bEntryfromDifferentRepo = true;\r
946                                 }\r
947                         }\r
948                 }\r
949                 if (status.IsExternal(GitPath))\r
950                 {\r
951                         arExtPaths.AddPath(GitPath);\r
952                         m_bHasExternals = TRUE;\r
953                 }\r
954                 if ((!bEntryfromDifferentRepo)&&(status.IsInExternal(GitPath)))\r
955                 {\r
956                         // if the externals are inside an unversioned folder (this happens if\r
957                         // the externals are specified with e.g. "ext\folder url" instead of just\r
958                         // "folder url"), then a commit won't succeed.\r
959                         // therefore, we treat those as if the externals come from a different\r
960                         // repository\r
961                         CTGitPath extpath = GitPath;\r
962                         while (basePath.IsAncestorOf(extpath))\r
963                         {\r
964                                 if (!extpath.HasAdminDir())\r
965                                 {\r
966                                         bEntryfromDifferentRepo = true;\r
967                                         break;\r
968                                 }\r
969                                 extpath = extpath.GetContainingDirectory();\r
970                         }\r
971                 }\r
972                 // Do we have any external paths?\r
973                 if(arExtPaths.GetCount() > 0)\r
974                 {\r
975                         // If do have external paths, we need to check if the current item belongs\r
976                         // to one of them\r
977                         for (int ix=0; ix<arExtPaths.GetCount(); ix++)\r
978                         {\r
979                                 if (arExtPaths[ix].IsAncestorOf(GitPath))\r
980                                 {\r
981                                         bDirectoryIsExternal = true;\r
982                                         break;\r
983                                 }\r
984                         }\r
985                 }\r
986 \r
987                 if ((wcFileStatus == Git_wc_status_unversioned)&&(!bDirectoryIsExternal))\r
988                         m_bHasUnversionedItems = TRUE;\r
989 \r
990                 const FileEntry* entry = AddNewFileEntry(s, GitPath, basePath, bAllDirect, bDirectoryIsExternal, bEntryfromDifferentRepo);\r
991 \r
992                 bool bMatchIgnore = !!config->MatchIgnorePattern(entry->path.GetFileOrDirectoryName());\r
993                 bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(entry->path.GetGitPathString());\r
994                 if ((((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(!bMatchIgnore))||\r
995                         ((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))||\r
996                         (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(bMatchIgnore)&&(m_bShowIgnores)))\r
997                 {\r
998                         if (entry->isfolder)\r
999                         {\r
1000                                 // we have an unversioned folder -> get all files in it recursively!\r
1001                                 AddUnversionedFolder(GitPath, basePath, config);\r
1002                         }\r
1003                 }\r
1004         } // while ((s = status.GetNextFileStatus(GitPath)) != NULL) \r
1005 #endif\r
1006 }\r
1007 \r
1008 // Get the show-flags bitmap value which corresponds to a particular Git status\r
1009 DWORD CGitStatusListCtrl::GetShowFlagsFromGitStatus(git_wc_status_kind status)\r
1010 {\r
1011         switch (status)\r
1012         {\r
1013         case git_wc_status_none:\r
1014         case git_wc_status_unversioned:\r
1015                 return SVNSLC_SHOWUNVERSIONED;\r
1016         case git_wc_status_ignored:\r
1017                 if (!m_bShowIgnores)\r
1018                         return SVNSLC_SHOWDIRECTS;\r
1019                 return SVNSLC_SHOWDIRECTS|SVNSLC_SHOWIGNORED;\r
1020         case git_wc_status_incomplete:\r
1021                 return SVNSLC_SHOWINCOMPLETE;\r
1022         case git_wc_status_normal:\r
1023                 return SVNSLC_SHOWNORMAL;\r
1024         case git_wc_status_external:\r
1025                 return SVNSLC_SHOWEXTERNAL;\r
1026         case git_wc_status_added:\r
1027                 return SVNSLC_SHOWADDED;\r
1028         case git_wc_status_missing:\r
1029                 return SVNSLC_SHOWMISSING;\r
1030         case git_wc_status_deleted:\r
1031                 return SVNSLC_SHOWREMOVED;\r
1032         case git_wc_status_replaced:\r
1033                 return SVNSLC_SHOWREPLACED;\r
1034         case git_wc_status_modified:\r
1035                 return SVNSLC_SHOWMODIFIED;\r
1036         case git_wc_status_merged:\r
1037                 return SVNSLC_SHOWMERGED;\r
1038         case git_wc_status_conflicted:\r
1039                 return SVNSLC_SHOWCONFLICTED;\r
1040         case git_wc_status_obstructed:\r
1041                 return SVNSLC_SHOWOBSTRUCTED;\r
1042         default:\r
1043                 // we should NEVER get here!\r
1044                 ASSERT(FALSE);\r
1045                 break;\r
1046         }\r
1047         return 0;\r
1048 }\r
1049 \r
1050 void CGitStatusListCtrl::Show(DWORD dwShow, DWORD dwCheck /*=0*/, bool bShowFolders /* = true */,BOOL UpdateStatusList)\r
1051 {\r
1052         CWinApp * pApp = AfxGetApp();\r
1053         if (pApp)\r
1054                 pApp->DoWaitCursor(1);\r
1055 \r
1056         Locker lock(m_critSec);\r
1057         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
1058         \r
1059         //SetItemCount(listIndex);\r
1060         SetRedraw(FALSE);\r
1061         DeleteAllItems();\r
1062         PrepareGroups();\r
1063         m_nSelected = 0;\r
1064 \r
1065         if(UpdateStatusList)\r
1066         {\r
1067                 m_arStatusArray.clear();\r
1068                 for(int i=0;i<this->m_StatusFileList.GetCount();i++)\r
1069                 {\r
1070                         m_arStatusArray.push_back((CTGitPath*)&m_StatusFileList[i]);\r
1071                 }\r
1072 \r
1073                 for(int i=0;i<this->m_UnRevFileList.GetCount();i++)\r
1074                 {\r
1075                         m_arStatusArray.push_back((CTGitPath*)&m_UnRevFileList[i]);\r
1076                 }\r
1077 \r
1078                 for(int i=0;i<this->m_IgnoreFileList.GetCount();i++)\r
1079                 {\r
1080                         m_arStatusArray.push_back((CTGitPath*)&m_IgnoreFileList[i]);\r
1081                 }\r
1082         }\r
1083         for(int i=0;i<this->m_arStatusArray.size();i++)\r
1084         {\r
1085                 if(((CTGitPath*)m_arStatusArray[i])->m_Action & dwShow)\r
1086                                 AddEntry((CTGitPath*)m_arStatusArray[i],langID,i);\r
1087         }\r
1088         \r
1089         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1090         for (int col = 0; col <= maxcol; col++)\r
1091         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1092 \r
1093     SetRedraw(TRUE);\r
1094         GetStatisticsString();\r
1095 \r
1096         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1097         HDITEM HeaderItem = {0};\r
1098         HeaderItem.mask = HDI_FORMAT;\r
1099         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1100         {\r
1101                 pHeader->GetItem(i, &HeaderItem);\r
1102                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1103                 pHeader->SetItem(i, &HeaderItem);\r
1104         }\r
1105         if (m_nSortedColumn)\r
1106         {\r
1107                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1108                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1109                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1110         }\r
1111 \r
1112 #if 0\r
1113         if (nSelectedEntry)\r
1114         {\r
1115                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1116                 EnsureVisible(nSelectedEntry, false);\r
1117         }\r
1118         else\r
1119         {\r
1120                 // Restore the item at the top of the list.\r
1121                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1122                 {\r
1123                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1124                         {\r
1125                                 break;\r
1126                         }\r
1127                 }\r
1128         }\r
1129 #endif\r
1130         if (pApp)\r
1131                 pApp->DoWaitCursor(-1);\r
1132 \r
1133         Invalidate();\r
1134         \r
1135         m_dwShow = dwShow;\r
1136 \r
1137 #if 0\r
1138 \r
1139         CWinApp * pApp = AfxGetApp();\r
1140         if (pApp)\r
1141                 pApp->DoWaitCursor(1);\r
1142 \r
1143         m_bShowFolders = bShowFolders;\r
1144         \r
1145         int nTopIndex = GetTopIndex();\r
1146         POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
1147         int nSelectedEntry = 0;\r
1148         if (posSelectedEntry)\r
1149                 nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
1150         SetRedraw(FALSE);\r
1151         DeleteAllItems();\r
1152 \r
1153         PrepareGroups();\r
1154 \r
1155         m_arListArray.clear();\r
1156 \r
1157         m_arListArray.reserve(m_arStatusArray.size());\r
1158         SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
1159 \r
1160         int listIndex = 0;\r
1161         for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
1162         {\r
1163                 FileEntry * entry = m_arStatusArray[i];\r
1164                 if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
1165                         continue;\r
1166                 if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
1167                         continue;\r
1168                 if (entry->IsFolder() && (!bShowFolders))\r
1169                         continue;       // don't show folders if they're not wanted.\r
1170 \r
1171 #if 0\r
1172                 git_wc_status_kind status = GitStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
1173                 DWORD showFlags = GetShowFlagsFromGitStatus(status);\r
1174                 if (entry->IsLocked())\r
1175                         showFlags |= SVNSLC_SHOWLOCKS;\r
1176                 if (entry->switched)\r
1177                         showFlags |= SVNSLC_SHOWSWITCHED;\r
1178                 if (!entry->changelist.IsEmpty())\r
1179                         showFlags |= SVNSLC_SHOWINCHANGELIST;\r
1180 #endif\r
1181                 bool bAllowCheck = ((entry->changelist.Compare(SVNSLC_IGNORECHANGELIST) != 0) \r
1182                         && (m_bCheckIfGroupsExist || (m_changelists.size()==0 || (m_changelists.size()==1 && m_bHasIgnoreGroup))));\r
1183 \r
1184                 // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
1185 #if 0\r
1186                 if (status != Git_wc_status_ignored || (entry->direct) || (dwShow & GitSLC_SHOWIGNORED))\r
1187                 {\r
1188                         if ((!entry->IsFolder()) && (status == Git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
1189                         {\r
1190                                 if (PathFileExists(entry->GetPath().GetWinPath()))\r
1191                                 {\r
1192                                         m_arListArray.push_back(i);\r
1193                                         if ((dwCheck & SVNSLC_SHOWREMOVEDANDPRESENT)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1194                                         {\r
1195                                                 if (bAllowCheck)\r
1196                                                         entry->checked = true;\r
1197                                         }\r
1198                                         AddEntry(entry, langID, listIndex++);\r
1199                                 }\r
1200                         }\r
1201                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
1202                         {\r
1203                                 m_arListArray.push_back(i);\r
1204                                 if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1205                                 {\r
1206                                         if (bAllowCheck)\r
1207                                                 entry->checked = true;\r
1208                                 }\r
1209                                 AddEntry(entry, langID, listIndex++);\r
1210                         }\r
1211                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
1212                         {\r
1213                                 m_arListArray.push_back(i);\r
1214                                 if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
1215                                 {\r
1216                                         if (bAllowCheck)\r
1217                                                 entry->checked = true;\r
1218                                 }\r
1219                                 AddEntry(entry, langID, listIndex++);\r
1220                         }\r
1221                 }\r
1222 #endif\r
1223         }\r
1224 \r
1225         SetItemCount(listIndex);\r
1226 \r
1227     m_ColumnManager.UpdateRelevance (m_arStatusArray, m_arListArray);\r
1228 \r
1229         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1230         for (int col = 0; col <= maxcol; col++)\r
1231         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1232 \r
1233     SetRedraw(TRUE);\r
1234         GetStatisticsString();\r
1235 \r
1236         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1237         HDITEM HeaderItem = {0};\r
1238         HeaderItem.mask = HDI_FORMAT;\r
1239         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1240         {\r
1241                 pHeader->GetItem(i, &HeaderItem);\r
1242                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1243                 pHeader->SetItem(i, &HeaderItem);\r
1244         }\r
1245         if (m_nSortedColumn)\r
1246         {\r
1247                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1248                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1249                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1250         }\r
1251 \r
1252         if (nSelectedEntry)\r
1253         {\r
1254                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1255                 EnsureVisible(nSelectedEntry, false);\r
1256         }\r
1257         else\r
1258         {\r
1259                 // Restore the item at the top of the list.\r
1260                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1261                 {\r
1262                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1263                         {\r
1264                                 break;\r
1265                         }\r
1266                 }\r
1267         }\r
1268 \r
1269         if (pApp)\r
1270                 pApp->DoWaitCursor(-1);\r
1271 \r
1272         m_bEmpty = (GetItemCount() == 0);\r
1273         Invalidate();\r
1274 #endif\r
1275 \r
1276 }\r
1277 \r
1278 void CGitStatusListCtrl::Show(DWORD dwShow, const CTGitPathList& checkedList, bool bShowFolders /* = true */)\r
1279 {\r
1280         return ;\r
1281 #if 0\r
1282 \r
1283         Locker lock(m_critSec);\r
1284         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
1285 \r
1286         CWinApp * pApp = AfxGetApp();\r
1287         if (pApp)\r
1288                 pApp->DoWaitCursor(1);\r
1289         m_dwShow = dwShow;\r
1290         m_bShowFolders = bShowFolders;\r
1291         m_nSelected = 0;\r
1292         int nTopIndex = GetTopIndex();\r
1293         POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
1294         int nSelectedEntry = 0;\r
1295         if (posSelectedEntry)\r
1296                 nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
1297         SetRedraw(FALSE);\r
1298         DeleteAllItems();\r
1299 \r
1300         PrepareGroups();\r
1301 \r
1302         m_arListArray.clear();\r
1303 \r
1304         m_arListArray.reserve(m_arStatusArray.size());\r
1305         SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
1306 \r
1307         int listIndex = 0;\r
1308         for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
1309         {\r
1310                 FileEntry * entry = m_arStatusArray[i];\r
1311                 if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
1312                         continue;\r
1313                 if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
1314                         continue;\r
1315                 if (entry->IsFolder() && (!bShowFolders))\r
1316                         continue;       // don't show folders if they're not wanted.\r
1317 #if 0\r
1318                 git_wc_status_kind status = SVNStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
1319                 DWORD showFlags = GetShowFlagsFromSVNStatus(status);\r
1320                 if (entry->IsLocked())\r
1321                         showFlags |= SVNSLC_SHOWLOCKS;\r
1322                 if (!entry->changelist.IsEmpty())\r
1323                         showFlags |= SVNSLC_SHOWINCHANGELIST;\r
1324 \r
1325                 // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
1326                 if (status != git_wc_status_ignored || (entry->direct) || (dwShow & SVNSLC_SHOWIGNORED))\r
1327                 {\r
1328                         for (int npath = 0; npath < checkedList.GetCount(); ++npath)\r
1329                         {\r
1330                                 if (entry->GetPath().IsEquivalentTo(checkedList[npath]))\r
1331                                 {\r
1332                                         entry->checked = true;\r
1333                                         break;\r
1334                                 }\r
1335                         }\r
1336                         if ((!entry->IsFolder()) && (status == git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
1337                         {\r
1338                                 if (PathFileExists(entry->GetPath().GetWinPath()))\r
1339                                 {\r
1340                                         m_arListArray.push_back(i);\r
1341                                         AddEntry(entry, langID, listIndex++);\r
1342                                 }\r
1343                         }\r
1344                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
1345                         {\r
1346                                 m_arListArray.push_back(i);\r
1347                                 AddEntry(entry, langID, listIndex++);\r
1348                         }\r
1349                         else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
1350                         {\r
1351                                 m_arListArray.push_back(i);\r
1352                                 AddEntry(entry, langID, listIndex++);\r
1353                         }\r
1354                         else if (entry->switched)\r
1355                         {\r
1356                                 m_arListArray.push_back(i);\r
1357                                 AddEntry(entry, langID, listIndex++);\r
1358                         }\r
1359                 }\r
1360 #endif\r
1361         }\r
1362 \r
1363         SetItemCount(listIndex);\r
1364 \r
1365         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
1366         for (int col = 0; col <= maxcol; col++)\r
1367         SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
1368 \r
1369     SetRedraw(TRUE);\r
1370         GetStatisticsString();\r
1371 \r
1372         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1373         HDITEM HeaderItem = {0};\r
1374         HeaderItem.mask = HDI_FORMAT;\r
1375         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1376         {\r
1377                 pHeader->GetItem(i, &HeaderItem);\r
1378                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1379                 pHeader->SetItem(i, &HeaderItem);\r
1380         }\r
1381         if (m_nSortedColumn)\r
1382         {\r
1383                 pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1384                 HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1385                 pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1386         }\r
1387 \r
1388         if (nSelectedEntry)\r
1389         {\r
1390                 SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
1391                 EnsureVisible(nSelectedEntry, false);\r
1392         }\r
1393         else\r
1394         {\r
1395                 // Restore the item at the top of the list.\r
1396                 for (int i=0;GetTopIndex() != nTopIndex;i++)\r
1397                 {\r
1398                         if ( !EnsureVisible(nTopIndex+i,false) )\r
1399                         {\r
1400                                 break;\r
1401                         }\r
1402                 }\r
1403         }\r
1404 \r
1405         if (pApp)\r
1406                 pApp->DoWaitCursor(-1);\r
1407 \r
1408         m_bEmpty = (GetItemCount() == 0);\r
1409         Invalidate();\r
1410 #endif\r
1411 \r
1412 }\r
1413 int CGitStatusListCtrl::GetColumnIndex(int mask)\r
1414 {\r
1415         int i=0;\r
1416         for(i=0;i<32;i++)\r
1417                 if(mask&0x1)\r
1418                         return i-1;\r
1419                 else\r
1420                         mask=mask>>1;\r
1421         return -1;\r
1422 }\r
1423 void CGitStatusListCtrl::AddEntry(CTGitPath * GitPath, WORD langID, int listIndex)\r
1424 {\r
1425         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
1426         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
1427 \r
1428         CString path = GitPath->GetGitPathString();\r
1429 \r
1430         m_bBlock = TRUE;\r
1431         TCHAR buf[100];\r
1432         int index = listIndex;\r
1433         int nCol = 1;\r
1434         CString entryname = GitPath->GetGitPathString();\r
1435         int icon_idx = 0;\r
1436 //      if (entry->isfolder)\r
1437 //              icon_idx = m_nIconFolder;\r
1438 //      else\r
1439         {\r
1440                 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(*GitPath);\r
1441         }\r
1442         // relative path\r
1443         InsertItem(index, entryname, icon_idx);\r
1444 \r
1445         this->SetItemData(index, (DWORD_PTR)GitPath);\r
1446         // SVNSLC_COLFILENAME\r
1447         SetItemText(index, nCol++, GitPath->GetFileOrDirectoryName());\r
1448         // SVNSLC_COLEXT\r
1449         SetItemText(index, nCol++, GitPath->GetFileExtension());\r
1450         // SVNSLC_COLSTATUS\r
1451         SetItemText(index, nCol++, GitPath->GetActionName());\r
1452 \r
1453         SetItemText(index, GetColumnIndex(SVNSLC_COLADD),GitPath->m_StatAdd);\r
1454         SetItemText(index, GetColumnIndex(SVNSLC_COLDEL),GitPath->m_StatDel);\r
1455 \r
1456 \r
1457         SetCheck(index, GitPath->m_Checked);\r
1458         if (GitPath->m_Checked)\r
1459                 m_nSelected++;\r
1460 \r
1461 \r
1462         if( GitPath->m_Action & CTGitPath::LOGACTIONS_IGNORE)\r
1463                 SetItemGroup(index, 2);\r
1464         else if( GitPath->m_Action & CTGitPath::LOGACTIONS_UNVER)\r
1465                 SetItemGroup(index,1);\r
1466         else\r
1467                 SetItemGroup(index,0);\r
1468         m_bBlock = FALSE;\r
1469 \r
1470 \r
1471 }\r
1472 #if 0\r
1473 void CGitStatusListCtrl::AddEntry(FileEntry * entry, WORD langID, int listIndex)\r
1474 {\r
1475         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
1476         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
1477 \r
1478         CString path = entry->GetPath().GetGitPathString();\r
1479         if ( m_mapFilenameToChecked.size()!=0 && m_mapFilenameToChecked.find(path) != m_mapFilenameToChecked.end() )\r
1480         {\r
1481                 // The user manually de-/selected an item. We now restore this status\r
1482                 // when refreshing.\r
1483                 entry->checked = m_mapFilenameToChecked[path];\r
1484         }\r
1485 \r
1486         m_bBlock = TRUE;\r
1487         TCHAR buf[100];\r
1488         int index = listIndex;\r
1489         int nCol = 1;\r
1490         CString entryname = entry->GetDisplayName();\r
1491         int icon_idx = 0;\r
1492         if (entry->isfolder)\r
1493                 icon_idx = m_nIconFolder;\r
1494         else\r
1495         {\r
1496                 icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(entry->path);\r
1497         }\r
1498         // relative path\r
1499         InsertItem(index, entryname, icon_idx);\r
1500         // SVNSLC_COLFILENAME\r
1501         SetItemText(index, nCol++, entry->path.GetFileOrDirectoryName());\r
1502         // SVNSLC_COLEXT\r
1503         SetItemText(index, nCol++, entry->path.GetFileExtension());\r
1504         // SVNSLC_COLSTATUS\r
1505         if (entry->isNested)\r
1506         {\r
1507                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1508                 SetItemText(index, nCol++, sTemp);\r
1509         }\r
1510         else\r
1511         {\r
1512                 GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1513                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1514                         _tcscat_s(buf, 100, _T(" (+)"));\r
1515                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1516                         _tcscat_s(buf, 100, _T(" (s)"));\r
1517 #if 0\r
1518                 if ((entry->status == entry->propstatus)&&\r
1519                         (entry->status != git_wc_status_normal)&&\r
1520                         (entry->status != git_wc_status_unversioned)&&\r
1521                         (!GitStatus::IsImportant(entry->textstatus)))\r
1522                         _tcscat_s(buf, 100, ponly);\r
1523 #endif\r
1524                 SetItemText(index, nCol++, buf);\r
1525         }\r
1526         // SVNSLC_COLREMOTESTATUS\r
1527         if (entry->isNested)\r
1528         {\r
1529                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1530                 SetItemText(index, nCol++, sTemp);\r
1531         }\r
1532         else\r
1533         {\r
1534 #if 0\r
1535                 SVNStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1536                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1537                         _tcscat_s(buf, 100, _T(" (+)"));\r
1538                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1539                         _tcscat_s(buf, 100, _T(" (s)"));\r
1540                 if ((entry->remotestatus == entry->remotepropstatus)&&\r
1541                         (entry->remotestatus != git_wc_status_none)&&\r
1542                         (entry->remotestatus != git_wc_status_normal)&&\r
1543                         (entry->remotestatus != git_wc_status_unversioned)&&\r
1544                         (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
1545                         _tcscat_s(buf, 100, ponly);\r
1546 #endif\r
1547                 SetItemText(index, nCol++, buf);\r
1548         }\r
1549         // SVNSLC_COLTEXTSTATUS\r
1550         if (entry->isNested)\r
1551         {\r
1552                 CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
1553                 SetItemText(index, nCol++, sTemp);\r
1554         }\r
1555         else\r
1556         {\r
1557 #if 0\r
1558                 SVNStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1559                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1560                         _tcscat_s(buf, 100, _T(" (+)"));\r
1561                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1562                         _tcscat_s(buf, 100, _T(" (s)"));\r
1563 #endif\r
1564                 SetItemText(index, nCol++, buf);\r
1565         }\r
1566         // SVNSLC_COLPROPSTATUS\r
1567         if (entry->isNested)\r
1568         {\r
1569                 SetItemText(index, nCol++, _T(""));\r
1570         }\r
1571         else\r
1572         {\r
1573 #if 0\r
1574                 SVNStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1575                 if ((entry->copied)&&(_tcslen(buf)>1))\r
1576                         _tcscat_s(buf, 100, _T(" (+)"));\r
1577                 if ((entry->switched)&&(_tcslen(buf)>1))\r
1578                         _tcscat_s(buf, 100, _T(" (s)"));\r
1579 #endif\r
1580                 SetItemText(index, nCol++, buf);\r
1581         }\r
1582         // SVNSLC_COLREMOTETEXT\r
1583         if (entry->isNested)\r
1584         {\r
1585                 SetItemText(index, nCol++, _T(""));\r
1586         }\r
1587         else\r
1588         {\r
1589 #if 0\r
1590                 SVNStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1591                 SetItemText(index, nCol++, buf);\r
1592 #endif\r
1593         }\r
1594         // SVNSLC_COLREMOTEPROP\r
1595         if (entry->isNested)\r
1596         {\r
1597                 SetItemText(index, nCol++, _T(""));\r
1598         }\r
1599         else\r
1600         {\r
1601 //              SVNStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
1602                 SetItemText(index, nCol++, buf);\r
1603         }\r
1604         // SVNSLC_COLURL\r
1605 //      SetItemText(index, nCol++, entry->url);\r
1606         // SVNSLC_COLLOCK\r
1607 #if 0\r
1608         if (!m_HeadRev.IsHead())\r
1609         {\r
1610                 // we have contacted the repository\r
1611 \r
1612                 // decision-matrix\r
1613                 // wc           repository              text\r
1614                 // ""           ""                              ""\r
1615                 // ""           UID1                    owner\r
1616                 // UID1         UID1                    owner\r
1617                 // UID1         ""                              lock has been broken\r
1618                 // UID1         UID2                    lock has been stolen\r
1619                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
1620                 {\r
1621                         if (entry->lock_owner.IsEmpty())\r
1622                                 SetItemText(index, nCol++, entry->lock_remoteowner);\r
1623                         else\r
1624                                 SetItemText(index, nCol++, entry->lock_owner);\r
1625                 }\r
1626                 else if (entry->lock_remotetoken.IsEmpty())\r
1627                 {\r
1628                         // broken lock\r
1629                         CString temp(MAKEINTRESOURCE(IDS_STATUSLIST_LOCKBROKEN));\r
1630                         SetItemText(index, nCol++, temp);\r
1631                 }\r
1632                 else\r
1633                 {\r
1634                         // stolen lock\r
1635                         CString temp;\r
1636                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
1637                         SetItemText(index, nCol++, temp);\r
1638                 }\r
1639         }\r
1640         else\r
1641                 SetItemText(index, nCol++, entry->lock_owner);\r
1642         // SVNSLC_COLLOCKCOMMENT\r
1643         SetItemText(index, nCol++, entry->lock_comment);\r
1644         // SVNSLC_COLAUTHOR\r
1645         SetItemText(index, nCol++, entry->last_commit_author);\r
1646         // SVNSLC_COLREVISION\r
1647         CString temp;\r
1648         temp.Format(_T("%ld"), entry->last_commit_rev);\r
1649         if (entry->last_commit_rev > 0)\r
1650                 SetItemText(index, nCol++, temp);\r
1651         else\r
1652                 SetItemText(index, nCol++, _T(""));\r
1653         // SVNSLC_COLREMOTEREVISION\r
1654         temp.Format(_T("%ld"), entry->remoterev);\r
1655         if (entry->remoterev > 0)\r
1656                 SetItemText(index, nCol++, temp);\r
1657         else\r
1658                 SetItemText(index, nCol++, _T(""));\r
1659         // SVNSLC_COLDATE\r
1660         TCHAR datebuf[SVN_DATE_BUFFER];\r
1661         apr_time_t date = entry->last_commit_date;\r
1662         SVN::formatDate(datebuf, date, true);\r
1663         if (date)\r
1664                 SetItemText(index, nCol++, datebuf);\r
1665         else\r
1666                 SetItemText(index, nCol++, _T(""));\r
1667         // SVNSLC_COLSVNNEEDSLOCK\r
1668     BOOL bFoundSVNNeedsLock = entry->present_props.IsNeedsLockSet();\r
1669         CString strSVNNeedsLock = (bFoundSVNNeedsLock) ? _T("*") : _T("");\r
1670         SetItemText(index, nCol++, strSVNNeedsLock);\r
1671         // SVNSLC_COLCOPYFROM\r
1672         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
1673                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
1674         else\r
1675                 temp = entry->copyfrom_url;\r
1676         SetItemText(index, nCol++, temp);\r
1677         // SVNSLC_COLMODIFICATIONDATE\r
1678         __int64 filetime = entry->GetPath().GetLastWriteTime();\r
1679         if ( (filetime) && (entry->status!=git_wc_status_deleted) )\r
1680         {\r
1681                 FILETIME* f = (FILETIME*)(__int64*)&filetime;\r
1682                 TCHAR datebuf[SVN_DATE_BUFFER];\r
1683                 SVN::formatDate(datebuf,*f,true);\r
1684                 SetItemText(index, nCol++, datebuf);\r
1685         }\r
1686         else\r
1687         {\r
1688                 SetItemText(index, nCol++, _T(""));\r
1689         }\r
1690 \r
1691     // user-defined properties\r
1692     for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
1693         ; i < count\r
1694         ; ++i)\r
1695     {\r
1696         assert (i == nCol++);\r
1697         assert (m_ColumnManager.IsUserProp (i));\r
1698 \r
1699         CString name = m_ColumnManager.GetName(i);\r
1700         if (entry->present_props.HasProperty (name))\r
1701                 {\r
1702                         const CString& propVal = entry->present_props [name];\r
1703                         if (propVal.IsEmpty())\r
1704                                 SetItemText(index, i, m_sNoPropValueText);\r
1705                         else\r
1706                                 SetItemText(index, i, propVal);\r
1707                 }\r
1708                 else\r
1709             SetItemText(index, i, _T(""));\r
1710     }\r
1711 \r
1712         SetCheck(index, entry->checked);\r
1713         if (entry->checked)\r
1714                 m_nSelected++;\r
1715         if (m_changelists.find(entry->changelist) != m_changelists.end())\r
1716                 SetItemGroup(index, m_changelists[entry->changelist]);\r
1717         else\r
1718                 SetItemGroup(index, 0);\r
1719         m_bBlock = FALSE;\r
1720 #endif\r
1721 }\r
1722 #endif\r
1723 bool CGitStatusListCtrl::SetItemGroup(int item, int groupindex)\r
1724 {\r
1725         if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS) == NULL)\r
1726                 return false;\r
1727         if (groupindex < 0)\r
1728                 return false;\r
1729         LVITEM i = {0};\r
1730         i.mask = LVIF_GROUPID;\r
1731         i.iItem = item;\r
1732         i.iSubItem = 0;\r
1733         i.iGroupId = groupindex;\r
1734 \r
1735         return !!SetItem(&i);\r
1736 }\r
1737 \r
1738 void CGitStatusListCtrl::Sort()\r
1739 {\r
1740         Locker lock(m_critSec);\r
1741 \r
1742     CSorter predicate (&m_ColumnManager, m_nSortedColumn, m_bAscending);\r
1743 \r
1744         std::sort(m_arStatusArray.begin(), m_arStatusArray.end(), predicate);\r
1745         SaveColumnWidths();\r
1746         Show(m_dwShow, 0, m_bShowFolders);\r
1747 \r
1748 }\r
1749 \r
1750 void CGitStatusListCtrl::OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult)\r
1751 {\r
1752         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1753         *pResult = 0;\r
1754         if (m_bBlock)\r
1755                 return;\r
1756         m_bBlock = TRUE;\r
1757         if (m_nSortedColumn == phdr->iItem)\r
1758                 m_bAscending = !m_bAscending;\r
1759         else\r
1760                 m_bAscending = TRUE;\r
1761         m_nSortedColumn = phdr->iItem;\r
1762         m_mapFilenameToChecked.clear();\r
1763         Sort();\r
1764 \r
1765         CHeaderCtrl * pHeader = GetHeaderCtrl();\r
1766         HDITEM HeaderItem = {0};\r
1767         HeaderItem.mask = HDI_FORMAT;\r
1768         for (int i=0; i<pHeader->GetItemCount(); ++i)\r
1769         {\r
1770                 pHeader->GetItem(i, &HeaderItem);\r
1771                 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
1772                 pHeader->SetItem(i, &HeaderItem);\r
1773         }\r
1774         pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
1775         HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
1776         pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
1777 \r
1778         // the checked state of the list control items must be restored\r
1779 \r
1780         for (int i=0; i<GetItemCount(); ++i)\r
1781         {\r
1782                 CTGitPath * entry = (CTGitPath*)GetItemData(i);\r
1783                 SetCheck(i, entry->m_Checked);\r
1784         }\r
1785 \r
1786         m_bBlock = FALSE;\r
1787 }\r
1788 \r
1789 void CGitStatusListCtrl::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
1790 {\r
1791         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1792         *pResult = 0;\r
1793 \r
1794 #define ISCHECKED(x) ((x) ? ((((x)&LVIS_STATEIMAGEMASK)>>12)-1) : FALSE)\r
1795         if ((m_bBlock)&&(m_bBlockUI))\r
1796         {\r
1797                 // if we're blocked, prevent changing of the check state\r
1798                 if ((!ISCHECKED(pNMLV->uOldState) && ISCHECKED(pNMLV->uNewState))||\r
1799                         (ISCHECKED(pNMLV->uOldState) && !ISCHECKED(pNMLV->uNewState)))\r
1800                         *pResult = TRUE;\r
1801         }\r
1802 }\r
1803 \r
1804 BOOL CGitStatusListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)\r
1805 {\r
1806         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1807         *pResult = 0;\r
1808         if ((pNMLV->uNewState==0)||(pNMLV->uNewState & LVIS_SELECTED)||(pNMLV->uNewState & LVIS_FOCUSED))\r
1809                 return FALSE;\r
1810 \r
1811         if (m_bBlock)\r
1812                 return FALSE;\r
1813 \r
1814         bool bSelected = !!(ListView_GetItemState(m_hWnd, pNMLV->iItem, LVIS_SELECTED) & LVIS_SELECTED);\r
1815         int nListItems = GetItemCount();\r
1816 \r
1817         m_bBlock = TRUE;\r
1818         // was the item checked?\r
1819         \r
1820         //CTGitPath *gitpath=(CTGitPath*)GetItemData(pNMLV->iItem);\r
1821         //gitpath->m_Checked=GetCheck(pNMLV->iItem);\r
1822 \r
1823         if (GetCheck(pNMLV->iItem))\r
1824         {\r
1825                 CheckEntry(pNMLV->iItem, nListItems);\r
1826                 if (bSelected)\r
1827                 {\r
1828                         POSITION pos = GetFirstSelectedItemPosition();\r
1829                         int index;\r
1830                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1831                         {\r
1832                                 if (index != pNMLV->iItem)\r
1833                                         CheckEntry(index, nListItems);\r
1834                         }\r
1835                 }\r
1836         }\r
1837         else\r
1838         {\r
1839                 UncheckEntry(pNMLV->iItem, nListItems);\r
1840                 if (bSelected)\r
1841                 {\r
1842                         POSITION pos = GetFirstSelectedItemPosition();\r
1843                         int index;\r
1844                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
1845                         {\r
1846                                 if (index != pNMLV->iItem)\r
1847                                         UncheckEntry(index, nListItems);\r
1848                         }\r
1849                 }\r
1850         }\r
1851 \r
1852         GetStatisticsString();\r
1853         m_bBlock = FALSE;\r
1854         NotifyCheck();\r
1855 \r
1856         return FALSE;\r
1857 }\r
1858 \r
1859 void CGitStatusListCtrl::OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult)\r
1860 {\r
1861         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1862     if (   (header != NULL) \r
1863         && (header->iItem >= 0) \r
1864         && (header->iItem < m_ColumnManager.GetColumnCount()))\r
1865     {\r
1866         m_ColumnManager.ColumnResized (header->iItem);\r
1867     }\r
1868 \r
1869     *pResult = FALSE;\r
1870 }\r
1871 \r
1872 void CGitStatusListCtrl::OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult)\r
1873 {\r
1874         LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1875         *pResult = TRUE;\r
1876     if (   (header != NULL) \r
1877         && (header->iItem >= 0) \r
1878         && (header->iItem < m_ColumnManager.GetColumnCount())\r
1879                 // only allow the reordering if the column was not moved left of the first\r
1880                 // visible item - otherwise the 'invisible' columns are not at the far left\r
1881                 // anymore and we get all kinds of redrawing problems.\r
1882                 && (header->pitem)\r
1883                 && (header->pitem->iOrder > m_ColumnManager.GetInvisibleCount()))\r
1884     {\r
1885         m_ColumnManager.ColumnMoved (header->iItem, header->pitem->iOrder);\r
1886                 *pResult = FALSE;\r
1887     }\r
1888 \r
1889     Invalidate(FALSE);\r
1890 }\r
1891 \r
1892 void CGitStatusListCtrl::CheckEntry(int index, int nListItems)\r
1893 {\r
1894         Locker lock(m_critSec);\r
1895         //FileEntry * entry = GetListEntry(index);\r
1896         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
1897         ASSERT(path != NULL);\r
1898         if (path == NULL)\r
1899                 return;\r
1900         SetCheck(index, TRUE);\r
1901         //entry = GetListEntry(index);\r
1902         // if an unversioned item was checked, then we need to check if\r
1903         // the parent folders are unversioned too. If the parent folders actually\r
1904         // are unversioned, then check those too.\r
1905 #if 0\r
1906         if (entry->status == git_wc_status_unversioned)\r
1907         {\r
1908                 // we need to check the parent folder too\r
1909                 const CTGitPath& folderpath = entry->path;\r
1910                 for (int i=0; i< nListItems; ++i)\r
1911                 {\r
1912                         FileEntry * testEntry = GetListEntry(i);\r
1913                         ASSERT(testEntry != NULL);\r
1914                         if (testEntry == NULL)\r
1915                                 continue;\r
1916                         if (!testEntry->checked)\r
1917                         {\r
1918                                 if (testEntry->path.IsAncestorOf(folderpath) && (!testEntry->path.IsEquivalentTo(folderpath)))\r
1919                                 {\r
1920                                         SetEntryCheck(testEntry,i,true);\r
1921                                         m_nSelected++;\r
1922                                 }\r
1923                         }\r
1924                 }\r
1925         }\r
1926         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
1927         if ( (entry->status == git_wc_status_deleted) || (m_bCheckChildrenWithParent) || (bShift) )\r
1928         {\r
1929                 // if a deleted folder gets checked, we have to check all\r
1930                 // children of that folder too.\r
1931                 if (entry->path.IsDirectory())\r
1932                 {\r
1933                         SetCheckOnAllDescendentsOf(entry, true);\r
1934                 }\r
1935 \r
1936                 // if a deleted file or folder gets checked, we have to\r
1937                 // check all parents of this item too.\r
1938                 for (int i=0; i<nListItems; ++i)\r
1939                 {\r
1940                         FileEntry * testEntry = GetListEntry(i);\r
1941                         ASSERT(testEntry != NULL);\r
1942                         if (testEntry == NULL)\r
1943                                 continue;\r
1944                         if (!testEntry->checked)\r
1945                         {\r
1946                                 if (testEntry->path.IsAncestorOf(entry->path) && (!testEntry->path.IsEquivalentTo(entry->path)))\r
1947                                 {\r
1948                                         if ((testEntry->status == git_wc_status_deleted)||(m_bCheckChildrenWithParent))\r
1949                                         {\r
1950                                                 SetEntryCheck(testEntry,i,true);\r
1951                                                 m_nSelected++;\r
1952                                                 // now we need to check all children of this parent folder\r
1953                                                 SetCheckOnAllDescendentsOf(testEntry, true);\r
1954                                         }\r
1955                                 }\r
1956                         }\r
1957                 }\r
1958         }\r
1959 #endif\r
1960         if ( !path->m_Checked )\r
1961         {\r
1962                 path->m_Checked = TRUE;\r
1963                 m_nSelected++;\r
1964         }\r
1965 }\r
1966 \r
1967 void CGitStatusListCtrl::UncheckEntry(int index, int nListItems)\r
1968 {\r
1969         Locker lock(m_critSec);\r
1970         CTGitPath *path=(CTGitPath*)GetItemData(index);\r
1971         ASSERT(path != NULL);\r
1972         if (path == NULL)\r
1973                 return;\r
1974         SetCheck(index, FALSE);\r
1975         //entry = GetListEntry(index);\r
1976         // item was unchecked\r
1977 #if 0\r
1978         if (entry->path.IsDirectory())\r
1979         {\r
1980                 // disable all files within an unselected folder, except when unchecking a folder with property changes\r
1981                 bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
1982                 if ( (entry->status != git_wc_status_modified) || (bShift) )\r
1983                 {\r
1984                         SetCheckOnAllDescendentsOf(entry, false);\r
1985                 }\r
1986         }\r
1987         else if (entry->status == git_wc_status_deleted)\r
1988         {\r
1989                 // a "deleted" file was unchecked, so uncheck all parent folders\r
1990                 // and all children of those parents\r
1991                 for (int i=0; i<nListItems; i++)\r
1992                 {\r
1993                         FileEntry * testEntry = GetListEntry(i);\r
1994                         ASSERT(testEntry != NULL);\r
1995                         if (testEntry == NULL)\r
1996                                 continue;\r
1997                         if (testEntry->checked)\r
1998                         {\r
1999                                 if (testEntry->path.IsAncestorOf(entry->path))\r
2000                                 {\r
2001                                         if (testEntry->status == git_wc_status_deleted)\r
2002                                         {\r
2003                                                 SetEntryCheck(testEntry,i,false);\r
2004                                                 m_nSelected--;\r
2005 \r
2006                                                 SetCheckOnAllDescendentsOf(testEntry, false);\r
2007                                         }\r
2008                                 }\r
2009                         }\r
2010                 }\r
2011         }\r
2012 #endif\r
2013         if ( path->m_Checked )\r
2014         {\r
2015                 path->m_Checked  = FALSE;\r
2016                 m_nSelected--;\r
2017         }\r
2018 }\r
2019 #if 0\r
2020 bool CGitStatusListCtrl::EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2)\r
2021 {\r
2022         return pEntry1->path < pEntry2->path;\r
2023 }\r
2024 \r
2025 bool CGitStatusListCtrl::IsEntryVersioned(const FileEntry* pEntry1)\r
2026 {\r
2027         return pEntry1->status != git_wc_status_unversioned;\r
2028 }\r
2029 #endif\r
2030 bool CGitStatusListCtrl::BuildStatistics()\r
2031 {\r
2032 #if 0\r
2033         bool bRefetchStatus = false;\r
2034         FileEntryVector::iterator itFirstUnversionedEntry;\r
2035         itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
2036         if (m_bUnversionedLast)\r
2037         {\r
2038                 // We partition the list of items so that it's arrange with all the versioned items first\r
2039                 // then all the unversioned items afterwards.\r
2040                 // Then we sort the versioned part of this, so that we can do quick look-ups in it\r
2041                 std::sort(m_arStatusArray.begin(), itFirstUnversionedEntry, EntryPathCompareNoCase);\r
2042                 // Also sort the unversioned section, to make the list look nice...\r
2043                 std::sort(itFirstUnversionedEntry, m_arStatusArray.end(), EntryPathCompareNoCase);\r
2044         }\r
2045 \r
2046         // now gather some statistics\r
2047         m_nUnversioned = 0;\r
2048         m_nNormal = 0;\r
2049         m_nModified = 0;\r
2050         m_nAdded = 0;\r
2051         m_nDeleted = 0;\r
2052         m_nConflicted = 0;\r
2053         m_nTotal = 0;\r
2054         m_nSelected = 0;\r
2055         for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2056         {\r
2057                 const FileEntry * entry = m_arStatusArray[i];\r
2058                 if (entry)\r
2059                 {\r
2060                         switch (entry->status)\r
2061                         {\r
2062                         case git_wc_status_normal:\r
2063                                 m_nNormal++;\r
2064                                 break;\r
2065                         case git_wc_status_added:\r
2066                                 m_nAdded++;\r
2067                                 break;\r
2068                         case git_wc_status_missing:\r
2069                         case git_wc_status_deleted:\r
2070                                 m_nDeleted++;\r
2071                                 break;\r
2072                         case git_wc_status_replaced:\r
2073                         case git_wc_status_modified:\r
2074                         case git_wc_status_merged:\r
2075                                 m_nModified++;\r
2076                                 break;\r
2077                         case git_wc_status_conflicted:\r
2078                         case git_wc_status_obstructed:\r
2079                                 m_nConflicted++;\r
2080                                 break;\r
2081                         case git_wc_status_ignored:\r
2082                                 m_nUnversioned++;\r
2083                                 break;\r
2084                         default:\r
2085 #if 0\r
2086                                 {\r
2087                                         if (GitStatus::IsImportant(entry->remotestatus))\r
2088                                                 break;\r
2089                                         m_nUnversioned++;\r
2090                                         // If an entry is in an unversioned folder, we don't have to do an expensive array search\r
2091                                         // to find out if it got case-renamed: an unversioned folder can't have versioned files\r
2092                                         // But nested folders are also considered to be in unversioned folders, we have to do the\r
2093                                         // check in that case too, otherwise we would miss case-renamed folders - they show up\r
2094                                         // as nested folders.\r
2095                                         if (((!entry->inunversionedfolder)||(entry->isNested))&&(m_bUnversionedLast))\r
2096                                         {\r
2097                                                 // check if the unversioned item is just\r
2098                                                 // a file differing in case but still versioned\r
2099                                                 FileEntryVector::iterator itMatchingItem;\r
2100                                                 if(std::binary_search(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase))\r
2101                                                 {\r
2102                                                         // We've confirmed that there *is* a matching file\r
2103                                                         // Find its exact location\r
2104                                                         FileEntryVector::iterator itMatchingItem;\r
2105                                                         itMatchingItem = std::lower_bound(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase);\r
2106 \r
2107                                                         // adjust the case of the filename\r
2108                                                         if (MoveFileEx(entry->path.GetWinPath(), (*itMatchingItem)->path.GetWinPath(), MOVEFILE_REPLACE_EXISTING))\r
2109                                                         {\r
2110                                                                 // We successfully adjusted the case in the filename. But there is now a file with status 'missing'\r
2111                                                                 // in the array, because that's the status of the file before we adjusted the case.\r
2112                                                                 // We have to refetch the status of that file.\r
2113                                                                 // Since fetching the status of single files/directories is very expensive and there can be\r
2114                                                                 // multiple case-renames here, we just set a flag and refetch the status at the end from scratch.\r
2115                                                                 bRefetchStatus = true;\r
2116                                                                 DeleteItem(i);\r
2117                                                                 m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
2118                                                                 delete entry;\r
2119                                                                 i--;\r
2120                                                                 m_nUnversioned--;\r
2121                                                                 // now that we removed an unversioned item from the array, find the first unversioned item in the 'new'\r
2122                                                                 // list again.\r
2123                                                                 itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
2124                                                         }\r
2125                                                         break;\r
2126                                                 }\r
2127                                         }\r
2128                                 }\r
2129 #endif\r
2130                                 break;\r
2131                         } // switch (entry->status)\r
2132                 } // if (entry)\r
2133         } // for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2134         return !bRefetchStatus;\r
2135 #endif \r
2136         return FALSE;\r
2137 }\r
2138 \r
2139 void CGitStatusListCtrl::GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly)\r
2140 {\r
2141 #if 0\r
2142         Locker lock(m_critSec);\r
2143         rMin = LONG_MAX;\r
2144         rMax = 0;\r
2145 \r
2146         if ((bShownOnly)||(bCheckedOnly))\r
2147         {\r
2148                 for (int i=0; i<GetItemCount(); ++i)\r
2149                 {\r
2150                         const FileEntry * entry = GetListEntry(i);\r
2151 \r
2152                         if ((entry)&&(entry->last_commit_rev))\r
2153                         {\r
2154                                 if ((!bCheckedOnly)||(entry->IsChecked()))\r
2155                                 {\r
2156                                         if (entry->last_commit_rev >= 0)\r
2157                                         {\r
2158                                                 rMin = min(rMin, entry->last_commit_rev);\r
2159                                                 rMax = max(rMax, entry->last_commit_rev);\r
2160                                         }\r
2161                                 }\r
2162                         }\r
2163                 }\r
2164         }\r
2165         else\r
2166         {\r
2167                 for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
2168                 {\r
2169                         const FileEntry * entry = m_arStatusArray[i];\r
2170                         if ((entry)&&(entry->last_commit_rev))\r
2171                         {\r
2172                                 if (entry->last_commit_rev >= 0)\r
2173                                 {\r
2174                                         rMin = min(rMin, entry->last_commit_rev);\r
2175                                         rMax = max(rMax, entry->last_commit_rev);\r
2176                                 }\r
2177                         }\r
2178                 }\r
2179         }\r
2180         if (rMin == LONG_MAX)\r
2181                 rMin = 0;\r
2182 #endif\r
2183 }\r
2184 \r
2185 int CGitStatusListCtrl::GetGroupFromPoint(POINT * ppt)\r
2186 {\r
2187         // the point must be relative to the upper left corner of the control\r
2188 \r
2189         if (ppt == NULL)\r
2190                 return -1;\r
2191         if (!IsGroupViewEnabled())\r
2192                 return -1;\r
2193 \r
2194         POINT pt = *ppt;\r
2195         pt.x = 10;\r
2196         UINT flags = 0;\r
2197         int nItem = -1;\r
2198         RECT rc;\r
2199         GetWindowRect(&rc);\r
2200         while (((flags & LVHT_BELOW) == 0)&&(pt.y < rc.bottom))\r
2201         {\r
2202                 nItem = HitTest(pt, &flags);\r
2203                 if ((flags & LVHT_ONITEM)||(flags & LVHT_EX_GROUP_HEADER))\r
2204                 {\r
2205                         // the first item below the point\r
2206 \r
2207                         // check if the point is too much right (i.e. if the point\r
2208                         // is farther to the right than the width of the item)\r
2209                         RECT r;\r
2210                         GetItemRect(nItem, &r, LVIR_LABEL);\r
2211                         if (ppt->x > r.right)\r
2212                                 return -1;\r
2213 \r
2214                         LVITEM lv = {0};\r
2215                         lv.mask = LVIF_GROUPID;\r
2216                         lv.iItem = nItem;\r
2217                         GetItem(&lv);\r
2218                         int groupID = lv.iGroupId;\r
2219                         // now we search upwards and check if the item above this one\r
2220                         // belongs to another group. If it belongs to the same group,\r
2221                         // we're not over a group header\r
2222                         while (pt.y >= 0)\r
2223                         {\r
2224                                 pt.y -= 2;\r
2225                                 nItem = HitTest(pt, &flags);\r
2226                                 if ((flags & LVHT_ONITEM)&&(nItem >= 0))\r
2227                                 {\r
2228                                         // the first item below the point\r
2229                                         LVITEM lv = {0};\r
2230                                         lv.mask = LVIF_GROUPID;\r
2231                                         lv.iItem = nItem;\r
2232                                         GetItem(&lv);\r
2233                                         if (lv.iGroupId != groupID)\r
2234                                                 return groupID;\r
2235                                         else\r
2236                                                 return -1;\r
2237                                 }\r
2238                         }\r
2239                         if (pt.y < 0)\r
2240                                 return groupID;\r
2241                         return -1;\r
2242                 }\r
2243                 pt.y += 2;\r
2244         };\r
2245         return -1;\r
2246 }\r
2247 \r
2248 void CGitStatusListCtrl::OnContextMenuGroup(CWnd * /*pWnd*/, CPoint point)\r
2249 {\r
2250         POINT clientpoint = point;\r
2251         ScreenToClient(&clientpoint);\r
2252         if ((IsGroupViewEnabled())&&(GetGroupFromPoint(&clientpoint) >= 0))\r
2253         {\r
2254                 CMenu popup;\r
2255                 if (popup.CreatePopupMenu())\r
2256                 {\r
2257                         CString temp;\r
2258                         temp.LoadString(IDS_STATUSLIST_CHECKGROUP);\r
2259                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CHECKGROUP, temp);\r
2260                         temp.LoadString(IDS_STATUSLIST_UNCHECKGROUP);\r
2261                         popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_UNCHECKGROUP, temp);\r
2262                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2263                         bool bCheck = false;\r
2264                         switch (cmd)\r
2265                         {\r
2266                         case IDSVNLC_CHECKGROUP:\r
2267                                 bCheck = true;\r
2268                                 // fall through here\r
2269                         case IDSVNLC_UNCHECKGROUP:\r
2270                                 {\r
2271                                         int group = GetGroupFromPoint(&clientpoint);\r
2272                                         // go through all items and check/uncheck those assigned to the group\r
2273                                         // but block the OnLvnItemChanged handler\r
2274                                         m_bBlock = true;\r
2275                                         LVITEM lv;\r
2276                                         for (int i=0; i<GetItemCount(); ++i)\r
2277                                         {\r
2278                                                 SecureZeroMemory(&lv, sizeof(LVITEM));\r
2279                                                 lv.mask = LVIF_GROUPID;\r
2280                                                 lv.iItem = i;\r
2281                                                 GetItem(&lv);\r
2282 #if 0\r
2283                                                 if (lv.iGroupId == group)\r
2284                                                 {\r
2285                                                         FileEntry * entry = GetListEntry(i);\r
2286                                                         if (entry)\r
2287                                                         {\r
2288                                                                 bool bOldCheck = !!GetCheck(i);\r
2289                                                                 //SetEntryCheck(entry, i, bCheck);\r
2290                                                                 if (bCheck != bOldCheck)\r
2291                                                                 {\r
2292                                                                         if (bCheck)\r
2293                                                                                 m_nSelected++;\r
2294                                                                         else\r
2295                                                                                 m_nSelected--;\r
2296                                                                 }\r
2297                                                         }\r
2298                                                 }\r
2299 #endif\r
2300                                         }\r
2301                                         GetStatisticsString();\r
2302                                         NotifyCheck();\r
2303                                         m_bBlock = false;\r
2304                                 }\r
2305                                 break;\r
2306                         }\r
2307                 }\r
2308         }\r
2309 }\r
2310 \r
2311 void CGitStatusListCtrl::OnContextMenuList(CWnd * pWnd, CPoint point)\r
2312 {\r
2313 \r
2314         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
2315 \r
2316         bool XPorLater = false;\r
2317         OSVERSIONINFOEX inf;\r
2318         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
2319         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
2320         GetVersionEx((OSVERSIONINFO *)&inf);\r
2321         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
2322         if (fullver >= 0x0501)\r
2323                 XPorLater = true;\r
2324         bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
2325         CTGitPath * filepath;\r
2326 \r
2327         int selIndex = GetSelectionMark();\r
2328         if ((point.x == -1) && (point.y == -1))\r
2329         {\r
2330                 CRect rect;\r
2331                 GetItemRect(selIndex, &rect, LVIR_LABEL);\r
2332                 ClientToScreen(&rect);\r
2333                 point = rect.CenterPoint();\r
2334         }\r
2335         if ((GetSelectedCount() == 0)&&(XPorLater)&&(m_bHasCheckboxes))\r
2336         {\r
2337                 // nothing selected could mean the context menu is requested for\r
2338                 // a group header\r
2339                 OnContextMenuGroup(pWnd, point);\r
2340         }\r
2341         else if (selIndex >= 0)\r
2342         {\r
2343                 //FileEntry * entry = GetListEntry(selIndex);\r
2344 \r
2345                 filepath = (CTGitPath * )GetItemData(selIndex);\r
2346 \r
2347                 ASSERT(filepath != NULL);\r
2348                 if (filepath == NULL)\r
2349                         return;\r
2350 \r
2351                 //const CTGitPath& filepath = entry->path;\r
2352                 int wcStatus = filepath->m_Action;\r
2353                 // entry is selected, now show the popup menu\r
2354                 Locker lock(m_critSec);\r
2355                 CIconMenu popup;\r
2356                 CMenu changelistSubMenu;\r
2357                 CMenu ignoreSubMenu;\r
2358                 if (popup.CreatePopupMenu())\r
2359                 {\r
2360                         //Add Menu for verion controled file\r
2361                         if (!(wcStatus &CTGitPath::LOGACTIONS_UNVER))\r
2362                         {\r
2363                                 if (m_dwContextMenus & SVNSLC_POPCOMPAREWITHBASE)\r
2364                                 {\r
2365                                         popup.AppendMenuIcon(IDSVNLC_COMPARE, IDS_LOG_COMPAREWITHBASE, IDI_DIFF);\r
2366                                         popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2367                                 }\r
2368                                 //Select one items\r
2369                                 if (GetSelectedCount() == 1)\r
2370                                 {\r
2371                                         bool bEntryAdded = false;\r
2372                                         //if (entry->remotestatus <= git_wc_status_normal)\r
2373                                         //{\r
2374                                         //      if (wcStatus > git_wc_status_normal)\r
2375                                         //      {\r
2376                                         //              if ((m_dwContextMenus & SVNSLC_POPGNUDIFF)&&(wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing))\r
2377                                         //              {\r
2378                                         if(!g_Git.IsInitRepos())\r
2379                                                 popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2380 \r
2381                                         bEntryAdded = true;\r
2382                                         //              }\r
2383                                         //      }\r
2384                                         //\r
2385                                         //}\r
2386                                         //else if (wcStatus != git_wc_status_deleted)\r
2387                                         //{\r
2388                                         //      if (m_dwContextMenus & SVNSLC_POPCOMPARE)\r
2389                                         //      {\r
2390                                         //              popup.AppendMenuIcon(IDSVNLC_COMPAREWC, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
2391                                         //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2392                                         //              bEntryAdded = true;\r
2393                                         //      }\r
2394                                         //      if (m_dwContextMenus & SVNSLC_POPGNUDIFF)\r
2395                                         //      {\r
2396                                         //              popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
2397                                         //              bEntryAdded = true;\r
2398                                         //      }\r
2399                                         //}\r
2400                                         if (bEntryAdded)\r
2401                                                 popup.AppendMenu(MF_SEPARATOR);\r
2402                                 }\r
2403                                 //else if (GetSelectedCount() > 1)  \r
2404                                 //{\r
2405                                 //      if (m_dwContextMenus & SVNSLC_POPCOMMIT)\r
2406                                 //      {\r
2407                                 //              popup.AppendMenuIcon(IDSVNLC_COMMIT, IDS_STATUSLIST_CONTEXT_COMMIT, IDI_COMMIT);\r
2408                                 //              popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
2409                                 //      }\r
2410                                 //}\r
2411                         }\r
2412                         \r
2413                         ///Select Multi item\r
2414                         //if (GetSelectedCount() > 0)\r
2415                         //{\r
2416                         //      if ((GetSelectedCount() == 2)&&(m_dwContextMenus & SVNSLC_POPREPAIRMOVE))\r
2417                         //      {\r
2418                         //              POSITION pos = GetFirstSelectedItemPosition();\r
2419                         //              int index = GetNextSelectedItem(pos);\r
2420                         //              if (index >= 0)\r
2421                         //              {\r
2422                         //                      FileEntry * entry = GetListEntry(index);\r
2423                         //                      git_wc_status_kind status1 = git_wc_status_none;\r
2424                         //                      git_wc_status_kind status2 = git_wc_status_none;\r
2425                         //                      if (entry)\r
2426                         //                              status1 = entry->status;\r
2427                         //                      index = GetNextSelectedItem(pos);\r
2428                         //                      if (index >= 0)\r
2429                         //                      {\r
2430                         //                              entry = GetListEntry(index);\r
2431                         //                              if (entry)\r
2432                         //                                      status2 = entry->status;\r
2433                         //                              if ((status1 == git_wc_status_missing && status2 == git_wc_status_unversioned) ||\r
2434                         //                                      (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned))\r
2435                         //                              {\r
2436                         //                                      popup.AppendMenuIcon(IDSVNLC_REPAIRMOVE, IDS_STATUSLIST_CONTEXT_REPAIRMOVE);\r
2437                         //                              }\r
2438                         //                      }\r
2439                         //              }\r
2440                         //      }\r
2441                         //      if (wcStatus > git_wc_status_normal)\r
2442                         //      {\r
2443                         //              if (m_dwContextMenus & SVNSLC_POPREVERT)\r
2444                         //              {\r
2445                         //                      // reverting missing folders is not possible\r
2446                         //                      if (!entry->IsFolder() || (wcStatus != git_wc_status_missing))\r
2447                         //                      {\r
2448                         //                              popup.AppendMenuIcon(IDSVNLC_REVERT, IDS_MENUREVERT, IDI_REVERT);\r
2449                         //                      }\r
2450                         //              }\r
2451                         //      }\r
2452                         //      if (entry->remotestatus > git_wc_status_normal)\r
2453                         //      {\r
2454                         //              if (m_dwContextMenus & SVNSLC_POPUPDATE)\r
2455                         //              {\r
2456                         //                      popup.AppendMenuIcon(IDSVNLC_UPDATE, IDS_MENUUPDATE, IDI_UPDATE);\r
2457                         //              }\r
2458                         //      }\r
2459                         //}\r
2460                         if ((GetSelectedCount() == 1)&&(!wcStatus & CTGitPath::LOGACTIONS_UNVER)\r
2461                                 &&(!wcStatus & CTGitPath::LOGACTIONS_IGNORE))\r
2462                         {\r
2463                                 if (m_dwContextMenus & SVNSLC_POPSHOWLOG)\r
2464                                 {\r
2465                                         popup.AppendMenuIcon(IDSVNLC_LOG, IDS_REPOBROWSE_SHOWLOG, IDI_LOG);\r
2466                                 }\r
2467 //                              if (m_dwContextMenus & SVNSLC_POPBLAME)\r
2468 //                              {\r
2469 //                                      popup.AppendMenuIcon(IDSVNLC_BLAME, IDS_MENUBLAME, IDI_BLAME);\r
2470 //                              }\r
2471                         }\r
2472 //                      if ((wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing) && (GetSelectedCount() == 1))\r
2473 //                      {\r
2474                                 if (m_dwContextMenus & SVNSLC_POPOPEN)\r
2475                                 {\r
2476                                         popup.AppendMenuIcon(IDSVNLC_OPEN, IDS_REPOBROWSE_OPEN, IDI_OPEN);\r
2477                                         popup.AppendMenuIcon(IDSVNLC_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
2478                                 }\r
2479                                 if (m_dwContextMenus & SVNSLC_POPEXPLORE)\r
2480                                 {\r
2481                                         popup.AppendMenuIcon(IDSVNLC_EXPLORE, IDS_STATUSLIST_CONTEXT_EXPLORE, IDI_EXPLORER);\r
2482                                 }\r
2483 //                      }\r
2484                         if (GetSelectedCount() > 0)\r
2485                         {\r
2486 //                              if (((wcStatus == git_wc_status_unversioned)||(wcStatus == git_wc_status_ignored))&&(m_dwContextMenus & SVNSLC_POPDELETE))\r
2487 //                              {\r
2488 //                                      popup.AppendMenuIcon(IDSVNLC_DELETE, IDS_MENUREMOVE, IDI_DELETE);\r
2489 //                              }\r
2490 //                              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
2491 //                              {\r
2492 //                                      if (bShift)\r
2493 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVEKEEP, IDI_DELETE);\r
2494 //                                      else\r
2495 //                                              popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVE, IDI_DELETE);\r
2496 //                              }\r
2497                                 if ((wcStatus & CTGitPath::LOGACTIONS_UNVER)/*||(wcStatus == git_wc_status_deleted)*/)\r
2498                                 {\r
2499                                         if (m_dwContextMenus & SVNSLC_POPADD)\r
2500                                         {\r
2501                                                 //if ( entry->IsFolder() )\r
2502                                                 //{\r
2503                                                 //      popup.AppendMenuIcon(IDSVNLC_ADD_RECURSIVE, IDS_STATUSLIST_CONTEXT_ADD_RECURSIVE, IDI_ADD);\r
2504                                                 //}\r
2505                                                 //else\r
2506                                                 {\r
2507                                                         popup.AppendMenuIcon(IDSVNLC_ADD, IDS_STATUSLIST_CONTEXT_ADD, IDI_ADD);\r
2508                                                 }\r
2509                                         }\r
2510                                 //}\r
2511                                 //if ( (wcStatus == git_wc_status_unversioned) || (wcStatus == git_wc_status_deleted) )\r
2512                                 //{\r
2513                                         if (m_dwContextMenus & SVNSLC_POPIGNORE)\r
2514                                         {\r
2515 \r
2516                                                 CTGitPathList ignorelist;\r
2517                                                 FillListOfSelectedItemPaths(ignorelist);\r
2518                                                 //check if all selected entries have the same extension\r
2519                                                 bool bSameExt = true;\r
2520                                                 CString sExt;\r
2521                                                 for (int i=0; i<ignorelist.GetCount(); ++i)\r
2522                                                 {\r
2523                                                         if (sExt.IsEmpty() && (i==0))\r
2524                                                                 sExt = ignorelist[i].GetFileExtension();\r
2525                                                         else if (sExt.CompareNoCase(ignorelist[i].GetFileExtension())!=0)\r
2526                                                                 bSameExt = false;\r
2527                                                 }\r
2528                                                 if (bSameExt)\r
2529                                                 {\r
2530                                                         if (ignoreSubMenu.CreateMenu())\r
2531                                                         {\r
2532                                                                 CString ignorepath;\r
2533                                                                 if (ignorelist.GetCount()==1)\r
2534                                                                         ignorepath = ignorelist[0].GetFileOrDirectoryName();\r
2535                                                                 else\r
2536                                                                         ignorepath.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2537                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNORE, ignorepath);\r
2538                                                                 ignorepath = _T("*")+sExt;\r
2539                                                                 ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNOREMASK, ignorepath);\r
2540                                                                 CString temp;\r
2541                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2542                                                                 popup.InsertMenu((UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)ignoreSubMenu.m_hMenu, temp);\r
2543                                                         }\r
2544                                                 }\r
2545                                                 else\r
2546                                                 {\r
2547                                                         CString temp;\r
2548                                                         if (ignorelist.GetCount()==1)\r
2549                                                         {\r
2550                                                                 temp.LoadString(IDS_MENUIGNORE);\r
2551                                                         }\r
2552                                                         else\r
2553                                                         {\r
2554                                                                 temp.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
2555                                                         }\r
2556                                                         popup.AppendMenuIcon(IDSVNLC_IGNORE, temp, IDI_IGNORE);\r
2557                                                 }\r
2558                                         }\r
2559                                 }\r
2560                         }\r
2561 #if 0\r
2562                         if (((wcStatus == git_wc_status_conflicted)||(entry->isConflicted)))\r
2563                         {\r
2564                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)||(m_dwContextMenus & SVNSLC_POPRESOLVE))\r
2565                                         popup.AppendMenu(MF_SEPARATOR);\r
2566 \r
2567                                 if ((m_dwContextMenus & SVNSLC_POPCONFLICT)&&(entry->textstatus == git_wc_status_conflicted))\r
2568                                 {\r
2569                                         popup.AppendMenuIcon(IDSVNLC_EDITCONFLICT, IDS_MENUCONFLICT, IDI_CONFLICT);\r
2570                                 }\r
2571                                 if (m_dwContextMenus & SVNSLC_POPRESOLVE)\r
2572                                 {\r
2573                                         popup.AppendMenuIcon(IDSVNLC_RESOLVECONFLICT, IDS_STATUSLIST_CONTEXT_RESOLVED, IDI_RESOLVE);\r
2574                                 }\r
2575                                 if ((m_dwContextMenus & SVNSLC_POPRESOLVE)&&(entry->textstatus == git_wc_status_conflicted))\r
2576                                 {\r
2577                                         popup.AppendMenuIcon(IDSVNLC_RESOLVETHEIRS, IDS_SVNPROGRESS_MENUUSETHEIRS, IDI_RESOLVE);\r
2578                                         popup.AppendMenuIcon(IDSVNLC_RESOLVEMINE, IDS_SVNPROGRESS_MENUUSEMINE, IDI_RESOLVE);\r
2579                                 }\r
2580                         }\r
2581 #endif\r
2582 #if 0                   \r
2583                         if (GetSelectedCount() > 0)\r
2584                         {\r
2585 \r
2586                                 if ((!entry->IsFolder())&&(wcStatus >= git_wc_status_normal)\r
2587                                         &&(wcStatus!=git_wc_status_missing)&&(wcStatus!=git_wc_status_deleted)\r
2588                                         &&(wcStatus!=git_wc_status_added))\r
2589                                 {\r
2590                                         popup.AppendMenu(MF_SEPARATOR);\r
2591                                         if ((entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2592                                         {\r
2593                                                 if (m_dwContextMenus & SVNSLC_POPLOCK)\r
2594                                                 {\r
2595                                                         popup.AppendMenuIcon(IDSVNLC_LOCK, IDS_MENU_LOCK, IDI_LOCK);\r
2596                                                 }\r
2597                                         }\r
2598                                         if ((!entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
2599                                         {\r
2600                                                 if (m_dwContextMenus & SVNSLC_POPUNLOCK)\r
2601                                                 {\r
2602                                                         popup.AppendMenuIcon(IDSVNLC_UNLOCK, IDS_MENU_UNLOCK, IDI_UNLOCK);\r
2603                                                 }\r
2604                                         }\r
2605                                 }\r
2606 \r
2607                                 if ((!entry->IsFolder())&&((!entry->lock_token.IsEmpty())||(!entry->lock_remotetoken.IsEmpty())))\r
2608                                 {\r
2609                                         if (m_dwContextMenus & SVNSLC_POPUNLOCKFORCE)\r
2610                                         {\r
2611                                                 popup.AppendMenuIcon(IDSVNLC_UNLOCKFORCE, IDS_MENU_UNLOCKFORCE, IDI_UNLOCK);\r
2612                                         }\r
2613                                 }\r
2614 \r
2615                                 if (wcStatus != git_wc_status_missing && wcStatus != git_wc_status_deleted &&wcStatus!=git_wc_status_unversioned)\r
2616                                 {\r
2617                                         popup.AppendMenu(MF_SEPARATOR);\r
2618                                         popup.AppendMenuIcon(IDSVNLC_PROPERTIES, IDS_STATUSLIST_CONTEXT_PROPERTIES, IDI_PROPERTIES);\r
2619                                 }\r
2620                                 popup.AppendMenu(MF_SEPARATOR);\r
2621                                 popup.AppendMenuIcon(IDSVNLC_COPY, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);\r
2622                                 popup.AppendMenuIcon(IDSVNLC_COPYEXT, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);\r
2623                                 if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS)&&(XPorLater)\r
2624                                         &&(wcStatus != git_wc_status_unversioned)&&(wcStatus != git_wc_status_none))\r
2625                                 {\r
2626                                         popup.AppendMenu(MF_SEPARATOR);\r
2627                                         // changelist commands\r
2628                                         size_t numChangelists = GetNumberOfChangelistsInSelection();\r
2629                                         if (numChangelists > 0)\r
2630                                         {\r
2631                                                 popup.AppendMenuIcon(IDSVNLC_REMOVEFROMCS, IDS_STATUSLIST_CONTEXT_REMOVEFROMCS);\r
2632                                         }\r
2633                                         if ((!entry->IsFolder())&&(changelistSubMenu.CreateMenu()))\r
2634                                         {\r
2635                                                 CString temp;\r
2636                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_CREATECS);\r
2637                                                 changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATECS, temp);\r
2638 \r
2639                                                 if (entry->changelist.Compare(SVNSLC_IGNORECHANGELIST))\r
2640                                                 {\r
2641                                                         changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2642                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATEIGNORECS, SVNSLC_IGNORECHANGELIST);\r
2643                                                 }\r
2644 \r
2645                                                 if (m_changelists.size() > 0)\r
2646                                                 {\r
2647                                                         // find the changelist names\r
2648                                                         bool bNeedSeparator = true;\r
2649                                                         int cmdID = IDSVNLC_MOVETOCS;\r
2650                                                         for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
2651                                                         {\r
2652                                                                 if ((entry->changelist.Compare(it->first))&&(it->first.Compare(SVNSLC_IGNORECHANGELIST)))\r
2653                                                                 {\r
2654                                                                         if (bNeedSeparator)\r
2655                                                                         {\r
2656                                                                                 changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
2657                                                                                 bNeedSeparator = false;\r
2658                                                                         }\r
2659                                                                         changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, cmdID, it->first);\r
2660                                                                         cmdID++;\r
2661                                                                 }\r
2662                                                         }\r
2663                                                 }\r
2664                                                 temp.LoadString(IDS_STATUSLIST_CONTEXT_MOVETOCS);\r
2665                                                 popup.AppendMenu(MF_POPUP|MF_STRING, (UINT_PTR)changelistSubMenu.GetSafeHmenu(), temp);\r
2666                                         }\r
2667                                 }\r
2668                         }\r
2669 #endif\r
2670                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
2671 \r
2672                         m_bBlock = TRUE;\r
2673                         AfxGetApp()->DoWaitCursor(1);\r
2674                         int iItemCountBeforeMenuCmd = GetItemCount();\r
2675                         bool bForce = false;\r
2676                         switch (cmd)\r
2677                         {\r
2678                         case IDSVNLC_OPEN:\r
2679                                 {\r
2680                                         CString file;\r
2681                                         if(this->m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2682                                         {\r
2683                                                 file= filepath->GetWinPath();\r
2684                                         }else\r
2685                                         {\r
2686                                                 CString temppath;\r
2687                                                 GetTempPath(temppath);\r
2688                                                 file.Format(_T("%s%s_%s%s"),\r
2689                                                         temppath,                                               \r
2690                                                         filepath->GetBaseFilename(),\r
2691                                                         m_CurrentVersion.Left(6),\r
2692                                                         filepath->GetFileExtension());\r
2693 \r
2694                                         }\r
2695                                         int ret = (int)ShellExecute(this->m_hWnd, NULL,file, NULL, NULL, SW_SHOW);\r
2696                                         if (ret <= HINSTANCE_ERROR)\r
2697                                         {\r
2698                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
2699                                                 cmd += file;\r
2700                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
2701                                         }\r
2702                                 }\r
2703                                 break;\r
2704                         case IDSVNLC_OPENWITH:\r
2705                                 {\r
2706                                         CString file;\r
2707                                         if(m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2708                                         {\r
2709                                                 file= filepath->GetWinPath();\r
2710                                         }else\r
2711                                         {\r
2712                                                 CString temppath;\r
2713                                                 GetTempPath(temppath);\r
2714                                                 file.Format(_T("%s%s_%s%s"),\r
2715                                                         temppath,                                               \r
2716                                                         filepath->GetBaseFilename(),\r
2717                                                         m_CurrentVersion.Left(6),\r
2718                                                         filepath->GetFileExtension());\r
2719 \r
2720                                         }\r
2721 \r
2722                                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
2723                                         cmd += file + _T(" ");\r
2724                                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
2725                                 }\r
2726                                 break;\r
2727                         case IDSVNLC_EXPLORE:\r
2728                                 {\r
2729                                         ShellExecute(this->m_hWnd, _T("explore"), filepath->GetWinPath(), NULL, NULL, SW_SHOW);\r
2730                                 }\r
2731                                 break;\r
2732                         case IDSVNLC_COMPARE:\r
2733                                 {\r
2734                                         POSITION pos = GetFirstSelectedItemPosition();\r
2735                                         while ( pos )\r
2736                                         {\r
2737                                                 int index = GetNextSelectedItem(pos);\r
2738                                                 StartDiff(index);\r
2739                                         }\r
2740                                 }\r
2741                                 break;\r
2742                         case IDSVNLC_GNUDIFF1:\r
2743                                 {\r
2744                                 //      SVNDiff diff(NULL, this->m_hWnd, true);\r
2745                                 //\r
2746                                 //      if (entry->remotestatus <= git_wc_status_normal)\r
2747                                 //              CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_BASE, entry->path, SVNRev::REV_WC);\r
2748                                 //      else\r
2749                                 //              CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_WC, entry->path, SVNRev::REV_HEAD);\r
2750                                         if(m_CurrentVersion.IsEmpty() || m_CurrentVersion == GIT_REV_ZERO)\r
2751                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd,*filepath,GitRev::GetWorkingCopy(),\r
2752                                                                                                                         *filepath,GitRev::GetHead());\r
2753                                         else\r
2754                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd,*filepath,m_CurrentVersion,\r
2755                                                                                                                         *filepath,m_CurrentVersion+_T("~1"));\r
2756                                 }\r
2757                                 break;\r
2758                         case IDSVNLC_ADD:\r
2759                                 {       // The add went ok, but we now need to run through the selected items again\r
2760                                         // and update their status\r
2761                                         POSITION pos = GetFirstSelectedItemPosition();\r
2762                                         int index;\r
2763                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
2764                                         {\r
2765                                                 CTGitPath * path=(CTGitPath*)GetItemData(index);\r
2766                                                 CString cmd;\r
2767                                                 cmd.Format(_T("git.exe add %s"),path->GetGitPathString());\r
2768                                                 CString output;\r
2769                                                 if(!g_Git.Run(cmd,&output))\r
2770                                                 {\r
2771                                                         path->m_Action = CTGitPath::LOGACTIONS_ADDED;\r
2772                                                         SetEntryCheck(path,index,true);\r
2773                                                         SetItemGroup(index,0);\r
2774                                                         this->m_StatusFileList.AddPath(*path);\r
2775                                                         this->m_UnRevFileList.RemoveItem(*path);\r
2776                                                         this->m_IgnoreFileList.RemoveItem(*path);\r
2777                                                         Show(this->m_dwShow,0,true,true);\r
2778                                                 }\r
2779                                         }\r
2780                                         \r
2781                                 }\r
2782                                 break;\r
2783 #if 0\r
2784                         case IDSVNLC_COPY:\r
2785                                 CopySelectedEntriesToClipboard(0);\r
2786                                 break;\r
2787                         case IDSVNLC_COPYEXT:\r
2788                                 CopySelectedEntriesToClipboard((DWORD)-1);\r
2789                                 break;\r
2790                         case IDSVNLC_PROPERTIES:\r
2791                                 {\r
2792                                         CTSVNPathList targetList;\r
2793                                         FillListOfSelectedItemPaths(targetList);\r
2794                                         CEditPropertiesDlg dlg;\r
2795                                         dlg.SetPathList(targetList);\r
2796                                         dlg.DoModal();\r
2797                                         if (dlg.HasChanged())\r
2798                                         {\r
2799                                                 // since the user might have changed/removed/added\r
2800                                                 // properties recursively, we don't really know\r
2801                                                 // which items have changed their status.\r
2802                                                 // So tell the parent to do a refresh.\r
2803                                                 CWnd* pParent = GetParent();\r
2804                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
2805                                                 {\r
2806                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
2807                                                 }\r
2808                                         }\r
2809                                 }\r
2810                                 break;\r
2811                         case IDSVNLC_COMMIT:\r
2812                                 {\r
2813                                         CTSVNPathList targetList;\r
2814                                         FillListOfSelectedItemPaths(targetList);\r
2815                                         CTSVNPath tempFile = CTempFiles::Instance().GetTempFilePath(false);\r
2816                                         VERIFY(targetList.WriteToFile(tempFile.GetWinPathString()));\r
2817                                         CString commandline = CPathUtils::GetAppDirectory();\r
2818                                         commandline += _T("TortoiseProc.exe /command:commit /pathfile:\"");\r
2819                                         commandline += tempFile.GetWinPathString();\r
2820                                         commandline += _T("\"");\r
2821                                         commandline += _T(" /deletepathfile");\r
2822                                         CAppUtils::LaunchApplication(commandline, NULL, false);\r
2823                                 }\r
2824                                 break;\r
2825                         case IDSVNLC_REVERT:\r
2826                                 {\r
2827                                         // If at least one item is not in the status "added"\r
2828                                         // we ask for a confirmation\r
2829                                         BOOL bConfirm = FALSE;\r
2830                                         POSITION pos = GetFirstSelectedItemPosition();\r
2831                                         int index;\r
2832                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
2833                                         {\r
2834                                                 FileEntry * fentry = GetListEntry(index);\r
2835                                                 if (fentry->textstatus != git_wc_status_added)\r
2836                                                 {\r
2837                                                         bConfirm = TRUE;\r
2838                                                         break;\r
2839                                                 }\r
2840                                         }       \r
2841 \r
2842                                         CString str;\r
2843                                         str.Format(IDS_PROC_WARNREVERT,GetSelectedCount());\r
2844 \r
2845                                         if (!bConfirm || CMessageBox::Show(this->m_hWnd, str, _T("TortoiseSVN"), MB_YESNO | MB_ICONQUESTION)==IDYES)\r
2846                                         {\r
2847                                                 CTSVNPathList targetList;\r
2848                                                 FillListOfSelectedItemPaths(targetList);\r
2849 \r
2850                                                 // make sure that the list is reverse sorted, so that\r
2851                                                 // children are removed before any parents\r
2852                                                 targetList.SortByPathname(true);\r
2853 \r
2854                                                 SVN git;\r
2855 \r
2856                                                 // put all reverted files in the trashbin, except the ones with 'added'\r
2857                                                 // status because they are not restored by the revert.\r
2858                                                 CTSVNPathList delList;\r
2859                                                 POSITION pos = GetFirstSelectedItemPosition();\r
2860                                                 int index;\r
2861                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
2862                                                 {\r
2863                                                         FileEntry * entry = GetListEntry(index);\r
2864                                                         if (entry->status != git_wc_status_added)\r
2865                                                                 delList.AddPath(entry->GetPath());\r
2866                                                 }\r
2867                                                 if (DWORD(CRegDWORD(_T("Software\\TortoiseSVN\\RevertWithRecycleBin"), TRUE)))\r
2868                                                         delList.DeleteAllFiles(true);\r
2869 \r
2870                                                 if (!git.Revert(targetList, CStringArray(), FALSE))\r
2871                                                 {\r
2872                                                         CMessageBox::Show(this->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
2873                                                 }\r
2874                                                 else\r
2875                                                 {\r
2876                                                         // since the entries got reverted we need to remove\r
2877                                                         // them from the list too, if no remote changes are shown,\r
2878                                                         // if the unmodified files are not shown\r
2879                                                         // and if the item is not part of a changelist\r
2880                                                         POSITION pos;\r
2881                                                         SetRedraw(FALSE);\r
2882                                                         while ((pos = GetFirstSelectedItemPosition())!=0)\r
2883                                                         {\r
2884                                                                 int index;\r
2885                                                                 index = GetNextSelectedItem(pos);\r
2886                                                                 FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
2887                                                                 if ( fentry->IsFolder() )\r
2888                                                                 {\r
2889                                                                         // refresh!\r
2890                                                                         CWnd* pParent = GetParent();\r
2891                                                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
2892                                                                         {\r
2893                                                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
2894                                                                         }\r
2895                                                                         break;\r
2896                                                                 }\r
2897 \r
2898                                                                 BOOL bAdded = (fentry->textstatus == git_wc_status_added);\r
2899                                                                 fentry->status = git_wc_status_normal;\r
2900                                                                 fentry->propstatus = git_wc_status_normal;\r
2901                                                                 fentry->textstatus = git_wc_status_normal;\r
2902                                                                 fentry->copied = false;\r
2903                                                                 fentry->isConflicted = false;\r
2904                                                                 if ((fentry->GetChangeList().IsEmpty()&&(fentry->remotestatus <= git_wc_status_normal))||(m_dwShow & SVNSLC_SHOWNORMAL))\r
2905                                                                 {\r
2906                                                                         if ( bAdded )\r
2907                                                                         {\r
2908                                                                                 // reverting added items makes them unversioned, not 'normal'\r
2909                                                                                 if (fentry->IsFolder())\r
2910                                                                                         fentry->propstatus = git_wc_status_none;\r
2911                                                                                 else\r
2912                                                                                         fentry->propstatus = git_wc_status_unversioned;\r
2913                                                                                 fentry->status = git_wc_status_unversioned;\r
2914                                                                                 fentry->textstatus = git_wc_status_unversioned;\r
2915                                                                                 SetItemState(index, 0, LVIS_SELECTED);\r
2916                                                                                 SetEntryCheck(fentry, index, false);\r
2917                                                                         }\r
2918                                                                         else if ((fentry->switched)||(m_dwShow & SVNSLC_SHOWNORMAL))\r
2919                                                                         {\r
2920                                                                                 SetItemState(index, 0, LVIS_SELECTED);\r
2921                                                                         }\r
2922                                                                         else\r
2923                                                                         {\r
2924                                                                                 m_nTotal--;\r
2925                                                                                 if (GetCheck(index))\r
2926                                                                                         m_nSelected--;\r
2927                                                                                 RemoveListEntry(index);\r
2928                                                                                 Invalidate();\r
2929                                                                         }\r
2930                                                                 }\r
2931                                                                 else\r
2932                                                                 {\r
2933                                                                         SetItemState(index, 0, LVIS_SELECTED);\r
2934                                                                 }\r
2935                                                         }\r
2936                                                         SetRedraw(TRUE);\r
2937                                                         SaveColumnWidths();\r
2938                                                         Show(m_dwShow, 0, m_bShowFolders);\r
2939                                                         NotifyCheck();\r
2940                                                 }\r
2941                                         }\r
2942                                 }\r
2943                                 break;\r
2944                         case IDSVNLC_COMPARE:\r
2945                                 {\r
2946                                         POSITION pos = GetFirstSelectedItemPosition();\r
2947                                         while ( pos )\r
2948                                         {\r
2949                                                 int index = GetNextSelectedItem(pos);\r
2950                                                 StartDiff(index);\r
2951                                         }\r
2952                                 }\r
2953                                 break;\r
2954                         case IDSVNLC_COMPAREWC:\r
2955                                 {\r
2956                                         POSITION pos = GetFirstSelectedItemPosition();\r
2957                                         while ( pos )\r
2958                                         {\r
2959                                                 int index = GetNextSelectedItem(pos);\r
2960                                                 FileEntry * entry = GetListEntry(index);\r
2961                                                 ASSERT(entry != NULL);\r
2962                                                 if (entry == NULL)\r
2963                                                         continue;\r
2964                                                 SVNDiff diff(NULL, m_hWnd, true);\r
2965                                                 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
2966                                                 git_revnum_t baseRev = entry->Revision;\r
2967                                                 diff.DiffFileAgainstBase(\r
2968                                                         entry->path, baseRev, entry->textstatus, entry->propstatus);\r
2969                                         }\r
2970                                 }\r
2971                                 break;\r
2972                         case IDSVNLC_GNUDIFF1:\r
2973                                 {\r
2974                                         SVNDiff diff(NULL, this->m_hWnd, true);\r
2975 \r
2976                                         if (entry->remotestatus <= git_wc_status_normal)\r
2977                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_BASE, entry->path, SVNRev::REV_WC);\r
2978                                         else\r
2979                                                 CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_WC, entry->path, SVNRev::REV_HEAD);\r
2980                                 }\r
2981                                 break;\r
2982                         case IDSVNLC_UPDATE:\r
2983                                 {\r
2984                                         CTSVNPathList targetList;\r
2985                                         FillListOfSelectedItemPaths(targetList);\r
2986                                         bool bAllExist = true;\r
2987                                         for (int i=0; i<targetList.GetCount(); ++i)\r
2988                                         {\r
2989                                                 if (!targetList[i].Exists())\r
2990                                                 {\r
2991                                                         bAllExist = false;\r
2992                                                         break;\r
2993                                                 }\r
2994                                         }\r
2995                                         if (bAllExist)\r
2996                                         {\r
2997                                                 CSVNProgressDlg dlg;\r
2998                                                 dlg.SetCommand(CSVNProgressDlg::SVNProgress_Update);\r
2999                                                 dlg.SetPathList(targetList);\r
3000                                                 dlg.SetRevision(SVNRev::REV_HEAD);\r
3001                                                 dlg.DoModal();\r
3002                                         }\r
3003                                         else\r
3004                                         {\r
3005                                                 CString sTempFile = CTempFiles::Instance().GetTempFilePath(false).GetWinPathString();\r
3006                                                 targetList.WriteToFile(sTempFile, false);\r
3007                                                 CString sCmd;\r
3008                                                 sCmd.Format(_T("\"%s\" /command:update /rev /pathfile:\"%s\" /deletepathfile"),\r
3009                                                         (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), (LPCTSTR)sTempFile);\r
3010 \r
3011                                                 CAppUtils::LaunchApplication(sCmd, NULL, false);\r
3012                                         }\r
3013                                 }\r
3014                                 break;\r
3015                         case IDSVNLC_LOG:\r
3016                                 {\r
3017                                         CString sCmd;\r
3018                                         sCmd.Format(_T("\"%s\" /command:log /path:\"%s\""),\r
3019                                                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
3020 \r
3021                                         if (!filepath.IsUrl())\r
3022                                         {\r
3023                                                 sCmd += _T(" /propspath:\"");\r
3024                                                 sCmd += filepath.GetWinPathString();\r
3025                                                 sCmd += _T("\"");\r
3026                                         }       \r
3027 \r
3028                                         CAppUtils::LaunchApplication(sCmd, NULL, false);\r
3029                                 }\r
3030                                 break;\r
3031                         case IDSVNLC_BLAME:\r
3032                                 {\r
3033                                         CString sCmd;\r
3034                                         sCmd.Format(_T("\"%s\" /command:blame /path:\"%s\""),\r
3035                                                 (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
3036 \r
3037                                         if (!filepath.IsUrl())\r
3038                                         {\r
3039                                                 sCmd += _T(" /propspath:\"");\r
3040                                                 sCmd += filepath.GetWinPathString();\r
3041                                                 sCmd += _T("\"");\r
3042                                         }       \r
3043 \r
3044                                         CAppUtils::LaunchApplication(sCmd, NULL, false);\r
3045                                 }\r
3046                                 break;\r
3047                         case IDSVNLC_OPEN:\r
3048                                 {\r
3049                                         int ret = (int)ShellExecute(this->m_hWnd, NULL, filepath.GetWinPath(), NULL, NULL, SW_SHOW);\r
3050                                         if (ret <= HINSTANCE_ERROR)\r
3051                                         {\r
3052                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
3053                                                 cmd += filepath.GetWinPathString();\r
3054                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
3055                                         }\r
3056                                 }\r
3057                                 break;\r
3058                         case IDSVNLC_OPENWITH:\r
3059                                 {\r
3060                                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
3061                                         cmd += filepath.GetWinPathString() + _T(" ");\r
3062                                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
3063                                 }\r
3064                                 break;\r
3065                         case IDSVNLC_EXPLORE:\r
3066                                 {\r
3067                                         ShellExecute(this->m_hWnd, _T("explore"), filepath.GetDirectory().GetWinPath(), NULL, NULL, SW_SHOW);\r
3068                                 }\r
3069                                 break;\r
3070                         case IDSVNLC_REMOVE:\r
3071                                 {\r
3072                                         SVN git;\r
3073                                         CTSVNPathList itemsToRemove;\r
3074                                         FillListOfSelectedItemPaths(itemsToRemove);\r
3075 \r
3076                                         // We must sort items before removing, so that files are always removed\r
3077                                         // *before* their parents\r
3078                                         itemsToRemove.SortByPathname(true);\r
3079 \r
3080                                         bool bSuccess = false;\r
3081                                         if (git.Remove(itemsToRemove, FALSE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
3082                                         {\r
3083                                                 bSuccess = true;\r
3084                                         }\r
3085                                         else\r
3086                                         {\r
3087                                                 if ((git.Err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE) ||\r
3088                                                         (git.Err->apr_err == SVN_ERR_CLIENT_MODIFIED))\r
3089                                                 {\r
3090                                                         CString msg, yes, no, yestoall;\r
3091                                                         msg.Format(IDS_PROC_REMOVEFORCE, (LPCTSTR)git.GetLastErrorMessage());\r
3092                                                         yes.LoadString(IDS_MSGBOX_YES);\r
3093                                                         no.LoadString(IDS_MSGBOX_NO);\r
3094                                                         yestoall.LoadString(IDS_PROC_YESTOALL);\r
3095                                                         UINT ret = CMessageBox::Show(m_hWnd, msg, _T("TortoiseSVN"), 2, IDI_ERROR, yes, no, yestoall);\r
3096                                                         if ((ret == 1)||(ret==3))\r
3097                                                         {\r
3098                                                                 if (!git.Remove(itemsToRemove, TRUE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
3099                                                                 {\r
3100                                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3101                                                                 }\r
3102                                                                 else\r
3103                                                                         bSuccess = true;\r
3104                                                         }\r
3105                                                 }\r
3106                                                 else\r
3107                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3108                                         }\r
3109                                         if (bSuccess)\r
3110                                         {\r
3111                                                 // The remove went ok, but we now need to run through the selected items again\r
3112                                                 // and update their status\r
3113                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3114                                                 int index;\r
3115                                                 std::vector<int> entriesToRemove;\r
3116                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3117                                                 {\r
3118                                                         FileEntry * e = GetListEntry(index);\r
3119                                                         if (!bShift &&\r
3120                                                                 ((e->textstatus == git_wc_status_unversioned)||\r
3121                                                                 (e->textstatus == git_wc_status_none)||\r
3122                                                                 (e->textstatus == git_wc_status_ignored)))\r
3123                                                         {\r
3124                                                                 if (GetCheck(index))\r
3125                                                                         m_nSelected--;\r
3126                                                                 m_nTotal--;\r
3127                                                                 entriesToRemove.push_back(index);\r
3128                                                         }\r
3129                                                         else\r
3130                                                         {\r
3131                                                                 e->textstatus = git_wc_status_deleted;\r
3132                                                                 e->status = git_wc_status_deleted;\r
3133                                                                 SetEntryCheck(e,index,true);\r
3134                                                         }\r
3135                                                 }\r
3136                                                 for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
3137                                                 {\r
3138                                                         RemoveListEntry(*it);\r
3139                                                 }\r
3140                                         }\r
3141                                         SaveColumnWidths();\r
3142                                         Show(m_dwShow, 0, m_bShowFolders);\r
3143                                         NotifyCheck();\r
3144                                 }\r
3145                                 break;\r
3146                         case IDSVNLC_DELETE:\r
3147                                 {\r
3148                                         CTSVNPathList pathlist;\r
3149                                         FillListOfSelectedItemPaths(pathlist);\r
3150                                         pathlist.RemoveChildren();\r
3151                                         CString filelist;\r
3152                                         for (INT_PTR i=0; i<pathlist.GetCount(); ++i)\r
3153                                         {\r
3154                                                 filelist += pathlist[i].GetWinPathString();\r
3155                                                 filelist += _T("|");\r
3156                                         }\r
3157                                         filelist += _T("|");\r
3158                                         int len = filelist.GetLength();\r
3159                                         TCHAR * buf = new TCHAR[len+2];\r
3160                                         _tcscpy_s(buf, len+2, filelist);\r
3161                                         for (int i=0; i<len; ++i)\r
3162                                                 if (buf[i] == '|')\r
3163                                                         buf[i] = 0;\r
3164                                         SHFILEOPSTRUCT fileop;\r
3165                                         fileop.hwnd = this->m_hWnd;\r
3166                                         fileop.wFunc = FO_DELETE;\r
3167                                         fileop.pFrom = buf;\r
3168                                         fileop.pTo = NULL;\r
3169                                         fileop.fFlags = FOF_NO_CONNECTED_ELEMENTS | ((GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 0 : FOF_ALLOWUNDO);\r
3170                                         fileop.lpszProgressTitle = _T("deleting file");\r
3171                                         int result = SHFileOperation(&fileop);\r
3172                                         delete [] buf;\r
3173 \r
3174                                         if ( (result==0) && (!fileop.fAnyOperationsAborted) )\r
3175                                         {\r
3176                                                 SetRedraw(FALSE);\r
3177                                                 POSITION pos = NULL;\r
3178                                                 CTSVNPathList deletedlist;      // to store list of deleted folders\r
3179                                                 while ((pos = GetFirstSelectedItemPosition()) != 0)\r
3180                                                 {\r
3181                                                         int index = GetNextSelectedItem(pos);\r
3182                                                         if (GetCheck(index))\r
3183                                                                 m_nSelected--;\r
3184                                                         m_nTotal--;\r
3185                                                         FileEntry * fentry = GetListEntry(index);\r
3186                                                         if ((fentry)&&(fentry->isfolder))\r
3187                                                                 deletedlist.AddPath(fentry->path);\r
3188                                                         RemoveListEntry(index);\r
3189                                                 }\r
3190                                                 // now go through the list of deleted folders\r
3191                                                 // and remove all their children from the list too!\r
3192                                                 int nListboxEntries = GetItemCount();\r
3193                                                 for (int folderindex = 0; folderindex < deletedlist.GetCount(); ++folderindex)\r
3194                                                 {\r
3195                                                         CTSVNPath folderpath = deletedlist[folderindex];\r
3196                                                         for (int i=0; i<nListboxEntries; ++i)\r
3197                                                         {\r
3198                                                                 FileEntry * entry = GetListEntry(i);\r
3199                                                                 if (folderpath.IsAncestorOf(entry->path))\r
3200                                                                 {\r
3201                                                                         RemoveListEntry(i--);\r
3202                                                                         nListboxEntries--;\r
3203                                                                 }\r
3204                                                         }\r
3205                                                 }\r
3206                                                 SetRedraw(TRUE);\r
3207                                         }\r
3208                                 }\r
3209                                 break;\r
3210                         case IDSVNLC_IGNOREMASK:\r
3211                                 {\r
3212                                         CString name = _T("*")+filepath.GetFileExtension();\r
3213                                         CTSVNPathList ignorelist;\r
3214                                         FillListOfSelectedItemPaths(ignorelist, true);\r
3215                                         std::set<CTSVNPath> parentlist;\r
3216                                         for (int i=0; i<ignorelist.GetCount(); ++i)\r
3217                                         {\r
3218                                                 parentlist.insert(ignorelist[i].GetContainingDirectory());\r
3219                                         }\r
3220                                         std::set<CTSVNPath>::iterator it;\r
3221                                         std::vector<CString> toremove;\r
3222                                         SetRedraw(FALSE);\r
3223                                         for (it = parentlist.begin(); it != parentlist.end(); ++it)\r
3224                                         {\r
3225                                                 CTSVNPath parentFolder = (*it).GetDirectory();\r
3226                                                 SVNProperties props(parentFolder, SVNRev::REV_WC, false);\r
3227                                                 CStringA value;\r
3228                                                 for (int i=0; i<props.GetCount(); i++)\r
3229                                                 {\r
3230                                                         CString propname(props.GetItemName(i).c_str());\r
3231                                                         if (propname.CompareNoCase(_T("git:ignore"))==0)\r
3232                                                         {\r
3233                                                                 stdstring stemp;\r
3234                                                                 // treat values as normal text even if they're not\r
3235                                                                 value = (char *)props.GetItemValue(i).c_str();\r
3236                                                         }\r
3237                                                 }\r
3238                                                 if (value.IsEmpty())\r
3239                                                         value = name;\r
3240                                                 else\r
3241                                                 {\r
3242                                                         value = value.Trim("\n\r");\r
3243                                                         value += "\n";\r
3244                                                         value += name;\r
3245                                                         value.Remove('\r');\r
3246                                                 }\r
3247                                                 if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
3248                                                 {\r
3249                                                         CString temp;\r
3250                                                         temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
3251                                                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
3252                                                 }\r
3253                                                 else\r
3254                                                 {\r
3255                                                         CTSVNPath basepath;\r
3256                                                         int nListboxEntries = GetItemCount();\r
3257                                                         for (int i=0; i<nListboxEntries; ++i)\r
3258                                                         {\r
3259                                                                 FileEntry * entry = GetListEntry(i);\r
3260                                                                 ASSERT(entry != NULL);\r
3261                                                                 if (entry == NULL)\r
3262                                                                         continue;\r
3263                                                                 if (basepath.IsEmpty())\r
3264                                                                         basepath = entry->basepath;\r
3265                                                                 // since we ignored files with a mask (e.g. *.exe)\r
3266                                                                 // we have to find find all files in the same\r
3267                                                                 // folder (IsAncestorOf() returns TRUE for _all_ children,\r
3268                                                                 // not just the immediate ones) which match the\r
3269                                                                 // mask and remove them from the list too.\r
3270                                                                 if ((entry->status == git_wc_status_unversioned)&&(parentFolder.IsAncestorOf(entry->path)))\r
3271                                                                 {\r
3272                                                                         CString f = entry->path.GetSVNPathString();\r
3273                                                                         if (f.Mid(parentFolder.GetSVNPathString().GetLength()).Find('/')<=0)\r
3274                                                                         {\r
3275                                                                                 if (CStringUtils::WildCardMatch(name, f))\r
3276                                                                                 {\r
3277                                                                                         if (GetCheck(i))\r
3278                                                                                                 m_nSelected--;\r
3279                                                                                         m_nTotal--;\r
3280                                                                                         toremove.push_back(f);\r
3281                                                                                 }\r
3282                                                                         }\r
3283                                                                 }\r
3284                                                         }\r
3285                                                         if (!m_bIgnoreRemoveOnly)\r
3286                                                         {\r
3287                                                                 SVNStatus status;\r
3288                                                                 git_wc_status2_t * s;\r
3289                                                                 CTSVNPath gitPath;\r
3290                                                                 s = status.GetFirstFileStatus(parentFolder, gitPath, false, git_depth_empty);\r
3291                                                                 if (s!=0)\r
3292                                                                 {\r
3293                                                                         // first check if the folder isn't already present in the list\r
3294                                                                         bool bFound = false;\r
3295                                                                         for (int i=0; i<nListboxEntries; ++i)\r
3296                                                                         {\r
3297                                                                                 FileEntry * entry = GetListEntry(i);\r
3298                                                                                 if (entry->path.IsEquivalentTo(gitPath))\r
3299                                                                                 {\r
3300                                                                                         bFound = true;\r
3301                                                                                         break;\r
3302                                                                                 }\r
3303                                                                         }\r
3304                                                                         if (!bFound)\r
3305                                                                         {\r
3306                                                                                 FileEntry * entry = new FileEntry();\r
3307                                                                                 entry->path = gitPath;\r
3308                                                                                 entry->basepath = basepath;\r
3309                                                                                 entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
3310                                                                                 entry->textstatus = s->text_status;\r
3311                                                                                 entry->propstatus = s->prop_status;\r
3312                                                                                 entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
3313                                                                                 entry->remotetextstatus = s->repos_text_status;\r
3314                                                                                 entry->remotepropstatus = s->repos_prop_status;\r
3315                                                                                 entry->inunversionedfolder = false;\r
3316                                                                                 entry->checked = true;\r
3317                                                                                 entry->inexternal = false;\r
3318                                                                                 entry->direct = false;\r
3319                                                                                 entry->isfolder = true;\r
3320                                                                                 entry->last_commit_date = 0;\r
3321                                                                                 entry->last_commit_rev = 0;\r
3322                                                                                 entry->remoterev = 0;\r
3323                                                                                 if (s->entry)\r
3324                                                                                 {\r
3325                                                                                         if (s->entry->url)\r
3326                                                                                         {\r
3327                                                                                                 entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
3328                                                                                         }\r
3329                                                                                 }\r
3330                                                                                 if (s->entry && s->entry->present_props)\r
3331                                                                                 {\r
3332                                                                                         entry->present_props = s->entry->present_props;\r
3333                                                                                 }\r
3334                                                                                 m_arStatusArray.push_back(entry);\r
3335                                                                                 m_arListArray.push_back(m_arStatusArray.size()-1);\r
3336                                                                                 AddEntry(entry, langID, GetItemCount());\r
3337                                                                         }\r
3338                                                                 }\r
3339                                                         }\r
3340                                                 }\r
3341                                         }\r
3342                                         for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
3343                                         {\r
3344                                                 int nListboxEntries = GetItemCount();\r
3345                                                 for (int i=0; i<nListboxEntries; ++i)\r
3346                                                 {\r
3347                                                         if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
3348                                                         {\r
3349                                                                 RemoveListEntry(i);\r
3350                                                                 break;\r
3351                                                         }\r
3352                                                 }\r
3353                                         }\r
3354                                         SetRedraw(TRUE);\r
3355                                 }\r
3356                                 break;\r
3357                         case IDSVNLC_IGNORE:\r
3358                                 {\r
3359                                         CTSVNPathList ignorelist;\r
3360                                         std::vector<CString> toremove;\r
3361                                         FillListOfSelectedItemPaths(ignorelist, true);\r
3362                                         SetRedraw(FALSE);\r
3363                                         for (int j=0; j<ignorelist.GetCount(); ++j)\r
3364                                         {\r
3365                                                 int nListboxEntries = GetItemCount();\r
3366                                                 for (int i=0; i<nListboxEntries; ++i)\r
3367                                                 {\r
3368                                                         if (GetListEntry(i)->GetPath().IsEquivalentTo(ignorelist[j]))\r
3369                                                         {\r
3370                                                                 selIndex = i;\r
3371                                                                 break;\r
3372                                                         }\r
3373                                                 }\r
3374                                                 CString name = CPathUtils::PathPatternEscape(ignorelist[j].GetFileOrDirectoryName());\r
3375                                                 CTSVNPath parentfolder = ignorelist[j].GetContainingDirectory();\r
3376                                                 SVNProperties props(parentfolder, SVNRev::REV_WC, false);\r
3377                                                 CStringA value;\r
3378                                                 for (int i=0; i<props.GetCount(); i++)\r
3379                                                 {\r
3380                                                         CString propname(props.GetItemName(i).c_str());\r
3381                                                         if (propname.CompareNoCase(_T("git:ignore"))==0)\r
3382                                                         {\r
3383                                                                 stdstring stemp;\r
3384                                                                 // treat values as normal text even if they're not\r
3385                                                                 value = (char *)props.GetItemValue(i).c_str();\r
3386                                                         }\r
3387                                                 }\r
3388                                                 if (value.IsEmpty())\r
3389                                                         value = name;\r
3390                                                 else\r
3391                                                 {\r
3392                                                         value = value.Trim("\n\r");\r
3393                                                         value += "\n";\r
3394                                                         value += name;\r
3395                                                         value.Remove('\r');\r
3396                                                 }\r
3397                                                 if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
3398                                                 {\r
3399                                                         CString temp;\r
3400                                                         temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
3401                                                         CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
3402                                                         break;\r
3403                                                 }\r
3404                                                 if (GetCheck(selIndex))\r
3405                                                         m_nSelected--;\r
3406                                                 m_nTotal--;\r
3407 \r
3408                                                 // now, if we ignored a folder, remove all its children\r
3409                                                 if (ignorelist[j].IsDirectory())\r
3410                                                 {\r
3411                                                         for (int i=0; i<(int)m_arListArray.size(); ++i)\r
3412                                                         {\r
3413                                                                 FileEntry * entry = GetListEntry(i);\r
3414                                                                 if (entry->status == git_wc_status_unversioned)\r
3415                                                                 {\r
3416                                                                         if (!ignorelist[j].IsEquivalentTo(entry->GetPath())&&(ignorelist[j].IsAncestorOf(entry->GetPath())))\r
3417                                                                         {\r
3418                                                                                 entry->status = git_wc_status_ignored;\r
3419                                                                                 entry->textstatus = git_wc_status_ignored;\r
3420                                                                                 if (GetCheck(i))\r
3421                                                                                         m_nSelected--;\r
3422                                                                                 toremove.push_back(entry->GetPath().GetSVNPathString());\r
3423                                                                         }\r
3424                                                                 }\r
3425                                                         }\r
3426                                                 }\r
3427 \r
3428                                                 CTSVNPath basepath = m_arStatusArray[m_arListArray[selIndex]]->basepath;\r
3429 \r
3430                                                 FileEntry * entry = m_arStatusArray[m_arListArray[selIndex]];\r
3431                                                 if ( entry->status == git_wc_status_unversioned ) // keep "deleted" items\r
3432                                                         toremove.push_back(entry->GetPath().GetSVNPathString());\r
3433 \r
3434                                                 if (!m_bIgnoreRemoveOnly)\r
3435                                                 {\r
3436                                                         SVNStatus status;\r
3437                                                         git_wc_status2_t * s;\r
3438                                                         CTSVNPath gitPath;\r
3439                                                         s = status.GetFirstFileStatus(parentfolder, gitPath, false, git_depth_empty);\r
3440                                                         // first check if the folder isn't already present in the list\r
3441                                                         bool bFound = false;\r
3442                                                         nListboxEntries = GetItemCount();\r
3443                                                         for (int i=0; i<nListboxEntries; ++i)\r
3444                                                         {\r
3445                                                                 FileEntry * entry = GetListEntry(i);\r
3446                                                                 if (entry->path.IsEquivalentTo(gitPath))\r
3447                                                                 {\r
3448                                                                         bFound = true;\r
3449                                                                         break;\r
3450                                                                 }\r
3451                                                         }\r
3452                                                         if (!bFound)\r
3453                                                         {\r
3454                                                                 if (s!=0)\r
3455                                                                 {\r
3456                                                                         FileEntry * entry = new FileEntry();\r
3457                                                                         entry->path = gitPath;\r
3458                                                                         entry->basepath = basepath;\r
3459                                                                         entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
3460                                                                         entry->textstatus = s->text_status;\r
3461                                                                         entry->propstatus = s->prop_status;\r
3462                                                                         entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
3463                                                                         entry->remotetextstatus = s->repos_text_status;\r
3464                                                                         entry->remotepropstatus = s->repos_prop_status;\r
3465                                                                         entry->inunversionedfolder = FALSE;\r
3466                                                                         entry->checked = true;\r
3467                                                                         entry->inexternal = false;\r
3468                                                                         entry->direct = false;\r
3469                                                                         entry->isfolder = true;\r
3470                                                                         entry->last_commit_date = 0;\r
3471                                                                         entry->last_commit_rev = 0;\r
3472                                                                         entry->remoterev = 0;\r
3473                                                                         if (s->entry)\r
3474                                                                         {\r
3475                                                                                 if (s->entry->url)\r
3476                                                                                 {\r
3477                                                                                         entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
3478                                                                                 }\r
3479                                                                         }\r
3480                                                                         if (s->entry && s->entry->present_props)\r
3481                                                                         {\r
3482                                                                                 entry->present_props = s->entry->present_props;\r
3483                                                                         }\r
3484                                                                         m_arStatusArray.push_back(entry);\r
3485                                                                         m_arListArray.push_back(m_arStatusArray.size()-1);\r
3486                                                                         AddEntry(entry, langID, GetItemCount());\r
3487                                                                 }\r
3488                                                         }\r
3489                                                 }\r
3490                                         }\r
3491                                         for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
3492                                         {\r
3493                                                 int nListboxEntries = GetItemCount();\r
3494                                                 for (int i=0; i<nListboxEntries; ++i)\r
3495                                                 {\r
3496                                                         if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
3497                                                         {\r
3498                                                                 RemoveListEntry(i);\r
3499                                                                 break;\r
3500                                                         }\r
3501                                                 }\r
3502                                         }\r
3503                                         SetRedraw(TRUE);\r
3504                                 }\r
3505                                 break;\r
3506                         case IDSVNLC_EDITCONFLICT:\r
3507                                 SVNDiff::StartConflictEditor(filepath);\r
3508                                 break;\r
3509                         case IDSVNLC_RESOLVECONFLICT:\r
3510                         case IDSVNLC_RESOLVEMINE:\r
3511                         case IDSVNLC_RESOLVETHEIRS:\r
3512                                 {\r
3513                                         git_wc_conflict_choice_t result = git_wc_conflict_choose_merged;\r
3514                                         switch (cmd)\r
3515                                         {\r
3516                                         case IDSVNLC_RESOLVETHEIRS:\r
3517                                                 result = git_wc_conflict_choose_theirs_full;\r
3518                                                 break;\r
3519                                         case IDSVNLC_RESOLVEMINE:\r
3520                                                 result = git_wc_conflict_choose_mine_full;\r
3521                                                 break;\r
3522                                         case IDSVNLC_RESOLVECONFLICT:\r
3523                                                 result = git_wc_conflict_choose_merged;\r
3524                                                 break;\r
3525                                         }\r
3526                                         if (CMessageBox::Show(m_hWnd, IDS_PROC_RESOLVE, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO)==IDYES)\r
3527                                         {\r
3528                                                 SVN git;\r
3529                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3530                                                 while (pos != 0)\r
3531                                                 {\r
3532                                                         int index;\r
3533                                                         index = GetNextSelectedItem(pos);\r
3534                                                         FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
3535                                                         if (!git.Resolve(fentry->GetPath(), result, FALSE))\r
3536                                                         {\r
3537                                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3538                                                         }\r
3539                                                         else\r
3540                                                         {\r
3541                                                                 fentry->status = git_wc_status_modified;\r
3542                                                                 fentry->textstatus = git_wc_status_modified;\r
3543                                                                 fentry->isConflicted = false;\r
3544                                                         }\r
3545                                                 }\r
3546                                                 Show(m_dwShow, 0, m_bShowFolders);\r
3547                                         }\r
3548                                 }\r
3549                                 break;\r
3550                         case IDSVNLC_ADD:\r
3551                                 {\r
3552                                         SVN git;\r
3553                                         CTSVNPathList itemsToAdd;\r
3554                                         FillListOfSelectedItemPaths(itemsToAdd);\r
3555 \r
3556                                         // We must sort items before adding, so that folders are always added\r
3557                                         // *before* any of their children\r
3558                                         itemsToAdd.SortByPathname();\r
3559 \r
3560                                         ProjectProperties props;\r
3561                                         props.ReadPropsPathList(itemsToAdd);\r
3562                                         if (git.Add(itemsToAdd, &props, git_depth_empty, TRUE, TRUE, TRUE))\r
3563                                         {\r
3564                                                 // The add went ok, but we now need to run through the selected items again\r
3565                                                 // and update their status\r
3566                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3567                                                 int index;\r
3568                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3569                                                 {\r
3570                                                         FileEntry * e = GetListEntry(index);\r
3571                                                         e->textstatus = git_wc_status_added;\r
3572                                                         e->propstatus = git_wc_status_none;\r
3573                                                         e->status = git_wc_status_added;\r
3574                                                         SetEntryCheck(e,index,true);\r
3575                                                 }\r
3576                                         }\r
3577                                         else\r
3578                                         {\r
3579                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3580                                         }\r
3581                                         SaveColumnWidths();\r
3582                                         Show(m_dwShow, 0, m_bShowFolders);\r
3583                                         NotifyCheck();\r
3584                                 }\r
3585                                 break;\r
3586                         case IDSVNLC_ADD_RECURSIVE:\r
3587                                 {\r
3588                                         CTSVNPathList itemsToAdd;\r
3589                                         FillListOfSelectedItemPaths(itemsToAdd);\r
3590 \r
3591                                         CAddDlg dlg;\r
3592                                         dlg.m_pathList = itemsToAdd;\r
3593                                         if (dlg.DoModal() == IDOK)\r
3594                                         {\r
3595                                                 if (dlg.m_pathList.GetCount() == 0)\r
3596                                                         break;\r
3597                                                 CSVNProgressDlg progDlg;\r
3598                                                 progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Add);\r
3599                                                 progDlg.SetPathList(dlg.m_pathList);\r
3600                                                 ProjectProperties props;\r
3601                                                 props.ReadPropsPathList(dlg.m_pathList);\r
3602                                                 progDlg.SetProjectProperties(props);\r
3603                                                 progDlg.SetItemCount(dlg.m_pathList.GetCount());\r
3604                                                 progDlg.DoModal();\r
3605 \r
3606                                                 // refresh!\r
3607                                                 CWnd* pParent = GetParent();\r
3608                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3609                                                 {\r
3610                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3611                                                 }\r
3612                                         }\r
3613                                 }\r
3614                                 break;\r
3615                         case IDSVNLC_LOCK:\r
3616                                 {\r
3617                                         CTSVNPathList itemsToLock;\r
3618                                         FillListOfSelectedItemPaths(itemsToLock);\r
3619                                         CInputDlg inpDlg;\r
3620                                         inpDlg.m_sTitle.LoadString(IDS_MENU_LOCK);\r
3621                                         CStringUtils::RemoveAccelerators(inpDlg.m_sTitle);\r
3622                                         inpDlg.m_sHintText.LoadString(IDS_LOCK_MESSAGEHINT);\r
3623                                         inpDlg.m_sCheckText.LoadString(IDS_LOCK_STEALCHECK);\r
3624                                         ProjectProperties props;\r
3625                                         props.ReadPropsPathList(itemsToLock);\r
3626                                         props.nMinLogSize = 0;          // the lock message is optional, so no minimum!\r
3627                                         inpDlg.m_pProjectProperties = &props;\r
3628                                         if (inpDlg.DoModal()==IDOK)\r
3629                                         {\r
3630                                                 CSVNProgressDlg progDlg;\r
3631                                                 progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Lock);\r
3632                                                 progDlg.SetOptions(inpDlg.m_iCheck ? ProgOptLockForce : ProgOptNone);\r
3633                                                 progDlg.SetPathList(itemsToLock);\r
3634                                                 progDlg.SetCommitMessage(inpDlg.m_sInputText);\r
3635                                                 progDlg.DoModal();\r
3636                                                 // refresh!\r
3637                                                 CWnd* pParent = GetParent();\r
3638                                                 if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3639                                                 {\r
3640                                                         pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3641                                                 }\r
3642                                         }\r
3643                                 }\r
3644                                 break;\r
3645                         case IDSVNLC_UNLOCKFORCE:\r
3646                                 bForce = true;\r
3647                         case IDSVNLC_UNLOCK:\r
3648                                 {\r
3649                                         CTSVNPathList itemsToUnlock;\r
3650                                         FillListOfSelectedItemPaths(itemsToUnlock);\r
3651                                         CSVNProgressDlg progDlg;\r
3652                                         progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Unlock);\r
3653                                         progDlg.SetOptions(bForce ? ProgOptLockForce : ProgOptNone);\r
3654                                         progDlg.SetPathList(itemsToUnlock);\r
3655                                         progDlg.DoModal();\r
3656                                         // refresh!\r
3657                                         CWnd* pParent = GetParent();\r
3658                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3659                                         {\r
3660                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3661                                         }\r
3662                                 }\r
3663                                 break;\r
3664                         case IDSVNLC_REPAIRMOVE:\r
3665                                 {\r
3666                                         POSITION pos = GetFirstSelectedItemPosition();\r
3667                                         int index = GetNextSelectedItem(pos);\r
3668                                         FileEntry * entry1 = NULL;\r
3669                                         FileEntry * entry2 = NULL;\r
3670                                         if (index >= 0)\r
3671                                         {\r
3672                                                 entry1 = GetListEntry(index);\r
3673                                                 git_wc_status_kind status1 = git_wc_status_none;\r
3674                                                 git_wc_status_kind status2 = git_wc_status_none;\r
3675                                                 if (entry1)\r
3676                                                 {\r
3677                                                         status1 = entry1->status;\r
3678                                                         index = GetNextSelectedItem(pos);\r
3679                                                         if (index >= 0)\r
3680                                                         {\r
3681                                                                 entry2 = GetListEntry(index);\r
3682                                                                 if (entry2)\r
3683                                                                 {\r
3684                                                                         status2 = entry2->status;\r
3685                                                                         if (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned)\r
3686                                                                         {\r
3687                                                                                 FileEntry * tempentry = entry1;\r
3688                                                                                 entry1 = entry2;\r
3689                                                                                 entry2 = tempentry;\r
3690                                                                         }\r
3691                                                                         // entry1 was renamed to entry2 but outside of Subversion\r
3692                                                                         // fix this by moving entry2 back to entry1 first,\r
3693                                                                         // then do an git-move from entry1 to entry2\r
3694                                                                         if (MoveFile(entry2->GetPath().GetWinPath(), entry1->GetPath().GetWinPath()))\r
3695                                                                         {\r
3696                                                                                 SVN git;\r
3697                                                                                 if (!git.Move(CTSVNPathList(entry1->GetPath()), entry2->GetPath(), TRUE))\r
3698                                                                                 {\r
3699                                                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3700                                                                                 }\r
3701                                                                                 else\r
3702                                                                                 {\r
3703                                                                                         // check the previously unversioned item\r
3704                                                                                         entry1->checked = true;\r
3705                                                                                         // fixing the move was successful. We have to adjust the new status of the\r
3706                                                                                         // files.\r
3707                                                                                         // Since we don't know if the moved/renamed file had local modifications or not,\r
3708                                                                                         // we can't guess the new status. That means we have to refresh...\r
3709                                                                                         CWnd* pParent = GetParent();\r
3710                                                                                         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3711                                                                                         {\r
3712                                                                                                 pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
3713                                                                                         }\r
3714                                                                                 }\r
3715                                                                         }\r
3716                                                                         else\r
3717                                                                         {\r
3718                                                                                 LPVOID lpMsgBuf;\r
3719                                                                                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
3720                                                                                         FORMAT_MESSAGE_FROM_SYSTEM | \r
3721                                                                                         FORMAT_MESSAGE_IGNORE_INSERTS,\r
3722                                                                                         NULL,\r
3723                                                                                         GetLastError(),\r
3724                                                                                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
3725                                                                                         (LPTSTR) &lpMsgBuf,\r
3726                                                                                         0,\r
3727                                                                                         NULL \r
3728                                                                                         );\r
3729                                                                                 MessageBox((LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );\r
3730                                                                                 LocalFree( lpMsgBuf );\r
3731                                                                         }\r
3732                                                                 }\r
3733                                                         }\r
3734                                                 }\r
3735                                         }\r
3736                                 }\r
3737                                 break;\r
3738                         case IDSVNLC_REMOVEFROMCS:\r
3739                                 {\r
3740                                         CTSVNPathList changelistItems;\r
3741                                         FillListOfSelectedItemPaths(changelistItems);\r
3742                                         SVN git;\r
3743                                         SetRedraw(FALSE);\r
3744                                         if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
3745                                         {\r
3746                                                 // The changelists were removed, but we now need to run through the selected items again\r
3747                                                 // and update their changelist\r
3748                                                 POSITION pos = GetFirstSelectedItemPosition();\r
3749                                                 int index;\r
3750                                                 std::vector<int> entriesToRemove;\r
3751                                                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
3752                                                 {\r
3753                                                         FileEntry * e = GetListEntry(index);\r
3754                                                         if (e)\r
3755                                                         {\r
3756                                                                 e->changelist.Empty();\r
3757                                                                 if (e->status == git_wc_status_normal)\r
3758                                                                 {\r
3759                                                                         // remove the entry completely\r
3760                                                                         entriesToRemove.push_back(index);\r
3761                                                                 }\r
3762                                                                 else\r
3763                                                                         SetItemGroup(index, 0);\r
3764                                                         }\r
3765                                                 }\r
3766                                                 for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
3767                                                 {\r
3768                                                         RemoveListEntry(*it);\r
3769                                                 }\r
3770                                                 // TODO: Should we go through all entries here and check if we also could\r
3771                                                 // remove the changelist from m_changelists ?\r
3772                                         }\r
3773                                         else\r
3774                                         {\r
3775                                                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3776                                         }\r
3777                                         SetRedraw(TRUE);\r
3778                                 }\r
3779                                 break;\r
3780                         case IDSVNLC_CREATEIGNORECS:\r
3781                                 CreateChangeList(SVNSLC_IGNORECHANGELIST);\r
3782                                 break;\r
3783                         case IDSVNLC_CREATECS:\r
3784                                 {\r
3785                                         CCreateChangelistDlg dlg;\r
3786                                         if (dlg.DoModal() == IDOK)\r
3787                                         {\r
3788                                                 CreateChangeList(dlg.m_sName);\r
3789                                         }\r
3790                                 }\r
3791                                 break;\r
3792                         default:\r
3793                                 {\r
3794                                         if (cmd < IDSVNLC_MOVETOCS)\r
3795                                                 break;\r
3796                                         CTSVNPathList changelistItems;\r
3797                                         FillListOfSelectedItemPaths(changelistItems);\r
3798 \r
3799                                         // find the changelist name\r
3800                                         CString sChangelist;\r
3801                                         int cmdID = IDSVNLC_MOVETOCS;\r
3802                                         SetRedraw(FALSE);\r
3803                                         for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
3804                                         {\r
3805                                                 if ((it->first.Compare(SVNSLC_IGNORECHANGELIST))&&(entry->changelist.Compare(it->first)))\r
3806                                                 {\r
3807                                                         if (cmd == cmdID)\r
3808                                                         {\r
3809                                                                 sChangelist = it->first;\r
3810                                                         }\r
3811                                                         cmdID++;\r
3812                                                 }\r
3813                                         }\r
3814                                         if (!sChangelist.IsEmpty())\r
3815                                         {\r
3816                                                 SVN git;\r
3817                                                 if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
3818                                                 {\r
3819                                                         // The changelists were moved, but we now need to run through the selected items again\r
3820                                                         // and update their changelist\r
3821                                                         POSITION pos = GetFirstSelectedItemPosition();\r
3822                                                         int index;\r
3823                                                         while ((index = GetNextSelectedItem(pos)) >= 0)\r
3824                                                         {\r
3825                                                                 FileEntry * e = GetListEntry(index);\r
3826                                                                 e->changelist = sChangelist;\r
3827                                                                 if (!e->IsFolder())\r
3828                                                                 {\r
3829                                                                         if (m_changelists.find(e->changelist)!=m_changelists.end())\r
3830                                                                                 SetItemGroup(index, m_changelists[e->changelist]);\r
3831                                                                         else\r
3832                                                                                 SetItemGroup(index, 0);\r
3833                                                                 }\r
3834                                                         }\r
3835                                                 }\r
3836                                                 else\r
3837                                                 {\r
3838                                                         CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
3839                                                 }\r
3840                                         }\r
3841                                         SetRedraw(TRUE);\r
3842                                 }\r
3843                                 break;\r
3844 #endif\r
3845 \r
3846                         } // switch (cmd)\r
3847                         m_bBlock = FALSE;\r
3848                         AfxGetApp()->DoWaitCursor(-1);\r
3849                         GetStatisticsString();\r
3850                         int iItemCountAfterMenuCmd = GetItemCount();\r
3851                         //if (iItemCountAfterMenuCmd != iItemCountBeforeMenuCmd)\r
3852                         //{\r
3853                         //      CWnd* pParent = GetParent();\r
3854                         //      if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
3855                         //      {\r
3856                         //              pParent->SendMessage(SVNSLNM_ITEMCOUNTCHANGED);\r
3857                         //      }\r
3858                         //}\r
3859                 } // if (popup.CreatePopupMenu())\r
3860         } // if (selIndex >= 0)\r
3861 \r
3862 }\r
3863 \r
3864 void CGitStatusListCtrl::OnContextMenuHeader(CWnd * pWnd, CPoint point)\r
3865 {\r
3866         bool XPorLater = false;\r
3867         OSVERSIONINFOEX inf;\r
3868         SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
3869         inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
3870         GetVersionEx((OSVERSIONINFO *)&inf);\r
3871         WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
3872         if (fullver >= 0x0501)\r
3873                 XPorLater = true;\r
3874 \r
3875         CHeaderCtrl * pHeaderCtrl = (CHeaderCtrl *)pWnd;\r
3876         if ((point.x == -1) && (point.y == -1))\r
3877         {\r
3878                 CRect rect;\r
3879                 pHeaderCtrl->GetItemRect(0, &rect);\r
3880                 ClientToScreen(&rect);\r
3881                 point = rect.CenterPoint();\r
3882         }\r
3883         Locker lock(m_critSec);\r
3884         CMenu popup;\r
3885         if (popup.CreatePopupMenu())\r
3886         {\r
3887                 int columnCount = m_ColumnManager.GetColumnCount();\r
3888 \r
3889                 CString temp;\r
3890                 UINT uCheckedFlags = MF_STRING | MF_ENABLED | MF_CHECKED;\r
3891                 UINT uUnCheckedFlags = MF_STRING | MF_ENABLED;\r
3892 \r
3893                 // build control menu\r
3894 \r
3895                 if (XPorLater)\r
3896                 {\r
3897                         temp.LoadString(IDS_STATUSLIST_SHOWGROUPS);\r
3898                         popup.AppendMenu(IsGroupViewEnabled() ? uCheckedFlags : uUnCheckedFlags, columnCount, temp);\r
3899                 }\r
3900 \r
3901                 if (m_ColumnManager.AnyUnusedProperties())\r
3902                 {\r
3903                         temp.LoadString(IDS_STATUSLIST_REMOVEUNUSEDPROPS);\r
3904                         popup.AppendMenu(uUnCheckedFlags, columnCount+1, temp);\r
3905                 }\r
3906 \r
3907                 temp.LoadString(IDS_STATUSLIST_RESETCOLUMNORDER);\r
3908                 popup.AppendMenu(uUnCheckedFlags, columnCount+2, temp);\r
3909                 popup.AppendMenu(MF_SEPARATOR);\r
3910 \r
3911                 // standard columns\r
3912 \r
3913                 for (int i = 1; i < SVNSLC_NUMCOLUMNS; ++i)\r
3914                 {\r
3915                         popup.AppendMenu ( m_ColumnManager.IsVisible(i) \r
3916                                 ? uCheckedFlags \r
3917                                 : uUnCheckedFlags\r
3918                                 , i\r
3919                                 , m_ColumnManager.GetName(i));\r
3920                 }\r
3921 \r
3922                 // user-prop columns:\r
3923                 // find relevant ones and sort 'em\r
3924 \r
3925                 std::map<CString, int> sortedProps;\r
3926                 for (int i = SVNSLC_NUMCOLUMNS; i < columnCount; ++i)\r
3927                         if (m_ColumnManager.IsRelevant(i))\r
3928                                 sortedProps[m_ColumnManager.GetName(i)] = i;\r
3929 \r
3930                 if (!sortedProps.empty())\r
3931                 {\r
3932                         // add 'em to the menu\r
3933 \r
3934                         popup.AppendMenu(MF_SEPARATOR);\r
3935 \r
3936                         typedef std::map<CString, int>::const_iterator CIT;\r
3937                         for ( CIT iter = sortedProps.begin(), end = sortedProps.end()\r
3938                                 ; iter != end\r
3939                                 ; ++iter)\r
3940                         {\r
3941                                 popup.AppendMenu ( m_ColumnManager.IsVisible(iter->second) \r
3942                                         ? uCheckedFlags \r
3943                                         : uUnCheckedFlags\r
3944                                         , iter->second\r
3945                                         , iter->first);\r
3946                         }\r
3947                 }\r
3948 \r
3949                 // show menu & let user pick an entry\r
3950 \r
3951                 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
3952                 if ((cmd >= 1)&&(cmd < columnCount))\r
3953                 {\r
3954                         m_ColumnManager.SetVisible (cmd, !m_ColumnManager.IsVisible(cmd));\r
3955                 } \r
3956                 else if (cmd == columnCount)\r
3957                 {\r
3958                         EnableGroupView(!IsGroupViewEnabled());\r
3959                 } \r
3960                 else if (cmd == columnCount+1)\r
3961                 {\r
3962                         m_ColumnManager.RemoveUnusedProps();\r
3963                 } \r
3964                 else if (cmd == columnCount+2)\r
3965                 {\r
3966                         m_ColumnManager.ResetColumns (m_dwDefaultColumns);\r
3967                 }\r
3968         }\r
3969 }\r
3970 \r
3971 void CGitStatusListCtrl::OnContextMenu(CWnd* pWnd, CPoint point)\r
3972 {\r
3973 \r
3974         if (pWnd == this)\r
3975         {\r
3976                 OnContextMenuList(pWnd, point);\r
3977         } // if (pWnd == this)\r
3978         else if (pWnd == GetHeaderCtrl())\r
3979         {\r
3980                 OnContextMenuHeader(pWnd, point);\r
3981         }\r
3982 }\r
3983 \r
3984 void CGitStatusListCtrl::CreateChangeList(const CString& name)\r
3985 {\r
3986 #if 0\r
3987         CTGitPathList changelistItems;\r
3988         FillListOfSelectedItemPaths(changelistItems);\r
3989         Git git;\r
3990         if (git.AddToChangeList(changelistItems, name, git_depth_empty))\r
3991         {\r
3992                 TCHAR groupname[1024];\r
3993                 LVGROUP grp = {0};\r
3994                 grp.cbSize = sizeof(LVGROUP);\r
3995                 grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
3996                 _tcsncpy_s(groupname, 1024, name, 1023);\r
3997                 grp.pszHeader = groupname;\r
3998                 grp.iGroupId = (int)m_changelists.size();\r
3999                 grp.uAlign = LVGA_HEADER_LEFT;\r
4000                 m_changelists[name] = InsertGroup(-1, &grp);\r
4001 \r
4002                 PrepareGroups(true);\r
4003 \r
4004                 POSITION pos = GetFirstSelectedItemPosition();\r
4005                 int index;\r
4006                 while ((index = GetNextSelectedItem(pos)) >= 0)\r
4007                 {\r
4008                         FileEntry * e = GetListEntry(index);\r
4009                         e->changelist = name;\r
4010                         SetEntryCheck(e, index, FALSE);\r
4011                 }\r
4012 \r
4013                 for (index = 0; index < GetItemCount(); ++index)\r
4014                 {\r
4015                         FileEntry * e = GetListEntry(index);\r
4016                         if (m_changelists.find(e->changelist)!=m_changelists.end())\r
4017                                 SetItemGroup(index, m_changelists[e->changelist]);\r
4018                         else\r
4019                                 SetItemGroup(index, 0);\r
4020                 }\r
4021         }\r
4022         else\r
4023         {\r
4024                 CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("Tortoisegit"), MB_ICONERROR);\r
4025         }\r
4026 #endif\r
4027 }\r
4028 \r
4029 void CGitStatusListCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)\r
4030 {\r
4031 \r
4032         Locker lock(m_critSec);\r
4033         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
4034         *pResult = 0;\r
4035         if (m_bBlock)\r
4036                 return;\r
4037 #if 0\r
4038         if (pNMLV->iItem < 0)\r
4039         {\r
4040                 if (!IsGroupViewEnabled())\r
4041                         return;\r
4042                 POINT pt;\r
4043                 DWORD ptW = GetMessagePos();\r
4044                 pt.x = GET_X_LPARAM(ptW);\r
4045                 pt.y = GET_Y_LPARAM(ptW);\r
4046                 ScreenToClient(&pt);\r
4047                 int group = GetGroupFromPoint(&pt);\r
4048                 if (group < 0)\r
4049                         return;\r
4050                 // check/uncheck the whole group depending on the check-state \r
4051                 // of the first item in the group\r
4052                 m_bBlock = true;\r
4053                 bool bCheck = false;\r
4054                 bool bFirst = false;\r
4055                 LVITEM lv;\r
4056                 for (int i=0; i<GetItemCount(); ++i)\r
4057                 {\r
4058                         SecureZeroMemory(&lv, sizeof(LVITEM));\r
4059                         lv.mask = LVIF_GROUPID;\r
4060                         lv.iItem = i;\r
4061                         GetItem(&lv);\r
4062                         if (lv.iGroupId == group)\r
4063                         {\r
4064                                 FileEntry * entry = GetListEntry(i);\r
4065                                 if (!bFirst)\r
4066                                 {\r
4067                                         bCheck = !GetCheck(i);\r
4068                                         bFirst = true;\r
4069                                 }\r
4070                                 if (entry)\r
4071                                 {\r
4072                                         bool bOldCheck = !!GetCheck(i);\r
4073                                         SetEntryCheck(entry, i, bCheck);\r
4074                                         if (bCheck != bOldCheck)\r
4075                                         {\r
4076                                                 if (bCheck)\r
4077                                                         m_nSelected++;\r
4078                                                 else\r
4079                                                         m_nSelected--;\r
4080                                         }\r
4081                                 }\r
4082                         }\r
4083                 }\r
4084                 GetStatisticsString();\r
4085                 m_bBlock = false;\r
4086                 NotifyCheck();\r
4087                 return;\r
4088         }\r
4089 #endif\r
4090 //      FileEntry * entry = GetListEntry(pNMLV->iItem);\r
4091 //      if (entry)\r
4092         {\r
4093 //              if (entry->isConflicted)\r
4094 //              {\r
4095 //                      gitDiff::StartConflictEditor(entry->GetPath());\r
4096 //              }\r
4097 //              else\r
4098                 {\r
4099                         StartDiff(pNMLV->iItem);\r
4100                 }\r
4101         }\r
4102 \r
4103 }\r
4104 \r
4105 void CGitStatusListCtrl::StartDiff(int fileindex)\r
4106 {\r
4107         if(fileindex<0)\r
4108                 return;\r
4109         if(this->m_CurrentVersion.IsEmpty() || m_CurrentVersion== GIT_REV_ZERO)\r
4110         {\r
4111                 if(!g_Git.IsInitRepos())\r
4112                         CGitDiff::Diff((CTGitPath*)GetItemData(fileindex),\r
4113                                 CString(GIT_REV_ZERO),\r
4114                                         GitRev::GetHead());\r
4115                 else\r
4116                         CGitDiff::DiffNull((CTGitPath*)GetItemData(fileindex),\r
4117                                 CString(GIT_REV_ZERO));\r
4118         }else\r
4119         {\r
4120                 CGitDiff::Diff((CTGitPath*)GetItemData(fileindex),\r
4121                                 m_CurrentVersion,\r
4122                                         m_CurrentVersion+_T("~1"));\r
4123         }\r
4124 #if 0\r
4125         if (fileindex < 0)\r
4126                 return;\r
4127         FileEntry * entry = GetListEntry(fileindex);\r
4128         ASSERT(entry != NULL);\r
4129         if (entry == NULL)\r
4130                 return;\r
4131         if (((entry->status == git_wc_status_normal)&&(entry->remotestatus <= git_wc_status_normal))||\r
4132                 (entry->status == git_wc_status_unversioned)||(entry->status == git_wc_status_none))\r
4133         {\r
4134                 int ret = (int)ShellExecute(this->m_hWnd, NULL, entry->path.GetWinPath(), NULL, NULL, SW_SHOW);\r
4135                 if (ret <= HINSTANCE_ERROR)\r
4136                 {\r
4137                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
4138                         cmd += entry->path.GetWinPathString();\r
4139                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
4140                 }\r
4141                 return;\r
4142         }\r
4143 \r
4144         GitDiff diff(NULL, m_hWnd, true);\r
4145         diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
4146         diff.DiffWCFile(\r
4147                 entry->path, entry->textstatus, entry->propstatus,\r
4148                 entry->remotetextstatus, entry->remotepropstatus);\r
4149 #endif\r
4150 }\r
4151 \r
4152 CString CGitStatusListCtrl::GetStatisticsString()\r
4153 {\r
4154 \r
4155         CString sNormal, sAdded, sDeleted, sModified, sConflicted, sUnversioned;\r
4156         WORD langID = (WORD)(DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
4157         TCHAR buf[MAX_STATUS_STRING_LENGTH];\r
4158         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_normal, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4159         sNormal = buf;\r
4160         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_added, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4161         sAdded = buf;\r
4162         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_deleted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4163         sDeleted = buf;\r
4164         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_modified, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4165         sModified = buf;\r
4166         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_conflicted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4167         sConflicted = buf;\r
4168         GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_unversioned, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
4169         sUnversioned = buf;\r
4170         CString sToolTip;\r
4171         sToolTip.Format(_T("%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d"),\r
4172                 (LPCTSTR)sNormal, m_nNormal,\r
4173                 (LPCTSTR)sUnversioned, m_nUnversioned,\r
4174                 (LPCTSTR)sModified, m_nModified,\r
4175                 (LPCTSTR)sAdded, m_nAdded,\r
4176                 (LPCTSTR)sDeleted, m_nDeleted,\r
4177                 (LPCTSTR)sConflicted, m_nConflicted\r
4178                 );\r
4179         CString sStats;\r
4180         sStats.Format(IDS_COMMITDLG_STATISTICSFORMAT, m_nSelected, GetItemCount());\r
4181         if (m_pStatLabel)\r
4182         {\r
4183                 m_pStatLabel->SetWindowText(sStats);\r
4184         }\r
4185 \r
4186         if (m_pSelectButton)\r
4187         {\r
4188                 if (m_nSelected == 0)\r
4189                         m_pSelectButton->SetCheck(BST_UNCHECKED);\r
4190                 else if (m_nSelected != GetItemCount())\r
4191                         m_pSelectButton->SetCheck(BST_INDETERMINATE);\r
4192                 else\r
4193                         m_pSelectButton->SetCheck(BST_CHECKED);\r
4194         }\r
4195 \r
4196         if (m_pConfirmButton)\r
4197         {\r
4198                 m_pConfirmButton->EnableWindow(m_nSelected>0);\r
4199         }\r
4200 \r
4201         return sToolTip;\r
4202 \r
4203 \r
4204 }\r
4205 \r
4206 CTGitPath CGitStatusListCtrl::GetCommonDirectory(bool bStrict)\r
4207 {\r
4208         if (!bStrict)\r
4209         {\r
4210                 // not strict means that the selected folder has priority\r
4211                 if (!m_StatusFileList.GetCommonDirectory().IsEmpty())\r
4212                         return m_StatusFileList.GetCommonDirectory();\r
4213         }\r
4214 \r
4215         CTGitPath commonBaseDirectory;\r
4216         int nListItems = GetItemCount();\r
4217         for (int i=0; i<nListItems; ++i)\r
4218         {\r
4219                 CTGitPath& baseDirectory = *(CTGitPath*)this->GetItemData(i);\r
4220                 if(commonBaseDirectory.IsEmpty())\r
4221                 {\r
4222                         commonBaseDirectory = baseDirectory;\r
4223                 }\r
4224                 else\r
4225                 {\r
4226                         if (commonBaseDirectory.GetWinPathString().GetLength() > baseDirectory.GetWinPathString().GetLength())\r
4227                         {\r
4228                                 if (baseDirectory.IsAncestorOf(commonBaseDirectory))\r
4229                                         commonBaseDirectory = baseDirectory;\r
4230                         }\r
4231                 }\r
4232         }\r
4233         return commonBaseDirectory;\r
4234 }\r
4235 \r
4236 CTGitPath CGitStatusListCtrl::GetCommonURL(bool bStrict)\r
4237 {\r
4238         CTGitPath commonBaseURL;\r
4239 #if 0\r
4240         \r
4241         if (!bStrict)\r
4242         {\r
4243                 // not strict means that the selected folder has priority\r
4244                 if (!m_StatusUrlList.GetCommonDirectory().IsEmpty())\r
4245                         return m_StatusUrlList.GetCommonDirectory();\r
4246         }\r
4247 \r
4248         int nListItems = GetItemCount();\r
4249         for (int i=0; i<nListItems; ++i)\r
4250         {\r
4251                 const CTGitPath& baseURL = CTGitPath(GetListEntry(i)->GetURL());\r
4252                 if (baseURL.IsEmpty())\r
4253                         continue;                       // item has no url\r
4254                 if(commonBaseURL.IsEmpty())\r
4255                 {\r
4256                         commonBaseURL = baseURL;\r
4257                 }\r
4258                 else\r
4259                 {\r
4260                         if (commonBaseURL.GetGitPathString().GetLength() > baseURL.GetGitPathString().GetLength())\r
4261                         {\r
4262                                 if (baseURL.IsAncestorOf(commonBaseURL))\r
4263                                         commonBaseURL = baseURL;\r
4264                         }\r
4265                 }\r
4266         }\r
4267         \r
4268 #endif\r
4269         return commonBaseURL;\r
4270 }\r
4271 \r
4272 void CGitStatusListCtrl::SelectAll(bool bSelect, bool bIncludeNoCommits)\r
4273 {\r
4274         CWaitCursor waitCursor;\r
4275         // block here so the LVN_ITEMCHANGED messages\r
4276         // get ignored\r
4277         m_bBlock = TRUE;\r
4278         SetRedraw(FALSE);\r
4279 \r
4280         int nListItems = GetItemCount();\r
4281         if (bSelect)\r
4282                 m_nSelected = nListItems;\r
4283         else\r
4284                 m_nSelected = 0;\r
4285 \r
4286         for (int i=0; i<nListItems; ++i)\r
4287         {\r
4288                 //FileEntry * entry = GetListEntry(i);\r
4289                 //ASSERT(entry != NULL);\r
4290                 CTGitPath *path = (CTGitPath *) GetItemData(i);\r
4291                 if (path == NULL)\r
4292                         continue;\r
4293                 //if ((bIncludeNoCommits)||(entry->GetChangeList().Compare(SVNSLC_IGNORECHANGELIST)))\r
4294                 SetEntryCheck(path,i,bSelect);\r
4295         }\r
4296 \r
4297         // unblock before redrawing\r
4298         m_bBlock = FALSE;\r
4299         SetRedraw(TRUE);\r
4300         GetStatisticsString();\r
4301         NotifyCheck();\r
4302 }\r
4303 \r
4304 void CGitStatusListCtrl::OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)\r
4305 {\r
4306         LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);\r
4307         *pResult = 0;\r
4308         if (m_bBlock)\r
4309                 return;\r
4310 #if 0\r
4311         if (GetListEntry(pGetInfoTip->iItem >= 0))\r
4312                 if (pGetInfoTip->cchTextMax > GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString().GetLength())\r
4313                 {\r
4314                         if (GetListEntry(pGetInfoTip->iItem)->GetRelativeGitPath().Compare(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString())!= 0)\r
4315                                 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
4316                         else if (GetStringWidth(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString()) > GetColumnWidth(pGetInfoTip->iItem))\r
4317                                 _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
4318                 }\r
4319 #endif\r
4320 }\r
4321 \r
4322 void CGitStatusListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)\r
4323 {\r
4324         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
4325 \r
4326         // Take the default processing unless we set this to something else below.\r
4327         *pResult = CDRF_DODEFAULT;\r
4328 \r
4329         // First thing - check the draw stage. If it's the control's prepaint\r
4330         // stage, then tell Windows we want messages for every item.\r
4331 \r
4332         switch (pLVCD->nmcd.dwDrawStage)\r
4333         {\r
4334         case CDDS_PREPAINT:\r
4335                 *pResult = CDRF_NOTIFYITEMDRAW;\r
4336                 break;\r
4337         case CDDS_ITEMPREPAINT:\r
4338                 {\r
4339                         // This is the prepaint stage for an item. Here's where we set the\r
4340                         // item's text color. Our return value will tell Windows to draw the\r
4341                         // item itself, but it will use the new color we set here.\r
4342 \r
4343                         // Tell Windows to paint the control itself.\r
4344                         *pResult = CDRF_DODEFAULT;\r
4345                         if (m_bBlock)\r
4346                                 return;\r
4347 \r
4348                         COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
4349 \r
4350                         if (m_arStatusArray.size() > (DWORD_PTR)pLVCD->nmcd.dwItemSpec)\r
4351                         {\r
4352 \r
4353                                 //FileEntry * entry = GetListEntry((int)pLVCD->nmcd.dwItemSpec);\r
4354                                 CTGitPath *entry=(CTGitPath *)GetItemData((int)pLVCD->nmcd.dwItemSpec);\r
4355                                 if (entry == NULL)\r
4356                                         return;\r
4357 \r
4358                                 // coloring\r
4359                                 // ========\r
4360                                 // black  : unversioned, normal\r
4361                                 // purple : added\r
4362                                 // blue   : modified\r
4363                                 // brown  : missing, deleted, replaced\r
4364                                 // green  : merged (or potential merges)\r
4365                                 // red    : conflicts or sure conflicts\r
4366                                 if(entry->m_Action & CTGitPath::LOGACTIONS_CONFLICT)\r
4367                                 {\r
4368                                         crText = m_Colors.GetColor(CColors::Conflict);\r
4369 \r
4370                                 }else if(entry->m_Action & CTGitPath::LOGACTIONS_MODIFIED)\r
4371                                 {\r
4372                                         crText = m_Colors.GetColor(CColors::Modified);\r
4373 \r
4374                                 }else if(entry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
4375                                 {\r
4376                                         crText = m_Colors.GetColor(CColors::Added);\r
4377                                 }\r
4378                                 else if(entry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
4379                                 {\r
4380                                         crText = m_Colors.GetColor(CColors::DeletedNode);\r
4381                                 }\r
4382                                 else if(entry->m_Action & CTGitPath::LOGACTIONS_REPLACED)\r
4383                                 {\r
4384                                         crText = m_Colors.GetColor(CColors::RenamedNode);\r
4385                                 }else\r
4386                                 {\r
4387                                         crText = GetSysColor(COLOR_WINDOWTEXT);\r
4388                                 }\r
4389                                 // Store the color back in the NMLVCUSTOMDRAW struct.\r
4390                                 pLVCD->clrText = crText;\r
4391                         }\r
4392                 }\r
4393                 break;\r
4394         }\r
4395 }\r
4396 \r
4397 BOOL CGitStatusListCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
4398 {\r
4399         if (pWnd != this)\r
4400                 return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
4401         if (!m_bBlock)\r
4402         {\r
4403                 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
4404                 SetCursor(hCur);\r
4405                 return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
4406         }\r
4407         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
4408         SetCursor(hCur);\r
4409         return TRUE;\r
4410 }\r
4411 \r
4412 void CGitStatusListCtrl::RemoveListEntry(int index)\r
4413 {\r
4414 #if 0\r
4415         Locker lock(m_critSec);\r
4416         DeleteItem(index);\r
4417         delete m_arStatusArray[m_arListArray[index]];\r
4418         m_arStatusArray.erase(m_arStatusArray.begin()+m_arListArray[index]);\r
4419         m_arListArray.erase(m_arListArray.begin()+index);\r
4420         for (int i=index; i< (int)m_arListArray.size(); ++i)\r
4421         {\r
4422                 m_arListArray[i]--;\r
4423         }\r
4424 #endif\r
4425 }\r
4426 \r
4427 ///< Set a checkbox on an entry in the listbox\r
4428 // NEVER, EVER call SetCheck directly, because you'll end-up with the checkboxes and the 'checked' flag getting out of sync\r
4429 void CGitStatusListCtrl::SetEntryCheck(CTGitPath* pEntry, int listboxIndex, bool bCheck)\r
4430 {\r
4431         pEntry->m_Checked = bCheck;\r
4432         SetCheck(listboxIndex, bCheck);\r
4433 }\r
4434 \r
4435 #if 0\r
4436 void CGitStatusListCtrl::SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck)\r
4437 {\r
4438 \r
4439         int nListItems = GetItemCount();\r
4440         for (int j=0; j< nListItems ; ++j)\r
4441         {\r
4442                 FileEntry * childEntry = GetListEntry(j);\r
4443                 ASSERT(childEntry != NULL);\r
4444                 if (childEntry == NULL || childEntry == parentEntry)\r
4445                         continue;\r
4446                 if (childEntry->checked != bCheck)\r
4447                 {\r
4448                         if (parentEntry->path.IsAncestorOf(childEntry->path))\r
4449                         {\r
4450                                 SetEntryCheck(childEntry,j,bCheck);\r
4451                                 if(bCheck)\r
4452                                 {\r
4453                                         m_nSelected++;\r
4454                                 }\r
4455                                 else\r
4456                                 {\r
4457                                         m_nSelected--;\r
4458                                 }\r
4459                         }\r
4460                 }\r
4461         }\r
4462 \r
4463 }\r
4464 #endif\r
4465 \r
4466 void CGitStatusListCtrl::WriteCheckedNamesToPathList(CTGitPathList& pathList)\r
4467 {\r
4468 #if 0\r
4469         pathList.Clear();\r
4470         int nListItems = GetItemCount();\r
4471         for (int i=0; i< nListItems; i++)\r
4472         {\r
4473                 const FileEntry* entry = GetListEntry(i);\r
4474                 ASSERT(entry != NULL);\r
4475                 if (entry->IsChecked())\r
4476                 {\r
4477                         pathList.AddPath(entry->path);\r
4478                 }\r
4479         }\r
4480         pathList.SortByPathname();\r
4481 #endif\r
4482 }\r
4483 \r
4484 \r
4485 /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)\r
4486 void CGitStatusListCtrl::FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored)\r
4487 {\r
4488         pathList.Clear();\r
4489 \r
4490         POSITION pos = GetFirstSelectedItemPosition();\r
4491         int index;\r
4492         while ((index = GetNextSelectedItem(pos)) >= 0)\r
4493         {\r
4494                 CTGitPath * entry = (CTGitPath*)GetItemData(index);\r
4495                 //if ((bNoIgnored)&&(entry->status == git_wc_status_ignored))\r
4496                 //      continue;\r
4497                 pathList.AddPath(*entry);\r
4498         }\r
4499 }\r
4500 \r
4501 UINT CGitStatusListCtrl::OnGetDlgCode()\r
4502 {\r
4503         // we want to process the return key and not have that one\r
4504         // routed to the default pushbutton\r
4505         return CListCtrl::OnGetDlgCode() | DLGC_WANTALLKEYS;\r
4506 }\r
4507 \r
4508 void CGitStatusListCtrl::OnNMReturn(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
4509 {\r
4510         *pResult = 0;\r
4511         if (m_bBlock)\r
4512                 return;\r
4513         POSITION pos = GetFirstSelectedItemPosition();\r
4514         while ( pos )\r
4515         {\r
4516                 int index = GetNextSelectedItem(pos);\r
4517                 StartDiff(index);\r
4518         }\r
4519 }\r
4520 \r
4521 void CGitStatusListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\r
4522 {\r
4523         // Since we catch all keystrokes (to have the enter key processed here instead\r
4524         // of routed to the default pushbutton) we have to make sure that other\r
4525         // keys like Tab and Esc still do what they're supposed to do\r
4526         // Tab = change focus to next/previous control\r
4527         // Esc = quit the dialog\r
4528         switch (nChar)\r
4529         {\r
4530         case (VK_TAB):\r
4531                 {\r
4532                         ::PostMessage(GetParent()->GetSafeHwnd(), WM_NEXTDLGCTL, GetKeyState(VK_SHIFT)&0x8000, 0);\r
4533                         return;\r
4534                 }\r
4535                 break;\r
4536         case (VK_ESCAPE):\r
4537                 {\r
4538                         ::SendMessage(GetParent()->GetSafeHwnd(), WM_CLOSE, 0, 0);\r
4539                 }\r
4540                 break;\r
4541         }\r
4542 \r
4543         CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);\r
4544 }\r
4545 \r
4546 void CGitStatusListCtrl::PreSubclassWindow()\r
4547 {\r
4548         CListCtrl::PreSubclassWindow();\r
4549         EnableToolTips(TRUE);\r
4550         m_Theme.SetWindowTheme(GetSafeHwnd(), L"Explorer", NULL);\r
4551 }\r
4552 \r
4553 INT_PTR CGitStatusListCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const\r
4554 {\r
4555         int row, col;\r
4556         RECT cellrect;\r
4557         row = CellRectFromPoint(point, &cellrect, &col );\r
4558 \r
4559         if (row == -1)\r
4560                 return -1;\r
4561 \r
4562 \r
4563         pTI->hwnd = m_hWnd;\r
4564         pTI->uId = (UINT)((row<<10)+(col&0x3ff)+1);\r
4565         pTI->lpszText = LPSTR_TEXTCALLBACK;\r
4566 \r
4567         pTI->rect = cellrect;\r
4568 \r
4569         return pTI->uId;\r
4570 }\r
4571 \r
4572 int CGitStatusListCtrl::CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const\r
4573 {\r
4574         int colnum;\r
4575 \r
4576         // Make sure that the ListView is in LVS_REPORT\r
4577         if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)\r
4578                 return -1;\r
4579 \r
4580         // Get the top and bottom row visible\r
4581         int row = GetTopIndex();\r
4582         int bottom = row + GetCountPerPage();\r
4583         if (bottom > GetItemCount())\r
4584                 bottom = GetItemCount();\r
4585 \r
4586         // Get the number of columns\r
4587         CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);\r
4588         int nColumnCount = pHeader->GetItemCount();\r
4589 \r
4590         // Loop through the visible rows\r
4591         for ( ;row <=bottom;row++)\r
4592         {\r
4593                 // Get bounding rect of item and check whether point falls in it.\r
4594                 CRect rect;\r
4595                 GetItemRect(row, &rect, LVIR_BOUNDS);\r
4596                 if (rect.PtInRect(point))\r
4597                 {\r
4598                         // Now find the column\r
4599                         for (colnum = 0; colnum < nColumnCount; colnum++)\r
4600                         {\r
4601                                 int colwidth = GetColumnWidth(colnum);\r
4602                                 if (point.x >= rect.left && point.x <= (rect.left + colwidth))\r
4603                                 {\r
4604                                         RECT rectClient;\r
4605                                         GetClientRect(&rectClient);\r
4606                                         if (col)\r
4607                                                 *col = colnum;\r
4608                                         rect.right = rect.left + colwidth;\r
4609 \r
4610                                         // Make sure that the right extent does not exceed\r
4611                                         // the client area\r
4612                                         if (rect.right > rectClient.right)\r
4613                                                 rect.right = rectClient.right;\r
4614                                         *cellrect = rect;\r
4615                                         return row;\r
4616                                 }\r
4617                                 rect.left += colwidth;\r
4618                         }\r
4619                 }\r
4620         }\r
4621         return -1;\r
4622 }\r
4623 \r
4624 BOOL CGitStatusListCtrl::OnToolTipText(UINT /*id*/, NMHDR *pNMHDR, LRESULT *pResult)\r
4625 {\r
4626 #if 0\r
4627         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;\r
4628         CString strTipText;\r
4629         UINT_PTR nID = pNMHDR->idFrom;\r
4630 \r
4631         if (nID == 0)\r
4632                 return FALSE;\r
4633 \r
4634         UINT_PTR row = ((nID-1) >> 10) & 0x3fffff;\r
4635         UINT_PTR col = (nID-1) & 0x3ff;\r
4636 \r
4637         if (col == 0)\r
4638                 return FALSE;   // no custom tooltip for the path, we use the infotip there!\r
4639 \r
4640         // get the internal column from the visible columns\r
4641         int internalcol = 0;\r
4642         UINT_PTR currentcol = 0;\r
4643     for (;    (currentcol != col) \r
4644            && (internalcol < m_ColumnManager.GetColumnCount()-1)\r
4645          ; ++internalcol)\r
4646         {\r
4647         if (m_ColumnManager.IsVisible (internalcol))\r
4648                         currentcol++;\r
4649         }\r
4650 \r
4651         AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();\r
4652         CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip;\r
4653         pToolTip->SendMessage(TTM_SETMAXTIPWIDTH, 0, 300);\r
4654 \r
4655         *pResult = 0;\r
4656         if ((internalcol == 2)||(internalcol == 4))\r
4657         {\r
4658                 FileEntry *fentry = GetListEntry(row);\r
4659                 if (fentry)\r
4660                 {\r
4661                         if (fentry->copied)\r
4662                         {\r
4663                                 CString url;\r
4664                                 url.Format(IDS_STATUSLIST_COPYFROM, (LPCTSTR)CPathUtils::PathUnescape(fentry->copyfrom_url), (LONG)fentry->copyfrom_rev);\r
4665                                 lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
4666                                 return TRUE;\r
4667                         }\r
4668                         if (fentry->switched)\r
4669                         {\r
4670                                 CString url;\r
4671                                 url.Format(IDS_STATUSLIST_SWITCHEDTO, (LPCTSTR)CPathUtils::PathUnescape(fentry->url));\r
4672                                 lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
4673                                 return TRUE;\r
4674                         }\r
4675                         if (fentry->keeplocal)\r
4676                         {\r
4677                                 lstrcpyn(pTTTW->szText, (LPCTSTR)CString(MAKEINTRESOURCE(IDS_STATUSLIST_KEEPLOCAL)), 80);\r
4678                                 return TRUE;\r
4679                         }\r
4680                 }\r
4681         }\r
4682 #endif\r
4683         return FALSE;\r
4684 }\r
4685 \r
4686 void CGitStatusListCtrl::OnPaint()\r
4687 {\r
4688         Default();\r
4689         if ((m_bBusy)||(m_bEmpty))\r
4690         {\r
4691                 CString str;\r
4692                 if (m_bBusy)\r
4693                 {\r
4694                         if (m_sBusy.IsEmpty())\r
4695                                 str.LoadString(IDS_STATUSLIST_BUSYMSG);\r
4696                         else\r
4697                                 str = m_sBusy;\r
4698                 }\r
4699                 else\r
4700                 {\r
4701                         if (m_sEmpty.IsEmpty())\r
4702                                 str.LoadString(IDS_STATUSLIST_EMPTYMSG);\r
4703                         else\r
4704                                 str = m_sEmpty;\r
4705                 }\r
4706                 COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);\r
4707                 COLORREF clrTextBk;\r
4708                 if (IsWindowEnabled())\r
4709                         clrTextBk = ::GetSysColor(COLOR_WINDOW);\r
4710                 else\r
4711                         clrTextBk = ::GetSysColor(COLOR_3DFACE);\r
4712 \r
4713                 CRect rc;\r
4714                 GetClientRect(&rc);\r
4715                 CHeaderCtrl* pHC;\r
4716                 pHC = GetHeaderCtrl();\r
4717                 if (pHC != NULL)\r
4718                 {\r
4719                         CRect rcH;\r
4720                         pHC->GetItemRect(0, &rcH);\r
4721                         rc.top += rcH.bottom;\r
4722                 }\r
4723                 CDC* pDC = GetDC();\r
4724                 {\r
4725                         CMyMemDC memDC(pDC, &rc);\r
4726 \r
4727                         memDC.SetTextColor(clrText);\r
4728                         memDC.SetBkColor(clrTextBk);\r
4729                         memDC.FillSolidRect(rc, clrTextBk);\r
4730                         rc.top += 10;\r
4731                         CGdiObject * oldfont = memDC.SelectStockObject(DEFAULT_GUI_FONT);\r
4732                         memDC.DrawText(str, rc, DT_CENTER | DT_VCENTER |\r
4733                                 DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);\r
4734                         memDC.SelectObject(oldfont);\r
4735                 }\r
4736                 ReleaseDC(pDC);\r
4737         }\r
4738 }\r
4739 \r
4740 // prevent users from extending our hidden (size 0) columns\r
4741 void CGitStatusListCtrl::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)\r
4742 {\r
4743         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
4744         *pResult = 0;\r
4745         if ((phdr->iItem < 0)||(phdr->iItem >= SVNSLC_NUMCOLUMNS))\r
4746                 return;\r
4747 \r
4748     if (m_ColumnManager.IsVisible (phdr->iItem))\r
4749         {\r
4750                 return;\r
4751         }\r
4752         *pResult = 1;\r
4753 }\r
4754 \r
4755 // prevent any function from extending our hidden (size 0) columns\r
4756 void CGitStatusListCtrl::OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
4757 {\r
4758         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
4759         *pResult = 0;\r
4760     if ((phdr->iItem < 0)||(phdr->iItem >= m_ColumnManager.GetColumnCount()))\r
4761         {\r
4762                 Default();\r
4763                 return;\r
4764         }\r
4765 \r
4766     // visible columns may be modified \r
4767 \r
4768     if (m_ColumnManager.IsVisible (phdr->iItem))\r
4769         {\r
4770                 Default();\r
4771                 return;\r
4772         }\r
4773 \r
4774     // columns already marked as "invisible" internally may be (re-)sized to 0\r
4775 \r
4776     if (   (phdr->pitem != NULL) \r
4777         && (phdr->pitem->mask == HDI_WIDTH)\r
4778         && (phdr->pitem->cxy == 0))\r
4779         {\r
4780                 Default();\r
4781                 return;\r
4782         }\r
4783 \r
4784         if (   (phdr->pitem != NULL) \r
4785                 && (phdr->pitem->mask != HDI_WIDTH))\r
4786         {\r
4787                 Default();\r
4788                 return;\r
4789         }\r
4790 \r
4791     *pResult = 1;\r
4792 }\r
4793 \r
4794 void CGitStatusListCtrl::OnDestroy()\r
4795 {\r
4796         SaveColumnWidths(true);\r
4797         CListCtrl::OnDestroy();\r
4798 }\r
4799 \r
4800 void CGitStatusListCtrl::OnBeginDrag(NMHDR* /*pNMHDR*/, LRESULT* pResult)\r
4801 {\r
4802 #if 0\r
4803         Locker lock(m_critSec);\r
4804         CDropFiles dropFiles; // class for creating DROPFILES struct\r
4805 \r
4806         int index;\r
4807         POSITION pos = GetFirstSelectedItemPosition();\r
4808         while ( (index = GetNextSelectedItem(pos)) >= 0 )\r
4809         {\r
4810                 FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
4811                 CTGitPath path = fentry->GetPath();\r
4812                 dropFiles.AddFile( path.GetWinPathString() );\r
4813         }\r
4814 \r
4815         if ( dropFiles.GetCount()>0 )\r
4816         {\r
4817                 m_bOwnDrag = true;\r
4818                 dropFiles.CreateStructure();\r
4819                 m_bOwnDrag = false;\r
4820         }\r
4821 #endif\r
4822         *pResult = 0;\r
4823 }\r
4824 \r
4825 void CGitStatusListCtrl::SaveColumnWidths(bool bSaveToRegistry /* = false */)\r
4826 {\r
4827         int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
4828         for (int col = 0; col <= maxcol; col++)\r
4829         if (m_ColumnManager.IsVisible (col))\r
4830             m_ColumnManager.ColumnResized (col);\r
4831 \r
4832         if (bSaveToRegistry)\r
4833         m_ColumnManager.WriteSettings();\r
4834 }\r
4835 \r
4836 bool CGitStatusListCtrl::EnableFileDrop()\r
4837 {\r
4838         m_bFileDropsEnabled = true;\r
4839         return true;\r
4840 }\r
4841 \r
4842 bool CGitStatusListCtrl::HasPath(const CTGitPath& path)\r
4843 {\r
4844 #if 0\r
4845         for (size_t i=0; i < m_arStatusArray.size(); i++)\r
4846         {\r
4847                 FileEntry * entry = m_arStatusArray[i];\r
4848                 if (entry->GetPath().IsEquivalentTo(path))\r
4849                         return true;\r
4850         }\r
4851 #endif\r
4852         return false;\r
4853 }\r
4854 \r
4855 bool CGitStatusListCtrl::IsPathShown(const CTGitPath& path)\r
4856 {\r
4857 #if 0\r
4858         int itemCount = GetItemCount();\r
4859         for (int i=0; i < itemCount; i++)\r
4860         {\r
4861                 FileEntry * entry = GetListEntry(i);\r
4862                 if (entry->GetPath().IsEquivalentTo(path))\r
4863                         return true;\r
4864         }\r
4865 #endif\r
4866         return false;\r
4867 }\r
4868 \r
4869 BOOL CGitStatusListCtrl::PreTranslateMessage(MSG* pMsg)\r
4870 {\r
4871         if (pMsg->message == WM_KEYDOWN)\r
4872         {\r
4873                 switch (pMsg->wParam)\r
4874                 {\r
4875                 case 'A':\r
4876                         {\r
4877                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
4878                                 {\r
4879                                         // select all entries\r
4880                                         for (int i=0; i<GetItemCount(); ++i)\r
4881                                         {\r
4882                                                 SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
4883                                         }\r
4884                                         return TRUE;\r
4885                                 }\r
4886                         }\r
4887                         break;\r
4888                 case 'C':\r
4889                 case VK_INSERT:\r
4890                         {\r
4891                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
4892                                 {\r
4893                                         // copy all selected paths to the clipboard\r
4894                                         if (GetAsyncKeyState(VK_SHIFT)&0x8000)\r
4895                                                 CopySelectedEntriesToClipboard(SVNSLC_COLSTATUS);\r
4896                                         else\r
4897                                                 CopySelectedEntriesToClipboard(0);\r
4898                                         return TRUE;\r
4899                                 }\r
4900                         }\r
4901                         break;\r
4902                 }\r
4903         }\r
4904 \r
4905         return CListCtrl::PreTranslateMessage(pMsg);\r
4906 }\r
4907 \r
4908 bool CGitStatusListCtrl::CopySelectedEntriesToClipboard(DWORD dwCols)\r
4909 {\r
4910 #if 0\r
4911         static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
4912         static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
4913         WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
4914 \r
4915         CString sClipboard;\r
4916         CString temp;\r
4917         TCHAR buf[100];\r
4918         if (GetSelectedCount() == 0)\r
4919                 return false;\r
4920         // first add the column titles as the first line\r
4921         temp.LoadString(IDS_STATUSLIST_COLFILE);\r
4922         sClipboard = temp;\r
4923 \r
4924     DWORD selection = 0;\r
4925     for (int i = 0, count = m_ColumnManager.GetColumnCount(); i < count; ++i)\r
4926         if (   ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
4927             || ((dwCols != 1) && (i < 32) && ((dwCols & (1 << i)) != 0)))\r
4928         {\r
4929             sClipboard += _T("\t") + m_ColumnManager.GetName(i);\r
4930 \r
4931             if (i < 32)\r
4932                 selection += 1 << i;\r
4933         }\r
4934 \r
4935         sClipboard += _T("\r\n");\r
4936 \r
4937         POSITION pos = GetFirstSelectedItemPosition();\r
4938         int index;\r
4939         while ((index = GetNextSelectedItem(pos)) >= 0)\r
4940         {\r
4941                 FileEntry * entry = GetListEntry(index);\r
4942                 sClipboard += entry->GetDisplayName();\r
4943                 if (selection & SVNSLC_COLFILENAME)\r
4944                 {\r
4945                         sClipboard += _T("\t")+entry->path.GetFileOrDirectoryName();\r
4946                 }\r
4947                 if (selection & SVNSLC_COLEXT)\r
4948                 {\r
4949                         sClipboard += _T("\t")+entry->path.GetFileExtension();\r
4950                 }\r
4951                 if (selection & SVNSLC_COLSTATUS)\r
4952                 {\r
4953                         if (entry->isNested)\r
4954                         {\r
4955                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4956                         }\r
4957                         else\r
4958                         {\r
4959                                 GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4960                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4961                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4962                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4963                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4964                                 if ((entry->status == entry->propstatus)&&\r
4965                                         (entry->status != git_wc_status_normal)&&\r
4966                                         (entry->status != git_wc_status_unversioned)&&\r
4967                                         (!GitStatus::IsImportant(entry->textstatus)))\r
4968                                         _tcscat_s(buf, 100, ponly);\r
4969                                 temp = buf;\r
4970                         }\r
4971                         sClipboard += _T("\t")+temp;\r
4972                 }\r
4973                 if (selection & SVNSLC_COLTEXTSTATUS)\r
4974                 {\r
4975                         if (entry->isNested)\r
4976                         {\r
4977                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4978                         }\r
4979                         else\r
4980                         {\r
4981                                 GitStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4982                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
4983                                         _tcscat_s(buf, 100, _T(" (+)"));\r
4984                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
4985                                         _tcscat_s(buf, 100, _T(" (s)"));\r
4986                                 temp = buf;\r
4987                         }\r
4988                         sClipboard += _T("\t")+temp;\r
4989                 }\r
4990                 if (selection & SVNSLC_COLREMOTESTATUS)\r
4991                 {\r
4992                         if (entry->isNested)\r
4993                         {\r
4994                                 temp.LoadString(IDS_STATUSLIST_NESTED);\r
4995                         }\r
4996                         else\r
4997                         {\r
4998                                 GitStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
4999                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
5000                                         _tcscat_s(buf, 100, _T(" (+)"));\r
5001                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
5002                                         _tcscat_s(buf, 100, _T(" (s)"));\r
5003                                 if ((entry->remotestatus == entry->remotepropstatus)&&\r
5004                                         (entry->remotestatus != git_wc_status_none)&&\r
5005                                         (entry->remotestatus != git_wc_status_normal)&&\r
5006                                         (entry->remotestatus != git_wc_status_unversioned)&&\r
5007                                         (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
5008                                         _tcscat_s(buf, 100, ponly);\r
5009                                 temp = buf;\r
5010                         }\r
5011                         sClipboard += _T("\t")+temp;\r
5012                 }\r
5013                 if (selection & GitSLC_COLPROPSTATUS)\r
5014                 {\r
5015                         if (entry->isNested)\r
5016                         {\r
5017                                 temp.Empty();\r
5018                         }\r
5019                         else\r
5020                         {\r
5021                                 GitStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
5022                                 if ((entry->copied)&&(_tcslen(buf)>1))\r
5023                                         _tcscat_s(buf, 100, _T(" (+)"));\r
5024                                 if ((entry->switched)&&(_tcslen(buf)>1))\r
5025                                         _tcscat_s(buf, 100, _T(" (s)"));\r
5026                                 temp = buf;\r
5027                         }\r
5028                         sClipboard += _T("\t")+temp;\r
5029                 }\r
5030                 if (selection & SVNSLC_COLREMOTETEXT)\r
5031                 {\r
5032                         if (entry->isNested)\r
5033                         {\r
5034                                 temp.Empty();\r
5035                         }\r
5036                         else\r
5037                         {\r
5038                                 GitStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
5039                                 temp = buf;\r
5040                         }\r
5041                         sClipboard += _T("\t")+temp;\r
5042                 }\r
5043                 if (selection & SVNSLC_COLREMOTEPROP)\r
5044                 {\r
5045                         // SVNSLC_COLREMOTEPROP\r
5046                         if (entry->isNested)\r
5047                         {\r
5048                                 temp.Empty();\r
5049                         }\r
5050                         else\r
5051                         {\r
5052                                 GitStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
5053                                 temp = buf;\r
5054                         }\r
5055                         sClipboard += _T("\t")+temp;\r
5056                 }\r
5057                 if (selection & SVNSLC_COLURL)\r
5058                         sClipboard += _T("\t")+entry->url;\r
5059                 if (selection & SVNSLC_COLLOCK)\r
5060                 {\r
5061                         if (!m_HeadRev.IsHead())\r
5062                         {\r
5063                                 // we have contacted the repository\r
5064 \r
5065                                 // decision-matrix\r
5066                                 // wc           repository              text\r
5067                                 // ""           ""                              ""\r
5068                                 // ""           UID1                    owner\r
5069                                 // UID1         UID1                    owner\r
5070                                 // UID1         ""                              lock has been broken\r
5071                                 // UID1         UID2                    lock has been stolen\r
5072                                 if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
5073                                 {\r
5074                                         if (entry->lock_owner.IsEmpty())\r
5075                                                 temp = entry->lock_remoteowner;\r
5076                                         else\r
5077                                                 temp = entry->lock_owner;\r
5078                                 }\r
5079                                 else if (entry->lock_remotetoken.IsEmpty())\r
5080                                 {\r
5081                                         // broken lock\r
5082                                         temp.LoadString(IDS_STATUSLIST_LOCKBROKEN);\r
5083                                 }\r
5084                                 else\r
5085                                 {\r
5086                                         // stolen lock\r
5087                                         temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
5088                                 }\r
5089                         }\r
5090                         else\r
5091                                 temp = entry->lock_owner;\r
5092                         sClipboard += _T("\t")+temp;\r
5093                 }\r
5094                 if (selection & SVNSLC_COLLOCKCOMMENT)\r
5095                         sClipboard += _T("\t")+entry->lock_comment;\r
5096                 if (selection & SVNSLC_COLAUTHOR)\r
5097                         sClipboard += _T("\t")+entry->last_commit_author;\r
5098                 if (selection & SVNSLC_COLREVISION)\r
5099                 {\r
5100                         temp.Format(_T("%ld"), entry->last_commit_rev);\r
5101                         if (entry->last_commit_rev == 0)\r
5102                                 temp.Empty();\r
5103                         sClipboard += _T("\t")+temp;\r
5104                 }\r
5105                 if (selection & SVNSLC_COLREMOTEREVISION)\r
5106                 {\r
5107                         temp.Format(_T("%ld"), entry->remoterev);\r
5108                         if (entry->remoterev == 0)\r
5109                                 temp.Empty();\r
5110                         sClipboard += _T("\t")+temp;\r
5111                 }\r
5112                 if (selection & SVNSLC_COLDATE)\r
5113                 {\r
5114                         TCHAR datebuf[SVN_DATE_BUFFER];\r
5115                         apr_time_t date = entry->last_commit_date;\r
5116                         SVN::formatDate(datebuf, date, true);\r
5117                         if (date)\r
5118                                 temp = datebuf;\r
5119                         else\r
5120                                 temp.Empty();\r
5121                         sClipboard += _T("\t")+temp;\r
5122                 }\r
5123                 if (selection & SVNSLC_COLCOPYFROM)\r
5124                 {\r
5125                         if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
5126                                 temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
5127                         else\r
5128                                 temp = entry->copyfrom_url;\r
5129                         sClipboard += _T("\t")+temp;\r
5130                 }\r
5131 \r
5132         for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
5133             ; i < count\r
5134             ; ++i)\r
5135         {\r
5136             if ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
5137             {\r
5138                 CString value \r
5139                     = entry->present_props[m_ColumnManager.GetName(i)];\r
5140                 sClipboard += _T("\t") + value;\r
5141             }\r
5142         }\r
5143 \r
5144                 sClipboard += _T("\r\n");\r
5145         }\r
5146 \r
5147         return CStringUtils::WriteAsciiStringToClipboard(sClipboard);\r
5148 #endif\r
5149         return TRUE;\r
5150 \r
5151 }\r
5152 \r
5153 size_t CGitStatusListCtrl::GetNumberOfChangelistsInSelection()\r
5154 {\r
5155 #if 0\r
5156         std::set<CString> changelists;\r
5157         POSITION pos = GetFirstSelectedItemPosition();\r
5158         int index;\r
5159         while ((index = GetNextSelectedItem(pos)) >= 0)\r
5160         {\r
5161                 FileEntry * entry = GetListEntry(index);\r
5162                 if (!entry->changelist.IsEmpty())\r
5163                         changelists.insert(entry->changelist);\r
5164         }\r
5165         return changelists.size();\r
5166 #endif \r
5167         return 0;\r
5168 }\r
5169 \r
5170 bool CGitStatusListCtrl::PrepareGroups(bool bForce /* = false */)\r
5171 {\r
5172 \r
5173         bool bHasGroups=false;\r
5174         if ( this->m_UnRevFileList.GetCount()>0 || \r
5175                 this->m_IgnoreFileList.GetCount()>0 || bForce)\r
5176         {\r
5177                 bHasGroups = true;\r
5178         }\r
5179 \r
5180         RemoveAllGroups();\r
5181         EnableGroupView(bHasGroups);\r
5182         \r
5183         TCHAR groupname[1024];\r
5184         int groupindex = 0;\r
5185 \r
5186         if(bHasGroups);\r
5187         {\r
5188                 LVGROUP grp = {0};\r
5189                 grp.cbSize = sizeof(LVGROUP);\r
5190                 grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5191                 CString sUnassignedName(_T("Modified File"));\r
5192                 _tcsncpy_s(groupname, 1024, (LPCTSTR)sUnassignedName, 1023);\r
5193                 grp.pszHeader = groupname;\r
5194                 grp.iGroupId = groupindex;\r
5195                 grp.uAlign = LVGA_HEADER_LEFT;\r
5196                 InsertGroup(groupindex++, &grp);\r
5197 \r
5198                 //if(m_UnRevFileList.GetCount()>0)\r
5199                 {\r
5200                         _tcsncpy_s(groupname, 1024, (LPCTSTR)_T("No Version Control"), 1023);\r
5201                         grp.pszHeader = groupname;\r
5202                         grp.iGroupId = groupindex;\r
5203                         grp.uAlign = LVGA_HEADER_LEFT;\r
5204                         InsertGroup(groupindex++, &grp);\r
5205                 }\r
5206 \r
5207                 //if(m_IgnoreFileList.GetCount()>0)\r
5208                 {\r
5209                         _tcsncpy_s(groupname, 1024, (LPCTSTR)_T("Ignored File"), 1023);\r
5210                         grp.pszHeader = groupname;\r
5211                         grp.iGroupId = groupindex;\r
5212                         grp.uAlign = LVGA_HEADER_LEFT;\r
5213                         InsertGroup(groupindex++, &grp);\r
5214                 }\r
5215 \r
5216         }\r
5217 \r
5218 \r
5219         m_bHasIgnoreGroup = false;\r
5220 \r
5221         // now add the items which don't belong to a group\r
5222         LVGROUP grp = {0};\r
5223         grp.cbSize = sizeof(LVGROUP);\r
5224         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5225         CString sUnassignedName(MAKEINTRESOURCE(IDS_STATUSLIST_UNASSIGNED_CHANGESET));\r
5226         _tcsncpy_s(groupname, 1024, (LPCTSTR)sUnassignedName, 1023);\r
5227         grp.pszHeader = groupname;\r
5228         grp.iGroupId = groupindex;\r
5229         grp.uAlign = LVGA_HEADER_LEFT;\r
5230         InsertGroup(groupindex++, &grp);\r
5231 \r
5232         for (std::map<CString,int>::iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
5233         {\r
5234                 if (it->first.Compare(SVNSLC_IGNORECHANGELIST)!=0)\r
5235                 {\r
5236                         LVGROUP grp = {0};\r
5237                         grp.cbSize = sizeof(LVGROUP);\r
5238                         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5239                         _tcsncpy_s(groupname, 1024, it->first, 1023);\r
5240                         grp.pszHeader = groupname;\r
5241                         grp.iGroupId = groupindex;\r
5242                         grp.uAlign = LVGA_HEADER_LEFT;\r
5243                         it->second = InsertGroup(groupindex++, &grp);\r
5244                 }\r
5245                 else\r
5246                         m_bHasIgnoreGroup = true;\r
5247         }\r
5248 \r
5249         if (m_bHasIgnoreGroup)\r
5250         {\r
5251                 // and now add the group 'ignore-on-commit'\r
5252                 std::map<CString,int>::iterator it = m_changelists.find(SVNSLC_IGNORECHANGELIST);\r
5253                 if (it != m_changelists.end())\r
5254                 {\r
5255                         grp.cbSize = sizeof(LVGROUP);\r
5256                         grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
5257                         _tcsncpy_s(groupname, 1024, SVNSLC_IGNORECHANGELIST, 1023);\r
5258                         grp.pszHeader = groupname;\r
5259                         grp.iGroupId = groupindex;\r
5260                         grp.uAlign = LVGA_HEADER_LEFT;\r
5261                         it->second = InsertGroup(groupindex, &grp);\r
5262                 }\r
5263         }\r
5264 \r
5265         return bHasGroups;\r
5266 }\r
5267 \r
5268 void CGitStatusListCtrl::NotifyCheck()\r
5269 {\r
5270         CWnd* pParent = GetParent();\r
5271         if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
5272         {\r
5273                 pParent->SendMessage(SVNSLNM_CHECKCHANGED, m_nSelected);\r
5274         }\r
5275 }\r
5276 \r
5277 int CGitStatusListCtrl::UpdateFileList(git_revnum_t hash,CTGitPathList *list)\r
5278 {\r
5279         CString out;\r
5280         this->m_bBusy=TRUE;\r
5281         m_CurrentVersion=hash;\r
5282 \r
5283         if(hash == GIT_REV_ZERO)\r
5284         {\r
5285                 int count = 0;\r
5286                 if(list == NULL)\r
5287                         count = 1;\r
5288                 else\r
5289                         count = list->GetCount();\r
5290 \r
5291                 for(int i=0;i<count;i++)\r
5292                 {       \r
5293                         CString cmdout;\r
5294                         CString cmd;\r
5295                         if(list == NULL)\r
5296                                 cmd=(_T("git.exe diff-index --raw HEAD --numstat -C -M"));\r
5297                         else\r
5298                                 cmd.Format(_T("git.exe diff-index --raw HEAD --numstat -C -M -- \"%s\""),(*list)[i].GetGitPathString());\r
5299 \r
5300                         if(g_Git.Run(cmd,&cmdout))\r
5301                         {\r
5302                                 cmdout.Empty();\r
5303                                 if(g_Git.Run(_T("git.exe rev-parse --revs-only HEAD"),&cmdout))\r
5304                                 {\r
5305                                         CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
5306                                         return -1;\r
5307                                 }\r
5308                                 if(cmdout.IsEmpty())\r
5309                                         break; //this is initial repositoyr, there are no any history\r
5310 \r
5311                                 CMessageBox::Show(NULL,cmdout,_T("TortoiseGit"),MB_OK);\r
5312                                 return -1;\r
5313 \r
5314                         }\r
5315 \r
5316                         out+=cmdout;\r
5317                 }\r
5318 \r
5319 \r
5320                 this->m_StatusFileList.ParserFromLog(out);\r
5321         }else\r
5322         {\r
5323                 int count = 0;\r
5324                 if(list == NULL)\r
5325                         count = 1;\r
5326                 else\r
5327                         count = list->GetCount();\r
5328 \r
5329                 for(int i=0;i<count;i++)\r
5330                 {       \r
5331                         CString cmdout;\r
5332                         CString cmd;\r
5333                         if(list == NULL)\r
5334                                 cmd.Format(_T("git.exe diff-tree --raw --numstat -C -M %s"),hash);\r
5335                         else\r
5336                                 cmd.Format(_T("git.exe diff-tree --raw  --numstat -C -M %s -- \"%s\""),hash,(*list)[i].GetGitPathString());\r
5337 \r
5338                         g_Git.Run(cmd,&cmdout);\r
5339 \r
5340                         out+=cmdout;\r
5341                 }\r
5342                 this->m_StatusFileList.ParserFromLog(out);\r
5343 \r
5344         }\r
5345         for(int i=0;i<m_StatusFileList.GetCount();i++)\r
5346         {\r
5347                 CTGitPath * gitpatch=(CTGitPath*)&m_StatusFileList[i];\r
5348                 gitpatch->m_Checked = TRUE;\r
5349                 m_arStatusArray.push_back((CTGitPath*)&m_StatusFileList[i]);\r
5350         }\r
5351         this->m_bBusy=FALSE;\r
5352         return 0;\r
5353 }\r
5354 \r
5355 int CGitStatusListCtrl::UpdateWithGitPathList(CTGitPathList &list)\r
5356 {\r
5357         m_arStatusArray.clear();\r
5358         for(int i=0;i<list.GetCount();i++)\r
5359         {\r
5360                 CTGitPath * gitpatch=(CTGitPath*)&list[i];\r
5361                 gitpatch->m_Checked = TRUE;\r
5362                 m_arStatusArray.push_back((CTGitPath*)&list[i]);\r
5363         }\r
5364         return 0;\r
5365 }\r
5366 \r
5367 int CGitStatusListCtrl::UpdateUnRevFileList(CTGitPathList *List)\r
5368 {\r
5369         this->m_UnRevFileList.FillUnRev(CTGitPath::LOGACTIONS_UNVER,List);\r
5370         for(int i=0;i<m_UnRevFileList.GetCount();i++)\r
5371         {\r
5372                 CTGitPath * gitpatch=(CTGitPath*)&m_UnRevFileList[i];\r
5373                 gitpatch->m_Checked = FALSE;\r
5374                 m_arStatusArray.push_back((CTGitPath*)&m_UnRevFileList[i]);\r
5375         }\r
5376         return 0;\r
5377 }\r
5378 \r
5379 int CGitStatusListCtrl::UpdateIgnoreFileList(CTGitPathList *List)\r
5380 {\r
5381         this->m_IgnoreFileList.FillUnRev(CTGitPath::LOGACTIONS_UNVER|CTGitPath::LOGACTIONS_IGNORE,List);\r
5382         for(int i=0;i<m_IgnoreFileList.GetCount();i++)\r
5383         {\r
5384                 CTGitPath * gitpatch=(CTGitPath*)&m_IgnoreFileList[i];\r
5385                 gitpatch->m_Checked = FALSE;\r
5386                 m_arStatusArray.push_back((CTGitPath*)&m_IgnoreFileList[i]);\r
5387         }\r
5388         return 0;\r
5389 }\r
5390 int CGitStatusListCtrl::UpdateFileList(int mask,bool once,CTGitPathList *List)\r
5391 {\r
5392         if(mask&CGitStatusListCtrl::FILELIST_MODIFY)\r
5393         {\r
5394                 if(once || (!(m_FileLoaded&CGitStatusListCtrl::FILELIST_MODIFY)))\r
5395                 {\r
5396                         UpdateFileList(git_revnum_t(GIT_REV_ZERO),List);\r
5397                         m_FileLoaded|=CGitStatusListCtrl::FILELIST_MODIFY;\r
5398                 }\r
5399         }\r
5400         if(mask&CGitStatusListCtrl::FILELIST_UNVER)\r
5401         {\r
5402                 if(once || (!(m_FileLoaded&CGitStatusListCtrl::FILELIST_UNVER)))\r
5403                 {\r
5404                         UpdateUnRevFileList(List);\r
5405                         m_FileLoaded|=CGitStatusListCtrl::FILELIST_UNVER;\r
5406                 }\r
5407         }\r
5408         return 0;\r
5409 }\r
5410 //////////////////////////////////////////////////////////////////////////\r
5411 #if 0\r
5412 bool CGitStatusListCtrlDropTarget::OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt)\r
5413 {\r
5414         if(pFmtEtc->cfFormat == CF_HDROP && medium.tymed == TYMED_HGLOBAL)\r
5415         {\r
5416                 HDROP hDrop = (HDROP)GlobalLock(medium.hGlobal);\r
5417                 if(hDrop != NULL)\r
5418                 {\r
5419                         TCHAR szFileName[MAX_PATH];\r
5420 \r
5421                         UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);\r
5422 \r
5423                         POINT clientpoint;\r
5424                         clientpoint.x = pt.x;\r
5425                         clientpoint.y = pt.y;\r
5426                         ScreenToClient(m_hTargetWnd, &clientpoint);\r
5427                         if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
5428                         {\r
5429                                 CTSVNPathList changelistItems;\r
5430                                 for(UINT i = 0; i < cFiles; ++i)\r
5431                                 {\r
5432                                         DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
5433                                         changelistItems.AddPath(CTSVNPath(szFileName));\r
5434                                 }\r
5435                                 // find the changelist name\r
5436                                 CString sChangelist;\r
5437                                 LONG_PTR nGroup = m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint);\r
5438                                 for (std::map<CString, int>::iterator it = m_pSVNStatusListCtrl->m_changelists.begin(); it != m_pSVNStatusListCtrl->m_changelists.end(); ++it)\r
5439                                         if (it->second == nGroup)\r
5440                                                 sChangelist = it->first;\r
5441                                 if (!sChangelist.IsEmpty())\r
5442                                 {\r
5443                                         SVN git;\r
5444                                         if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
5445                                         {\r
5446                                                 for (int l=0; l<changelistItems.GetCount(); ++l)\r
5447                                                 {\r
5448                                                         int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
5449                                                         if (index >= 0)\r
5450                                                         {\r
5451                                                                 CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
5452                                                                 if (e)\r
5453                                                                 {\r
5454                                                                         e->changelist = sChangelist;\r
5455                                                                         if (!e->IsFolder())\r
5456                                                                         {\r
5457                                                                                 if (m_pSVNStatusListCtrl->m_changelists.find(e->changelist)!=m_pSVNStatusListCtrl->m_changelists.end())\r
5458                                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, m_pSVNStatusListCtrl->m_changelists[e->changelist]);\r
5459                                                                                 else\r
5460                                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
5461                                                                         }\r
5462                                                                 }\r
5463                                                         }\r
5464                                                         else\r
5465                                                         {\r
5466                                                                 HWND hParentWnd = GetParent(m_hTargetWnd);\r
5467                                                                 if (hParentWnd != NULL)\r
5468                                                                         ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
5469                                                         }\r
5470                                                 }\r
5471                                         }\r
5472                                         else\r
5473                                         {\r
5474                                                 CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
5475                                         }\r
5476                                 }\r
5477                                 else\r
5478                                 {\r
5479                                         SVN git;\r
5480                                         if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
5481                                         {\r
5482                                                 for (int l=0; l<changelistItems.GetCount(); ++l)\r
5483                                                 {\r
5484                                                         int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
5485                                                         if (index >= 0)\r
5486                                                         {\r
5487                                                                 CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
5488                                                                 if (e)\r
5489                                                                 {\r
5490                                                                         e->changelist = sChangelist;\r
5491                                                                         m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
5492                                                                 }\r
5493                                                         }\r
5494                                                         else\r
5495                                                         {\r
5496                                                                 HWND hParentWnd = GetParent(m_hTargetWnd);\r
5497                                                                 if (hParentWnd != NULL)\r
5498                                                                         ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
5499                                                         }\r
5500                                                 }\r
5501                                         }\r
5502                                         else\r
5503                                         {\r
5504                                                 CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
5505                                         }\r
5506                                 }\r
5507                         }\r
5508                         else\r
5509                         {\r
5510                                 for(UINT i = 0; i < cFiles; ++i)\r
5511                                 {\r
5512                                         DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
5513                                         HWND hParentWnd = GetParent(m_hTargetWnd);\r
5514                                         if (hParentWnd != NULL)\r
5515                                                 ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)szFileName);\r
5516                                 }\r
5517                         }\r
5518                 }\r
5519                 GlobalUnlock(medium.hGlobal);\r
5520         }\r
5521         return true; //let base free the medium\r
5522 }\r
5523 HRESULT STDMETHODCALLTYPE CSVNStatusListCtrlDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect)\r
5524 {\r
5525         CIDropTarget::DragOver(grfKeyState, pt, pdwEffect);\r
5526         *pdwEffect = DROPEFFECT_COPY;\r
5527         if (m_pSVNStatusListCtrl)\r
5528         {\r
5529                 POINT clientpoint;\r
5530                 clientpoint.x = pt.x;\r
5531                 clientpoint.y = pt.y;\r
5532                 ScreenToClient(m_hTargetWnd, &clientpoint);\r
5533                 if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
5534                 {\r
5535                         *pdwEffect = DROPEFFECT_MOVE;\r
5536                 }\r
5537                 else if ((!m_pSVNStatusListCtrl->m_bFileDropsEnabled)||(m_pSVNStatusListCtrl->m_bOwnDrag))\r
5538                 {\r
5539                         *pdwEffect = DROPEFFECT_NONE;\r
5540                 }\r
5541         }\r
5542         return S_OK;\r
5543 }f\r
5544 \r
5545 #endif