OSDN Git Service

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