OSDN Git Service

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