OSDN Git Service

GitStatusListCtrl port build complete
authorFrank Li <lznuaa@gmail.com>
Thu, 13 Nov 2008 05:39:04 +0000 (13:39 +0800)
committerFrank Li <lznuaa@gmail.com>
Thu, 13 Nov 2008 05:39:04 +0000 (13:39 +0800)
27 files changed:
Git/Git.cpp [new file with mode: 0644]
Git/Git.h [new file with mode: 0644]
Git/Git.rc [new file with mode: 0644]
Git/Git.vcproj
Git/GitConfig.cpp [new file with mode: 0644]
Git/GitConfig.h [new file with mode: 0644]
Git/GitRev.h
Git/GitStatus.h
Git/GitStatusListCtrl.cpp
Git/GitStatusListCtrl.h
TortoiseProc/AppUtils.cpp
TortoiseProc/AppUtils.h
TortoiseProc/CommitDlg.cpp
TortoiseProc/CommitDlg.h
TortoiseProc/GitStatusListCtrlHelpers.cpp [new file with mode: 0644]
TortoiseProc/InputDlg.h
TortoiseProc/LogDlg.h
TortoiseProc/LogDlgHelper.h
TortoiseProc/RepositoryBar.h
TortoiseProc/RepositoryBrowser.h
TortoiseProc/TortoiseProc.cpp
TortoiseProc/TortoiseProc.vcproj
TortoiseShell/TortoiseShell.suo
Utils/TempFile.h
Utils/resource.rc [new file with mode: 0644]
ext/hunspell/license.hunspell [new file with mode: 0644]
ext/hunspell/license.myspell [new file with mode: 0644]

diff --git a/Git/Git.cpp b/Git/Git.cpp
new file mode 100644 (file)
index 0000000..b830215
--- /dev/null
@@ -0,0 +1,79 @@
+#include "StdAfx.h"\r
+#include "Git.h"\r
+#include "atlconv.h"\r
+#include "afx.h"\r
+\r
+CGit::CGit(void)\r
+{\r
+}\r
+\r
+CGit::~CGit(void)\r
+{\r
+}\r
+\r
+char buffer[4096];\r
+\r
+int CGit::Run(CString cmd, CString* output)\r
+{\r
+       SECURITY_ATTRIBUTES sa;\r
+       HANDLE hRead, hWrite;\r
+\r
+       sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
+       sa.lpSecurityDescriptor=NULL;\r
+       sa.bInheritHandle=TRUE;\r
+       if(!CreatePipe(&hRead,&hWrite,&sa,0))\r
+       {\r
+               return GIT_ERROR_OPEN_PIP;\r
+       }\r
+       \r
+       STARTUPINFO si;\r
+       PROCESS_INFORMATION pi;\r
+       si.cb=sizeof(STARTUPINFO);\r
+       GetStartupInfo(&si);\r
+\r
+       si.hStdError=hWrite;\r
+       si.hStdOutput=hWrite;\r
+       si.wShowWindow=SW_HIDE;\r
+       si.dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;\r
+\r
+       \r
+       if(!CreateProcess(NULL,(LPWSTR)cmd.GetString(), NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))\r
+       {\r
+               LPVOID lpMsgBuf;\r
+               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,\r
+                       NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
+                       (LPTSTR)&lpMsgBuf,\r
+                       0,NULL);\r
+               return GIT_ERROR_CREATE_PROCESS;\r
+       }\r
+       \r
+       DWORD readnumber;\r
+       while(ReadFile(hRead,buffer,4090,&readnumber,NULL))\r
+       {\r
+               buffer[readnumber]=0;\r
+               USES_CONVERSION;\r
+               output->Append(A2W(buffer));\r
+               if(readnumber<4090)\r
+                       break;\r
+       }\r
+\r
+       \r
+       CloseHandle(pi.hThread);\r
+       CloseHandle(pi.hProcess);\r
+       CloseHandle(hWrite);\r
+       CloseHandle(hRead);\r
+       return GIT_SUCCESS;\r
+}\r
+\r
+CString CGit::GetUserName(void)\r
+{\r
+       CString UserName;\r
+       Run(_T("git.cmd config user.name"),&UserName);\r
+       return UserName;\r
+}\r
+CString CGit::GetUserEmail(void)\r
+{\r
+       CString UserName;\r
+       Run(_T("git.cmd config user.email"),&UserName);\r
+       return UserName;\r
+}\r
diff --git a/Git/Git.h b/Git/Git.h
new file mode 100644 (file)
index 0000000..a7ffbc1
--- /dev/null
+++ b/Git/Git.h
@@ -0,0 +1,18 @@
+#pragma once\r
+\r
+enum\r
+{\r
+       GIT_SUCCESS=0,\r
+       GIT_ERROR_OPEN_PIP,\r
+       GIT_ERROR_CREATE_PROCESS\r
+};\r
+class CGit\r
+{\r
+public:\r
+\r
+       CGit(void);\r
+       ~CGit(void);\r
+       int Run(CString cmd, CString* output);\r
+       CString GetUserName(void);\r
+       CString GetUserEmail(void);\r
+};\r
diff --git a/Git/Git.rc b/Git/Git.rc
new file mode 100644 (file)
index 0000000..f7471a1
--- /dev/null
@@ -0,0 +1,61 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 4, 2\r
+#pragma code_page(936)\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE  \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE  \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE  \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
index 03df4c2..73597ed 100644 (file)
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
                        >\r
                        <File\r
+                               RelativePath=".\Git.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\GitAdminDir.cpp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\GitRev.cpp"\r
+                               RelativePath=".\GitConfig.cpp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\GitStatus.cpp"\r
+                               RelativePath=".\GitRev.cpp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\GitStatusListCtrl.cpp"\r
+                               RelativePath=".\GitStatus.cpp"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\Git.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\GitAdminDir.h"\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\GitConfig.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\GitRev.h"\r
                                >\r
                        </File>\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\GitStatusListCtrl.h"\r
+                               RelativePath=".\resource.h"\r
                                >\r
                        </File>\r
                        <File\r
                        Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
                        UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
                        >\r
+                       <File\r
+                               RelativePath=".\Git.rc"\r
+                               >\r
+                       </File>\r
                </Filter>\r
                <File\r
                        RelativePath=".\ReadMe.txt"\r
diff --git a/Git/GitConfig.cpp b/Git/GitConfig.cpp
new file mode 100644 (file)
index 0000000..c1accd4
--- /dev/null
@@ -0,0 +1,10 @@
+#include "StdAfx.h"\r
+#include "GitConfig.h"\r
+\r
+GitConfig::GitConfig(void)\r
+{\r
+}\r
+\r
+GitConfig::~GitConfig(void)\r
+{\r
+}\r
diff --git a/Git/GitConfig.h b/Git/GitConfig.h
new file mode 100644 (file)
index 0000000..85d5d70
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once\r
+\r
+class GitConfig\r
+{\r
+public:\r
+       GitConfig(void);\r
+       ~GitConfig(void);\r
+};\r
index 48445c5..843037e 100644 (file)
@@ -4,5 +4,14 @@ class GitRev
 {\r
 public:\r
        GitRev(void);\r
+       GitRev(GitRev &rev);\r
        ~GitRev(void);\r
+       enum\r
+       {\r
+               REV_HEAD = -1,                  ///< head revision\r
+               REV_BASE = -2,                  ///< base revision\r
+               REV_WC = -3,                    ///< revision of the working copy\r
+               REV_UNSPECIFIED = -4,   ///< unspecified revision\r
+       };\r
+\r
 };\r
index e36ec17..1ba4e16 100644 (file)
@@ -45,7 +45,7 @@ typedef enum
 }git_depth_t;\r
 \r
 \r
-\r
+#define GIT_REV_ZERO _T("0000000000000000000000000000000000000000")\r
 typedef CString git_revnum_t;\r
 typedef int git_error_t;\r
 \r
index e184a63..9f75074 100644 (file)
+\r
+\r
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+\r
 #include "StdAfx.h"\r
 #include "GitStatusListCtrl.h"\r
+#include "resource.h"\r
+#include "MessageBox.h"\r
+#include "MyMemDC.h"\r
+#include "UnicodeUtils.h"\r
+#include "AppUtils.h"\r
+#include "PathUtils.h"\r
+#include "TempFile.h"\r
+#include "StringUtils.h"\r
+#include "DirFileEnum.h"\r
+#include "GitConfig.h"\r
+//#include "SVNProperties.h"\r
+#include "Git.h"\r
+//#include "SVNDiff.h"\r
+//#include "LogDlg.h"\r
+//#include "SVNProgressDlg.h"\r
+#include "SysImageList.h"\r
+//#include "Svnstatuslistctrl.h"\r
+#include "TGitPath.h"\r
+#include "Registry.h"\r
+#include "GitStatus.h"\r
+//#include "SVNHelpers.h"\r
+#include "InputDlg.h"\r
+#include "ShellUpdater.h"\r
+#include "GitAdminDir.h"\r
+//#include "DropFiles.h"\r
+#include "IconMenu.h"\r
+//#include "AddDlg.h"\r
+//#include "EditPropertiesDlg.h"\r
+//#include "CreateChangelistDlg.h"\r
+#include "XPTheme.h"\r
+\r
+const UINT CGitStatusListCtrl::SVNSLNM_ITEMCOUNTCHANGED\r
+                                       = ::RegisterWindowMessage(_T("GITSLNM_ITEMCOUNTCHANGED"));\r
+const UINT CGitStatusListCtrl::SVNSLNM_NEEDSREFRESH\r
+                                       = ::RegisterWindowMessage(_T("GITSLNM_NEEDSREFRESH"));\r
+const UINT CGitStatusListCtrl::SVNSLNM_ADDFILE\r
+                                       = ::RegisterWindowMessage(_T("GITSLNM_ADDFILE"));\r
+const UINT CGitStatusListCtrl::SVNSLNM_CHECKCHANGED\r
+                                       = ::RegisterWindowMessage(_T("GITSLNM_CHECKCHANGED"));\r
+\r
+#define IDSVNLC_REVERT                  1\r
+#define IDSVNLC_COMPARE                         2\r
+#define IDSVNLC_OPEN                    3\r
+#define IDSVNLC_DELETE                  4\r
+#define IDSVNLC_IGNORE                  5\r
+#define IDSVNLC_GNUDIFF1                6\r
+#define IDSVNLC_UPDATE           7\r
+#define IDSVNLC_LOG              8\r
+#define IDSVNLC_EDITCONFLICT     9\r
+#define IDSVNLC_IGNOREMASK         10\r
+#define IDSVNLC_ADD                        11\r
+#define IDSVNLC_RESOLVECONFLICT 12\r
+#define IDSVNLC_LOCK                   13\r
+#define IDSVNLC_LOCKFORCE              14\r
+#define IDSVNLC_UNLOCK                 15\r
+#define IDSVNLC_UNLOCKFORCE            16\r
+#define IDSVNLC_OPENWITH               17\r
+#define IDSVNLC_EXPLORE                        18\r
+#define IDSVNLC_RESOLVETHEIRS  19\r
+#define IDSVNLC_RESOLVEMINE            20\r
+#define IDSVNLC_REMOVE                 21\r
+#define IDSVNLC_COMMIT                 22\r
+#define IDSVNLC_PROPERTIES             23\r
+#define IDSVNLC_COPY                   24\r
+#define IDSVNLC_COPYEXT                        25\r
+#define IDSVNLC_REPAIRMOVE             26\r
+#define IDSVNLC_REMOVEFROMCS   27\r
+#define IDSVNLC_CREATECS               28\r
+#define IDSVNLC_CREATEIGNORECS 29\r
+#define IDSVNLC_CHECKGROUP             30\r
+#define IDSVNLC_UNCHECKGROUP   31\r
+#define IDSVNLC_ADD_RECURSIVE   32\r
+#define IDSVNLC_COMPAREWC              33\r
+#define IDSVNLC_BLAME                  34\r
+// the IDSVNLC_MOVETOCS *must* be the last index, because it contains a dynamic submenu where \r
+// the submenu items get command ID's sequent to this number\r
+#define IDSVNLC_MOVETOCS               35\r
+\r
+\r
+BEGIN_MESSAGE_MAP(CGitStatusListCtrl, CListCtrl)\r
+       ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHdnItemclick)\r
+       ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHdnItemclick)\r
+       ON_NOTIFY(HDN_ENDTRACK, 0, OnColumnResized)\r
+       ON_NOTIFY(HDN_ENDDRAG, 0, OnColumnMoved)\r
+       ON_NOTIFY_REFLECT_EX(LVN_ITEMCHANGED, OnLvnItemchanged)\r
+       ON_WM_CONTEXTMENU()\r
+       ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)\r
+       ON_NOTIFY_REFLECT(LVN_GETINFOTIP, OnLvnGetInfoTip)\r
+       ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnNMCustomdraw)\r
+       ON_WM_SETCURSOR()\r
+       ON_WM_GETDLGCODE()\r
+       ON_NOTIFY_REFLECT(NM_RETURN, OnNMReturn)\r
+       ON_WM_KEYDOWN()\r
+       ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)\r
+       ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)\r
+       ON_WM_PAINT()\r
+       ON_NOTIFY(HDN_BEGINTRACKA, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
+       ON_NOTIFY(HDN_BEGINTRACKW, 0, &CGitStatusListCtrl::OnHdnBegintrack)\r
+       ON_NOTIFY(HDN_ITEMCHANGINGA, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
+       ON_NOTIFY(HDN_ITEMCHANGINGW, 0, &CGitStatusListCtrl::OnHdnItemchanging)\r
+       ON_WM_DESTROY()\r
+       ON_NOTIFY_REFLECT(LVN_BEGINDRAG, OnBeginDrag)\r
+       ON_NOTIFY_REFLECT(LVN_ITEMCHANGING, &CGitStatusListCtrl::OnLvnItemchanging)\r
+END_MESSAGE_MAP()\r
+\r
+\r
+\r
+CGitStatusListCtrl::CGitStatusListCtrl() : CListCtrl()\r
+       //, m_HeadRev(GitRev::REV_HEAD)\r
+       , m_pbCanceled(NULL)\r
+       , m_pStatLabel(NULL)\r
+       , m_pSelectButton(NULL)\r
+       , m_pConfirmButton(NULL)\r
+       , m_bBusy(false)\r
+       , m_bEmpty(false)\r
+       , m_bUnversionedRecurse(true)\r
+       , m_bShowIgnores(false)\r
+       , m_pDropTarget(NULL)\r
+       , m_bIgnoreRemoveOnly(false)\r
+       , m_bCheckChildrenWithParent(false)\r
+       , m_bUnversionedLast(true)\r
+       , m_bHasChangeLists(false)\r
+       , m_bHasLocks(false)\r
+       , m_bBlock(false)\r
+       , m_bBlockUI(false)\r
+       , m_bHasCheckboxes(false)\r
+       , m_bCheckIfGroupsExist(true)\r
+       , m_bFileDropsEnabled(false)\r
+       , m_bOwnDrag(false)\r
+    , m_dwDefaultColumns(0)\r
+    , m_ColumnManager(this)\r
+    , m_bAscending(false)\r
+    , m_nSortedColumn(-1)\r
+       , m_sNoPropValueText(MAKEINTRESOURCE(IDS_STATUSLIST_NOPROPVALUE))\r
+{\r
+       m_critSec.Init();\r
+}\r
+\r
+CGitStatusListCtrl::~CGitStatusListCtrl()\r
+{\r
+       if (m_pDropTarget)\r
+               delete m_pDropTarget;\r
+       ClearStatusArray();\r
+}\r
+\r
+void CGitStatusListCtrl::ClearStatusArray()\r
+{\r
+       Locker lock(m_critSec);\r
+       for (size_t i=0; i < m_arStatusArray.size(); i++)\r
+       {\r
+               delete m_arStatusArray[i];\r
+       }\r
+       m_arStatusArray.clear();\r
+}\r
+\r
+CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(UINT_PTR index)\r
+{\r
+       if (index >= (UINT_PTR)m_arListArray.size())\r
+               return NULL;\r
+       if (m_arListArray[index] >= m_arStatusArray.size())\r
+               return NULL;\r
+       return m_arStatusArray[m_arListArray[index]];\r
+}\r
+\r
+CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetVisibleListEntry(const CTGitPath& path)\r
+{\r
+       int itemCount = GetItemCount();\r
+       for (int i=0; i < itemCount; i++)\r
+       {\r
+               FileEntry * entry = GetListEntry(i);\r
+               if (entry->GetPath().IsEquivalentTo(path))\r
+                       return entry;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+CGitStatusListCtrl::FileEntry * CGitStatusListCtrl::GetListEntry(const CTGitPath& path)\r
+{\r
+       for (size_t i=0; i < m_arStatusArray.size(); i++)\r
+       {\r
+               FileEntry * entry = m_arStatusArray[i];\r
+               if (entry->GetPath().IsEquivalentTo(path))\r
+                       return entry;\r
+       }\r
+       return NULL;\r
+}\r
+\r
+int CGitStatusListCtrl::GetIndex(const CTGitPath& path)\r
+{\r
+       int itemCount = GetItemCount();\r
+       for (int i=0; i < itemCount; i++)\r
+       {\r
+               FileEntry * entry = GetListEntry(i);\r
+               if (entry->GetPath().IsEquivalentTo(path))\r
+                       return i;\r
+       }\r
+       return -1;\r
+}\r
+\r
+void CGitStatusListCtrl::Init(DWORD dwColumns, const CString& sColumnInfoContainer, DWORD dwContextMenus /* = GitSLC_POPALL */, bool bHasCheckboxes /* = true */)\r
+{\r
+       Locker lock(m_critSec);\r
+\r
+    m_dwDefaultColumns = dwColumns | 1;\r
+    m_dwContextMenus = dwContextMenus;\r
+       m_bHasCheckboxes = bHasCheckboxes;\r
+\r
+    // set the extended style of the listcontrol\r
+       // 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
+       CRegDWORD regFullRowSelect(_T("Software\\TortoiseGit\\FullRowSelect"), TRUE);\r
+       DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES;\r
+       if (DWORD(regFullRowSelect))\r
+               exStyle |= LVS_EX_FULLROWSELECT;\r
+       exStyle |= (bHasCheckboxes ? LVS_EX_CHECKBOXES : 0);\r
+       SetRedraw(false);\r
+       SetExtendedStyle(exStyle);\r
+\r
+       CXPTheme theme;\r
+       theme.SetWindowTheme(m_hWnd, L"Explorer", NULL);\r
+\r
+       m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();\r
+       SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);\r
+\r
+    m_ColumnManager.ReadSettings (m_dwDefaultColumns, sColumnInfoContainer);\r
+\r
+       // enable file drops\r
+#if 0\r
+       if (m_pDropTarget == NULL)\r
+       {\r
+               m_pDropTarget = new CGitStatusListCtrlDropTarget(this);\r
+               RegisterDragDrop(m_hWnd,m_pDropTarget);\r
+               // create the supported formats:\r
+               FORMATETC ftetc={0};\r
+               ftetc.dwAspect = DVASPECT_CONTENT;\r
+               ftetc.lindex = -1;\r
+               ftetc.tymed = TYMED_HGLOBAL;\r
+               ftetc.cfFormat=CF_HDROP;\r
+               m_pDropTarget->AddSuportedFormat(ftetc);\r
+       }\r
+#endif\r
+\r
+       SetRedraw(true);\r
+\r
+       m_bUnversionedRecurse = !!((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\UnversionedRecurse"), TRUE));\r
+}\r
 \r
-CGitStatusListCtrl::CGitStatusListCtrl(void)\r
+bool CGitStatusListCtrl::SetBackgroundImage(UINT nID)\r
 {\r
+       return CAppUtils::SetListCtrlBackgroundImage(GetSafeHwnd(), nID);\r
 }\r
 \r
-CGitStatusListCtrl::~CGitStatusListCtrl(void)\r
+BOOL CGitStatusListCtrl::GetStatus ( const CTGitPathList& pathList\r
+                                   , bool bUpdate /* = FALSE */\r
+                                   , bool bShowIgnores /* = false */\r
+                                   , bool bShowUserProps /* = false */)\r
 {\r
+       Locker lock(m_critSec);\r
+       int refetchcounter = 0;\r
+       BOOL bRet = TRUE;\r
+       Invalidate();\r
+       // force the cursor to change\r
+       POINT pt;\r
+       GetCursorPos(&pt);\r
+       SetCursorPos(pt.x, pt.y);\r
+\r
+       m_mapFilenameToChecked.clear();\r
+       m_StatusUrlList.Clear();\r
+       bool bHasChangelists = (m_changelists.size()>1 || (m_changelists.size()>0 && !m_bHasIgnoreGroup));\r
+       m_changelists.clear();\r
+       for (size_t i=0; i < m_arStatusArray.size(); i++)\r
+       {\r
+               FileEntry * entry = m_arStatusArray[i];\r
+               if ( bHasChangelists && entry->checked)\r
+               {\r
+                       // If change lists are present, remember all checked entries\r
+                       CString path = entry->GetPath().GetGitPathString();\r
+                       m_mapFilenameToChecked[path] = true;\r
+               }\r
+               if ( (entry->status==git_wc_status_unversioned || entry->status==git_wc_status_missing ) && entry->checked )\r
+               {\r
+                       // The user manually selected an unversioned or missing file. We remember\r
+                       // this so that the selection can be restored when refreshing.\r
+                       CString path = entry->GetPath().GetGitPathString();\r
+                       m_mapFilenameToChecked[path] = true;\r
+               }\r
+               else if ( entry->status > git_wc_status_normal && !entry->checked )\r
+               {\r
+                       // The user manually deselected a versioned file. We remember\r
+                       // this so that the deselection can be restored when refreshing.\r
+                       CString path = entry->GetPath().GetGitPathString();\r
+                       m_mapFilenameToChecked[path] = false;\r
+               }\r
+       }\r
+\r
+       // use a sorted path list to make sure we fetch the status of\r
+       // parent items first, *then* the child items (if any)\r
+       CTGitPathList sortedPathList = pathList;\r
+       sortedPathList.SortByPathname();\r
+       do\r
+       {\r
+               bRet = TRUE;\r
+               m_nTargetCount = 0;\r
+               m_bHasExternalsFromDifferentRepos = FALSE;\r
+               m_bHasExternals = FALSE;\r
+               m_bHasUnversionedItems = FALSE;\r
+               m_bHasLocks = false;\r
+               m_bHasChangeLists = false;\r
+               m_bShowIgnores = bShowIgnores;\r
+               m_nSortedColumn = 0;\r
+               m_bBlock = TRUE;\r
+               m_bBusy = true;\r
+               m_bEmpty = false;\r
+               Invalidate();\r
+\r
+               // first clear possible status data left from\r
+               // previous GetStatus() calls\r
+               ClearStatusArray();\r
+\r
+               m_StatusFileList = sortedPathList;\r
+\r
+               // Since Git_client_status() returns all files, even those in\r
+               // folders included with Git:externals we need to check if all\r
+               // files we get here belongs to the same repository.\r
+               // It is possible to commit changes in an external folder, as long\r
+               // as the folder belongs to the same repository (but another path),\r
+               // but it is not possible to commit all files if the externals are\r
+               // from a different repository.\r
+               //\r
+               // To check if all files belong to the same repository, we compare the\r
+               // UUID's - if they're identical then the files belong to the same\r
+               // repository and can be committed. But if they're different, then\r
+               // tell the user to commit all changes in the external folders\r
+               // first and exit.\r
+               CStringA sUUID;                                 // holds the repo UUID\r
+               CTGitPathList arExtPaths;               // list of Git:external paths\r
+\r
+               GitConfig config;\r
+\r
+               m_sURL.Empty();\r
+\r
+               m_nTargetCount = sortedPathList.GetCount();\r
+\r
+               GitStatus status(m_pbCanceled);\r
+               if(m_nTargetCount > 1 && sortedPathList.AreAllPathsFilesInOneDirectory())\r
+               {\r
+                       // This is a special case, where we've been given a list of files\r
+                       // all from one folder\r
+                       // We handle them by setting a status filter, then requesting the Git status of\r
+                       // all the files in the directory, filtering for the ones we're interested in\r
+                       status.SetFilter(sortedPathList);\r
+\r
+                       // if all selected entries are files, we don't do a recursive status\r
+                       // fetching. But if only one is a directory, we have to recurse.\r
+                       git_depth_t depth = git_depth_files;\r
+                       // We have set a filter. If all selected items were files or we fetch\r
+                       // the status not recursively, then we have to include\r
+                       // ignored items too - the user has selected them\r
+                       bool bShowIgnoresRight = true;\r
+                       for (int fcindex=0; fcindex<sortedPathList.GetCount(); ++fcindex)\r
+                       {\r
+                               if (sortedPathList[fcindex].IsDirectory())\r
+                               {\r
+                                       depth = git_depth_infinity;\r
+                                       bShowIgnoresRight = false;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if(!FetchStatusForSingleTarget(config, status, sortedPathList.GetCommonDirectory(), bUpdate, sUUID, arExtPaths, true, depth, bShowIgnoresRight))\r
+                       {\r
+                               bRet = FALSE;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       for(int nTarget = 0; nTarget < m_nTargetCount; nTarget++)\r
+                       {\r
+                               // check whether the path we want the status for is already fetched due to status-fetching\r
+                               // of a parent path.\r
+                               // this check is only done for file paths, because folder paths could be included already\r
+                               // but not recursively\r
+                               if (sortedPathList[nTarget].IsDirectory() || GetListEntry(sortedPathList[nTarget]) == NULL)\r
+                               {\r
+                                       if(!FetchStatusForSingleTarget(config, status, sortedPathList[nTarget], bUpdate, sUUID, \r
+                                               arExtPaths, false, git_depth_infinity, bShowIgnores))\r
+                                       {\r
+                                               bRet = FALSE;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // remove the 'helper' files of conflicted items from the list.\r
+               // otherwise they would appear as unversioned files.\r
+               for (INT_PTR cind = 0; cind < m_ConflictFileList.GetCount(); ++cind)\r
+               {\r
+                       for (size_t i=0; i < m_arStatusArray.size(); i++)\r
+                       {\r
+                               if (m_arStatusArray[i]->GetPath().IsEquivalentTo(m_ConflictFileList[cind]))\r
+                               {\r
+                                       delete m_arStatusArray[i];\r
+                                       m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               refetchcounter++;\r
+       } while(!BuildStatistics() && (refetchcounter < 2) && (*m_pbCanceled==false));\r
+\r
+    if (bShowUserProps)\r
+        FetchUserProperties();\r
+\r
+    m_ColumnManager.UpdateUserPropList (m_arStatusArray);\r
+\r
+       m_bBlock = FALSE;\r
+       m_bBusy = false;\r
+       GetCursorPos(&pt);\r
+       SetCursorPos(pt.x, pt.y);\r
+       return bRet;\r
 }\r
+\r
+//\r
+// Fetch all local properties for all elements in the status array\r
+//\r
+void CGitStatusListCtrl::FetchUserProperties()\r
+{\r
+#if 0\r
+       GitPool globalPool;\r
+\r
+    for (size_t i = 0, count = m_arStatusArray.size(); i < count; ++i)\r
+    {\r
+        // local / temp pool to hold parameters and props for a single item\r
+\r
+       GitPool localPool ((apr_pool_t*)globalPool);\r
+\r
+        // open working copy for this path\r
+\r
+        const char* path = m_arStatusArray[i]->path.GetGitApiPath (localPool);\r
+         \r
+           Git_wc_adm_access_t *adm_access = NULL;          \r
+        Git_error_t * error = Git_wc_adm_probe_open3 ( &adm_access\r
+                                                     , NULL\r
+                                                     , path\r
+                                                     , FALSE   // no write lock\r
+                                                                                                        , 0            // lock just the directory/file itself\r
+                                                     , NULL\r
+                                                                                                        , NULL\r
+                                                     , localPool);\r
+        if (error == NULL)\r
+        {\r
+            // get the props and add them to the status info\r
+\r
+            apr_hash_t* props = NULL;\r
+            Git_error_t * error = Git_wc_prop_list ( &props\r
+                                                   , path\r
+                                                   , adm_access\r
+                                                   , localPool);\r
+            if (error == NULL)\r
+            {\r
+                for ( apr_hash_index_t *index \r
+                        = apr_hash_first (localPool, props)\r
+                    ; index != NULL\r
+                    ; index = apr_hash_next (index))\r
+                {\r
+                    // extract next entry from hash\r
+\r
+                    const char* key = NULL;\r
+                    ptrdiff_t keyLen;\r
+                    const char** val = NULL;\r
+\r
+                    apr_hash_this ( index\r
+                                  , reinterpret_cast<const void**>(&key)\r
+                                  , &keyLen\r
+                                  , reinterpret_cast<void**>(&val));\r
+\r
+                    // decode / dispatch it\r
+\r
+                       CString name = CUnicodeUtils::GetUnicode (key);\r
+                       CString value = CUnicodeUtils::GetUnicode (*val);\r
+\r
+                    // store in property container (truncate it after ~100 chars)\r
+\r
+                    m_arStatusArray[i]->present_props[name] \r
+                        = value.Left (GitSLC_MAXUSERPROPLENGTH);\r
+                }\r
+            }\r
+            error = Git_wc_adm_close2 (adm_access, localPool);\r
+        }\r
+        Git_error_clear (error);\r
+    }\r
+#endif\r
+}\r
+\r
+\r
+//\r
+// Work on a single item from the list of paths which is provided to us\r
+//\r
+bool CGitStatusListCtrl::FetchStatusForSingleTarget(\r
+                                                       GitConfig& config,\r
+                                                       GitStatus& status,\r
+                                                       const CTGitPath& target,\r
+                                                       bool bFetchStatusFromRepository,\r
+                                                       CStringA& strCurrentRepositoryUUID,\r
+                                                       CTGitPathList& arExtPaths,\r
+                                                       bool bAllDirect,\r
+                                                       git_depth_t depth,\r
+                                                       bool bShowIgnores\r
+                                                       )\r
+{\r
+#if 0\r
+       config.GetDefaultIgnores();\r
+\r
+       CTGitPath workingTarget(target);\r
+\r
+       git_wc_status2_t * s;\r
+       CTGitPath GitPath;\r
+       s = status.GetFirstFileStatus(workingTarget, GitPath, bFetchStatusFromRepository, depth, bShowIgnores);\r
+\r
+       m_HeadRev = SVNRev(status.headrev);\r
+       if (s!=0)\r
+       {\r
+               Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
+\r
+               // This one fixes a problem with externals:\r
+               // If a strLine is a file, Git:externals and its parent directory\r
+               // will also be returned by GetXXXFileStatus. Hence, we skip all\r
+               // status info until we find the one matching workingTarget.\r
+               if (!workingTarget.IsDirectory())\r
+               {\r
+                       if (!workingTarget.IsEquivalentTo(GitPath))\r
+                       {\r
+                               while (s != 0)\r
+                               {\r
+                                       s = status.GetNextFileStatus(GitPath);\r
+                                       if(workingTarget.IsEquivalentTo(GitPath))\r
+                                       {\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if (s == 0)\r
+                               {\r
+                                       m_sLastError = status.GetLastErrorMsg();\r
+                                       return false;\r
+                               }\r
+                               // Now, set working target to be the base folder of this item\r
+                               workingTarget = workingTarget.GetDirectory();\r
+                       }\r
+               }\r
+               bool bEntryFromDifferentRepo = false;\r
+               // Is this a versioned item with an associated repos UUID?\r
+               if ((s->entry)&&(s->entry->uuid))\r
+               {\r
+                       // Have we seen a repos UUID yet?\r
+                       if (strCurrentRepositoryUUID.IsEmpty())\r
+                       {\r
+                               // This is the first repos UUID we've seen - record it\r
+                               strCurrentRepositoryUUID = s->entry->uuid;\r
+                               m_sUUID = strCurrentRepositoryUUID;\r
+                       }\r
+                       else\r
+                       {\r
+                               if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
+                               {\r
+                                       // This item comes from a different repository than our main one\r
+                                       m_bHasExternalsFromDifferentRepos = TRUE;\r
+                                       bEntryFromDifferentRepo = true;\r
+                                       if (s->entry->kind == Git_node_dir)\r
+                                               arExtPaths.AddPath(workingTarget);\r
+                               }\r
+                       }\r
+               }\r
+               else if (strCurrentRepositoryUUID.IsEmpty() && (s->text_status == Git_wc_status_added))\r
+               {\r
+                       // An added entry doesn't have an UUID assigned to it yet.\r
+                       // So we fetch the status of the parent directory instead and\r
+                       // check if that one has an UUID assigned to it.\r
+                       Git_wc_status2_t * sparent;\r
+                       CTGitPath path = workingTarget;\r
+                       do\r
+                       {\r
+                               CTGitPath GitParentPath;\r
+                               GitStatus tempstatus;\r
+                               sparent = tempstatus.GetFirstFileStatus(path.GetContainingDirectory(), GitParentPath, false, Git_depth_empty, false);\r
+                               path = GitParentPath;\r
+                       } while ( (sparent) && (sparent->entry) && (!sparent->entry->uuid) && (sparent->text_status==Git_wc_status_added) );\r
+                       if (sparent && sparent->entry && sparent->entry->uuid)\r
+                       {\r
+                               strCurrentRepositoryUUID = sparent->entry->uuid;\r
+                               m_sUUID = strCurrentRepositoryUUID;\r
+                       }\r
+               }\r
+\r
+               if ((wcFileStatus == Git_wc_status_unversioned)&& GitPath.IsDirectory())\r
+               {\r
+                       // check if the unversioned folder is maybe versioned. This\r
+                       // could happen with nested layouts\r
+                       Git_wc_status_kind st = GitStatus::GetAllStatus(workingTarget);\r
+                       if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
+                       {\r
+                               return true;    // ignore nested layouts\r
+                       }\r
+               }\r
+               if (status.IsExternal(GitPath))\r
+               {\r
+                       m_bHasExternals = TRUE;\r
+               }\r
+\r
+               AddNewFileEntry(s, GitPath, workingTarget, true, m_bHasExternals, bEntryFromDifferentRepo);\r
+\r
+               if (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none)||((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))) && GitPath.IsDirectory())\r
+               {\r
+                       // we have an unversioned folder -> get all files in it recursively!\r
+                       AddUnversionedFolder(GitPath, workingTarget.GetContainingDirectory(), &config);\r
+               }\r
+\r
+               // for folders, get all statuses inside it too\r
+               if(workingTarget.IsDirectory())\r
+               {\r
+                       ReadRemainingItemsStatus(status, workingTarget, strCurrentRepositoryUUID, arExtPaths, &config, bAllDirect);\r
+               }\r
+\r
+       } // if (s!=0)\r
+       else\r
+       {\r
+               m_sLastError = status.GetLastErrorMsg();\r
+               return false;\r
+       }\r
+#endif\r
+       return true;\r
+}\r
+\r
+const CGitStatusListCtrl::FileEntry*\r
+CGitStatusListCtrl::AddNewFileEntry(\r
+                       const git_wc_status2_t* pGitStatus,  // The return from the Git GetStatus functions\r
+                       const CTGitPath& path,                          // The path of the item we're adding\r
+                       const CTGitPath& basePath,                      // The base directory for this status build\r
+                       bool bDirectItem,                                       // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call\r
+                       bool bInExternal,                                       // Are we in an 'external' folder\r
+                       bool bEntryfromDifferentRepo            // if the entry is from a different repository\r
+                       )\r
+{\r
+       FileEntry * entry = new FileEntry();\r
+#if 0\r
+       \r
+       entry->path = path;\r
+       entry->basepath = basePath;\r
+       entry->status = GitStatus::GetMoreImportant(pGitStatus->text_status, pGitStatus->prop_status);\r
+       entry->textstatus = pGitStatus->text_status;\r
+       entry->propstatus = pGitStatus->prop_status;\r
+//     entry->remotestatus = GitStatus::GetMoreImportant(pGitStatus->repos_text_status, pGitStatus->repos_prop_status);\r
+//     entry->remotetextstatus = pGitStatus->repos_text_status;\r
+//     entry->remotepropstatus = pGitStatus->repos_prop_status;\r
+       entry->inexternal = bInExternal;\r
+       entry->differentrepo = bEntryfromDifferentRepo;\r
+       entry->direct = bDirectItem;\r
+//     entry->copied = !!pGitStatus->copied;\r
+//     entry->switched = !!pGitStatus->switched;\r
+\r
+       entry->last_commit_date = pGitStatus->ood_last_cmt_date;\r
+       if ((entry->last_commit_date == NULL)&&(pGitStatus->entry))\r
+               entry->last_commit_date = pGitStatus->entry->cmt_date;\r
+       entry->remoterev = pGitStatus->ood_last_cmt_rev;\r
+       if (pGitStatus->entry)\r
+               entry->last_commit_rev = pGitStatus->entry->cmt_rev;\r
+       if (pGitStatus->ood_last_cmt_author)\r
+               entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->ood_last_cmt_author);\r
+       if ((entry->last_commit_author.IsEmpty())&&(pGitStatus->entry)&&(pGitStatus->entry->cmt_author))\r
+               entry->last_commit_author = CUnicodeUtils::GetUnicode(pGitStatus->entry->cmt_author);\r
+\r
+       if (pGitStatus->entry)\r
+               entry->isConflicted = (pGitStatus->entry->conflict_wrk && PathFileExists(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk))) ? true : false;\r
+\r
+       if ((entry->status == Git_wc_status_conflicted)||(entry->isConflicted))\r
+       {\r
+               entry->isConflicted = true;\r
+               if (pGitStatus->entry)\r
+               {\r
+                       CTGitPath cpath;\r
+                       if (pGitStatus->entry->conflict_wrk)\r
+                       {\r
+                               cpath = path.GetDirectory();\r
+                               cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_wrk));\r
+                               m_ConflictFileList.AddPath(cpath);\r
+                       }\r
+                       if (pGitStatus->entry->conflict_old)\r
+                       {\r
+                               cpath = path.GetDirectory();\r
+                               cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_old));\r
+                               m_ConflictFileList.AddPath(cpath);\r
+                       }\r
+                       if (pGitStatus->entry->conflict_new)\r
+                       {\r
+                               cpath = path.GetDirectory();\r
+                               cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->conflict_new));\r
+                               m_ConflictFileList.AddPath(cpath);\r
+                       }\r
+                       if (pGitStatus->entry->prejfile)\r
+                       {\r
+                               cpath = path.GetDirectory();\r
+                               cpath.AppendPathString(CUnicodeUtils::GetUnicode(pGitStatus->entry->prejfile));\r
+                               m_ConflictFileList.AddPath(cpath);\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (pGitStatus->entry)\r
+       {\r
+               entry->isfolder = (pGitStatus->entry->kind == Git_node_dir);\r
+               entry->Revision = pGitStatus->entry->revision;\r
+               entry->keeplocal = !!pGitStatus->entry->keep_local;\r
+               entry->working_size = pGitStatus->entry->working_size;\r
+               entry->depth = pGitStatus->entry->depth;\r
+\r
+               if (pGitStatus->entry->url)\r
+               {\r
+                       entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->url));\r
+               }\r
+               if (pGitStatus->entry->copyfrom_url)\r
+               {\r
+                       entry->copyfrom_url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(pGitStatus->entry->copyfrom_url));\r
+                       entry->copyfrom_rev = pGitStatus->entry->copyfrom_rev;\r
+               }\r
+               else\r
+                       entry->copyfrom_rev = 0;\r
+\r
+               if(bDirectItem)\r
+               {\r
+                       if (m_sURL.IsEmpty())\r
+                               m_sURL = entry->url;\r
+                       else\r
+                               m_sURL.LoadString(IDS_STATUSLIST_MULTIPLETARGETS);\r
+                       m_StatusUrlList.AddPath(CTGitPath(entry->url));\r
+               }\r
+               if (pGitStatus->entry->lock_owner)\r
+                       entry->lock_owner = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_owner);\r
+               if (pGitStatus->entry->lock_token)\r
+               {\r
+                       entry->lock_token = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_token);\r
+                       m_bHasLocks = true;\r
+               }\r
+               if (pGitStatus->entry->lock_comment)\r
+                       entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->entry->lock_comment);\r
+\r
+               if (pGitStatus->entry->present_props)\r
+               {\r
+                       entry->present_props = pGitStatus->entry->present_props;\r
+               }\r
+\r
+               if (pGitStatus->entry->changelist)\r
+               {\r
+                       entry->changelist = CUnicodeUtils::GetUnicode(pGitStatus->entry->changelist);\r
+                       m_changelists[entry->changelist] = -1;\r
+                       m_bHasChangeLists = true;\r
+               }\r
+               entry->needslock = (pGitStatus->entry->present_props && (strstr(pGitStatus->entry->present_props, "Git:needs-lock")!=NULL) );\r
+       }\r
+       else\r
+       {\r
+               if (pGitStatus->ood_kind == Git_node_none)\r
+                       entry->isfolder = path.IsDirectory();\r
+               else\r
+                       entry->isfolder = (pGitStatus->ood_kind == Git_node_dir);\r
+       }\r
+       if (pGitStatus->repos_lock)\r
+       {\r
+               if (pGitStatus->repos_lock->owner)\r
+                       entry->lock_remoteowner = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->owner);\r
+               if (pGitStatus->repos_lock->token)\r
+                       entry->lock_remotetoken = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->token);\r
+               if (pGitStatus->repos_lock->comment)\r
+                       entry->lock_comment = CUnicodeUtils::GetUnicode(pGitStatus->repos_lock->comment);\r
+       }\r
+\r
+       // Pass ownership of the entry to the array\r
+       m_arStatusArray.push_back(entry);\r
+#endif\r
+       return entry;\r
+}\r
+\r
+void CGitStatusListCtrl::AddUnversionedFolder(const CTGitPath& folderName,\r
+                                                                                               const CTGitPath& basePath,\r
+                                                                                               GitConfig * config)\r
+{\r
+#if 0\r
+       if (!m_bUnversionedRecurse)\r
+               return;\r
+       CSimpleFileFind filefinder(folderName.GetWinPathString());\r
+\r
+       CTGitPath filename;\r
+       m_bHasUnversionedItems = TRUE;\r
+       while (filefinder.FindNextFileNoDots())\r
+       {\r
+               filename.SetFromWin(filefinder.GetFilePath(), filefinder.IsDirectory());\r
+\r
+               bool bMatchIgnore = !!config->MatchIgnorePattern(filename.GetFileOrDirectoryName());\r
+               bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(filename.GetGitPathString());\r
+               if (((bMatchIgnore)&&(m_bShowIgnores))||(!bMatchIgnore))\r
+               {\r
+                       FileEntry * entry = new FileEntry();\r
+                       entry->path = filename;\r
+                       entry->basepath = basePath;\r
+                       entry->inunversionedfolder = true;\r
+                       entry->isfolder = filefinder.IsDirectory();\r
+\r
+                       m_arStatusArray.push_back(entry);\r
+                       if (entry->isfolder)\r
+                       {\r
+                               if (!g_GitAdminDir.HasAdminDir(entry->path.GetWinPathString(), true))\r
+                                       AddUnversionedFolder(entry->path, basePath, config);\r
+                       }\r
+               }\r
+       }\r
+#endif\r
+}\r
+\r
+\r
+void CGitStatusListCtrl::ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& basePath,\r
+                                                                                 CStringA& strCurrentRepositoryUUID,\r
+                                                                                 CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect)\r
+{\r
+#if 0\r
+       git_wc_status2_t * s;\r
+\r
+       CTGitPath lastexternalpath;\r
+       CTGitPath GitPath;\r
+       while ((s = status.GetNextFileStatus(GitPath)) != NULL)\r
+       {\r
+               Git_wc_status_kind wcFileStatus = GitStatus::GetMoreImportant(s->text_status, s->prop_status);\r
+               if ((wcFileStatus == Git_wc_status_unversioned) && (GitPath.IsDirectory()))\r
+               {\r
+                       // check if the unversioned folder is maybe versioned. This\r
+                       // could happen with nested layouts\r
+                       Git_wc_status_kind st = GitStatus::GetAllStatus(GitPath);\r
+                       if ((st != Git_wc_status_unversioned)&&(st != Git_wc_status_none))\r
+                       {\r
+                               FileEntry * entry = new FileEntry();\r
+                               entry->path = GitPath;\r
+                               entry->basepath = basePath;\r
+                               entry->inunversionedfolder = true;\r
+                               entry->isfolder = true;\r
+                               entry->isNested = true;\r
+                               m_arStatusArray.push_back(entry);\r
+                               continue;\r
+                       }\r
+               }\r
+               bool bDirectoryIsExternal = false;\r
+               bool bEntryfromDifferentRepo = false;\r
+               if (s->entry)\r
+               {\r
+                       if (s->entry->uuid)\r
+                       {\r
+                               if (strCurrentRepositoryUUID.IsEmpty())\r
+                                       strCurrentRepositoryUUID = s->entry->uuid;\r
+                               else\r
+                               {\r
+                                       if (strCurrentRepositoryUUID.Compare(s->entry->uuid)!=0)\r
+                                       {\r
+                                               bEntryfromDifferentRepo = true;\r
+                                               if (GitStatus::IsImportant(wcFileStatus))\r
+                                                       m_bHasExternalsFromDifferentRepos = TRUE;\r
+                                               if (s->entry->kind == Git_node_dir)\r
+                                               {\r
+                                                       if ((lastexternalpath.IsEmpty())||(!lastexternalpath.IsAncestorOf(GitPath)))\r
+                                                       {\r
+                                                               arExtPaths.AddPath(GitPath);\r
+                                                               lastexternalpath = GitPath;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               // we don't have an UUID - maybe an added file/folder\r
+                               if (!strCurrentRepositoryUUID.IsEmpty())\r
+                               {\r
+                                       if ((!lastexternalpath.IsEmpty())&&\r
+                                               (lastexternalpath.IsAncestorOf(GitPath)))\r
+                                       {\r
+                                               bEntryfromDifferentRepo = true;\r
+                                               m_bHasExternalsFromDifferentRepos = TRUE;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // if unversioned items lie around in external\r
+                       // directories from different repos, we have to mark them\r
+                       // as such too.\r
+                       if (!strCurrentRepositoryUUID.IsEmpty())\r
+                       {\r
+                               if ((!lastexternalpath.IsEmpty())&&\r
+                                       (lastexternalpath.IsAncestorOf(GitPath)))\r
+                               {\r
+                                       bEntryfromDifferentRepo = true;\r
+                               }\r
+                       }\r
+               }\r
+               if (status.IsExternal(GitPath))\r
+               {\r
+                       arExtPaths.AddPath(GitPath);\r
+                       m_bHasExternals = TRUE;\r
+               }\r
+               if ((!bEntryfromDifferentRepo)&&(status.IsInExternal(GitPath)))\r
+               {\r
+                       // if the externals are inside an unversioned folder (this happens if\r
+                       // the externals are specified with e.g. "ext\folder url" instead of just\r
+                       // "folder url"), then a commit won't succeed.\r
+                       // therefore, we treat those as if the externals come from a different\r
+                       // repository\r
+                       CTGitPath extpath = GitPath;\r
+                       while (basePath.IsAncestorOf(extpath))\r
+                       {\r
+                               if (!extpath.HasAdminDir())\r
+                               {\r
+                                       bEntryfromDifferentRepo = true;\r
+                                       break;\r
+                               }\r
+                               extpath = extpath.GetContainingDirectory();\r
+                       }\r
+               }\r
+               // Do we have any external paths?\r
+               if(arExtPaths.GetCount() > 0)\r
+               {\r
+                       // If do have external paths, we need to check if the current item belongs\r
+                       // to one of them\r
+                       for (int ix=0; ix<arExtPaths.GetCount(); ix++)\r
+                       {\r
+                               if (arExtPaths[ix].IsAncestorOf(GitPath))\r
+                               {\r
+                                       bDirectoryIsExternal = true;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               if ((wcFileStatus == Git_wc_status_unversioned)&&(!bDirectoryIsExternal))\r
+                       m_bHasUnversionedItems = TRUE;\r
+\r
+               const FileEntry* entry = AddNewFileEntry(s, GitPath, basePath, bAllDirect, bDirectoryIsExternal, bEntryfromDifferentRepo);\r
+\r
+               bool bMatchIgnore = !!config->MatchIgnorePattern(entry->path.GetFileOrDirectoryName());\r
+               bMatchIgnore = bMatchIgnore || config->MatchIgnorePattern(entry->path.GetGitPathString());\r
+               if ((((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(!bMatchIgnore))||\r
+                       ((wcFileStatus == Git_wc_status_ignored)&&(m_bShowIgnores))||\r
+                       (((wcFileStatus == Git_wc_status_unversioned)||(wcFileStatus == Git_wc_status_none))&&(bMatchIgnore)&&(m_bShowIgnores)))\r
+               {\r
+                       if (entry->isfolder)\r
+                       {\r
+                               // we have an unversioned folder -> get all files in it recursively!\r
+                               AddUnversionedFolder(GitPath, basePath, config);\r
+                       }\r
+               }\r
+       } // while ((s = status.GetNextFileStatus(GitPath)) != NULL) \r
+#endif\r
+}\r
+\r
+// Get the show-flags bitmap value which corresponds to a particular Git status\r
+DWORD CGitStatusListCtrl::GetShowFlagsFromGitStatus(git_wc_status_kind status)\r
+{\r
+       switch (status)\r
+       {\r
+       case git_wc_status_none:\r
+       case git_wc_status_unversioned:\r
+               return SVNSLC_SHOWUNVERSIONED;\r
+       case git_wc_status_ignored:\r
+               if (!m_bShowIgnores)\r
+                       return SVNSLC_SHOWDIRECTS;\r
+               return SVNSLC_SHOWDIRECTS|SVNSLC_SHOWIGNORED;\r
+       case git_wc_status_incomplete:\r
+               return SVNSLC_SHOWINCOMPLETE;\r
+       case git_wc_status_normal:\r
+               return SVNSLC_SHOWNORMAL;\r
+       case git_wc_status_external:\r
+               return SVNSLC_SHOWEXTERNAL;\r
+       case git_wc_status_added:\r
+               return SVNSLC_SHOWADDED;\r
+       case git_wc_status_missing:\r
+               return SVNSLC_SHOWMISSING;\r
+       case git_wc_status_deleted:\r
+               return SVNSLC_SHOWREMOVED;\r
+       case git_wc_status_replaced:\r
+               return SVNSLC_SHOWREPLACED;\r
+       case git_wc_status_modified:\r
+               return SVNSLC_SHOWMODIFIED;\r
+       case git_wc_status_merged:\r
+               return SVNSLC_SHOWMERGED;\r
+       case git_wc_status_conflicted:\r
+               return SVNSLC_SHOWCONFLICTED;\r
+       case git_wc_status_obstructed:\r
+               return SVNSLC_SHOWOBSTRUCTED;\r
+       default:\r
+               // we should NEVER get here!\r
+               ASSERT(FALSE);\r
+               break;\r
+       }\r
+       return 0;\r
+}\r
+\r
+void CGitStatusListCtrl::Show(DWORD dwShow, DWORD dwCheck /*=0*/, bool bShowFolders /* = true */)\r
+{\r
+#if 0\r
+       Locker lock(m_critSec);\r
+       WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
+\r
+       CWinApp * pApp = AfxGetApp();\r
+       if (pApp)\r
+               pApp->DoWaitCursor(1);\r
+       m_dwShow = dwShow;\r
+       m_bShowFolders = bShowFolders;\r
+       m_nSelected = 0;\r
+       int nTopIndex = GetTopIndex();\r
+       POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
+       int nSelectedEntry = 0;\r
+       if (posSelectedEntry)\r
+               nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
+       SetRedraw(FALSE);\r
+       DeleteAllItems();\r
+\r
+       PrepareGroups();\r
+\r
+       m_arListArray.clear();\r
+\r
+       m_arListArray.reserve(m_arStatusArray.size());\r
+       SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
+\r
+       int listIndex = 0;\r
+       for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
+       {\r
+               FileEntry * entry = m_arStatusArray[i];\r
+               if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
+                       continue;\r
+               if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
+                       continue;\r
+               if (entry->IsFolder() && (!bShowFolders))\r
+                       continue;       // don't show folders if they're not wanted.\r
+               git_wc_status_kind status = GitStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
+               DWORD showFlags = GetShowFlagsFromGitStatus(status);\r
+               if (entry->IsLocked())\r
+                       showFlags |= SVNSLC_SHOWLOCKS;\r
+               if (entry->switched)\r
+                       showFlags |= SVNSLC_SHOWSWITCHED;\r
+               if (!entry->changelist.IsEmpty())\r
+                       showFlags |= SVNSLC_SHOWINCHANGELIST;\r
+\r
+               bool bAllowCheck = ((entry->changelist.Compare(SVNSLC_IGNORECHANGELIST) != 0) && (m_bCheckIfGroupsExist || (m_changelists.size()==0 || (m_changelists.size()==1 && m_bHasIgnoreGroup))));\r
+\r
+               // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
+               if (status != Git_wc_status_ignored || (entry->direct) || (dwShow & GitSLC_SHOWIGNORED))\r
+               {\r
+                       if ((!entry->IsFolder()) && (status == Git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
+                       {\r
+                               if (PathFileExists(entry->GetPath().GetWinPath()))\r
+                               {\r
+                                       m_arListArray.push_back(i);\r
+                                       if ((dwCheck & SVNSLC_SHOWREMOVEDANDPRESENT)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
+                                       {\r
+                                               if (bAllowCheck)\r
+                                                       entry->checked = true;\r
+                                       }\r
+                                       AddEntry(entry, langID, listIndex++);\r
+                               }\r
+                       }\r
+                       else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
+                       {\r
+                               m_arListArray.push_back(i);\r
+                               if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
+                               {\r
+                                       if (bAllowCheck)\r
+                                               entry->checked = true;\r
+                               }\r
+                               AddEntry(entry, langID, listIndex++);\r
+                       }\r
+                       else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
+                       {\r
+                               m_arListArray.push_back(i);\r
+                               if ((dwCheck & showFlags)||((dwCheck & SVNSLC_SHOWDIRECTS)&&(entry->direct)))\r
+                               {\r
+                                       if (bAllowCheck)\r
+                                               entry->checked = true;\r
+                               }\r
+                               AddEntry(entry, langID, listIndex++);\r
+                       }\r
+               }\r
+       }\r
+\r
+       SetItemCount(listIndex);\r
+\r
+    m_ColumnManager.UpdateRelevance (m_arStatusArray, m_arListArray);\r
+\r
+       int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       for (int col = 0; col <= maxcol; col++)\r
+        SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
+\r
+    SetRedraw(TRUE);\r
+       GetStatisticsString();\r
+\r
+       CHeaderCtrl * pHeader = GetHeaderCtrl();\r
+       HDITEM HeaderItem = {0};\r
+       HeaderItem.mask = HDI_FORMAT;\r
+       for (int i=0; i<pHeader->GetItemCount(); ++i)\r
+       {\r
+               pHeader->GetItem(i, &HeaderItem);\r
+               HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
+               pHeader->SetItem(i, &HeaderItem);\r
+       }\r
+       if (m_nSortedColumn)\r
+       {\r
+               pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
+               HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
+               pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
+       }\r
+\r
+       if (nSelectedEntry)\r
+       {\r
+               SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
+               EnsureVisible(nSelectedEntry, false);\r
+       }\r
+       else\r
+       {\r
+               // Restore the item at the top of the list.\r
+               for (int i=0;GetTopIndex() != nTopIndex;i++)\r
+               {\r
+                       if ( !EnsureVisible(nTopIndex+i,false) )\r
+                       {\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (pApp)\r
+               pApp->DoWaitCursor(-1);\r
+\r
+       m_bEmpty = (GetItemCount() == 0);\r
+       Invalidate();\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::Show(DWORD dwShow, const CTGitPathList& checkedList, bool bShowFolders /* = true */)\r
+{\r
+#if 0\r
+       Locker lock(m_critSec);\r
+       WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseSVN\\LanguageID"), GetUserDefaultLangID());\r
+\r
+       CWinApp * pApp = AfxGetApp();\r
+       if (pApp)\r
+               pApp->DoWaitCursor(1);\r
+       m_dwShow = dwShow;\r
+       m_bShowFolders = bShowFolders;\r
+       m_nSelected = 0;\r
+       int nTopIndex = GetTopIndex();\r
+       POSITION posSelectedEntry = GetFirstSelectedItemPosition();\r
+       int nSelectedEntry = 0;\r
+       if (posSelectedEntry)\r
+               nSelectedEntry = GetNextSelectedItem(posSelectedEntry);\r
+       SetRedraw(FALSE);\r
+       DeleteAllItems();\r
+\r
+       PrepareGroups();\r
+\r
+       m_arListArray.clear();\r
+\r
+       m_arListArray.reserve(m_arStatusArray.size());\r
+       SetItemCount (static_cast<int>(m_arStatusArray.size()));\r
+\r
+       int listIndex = 0;\r
+       for (size_t i=0; i < m_arStatusArray.size(); ++i)\r
+       {\r
+               FileEntry * entry = m_arStatusArray[i];\r
+               if ((entry->inexternal) && (!(dwShow & SVNSLC_SHOWINEXTERNALS)))\r
+                       continue;\r
+               if ((entry->differentrepo || entry->isNested) && (! (dwShow & SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)))\r
+                       continue;\r
+               if (entry->IsFolder() && (!bShowFolders))\r
+                       continue;       // don't show folders if they're not wanted.\r
+               git_wc_status_kind status = SVNStatus::GetMoreImportant(entry->status, entry->remotestatus);\r
+               DWORD showFlags = GetShowFlagsFromSVNStatus(status);\r
+               if (entry->IsLocked())\r
+                       showFlags |= SVNSLC_SHOWLOCKS;\r
+               if (!entry->changelist.IsEmpty())\r
+                       showFlags |= SVNSLC_SHOWINCHANGELIST;\r
+\r
+               // status_ignored is a special case - we must have the 'direct' flag set to add a status_ignored item\r
+               if (status != git_wc_status_ignored || (entry->direct) || (dwShow & SVNSLC_SHOWIGNORED))\r
+               {\r
+                       for (int npath = 0; npath < checkedList.GetCount(); ++npath)\r
+                       {\r
+                               if (entry->GetPath().IsEquivalentTo(checkedList[npath]))\r
+                               {\r
+                                       entry->checked = true;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if ((!entry->IsFolder()) && (status == git_wc_status_deleted) && (dwShow & SVNSLC_SHOWREMOVEDANDPRESENT))\r
+                       {\r
+                               if (PathFileExists(entry->GetPath().GetWinPath()))\r
+                               {\r
+                                       m_arListArray.push_back(i);\r
+                                       AddEntry(entry, langID, listIndex++);\r
+                               }\r
+                       }\r
+                       else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFILES)&&(entry->direct)&&(!entry->IsFolder())))\r
+                       {\r
+                               m_arListArray.push_back(i);\r
+                               AddEntry(entry, langID, listIndex++);\r
+                       }\r
+                       else if ((dwShow & showFlags)||((dwShow & SVNSLC_SHOWDIRECTFOLDER)&&(entry->direct)&&entry->IsFolder()))\r
+                       {\r
+                               m_arListArray.push_back(i);\r
+                               AddEntry(entry, langID, listIndex++);\r
+                       }\r
+                       else if (entry->switched)\r
+                       {\r
+                               m_arListArray.push_back(i);\r
+                               AddEntry(entry, langID, listIndex++);\r
+                       }\r
+               }\r
+       }\r
+\r
+       SetItemCount(listIndex);\r
+\r
+       int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       for (int col = 0; col <= maxcol; col++)\r
+        SetColumnWidth (col, m_ColumnManager.GetWidth (col, true));\r
+\r
+    SetRedraw(TRUE);\r
+       GetStatisticsString();\r
+\r
+       CHeaderCtrl * pHeader = GetHeaderCtrl();\r
+       HDITEM HeaderItem = {0};\r
+       HeaderItem.mask = HDI_FORMAT;\r
+       for (int i=0; i<pHeader->GetItemCount(); ++i)\r
+       {\r
+               pHeader->GetItem(i, &HeaderItem);\r
+               HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
+               pHeader->SetItem(i, &HeaderItem);\r
+       }\r
+       if (m_nSortedColumn)\r
+       {\r
+               pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
+               HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
+               pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
+       }\r
+\r
+       if (nSelectedEntry)\r
+       {\r
+               SetItemState(nSelectedEntry, LVIS_SELECTED, LVIS_SELECTED);\r
+               EnsureVisible(nSelectedEntry, false);\r
+       }\r
+       else\r
+       {\r
+               // Restore the item at the top of the list.\r
+               for (int i=0;GetTopIndex() != nTopIndex;i++)\r
+               {\r
+                       if ( !EnsureVisible(nTopIndex+i,false) )\r
+                       {\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (pApp)\r
+               pApp->DoWaitCursor(-1);\r
+\r
+       m_bEmpty = (GetItemCount() == 0);\r
+       Invalidate();\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::AddEntry(FileEntry * entry, WORD langID, int listIndex)\r
+{\r
+       static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
+       static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
+\r
+       CString path = entry->GetPath().GetGitPathString();\r
+       if ( m_mapFilenameToChecked.size()!=0 && m_mapFilenameToChecked.find(path) != m_mapFilenameToChecked.end() )\r
+       {\r
+               // The user manually de-/selected an item. We now restore this status\r
+               // when refreshing.\r
+               entry->checked = m_mapFilenameToChecked[path];\r
+       }\r
+\r
+       m_bBlock = TRUE;\r
+       TCHAR buf[100];\r
+       int index = listIndex;\r
+       int nCol = 1;\r
+       CString entryname = entry->GetDisplayName();\r
+       int icon_idx = 0;\r
+       if (entry->isfolder)\r
+               icon_idx = m_nIconFolder;\r
+       else\r
+       {\r
+               icon_idx = SYS_IMAGE_LIST().GetPathIconIndex(entry->path);\r
+       }\r
+       // relative path\r
+       InsertItem(index, entryname, icon_idx);\r
+       // SVNSLC_COLFILENAME\r
+       SetItemText(index, nCol++, entry->path.GetFileOrDirectoryName());\r
+       // SVNSLC_COLEXT\r
+       SetItemText(index, nCol++, entry->path.GetFileExtension());\r
+       // SVNSLC_COLSTATUS\r
+       if (entry->isNested)\r
+       {\r
+               CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
+               SetItemText(index, nCol++, sTemp);\r
+       }\r
+       else\r
+       {\r
+               GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (+)"));\r
+               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (s)"));\r
+#if 0\r
+               if ((entry->status == entry->propstatus)&&\r
+                       (entry->status != git_wc_status_normal)&&\r
+                       (entry->status != git_wc_status_unversioned)&&\r
+                       (!GitStatus::IsImportant(entry->textstatus)))\r
+                       _tcscat_s(buf, 100, ponly);\r
+#endif\r
+               SetItemText(index, nCol++, buf);\r
+       }\r
+       // SVNSLC_COLREMOTESTATUS\r
+       if (entry->isNested)\r
+       {\r
+               CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
+               SetItemText(index, nCol++, sTemp);\r
+       }\r
+       else\r
+       {\r
+#if 0\r
+               SVNStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (+)"));\r
+               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (s)"));\r
+               if ((entry->remotestatus == entry->remotepropstatus)&&\r
+                       (entry->remotestatus != git_wc_status_none)&&\r
+                       (entry->remotestatus != git_wc_status_normal)&&\r
+                       (entry->remotestatus != git_wc_status_unversioned)&&\r
+                       (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
+                       _tcscat_s(buf, 100, ponly);\r
+#endif\r
+               SetItemText(index, nCol++, buf);\r
+       }\r
+       // SVNSLC_COLTEXTSTATUS\r
+       if (entry->isNested)\r
+       {\r
+               CString sTemp(MAKEINTRESOURCE(IDS_STATUSLIST_NESTED));\r
+               SetItemText(index, nCol++, sTemp);\r
+       }\r
+       else\r
+       {\r
+#if 0\r
+               SVNStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (+)"));\r
+               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (s)"));\r
+#endif\r
+               SetItemText(index, nCol++, buf);\r
+       }\r
+       // SVNSLC_COLPROPSTATUS\r
+       if (entry->isNested)\r
+       {\r
+               SetItemText(index, nCol++, _T(""));\r
+       }\r
+       else\r
+       {\r
+#if 0\r
+               SVNStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (+)"));\r
+               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                       _tcscat_s(buf, 100, _T(" (s)"));\r
+#endif\r
+               SetItemText(index, nCol++, buf);\r
+       }\r
+       // SVNSLC_COLREMOTETEXT\r
+       if (entry->isNested)\r
+       {\r
+               SetItemText(index, nCol++, _T(""));\r
+       }\r
+       else\r
+       {\r
+#if 0\r
+               SVNStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               SetItemText(index, nCol++, buf);\r
+#endif\r
+       }\r
+       // SVNSLC_COLREMOTEPROP\r
+       if (entry->isNested)\r
+       {\r
+               SetItemText(index, nCol++, _T(""));\r
+       }\r
+       else\r
+       {\r
+//             SVNStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+               SetItemText(index, nCol++, buf);\r
+       }\r
+       // SVNSLC_COLURL\r
+//     SetItemText(index, nCol++, entry->url);\r
+       // SVNSLC_COLLOCK\r
+#if 0\r
+       if (!m_HeadRev.IsHead())\r
+       {\r
+               // we have contacted the repository\r
+\r
+               // decision-matrix\r
+               // wc           repository              text\r
+               // ""           ""                              ""\r
+               // ""           UID1                    owner\r
+               // UID1         UID1                    owner\r
+               // UID1         ""                              lock has been broken\r
+               // UID1         UID2                    lock has been stolen\r
+               if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
+               {\r
+                       if (entry->lock_owner.IsEmpty())\r
+                               SetItemText(index, nCol++, entry->lock_remoteowner);\r
+                       else\r
+                               SetItemText(index, nCol++, entry->lock_owner);\r
+               }\r
+               else if (entry->lock_remotetoken.IsEmpty())\r
+               {\r
+                       // broken lock\r
+                       CString temp(MAKEINTRESOURCE(IDS_STATUSLIST_LOCKBROKEN));\r
+                       SetItemText(index, nCol++, temp);\r
+               }\r
+               else\r
+               {\r
+                       // stolen lock\r
+                       CString temp;\r
+                       temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
+                       SetItemText(index, nCol++, temp);\r
+               }\r
+       }\r
+       else\r
+               SetItemText(index, nCol++, entry->lock_owner);\r
+       // SVNSLC_COLLOCKCOMMENT\r
+       SetItemText(index, nCol++, entry->lock_comment);\r
+       // SVNSLC_COLAUTHOR\r
+       SetItemText(index, nCol++, entry->last_commit_author);\r
+       // SVNSLC_COLREVISION\r
+       CString temp;\r
+       temp.Format(_T("%ld"), entry->last_commit_rev);\r
+       if (entry->last_commit_rev > 0)\r
+               SetItemText(index, nCol++, temp);\r
+       else\r
+               SetItemText(index, nCol++, _T(""));\r
+       // SVNSLC_COLREMOTEREVISION\r
+       temp.Format(_T("%ld"), entry->remoterev);\r
+       if (entry->remoterev > 0)\r
+               SetItemText(index, nCol++, temp);\r
+       else\r
+               SetItemText(index, nCol++, _T(""));\r
+       // SVNSLC_COLDATE\r
+       TCHAR datebuf[SVN_DATE_BUFFER];\r
+       apr_time_t date = entry->last_commit_date;\r
+       SVN::formatDate(datebuf, date, true);\r
+       if (date)\r
+               SetItemText(index, nCol++, datebuf);\r
+       else\r
+               SetItemText(index, nCol++, _T(""));\r
+       // SVNSLC_COLSVNNEEDSLOCK\r
+    BOOL bFoundSVNNeedsLock = entry->present_props.IsNeedsLockSet();\r
+       CString strSVNNeedsLock = (bFoundSVNNeedsLock) ? _T("*") : _T("");\r
+       SetItemText(index, nCol++, strSVNNeedsLock);\r
+       // SVNSLC_COLCOPYFROM\r
+       if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
+               temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
+       else\r
+               temp = entry->copyfrom_url;\r
+       SetItemText(index, nCol++, temp);\r
+       // SVNSLC_COLMODIFICATIONDATE\r
+       __int64 filetime = entry->GetPath().GetLastWriteTime();\r
+       if ( (filetime) && (entry->status!=git_wc_status_deleted) )\r
+       {\r
+               FILETIME* f = (FILETIME*)(__int64*)&filetime;\r
+               TCHAR datebuf[SVN_DATE_BUFFER];\r
+               SVN::formatDate(datebuf,*f,true);\r
+               SetItemText(index, nCol++, datebuf);\r
+       }\r
+       else\r
+       {\r
+               SetItemText(index, nCol++, _T(""));\r
+       }\r
+\r
+    // user-defined properties\r
+    for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
+        ; i < count\r
+        ; ++i)\r
+    {\r
+        assert (i == nCol++);\r
+        assert (m_ColumnManager.IsUserProp (i));\r
+\r
+        CString name = m_ColumnManager.GetName(i);\r
+        if (entry->present_props.HasProperty (name))\r
+               {\r
+                       const CString& propVal = entry->present_props [name];\r
+                       if (propVal.IsEmpty())\r
+                               SetItemText(index, i, m_sNoPropValueText);\r
+                       else\r
+                               SetItemText(index, i, propVal);\r
+               }\r
+               else\r
+            SetItemText(index, i, _T(""));\r
+    }\r
+\r
+       SetCheck(index, entry->checked);\r
+       if (entry->checked)\r
+               m_nSelected++;\r
+       if (m_changelists.find(entry->changelist) != m_changelists.end())\r
+               SetItemGroup(index, m_changelists[entry->changelist]);\r
+       else\r
+               SetItemGroup(index, 0);\r
+       m_bBlock = FALSE;\r
+#endif\r
+}\r
+\r
+bool CGitStatusListCtrl::SetItemGroup(int item, int groupindex)\r
+{\r
+       if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS) == NULL)\r
+               return false;\r
+       if (groupindex < 0)\r
+               return false;\r
+       LVITEM i = {0};\r
+       i.mask = LVIF_GROUPID;\r
+       i.iItem = item;\r
+       i.iSubItem = 0;\r
+       i.iGroupId = groupindex;\r
+\r
+       return !!SetItem(&i);\r
+}\r
+\r
+void CGitStatusListCtrl::Sort()\r
+{\r
+       Locker lock(m_critSec);\r
+\r
+    CSorter predicate (&m_ColumnManager, m_nSortedColumn, m_bAscending);\r
+\r
+       std::sort(m_arStatusArray.begin(), m_arStatusArray.end(), predicate);\r
+       SaveColumnWidths();\r
+       Show(m_dwShow, 0, m_bShowFolders);\r
+}\r
+\r
+void CGitStatusListCtrl::OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
+       *pResult = 0;\r
+       if (m_bBlock)\r
+               return;\r
+       m_bBlock = TRUE;\r
+       if (m_nSortedColumn == phdr->iItem)\r
+               m_bAscending = !m_bAscending;\r
+       else\r
+               m_bAscending = TRUE;\r
+       m_nSortedColumn = phdr->iItem;\r
+       m_mapFilenameToChecked.clear();\r
+       Sort();\r
+\r
+       CHeaderCtrl * pHeader = GetHeaderCtrl();\r
+       HDITEM HeaderItem = {0};\r
+       HeaderItem.mask = HDI_FORMAT;\r
+       for (int i=0; i<pHeader->GetItemCount(); ++i)\r
+       {\r
+               pHeader->GetItem(i, &HeaderItem);\r
+               HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);\r
+               pHeader->SetItem(i, &HeaderItem);\r
+       }\r
+       pHeader->GetItem(m_nSortedColumn, &HeaderItem);\r
+       HeaderItem.fmt |= (m_bAscending ? HDF_SORTUP : HDF_SORTDOWN);\r
+       pHeader->SetItem(m_nSortedColumn, &HeaderItem);\r
+\r
+       // the checked state of the list control items must be restored\r
+       for (int i=0; i<GetItemCount(); ++i)\r
+       {\r
+               FileEntry * entry = GetListEntry(i);\r
+               SetCheck(i, entry->IsChecked());\r
+       }\r
+\r
+       m_bBlock = FALSE;\r
+}\r
+\r
+void CGitStatusListCtrl::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
+       *pResult = 0;\r
+\r
+#define ISCHECKED(x) ((x) ? ((((x)&LVIS_STATEIMAGEMASK)>>12)-1) : FALSE)\r
+       if ((m_bBlock)&&(m_bBlockUI))\r
+       {\r
+               // if we're blocked, prevent changing of the check state\r
+               if ((!ISCHECKED(pNMLV->uOldState) && ISCHECKED(pNMLV->uNewState))||\r
+                       (ISCHECKED(pNMLV->uOldState) && !ISCHECKED(pNMLV->uNewState)))\r
+                       *pResult = TRUE;\r
+       }\r
+}\r
+\r
+BOOL CGitStatusListCtrl::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
+       *pResult = 0;\r
+       if ((pNMLV->uNewState==0)||(pNMLV->uNewState & LVIS_SELECTED)||(pNMLV->uNewState & LVIS_FOCUSED))\r
+               return FALSE;\r
+\r
+       if (m_bBlock)\r
+               return FALSE;\r
+\r
+       bool bSelected = !!(ListView_GetItemState(m_hWnd, pNMLV->iItem, LVIS_SELECTED) & LVIS_SELECTED);\r
+       int nListItems = GetItemCount();\r
+\r
+       m_bBlock = TRUE;\r
+       // was the item checked?\r
+       if (GetCheck(pNMLV->iItem))\r
+       {\r
+               CheckEntry(pNMLV->iItem, nListItems);\r
+               if (bSelected)\r
+               {\r
+                       POSITION pos = GetFirstSelectedItemPosition();\r
+                       int index;\r
+                       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                       {\r
+                               if (index != pNMLV->iItem)\r
+                                       CheckEntry(index, nListItems);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               UncheckEntry(pNMLV->iItem, nListItems);\r
+               if (bSelected)\r
+               {\r
+                       POSITION pos = GetFirstSelectedItemPosition();\r
+                       int index;\r
+                       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                       {\r
+                               if (index != pNMLV->iItem)\r
+                                       UncheckEntry(index, nListItems);\r
+                       }\r
+               }\r
+       }\r
+       GetStatisticsString();\r
+       m_bBlock = FALSE;\r
+       NotifyCheck();\r
+\r
+       return FALSE;\r
+}\r
+\r
+void CGitStatusListCtrl::OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
+    if (   (header != NULL) \r
+        && (header->iItem >= 0) \r
+        && (header->iItem < m_ColumnManager.GetColumnCount()))\r
+    {\r
+        m_ColumnManager.ColumnResized (header->iItem);\r
+    }\r
+\r
+    *pResult = FALSE;\r
+}\r
+\r
+void CGitStatusListCtrl::OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMHEADER header = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
+       *pResult = TRUE;\r
+    if (   (header != NULL) \r
+        && (header->iItem >= 0) \r
+        && (header->iItem < m_ColumnManager.GetColumnCount())\r
+               // only allow the reordering if the column was not moved left of the first\r
+               // visible item - otherwise the 'invisible' columns are not at the far left\r
+               // anymore and we get all kinds of redrawing problems.\r
+               && (header->pitem)\r
+               && (header->pitem->iOrder > m_ColumnManager.GetInvisibleCount()))\r
+    {\r
+        m_ColumnManager.ColumnMoved (header->iItem, header->pitem->iOrder);\r
+               *pResult = FALSE;\r
+    }\r
+\r
+    Invalidate(FALSE);\r
+}\r
+\r
+void CGitStatusListCtrl::CheckEntry(int index, int nListItems)\r
+{\r
+       Locker lock(m_critSec);\r
+       FileEntry * entry = GetListEntry(index);\r
+       ASSERT(entry != NULL);\r
+       if (entry == NULL)\r
+               return;\r
+       SetCheck(index, TRUE);\r
+       entry = GetListEntry(index);\r
+       // if an unversioned item was checked, then we need to check if\r
+       // the parent folders are unversioned too. If the parent folders actually\r
+       // are unversioned, then check those too.\r
+       if (entry->status == git_wc_status_unversioned)\r
+       {\r
+               // we need to check the parent folder too\r
+               const CTGitPath& folderpath = entry->path;\r
+               for (int i=0; i< nListItems; ++i)\r
+               {\r
+                       FileEntry * testEntry = GetListEntry(i);\r
+                       ASSERT(testEntry != NULL);\r
+                       if (testEntry == NULL)\r
+                               continue;\r
+                       if (!testEntry->checked)\r
+                       {\r
+                               if (testEntry->path.IsAncestorOf(folderpath) && (!testEntry->path.IsEquivalentTo(folderpath)))\r
+                               {\r
+                                       SetEntryCheck(testEntry,i,true);\r
+                                       m_nSelected++;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
+       if ( (entry->status == git_wc_status_deleted) || (m_bCheckChildrenWithParent) || (bShift) )\r
+       {\r
+               // if a deleted folder gets checked, we have to check all\r
+               // children of that folder too.\r
+               if (entry->path.IsDirectory())\r
+               {\r
+                       SetCheckOnAllDescendentsOf(entry, true);\r
+               }\r
+\r
+               // if a deleted file or folder gets checked, we have to\r
+               // check all parents of this item too.\r
+               for (int i=0; i<nListItems; ++i)\r
+               {\r
+                       FileEntry * testEntry = GetListEntry(i);\r
+                       ASSERT(testEntry != NULL);\r
+                       if (testEntry == NULL)\r
+                               continue;\r
+                       if (!testEntry->checked)\r
+                       {\r
+                               if (testEntry->path.IsAncestorOf(entry->path) && (!testEntry->path.IsEquivalentTo(entry->path)))\r
+                               {\r
+                                       if ((testEntry->status == git_wc_status_deleted)||(m_bCheckChildrenWithParent))\r
+                                       {\r
+                                               SetEntryCheck(testEntry,i,true);\r
+                                               m_nSelected++;\r
+                                               // now we need to check all children of this parent folder\r
+                                               SetCheckOnAllDescendentsOf(testEntry, true);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       if ( !entry->checked )\r
+       {\r
+               entry->checked = TRUE;\r
+               m_nSelected++;\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::UncheckEntry(int index, int nListItems)\r
+{\r
+       Locker lock(m_critSec);\r
+       FileEntry * entry = GetListEntry(index);\r
+       ASSERT(entry != NULL);\r
+       if (entry == NULL)\r
+               return;\r
+       SetCheck(index, FALSE);\r
+       entry = GetListEntry(index);\r
+       // item was unchecked\r
+       if (entry->path.IsDirectory())\r
+       {\r
+               // disable all files within an unselected folder, except when unchecking a folder with property changes\r
+               bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
+               if ( (entry->status != git_wc_status_modified) || (bShift) )\r
+               {\r
+                       SetCheckOnAllDescendentsOf(entry, false);\r
+               }\r
+       }\r
+       else if (entry->status == git_wc_status_deleted)\r
+       {\r
+               // a "deleted" file was unchecked, so uncheck all parent folders\r
+               // and all children of those parents\r
+               for (int i=0; i<nListItems; i++)\r
+               {\r
+                       FileEntry * testEntry = GetListEntry(i);\r
+                       ASSERT(testEntry != NULL);\r
+                       if (testEntry == NULL)\r
+                               continue;\r
+                       if (testEntry->checked)\r
+                       {\r
+                               if (testEntry->path.IsAncestorOf(entry->path))\r
+                               {\r
+                                       if (testEntry->status == git_wc_status_deleted)\r
+                                       {\r
+                                               SetEntryCheck(testEntry,i,false);\r
+                                               m_nSelected--;\r
+\r
+                                               SetCheckOnAllDescendentsOf(testEntry, false);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       if ( entry->checked )\r
+       {\r
+               entry->checked = FALSE;\r
+               m_nSelected--;\r
+       }\r
+}\r
+\r
+bool CGitStatusListCtrl::EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2)\r
+{\r
+       return pEntry1->path < pEntry2->path;\r
+}\r
+\r
+bool CGitStatusListCtrl::IsEntryVersioned(const FileEntry* pEntry1)\r
+{\r
+       return pEntry1->status != git_wc_status_unversioned;\r
+}\r
+\r
+bool CGitStatusListCtrl::BuildStatistics()\r
+{\r
+       bool bRefetchStatus = false;\r
+       FileEntryVector::iterator itFirstUnversionedEntry;\r
+       itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
+       if (m_bUnversionedLast)\r
+       {\r
+               // We partition the list of items so that it's arrange with all the versioned items first\r
+               // then all the unversioned items afterwards.\r
+               // Then we sort the versioned part of this, so that we can do quick look-ups in it\r
+               std::sort(m_arStatusArray.begin(), itFirstUnversionedEntry, EntryPathCompareNoCase);\r
+               // Also sort the unversioned section, to make the list look nice...\r
+               std::sort(itFirstUnversionedEntry, m_arStatusArray.end(), EntryPathCompareNoCase);\r
+       }\r
+\r
+       // now gather some statistics\r
+       m_nUnversioned = 0;\r
+       m_nNormal = 0;\r
+       m_nModified = 0;\r
+       m_nAdded = 0;\r
+       m_nDeleted = 0;\r
+       m_nConflicted = 0;\r
+       m_nTotal = 0;\r
+       m_nSelected = 0;\r
+       for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
+       {\r
+               const FileEntry * entry = m_arStatusArray[i];\r
+               if (entry)\r
+               {\r
+                       switch (entry->status)\r
+                       {\r
+                       case git_wc_status_normal:\r
+                               m_nNormal++;\r
+                               break;\r
+                       case git_wc_status_added:\r
+                               m_nAdded++;\r
+                               break;\r
+                       case git_wc_status_missing:\r
+                       case git_wc_status_deleted:\r
+                               m_nDeleted++;\r
+                               break;\r
+                       case git_wc_status_replaced:\r
+                       case git_wc_status_modified:\r
+                       case git_wc_status_merged:\r
+                               m_nModified++;\r
+                               break;\r
+                       case git_wc_status_conflicted:\r
+                       case git_wc_status_obstructed:\r
+                               m_nConflicted++;\r
+                               break;\r
+                       case git_wc_status_ignored:\r
+                               m_nUnversioned++;\r
+                               break;\r
+                       default:\r
+#if 0\r
+                               {\r
+                                       if (GitStatus::IsImportant(entry->remotestatus))\r
+                                               break;\r
+                                       m_nUnversioned++;\r
+                                       // If an entry is in an unversioned folder, we don't have to do an expensive array search\r
+                                       // to find out if it got case-renamed: an unversioned folder can't have versioned files\r
+                                       // But nested folders are also considered to be in unversioned folders, we have to do the\r
+                                       // check in that case too, otherwise we would miss case-renamed folders - they show up\r
+                                       // as nested folders.\r
+                                       if (((!entry->inunversionedfolder)||(entry->isNested))&&(m_bUnversionedLast))\r
+                                       {\r
+                                               // check if the unversioned item is just\r
+                                               // a file differing in case but still versioned\r
+                                               FileEntryVector::iterator itMatchingItem;\r
+                                               if(std::binary_search(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase))\r
+                                               {\r
+                                                       // We've confirmed that there *is* a matching file\r
+                                                       // Find its exact location\r
+                                                       FileEntryVector::iterator itMatchingItem;\r
+                                                       itMatchingItem = std::lower_bound(m_arStatusArray.begin(), itFirstUnversionedEntry, entry, EntryPathCompareNoCase);\r
+\r
+                                                       // adjust the case of the filename\r
+                                                       if (MoveFileEx(entry->path.GetWinPath(), (*itMatchingItem)->path.GetWinPath(), MOVEFILE_REPLACE_EXISTING))\r
+                                                       {\r
+                                                               // We successfully adjusted the case in the filename. But there is now a file with status 'missing'\r
+                                                               // in the array, because that's the status of the file before we adjusted the case.\r
+                                                               // We have to refetch the status of that file.\r
+                                                               // Since fetching the status of single files/directories is very expensive and there can be\r
+                                                               // multiple case-renames here, we just set a flag and refetch the status at the end from scratch.\r
+                                                               bRefetchStatus = true;\r
+                                                               DeleteItem(i);\r
+                                                               m_arStatusArray.erase(m_arStatusArray.begin()+i);\r
+                                                               delete entry;\r
+                                                               i--;\r
+                                                               m_nUnversioned--;\r
+                                                               // now that we removed an unversioned item from the array, find the first unversioned item in the 'new'\r
+                                                               // list again.\r
+                                                               itFirstUnversionedEntry = std::partition(m_arStatusArray.begin(), m_arStatusArray.end(), IsEntryVersioned);\r
+                                                       }\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                               }\r
+#endif\r
+                               break;\r
+                       } // switch (entry->status)\r
+               } // if (entry)\r
+       } // for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
+       return !bRefetchStatus;\r
+}\r
+\r
+void CGitStatusListCtrl::GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly)\r
+{\r
+#if 0\r
+       Locker lock(m_critSec);\r
+       rMin = LONG_MAX;\r
+       rMax = 0;\r
+\r
+       if ((bShownOnly)||(bCheckedOnly))\r
+       {\r
+               for (int i=0; i<GetItemCount(); ++i)\r
+               {\r
+                       const FileEntry * entry = GetListEntry(i);\r
+\r
+                       if ((entry)&&(entry->last_commit_rev))\r
+                       {\r
+                               if ((!bCheckedOnly)||(entry->IsChecked()))\r
+                               {\r
+                                       if (entry->last_commit_rev >= 0)\r
+                                       {\r
+                                               rMin = min(rMin, entry->last_commit_rev);\r
+                                               rMax = max(rMax, entry->last_commit_rev);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (int i=0; i < (int)m_arStatusArray.size(); ++i)\r
+               {\r
+                       const FileEntry * entry = m_arStatusArray[i];\r
+                       if ((entry)&&(entry->last_commit_rev))\r
+                       {\r
+                               if (entry->last_commit_rev >= 0)\r
+                               {\r
+                                       rMin = min(rMin, entry->last_commit_rev);\r
+                                       rMax = max(rMax, entry->last_commit_rev);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       if (rMin == LONG_MAX)\r
+               rMin = 0;\r
+#endif\r
+}\r
+\r
+int CGitStatusListCtrl::GetGroupFromPoint(POINT * ppt)\r
+{\r
+       // the point must be relative to the upper left corner of the control\r
+\r
+       if (ppt == NULL)\r
+               return -1;\r
+       if (!IsGroupViewEnabled())\r
+               return -1;\r
+\r
+       POINT pt = *ppt;\r
+       pt.x = 10;\r
+       UINT flags = 0;\r
+       int nItem = -1;\r
+       RECT rc;\r
+       GetWindowRect(&rc);\r
+       while (((flags & LVHT_BELOW) == 0)&&(pt.y < rc.bottom))\r
+       {\r
+               nItem = HitTest(pt, &flags);\r
+               if ((flags & LVHT_ONITEM)||(flags & LVHT_EX_GROUP_HEADER))\r
+               {\r
+                       // the first item below the point\r
+\r
+                       // check if the point is too much right (i.e. if the point\r
+                       // is farther to the right than the width of the item)\r
+                       RECT r;\r
+                       GetItemRect(nItem, &r, LVIR_LABEL);\r
+                       if (ppt->x > r.right)\r
+                               return -1;\r
+\r
+                       LVITEM lv = {0};\r
+                       lv.mask = LVIF_GROUPID;\r
+                       lv.iItem = nItem;\r
+                       GetItem(&lv);\r
+                       int groupID = lv.iGroupId;\r
+                       // now we search upwards and check if the item above this one\r
+                       // belongs to another group. If it belongs to the same group,\r
+                       // we're not over a group header\r
+                       while (pt.y >= 0)\r
+                       {\r
+                               pt.y -= 2;\r
+                               nItem = HitTest(pt, &flags);\r
+                               if ((flags & LVHT_ONITEM)&&(nItem >= 0))\r
+                               {\r
+                                       // the first item below the point\r
+                                       LVITEM lv = {0};\r
+                                       lv.mask = LVIF_GROUPID;\r
+                                       lv.iItem = nItem;\r
+                                       GetItem(&lv);\r
+                                       if (lv.iGroupId != groupID)\r
+                                               return groupID;\r
+                                       else\r
+                                               return -1;\r
+                               }\r
+                       }\r
+                       if (pt.y < 0)\r
+                               return groupID;\r
+                       return -1;\r
+               }\r
+               pt.y += 2;\r
+       };\r
+       return -1;\r
+}\r
+\r
+void CGitStatusListCtrl::OnContextMenuGroup(CWnd * /*pWnd*/, CPoint point)\r
+{\r
+       POINT clientpoint = point;\r
+       ScreenToClient(&clientpoint);\r
+       if ((IsGroupViewEnabled())&&(GetGroupFromPoint(&clientpoint) >= 0))\r
+       {\r
+               CMenu popup;\r
+               if (popup.CreatePopupMenu())\r
+               {\r
+                       CString temp;\r
+                       temp.LoadString(IDS_STATUSLIST_CHECKGROUP);\r
+                       popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CHECKGROUP, temp);\r
+                       temp.LoadString(IDS_STATUSLIST_UNCHECKGROUP);\r
+                       popup.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_UNCHECKGROUP, temp);\r
+                       int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
+                       bool bCheck = false;\r
+                       switch (cmd)\r
+                       {\r
+                       case IDSVNLC_CHECKGROUP:\r
+                               bCheck = true;\r
+                               // fall through here\r
+                       case IDSVNLC_UNCHECKGROUP:\r
+                               {\r
+                                       int group = GetGroupFromPoint(&clientpoint);\r
+                                       // go through all items and check/uncheck those assigned to the group\r
+                                       // but block the OnLvnItemChanged handler\r
+                                       m_bBlock = true;\r
+                                       LVITEM lv;\r
+                                       for (int i=0; i<GetItemCount(); ++i)\r
+                                       {\r
+                                               SecureZeroMemory(&lv, sizeof(LVITEM));\r
+                                               lv.mask = LVIF_GROUPID;\r
+                                               lv.iItem = i;\r
+                                               GetItem(&lv);\r
+                                               if (lv.iGroupId == group)\r
+                                               {\r
+                                                       FileEntry * entry = GetListEntry(i);\r
+                                                       if (entry)\r
+                                                       {\r
+                                                               bool bOldCheck = !!GetCheck(i);\r
+                                                               SetEntryCheck(entry, i, bCheck);\r
+                                                               if (bCheck != bOldCheck)\r
+                                                               {\r
+                                                                       if (bCheck)\r
+                                                                               m_nSelected++;\r
+                                                                       else\r
+                                                                               m_nSelected--;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       GetStatisticsString();\r
+                                       NotifyCheck();\r
+                                       m_bBlock = false;\r
+                               }\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::OnContextMenuList(CWnd * pWnd, CPoint point)\r
+{\r
+#if 0\r
+       WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
+\r
+       bool XPorLater = false;\r
+       OSVERSIONINFOEX inf;\r
+       SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
+       inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
+       GetVersionEx((OSVERSIONINFO *)&inf);\r
+       WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
+       if (fullver >= 0x0501)\r
+               XPorLater = true;\r
+       bool bShift = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
+\r
+       int selIndex = GetSelectionMark();\r
+       if ((point.x == -1) && (point.y == -1))\r
+       {\r
+               CRect rect;\r
+               GetItemRect(selIndex, &rect, LVIR_LABEL);\r
+               ClientToScreen(&rect);\r
+               point = rect.CenterPoint();\r
+       }\r
+       if ((GetSelectedCount() == 0)&&(XPorLater)&&(m_bHasCheckboxes))\r
+       {\r
+               // nothing selected could mean the context menu is requested for\r
+               // a group header\r
+               OnContextMenuGroup(pWnd, point);\r
+       }\r
+       else if (selIndex >= 0)\r
+       {\r
+               FileEntry * entry = GetListEntry(selIndex);\r
+               ASSERT(entry != NULL);\r
+               if (entry == NULL)\r
+                       return;\r
+               const CTGitPath& filepath = entry->path;\r
+               git_wc_status_kind wcStatus = entry->status;\r
+               // entry is selected, now show the popup menu\r
+               Locker lock(m_critSec);\r
+               CIconMenu popup;\r
+               CMenu changelistSubMenu;\r
+               CMenu ignoreSubMenu;\r
+               if (popup.CreatePopupMenu())\r
+               {\r
+                       if (wcStatus >= git_wc_status_normal)\r
+                       {\r
+                               if (m_dwContextMenus & SVNSLC_POPCOMPAREWITHBASE)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_COMPARE, IDS_LOG_COMPAREWITHBASE, IDI_DIFF);\r
+                                       popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
+                               }\r
+\r
+                               if (GetSelectedCount() == 1)\r
+                               {\r
+                                       bool bEntryAdded = false;\r
+                                       if (entry->remotestatus <= git_wc_status_normal)\r
+                                       {\r
+                                               if (wcStatus > git_wc_status_normal)\r
+                                               {\r
+                                                       if ((m_dwContextMenus & SVNSLC_POPGNUDIFF)&&(wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing))\r
+                                                       {\r
+                                                               popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
+                                                               bEntryAdded = true;\r
+                                                       }\r
+                                               }\r
+                                               if (wcStatus > git_wc_status_normal)\r
+                                               {\r
+                                                       if (m_dwContextMenus & SVNSLC_POPCOMMIT)\r
+                                                       {\r
+                                                               popup.AppendMenuIcon(IDSVNLC_COMMIT, IDS_STATUSLIST_CONTEXT_COMMIT, IDI_COMMIT);\r
+                                                               popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
+                                                               bEntryAdded = true;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else if (wcStatus != git_wc_status_deleted)\r
+                                       {\r
+                                               if (m_dwContextMenus & SVNSLC_POPCOMPARE)\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_COMPAREWC, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
+                                                       popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
+                                                       bEntryAdded = true;\r
+                                               }\r
+                                               if (m_dwContextMenus & SVNSLC_POPGNUDIFF)\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_GNUDIFF1, IDS_LOG_POPUP_GNUDIFF, IDI_DIFF);\r
+                                                       bEntryAdded = true;\r
+                                               }\r
+                                       }\r
+                                       if (bEntryAdded)\r
+                                               popup.AppendMenu(MF_SEPARATOR);\r
+                               }\r
+                               else if (GetSelectedCount() > 1)\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPCOMMIT)\r
+                                       {\r
+                                               popup.AppendMenuIcon(IDSVNLC_COMMIT, IDS_STATUSLIST_CONTEXT_COMMIT, IDI_COMMIT);\r
+                                               popup.SetDefaultItem(IDSVNLC_COMPARE, FALSE);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (GetSelectedCount() > 0)\r
+                       {\r
+                               if ((GetSelectedCount() == 2)&&(m_dwContextMenus & SVNSLC_POPREPAIRMOVE))\r
+                               {\r
+                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                       int index = GetNextSelectedItem(pos);\r
+                                       if (index >= 0)\r
+                                       {\r
+                                               FileEntry * entry = GetListEntry(index);\r
+                                               git_wc_status_kind status1 = git_wc_status_none;\r
+                                               git_wc_status_kind status2 = git_wc_status_none;\r
+                                               if (entry)\r
+                                                       status1 = entry->status;\r
+                                               index = GetNextSelectedItem(pos);\r
+                                               if (index >= 0)\r
+                                               {\r
+                                                       entry = GetListEntry(index);\r
+                                                       if (entry)\r
+                                                               status2 = entry->status;\r
+                                                       if ((status1 == git_wc_status_missing && status2 == git_wc_status_unversioned) ||\r
+                                                               (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned))\r
+                                                       {\r
+                                                               popup.AppendMenuIcon(IDSVNLC_REPAIRMOVE, IDS_STATUSLIST_CONTEXT_REPAIRMOVE);\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if (wcStatus > git_wc_status_normal)\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPREVERT)\r
+                                       {\r
+                                               // reverting missing folders is not possible\r
+                                               if (!entry->IsFolder() || (wcStatus != git_wc_status_missing))\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_REVERT, IDS_MENUREVERT, IDI_REVERT);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if (entry->remotestatus > git_wc_status_normal)\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPUPDATE)\r
+                                       {\r
+                                               popup.AppendMenuIcon(IDSVNLC_UPDATE, IDS_MENUUPDATE, IDI_UPDATE);\r
+                                       }\r
+                               }\r
+                       }\r
+                       if ((GetSelectedCount() == 1)&&(wcStatus >= git_wc_status_normal)\r
+                               &&(wcStatus != git_wc_status_ignored))\r
+                       {\r
+                               if (m_dwContextMenus & SVNSLC_POPSHOWLOG)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_LOG, IDS_REPOBROWSE_SHOWLOG, IDI_LOG);\r
+                               }\r
+                               if (m_dwContextMenus & SVNSLC_POPBLAME)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_BLAME, IDS_MENUBLAME, IDI_BLAME);\r
+                               }\r
+                       }\r
+                       if ((wcStatus != git_wc_status_deleted)&&(wcStatus != git_wc_status_missing) && (GetSelectedCount() == 1))\r
+                       {\r
+                               if (m_dwContextMenus & SVNSLC_POPOPEN)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_OPEN, IDS_REPOBROWSE_OPEN, IDI_OPEN);\r
+                                       popup.AppendMenuIcon(IDSVNLC_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
+                               }\r
+                               if (m_dwContextMenus & SVNSLC_POPEXPLORE)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_EXPLORE, IDS_STATUSLIST_CONTEXT_EXPLORE, IDI_EXPLORER);\r
+                               }\r
+                       }\r
+                       if (GetSelectedCount() > 0)\r
+                       {\r
+                               if (((wcStatus == git_wc_status_unversioned)||(wcStatus == git_wc_status_ignored))&&(m_dwContextMenus & SVNSLC_POPDELETE))\r
+                               {\r
+                                       popup.AppendMenuIcon(IDGitLC_DELETE, IDS_MENUREMOVE, IDI_DELETE);\r
+                               }\r
+                               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
+                               {\r
+                                       if (bShift)\r
+                                               popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVEKEEP, IDI_DELETE);\r
+                                       else\r
+                                               popup.AppendMenuIcon(IDGitLC_REMOVE, IDS_MENUREMOVE, IDI_DELETE);\r
+                               }\r
+                               if ((wcStatus == git_wc_status_unversioned)||(wcStatus == git_wc_status_deleted))\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPADD)\r
+                                       {\r
+                                               if ( entry->IsFolder() )\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_ADD_RECURSIVE, IDS_STATUSLIST_CONTEXT_ADD_RECURSIVE, IDI_ADD);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_ADD, IDS_STATUSLIST_CONTEXT_ADD, IDI_ADD);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if ( (wcStatus == git_wc_status_unversioned) || (wcStatus == git_wc_status_deleted) )\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPIGNORE)\r
+                                       {\r
+                                               CTSVNPathList ignorelist;\r
+                                               FillListOfSelectedItemPaths(ignorelist);\r
+                                               // check if all selected entries have the same extension\r
+                                               bool bSameExt = true;\r
+                                               CString sExt;\r
+                                               for (int i=0; i<ignorelist.GetCount(); ++i)\r
+                                               {\r
+                                                       if (sExt.IsEmpty() && (i==0))\r
+                                                               sExt = ignorelist[i].GetFileExtension();\r
+                                                       else if (sExt.CompareNoCase(ignorelist[i].GetFileExtension())!=0)\r
+                                                               bSameExt = false;\r
+                                               }\r
+                                               if (bSameExt)\r
+                                               {\r
+                                                       if (ignoreSubMenu.CreateMenu())\r
+                                                       {\r
+                                                               CString ignorepath;\r
+                                                               if (ignorelist.GetCount()==1)\r
+                                                                       ignorepath = ignorelist[0].GetFileOrDirectoryName();\r
+                                                               else\r
+                                                                       ignorepath.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
+                                                               ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNORE, ignorepath);\r
+                                                               ignorepath = _T("*")+sExt;\r
+                                                               ignoreSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_IGNOREMASK, ignorepath);\r
+                                                               CString temp;\r
+                                                               temp.LoadString(IDS_MENUIGNORE);\r
+                                                               popup.InsertMenu((UINT)-1, MF_BYPOSITION | MF_POPUP, (UINT_PTR)ignoreSubMenu.m_hMenu, temp);\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       CString temp;\r
+                                                       if (ignorelist.GetCount()==1)\r
+                                                       {\r
+                                                               temp.LoadString(IDS_MENUIGNORE);\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               temp.Format(IDS_MENUIGNOREMULTIPLE, ignorelist.GetCount());\r
+                                                       }\r
+                                                       popup.AppendMenuIcon(IDSVNLC_IGNORE, temp, IDI_IGNORE);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       if (((wcStatus == git_wc_status_conflicted)||(entry->isConflicted)))\r
+                       {\r
+                               if ((m_dwContextMenus & SVNSLC_POPCONFLICT)||(m_dwContextMenus & SVNSLC_POPRESOLVE))\r
+                                       popup.AppendMenu(MF_SEPARATOR);\r
+\r
+                               if ((m_dwContextMenus & SVNSLC_POPCONFLICT)&&(entry->textstatus == git_wc_status_conflicted))\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_EDITCONFLICT, IDS_MENUCONFLICT, IDI_CONFLICT);\r
+                               }\r
+                               if (m_dwContextMenus & SVNSLC_POPRESOLVE)\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_RESOLVECONFLICT, IDS_STATUSLIST_CONTEXT_RESOLVED, IDI_RESOLVE);\r
+                               }\r
+                               if ((m_dwContextMenus & SVNSLC_POPRESOLVE)&&(entry->textstatus == git_wc_status_conflicted))\r
+                               {\r
+                                       popup.AppendMenuIcon(IDSVNLC_RESOLVETHEIRS, IDS_SVNPROGRESS_MENUUSETHEIRS, IDI_RESOLVE);\r
+                                       popup.AppendMenuIcon(IDSVNLC_RESOLVEMINE, IDS_SVNPROGRESS_MENUUSEMINE, IDI_RESOLVE);\r
+                               }\r
+                       }\r
+                       if (GetSelectedCount() > 0)\r
+                       {\r
+                               if ((!entry->IsFolder())&&(wcStatus >= git_wc_status_normal)\r
+                                       &&(wcStatus!=git_wc_status_missing)&&(wcStatus!=git_wc_status_deleted)\r
+                                       &&(wcStatus!=git_wc_status_added))\r
+                               {\r
+                                       popup.AppendMenu(MF_SEPARATOR);\r
+                                       if ((entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
+                                       {\r
+                                               if (m_dwContextMenus & SVNSLC_POPLOCK)\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_LOCK, IDS_MENU_LOCK, IDI_LOCK);\r
+                                               }\r
+                                       }\r
+                                       if ((!entry->lock_token.IsEmpty())&&(!entry->IsFolder()))\r
+                                       {\r
+                                               if (m_dwContextMenus & SVNSLC_POPUNLOCK)\r
+                                               {\r
+                                                       popup.AppendMenuIcon(IDSVNLC_UNLOCK, IDS_MENU_UNLOCK, IDI_UNLOCK);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if ((!entry->IsFolder())&&((!entry->lock_token.IsEmpty())||(!entry->lock_remotetoken.IsEmpty())))\r
+                               {\r
+                                       if (m_dwContextMenus & SVNSLC_POPUNLOCKFORCE)\r
+                                       {\r
+                                               popup.AppendMenuIcon(IDSVNLC_UNLOCKFORCE, IDS_MENU_UNLOCKFORCE, IDI_UNLOCK);\r
+                                       }\r
+                               }\r
+\r
+                               if (wcStatus != git_wc_status_missing && wcStatus != git_wc_status_deleted &&wcStatus!=git_wc_status_unversioned)\r
+                               {\r
+                                       popup.AppendMenu(MF_SEPARATOR);\r
+                                       popup.AppendMenuIcon(IDSVNLC_PROPERTIES, IDS_STATUSLIST_CONTEXT_PROPERTIES, IDI_PROPERTIES);\r
+                               }\r
+                               popup.AppendMenu(MF_SEPARATOR);\r
+                               popup.AppendMenuIcon(IDSVNLC_COPY, IDS_STATUSLIST_CONTEXT_COPY, IDI_COPYCLIP);\r
+                               popup.AppendMenuIcon(IDSVNLC_COPYEXT, IDS_STATUSLIST_CONTEXT_COPYEXT, IDI_COPYCLIP);\r
+                               if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS)&&(XPorLater)\r
+                                       &&(wcStatus != git_wc_status_unversioned)&&(wcStatus != git_wc_status_none))\r
+                               {\r
+                                       popup.AppendMenu(MF_SEPARATOR);\r
+                                       // changelist commands\r
+                                       size_t numChangelists = GetNumberOfChangelistsInSelection();\r
+                                       if (numChangelists > 0)\r
+                                       {\r
+                                               popup.AppendMenuIcon(IDSVNLC_REMOVEFROMCS, IDS_STATUSLIST_CONTEXT_REMOVEFROMCS);\r
+                                       }\r
+                                       if ((!entry->IsFolder())&&(changelistSubMenu.CreateMenu()))\r
+                                       {\r
+                                               CString temp;\r
+                                               temp.LoadString(IDS_STATUSLIST_CONTEXT_CREATECS);\r
+                                               changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATECS, temp);\r
+\r
+                                               if (entry->changelist.Compare(SVNSLC_IGNORECHANGELIST))\r
+                                               {\r
+                                                       changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
+                                                       changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, IDSVNLC_CREATEIGNORECS, SVNSLC_IGNORECHANGELIST);\r
+                                               }\r
+\r
+                                               if (m_changelists.size() > 0)\r
+                                               {\r
+                                                       // find the changelist names\r
+                                                       bool bNeedSeparator = true;\r
+                                                       int cmdID = IDSVNLC_MOVETOCS;\r
+                                                       for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
+                                                       {\r
+                                                               if ((entry->changelist.Compare(it->first))&&(it->first.Compare(SVNSLC_IGNORECHANGELIST)))\r
+                                                               {\r
+                                                                       if (bNeedSeparator)\r
+                                                                       {\r
+                                                                               changelistSubMenu.AppendMenu(MF_SEPARATOR);\r
+                                                                               bNeedSeparator = false;\r
+                                                                       }\r
+                                                                       changelistSubMenu.AppendMenu(MF_STRING | MF_ENABLED, cmdID, it->first);\r
+                                                                       cmdID++;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               temp.LoadString(IDS_STATUSLIST_CONTEXT_MOVETOCS);\r
+                                               popup.AppendMenu(MF_POPUP|MF_STRING, (UINT_PTR)changelistSubMenu.GetSafeHmenu(), temp);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
+                       m_bBlock = TRUE;\r
+                       AfxGetApp()->DoWaitCursor(1);\r
+                       int iItemCountBeforeMenuCmd = GetItemCount();\r
+                       bool bForce = false;\r
+                       switch (cmd)\r
+                       {\r
+                       case IDSVNLC_COPY:\r
+                               CopySelectedEntriesToClipboard(0);\r
+                               break;\r
+                       case IDSVNLC_COPYEXT:\r
+                               CopySelectedEntriesToClipboard((DWORD)-1);\r
+                               break;\r
+                       case IDSVNLC_PROPERTIES:\r
+                               {\r
+                                       CTSVNPathList targetList;\r
+                                       FillListOfSelectedItemPaths(targetList);\r
+                                       CEditPropertiesDlg dlg;\r
+                                       dlg.SetPathList(targetList);\r
+                                       dlg.DoModal();\r
+                                       if (dlg.HasChanged())\r
+                                       {\r
+                                               // since the user might have changed/removed/added\r
+                                               // properties recursively, we don't really know\r
+                                               // which items have changed their status.\r
+                                               // So tell the parent to do a refresh.\r
+                                               CWnd* pParent = GetParent();\r
+                                               if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                               {\r
+                                                       pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_COMMIT:\r
+                               {\r
+                                       CTSVNPathList targetList;\r
+                                       FillListOfSelectedItemPaths(targetList);\r
+                                       CTSVNPath tempFile = CTempFiles::Instance().GetTempFilePath(false);\r
+                                       VERIFY(targetList.WriteToFile(tempFile.GetWinPathString()));\r
+                                       CString commandline = CPathUtils::GetAppDirectory();\r
+                                       commandline += _T("TortoiseProc.exe /command:commit /pathfile:\"");\r
+                                       commandline += tempFile.GetWinPathString();\r
+                                       commandline += _T("\"");\r
+                                       commandline += _T(" /deletepathfile");\r
+                                       CAppUtils::LaunchApplication(commandline, NULL, false);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_REVERT:\r
+                               {\r
+                                       // If at least one item is not in the status "added"\r
+                                       // we ask for a confirmation\r
+                                       BOOL bConfirm = FALSE;\r
+                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                       int index;\r
+                                       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                       {\r
+                                               FileEntry * fentry = GetListEntry(index);\r
+                                               if (fentry->textstatus != git_wc_status_added)\r
+                                               {\r
+                                                       bConfirm = TRUE;\r
+                                                       break;\r
+                                               }\r
+                                       }       \r
+\r
+                                       CString str;\r
+                                       str.Format(IDS_PROC_WARNREVERT,GetSelectedCount());\r
+\r
+                                       if (!bConfirm || CMessageBox::Show(this->m_hWnd, str, _T("TortoiseSVN"), MB_YESNO | MB_ICONQUESTION)==IDYES)\r
+                                       {\r
+                                               CTSVNPathList targetList;\r
+                                               FillListOfSelectedItemPaths(targetList);\r
+\r
+                                               // make sure that the list is reverse sorted, so that\r
+                                               // children are removed before any parents\r
+                                               targetList.SortByPathname(true);\r
+\r
+                                               SVN git;\r
+\r
+                                               // put all reverted files in the trashbin, except the ones with 'added'\r
+                                               // status because they are not restored by the revert.\r
+                                               CTSVNPathList delList;\r
+                                               POSITION pos = GetFirstSelectedItemPosition();\r
+                                               int index;\r
+                                               while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                               {\r
+                                                       FileEntry * entry = GetListEntry(index);\r
+                                                       if (entry->status != git_wc_status_added)\r
+                                                               delList.AddPath(entry->GetPath());\r
+                                               }\r
+                                               if (DWORD(CRegDWORD(_T("Software\\TortoiseSVN\\RevertWithRecycleBin"), TRUE)))\r
+                                                       delList.DeleteAllFiles(true);\r
+\r
+                                               if (!git.Revert(targetList, CStringArray(), FALSE))\r
+                                               {\r
+                                                       CMessageBox::Show(this->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       // since the entries got reverted we need to remove\r
+                                                       // them from the list too, if no remote changes are shown,\r
+                                                       // if the unmodified files are not shown\r
+                                                       // and if the item is not part of a changelist\r
+                                                       POSITION pos;\r
+                                                       SetRedraw(FALSE);\r
+                                                       while ((pos = GetFirstSelectedItemPosition())!=0)\r
+                                                       {\r
+                                                               int index;\r
+                                                               index = GetNextSelectedItem(pos);\r
+                                                               FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
+                                                               if ( fentry->IsFolder() )\r
+                                                               {\r
+                                                                       // refresh!\r
+                                                                       CWnd* pParent = GetParent();\r
+                                                                       if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                                                       {\r
+                                                                               pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                                                       }\r
+                                                                       break;\r
+                                                               }\r
+\r
+                                                               BOOL bAdded = (fentry->textstatus == git_wc_status_added);\r
+                                                               fentry->status = git_wc_status_normal;\r
+                                                               fentry->propstatus = git_wc_status_normal;\r
+                                                               fentry->textstatus = git_wc_status_normal;\r
+                                                               fentry->copied = false;\r
+                                                               fentry->isConflicted = false;\r
+                                                               if ((fentry->GetChangeList().IsEmpty()&&(fentry->remotestatus <= git_wc_status_normal))||(m_dwShow & SVNSLC_SHOWNORMAL))\r
+                                                               {\r
+                                                                       if ( bAdded )\r
+                                                                       {\r
+                                                                               // reverting added items makes them unversioned, not 'normal'\r
+                                                                               if (fentry->IsFolder())\r
+                                                                                       fentry->propstatus = git_wc_status_none;\r
+                                                                               else\r
+                                                                                       fentry->propstatus = git_wc_status_unversioned;\r
+                                                                               fentry->status = git_wc_status_unversioned;\r
+                                                                               fentry->textstatus = git_wc_status_unversioned;\r
+                                                                               SetItemState(index, 0, LVIS_SELECTED);\r
+                                                                               SetEntryCheck(fentry, index, false);\r
+                                                                       }\r
+                                                                       else if ((fentry->switched)||(m_dwShow & SVNSLC_SHOWNORMAL))\r
+                                                                       {\r
+                                                                               SetItemState(index, 0, LVIS_SELECTED);\r
+                                                                       }\r
+                                                                       else\r
+                                                                       {\r
+                                                                               m_nTotal--;\r
+                                                                               if (GetCheck(index))\r
+                                                                                       m_nSelected--;\r
+                                                                               RemoveListEntry(index);\r
+                                                                               Invalidate();\r
+                                                                       }\r
+                                                               }\r
+                                                               else\r
+                                                               {\r
+                                                                       SetItemState(index, 0, LVIS_SELECTED);\r
+                                                               }\r
+                                                       }\r
+                                                       SetRedraw(TRUE);\r
+                                                       SaveColumnWidths();\r
+                                                       Show(m_dwShow, 0, m_bShowFolders);\r
+                                                       NotifyCheck();\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_COMPARE:\r
+                               {\r
+                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                       while ( pos )\r
+                                       {\r
+                                               int index = GetNextSelectedItem(pos);\r
+                                               StartDiff(index);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_COMPAREWC:\r
+                               {\r
+                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                       while ( pos )\r
+                                       {\r
+                                               int index = GetNextSelectedItem(pos);\r
+                                               FileEntry * entry = GetListEntry(index);\r
+                                               ASSERT(entry != NULL);\r
+                                               if (entry == NULL)\r
+                                                       continue;\r
+                                               SVNDiff diff(NULL, m_hWnd, true);\r
+                                               diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+                                               git_revnum_t baseRev = entry->Revision;\r
+                                               diff.DiffFileAgainstBase(\r
+                                                       entry->path, baseRev, entry->textstatus, entry->propstatus);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_GNUDIFF1:\r
+                               {\r
+                                       SVNDiff diff(NULL, this->m_hWnd, true);\r
+\r
+                                       if (entry->remotestatus <= git_wc_status_normal)\r
+                                               CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_BASE, entry->path, SVNRev::REV_WC);\r
+                                       else\r
+                                               CAppUtils::StartShowUnifiedDiff(m_hWnd, entry->path, SVNRev::REV_WC, entry->path, SVNRev::REV_HEAD);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_UPDATE:\r
+                               {\r
+                                       CTSVNPathList targetList;\r
+                                       FillListOfSelectedItemPaths(targetList);\r
+                                       bool bAllExist = true;\r
+                                       for (int i=0; i<targetList.GetCount(); ++i)\r
+                                       {\r
+                                               if (!targetList[i].Exists())\r
+                                               {\r
+                                                       bAllExist = false;\r
+                                                       break;\r
+                                               }\r
+                                       }\r
+                                       if (bAllExist)\r
+                                       {\r
+                                               CSVNProgressDlg dlg;\r
+                                               dlg.SetCommand(CSVNProgressDlg::SVNProgress_Update);\r
+                                               dlg.SetPathList(targetList);\r
+                                               dlg.SetRevision(SVNRev::REV_HEAD);\r
+                                               dlg.DoModal();\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CString sTempFile = CTempFiles::Instance().GetTempFilePath(false).GetWinPathString();\r
+                                               targetList.WriteToFile(sTempFile, false);\r
+                                               CString sCmd;\r
+                                               sCmd.Format(_T("\"%s\" /command:update /rev /pathfile:\"%s\" /deletepathfile"),\r
+                                                       (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), (LPCTSTR)sTempFile);\r
+\r
+                                               CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_LOG:\r
+                               {\r
+                                       CString sCmd;\r
+                                       sCmd.Format(_T("\"%s\" /command:log /path:\"%s\""),\r
+                                               (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
+\r
+                                       if (!filepath.IsUrl())\r
+                                       {\r
+                                               sCmd += _T(" /propspath:\"");\r
+                                               sCmd += filepath.GetWinPathString();\r
+                                               sCmd += _T("\"");\r
+                                       }       \r
+\r
+                                       CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_BLAME:\r
+                               {\r
+                                       CString sCmd;\r
+                                       sCmd.Format(_T("\"%s\" /command:blame /path:\"%s\""),\r
+                                               (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")), filepath.GetWinPath());\r
+\r
+                                       if (!filepath.IsUrl())\r
+                                       {\r
+                                               sCmd += _T(" /propspath:\"");\r
+                                               sCmd += filepath.GetWinPathString();\r
+                                               sCmd += _T("\"");\r
+                                       }       \r
+\r
+                                       CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_OPEN:\r
+                               {\r
+                                       int ret = (int)ShellExecute(this->m_hWnd, NULL, filepath.GetWinPath(), NULL, NULL, SW_SHOW);\r
+                                       if (ret <= HINSTANCE_ERROR)\r
+                                       {\r
+                                               CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
+                                               cmd += filepath.GetWinPathString();\r
+                                               CAppUtils::LaunchApplication(cmd, NULL, false);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_OPENWITH:\r
+                               {\r
+                                       CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
+                                       cmd += filepath.GetWinPathString() + _T(" ");\r
+                                       CAppUtils::LaunchApplication(cmd, NULL, false);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_EXPLORE:\r
+                               {\r
+                                       ShellExecute(this->m_hWnd, _T("explore"), filepath.GetDirectory().GetWinPath(), NULL, NULL, SW_SHOW);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_REMOVE:\r
+                               {\r
+                                       SVN git;\r
+                                       CTSVNPathList itemsToRemove;\r
+                                       FillListOfSelectedItemPaths(itemsToRemove);\r
+\r
+                                       // We must sort items before removing, so that files are always removed\r
+                                       // *before* their parents\r
+                                       itemsToRemove.SortByPathname(true);\r
+\r
+                                       bool bSuccess = false;\r
+                                       if (git.Remove(itemsToRemove, FALSE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
+                                       {\r
+                                               bSuccess = true;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               if ((git.Err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE) ||\r
+                                                       (git.Err->apr_err == SVN_ERR_CLIENT_MODIFIED))\r
+                                               {\r
+                                                       CString msg, yes, no, yestoall;\r
+                                                       msg.Format(IDS_PROC_REMOVEFORCE, (LPCTSTR)git.GetLastErrorMessage());\r
+                                                       yes.LoadString(IDS_MSGBOX_YES);\r
+                                                       no.LoadString(IDS_MSGBOX_NO);\r
+                                                       yestoall.LoadString(IDS_PROC_YESTOALL);\r
+                                                       UINT ret = CMessageBox::Show(m_hWnd, msg, _T("TortoiseSVN"), 2, IDI_ERROR, yes, no, yestoall);\r
+                                                       if ((ret == 1)||(ret==3))\r
+                                                       {\r
+                                                               if (!git.Remove(itemsToRemove, TRUE, !!(GetAsyncKeyState(VK_SHIFT) & 0x8000)))\r
+                                                               {\r
+                                                                       CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                                               }\r
+                                                               else\r
+                                                                       bSuccess = true;\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                                       CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                       }\r
+                                       if (bSuccess)\r
+                                       {\r
+                                               // The remove went ok, but we now need to run through the selected items again\r
+                                               // and update their status\r
+                                               POSITION pos = GetFirstSelectedItemPosition();\r
+                                               int index;\r
+                                               std::vector<int> entriesToRemove;\r
+                                               while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                               {\r
+                                                       FileEntry * e = GetListEntry(index);\r
+                                                       if (!bShift &&\r
+                                                               ((e->textstatus == git_wc_status_unversioned)||\r
+                                                               (e->textstatus == git_wc_status_none)||\r
+                                                               (e->textstatus == git_wc_status_ignored)))\r
+                                                       {\r
+                                                               if (GetCheck(index))\r
+                                                                       m_nSelected--;\r
+                                                               m_nTotal--;\r
+                                                               entriesToRemove.push_back(index);\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               e->textstatus = git_wc_status_deleted;\r
+                                                               e->status = git_wc_status_deleted;\r
+                                                               SetEntryCheck(e,index,true);\r
+                                                       }\r
+                                               }\r
+                                               for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
+                                               {\r
+                                                       RemoveListEntry(*it);\r
+                                               }\r
+                                       }\r
+                                       SaveColumnWidths();\r
+                                       Show(m_dwShow, 0, m_bShowFolders);\r
+                                       NotifyCheck();\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_DELETE:\r
+                               {\r
+                                       CTSVNPathList pathlist;\r
+                                       FillListOfSelectedItemPaths(pathlist);\r
+                                       pathlist.RemoveChildren();\r
+                                       CString filelist;\r
+                                       for (INT_PTR i=0; i<pathlist.GetCount(); ++i)\r
+                                       {\r
+                                               filelist += pathlist[i].GetWinPathString();\r
+                                               filelist += _T("|");\r
+                                       }\r
+                                       filelist += _T("|");\r
+                                       int len = filelist.GetLength();\r
+                                       TCHAR * buf = new TCHAR[len+2];\r
+                                       _tcscpy_s(buf, len+2, filelist);\r
+                                       for (int i=0; i<len; ++i)\r
+                                               if (buf[i] == '|')\r
+                                                       buf[i] = 0;\r
+                                       SHFILEOPSTRUCT fileop;\r
+                                       fileop.hwnd = this->m_hWnd;\r
+                                       fileop.wFunc = FO_DELETE;\r
+                                       fileop.pFrom = buf;\r
+                                       fileop.pTo = NULL;\r
+                                       fileop.fFlags = FOF_NO_CONNECTED_ELEMENTS | ((GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 0 : FOF_ALLOWUNDO);\r
+                                       fileop.lpszProgressTitle = _T("deleting file");\r
+                                       int result = SHFileOperation(&fileop);\r
+                                       delete [] buf;\r
+\r
+                                       if ( (result==0) && (!fileop.fAnyOperationsAborted) )\r
+                                       {\r
+                                               SetRedraw(FALSE);\r
+                                               POSITION pos = NULL;\r
+                                               CTSVNPathList deletedlist;      // to store list of deleted folders\r
+                                               while ((pos = GetFirstSelectedItemPosition()) != 0)\r
+                                               {\r
+                                                       int index = GetNextSelectedItem(pos);\r
+                                                       if (GetCheck(index))\r
+                                                               m_nSelected--;\r
+                                                       m_nTotal--;\r
+                                                       FileEntry * fentry = GetListEntry(index);\r
+                                                       if ((fentry)&&(fentry->isfolder))\r
+                                                               deletedlist.AddPath(fentry->path);\r
+                                                       RemoveListEntry(index);\r
+                                               }\r
+                                               // now go through the list of deleted folders\r
+                                               // and remove all their children from the list too!\r
+                                               int nListboxEntries = GetItemCount();\r
+                                               for (int folderindex = 0; folderindex < deletedlist.GetCount(); ++folderindex)\r
+                                               {\r
+                                                       CTSVNPath folderpath = deletedlist[folderindex];\r
+                                                       for (int i=0; i<nListboxEntries; ++i)\r
+                                                       {\r
+                                                               FileEntry * entry = GetListEntry(i);\r
+                                                               if (folderpath.IsAncestorOf(entry->path))\r
+                                                               {\r
+                                                                       RemoveListEntry(i--);\r
+                                                                       nListboxEntries--;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               SetRedraw(TRUE);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_IGNOREMASK:\r
+                               {\r
+                                       CString name = _T("*")+filepath.GetFileExtension();\r
+                                       CTSVNPathList ignorelist;\r
+                                       FillListOfSelectedItemPaths(ignorelist, true);\r
+                                       std::set<CTSVNPath> parentlist;\r
+                                       for (int i=0; i<ignorelist.GetCount(); ++i)\r
+                                       {\r
+                                               parentlist.insert(ignorelist[i].GetContainingDirectory());\r
+                                       }\r
+                                       std::set<CTSVNPath>::iterator it;\r
+                                       std::vector<CString> toremove;\r
+                                       SetRedraw(FALSE);\r
+                                       for (it = parentlist.begin(); it != parentlist.end(); ++it)\r
+                                       {\r
+                                               CTSVNPath parentFolder = (*it).GetDirectory();\r
+                                               SVNProperties props(parentFolder, SVNRev::REV_WC, false);\r
+                                               CStringA value;\r
+                                               for (int i=0; i<props.GetCount(); i++)\r
+                                               {\r
+                                                       CString propname(props.GetItemName(i).c_str());\r
+                                                       if (propname.CompareNoCase(_T("git:ignore"))==0)\r
+                                                       {\r
+                                                               stdstring stemp;\r
+                                                               // treat values as normal text even if they're not\r
+                                                               value = (char *)props.GetItemValue(i).c_str();\r
+                                                       }\r
+                                               }\r
+                                               if (value.IsEmpty())\r
+                                                       value = name;\r
+                                               else\r
+                                               {\r
+                                                       value = value.Trim("\n\r");\r
+                                                       value += "\n";\r
+                                                       value += name;\r
+                                                       value.Remove('\r');\r
+                                               }\r
+                                               if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
+                                               {\r
+                                                       CString temp;\r
+                                                       temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
+                                                       CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       CTSVNPath basepath;\r
+                                                       int nListboxEntries = GetItemCount();\r
+                                                       for (int i=0; i<nListboxEntries; ++i)\r
+                                                       {\r
+                                                               FileEntry * entry = GetListEntry(i);\r
+                                                               ASSERT(entry != NULL);\r
+                                                               if (entry == NULL)\r
+                                                                       continue;\r
+                                                               if (basepath.IsEmpty())\r
+                                                                       basepath = entry->basepath;\r
+                                                               // since we ignored files with a mask (e.g. *.exe)\r
+                                                               // we have to find find all files in the same\r
+                                                               // folder (IsAncestorOf() returns TRUE for _all_ children,\r
+                                                               // not just the immediate ones) which match the\r
+                                                               // mask and remove them from the list too.\r
+                                                               if ((entry->status == git_wc_status_unversioned)&&(parentFolder.IsAncestorOf(entry->path)))\r
+                                                               {\r
+                                                                       CString f = entry->path.GetSVNPathString();\r
+                                                                       if (f.Mid(parentFolder.GetSVNPathString().GetLength()).Find('/')<=0)\r
+                                                                       {\r
+                                                                               if (CStringUtils::WildCardMatch(name, f))\r
+                                                                               {\r
+                                                                                       if (GetCheck(i))\r
+                                                                                               m_nSelected--;\r
+                                                                                       m_nTotal--;\r
+                                                                                       toremove.push_back(f);\r
+                                                                               }\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                                       if (!m_bIgnoreRemoveOnly)\r
+                                                       {\r
+                                                               SVNStatus status;\r
+                                                               git_wc_status2_t * s;\r
+                                                               CTSVNPath gitPath;\r
+                                                               s = status.GetFirstFileStatus(parentFolder, gitPath, false, git_depth_empty);\r
+                                                               if (s!=0)\r
+                                                               {\r
+                                                                       // first check if the folder isn't already present in the list\r
+                                                                       bool bFound = false;\r
+                                                                       for (int i=0; i<nListboxEntries; ++i)\r
+                                                                       {\r
+                                                                               FileEntry * entry = GetListEntry(i);\r
+                                                                               if (entry->path.IsEquivalentTo(gitPath))\r
+                                                                               {\r
+                                                                                       bFound = true;\r
+                                                                                       break;\r
+                                                                               }\r
+                                                                       }\r
+                                                                       if (!bFound)\r
+                                                                       {\r
+                                                                               FileEntry * entry = new FileEntry();\r
+                                                                               entry->path = gitPath;\r
+                                                                               entry->basepath = basepath;\r
+                                                                               entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
+                                                                               entry->textstatus = s->text_status;\r
+                                                                               entry->propstatus = s->prop_status;\r
+                                                                               entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
+                                                                               entry->remotetextstatus = s->repos_text_status;\r
+                                                                               entry->remotepropstatus = s->repos_prop_status;\r
+                                                                               entry->inunversionedfolder = false;\r
+                                                                               entry->checked = true;\r
+                                                                               entry->inexternal = false;\r
+                                                                               entry->direct = false;\r
+                                                                               entry->isfolder = true;\r
+                                                                               entry->last_commit_date = 0;\r
+                                                                               entry->last_commit_rev = 0;\r
+                                                                               entry->remoterev = 0;\r
+                                                                               if (s->entry)\r
+                                                                               {\r
+                                                                                       if (s->entry->url)\r
+                                                                                       {\r
+                                                                                               entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
+                                                                                       }\r
+                                                                               }\r
+                                                                               if (s->entry && s->entry->present_props)\r
+                                                                               {\r
+                                                                                       entry->present_props = s->entry->present_props;\r
+                                                                               }\r
+                                                                               m_arStatusArray.push_back(entry);\r
+                                                                               m_arListArray.push_back(m_arStatusArray.size()-1);\r
+                                                                               AddEntry(entry, langID, GetItemCount());\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
+                                       {\r
+                                               int nListboxEntries = GetItemCount();\r
+                                               for (int i=0; i<nListboxEntries; ++i)\r
+                                               {\r
+                                                       if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
+                                                       {\r
+                                                               RemoveListEntry(i);\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       SetRedraw(TRUE);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_IGNORE:\r
+                               {\r
+                                       CTSVNPathList ignorelist;\r
+                                       std::vector<CString> toremove;\r
+                                       FillListOfSelectedItemPaths(ignorelist, true);\r
+                                       SetRedraw(FALSE);\r
+                                       for (int j=0; j<ignorelist.GetCount(); ++j)\r
+                                       {\r
+                                               int nListboxEntries = GetItemCount();\r
+                                               for (int i=0; i<nListboxEntries; ++i)\r
+                                               {\r
+                                                       if (GetListEntry(i)->GetPath().IsEquivalentTo(ignorelist[j]))\r
+                                                       {\r
+                                                               selIndex = i;\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                               CString name = CPathUtils::PathPatternEscape(ignorelist[j].GetFileOrDirectoryName());\r
+                                               CTSVNPath parentfolder = ignorelist[j].GetContainingDirectory();\r
+                                               SVNProperties props(parentfolder, SVNRev::REV_WC, false);\r
+                                               CStringA value;\r
+                                               for (int i=0; i<props.GetCount(); i++)\r
+                                               {\r
+                                                       CString propname(props.GetItemName(i).c_str());\r
+                                                       if (propname.CompareNoCase(_T("git:ignore"))==0)\r
+                                                       {\r
+                                                               stdstring stemp;\r
+                                                               // treat values as normal text even if they're not\r
+                                                               value = (char *)props.GetItemValue(i).c_str();\r
+                                                       }\r
+                                               }\r
+                                               if (value.IsEmpty())\r
+                                                       value = name;\r
+                                               else\r
+                                               {\r
+                                                       value = value.Trim("\n\r");\r
+                                                       value += "\n";\r
+                                                       value += name;\r
+                                                       value.Remove('\r');\r
+                                               }\r
+                                               if (!props.Add(_T("git:ignore"), (LPCSTR)value))\r
+                                               {\r
+                                                       CString temp;\r
+                                                       temp.Format(IDS_ERR_FAILEDIGNOREPROPERTY, (LPCTSTR)name);\r
+                                                       CMessageBox::Show(this->m_hWnd, temp, _T("TortoiseSVN"), MB_ICONERROR);\r
+                                                       break;\r
+                                               }\r
+                                               if (GetCheck(selIndex))\r
+                                                       m_nSelected--;\r
+                                               m_nTotal--;\r
+\r
+                                               // now, if we ignored a folder, remove all its children\r
+                                               if (ignorelist[j].IsDirectory())\r
+                                               {\r
+                                                       for (int i=0; i<(int)m_arListArray.size(); ++i)\r
+                                                       {\r
+                                                               FileEntry * entry = GetListEntry(i);\r
+                                                               if (entry->status == git_wc_status_unversioned)\r
+                                                               {\r
+                                                                       if (!ignorelist[j].IsEquivalentTo(entry->GetPath())&&(ignorelist[j].IsAncestorOf(entry->GetPath())))\r
+                                                                       {\r
+                                                                               entry->status = git_wc_status_ignored;\r
+                                                                               entry->textstatus = git_wc_status_ignored;\r
+                                                                               if (GetCheck(i))\r
+                                                                                       m_nSelected--;\r
+                                                                               toremove.push_back(entry->GetPath().GetSVNPathString());\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+\r
+                                               CTSVNPath basepath = m_arStatusArray[m_arListArray[selIndex]]->basepath;\r
+\r
+                                               FileEntry * entry = m_arStatusArray[m_arListArray[selIndex]];\r
+                                               if ( entry->status == git_wc_status_unversioned ) // keep "deleted" items\r
+                                                       toremove.push_back(entry->GetPath().GetSVNPathString());\r
+\r
+                                               if (!m_bIgnoreRemoveOnly)\r
+                                               {\r
+                                                       SVNStatus status;\r
+                                                       git_wc_status2_t * s;\r
+                                                       CTSVNPath gitPath;\r
+                                                       s = status.GetFirstFileStatus(parentfolder, gitPath, false, git_depth_empty);\r
+                                                       // first check if the folder isn't already present in the list\r
+                                                       bool bFound = false;\r
+                                                       nListboxEntries = GetItemCount();\r
+                                                       for (int i=0; i<nListboxEntries; ++i)\r
+                                                       {\r
+                                                               FileEntry * entry = GetListEntry(i);\r
+                                                               if (entry->path.IsEquivalentTo(gitPath))\r
+                                                               {\r
+                                                                       bFound = true;\r
+                                                                       break;\r
+                                                               }\r
+                                                       }\r
+                                                       if (!bFound)\r
+                                                       {\r
+                                                               if (s!=0)\r
+                                                               {\r
+                                                                       FileEntry * entry = new FileEntry();\r
+                                                                       entry->path = gitPath;\r
+                                                                       entry->basepath = basepath;\r
+                                                                       entry->status = SVNStatus::GetMoreImportant(s->text_status, s->prop_status);\r
+                                                                       entry->textstatus = s->text_status;\r
+                                                                       entry->propstatus = s->prop_status;\r
+                                                                       entry->remotestatus = SVNStatus::GetMoreImportant(s->repos_text_status, s->repos_prop_status);\r
+                                                                       entry->remotetextstatus = s->repos_text_status;\r
+                                                                       entry->remotepropstatus = s->repos_prop_status;\r
+                                                                       entry->inunversionedfolder = FALSE;\r
+                                                                       entry->checked = true;\r
+                                                                       entry->inexternal = false;\r
+                                                                       entry->direct = false;\r
+                                                                       entry->isfolder = true;\r
+                                                                       entry->last_commit_date = 0;\r
+                                                                       entry->last_commit_rev = 0;\r
+                                                                       entry->remoterev = 0;\r
+                                                                       if (s->entry)\r
+                                                                       {\r
+                                                                               if (s->entry->url)\r
+                                                                               {\r
+                                                                                       entry->url = CUnicodeUtils::GetUnicode(CPathUtils::PathUnescape(s->entry->url));\r
+                                                                               }\r
+                                                                       }\r
+                                                                       if (s->entry && s->entry->present_props)\r
+                                                                       {\r
+                                                                               entry->present_props = s->entry->present_props;\r
+                                                                       }\r
+                                                                       m_arStatusArray.push_back(entry);\r
+                                                                       m_arListArray.push_back(m_arStatusArray.size()-1);\r
+                                                                       AddEntry(entry, langID, GetItemCount());\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       for (std::vector<CString>::iterator it = toremove.begin(); it != toremove.end(); ++it)\r
+                                       {\r
+                                               int nListboxEntries = GetItemCount();\r
+                                               for (int i=0; i<nListboxEntries; ++i)\r
+                                               {\r
+                                                       if (GetListEntry(i)->path.GetSVNPathString().Compare(*it)==0)\r
+                                                       {\r
+                                                               RemoveListEntry(i);\r
+                                                               break;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       SetRedraw(TRUE);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_EDITCONFLICT:\r
+                               SVNDiff::StartConflictEditor(filepath);\r
+                               break;\r
+                       case IDSVNLC_RESOLVECONFLICT:\r
+                       case IDSVNLC_RESOLVEMINE:\r
+                       case IDSVNLC_RESOLVETHEIRS:\r
+                               {\r
+                                       git_wc_conflict_choice_t result = git_wc_conflict_choose_merged;\r
+                                       switch (cmd)\r
+                                       {\r
+                                       case IDSVNLC_RESOLVETHEIRS:\r
+                                               result = git_wc_conflict_choose_theirs_full;\r
+                                               break;\r
+                                       case IDSVNLC_RESOLVEMINE:\r
+                                               result = git_wc_conflict_choose_mine_full;\r
+                                               break;\r
+                                       case IDSVNLC_RESOLVECONFLICT:\r
+                                               result = git_wc_conflict_choose_merged;\r
+                                               break;\r
+                                       }\r
+                                       if (CMessageBox::Show(m_hWnd, IDS_PROC_RESOLVE, IDS_APPNAME, MB_ICONQUESTION | MB_YESNO)==IDYES)\r
+                                       {\r
+                                               SVN git;\r
+                                               POSITION pos = GetFirstSelectedItemPosition();\r
+                                               while (pos != 0)\r
+                                               {\r
+                                                       int index;\r
+                                                       index = GetNextSelectedItem(pos);\r
+                                                       FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
+                                                       if (!git.Resolve(fentry->GetPath(), result, FALSE))\r
+                                                       {\r
+                                                               CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               fentry->status = git_wc_status_modified;\r
+                                                               fentry->textstatus = git_wc_status_modified;\r
+                                                               fentry->isConflicted = false;\r
+                                                       }\r
+                                               }\r
+                                               Show(m_dwShow, 0, m_bShowFolders);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_ADD:\r
+                               {\r
+                                       SVN git;\r
+                                       CTSVNPathList itemsToAdd;\r
+                                       FillListOfSelectedItemPaths(itemsToAdd);\r
+\r
+                                       // We must sort items before adding, so that folders are always added\r
+                                       // *before* any of their children\r
+                                       itemsToAdd.SortByPathname();\r
+\r
+                                       ProjectProperties props;\r
+                                       props.ReadPropsPathList(itemsToAdd);\r
+                                       if (git.Add(itemsToAdd, &props, git_depth_empty, TRUE, TRUE, TRUE))\r
+                                       {\r
+                                               // The add went ok, but we now need to run through the selected items again\r
+                                               // and update their status\r
+                                               POSITION pos = GetFirstSelectedItemPosition();\r
+                                               int index;\r
+                                               while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                               {\r
+                                                       FileEntry * e = GetListEntry(index);\r
+                                                       e->textstatus = git_wc_status_added;\r
+                                                       e->propstatus = git_wc_status_none;\r
+                                                       e->status = git_wc_status_added;\r
+                                                       SetEntryCheck(e,index,true);\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                       }\r
+                                       SaveColumnWidths();\r
+                                       Show(m_dwShow, 0, m_bShowFolders);\r
+                                       NotifyCheck();\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_ADD_RECURSIVE:\r
+                               {\r
+                                       CTSVNPathList itemsToAdd;\r
+                                       FillListOfSelectedItemPaths(itemsToAdd);\r
+\r
+                                       CAddDlg dlg;\r
+                                       dlg.m_pathList = itemsToAdd;\r
+                                       if (dlg.DoModal() == IDOK)\r
+                                       {\r
+                                               if (dlg.m_pathList.GetCount() == 0)\r
+                                                       break;\r
+                                               CSVNProgressDlg progDlg;\r
+                                               progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Add);\r
+                                               progDlg.SetPathList(dlg.m_pathList);\r
+                                               ProjectProperties props;\r
+                                               props.ReadPropsPathList(dlg.m_pathList);\r
+                                               progDlg.SetProjectProperties(props);\r
+                                               progDlg.SetItemCount(dlg.m_pathList.GetCount());\r
+                                               progDlg.DoModal();\r
+\r
+                                               // refresh!\r
+                                               CWnd* pParent = GetParent();\r
+                                               if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                               {\r
+                                                       pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_LOCK:\r
+                               {\r
+                                       CTSVNPathList itemsToLock;\r
+                                       FillListOfSelectedItemPaths(itemsToLock);\r
+                                       CInputDlg inpDlg;\r
+                                       inpDlg.m_sTitle.LoadString(IDS_MENU_LOCK);\r
+                                       CStringUtils::RemoveAccelerators(inpDlg.m_sTitle);\r
+                                       inpDlg.m_sHintText.LoadString(IDS_LOCK_MESSAGEHINT);\r
+                                       inpDlg.m_sCheckText.LoadString(IDS_LOCK_STEALCHECK);\r
+                                       ProjectProperties props;\r
+                                       props.ReadPropsPathList(itemsToLock);\r
+                                       props.nMinLogSize = 0;          // the lock message is optional, so no minimum!\r
+                                       inpDlg.m_pProjectProperties = &props;\r
+                                       if (inpDlg.DoModal()==IDOK)\r
+                                       {\r
+                                               CSVNProgressDlg progDlg;\r
+                                               progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Lock);\r
+                                               progDlg.SetOptions(inpDlg.m_iCheck ? ProgOptLockForce : ProgOptNone);\r
+                                               progDlg.SetPathList(itemsToLock);\r
+                                               progDlg.SetCommitMessage(inpDlg.m_sInputText);\r
+                                               progDlg.DoModal();\r
+                                               // refresh!\r
+                                               CWnd* pParent = GetParent();\r
+                                               if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                               {\r
+                                                       pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_UNLOCKFORCE:\r
+                               bForce = true;\r
+                       case IDSVNLC_UNLOCK:\r
+                               {\r
+                                       CTSVNPathList itemsToUnlock;\r
+                                       FillListOfSelectedItemPaths(itemsToUnlock);\r
+                                       CSVNProgressDlg progDlg;\r
+                                       progDlg.SetCommand(CSVNProgressDlg::SVNProgress_Unlock);\r
+                                       progDlg.SetOptions(bForce ? ProgOptLockForce : ProgOptNone);\r
+                                       progDlg.SetPathList(itemsToUnlock);\r
+                                       progDlg.DoModal();\r
+                                       // refresh!\r
+                                       CWnd* pParent = GetParent();\r
+                                       if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                       {\r
+                                               pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_REPAIRMOVE:\r
+                               {\r
+                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                       int index = GetNextSelectedItem(pos);\r
+                                       FileEntry * entry1 = NULL;\r
+                                       FileEntry * entry2 = NULL;\r
+                                       if (index >= 0)\r
+                                       {\r
+                                               entry1 = GetListEntry(index);\r
+                                               git_wc_status_kind status1 = git_wc_status_none;\r
+                                               git_wc_status_kind status2 = git_wc_status_none;\r
+                                               if (entry1)\r
+                                               {\r
+                                                       status1 = entry1->status;\r
+                                                       index = GetNextSelectedItem(pos);\r
+                                                       if (index >= 0)\r
+                                                       {\r
+                                                               entry2 = GetListEntry(index);\r
+                                                               if (entry2)\r
+                                                               {\r
+                                                                       status2 = entry2->status;\r
+                                                                       if (status2 == git_wc_status_missing && status1 == git_wc_status_unversioned)\r
+                                                                       {\r
+                                                                               FileEntry * tempentry = entry1;\r
+                                                                               entry1 = entry2;\r
+                                                                               entry2 = tempentry;\r
+                                                                       }\r
+                                                                       // entry1 was renamed to entry2 but outside of Subversion\r
+                                                                       // fix this by moving entry2 back to entry1 first,\r
+                                                                       // then do an git-move from entry1 to entry2\r
+                                                                       if (MoveFile(entry2->GetPath().GetWinPath(), entry1->GetPath().GetWinPath()))\r
+                                                                       {\r
+                                                                               SVN git;\r
+                                                                               if (!git.Move(CTSVNPathList(entry1->GetPath()), entry2->GetPath(), TRUE))\r
+                                                                               {\r
+                                                                                       CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                                                               }\r
+                                                                               else\r
+                                                                               {\r
+                                                                                       // check the previously unversioned item\r
+                                                                                       entry1->checked = true;\r
+                                                                                       // fixing the move was successful. We have to adjust the new status of the\r
+                                                                                       // files.\r
+                                                                                       // Since we don't know if the moved/renamed file had local modifications or not,\r
+                                                                                       // we can't guess the new status. That means we have to refresh...\r
+                                                                                       CWnd* pParent = GetParent();\r
+                                                                                       if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                                                                                       {\r
+                                                                                               pParent->SendMessage(SVNSLNM_NEEDSREFRESH);\r
+                                                                                       }\r
+                                                                               }\r
+                                                                       }\r
+                                                                       else\r
+                                                                       {\r
+                                                                               LPVOID lpMsgBuf;\r
+                                                                               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | \r
+                                                                                       FORMAT_MESSAGE_FROM_SYSTEM | \r
+                                                                                       FORMAT_MESSAGE_IGNORE_INSERTS,\r
+                                                                                       NULL,\r
+                                                                                       GetLastError(),\r
+                                                                                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\r
+                                                                                       (LPTSTR) &lpMsgBuf,\r
+                                                                                       0,\r
+                                                                                       NULL \r
+                                                                                       );\r
+                                                                               MessageBox((LPCTSTR)lpMsgBuf, _T("Error"), MB_OK | MB_ICONINFORMATION );\r
+                                                                               LocalFree( lpMsgBuf );\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_REMOVEFROMCS:\r
+                               {\r
+                                       CTSVNPathList changelistItems;\r
+                                       FillListOfSelectedItemPaths(changelistItems);\r
+                                       SVN git;\r
+                                       SetRedraw(FALSE);\r
+                                       if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
+                                       {\r
+                                               // The changelists were removed, but we now need to run through the selected items again\r
+                                               // and update their changelist\r
+                                               POSITION pos = GetFirstSelectedItemPosition();\r
+                                               int index;\r
+                                               std::vector<int> entriesToRemove;\r
+                                               while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                               {\r
+                                                       FileEntry * e = GetListEntry(index);\r
+                                                       if (e)\r
+                                                       {\r
+                                                               e->changelist.Empty();\r
+                                                               if (e->status == git_wc_status_normal)\r
+                                                               {\r
+                                                                       // remove the entry completely\r
+                                                                       entriesToRemove.push_back(index);\r
+                                                               }\r
+                                                               else\r
+                                                                       SetItemGroup(index, 0);\r
+                                                       }\r
+                                               }\r
+                                               for (std::vector<int>::reverse_iterator it = entriesToRemove.rbegin(); it != entriesToRemove.rend(); ++it)\r
+                                               {\r
+                                                       RemoveListEntry(*it);\r
+                                               }\r
+                                               // TODO: Should we go through all entries here and check if we also could\r
+                                               // remove the changelist from m_changelists ?\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                       }\r
+                                       SetRedraw(TRUE);\r
+                               }\r
+                               break;\r
+                       case IDSVNLC_CREATEIGNORECS:\r
+                               CreateChangeList(SVNSLC_IGNORECHANGELIST);\r
+                               break;\r
+                       case IDSVNLC_CREATECS:\r
+                               {\r
+                                       CCreateChangelistDlg dlg;\r
+                                       if (dlg.DoModal() == IDOK)\r
+                                       {\r
+                                               CreateChangeList(dlg.m_sName);\r
+                                       }\r
+                               }\r
+                               break;\r
+                       default:\r
+                               {\r
+                                       if (cmd < IDSVNLC_MOVETOCS)\r
+                                               break;\r
+                                       CTSVNPathList changelistItems;\r
+                                       FillListOfSelectedItemPaths(changelistItems);\r
+\r
+                                       // find the changelist name\r
+                                       CString sChangelist;\r
+                                       int cmdID = IDSVNLC_MOVETOCS;\r
+                                       SetRedraw(FALSE);\r
+                                       for (std::map<CString, int>::const_iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
+                                       {\r
+                                               if ((it->first.Compare(SVNSLC_IGNORECHANGELIST))&&(entry->changelist.Compare(it->first)))\r
+                                               {\r
+                                                       if (cmd == cmdID)\r
+                                                       {\r
+                                                               sChangelist = it->first;\r
+                                                       }\r
+                                                       cmdID++;\r
+                                               }\r
+                                       }\r
+                                       if (!sChangelist.IsEmpty())\r
+                                       {\r
+                                               SVN git;\r
+                                               if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
+                                               {\r
+                                                       // The changelists were moved, but we now need to run through the selected items again\r
+                                                       // and update their changelist\r
+                                                       POSITION pos = GetFirstSelectedItemPosition();\r
+                                                       int index;\r
+                                                       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+                                                       {\r
+                                                               FileEntry * e = GetListEntry(index);\r
+                                                               e->changelist = sChangelist;\r
+                                                               if (!e->IsFolder())\r
+                                                               {\r
+                                                                       if (m_changelists.find(e->changelist)!=m_changelists.end())\r
+                                                                               SetItemGroup(index, m_changelists[e->changelist]);\r
+                                                                       else\r
+                                                                               SetItemGroup(index, 0);\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                               }\r
+                                       }\r
+                                       SetRedraw(TRUE);\r
+                               }\r
+                               break;\r
+                       } // switch (cmd)\r
+                       m_bBlock = FALSE;\r
+                       AfxGetApp()->DoWaitCursor(-1);\r
+                       GetStatisticsString();\r
+                       int iItemCountAfterMenuCmd = GetItemCount();\r
+                       if (iItemCountAfterMenuCmd != iItemCountBeforeMenuCmd)\r
+                       {\r
+                               CWnd* pParent = GetParent();\r
+                               if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+                               {\r
+                                       pParent->SendMessage(SVNSLNM_ITEMCOUNTCHANGED);\r
+                               }\r
+                       }\r
+               } // if (popup.CreatePopupMenu())\r
+       } // if (selIndex >= 0)\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::OnContextMenuHeader(CWnd * pWnd, CPoint point)\r
+{\r
+       bool XPorLater = false;\r
+       OSVERSIONINFOEX inf;\r
+       SecureZeroMemory(&inf, sizeof(OSVERSIONINFOEX));\r
+       inf.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
+       GetVersionEx((OSVERSIONINFO *)&inf);\r
+       WORD fullver = MAKEWORD(inf.dwMinorVersion, inf.dwMajorVersion);\r
+       if (fullver >= 0x0501)\r
+               XPorLater = true;\r
+\r
+       CHeaderCtrl * pHeaderCtrl = (CHeaderCtrl *)pWnd;\r
+       if ((point.x == -1) && (point.y == -1))\r
+       {\r
+               CRect rect;\r
+               pHeaderCtrl->GetItemRect(0, &rect);\r
+               ClientToScreen(&rect);\r
+               point = rect.CenterPoint();\r
+       }\r
+       Locker lock(m_critSec);\r
+       CMenu popup;\r
+       if (popup.CreatePopupMenu())\r
+       {\r
+               int columnCount = m_ColumnManager.GetColumnCount();\r
+\r
+               CString temp;\r
+               UINT uCheckedFlags = MF_STRING | MF_ENABLED | MF_CHECKED;\r
+               UINT uUnCheckedFlags = MF_STRING | MF_ENABLED;\r
+\r
+               // build control menu\r
+\r
+               if (XPorLater)\r
+               {\r
+                       temp.LoadString(IDS_STATUSLIST_SHOWGROUPS);\r
+                       popup.AppendMenu(IsGroupViewEnabled() ? uCheckedFlags : uUnCheckedFlags, columnCount, temp);\r
+               }\r
+\r
+               if (m_ColumnManager.AnyUnusedProperties())\r
+               {\r
+                       temp.LoadString(IDS_STATUSLIST_REMOVEUNUSEDPROPS);\r
+                       popup.AppendMenu(uUnCheckedFlags, columnCount+1, temp);\r
+               }\r
+\r
+               temp.LoadString(IDS_STATUSLIST_RESETCOLUMNORDER);\r
+               popup.AppendMenu(uUnCheckedFlags, columnCount+2, temp);\r
+               popup.AppendMenu(MF_SEPARATOR);\r
+\r
+               // standard columns\r
+\r
+               for (int i = 1; i < SVNSLC_NUMCOLUMNS; ++i)\r
+               {\r
+                       popup.AppendMenu ( m_ColumnManager.IsVisible(i) \r
+                               ? uCheckedFlags \r
+                               : uUnCheckedFlags\r
+                               , i\r
+                               , m_ColumnManager.GetName(i));\r
+               }\r
+\r
+               // user-prop columns:\r
+               // find relevant ones and sort 'em\r
+\r
+               std::map<CString, int> sortedProps;\r
+               for (int i = SVNSLC_NUMCOLUMNS; i < columnCount; ++i)\r
+                       if (m_ColumnManager.IsRelevant(i))\r
+                               sortedProps[m_ColumnManager.GetName(i)] = i;\r
+\r
+               if (!sortedProps.empty())\r
+               {\r
+                       // add 'em to the menu\r
+\r
+                       popup.AppendMenu(MF_SEPARATOR);\r
+\r
+                       typedef std::map<CString, int>::const_iterator CIT;\r
+                       for ( CIT iter = sortedProps.begin(), end = sortedProps.end()\r
+                               ; iter != end\r
+                               ; ++iter)\r
+                       {\r
+                               popup.AppendMenu ( m_ColumnManager.IsVisible(iter->second) \r
+                                       ? uCheckedFlags \r
+                                       : uUnCheckedFlags\r
+                                       , iter->second\r
+                                       , iter->first);\r
+                       }\r
+               }\r
+\r
+               // show menu & let user pick an entry\r
+\r
+               int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
+               if ((cmd >= 1)&&(cmd < columnCount))\r
+               {\r
+                       m_ColumnManager.SetVisible (cmd, !m_ColumnManager.IsVisible(cmd));\r
+               } \r
+               else if (cmd == columnCount)\r
+               {\r
+                       EnableGroupView(!IsGroupViewEnabled());\r
+               } \r
+               else if (cmd == columnCount+1)\r
+               {\r
+                       m_ColumnManager.RemoveUnusedProps();\r
+               } \r
+               else if (cmd == columnCount+2)\r
+               {\r
+                       m_ColumnManager.ResetColumns (m_dwDefaultColumns);\r
+               }\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::OnContextMenu(CWnd* pWnd, CPoint point)\r
+{\r
+\r
+       if (pWnd == this)\r
+       {\r
+               OnContextMenuList(pWnd, point);\r
+       } // if (pWnd == this)\r
+       else if (pWnd == GetHeaderCtrl())\r
+       {\r
+               OnContextMenuHeader(pWnd, point);\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::CreateChangeList(const CString& name)\r
+{\r
+#if 0\r
+       CTGitPathList changelistItems;\r
+       FillListOfSelectedItemPaths(changelistItems);\r
+       Git git;\r
+       if (git.AddToChangeList(changelistItems, name, git_depth_empty))\r
+       {\r
+               TCHAR groupname[1024];\r
+               LVGROUP grp = {0};\r
+               grp.cbSize = sizeof(LVGROUP);\r
+               grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
+               _tcsncpy_s(groupname, 1024, name, 1023);\r
+               grp.pszHeader = groupname;\r
+               grp.iGroupId = (int)m_changelists.size();\r
+               grp.uAlign = LVGA_HEADER_LEFT;\r
+               m_changelists[name] = InsertGroup(-1, &grp);\r
+\r
+               PrepareGroups(true);\r
+\r
+               POSITION pos = GetFirstSelectedItemPosition();\r
+               int index;\r
+               while ((index = GetNextSelectedItem(pos)) >= 0)\r
+               {\r
+                       FileEntry * e = GetListEntry(index);\r
+                       e->changelist = name;\r
+                       SetEntryCheck(e, index, FALSE);\r
+               }\r
+\r
+               for (index = 0; index < GetItemCount(); ++index)\r
+               {\r
+                       FileEntry * e = GetListEntry(index);\r
+                       if (m_changelists.find(e->changelist)!=m_changelists.end())\r
+                               SetItemGroup(index, m_changelists[e->changelist]);\r
+                       else\r
+                               SetItemGroup(index, 0);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               CMessageBox::Show(m_hWnd, git.GetLastErrorMessage(), _T("Tortoisegit"), MB_ICONERROR);\r
+       }\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+#if 0\r
+       Locker lock(m_critSec);\r
+       LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
+       *pResult = 0;\r
+       if (m_bBlock)\r
+               return;\r
+       if (pNMLV->iItem < 0)\r
+       {\r
+               if (!IsGroupViewEnabled())\r
+                       return;\r
+               POINT pt;\r
+               DWORD ptW = GetMessagePos();\r
+               pt.x = GET_X_LPARAM(ptW);\r
+               pt.y = GET_Y_LPARAM(ptW);\r
+               ScreenToClient(&pt);\r
+               int group = GetGroupFromPoint(&pt);\r
+               if (group < 0)\r
+                       return;\r
+               // check/uncheck the whole group depending on the check-state \r
+               // of the first item in the group\r
+               m_bBlock = true;\r
+               bool bCheck = false;\r
+               bool bFirst = false;\r
+               LVITEM lv;\r
+               for (int i=0; i<GetItemCount(); ++i)\r
+               {\r
+                       SecureZeroMemory(&lv, sizeof(LVITEM));\r
+                       lv.mask = LVIF_GROUPID;\r
+                       lv.iItem = i;\r
+                       GetItem(&lv);\r
+                       if (lv.iGroupId == group)\r
+                       {\r
+                               FileEntry * entry = GetListEntry(i);\r
+                               if (!bFirst)\r
+                               {\r
+                                       bCheck = !GetCheck(i);\r
+                                       bFirst = true;\r
+                               }\r
+                               if (entry)\r
+                               {\r
+                                       bool bOldCheck = !!GetCheck(i);\r
+                                       SetEntryCheck(entry, i, bCheck);\r
+                                       if (bCheck != bOldCheck)\r
+                                       {\r
+                                               if (bCheck)\r
+                                                       m_nSelected++;\r
+                                               else\r
+                                                       m_nSelected--;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               GetStatisticsString();\r
+               m_bBlock = false;\r
+               NotifyCheck();\r
+               return;\r
+       }\r
+       FileEntry * entry = GetListEntry(pNMLV->iItem);\r
+       if (entry)\r
+       {\r
+               if (entry->isConflicted)\r
+               {\r
+                       gitDiff::StartConflictEditor(entry->GetPath());\r
+               }\r
+               else\r
+               {\r
+                       StartDiff(pNMLV->iItem);\r
+               }\r
+       }\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::StartDiff(int fileindex)\r
+{\r
+#if 0\r
+       if (fileindex < 0)\r
+               return;\r
+       FileEntry * entry = GetListEntry(fileindex);\r
+       ASSERT(entry != NULL);\r
+       if (entry == NULL)\r
+               return;\r
+       if (((entry->status == git_wc_status_normal)&&(entry->remotestatus <= git_wc_status_normal))||\r
+               (entry->status == git_wc_status_unversioned)||(entry->status == git_wc_status_none))\r
+       {\r
+               int ret = (int)ShellExecute(this->m_hWnd, NULL, entry->path.GetWinPath(), NULL, NULL, SW_SHOW);\r
+               if (ret <= HINSTANCE_ERROR)\r
+               {\r
+                       CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
+                       cmd += entry->path.GetWinPathString();\r
+                       CAppUtils::LaunchApplication(cmd, NULL, false);\r
+               }\r
+               return;\r
+       }\r
+\r
+       GitDiff diff(NULL, m_hWnd, true);\r
+       diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
+       diff.DiffWCFile(\r
+               entry->path, entry->textstatus, entry->propstatus,\r
+               entry->remotetextstatus, entry->remotepropstatus);\r
+#endif\r
+}\r
+\r
+CString CGitStatusListCtrl::GetStatisticsString()\r
+{\r
+#if 0\r
+       CString sNormal, sAdded, sDeleted, sModified, sConflicted, sUnversioned;\r
+       WORD langID = (WORD)(DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
+       TCHAR buf[MAX_STATUS_STRING_LENGTH];\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_normal, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sNormal = buf;\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_added, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sAdded = buf;\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_deleted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sDeleted = buf;\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_modified, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sModified = buf;\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_conflicted, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sConflicted = buf;\r
+       GitStatus::GetStatusString(AfxGetResourceHandle(), git_wc_status_unversioned, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
+       sUnversioned = buf;\r
+       CString sToolTip;\r
+       sToolTip.Format(_T("%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d\n%s = %d"),\r
+               (LPCTSTR)sNormal, m_nNormal,\r
+               (LPCTSTR)sUnversioned, m_nUnversioned,\r
+               (LPCTSTR)sModified, m_nModified,\r
+               (LPCTSTR)sAdded, m_nAdded,\r
+               (LPCTSTR)sDeleted, m_nDeleted,\r
+               (LPCTSTR)sConflicted, m_nConflicted\r
+               );\r
+       CString sStats;\r
+       sStats.Format(IDS_COMMITDLG_STATISTICSFORMAT, m_nSelected, GetItemCount());\r
+       if (m_pStatLabel)\r
+       {\r
+               m_pStatLabel->SetWindowText(sStats);\r
+       }\r
+\r
+       if (m_pSelectButton)\r
+       {\r
+               if (m_nSelected == 0)\r
+                       m_pSelectButton->SetCheck(BST_UNCHECKED);\r
+               else if (m_nSelected != GetItemCount())\r
+                       m_pSelectButton->SetCheck(BST_INDETERMINATE);\r
+               else\r
+                       m_pSelectButton->SetCheck(BST_CHECKED);\r
+       }\r
+\r
+       if (m_pConfirmButton)\r
+       {\r
+               m_pConfirmButton->EnableWindow(m_nSelected>0);\r
+       }\r
+\r
+       return sToolTip;\r
+#endif\r
+       return _T("");\r
+}\r
+\r
+CTGitPath CGitStatusListCtrl::GetCommonDirectory(bool bStrict)\r
+{\r
+       if (!bStrict)\r
+       {\r
+               // not strict means that the selected folder has priority\r
+               if (!m_StatusFileList.GetCommonDirectory().IsEmpty())\r
+                       return m_StatusFileList.GetCommonDirectory();\r
+       }\r
+\r
+       CTGitPath commonBaseDirectory;\r
+       int nListItems = GetItemCount();\r
+       for (int i=0; i<nListItems; ++i)\r
+       {\r
+               const CTGitPath& baseDirectory = GetListEntry(i)->GetPath().GetDirectory();\r
+               if(commonBaseDirectory.IsEmpty())\r
+               {\r
+                       commonBaseDirectory = baseDirectory;\r
+               }\r
+               else\r
+               {\r
+                       if (commonBaseDirectory.GetWinPathString().GetLength() > baseDirectory.GetWinPathString().GetLength())\r
+                       {\r
+                               if (baseDirectory.IsAncestorOf(commonBaseDirectory))\r
+                                       commonBaseDirectory = baseDirectory;\r
+                       }\r
+               }\r
+       }\r
+       return commonBaseDirectory;\r
+}\r
+\r
+CTGitPath CGitStatusListCtrl::GetCommonURL(bool bStrict)\r
+{\r
+       CTGitPath commonBaseURL;\r
+#if 0\r
+       \r
+       if (!bStrict)\r
+       {\r
+               // not strict means that the selected folder has priority\r
+               if (!m_StatusUrlList.GetCommonDirectory().IsEmpty())\r
+                       return m_StatusUrlList.GetCommonDirectory();\r
+       }\r
+\r
+       int nListItems = GetItemCount();\r
+       for (int i=0; i<nListItems; ++i)\r
+       {\r
+               const CTGitPath& baseURL = CTGitPath(GetListEntry(i)->GetURL());\r
+               if (baseURL.IsEmpty())\r
+                       continue;                       // item has no url\r
+               if(commonBaseURL.IsEmpty())\r
+               {\r
+                       commonBaseURL = baseURL;\r
+               }\r
+               else\r
+               {\r
+                       if (commonBaseURL.GetGitPathString().GetLength() > baseURL.GetGitPathString().GetLength())\r
+                       {\r
+                               if (baseURL.IsAncestorOf(commonBaseURL))\r
+                                       commonBaseURL = baseURL;\r
+                       }\r
+               }\r
+       }\r
+       \r
+#endif\r
+       return commonBaseURL;\r
+}\r
+\r
+void CGitStatusListCtrl::SelectAll(bool bSelect, bool bIncludeNoCommits)\r
+{\r
+       CWaitCursor waitCursor;\r
+       // block here so the LVN_ITEMCHANGED messages\r
+       // get ignored\r
+       m_bBlock = TRUE;\r
+       SetRedraw(FALSE);\r
+\r
+       int nListItems = GetItemCount();\r
+       if (bSelect)\r
+               m_nSelected = nListItems;\r
+       else\r
+               m_nSelected = 0;\r
+       for (int i=0; i<nListItems; ++i)\r
+       {\r
+               FileEntry * entry = GetListEntry(i);\r
+               ASSERT(entry != NULL);\r
+               if (entry == NULL)\r
+                       continue;\r
+               if ((bIncludeNoCommits)||(entry->GetChangeList().Compare(SVNSLC_IGNORECHANGELIST)))\r
+                       SetEntryCheck(entry,i,bSelect);\r
+       }\r
+       // unblock before redrawing\r
+       m_bBlock = FALSE;\r
+       SetRedraw(TRUE);\r
+       GetStatisticsString();\r
+       NotifyCheck();\r
+}\r
+\r
+void CGitStatusListCtrl::OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);\r
+       *pResult = 0;\r
+       if (m_bBlock)\r
+               return;\r
+       if (GetListEntry(pGetInfoTip->iItem >= 0))\r
+               if (pGetInfoTip->cchTextMax > GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString().GetLength())\r
+               {\r
+                       if (GetListEntry(pGetInfoTip->iItem)->GetRelativeGitPath().Compare(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString())!= 0)\r
+                               _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
+                       else if (GetStringWidth(GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString()) > GetColumnWidth(pGetInfoTip->iItem))\r
+                               _tcsncpy_s(pGetInfoTip->pszText, pGetInfoTip->cchTextMax, GetListEntry(pGetInfoTip->iItem)->path.GetGitPathString(), pGetInfoTip->cchTextMax);\r
+               }\r
+}\r
+\r
+void CGitStatusListCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
+\r
+       // Take the default processing unless we set this to something else below.\r
+       *pResult = CDRF_DODEFAULT;\r
+\r
+       // First thing - check the draw stage. If it's the control's prepaint\r
+       // stage, then tell Windows we want messages for every item.\r
+\r
+       switch (pLVCD->nmcd.dwDrawStage)\r
+       {\r
+       case CDDS_PREPAINT:\r
+               *pResult = CDRF_NOTIFYITEMDRAW;\r
+               break;\r
+       case CDDS_ITEMPREPAINT:\r
+               {\r
+                       // This is the prepaint stage for an item. Here's where we set the\r
+                       // item's text color. Our return value will tell Windows to draw the\r
+                       // item itself, but it will use the new color we set here.\r
+\r
+                       // Tell Windows to paint the control itself.\r
+                       *pResult = CDRF_DODEFAULT;\r
+                       if (m_bBlock)\r
+                               return;\r
+\r
+                       COLORREF crText = GetSysColor(COLOR_WINDOWTEXT);\r
+\r
+                       if (m_arListArray.size() > (DWORD_PTR)pLVCD->nmcd.dwItemSpec)\r
+                       {\r
+                               FileEntry * entry = GetListEntry((int)pLVCD->nmcd.dwItemSpec);\r
+                               if (entry == NULL)\r
+                                       return;\r
+\r
+                               // coloring\r
+                               // ========\r
+                               // black  : unversioned, normal\r
+                               // purple : added\r
+                               // blue   : modified\r
+                               // brown  : missing, deleted, replaced\r
+                               // green  : merged (or potential merges)\r
+                               // red    : conflicts or sure conflicts\r
+                               switch (entry->status)\r
+                               {\r
+                               case git_wc_status_added:\r
+//                                     if (entry->remotestatus > git_wc_status_unversioned)\r
+                                               // locally added file, but file already exists in repository!\r
+//                                             crText = m_Colors.GetColor(CColors::Conflict);\r
+//                                     else\r
+                                               crText = m_Colors.GetColor(CColors::Added);\r
+                                       break;\r
+                               case git_wc_status_missing:\r
+                               case git_wc_status_deleted:\r
+                               case git_wc_status_replaced:\r
+                                       crText = m_Colors.GetColor(CColors::Deleted);\r
+                                       break;\r
+                               case git_wc_status_modified:\r
+//                                     if (entry->remotestatus == git_wc_status_modified)\r
+                                               // indicate a merge (both local and remote changes will require a merge)\r
+//                                             crText = m_Colors.GetColor(CColors::Merged);\r
+//                                     else if (entry->remotestatus == git_wc_status_deleted)\r
+//                                             // locally modified, but already deleted in the repository\r
+//                                             crText = m_Colors.GetColor(CColors::Conflict);\r
+//                                     else\r
+                                               crText = m_Colors.GetColor(CColors::Modified);\r
+                                       break;\r
+                               case git_wc_status_merged:\r
+                                       crText = m_Colors.GetColor(CColors::Merged);\r
+                                       break;\r
+                               case git_wc_status_conflicted:\r
+                               case git_wc_status_obstructed:\r
+                                       crText = m_Colors.GetColor(CColors::Conflict);\r
+                                       break;\r
+                               case git_wc_status_none:\r
+                               case git_wc_status_unversioned:\r
+                               case git_wc_status_ignored:\r
+                               case git_wc_status_incomplete:\r
+                               case git_wc_status_normal:\r
+                               case git_wc_status_external:\r
+                               default:\r
+                                       crText = GetSysColor(COLOR_WINDOWTEXT);\r
+                                       break;\r
+                               }\r
+\r
+                               if (entry->isConflicted)\r
+                                       crText = m_Colors.GetColor(CColors::Conflict);\r
+\r
+                               // Store the color back in the NMLVCUSTOMDRAW struct.\r
+                               pLVCD->clrText = crText;\r
+                       }\r
+               }\r
+               break;\r
+       }\r
+}\r
+\r
+BOOL CGitStatusListCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
+{\r
+       if (pWnd != this)\r
+               return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
+       if (!m_bBlock)\r
+       {\r
+               HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
+               SetCursor(hCur);\r
+               return CListCtrl::OnSetCursor(pWnd, nHitTest, message);\r
+       }\r
+       HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
+       SetCursor(hCur);\r
+       return TRUE;\r
+}\r
+\r
+void CGitStatusListCtrl::RemoveListEntry(int index)\r
+{\r
+       Locker lock(m_critSec);\r
+       DeleteItem(index);\r
+       delete m_arStatusArray[m_arListArray[index]];\r
+       m_arStatusArray.erase(m_arStatusArray.begin()+m_arListArray[index]);\r
+       m_arListArray.erase(m_arListArray.begin()+index);\r
+       for (int i=index; i< (int)m_arListArray.size(); ++i)\r
+       {\r
+               m_arListArray[i]--;\r
+       }\r
+}\r
+\r
+///< Set a checkbox on an entry in the listbox\r
+// NEVER, EVER call SetCheck directly, because you'll end-up with the checkboxes and the 'checked' flag getting out of sync\r
+void CGitStatusListCtrl::SetEntryCheck(FileEntry* pEntry, int listboxIndex, bool bCheck)\r
+{\r
+       pEntry->checked = bCheck;\r
+       SetCheck(listboxIndex, bCheck);\r
+}\r
+\r
+\r
+void CGitStatusListCtrl::SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck)\r
+{\r
+       int nListItems = GetItemCount();\r
+       for (int j=0; j< nListItems ; ++j)\r
+       {\r
+               FileEntry * childEntry = GetListEntry(j);\r
+               ASSERT(childEntry != NULL);\r
+               if (childEntry == NULL || childEntry == parentEntry)\r
+                       continue;\r
+               if (childEntry->checked != bCheck)\r
+               {\r
+                       if (parentEntry->path.IsAncestorOf(childEntry->path))\r
+                       {\r
+                               SetEntryCheck(childEntry,j,bCheck);\r
+                               if(bCheck)\r
+                               {\r
+                                       m_nSelected++;\r
+                               }\r
+                               else\r
+                               {\r
+                                       m_nSelected--;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::WriteCheckedNamesToPathList(CTGitPathList& pathList)\r
+{\r
+       pathList.Clear();\r
+       int nListItems = GetItemCount();\r
+       for (int i=0; i< nListItems; i++)\r
+       {\r
+               const FileEntry* entry = GetListEntry(i);\r
+               ASSERT(entry != NULL);\r
+               if (entry->IsChecked())\r
+               {\r
+                       pathList.AddPath(entry->path);\r
+               }\r
+       }\r
+       pathList.SortByPathname();\r
+}\r
+\r
+\r
+/// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)\r
+void CGitStatusListCtrl::FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored)\r
+{\r
+       pathList.Clear();\r
+\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       int index;\r
+       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+       {\r
+               FileEntry * entry = GetListEntry(index);\r
+               if ((bNoIgnored)&&(entry->status == git_wc_status_ignored))\r
+                       continue;\r
+               pathList.AddPath(GetListEntry(index)->path);\r
+       }\r
+}\r
+\r
+UINT CGitStatusListCtrl::OnGetDlgCode()\r
+{\r
+       // we want to process the return key and not have that one\r
+       // routed to the default pushbutton\r
+       return CListCtrl::OnGetDlgCode() | DLGC_WANTALLKEYS;\r
+}\r
+\r
+void CGitStatusListCtrl::OnNMReturn(NMHDR * /*pNMHDR*/, LRESULT *pResult)\r
+{\r
+       *pResult = 0;\r
+       if (m_bBlock)\r
+               return;\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       while ( pos )\r
+       {\r
+               int index = GetNextSelectedItem(pos);\r
+               StartDiff(index);\r
+       }\r
+}\r
+\r
+void CGitStatusListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\r
+{\r
+       // Since we catch all keystrokes (to have the enter key processed here instead\r
+       // of routed to the default pushbutton) we have to make sure that other\r
+       // keys like Tab and Esc still do what they're supposed to do\r
+       // Tab = change focus to next/previous control\r
+       // Esc = quit the dialog\r
+       switch (nChar)\r
+       {\r
+       case (VK_TAB):\r
+               {\r
+                       ::PostMessage(GetParent()->GetSafeHwnd(), WM_NEXTDLGCTL, GetKeyState(VK_SHIFT)&0x8000, 0);\r
+                       return;\r
+               }\r
+               break;\r
+       case (VK_ESCAPE):\r
+               {\r
+                       ::SendMessage(GetParent()->GetSafeHwnd(), WM_CLOSE, 0, 0);\r
+               }\r
+               break;\r
+       }\r
+\r
+       CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);\r
+}\r
+\r
+void CGitStatusListCtrl::PreSubclassWindow()\r
+{\r
+       CListCtrl::PreSubclassWindow();\r
+       EnableToolTips(TRUE);\r
+}\r
+\r
+INT_PTR CGitStatusListCtrl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const\r
+{\r
+       int row, col;\r
+       RECT cellrect;\r
+       row = CellRectFromPoint(point, &cellrect, &col );\r
+\r
+       if (row == -1)\r
+               return -1;\r
+\r
+\r
+       pTI->hwnd = m_hWnd;\r
+       pTI->uId = (UINT)((row<<10)+(col&0x3ff)+1);\r
+       pTI->lpszText = LPSTR_TEXTCALLBACK;\r
+\r
+       pTI->rect = cellrect;\r
+\r
+       return pTI->uId;\r
+}\r
+\r
+int CGitStatusListCtrl::CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const\r
+{\r
+       int colnum;\r
+\r
+       // Make sure that the ListView is in LVS_REPORT\r
+       if ((GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT)\r
+               return -1;\r
+\r
+       // Get the top and bottom row visible\r
+       int row = GetTopIndex();\r
+       int bottom = row + GetCountPerPage();\r
+       if (bottom > GetItemCount())\r
+               bottom = GetItemCount();\r
+\r
+       // Get the number of columns\r
+       CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);\r
+       int nColumnCount = pHeader->GetItemCount();\r
+\r
+       // Loop through the visible rows\r
+       for ( ;row <=bottom;row++)\r
+       {\r
+               // Get bounding rect of item and check whether point falls in it.\r
+               CRect rect;\r
+               GetItemRect(row, &rect, LVIR_BOUNDS);\r
+               if (rect.PtInRect(point))\r
+               {\r
+                       // Now find the column\r
+                       for (colnum = 0; colnum < nColumnCount; colnum++)\r
+                       {\r
+                               int colwidth = GetColumnWidth(colnum);\r
+                               if (point.x >= rect.left && point.x <= (rect.left + colwidth))\r
+                               {\r
+                                       RECT rectClient;\r
+                                       GetClientRect(&rectClient);\r
+                                       if (col)\r
+                                               *col = colnum;\r
+                                       rect.right = rect.left + colwidth;\r
+\r
+                                       // Make sure that the right extent does not exceed\r
+                                       // the client area\r
+                                       if (rect.right > rectClient.right)\r
+                                               rect.right = rectClient.right;\r
+                                       *cellrect = rect;\r
+                                       return row;\r
+                               }\r
+                               rect.left += colwidth;\r
+                       }\r
+               }\r
+       }\r
+       return -1;\r
+}\r
+\r
+BOOL CGitStatusListCtrl::OnToolTipText(UINT /*id*/, NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+#if 0\r
+       TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;\r
+       CString strTipText;\r
+       UINT_PTR nID = pNMHDR->idFrom;\r
+\r
+       if (nID == 0)\r
+               return FALSE;\r
+\r
+       UINT_PTR row = ((nID-1) >> 10) & 0x3fffff;\r
+       UINT_PTR col = (nID-1) & 0x3ff;\r
+\r
+       if (col == 0)\r
+               return FALSE;   // no custom tooltip for the path, we use the infotip there!\r
+\r
+       // get the internal column from the visible columns\r
+       int internalcol = 0;\r
+       UINT_PTR currentcol = 0;\r
+    for (;    (currentcol != col) \r
+           && (internalcol < m_ColumnManager.GetColumnCount()-1)\r
+         ; ++internalcol)\r
+       {\r
+        if (m_ColumnManager.IsVisible (internalcol))\r
+                       currentcol++;\r
+       }\r
+\r
+       AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();\r
+       CToolTipCtrl* pToolTip = pModuleThreadState->m_pToolTip;\r
+       pToolTip->SendMessage(TTM_SETMAXTIPWIDTH, 0, 300);\r
+\r
+       *pResult = 0;\r
+       if ((internalcol == 2)||(internalcol == 4))\r
+       {\r
+               FileEntry *fentry = GetListEntry(row);\r
+               if (fentry)\r
+               {\r
+                       if (fentry->copied)\r
+                       {\r
+                               CString url;\r
+                               url.Format(IDS_STATUSLIST_COPYFROM, (LPCTSTR)CPathUtils::PathUnescape(fentry->copyfrom_url), (LONG)fentry->copyfrom_rev);\r
+                               lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
+                               return TRUE;\r
+                       }\r
+                       if (fentry->switched)\r
+                       {\r
+                               CString url;\r
+                               url.Format(IDS_STATUSLIST_SWITCHEDTO, (LPCTSTR)CPathUtils::PathUnescape(fentry->url));\r
+                               lstrcpyn(pTTTW->szText, (LPCTSTR)url, 80);\r
+                               return TRUE;\r
+                       }\r
+                       if (fentry->keeplocal)\r
+                       {\r
+                               lstrcpyn(pTTTW->szText, (LPCTSTR)CString(MAKEINTRESOURCE(IDS_STATUSLIST_KEEPLOCAL)), 80);\r
+                               return TRUE;\r
+                       }\r
+               }\r
+       }\r
+#endif\r
+       return FALSE;\r
+}\r
+\r
+void CGitStatusListCtrl::OnPaint()\r
+{\r
+       Default();\r
+       if ((m_bBusy)||(m_bEmpty))\r
+       {\r
+               CString str;\r
+               if (m_bBusy)\r
+               {\r
+                       if (m_sBusy.IsEmpty())\r
+                               str.LoadString(IDS_STATUSLIST_BUSYMSG);\r
+                       else\r
+                               str = m_sBusy;\r
+               }\r
+               else\r
+               {\r
+                       if (m_sEmpty.IsEmpty())\r
+                               str.LoadString(IDS_STATUSLIST_EMPTYMSG);\r
+                       else\r
+                               str = m_sEmpty;\r
+               }\r
+               COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);\r
+               COLORREF clrTextBk;\r
+               if (IsWindowEnabled())\r
+                       clrTextBk = ::GetSysColor(COLOR_WINDOW);\r
+               else\r
+                       clrTextBk = ::GetSysColor(COLOR_3DFACE);\r
+\r
+               CRect rc;\r
+               GetClientRect(&rc);\r
+               CHeaderCtrl* pHC;\r
+               pHC = GetHeaderCtrl();\r
+               if (pHC != NULL)\r
+               {\r
+                       CRect rcH;\r
+                       pHC->GetItemRect(0, &rcH);\r
+                       rc.top += rcH.bottom;\r
+               }\r
+               CDC* pDC = GetDC();\r
+               {\r
+                       CMyMemDC memDC(pDC, &rc);\r
+\r
+                       memDC.SetTextColor(clrText);\r
+                       memDC.SetBkColor(clrTextBk);\r
+                       memDC.FillSolidRect(rc, clrTextBk);\r
+                       rc.top += 10;\r
+                       CGdiObject * oldfont = memDC.SelectStockObject(DEFAULT_GUI_FONT);\r
+                       memDC.DrawText(str, rc, DT_CENTER | DT_VCENTER |\r
+                               DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);\r
+                       memDC.SelectObject(oldfont);\r
+               }\r
+               ReleaseDC(pDC);\r
+       }\r
+}\r
+\r
+// prevent users from extending our hidden (size 0) columns\r
+void CGitStatusListCtrl::OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
+       *pResult = 0;\r
+       if ((phdr->iItem < 0)||(phdr->iItem >= SVNSLC_NUMCOLUMNS))\r
+               return;\r
+\r
+    if (m_ColumnManager.IsVisible (phdr->iItem))\r
+       {\r
+               return;\r
+       }\r
+       *pResult = 1;\r
+}\r
+\r
+// prevent any function from extending our hidden (size 0) columns\r
+void CGitStatusListCtrl::OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)\r
+{\r
+       LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
+       *pResult = 0;\r
+    if ((phdr->iItem < 0)||(phdr->iItem >= m_ColumnManager.GetColumnCount()))\r
+       {\r
+               Default();\r
+               return;\r
+       }\r
+\r
+    // visible columns may be modified \r
+\r
+    if (m_ColumnManager.IsVisible (phdr->iItem))\r
+       {\r
+               Default();\r
+               return;\r
+       }\r
+\r
+    // columns already marked as "invisible" internally may be (re-)sized to 0\r
+\r
+    if (   (phdr->pitem != NULL) \r
+        && (phdr->pitem->mask == HDI_WIDTH)\r
+        && (phdr->pitem->cxy == 0))\r
+       {\r
+               Default();\r
+               return;\r
+       }\r
+\r
+       if (   (phdr->pitem != NULL) \r
+               && (phdr->pitem->mask != HDI_WIDTH))\r
+       {\r
+               Default();\r
+               return;\r
+       }\r
+\r
+    *pResult = 1;\r
+}\r
+\r
+void CGitStatusListCtrl::OnDestroy()\r
+{\r
+       SaveColumnWidths(true);\r
+       CListCtrl::OnDestroy();\r
+}\r
+\r
+void CGitStatusListCtrl::OnBeginDrag(NMHDR* /*pNMHDR*/, LRESULT* pResult)\r
+{\r
+#if 0\r
+       Locker lock(m_critSec);\r
+       CDropFiles dropFiles; // class for creating DROPFILES struct\r
+\r
+       int index;\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       while ( (index = GetNextSelectedItem(pos)) >= 0 )\r
+       {\r
+               FileEntry * fentry = m_arStatusArray[m_arListArray[index]];\r
+               CTGitPath path = fentry->GetPath();\r
+               dropFiles.AddFile( path.GetWinPathString() );\r
+       }\r
+\r
+       if ( dropFiles.GetCount()>0 )\r
+       {\r
+               m_bOwnDrag = true;\r
+               dropFiles.CreateStructure();\r
+               m_bOwnDrag = false;\r
+       }\r
+#endif\r
+       *pResult = 0;\r
+}\r
+\r
+void CGitStatusListCtrl::SaveColumnWidths(bool bSaveToRegistry /* = false */)\r
+{\r
+       int maxcol = ((CHeaderCtrl*)(GetDlgItem(0)))->GetItemCount()-1;\r
+       for (int col = 0; col <= maxcol; col++)\r
+        if (m_ColumnManager.IsVisible (col))\r
+            m_ColumnManager.ColumnResized (col);\r
+\r
+       if (bSaveToRegistry)\r
+        m_ColumnManager.WriteSettings();\r
+}\r
+\r
+bool CGitStatusListCtrl::EnableFileDrop()\r
+{\r
+       m_bFileDropsEnabled = true;\r
+       return true;\r
+}\r
+\r
+bool CGitStatusListCtrl::HasPath(const CTGitPath& path)\r
+{\r
+       for (size_t i=0; i < m_arStatusArray.size(); i++)\r
+       {\r
+               FileEntry * entry = m_arStatusArray[i];\r
+               if (entry->GetPath().IsEquivalentTo(path))\r
+                       return true;\r
+       }\r
+       return false;\r
+}\r
+\r
+bool CGitStatusListCtrl::IsPathShown(const CTGitPath& path)\r
+{\r
+       int itemCount = GetItemCount();\r
+       for (int i=0; i < itemCount; i++)\r
+       {\r
+               FileEntry * entry = GetListEntry(i);\r
+               if (entry->GetPath().IsEquivalentTo(path))\r
+                       return true;\r
+       }\r
+       return false;\r
+}\r
+\r
+BOOL CGitStatusListCtrl::PreTranslateMessage(MSG* pMsg)\r
+{\r
+       if (pMsg->message == WM_KEYDOWN)\r
+       {\r
+               switch (pMsg->wParam)\r
+               {\r
+               case 'A':\r
+                       {\r
+                               if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
+                               {\r
+                                       // select all entries\r
+                                       for (int i=0; i<GetItemCount(); ++i)\r
+                                       {\r
+                                               SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
+                                       }\r
+                                       return TRUE;\r
+                               }\r
+                       }\r
+                       break;\r
+               case 'C':\r
+               case VK_INSERT:\r
+                       {\r
+                               if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
+                               {\r
+                                       // copy all selected paths to the clipboard\r
+                                       if (GetAsyncKeyState(VK_SHIFT)&0x8000)\r
+                                               CopySelectedEntriesToClipboard(SVNSLC_COLSTATUS|SVNSLC_COLURL);\r
+                                       else\r
+                                               CopySelectedEntriesToClipboard(0);\r
+                                       return TRUE;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+       }\r
+\r
+       return CListCtrl::PreTranslateMessage(pMsg);\r
+}\r
+\r
+bool CGitStatusListCtrl::CopySelectedEntriesToClipboard(DWORD dwCols)\r
+{\r
+#if 0\r
+       static CString ponly(MAKEINTRESOURCE(IDS_STATUSLIST_PROPONLY));\r
+       static HINSTANCE hResourceHandle(AfxGetResourceHandle());\r
+       WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
+\r
+       CString sClipboard;\r
+       CString temp;\r
+       TCHAR buf[100];\r
+       if (GetSelectedCount() == 0)\r
+               return false;\r
+       // first add the column titles as the first line\r
+       temp.LoadString(IDS_STATUSLIST_COLFILE);\r
+       sClipboard = temp;\r
+\r
+    DWORD selection = 0;\r
+    for (int i = 0, count = m_ColumnManager.GetColumnCount(); i < count; ++i)\r
+        if (   ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
+            || ((dwCols != 1) && (i < 32) && ((dwCols & (1 << i)) != 0)))\r
+        {\r
+            sClipboard += _T("\t") + m_ColumnManager.GetName(i);\r
+\r
+            if (i < 32)\r
+                selection += 1 << i;\r
+        }\r
+\r
+       sClipboard += _T("\r\n");\r
+\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       int index;\r
+       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+       {\r
+               FileEntry * entry = GetListEntry(index);\r
+               sClipboard += entry->GetDisplayName();\r
+               if (selection & SVNSLC_COLFILENAME)\r
+               {\r
+                       sClipboard += _T("\t")+entry->path.GetFileOrDirectoryName();\r
+               }\r
+               if (selection & SVNSLC_COLEXT)\r
+               {\r
+                       sClipboard += _T("\t")+entry->path.GetFileExtension();\r
+               }\r
+               if (selection & SVNSLC_COLSTATUS)\r
+               {\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.LoadString(IDS_STATUSLIST_NESTED);\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->status, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (+)"));\r
+                               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (s)"));\r
+                               if ((entry->status == entry->propstatus)&&\r
+                                       (entry->status != git_wc_status_normal)&&\r
+                                       (entry->status != git_wc_status_unversioned)&&\r
+                                       (!GitStatus::IsImportant(entry->textstatus)))\r
+                                       _tcscat_s(buf, 100, ponly);\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLTEXTSTATUS)\r
+               {\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.LoadString(IDS_STATUSLIST_NESTED);\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->textstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (+)"));\r
+                               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (s)"));\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLREMOTESTATUS)\r
+               {\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.LoadString(IDS_STATUSLIST_NESTED);\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->remotestatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (+)"));\r
+                               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (s)"));\r
+                               if ((entry->remotestatus == entry->remotepropstatus)&&\r
+                                       (entry->remotestatus != git_wc_status_none)&&\r
+                                       (entry->remotestatus != git_wc_status_normal)&&\r
+                                       (entry->remotestatus != git_wc_status_unversioned)&&\r
+                                       (!SVNStatus::IsImportant(entry->remotetextstatus)))\r
+                                       _tcscat_s(buf, 100, ponly);\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & GitSLC_COLPROPSTATUS)\r
+               {\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.Empty();\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->propstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               if ((entry->copied)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (+)"));\r
+                               if ((entry->switched)&&(_tcslen(buf)>1))\r
+                                       _tcscat_s(buf, 100, _T(" (s)"));\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLREMOTETEXT)\r
+               {\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.Empty();\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->remotetextstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLREMOTEPROP)\r
+               {\r
+                       // SVNSLC_COLREMOTEPROP\r
+                       if (entry->isNested)\r
+                       {\r
+                               temp.Empty();\r
+                       }\r
+                       else\r
+                       {\r
+                               GitStatus::GetStatusString(hResourceHandle, entry->remotepropstatus, buf, sizeof(buf)/sizeof(TCHAR), (WORD)langID);\r
+                               temp = buf;\r
+                       }\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLURL)\r
+                       sClipboard += _T("\t")+entry->url;\r
+               if (selection & SVNSLC_COLLOCK)\r
+               {\r
+                       if (!m_HeadRev.IsHead())\r
+                       {\r
+                               // we have contacted the repository\r
+\r
+                               // decision-matrix\r
+                               // wc           repository              text\r
+                               // ""           ""                              ""\r
+                               // ""           UID1                    owner\r
+                               // UID1         UID1                    owner\r
+                               // UID1         ""                              lock has been broken\r
+                               // UID1         UID2                    lock has been stolen\r
+                               if (entry->lock_token.IsEmpty() || (entry->lock_token.Compare(entry->lock_remotetoken)==0))\r
+                               {\r
+                                       if (entry->lock_owner.IsEmpty())\r
+                                               temp = entry->lock_remoteowner;\r
+                                       else\r
+                                               temp = entry->lock_owner;\r
+                               }\r
+                               else if (entry->lock_remotetoken.IsEmpty())\r
+                               {\r
+                                       // broken lock\r
+                                       temp.LoadString(IDS_STATUSLIST_LOCKBROKEN);\r
+                               }\r
+                               else\r
+                               {\r
+                                       // stolen lock\r
+                                       temp.Format(IDS_STATUSLIST_LOCKSTOLEN, (LPCTSTR)entry->lock_remoteowner);\r
+                               }\r
+                       }\r
+                       else\r
+                               temp = entry->lock_owner;\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLLOCKCOMMENT)\r
+                       sClipboard += _T("\t")+entry->lock_comment;\r
+               if (selection & SVNSLC_COLAUTHOR)\r
+                       sClipboard += _T("\t")+entry->last_commit_author;\r
+               if (selection & SVNSLC_COLREVISION)\r
+               {\r
+                       temp.Format(_T("%ld"), entry->last_commit_rev);\r
+                       if (entry->last_commit_rev == 0)\r
+                               temp.Empty();\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLREMOTEREVISION)\r
+               {\r
+                       temp.Format(_T("%ld"), entry->remoterev);\r
+                       if (entry->remoterev == 0)\r
+                               temp.Empty();\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLDATE)\r
+               {\r
+                       TCHAR datebuf[SVN_DATE_BUFFER];\r
+                       apr_time_t date = entry->last_commit_date;\r
+                       SVN::formatDate(datebuf, date, true);\r
+                       if (date)\r
+                               temp = datebuf;\r
+                       else\r
+                               temp.Empty();\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+               if (selection & SVNSLC_COLCOPYFROM)\r
+               {\r
+                       if (m_sURL.Compare(entry->copyfrom_url.Left(m_sURL.GetLength()))==0)\r
+                               temp = entry->copyfrom_url.Mid(m_sURL.GetLength());\r
+                       else\r
+                               temp = entry->copyfrom_url;\r
+                       sClipboard += _T("\t")+temp;\r
+               }\r
+\r
+        for ( int i = SVNSLC_NUMCOLUMNS, count = m_ColumnManager.GetColumnCount()\r
+            ; i < count\r
+            ; ++i)\r
+        {\r
+            if ((dwCols == -1) && m_ColumnManager.IsVisible (i))\r
+            {\r
+                CString value \r
+                    = entry->present_props[m_ColumnManager.GetName(i)];\r
+                sClipboard += _T("\t") + value;\r
+            }\r
+        }\r
+\r
+               sClipboard += _T("\r\n");\r
+       }\r
+\r
+       return CStringUtils::WriteAsciiStringToClipboard(sClipboard);\r
+#endif\r
+       return TRUE;\r
+\r
+}\r
+\r
+size_t CGitStatusListCtrl::GetNumberOfChangelistsInSelection()\r
+{\r
+       std::set<CString> changelists;\r
+       POSITION pos = GetFirstSelectedItemPosition();\r
+       int index;\r
+       while ((index = GetNextSelectedItem(pos)) >= 0)\r
+       {\r
+               FileEntry * entry = GetListEntry(index);\r
+               if (!entry->changelist.IsEmpty())\r
+                       changelists.insert(entry->changelist);\r
+       }\r
+       return changelists.size();\r
+}\r
+\r
+bool CGitStatusListCtrl::PrepareGroups(bool bForce /* = false */)\r
+{\r
+       if ((m_dwContextMenus & SVNSLC_POPCHANGELISTS) == NULL)\r
+               return false;   // don't show groups\r
+\r
+       bool bHasGroups = (m_changelists.size() > 0)||(bForce);\r
+       RemoveAllGroups();\r
+       EnableGroupView(bHasGroups);\r
+\r
+       TCHAR groupname[1024];\r
+\r
+       m_bHasIgnoreGroup = false;\r
+\r
+       // add a new group for each changelist\r
+       int groupindex = 0;\r
+\r
+       // now add the items which don't belong to a group\r
+       LVGROUP grp = {0};\r
+       grp.cbSize = sizeof(LVGROUP);\r
+       grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
+       CString sUnassignedName(MAKEINTRESOURCE(IDS_STATUSLIST_UNASSIGNED_CHANGESET));\r
+       _tcsncpy_s(groupname, 1024, (LPCTSTR)sUnassignedName, 1023);\r
+       grp.pszHeader = groupname;\r
+       grp.iGroupId = groupindex;\r
+       grp.uAlign = LVGA_HEADER_LEFT;\r
+       InsertGroup(groupindex++, &grp);\r
+\r
+       for (std::map<CString,int>::iterator it = m_changelists.begin(); it != m_changelists.end(); ++it)\r
+       {\r
+               if (it->first.Compare(SVNSLC_IGNORECHANGELIST)!=0)\r
+               {\r
+                       LVGROUP grp = {0};\r
+                       grp.cbSize = sizeof(LVGROUP);\r
+                       grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
+                       _tcsncpy_s(groupname, 1024, it->first, 1023);\r
+                       grp.pszHeader = groupname;\r
+                       grp.iGroupId = groupindex;\r
+                       grp.uAlign = LVGA_HEADER_LEFT;\r
+                       it->second = InsertGroup(groupindex++, &grp);\r
+               }\r
+               else\r
+                       m_bHasIgnoreGroup = true;\r
+       }\r
+\r
+       if (m_bHasIgnoreGroup)\r
+       {\r
+               // and now add the group 'ignore-on-commit'\r
+               std::map<CString,int>::iterator it = m_changelists.find(SVNSLC_IGNORECHANGELIST);\r
+               if (it != m_changelists.end())\r
+               {\r
+                       grp.cbSize = sizeof(LVGROUP);\r
+                       grp.mask = LVGF_ALIGN | LVGF_GROUPID | LVGF_HEADER;\r
+                       _tcsncpy_s(groupname, 1024, SVNSLC_IGNORECHANGELIST, 1023);\r
+                       grp.pszHeader = groupname;\r
+                       grp.iGroupId = groupindex;\r
+                       grp.uAlign = LVGA_HEADER_LEFT;\r
+                       it->second = InsertGroup(groupindex, &grp);\r
+               }\r
+       }\r
+\r
+       return bHasGroups;\r
+}\r
+\r
+void CGitStatusListCtrl::NotifyCheck()\r
+{\r
+       CWnd* pParent = GetParent();\r
+       if (NULL != pParent && NULL != pParent->GetSafeHwnd())\r
+       {\r
+               pParent->SendMessage(SVNSLNM_CHECKCHANGED, m_nSelected);\r
+       }\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////\r
+#if 0\r
+bool CGitStatusListCtrlDropTarget::OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt)\r
+{\r
+       if(pFmtEtc->cfFormat == CF_HDROP && medium.tymed == TYMED_HGLOBAL)\r
+       {\r
+               HDROP hDrop = (HDROP)GlobalLock(medium.hGlobal);\r
+               if(hDrop != NULL)\r
+               {\r
+                       TCHAR szFileName[MAX_PATH];\r
+\r
+                       UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);\r
+\r
+                       POINT clientpoint;\r
+                       clientpoint.x = pt.x;\r
+                       clientpoint.y = pt.y;\r
+                       ScreenToClient(m_hTargetWnd, &clientpoint);\r
+                       if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
+                       {\r
+                               CTSVNPathList changelistItems;\r
+                               for(UINT i = 0; i < cFiles; ++i)\r
+                               {\r
+                                       DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
+                                       changelistItems.AddPath(CTSVNPath(szFileName));\r
+                               }\r
+                               // find the changelist name\r
+                               CString sChangelist;\r
+                               LONG_PTR nGroup = m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint);\r
+                               for (std::map<CString, int>::iterator it = m_pSVNStatusListCtrl->m_changelists.begin(); it != m_pSVNStatusListCtrl->m_changelists.end(); ++it)\r
+                                       if (it->second == nGroup)\r
+                                               sChangelist = it->first;\r
+                               if (!sChangelist.IsEmpty())\r
+                               {\r
+                                       SVN git;\r
+                                       if (git.AddToChangeList(changelistItems, sChangelist, git_depth_empty))\r
+                                       {\r
+                                               for (int l=0; l<changelistItems.GetCount(); ++l)\r
+                                               {\r
+                                                       int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
+                                                       if (index >= 0)\r
+                                                       {\r
+                                                               CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
+                                                               if (e)\r
+                                                               {\r
+                                                                       e->changelist = sChangelist;\r
+                                                                       if (!e->IsFolder())\r
+                                                                       {\r
+                                                                               if (m_pSVNStatusListCtrl->m_changelists.find(e->changelist)!=m_pSVNStatusListCtrl->m_changelists.end())\r
+                                                                                       m_pSVNStatusListCtrl->SetItemGroup(index, m_pSVNStatusListCtrl->m_changelists[e->changelist]);\r
+                                                                               else\r
+                                                                                       m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               HWND hParentWnd = GetParent(m_hTargetWnd);\r
+                                                               if (hParentWnd != NULL)\r
+                                                                       ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       SVN git;\r
+                                       if (git.RemoveFromChangeList(changelistItems, CStringArray(), git_depth_empty))\r
+                                       {\r
+                                               for (int l=0; l<changelistItems.GetCount(); ++l)\r
+                                               {\r
+                                                       int index = m_pSVNStatusListCtrl->GetIndex(changelistItems[l]);\r
+                                                       if (index >= 0)\r
+                                                       {\r
+                                                               CSVNStatusListCtrl::FileEntry * e = m_pSVNStatusListCtrl->GetListEntry(index);\r
+                                                               if (e)\r
+                                                               {\r
+                                                                       e->changelist = sChangelist;\r
+                                                                       m_pSVNStatusListCtrl->SetItemGroup(index, 0);\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               HWND hParentWnd = GetParent(m_hTargetWnd);\r
+                                                               if (hParentWnd != NULL)\r
+                                                                       ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)changelistItems[l].GetWinPath());\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               CMessageBox::Show(m_pSVNStatusListCtrl->m_hWnd, git.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
+                                       }\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               for(UINT i = 0; i < cFiles; ++i)\r
+                               {\r
+                                       DragQueryFile(hDrop, i, szFileName, sizeof(szFileName));\r
+                                       HWND hParentWnd = GetParent(m_hTargetWnd);\r
+                                       if (hParentWnd != NULL)\r
+                                               ::SendMessage(hParentWnd, CSVNStatusListCtrl::SVNSLNM_ADDFILE, 0, (LPARAM)szFileName);\r
+                               }\r
+                       }\r
+               }\r
+               GlobalUnlock(medium.hGlobal);\r
+       }\r
+       return true; //let base free the medium\r
+}\r
+HRESULT STDMETHODCALLTYPE CSVNStatusListCtrlDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect)\r
+{\r
+       CIDropTarget::DragOver(grfKeyState, pt, pdwEffect);\r
+       *pdwEffect = DROPEFFECT_COPY;\r
+       if (m_pSVNStatusListCtrl)\r
+       {\r
+               POINT clientpoint;\r
+               clientpoint.x = pt.x;\r
+               clientpoint.y = pt.y;\r
+               ScreenToClient(m_hTargetWnd, &clientpoint);\r
+               if ((m_pSVNStatusListCtrl->IsGroupViewEnabled())&&(m_pSVNStatusListCtrl->GetGroupFromPoint(&clientpoint) >= 0))\r
+               {\r
+                       *pdwEffect = DROPEFFECT_MOVE;\r
+               }\r
+               else if ((!m_pSVNStatusListCtrl->m_bFileDropsEnabled)||(m_pSVNStatusListCtrl->m_bOwnDrag))\r
+               {\r
+                       *pdwEffect = DROPEFFECT_NONE;\r
+               }\r
+       }\r
+       return S_OK;\r
+}\r
+\r
+#endif
\ No newline at end of file
index 6addb94..7113000 100644 (file)
@@ -1,9 +1,898 @@
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2003-2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
 #pragma once\r
+#include "TGitPath.h"\r
+#include "GitStatus.h"\r
+#include "GitRev.h"\r
+#include "GitConfig.h"\r
+#include "Colors.h"\r
+\r
+#define SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN (-1)\r
+\r
+// these defines must be in the order the columns are inserted!\r
+#define SVNSLC_COLFILENAME                     0x000000002\r
+#define SVNSLC_COLEXT                          0x000000004\r
+#define SVNSLC_COLSTATUS                       0x000000008\r
+#define SVNSLC_COLREMOTESTATUS         0x000000010\r
+#define SVNSLC_COLTEXTSTATUS           0x000000020\r
+#define SVNSLC_COLPROPSTATUS           0x000000040\r
+#define SVNSLC_COLREMOTETEXT           0x000000080\r
+#define SVNSLC_COLREMOTEPROP           0x000000100\r
+#define SVNSLC_COLURL                          0x000000200\r
+#define SVNSLC_COLLOCK                         0x000000400\r
+#define SVNSLC_COLLOCKCOMMENT          0x000000800\r
+#define SVNSLC_COLAUTHOR                       0x000001000\r
+#define        SVNSLC_COLREVISION                      0x000002000\r
+#define        SVNSLC_COLREMOTEREVISION        0x000004000\r
+#define        SVNSLC_COLDATE                          0x000009000\r
+#define SVNSLC_COLSVNNEEDSLOCK         0x000010000\r
+#define SVNSLC_COLCOPYFROM                     0x000020000\r
+#define        SVNSLC_COLMODIFICATIONDATE      0x000040000\r
+#define SVNSLC_NUMCOLUMNS              19\r
+\r
+#define SVNSLC_SHOWUNVERSIONED 0x000000001\r
+#define SVNSLC_SHOWNORMAL              0x000000002\r
+#define SVNSLC_SHOWMODIFIED            0x000000004\r
+#define SVNSLC_SHOWADDED               0x000000008\r
+#define SVNSLC_SHOWREMOVED             0x000000010\r
+#define SVNSLC_SHOWCONFLICTED  0x000000020\r
+#define SVNSLC_SHOWMISSING             0x000000040\r
+#define SVNSLC_SHOWREPLACED            0x000000080\r
+#define SVNSLC_SHOWMERGED              0x000000100\r
+#define SVNSLC_SHOWIGNORED             0x000000200\r
+#define SVNSLC_SHOWOBSTRUCTED  0x000000400\r
+#define SVNSLC_SHOWEXTERNAL            0x000000800\r
+#define SVNSLC_SHOWINCOMPLETE  0x000001000\r
+#define SVNSLC_SHOWINEXTERNALS 0x000002000\r
+#define SVNSLC_SHOWREMOVEDANDPRESENT 0x000004000\r
+#define SVNSLC_SHOWLOCKS               0x000008000\r
+#define SVNSLC_SHOWDIRECTFILES 0x000010000\r
+#define SVNSLC_SHOWDIRECTFOLDER 0x000020000\r
+#define SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO 0x000040000\r
+#define SVNSLC_SHOWSWITCHED            0x000080000\r
+#define SVNSLC_SHOWINCHANGELIST 0x000100000\r
+\r
+#define SVNSLC_SHOWDIRECTS             (SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWDIRECTFOLDER)\r
+\r
+\r
+#define SVNSLC_SHOWVERSIONED (SVNSLC_SHOWNORMAL|SVNSLC_SHOWMODIFIED|\\r
+SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\\r
+SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\\r
+SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\\r
+SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)\r
+\r
+#define SVNSLC_SHOWVERSIONEDBUTNORMAL (SVNSLC_SHOWMODIFIED|SVNSLC_SHOWADDED|\\r
+SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\\r
+SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\\r
+SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWINEXTERNALS|\\r
+SVNSLC_SHOWEXTERNALFROMDIFFERENTREPO)\r
+\r
+#define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS (SVNSLC_SHOWMODIFIED|\\r
+SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\\r
+SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\\r
+SVNSLC_SHOWINCOMPLETE|SVNSLC_SHOWEXTERNAL|SVNSLC_SHOWINEXTERNALS)\r
+\r
+#define SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALS (SVNSLC_SHOWMODIFIED|\\r
+       SVNSLC_SHOWADDED|SVNSLC_SHOWREMOVED|SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWMISSING|\\r
+       SVNSLC_SHOWREPLACED|SVNSLC_SHOWMERGED|SVNSLC_SHOWIGNORED|SVNSLC_SHOWOBSTRUCTED|\\r
+       SVNSLC_SHOWINCOMPLETE)\r
+\r
+#define SVNSLC_SHOWALL (SVNSLC_SHOWVERSIONED|SVNSLC_SHOWUNVERSIONED)\r
+\r
+#define SVNSLC_POPALL                                  0xFFFFFFFF\r
+#define SVNSLC_POPCOMPAREWITHBASE              0x00000001\r
+#define SVNSLC_POPCOMPARE                              0x00000002\r
+#define SVNSLC_POPGNUDIFF                              0x00000004\r
+#define SVNSLC_POPREVERT                               0x00000008\r
+#define SVNSLC_POPUPDATE                               0x00000010\r
+#define SVNSLC_POPSHOWLOG                              0x00000020\r
+#define SVNSLC_POPOPEN                                 0x00000040\r
+#define SVNSLC_POPDELETE                               0x00000080\r
+#define SVNSLC_POPADD                                  0x00000100\r
+#define SVNSLC_POPIGNORE                               0x00000200\r
+#define SVNSLC_POPCONFLICT                             0x00000400\r
+#define SVNSLC_POPRESOLVE                              0x00000800\r
+#define SVNSLC_POPLOCK                                 0x00001000\r
+#define SVNSLC_POPUNLOCK                               0x00002000\r
+#define SVNSLC_POPUNLOCKFORCE                  0x00004000\r
+#define SVNSLC_POPEXPLORE                              0x00008000\r
+#define SVNSLC_POPCOMMIT                               0x00010000\r
+#define SVNSLC_POPPROPERTIES                   0x00020000\r
+#define SVNSLC_POPREPAIRMOVE                   0x00040000\r
+#define SVNSLC_POPCHANGELISTS                  0x00080000\r
+#define SVNSLC_POPBLAME                                        0x00100000\r
+\r
+#define SVNSLC_IGNORECHANGELIST                        _T("ignore-on-commit")\r
+\r
+// This gives up to 64 standard properties and menu entries\r
+// plus 192 user-defined properties (should be plenty).\r
+// User-defined properties will start at column SVNSLC_NUMCOLUMNS+1\r
+// but in the registry, we will record them starting at SVNSLC_USERPROPCOLOFFSET.\r
+\r
+#define SVNSLC_USERPROPCOLOFFSET        0x40\r
+#define SVNSLC_USERPROPCOLLIMIT         0xff\r
+#define SVNSLC_MAXCOLUMNCOUNT           0xff\r
 \r
+// Supporting extreamly long user props makes no sense here --\r
+// especially for binary properties. CString uses a pool allocator\r
+// that works for up to 256 chars. Make sure we are well below that.\r
+\r
+#define SVNSLC_MAXUSERPROPLENGTH        0x70\r
+\r
+typedef int (__cdecl *GENERICCOMPAREFN)(const void * elem1, const void * elem2);\r
+typedef CComCritSecLock<CComCriticalSection> Locker;\r
+\r
+/**\r
+ * \ingroup SVN\r
+ * A List control, based on the MFC CListCtrl which shows a list of\r
+ * files with their Subversion status. The control also provides a context\r
+ * menu to do some Subversion tasks on the selected files.\r
+ *\r
+ * This is the main control used in many dialogs to show a list of files to\r
+ * work on.\r
+ */\r
 class CGitStatusListCtrl :\r
        public CListCtrl\r
 {\r
 public:\r
+       /**\r
+        * Sent to the parent window (using ::SendMessage) after a context menu\r
+        * command has finished if the item count has changed.\r
+        */\r
+       static const UINT SVNSLNM_ITEMCOUNTCHANGED;\r
+       /**\r
+        * Sent to the parent window (using ::SendMessage) when the control needs\r
+        * to be refreshed. Since this is done usually in the parent window using\r
+        * a thread, this message is used to tell the parent to do exactly that.\r
+        */\r
+       static const UINT SVNSLNM_NEEDSREFRESH;\r
+\r
+       /**\r
+        * Sent to the parent window (using ::SendMessage) when the user drops\r
+        * files on the control. The LPARAM is a pointer to a TCHAR string\r
+        * containing the dropped path.\r
+        */\r
+       static const UINT SVNSLNM_ADDFILE;\r
+\r
+       /**\r
+        * Sent to the parent window (using ::SendMessage) when the user checks/unchecks\r
+        * one or more items in the control. The WPARAM contains the number of\r
+        * checked items in the control.\r
+        */\r
+       static const UINT SVNSLNM_CHECKCHANGED;\r
+\r
        CGitStatusListCtrl(void);\r
        ~CGitStatusListCtrl(void);\r
+\r
+       /**\r
+        * \ingroup TortoiseProc\r
+        * Helper class for CGitStatusListCtrl which represents\r
+        * the data for each file shown.\r
+        */\r
+       class FileEntry\r
+       {\r
+       public:\r
+               FileEntry() : status(git_wc_status_unversioned)\r
+//                     , copyfrom_rev(GIT_REV_ZERO)\r
+                       , last_commit_date(0)\r
+                       , last_commit_rev(GIT_REV_ZERO)\r
+//                     , remoterev(GIT_REV_ZERO)\r
+                       , textstatus(git_wc_status_unversioned)\r
+                       , propstatus(git_wc_status_unversioned)\r
+//                     , remotestatus(git_wc_status_unversioned)\r
+//                     , remotetextstatus(git_wc_status_unversioned)\r
+//                     , remotepropstatus(git_wc_status_unversioned)\r
+                       , copied(false)\r
+                       , switched(false)\r
+                       , checked(false)\r
+                       , inunversionedfolder(false)\r
+                       , inexternal(false)\r
+                       , differentrepo(false)\r
+                       , direct(false)\r
+                       , isfolder(false)\r
+                       , isNested(false)\r
+                       , Revision(GIT_REV_ZERO)\r
+                       , isConflicted(false)\r
+//                     , present_props()\r
+                       , needslock(false)\r
+///                    , working_size(SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN)\r
+                       , keeplocal(false)\r
+//                     , depth(git_depth_unknown)\r
+               {\r
+               }\r
+               const CTGitPath& GetPath() const\r
+               {\r
+                       return path;\r
+               }\r
+               const bool IsChecked() const\r
+               {\r
+                       return checked;\r
+               }\r
+               CString GetRelativeGitPath() const\r
+               {\r
+                       if (path.IsEquivalentTo(basepath))\r
+                               return path.GetGitPathString();\r
+                       return path.GetGitPathString().Mid(basepath.GetGitPathString().GetLength()+1);\r
+               }\r
+//             const bool IsLocked() const\r
+//             {\r
+//                     return !(lock_token.IsEmpty() && lock_remotetoken.IsEmpty());\r
+//             }\r
+//             const bool HasNeedsLock() const\r
+//             {\r
+//                     return needslock;\r
+//             }\r
+               const bool IsFolder() const\r
+               {\r
+                       return isfolder;\r
+               }\r
+               const bool IsInExternal() const\r
+               {\r
+                       return inexternal;\r
+               }\r
+               const bool IsNested() const\r
+               {\r
+                       return isNested;\r
+               }\r
+               const bool IsFromDifferentRepository() const\r
+               {\r
+                       return differentrepo;\r
+               }\r
+               CString GetDisplayName() const\r
+               {\r
+                       CString const& chopped = path.GetDisplayString(&basepath);\r
+                       if (!chopped.IsEmpty())\r
+                       {\r
+                               return chopped;\r
+                       }\r
+                       else\r
+                       {\r
+                               // "Display name" must not be empty.\r
+                               return path.GetFileOrDirectoryName();\r
+                       }\r
+               }\r
+               CString GetChangeList() const\r
+               {\r
+                       return changelist;\r
+               }\r
+//             CString GetURL() const\r
+//             {\r
+//                     return url;\r
+//             }\r
+       public:\r
+               git_wc_status_kind              status;                                 ///< local status\r
+               git_wc_status_kind              textstatus;                             ///< local text status\r
+               git_wc_status_kind              propstatus;                             ///< local property status\r
+               \r
+       private:\r
+               CTGitPath                               path;                                   ///< full path of the file\r
+               CTGitPath                               basepath;                               ///< common ancestor path of all files\r
+               \r
+               CString                                 changelist;                             ///< the name of the changelist the item belongs to\r
+               \r
+               CString                                 last_commit_author;             ///< the author which last committed this item\r
+               CTime                                   last_commit_date;               ///< the date when this item was last committed\r
+               git_revnum_t                    last_commit_rev;                ///< the revision where this item was last committed\r
+               \r
+               git_revnum_t                    remoterev;                              ///< the revision in HEAD of the repository\r
+               bool                                    copied;                                 ///< if the file/folder is added-with-history\r
+               bool                                    switched;                               ///< if the file/folder is switched to another url\r
+               bool                                    checked;                                ///< if the file is checked in the list control\r
+               bool                                    inunversionedfolder;    ///< if the file is inside an unversioned folder\r
+               bool                                    inexternal;                             ///< if the item is in an external folder\r
+               bool                                    differentrepo;                  ///< if the item is from a different repository than the rest\r
+               bool                                    direct;                                 ///< directly included (TRUE) or just a child of a folder\r
+               bool                                    isfolder;                               ///< TRUE if entry refers to a folder\r
+               bool                                    isNested;                               ///< TRUE if the folder from a different repository and/or path\r
+               bool                                    isConflicted;                   ///< TRUE if a file entry is conflicted, i.e. if it has the conflicted paths set\r
+               bool                                    needslock;                              ///< TRUE if the Git:needs-lock property is set\r
+               git_revnum_t                    Revision;                               ///< the base revision\r
+//             PropertyList                    present_props;                  ///< cacheable properties present in BASE\r
+               bool                                    keeplocal;                              ///< Whether a local copy of this entry should be kept in the working copy after a deletion has been committed\r
+               git_depth_t                             depth;                                  ///< the depth of this entry\r
+               friend class CGitStatusListCtrl;\r
+               friend class CGitStatusListCtrlDropTarget;\r
+        friend class CSorter;\r
+       };\r
+       /**\r
+        * \ingroup TortoiseProc\r
+        * Helper class for CGitStatusListCtrl that represents\r
+        * the columns visible and their order as well as \r
+     * persisting that data in the registry.\r
+     *\r
+     * It assigns logical index values to the (potential) columns:\r
+     * 0 .. GitSLC_NUMCOLUMNS-1 contain the standard attributes\r
+     * GitSLC_USERPROPCOLOFFSET .. GitSLC_MAXCOLUMNCOUNT are user props.\r
+     *\r
+     * The column vector contains the columns that are actually\r
+     * available in the control.\r
+     *\r
+     * Since the set of userprops may change from one WC to another,\r
+     * we also store the settings (width and order) for those\r
+     * userprops that are not used in this WC.\r
+     *\r
+     * A userprop is considered "in use", if the respective column\r
+     * is not hidden or if at least one item has this property set.\r
+        */\r
+       class ColumnManager\r
+       {\r
+    public:\r
+\r
+        /// construction / destruction\r
+\r
+        ColumnManager (CListCtrl* control) : control (control) {};\r
+        ~ColumnManager() {};\r
+\r
+        /// registry access\r
+\r
+        void ReadSettings (DWORD defaultColumns, const CString& containerName);\r
+        void WriteSettings() const;\r
+\r
+        /// read column definitions\r
+\r
+        int GetColumnCount() const;                     ///< total number of columns\r
+        bool IsVisible (int column) const;\r
+               int GetInvisibleCount() const;\r
+        bool IsRelevant (int column) const;\r
+        bool IsUserProp (int column) const;\r
+        CString GetName (int column) const;\r
+        int GetWidth (int column, bool useDefaults = false) const;\r
+        int GetVisibleWidth (int column, bool useDefaults) const;\r
+\r
+        /// switch columns on and off\r
+\r
+        void SetVisible (int column, bool visible);\r
+\r
+        /// tracking column modifications\r
+\r
+        void ColumnMoved (int column, int position);\r
+        void ColumnResized (int column);\r
+\r
+        /// call these to update the user-prop list\r
+        /// (will also auto-insert /-remove new list columns)\r
+\r
+        void UpdateUserPropList (const std::vector<FileEntry*>& files);\r
+        void UpdateRelevance ( const std::vector<FileEntry*>& files\r
+                             , const std::vector<size_t>& visibleFiles);\r
+\r
+        /// don't clutter the context menu with irrelevant prop info\r
+\r
+        bool AnyUnusedProperties() const;\r
+        void RemoveUnusedProps();\r
+\r
+        /// bring everything back to its "natural" order\r
+\r
+        void ResetColumns (DWORD defaultColumns);\r
+\r
+    private:\r
+\r
+        /// initialization utilities\r
+\r
+        void ParseUserPropSettings ( const CString& userPropList\r
+                                   , const CString& shownUserProps);\r
+        void ParseWidths (const CString& widths);\r
+        void SetStandardColumnVisibility (DWORD visibility);\r
+        void ParseColumnOrder (const CString& widths);\r
+        \r
+        /// map internal column order onto visible column order\r
+        /// (all invisibles in front)\r
+\r
+        std::vector<int> GetGridColumnOrder();\r
+        void ApplyColumnOrder();\r
+\r
+        /// utilities used when writing data to the registry\r
+\r
+        DWORD GetSelectedStandardColumns() const;\r
+        CString GetUserPropList() const;\r
+        CString GetShownUserProps() const;\r
+        CString GetWidthString() const;\r
+        CString GetColumnOrderString() const;\r
+\r
+        /// our parent control and its data\r
+\r
+        CListCtrl* control;\r
+\r
+        /// where to store in the registry\r
+\r
+        CString registryPrefix;\r
+\r
+        /// all columns in their "natural" order\r
+\r
+        struct ColumnInfo\r
+        {\r
+            int index;          ///< is a user prop when < GitSLC_USERPROPCOLOFFSET\r
+            int width;\r
+            bool visible;\r
+            bool relevant;      ///< set to @a visible, if no *shown* item has that property\r
+        };\r
+\r
+        std::vector<ColumnInfo> columns;\r
+\r
+        /// user-defined properties\r
+\r
+        struct UserProp\r
+        {\r
+            CString name;       ///< is a user prop when < GitSLC_USERPROPCOLOFFSET\r
+            int width;\r
+        };\r
+\r
+        std::vector<UserProp> userProps;\r
+\r
+        /// stored result from last UpdateUserPropList() call\r
+\r
+        std::set<CString> itemProps;\r
+\r
+        /// global column ordering including unused user props\r
+\r
+        std::vector<int> columnOrder;\r
+    };/**\r
+        * \ingroup TortoiseProc\r
+        * Simple utility class that defines the sort column order.\r
+        */\r
+    class CSorter\r
+    {\r
+    public:\r
+\r
+        CSorter ( ColumnManager* columnManager\r
+                , int sortedColumn\r
+                , bool ascending);\r
+\r
+        bool operator() ( const FileEntry* entry1\r
+                        , const FileEntry* entry2) const;\r
+\r
+    private:\r
+\r
+        ColumnManager* columnManager;\r
+        int sortedColumn;\r
+        bool ascending;\r
+    };\r
+\r
+       /**\r
+        * Initializes the control, sets up the columns.\r
+        * \param dwColumns mask of columns to show. Use the GitSLC_COLxxx defines.\r
+        * \param sColumnInfoContainer Name of a registry key\r
+        *                             where the position and visibility of each column\r
+        *                             is saved and used from. If the registry key\r
+        *                             doesn't exist, the default order is used\r
+        *                             and dwColumns tells which columns are visible.\r
+        * \param dwContextMenus mask of context menus to be active, not all make sense for every use of this control.\r
+        *                       Use the GitSLC_POPxxx defines.\r
+        * \param bHasCheckboxes TRUE if the control should show check boxes on the left of each file entry.\r
+        */\r
+       void Init(DWORD dwColumns, const CString& sColumnInfoContainer, DWORD dwContextMenus = (SVNSLC_POPALL ^ SVNSLC_POPCOMMIT), bool bHasCheckboxes = true);\r
+       /**\r
+        * Sets a background image for the list control.\r
+        * The image is shown in the right bottom corner.\r
+        * \param nID the resource ID of the bitmap to use as the background\r
+        */\r
+       bool SetBackgroundImage(UINT nID);\r
+       /**\r
+        * Makes the 'ignore' context menu only ignore the files and not add the\r
+        * folder which gets the Git:ignore property changed to the list.\r
+        * This is needed e.g. for the Add-dialog, where the modified folder\r
+        * showing up would break the resulting "add" command.\r
+        */\r
+       void SetIgnoreRemoveOnly(bool bRemoveOnly = true) {m_bIgnoreRemoveOnly = bRemoveOnly;}\r
+       /**\r
+        * The unversioned items are by default shown after all other files in the list.\r
+        * If that behavior should be changed, set this value to false.\r
+        */\r
+       void PutUnversionedLast(bool bLast) {m_bUnversionedLast = bLast;}\r
+       /**\r
+        * Fetches the Subversion status of all files and stores the information\r
+        * about them in an internal array.\r
+        * \param sFilePath path to a file which contains a list of files and/or folders for which to\r
+        *                  fetch the status, separated by newlines.\r
+        * \param bUpdate TRUE if the remote status is requested too.\r
+        * \return TRUE on success.\r
+        */\r
+       BOOL GetStatus ( const CTGitPathList& pathList\r
+                   , bool bUpdate = false\r
+                   , bool bShowIgnores = false\r
+                   , bool bShowUserProps = false);\r
+\r
+       /**\r
+        * Populates the list control with the previously (with GetStatus) gathered status information.\r
+        * \param dwShow mask of file types to show. Use the GitSLC_SHOWxxx defines.\r
+        * \param dwCheck mask of file types to check. Use GitLC_SHOWxxx defines. Default (0) means 'use the entry's stored check status'\r
+        */\r
+       void Show(DWORD dwShow, DWORD dwCheck = 0, bool bShowFolders = true);\r
+       void Show(DWORD dwShow, const CTGitPathList& checkedList, bool bShowFolders = true);\r
+\r
+       /**\r
+        * Copies the selected entries in the control to the clipboard. The entries\r
+        * are separated by newlines.\r
+        * \param dwCols the columns to copy. Each column is separated by a tab.\r
+        */\r
+       bool CopySelectedEntriesToClipboard(DWORD dwCols);\r
+\r
+       /**\r
+        * If during the call to GetStatus() some Git:externals are found from different\r
+        * repositories than the first one checked, then this method returns TRUE.\r
+        */\r
+       BOOL HasExternalsFromDifferentRepos() const {return m_bHasExternalsFromDifferentRepos;}\r
+\r
+       /**\r
+        * If during the call to GetStatus() some Git:externals are found then this method returns TRUE.\r
+        */\r
+       BOOL HasExternals() const {return m_bHasExternals;}\r
+\r
+       /**\r
+        * If unversioned files are found (but not necessarily shown) TRUE is returned.\r
+        */\r
+       BOOL HasUnversionedItems() {return m_bHasUnversionedItems;}\r
+\r
+       /**\r
+        * If there are any locks in the working copy, TRUE is returned\r
+        */\r
+       BOOL HasLocks() const {return m_bHasLocks;}\r
+\r
+       /**\r
+        * If there are any change lists defined in the working copy, TRUE is returned\r
+        */\r
+       BOOL HasChangeLists() const {return m_bHasChangeLists;}\r
+\r
+       /**\r
+        * Returns the file entry data for the list control index.\r
+        */\r
+       CGitStatusListCtrl::FileEntry * GetListEntry(UINT_PTR index);\r
+\r
+       /**\r
+        * Returns the file entry data for the specified path.\r
+        * \note The entry might not be shown in the list control.\r
+        */\r
+       CGitStatusListCtrl::FileEntry * GetListEntry(const CTGitPath& path);\r
+\r
+       /**\r
+        * Returns the index of the list control entry with the specified path,\r
+        * or -1 if the path is not in the list control.\r
+        */\r
+       int GetIndex(const CTGitPath& path);\r
+\r
+       /**\r
+        * Returns the file entry data for the specified path in the list control.\r
+        */\r
+       CGitStatusListCtrl::FileEntry * GetVisibleListEntry(const CTGitPath& path);\r
+\r
+       /**\r
+        * Returns a String containing some statistics like number of modified, normal, deleted,...\r
+        * files.\r
+        */\r
+       CString GetStatisticsString();\r
+\r
+       /**\r
+        * Set a static control which will be updated automatically with\r
+        * the number of selected and total files shown in the list control.\r
+        */\r
+       void SetStatLabel(CWnd * pStatLabel){m_pStatLabel = pStatLabel;};\r
+\r
+       /**\r
+        * Set a tri-state checkbox which is updated automatically if the\r
+        * user checks/unchecks file entries in the list control to indicate\r
+        * if all files are checked, none are checked or some are checked.\r
+        */\r
+       void SetSelectButton(CButton * pButton) {m_pSelectButton = pButton;}\r
+\r
+       /**\r
+        * Set a button which is de-/activated automatically. The button is\r
+        * only set active if at least one item is selected.\r
+        */\r
+       void SetConfirmButton(CButton * pButton) {m_pConfirmButton = pButton;}\r
+\r
+       /**\r
+        * Select/unselect all entries in the list control.\r
+        * \param bSelect TRUE to check, FALSE to uncheck.\r
+        */\r
+       void SelectAll(bool bSelect, bool bIncludeNoCommits = false);\r
+\r
+       /** Set a checkbox on an entry in the listbox\r
+        * Keeps the listctrl checked state and the FileEntry's checked flag in sync\r
+        */\r
+       void SetEntryCheck(FileEntry* pEntry, int listboxIndex, bool bCheck);\r
+\r
+       /** Write a list of the checked items' paths into a path list\r
+        */\r
+       void WriteCheckedNamesToPathList(CTGitPathList& pathList);\r
+\r
+       /** fills in \a lMin and \a lMax with the lowest/highest revision of all\r
+        * files/folders in the working copy.\r
+        * \param bShownOnly if true, the min/max revisions are calculated only for shown items\r
+        * \param bCheckedOnly if true, the min/max revisions are calculated only for items \r
+        *                   which are checked.\r
+        * \remark Since an item can only be checked if it is visible/shown in the list control\r
+        *         bShownOnly is automatically set to true if bCheckedOnly is true\r
+        */\r
+       void GetMinMaxRevisions(git_revnum_t& rMin, git_revnum_t& rMax, bool bShownOnly, bool bCheckedOnly);\r
+\r
+       /**\r
+        * Returns the parent directory of all entries in the control.\r
+        * if \a bStrict is set to false, then the paths passed to the control\r
+        * to fetch the status (in GetStatus()) are used if possible.\r
+        */\r
+       CTGitPath GetCommonDirectory(bool bStrict);\r
+\r
+       /**\r
+        * Returns the parent url of all entries in the control.\r
+        * if \a bStrict is set to false, then the paths passed to the control\r
+        * to fetch the status (in GetStatus()) are used if possible.\r
+        */\r
+       CTGitPath GetCommonURL(bool bStrict);\r
+\r
+       /**\r
+        * Sets a pointer to a boolean variable which is checked periodically\r
+        * during the status fetching. As soon as the variable changes to true,\r
+        * the operations stops.\r
+        */\r
+       void SetCancelBool(bool * pbCanceled) {m_pbCanceled = pbCanceled;}\r
+\r
+       /**\r
+        * Sets the string shown in the control while the status is fetched.\r
+        * If not set, it defaults to "please wait..."\r
+        */\r
+       void SetBusyString(const CString& str) {m_sBusy = str;}\r
+       void SetBusyString(UINT id) {m_sBusy.LoadString(id);}\r
+\r
+       /**\r
+        * Sets the string shown in the control if no items are shown. This\r
+        * can happen for example if there's nothing modified and the unversioned\r
+        * files aren't shown either, so there's nothing to commit.\r
+        * If not set, it defaults to "file list is empty".\r
+        */\r
+       void SetEmptyString(const CString& str) {m_sEmpty = str;}\r
+       void SetEmptyString(UINT id) {m_sEmpty.LoadString(id);}\r
+\r
+       /**\r
+        * Determines if the control should recurse into unversioned folders\r
+        * when fetching the status. The default behavior is defined by the\r
+        * registry key HKCU\Software\TortoiseGit\UnversionedRecurse, which\r
+        * is read in the Init() method.\r
+        * If you want to change the behavior, call this method *after*\r
+        * calling Init().\r
+        */\r
+       void SetUnversionedRecurse(bool bUnversionedRecurse) {m_bUnversionedRecurse = bUnversionedRecurse;}\r
+\r
+       /**\r
+        * Returns the number of selected items\r
+        */\r
+       LONG GetSelected(){return m_nSelected;};\r
+\r
+       /**\r
+        * Enables dropping of files on the control.\r
+        */\r
+       bool EnableFileDrop();\r
+\r
+       /**\r
+        * Checks if the path already exists in the list.\r
+        */\r
+       bool HasPath(const CTGitPath& path);\r
+       /**\r
+        * Checks if the path is shown/visible in the list control.\r
+        */\r
+       bool IsPathShown(const CTGitPath& path);\r
+       /**\r
+        * Forces the children to be checked when the parent folder is checked,\r
+        * and the parent folder to be unchecked if one of its children is unchecked.\r
+        */\r
+       void CheckChildrenWithParent(bool bCheck) {m_bCheckChildrenWithParent = bCheck;}\r
+\r
+       /**\r
+        * Allows checking the items if change lists are present. If set to false,\r
+        * items are not checked if at least one changelist is available.\r
+        */\r
+       void CheckIfChangelistsArePresent(bool bCheck) {m_bCheckIfGroupsExist = bCheck;}\r
+       /**\r
+        * Returns the currently used show flags passed to the Show() method.\r
+        */\r
+       DWORD GetShowFlags() {return m_dwShow;}\r
+public:\r
+       CString GetLastErrorMessage() {return m_sLastError;}\r
+\r
+       void Block(BOOL block, BOOL blockUI) {m_bBlock = block; m_bBlockUI = blockUI;}\r
+\r
+       LONG                                            m_nTargetCount;         ///< number of targets in the file passed to GetStatus()\r
+\r
+       CString                                         m_sURL;                         ///< the URL of the target or "(multiple targets)"\r
+\r
+       GitRev                                          m_HeadRev;                      ///< the HEAD revision of the repository if bUpdate was TRUE\r
+\r
+       CString                                         m_sUUID;                        ///< the UUID of the associated repository\r
+\r
+       DECLARE_MESSAGE_MAP()\r
+\r
+private:\r
+       void SaveColumnWidths(bool bSaveToRegistry = false);\r
+       void Sort();    ///< Sorts the control by columns\r
+       void AddEntry(FileEntry * entry, WORD langID, int listIndex);   ///< add an entry to the control\r
+       void RemoveListEntry(int index);        ///< removes an entry from the listcontrol and both arrays\r
+       bool BuildStatistics(); ///< build the statistics and correct the case of files/folders\r
+       void StartDiff(int fileindex);  ///< start the external diff program\r
+\r
+    /// fetch all user properties for all items\r
+    void FetchUserProperties();\r
+\r
+       /// Process one line of the command file supplied to GetStatus\r
+       bool FetchStatusForSingleTarget(GitConfig& config, GitStatus& status, const CTGitPath& target, \r
+               bool bFetchStatusFromRepository, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths, \r
+               bool bAllDirect, git_depth_t depth = git_depth_infinity, bool bShowIgnores = false);\r
+\r
+       /// Create 'status' data for each item in an unversioned folder\r
+       void AddUnversionedFolder(const CTGitPath& strFolderName, const CTGitPath& strBasePath, GitConfig * config);\r
+\r
+       /// Read the all the other status items which result from a single GetFirstStatus call\r
+       void ReadRemainingItemsStatus(GitStatus& status, const CTGitPath& strBasePath, CStringA& strCurrentRepositoryUUID, CTGitPathList& arExtPaths, GitConfig * config, bool bAllDirect);\r
+\r
+       /// Clear the status vector (contains custodial pointers)\r
+       void ClearStatusArray();\r
+\r
+       /// Sort predicate function - Compare the paths of two entries without regard to case\r
+       static bool EntryPathCompareNoCase(const FileEntry* pEntry1, const FileEntry* pEntry2);\r
+\r
+       /// Predicate used to build a list of only the versioned entries of the FileEntry array\r
+       static bool IsEntryVersioned(const FileEntry* pEntry1);\r
+\r
+       /// Look up the relevant show flags for a particular Git status value\r
+       DWORD GetShowFlagsFromGitStatus(git_wc_status_kind status);\r
+\r
+       /// Build a FileEntry item and add it to the FileEntry array\r
+       const FileEntry* AddNewFileEntry(\r
+               const git_wc_status2_t* pGitStatus,  // The return from the Git GetStatus functions\r
+               const CTGitPath& path,                          // The path of the item we're adding\r
+               const CTGitPath& basePath,                      // The base directory for this status build\r
+               bool bDirectItem,                                       // Was this item the first found by GetFirstFileStatus or by a subsequent GetNextFileStatus call\r
+               bool bInExternal,                                       // Are we in an 'external' folder\r
+               bool bEntryfromDifferentRepo            // if the entry is from a different repository\r
+               );\r
+\r
+       /// Adjust the checkbox-state on all descendants of a specific item\r
+       void SetCheckOnAllDescendentsOf(const FileEntry* parentEntry, bool bCheck);\r
+\r
+       /// Build a path list of all the selected items in the list (NOTE - SELECTED, not CHECKED)\r
+       void FillListOfSelectedItemPaths(CTGitPathList& pathList, bool bNoIgnored = false);\r
+\r
+       /// Enables/Disables group view and adds all groups to the list control.\r
+       /// If bForce is true, then group view is enabled and the 'null' group is added.\r
+       bool PrepareGroups(bool bForce = false);\r
+       /// Returns the group number to which the group header belongs\r
+       /// If the point is not over a group header, -1 is returned\r
+       int GetGroupFromPoint(POINT * ppt);\r
+       /// Returns the number of change lists the selection has\r
+       size_t GetNumberOfChangelistsInSelection();\r
+\r
+       /// Puts the item to the corresponding group\r
+       bool SetItemGroup(int item, int groupindex);\r
+\r
+       void CheckEntry(int index, int nListItems);\r
+       void UncheckEntry(int index, int nListItems);\r
+\r
+       /// sends an GitSLNM_CHECKCHANGED notification to the parent\r
+       void NotifyCheck();\r
+\r
+       int CellRectFromPoint(CPoint& point, RECT *cellrect, int *col) const;\r
+\r
+       void OnContextMenuList(CWnd * pWnd, CPoint point);\r
+       void OnContextMenuGroup(CWnd * pWnd, CPoint point);\r
+       void OnContextMenuHeader(CWnd * pWnd, CPoint point);\r
+\r
+       virtual void PreSubclassWindow();\r
+       virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+       virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;\r
+       afx_msg void OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult);\r
+       afx_msg BOOL OnToolTipText(UINT id, NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnHdnItemclick(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg BOOL OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult);\r
+    afx_msg void OnColumnResized(NMHDR *pNMHDR, LRESULT *pResult);\r
+    afx_msg void OnColumnMoved(NMHDR *pNMHDR, LRESULT *pResult);\r
+    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);\r
+\r
+       void CreateChangeList(const CString& name);\r
+\r
+       afx_msg void OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnLvnGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);\r
+       afx_msg UINT OnGetDlgCode();\r
+       afx_msg void OnNMReturn(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);\r
+       afx_msg void OnPaint();\r
+       afx_msg void OnHdnBegintrack(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnHdnItemchanging(NMHDR *pNMHDR, LRESULT *pResult);\r
+       afx_msg void OnDestroy();\r
+\r
+private:\r
+       bool *                                          m_pbCanceled;\r
+       bool                                        m_bAscending;               ///< sort direction\r
+       int                                             m_nSortedColumn;        ///< which column to sort\r
+       bool                                            m_bHasCheckboxes;\r
+       bool                                            m_bUnversionedLast;\r
+       bool                                            m_bHasExternalsFromDifferentRepos;\r
+       bool                                            m_bHasExternals;\r
+       BOOL                                            m_bHasUnversionedItems;\r
+       bool                                            m_bHasLocks;\r
+       bool                                            m_bHasChangeLists;\r
+       typedef std::vector<FileEntry*> FileEntryVector;\r
+       FileEntryVector                         m_arStatusArray;\r
+       std::vector<size_t>                     m_arListArray;\r
+       std::map<CString, int>      m_changelists;\r
+       bool                                            m_bHasIgnoreGroup;\r
+       CTGitPathList                           m_ConflictFileList;\r
+       CTGitPathList                           m_StatusFileList;\r
+       CTGitPathList                           m_StatusUrlList;\r
+       CString                                         m_sLastError;\r
+\r
+       LONG                                            m_nUnversioned;\r
+       LONG                                            m_nNormal;\r
+       LONG                                            m_nModified;\r
+       LONG                                            m_nAdded;\r
+       LONG                                            m_nDeleted;\r
+       LONG                                            m_nConflicted;\r
+       LONG                                            m_nTotal;\r
+       LONG                                            m_nSelected;\r
+\r
+       DWORD                                           m_dwDefaultColumns;\r
+       DWORD                                           m_dwShow;\r
+       bool                                            m_bShowFolders;\r
+       bool                                            m_bShowIgnores;\r
+       bool                                            m_bUpdate;\r
+       DWORD                                           m_dwContextMenus;\r
+       BOOL                                            m_bBlock;\r
+       BOOL                                            m_bBlockUI;\r
+       bool                                            m_bBusy;\r
+       bool                                            m_bEmpty;\r
+       bool                                            m_bIgnoreRemoveOnly;\r
+       bool                                            m_bCheckIfGroupsExist;\r
+       bool                                            m_bFileDropsEnabled;\r
+       bool                                            m_bOwnDrag;\r
+\r
+       int                                                     m_nIconFolder;\r
+\r
+       CWnd *                                          m_pStatLabel;\r
+       CButton *                                       m_pSelectButton;\r
+       CButton *                                       m_pConfirmButton;\r
+       CColors                                         m_Colors;\r
+\r
+       CString                                         m_sEmpty;\r
+       CString                                         m_sBusy;\r
+       CString                                         m_sNoPropValueText;\r
+\r
+       bool                                            m_bUnversionedRecurse;\r
+\r
+       bool                                            m_bCheckChildrenWithParent;\r
+       CGitStatusListCtrlDropTarget * m_pDropTarget;\r
+\r
+    ColumnManager               m_ColumnManager;\r
+\r
+       std::map<CString,bool>          m_mapFilenameToChecked; ///< Remember manually de-/selected items\r
+       CComCriticalSection                     m_critSec;\r
+\r
+       friend class CGitStatusListCtrlDropTarget;\r
+};\r
+\r
+#if 0\r
+class CGitStatusListCtrlDropTarget : public CIDropTarget\r
+{\r
+public:\r
+       CGitStatusListCtrlDropTarget(CGitStatusListCtrl * pGitStatusListCtrl):CIDropTarget(pGitStatusListCtrl->m_hWnd){m_pGitStatusListCtrl = pGitStatusListCtrl;}\r
+\r
+       virtual bool OnDrop(FORMATETC* pFmtEtc, STGMEDIUM& medium, DWORD * /*pdwEffect*/, POINTL pt);\r
+       virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD __RPC_FAR *pdwEffect);\r
+private:\r
+       CGitStatusListCtrl * m_pGitStatusListCtrl;\r
 };\r
+#endif
\ No newline at end of file
index 5cc124c..7192d47 100644 (file)
@@ -1,6 +1,6 @@
-// TortoiseSVN - a Windows shell extension for easy version control\r
+// TortoiseGit - a Windows shell extension for easy version control\r
 \r
-// Copyright (C) 2003-2008 - TortoiseSVN\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
 \r
 // This program is free software; you can redistribute it and/or\r
 // modify it under the terms of the GNU General Public License\r
 #include "TortoiseProc.h"\r
 #include "PathUtils.h"\r
 #include "AppUtils.h"\r
-#include "SVNProperties.h"\r
+//#include "GitProperties.h"\r
 #include "StringUtils.h"\r
 #include "MessageBox.h"\r
 #include "Registry.h"\r
-#include "TSVNPath.h"\r
-#include "SVN.h"\r
-#include "RepositoryBrowser.h"\r
-#include "BrowseFolder.h"\r
-\r
+#include "TGitPath.h"\r
+#include "Git.h"\r
+//#include "RepositoryBrowser.h"\r
+//#include "BrowseFolder.h"\r
+#include "UnicodeUtils.h"\r
 \r
 CAppUtils::CAppUtils(void)\r
 {\r
@@ -39,9 +39,10 @@ CAppUtils::~CAppUtils(void)
 {\r
 }\r
 \r
-bool CAppUtils::GetMimeType(const CTSVNPath& file, CString& mimetype)\r
+bool CAppUtils::GetMimeType(const CTGitPath& file, CString& mimetype)\r
 {\r
-       SVNProperties props(file, SVNRev::REV_WC, false);\r
+#if 0\r
+       GitProperties props(file, GitRev::REV_WC, false);\r
        for (int i = 0; i < props.GetCount(); ++i)\r
        {\r
                if (props.GetItemName(i).compare(_T("svn:mime-type"))==0)\r
@@ -50,15 +51,16 @@ bool CAppUtils::GetMimeType(const CTSVNPath& file, CString& mimetype)
                        return true;\r
                }\r
        }\r
+#endif\r
        return false;\r
 }\r
 \r
 BOOL CAppUtils::StartExtMerge(\r
-       const CTSVNPath& basefile, const CTSVNPath& theirfile, const CTSVNPath& yourfile, const CTSVNPath& mergedfile,\r
+       const CTGitPath& basefile, const CTGitPath& theirfile, const CTGitPath& yourfile, const CTGitPath& mergedfile,\r
        const CString& basename, const CString& theirname, const CString& yourname, const CString& mergedname, bool bReadOnly)\r
 {\r
 \r
-       CRegString regCom = CRegString(_T("Software\\TortoiseSVN\\Merge"));\r
+       CRegString regCom = CRegString(_T("Software\\TortoiseGit\\Merge"));\r
        CString ext = mergedfile.GetFileExtension();\r
        CString com = regCom;\r
        bool bInternal = false;\r
@@ -67,7 +69,7 @@ BOOL CAppUtils::StartExtMerge(
        if (ext != "")\r
        {\r
                // is there an extension specific merge tool?\r
-               CRegString mergetool(_T("Software\\TortoiseSVN\\MergeTools\\") + ext.MakeLower());\r
+               CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + ext.MakeLower());\r
                if (CString(mergetool) != "")\r
                {\r
                        com = mergetool;\r
@@ -76,7 +78,7 @@ BOOL CAppUtils::StartExtMerge(
        if (GetMimeType(yourfile, mimetype) || GetMimeType(theirfile, mimetype) || GetMimeType(basefile, mimetype))\r
        {\r
                // is there a mime type specific merge tool?\r
-               CRegString mergetool(_T("Software\\TortoiseSVN\\MergeTools\\") + mimetype);\r
+               CRegString mergetool(_T("Software\\TortoiseGit\\MergeTools\\") + mimetype);\r
                if (CString(mergetool) != "")\r
                {\r
                        com = mergetool;\r
@@ -87,7 +89,7 @@ BOOL CAppUtils::StartExtMerge(
        {\r
                // use TortoiseMerge\r
                bInternal = true;\r
-               CRegString tortoiseMergePath(_T("Software\\TortoiseSVN\\TMergePath"), _T(""), false, HKEY_LOCAL_MACHINE);\r
+               CRegString tortoiseMergePath(_T("Software\\TortoiseGit\\TMergePath"), _T(""), false, HKEY_LOCAL_MACHINE);\r
                com = tortoiseMergePath;\r
                if (com.IsEmpty())\r
                {\r
@@ -202,7 +204,7 @@ BOOL CAppUtils::StartExtMerge(
        return TRUE;\r
 }\r
 \r
-BOOL CAppUtils::StartExtPatch(const CTSVNPath& patchfile, const CTSVNPath& dir, const CString& sOriginalDescription, const CString& sPatchedDescription, BOOL bReversed, BOOL bWait)\r
+BOOL CAppUtils::StartExtPatch(const CTGitPath& patchfile, const CTGitPath& dir, const CString& sOriginalDescription, const CString& sPatchedDescription, BOOL bReversed, BOOL bWait)\r
 {\r
        CString viewer;\r
        // use TortoiseMerge\r
@@ -225,13 +227,13 @@ BOOL CAppUtils::StartExtPatch(const CTSVNPath& patchfile, const CTSVNPath& dir,
        return TRUE;\r
 }\r
 \r
-CString CAppUtils::PickDiffTool(const CTSVNPath& file1, const CTSVNPath& file2)\r
+CString CAppUtils::PickDiffTool(const CTGitPath& file1, const CTGitPath& file2)\r
 {\r
        // Is there a mime type specific diff tool?\r
        CString mimetype;\r
        if (GetMimeType(file1, mimetype) ||  GetMimeType(file2, mimetype))\r
        {\r
-               CString difftool = CRegString(_T("Software\\TortoiseSVN\\DiffTools\\") + mimetype);\r
+               CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + mimetype);\r
                if (!difftool.IsEmpty())\r
                        return difftool;\r
        }\r
@@ -240,7 +242,7 @@ CString CAppUtils::PickDiffTool(const CTSVNPath& file1, const CTSVNPath& file2)
        CString ext = file2.GetFileExtension().MakeLower();\r
        if (!ext.IsEmpty())\r
        {\r
-               CString difftool = CRegString(_T("Software\\TortoiseSVN\\DiffTools\\") + ext);\r
+               CString difftool = CRegString(_T("Software\\TortoiseGit\\DiffTools\\") + ext);\r
                if (!difftool.IsEmpty())\r
                        return difftool;\r
                // Maybe we should use TortoiseIDiff?\r
@@ -256,17 +258,17 @@ CString CAppUtils::PickDiffTool(const CTSVNPath& file1, const CTSVNPath& file2)
        }\r
        \r
        // Finally, pick a generic external diff tool\r
-       CString difftool = CRegString(_T("Software\\TortoiseSVN\\Diff"));\r
+       CString difftool = CRegString(_T("Software\\TortoiseGit\\Diff"));\r
        return difftool;\r
 }\r
 \r
 bool CAppUtils::StartExtDiff(\r
-       const CTSVNPath& file1, const CTSVNPath& file2,\r
+       const CTGitPath& file1, const CTGitPath& file2,\r
        const CString& sName1, const CString& sName2, const DiffFlags& flags)\r
 {\r
        CString viewer;\r
 \r
-       CRegDWORD blamediff(_T("Software\\TortoiseSVN\\DiffBlamesWithTortoiseMerge"), FALSE);\r
+       CRegDWORD blamediff(_T("Software\\TortoiseGit\\DiffBlamesWithTortoiseMerge"), FALSE);\r
        if (!flags.bBlame || !(DWORD)blamediff)\r
        {\r
                viewer = PickDiffTool(file1, file2);\r
@@ -324,9 +326,9 @@ bool CAppUtils::StartExtDiff(
        return LaunchApplication(viewer, IDS_ERR_EXTDIFFSTART, flags.bWait);\r
 }\r
 \r
-BOOL CAppUtils::StartExtDiffProps(const CTSVNPath& file1, const CTSVNPath& file2, const CString& sName1, const CString& sName2, BOOL bWait, BOOL bReadOnly)\r
+BOOL CAppUtils::StartExtDiffProps(const CTGitPath& file1, const CTGitPath& file2, const CString& sName1, const CString& sName2, BOOL bWait, BOOL bReadOnly)\r
 {\r
-       CRegString diffpropsexe(_T("Software\\TortoiseSVN\\DiffProps"));\r
+       CRegString diffpropsexe(_T("Software\\TortoiseGit\\DiffProps"));\r
        CString viewer = diffpropsexe;\r
        bool bInternal = false;\r
        if (viewer.IsEmpty()||(viewer.Left(1).Compare(_T("#"))==0))\r
@@ -374,10 +376,10 @@ BOOL CAppUtils::StartExtDiffProps(const CTSVNPath& file1, const CTSVNPath& file2
        return TRUE;\r
 }\r
 \r
-BOOL CAppUtils::StartUnifiedDiffViewer(const CTSVNPath& patchfile, const CString& title, BOOL bWait)\r
+BOOL CAppUtils::StartUnifiedDiffViewer(const CTGitPath& patchfile, const CString& title, BOOL bWait)\r
 {\r
        CString viewer;\r
-       CRegString v = CRegString(_T("Software\\TortoiseSVN\\DiffViewer"));\r
+       CRegString v = CRegString(_T("Software\\TortoiseGit\\DiffViewer"));\r
        viewer = v;\r
        if (viewer.IsEmpty() || (viewer.Left(1).Compare(_T("#"))==0))\r
        {\r
@@ -497,7 +499,7 @@ BOOL CAppUtils::StartTextViewer(CString file)
        return TRUE;\r
 }\r
 \r
-BOOL CAppUtils::CheckForEmptyDiff(const CTSVNPath& sDiffPath)\r
+BOOL CAppUtils::CheckForEmptyDiff(const CTGitPath& sDiffPath)\r
 {\r
        DWORD length = 0;\r
        HANDLE hFile = ::CreateFile(sDiffPath.GetWinPath(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);\r
@@ -515,7 +517,7 @@ void CAppUtils::CreateFontForLogs(CFont& fontToCreate)
 {\r
        LOGFONT logFont;\r
        HDC hScreenDC = ::GetDC(NULL);\r
-       logFont.lfHeight         = -MulDiv((DWORD)CRegDWORD(_T("Software\\TortoiseSVN\\LogFontSize"), 8), GetDeviceCaps(hScreenDC, LOGPIXELSY), 72);\r
+       logFont.lfHeight         = -MulDiv((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8), GetDeviceCaps(hScreenDC, LOGPIXELSY), 72);\r
        ::ReleaseDC(NULL, hScreenDC);\r
        logFont.lfWidth          = 0;\r
        logFont.lfEscapement     = 0;\r
@@ -529,7 +531,7 @@ void CAppUtils::CreateFontForLogs(CFont& fontToCreate)
        logFont.lfClipPrecision  = CLIP_DEFAULT_PRECIS;\r
        logFont.lfQuality        = DRAFT_QUALITY;\r
        logFont.lfPitchAndFamily = FF_DONTCARE | FIXED_PITCH;\r
-       _tcscpy_s(logFont.lfFaceName, 32, (LPCTSTR)(CString)CRegString(_T("Software\\TortoiseSVN\\LogFontName"), _T("Courier New")));\r
+       _tcscpy_s(logFont.lfFaceName, 32, (LPCTSTR)(CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")));\r
        VERIFY(fontToCreate.CreateFontIndirect(&logFont));\r
 }\r
 \r
@@ -560,7 +562,7 @@ bool CAppUtils::LaunchApplication(const CString& sCommandLine, UINT idErrMessage
                                );\r
                        CString temp;\r
                        temp.Format(idErrMessageFormat, lpMsgBuf);\r
-                       CMessageBox::Show(NULL, temp, _T("TortoiseSVN"), MB_OK | MB_ICONINFORMATION);\r
+                       CMessageBox::Show(NULL, temp, _T("TortoiseGit"), MB_OK | MB_ICONINFORMATION);\r
                        LocalFree( lpMsgBuf );\r
                }\r
                return false;\r
@@ -744,8 +746,9 @@ bool CAppUtils::FindStyleChars(const CString& sText, TCHAR stylechar, int& start
        return bFoundMarker;\r
 }\r
 \r
-bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, SVNRev& rev)\r
+bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, GitRev& rev)\r
 {\r
+#if 0\r
        CString strUrl;\r
        combo.GetWindowText(strUrl);\r
        strUrl.Replace('\\', '/');\r
@@ -754,13 +757,13 @@ bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, SVNRev& r
        if (strUrl.Left(7) == _T("file://"))\r
        {\r
                CString strFile(strUrl);\r
-               SVN::UrlToPath(strFile);\r
+               Git::UrlToPath(strFile);\r
 \r
-               SVN svn;\r
-               if (svn.IsRepository(CTSVNPath(strFile)))\r
+               Git svn;\r
+               if (svn.IsRepository(CTGitPath(strFile)))\r
                {\r
                        // browse repository - show repository browser\r
-                       SVN::preparePath(strUrl);\r
+                       Git::preparePath(strUrl);\r
                        CRepositoryBrowser browser(strUrl, rev, pParent);\r
                        if (browser.DoModal() == IDOK)\r
                        {\r
@@ -776,10 +779,10 @@ bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, SVNRev& r
                        CBrowseFolder folderBrowser;\r
                        folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
                        // remove the 'file:///' so the shell can recognize the local path\r
-                       SVN::UrlToPath(strUrl);\r
+                       Git::UrlToPath(strUrl);\r
                        if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
                        {\r
-                               SVN::PathToUrl(strUrl);\r
+                               Git::PathToUrl(strUrl);\r
 \r
                                combo.SetCurSel(-1);\r
                                combo.SetWindowText(strUrl);\r
@@ -809,13 +812,14 @@ bool CAppUtils::BrowseRepository(CHistoryCombo& combo, CWnd * pParent, SVNRev& r
                folderBrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;\r
                if (folderBrowser.Show(pParent->GetSafeHwnd(), strUrl) == CBrowseFolder::OK)\r
                {\r
-                       SVN::PathToUrl(strUrl);\r
+                       Git::PathToUrl(strUrl);\r
 \r
                        combo.SetCurSel(-1);\r
                        combo.SetWindowText(strUrl);\r
                        return true;\r
                }\r
        }\r
+#endif\r
        return false;\r
 }\r
 \r
@@ -970,18 +974,19 @@ CString CAppUtils::GetProjectNameFromURL(CString url)
        return name;\r
 }\r
 \r
-bool CAppUtils::StartShowUnifiedDiff(HWND hWnd, const CTSVNPath& url1, const SVNRev& rev1, \r
-                                                                        const CTSVNPath& url2, const SVNRev& rev2, \r
-                                                                        const SVNRev& peg /* = SVNRev */, const SVNRev& headpeg /* = SVNRev */,  \r
+bool CAppUtils::StartShowUnifiedDiff(HWND hWnd, const CTGitPath& url1, const GitRev& rev1, \r
+                                                                        const CTGitPath& url2, const GitRev& rev2, \r
+                                                                        const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */,  \r
                                                                         bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool /* blame = false */)\r
 {\r
+#if 0\r
        CString sCmd;\r
        sCmd.Format(_T("%s /command:showcompare /unified"),\r
                (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
-       sCmd += _T(" /url1:\"") + url1.GetSVNPathString() + _T("\"");\r
+       sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
        if (rev1.IsValid())\r
                sCmd += _T(" /revision1:") + rev1.ToString();\r
-       sCmd += _T(" /url2:\"") + url2.GetSVNPathString() + _T("\"");\r
+       sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
        if (rev2.IsValid())\r
                sCmd += _T(" /revision2:") + rev2.ToString();\r
        if (peg.IsValid())\r
@@ -1004,20 +1009,23 @@ bool CAppUtils::StartShowUnifiedDiff(HWND hWnd, const CTSVNPath& url1, const SVN
        }\r
 \r
        return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+#endif\r
+       return TRUE;\r
 }\r
 \r
-bool CAppUtils::StartShowCompare(HWND hWnd, const CTSVNPath& url1, const SVNRev& rev1, \r
-                                                                const CTSVNPath& url2, const SVNRev& rev2, \r
-                                                                const SVNRev& peg /* = SVNRev */, const SVNRev& headpeg /* = SVNRev */, \r
+bool CAppUtils::StartShowCompare(HWND hWnd, const CTGitPath& url1, const GitRev& rev1, \r
+                                                                const CTGitPath& url2, const GitRev& rev2, \r
+                                                                const GitRev& peg /* = GitRev */, const GitRev& headpeg /* = GitRev */, \r
                                                                 bool bAlternateDiff /* = false */, bool bIgnoreAncestry /* = false */, bool blame /* = false */)\r
 {\r
+#if 0\r
        CString sCmd;\r
        sCmd.Format(_T("%s /command:showcompare"),\r
                (LPCTSTR)(CPathUtils::GetAppDirectory()+_T("TortoiseProc.exe")));\r
-       sCmd += _T(" /url1:\"") + url1.GetSVNPathString() + _T("\"");\r
+       sCmd += _T(" /url1:\"") + url1.GetGitPathString() + _T("\"");\r
        if (rev1.IsValid())\r
                sCmd += _T(" /revision1:") + rev1.ToString();\r
-       sCmd += _T(" /url2:\"") + url2.GetSVNPathString() + _T("\"");\r
+       sCmd += _T(" /url2:\"") + url2.GetGitPathString() + _T("\"");\r
        if (rev2.IsValid())\r
                sCmd += _T(" /revision2:") + rev2.ToString();\r
        if (peg.IsValid())\r
@@ -1040,4 +1048,6 @@ bool CAppUtils::StartShowCompare(HWND hWnd, const CTSVNPath& url1, const SVNRev&
        }\r
 \r
        return CAppUtils::LaunchApplication(sCmd, NULL, false);\r
+#endif\r
+       return true;\r
 }
\ No newline at end of file
index 8c91e14..5ff0690 100644 (file)
@@ -54,14 +54,14 @@ public:
         * \return TRUE if the program could be started\r
         */\r
        static BOOL StartExtMerge(\r
-               const CTSVNPath& basefile, const CTSVNPath& theirfile, const CTSVNPath& yourfile, const CTSVNPath& mergedfile,\r
+               const CTGitPath& basefile, const CTGitPath& theirfile, const CTGitPath& yourfile, const CTGitPath& mergedfile,\r
                const CString& basename = CString(), const CString& theirname = CString(), const CString& yourname = CString(),\r
                const CString& mergedname = CString(), bool bReadOnly = false);\r
 \r
        /**\r
         * Starts the external patch program (currently always TortoiseMerge)\r
         */\r
-       static BOOL StartExtPatch(const CTSVNPath& patchfile, const CTSVNPath& dir, \r
+       static BOOL StartExtPatch(const CTGitPath& patchfile, const CTGitPath& dir, \r
                        const CString& sOriginalDescription = CString(), const CString& sPatchedDescription = CString(), \r
                        BOOL bReversed = FALSE, BOOL bWait = FALSE);\r
 \r
@@ -69,19 +69,19 @@ public:
         * Starts the external unified diff viewer (the app associated with *.diff or *.patch files).\r
         * If no app is associated with those file types, the default text editor is used.\r
         */\r
-       static BOOL StartUnifiedDiffViewer(const CTSVNPath& patchfile, const CString& title, BOOL bWait = FALSE);\r
+       static BOOL StartUnifiedDiffViewer(const CTGitPath& patchfile, const CString& title, BOOL bWait = FALSE);\r
 \r
        /**\r
         * Starts the external diff application\r
         */\r
        static bool StartExtDiff(\r
-               const CTSVNPath& file1, const CTSVNPath& file2, \r
+               const CTGitPath& file1, const CTGitPath& file2, \r
                const CString& sName1, const CString& sName2, const DiffFlags& flags);\r
 \r
        /**\r
         * Starts the external diff application for properties\r
         */\r
-       static BOOL StartExtDiffProps(const CTSVNPath& file1, const CTSVNPath& file2, \r
+       static BOOL StartExtDiffProps(const CTGitPath& file1, const CTGitPath& file2, \r
                        const CString& sName1 = CString(), const CString& sName2 = CString(),\r
                        BOOL bWait = FALSE, BOOL bReadOnly = FALSE);\r
 \r
@@ -96,7 +96,7 @@ public:
         * Checks if the given file has a size of less than four, which means\r
         * an 'empty' file or just newlines, i.e. an empty diff.\r
         */\r
-       static BOOL CheckForEmptyDiff(const CTSVNPath& sDiffPath);\r
+       static BOOL CheckForEmptyDiff(const CTGitPath& sDiffPath);\r
 \r
        /**\r
         * Create a font which can is used for log messages, etc\r
@@ -141,7 +141,7 @@ public:
        static  CString GetProjectNameFromURL(CString url);\r
 \r
        /**\r
-        * Replacement for SVNDiff::ShowUnifiedDiff(), but started as a separate process.\r
+        * Replacement for GitDiff::ShowUnifiedDiff(), but started as a separate process.\r
         */\r
        static bool StartShowUnifiedDiff(HWND hWnd, const CTGitPath& url1, const GitRev& rev1, \r
                                                                        const CTGitPath& url2, const GitRev& rev2, \r
index 40e37fa..58ef16f 100644 (file)
@@ -25,7 +25,7 @@
 #include "MessageBox.h"\r
 #include "AppUtils.h"\r
 #include "PathUtils.h"\r
-//#include "Git.h"\r
+#include "Git.h"\r
 #include "Registry.h"\r
 #include "GitStatus.h"\r
 #include "HistoryDlg.h"\r
@@ -91,6 +91,7 @@ BEGIN_MESSAGE_MAP(CCommitDlg, CResizableStandAloneDialog)
        ON_WM_TIMER()\r
     ON_WM_SIZE()\r
        ON_STN_CLICKED(IDC_EXTERNALWARNING, &CCommitDlg::OnStnClickedExternalwarning)\r
+       ON_BN_CLICKED(IDC_SIGN_OFF, &CCommitDlg::OnBnClickedSignOff)\r
 END_MESSAGE_MAP()\r
 \r
 BOOL CCommitDlg::OnInitDialog()\r
@@ -1347,3 +1348,12 @@ void CCommitDlg::OnSize(UINT nType, int cx, int cy)
     SetSplitterRange();\r
 }\r
 \r
+\r
+void CCommitDlg::OnBnClickedSignOff()\r
+{\r
+       // TODO: Add your control notification handler code here\r
+       CGit git;\r
+       CString str;\r
+       str.Format(_T("Signed-off-by: %s <%s>\n"),git.GetUserName(), git.GetUserEmail());\r
+       m_cLogMessage.InsertText(str,true);\r
+}\r
index b63bb02..f805a72 100644 (file)
@@ -135,4 +135,6 @@ private:
 \r
 //     CBugTraqAssociation m_bugtraq_association;\r
 \r
+public:\r
+       afx_msg void OnBnClickedSignOff();\r
 };\r
diff --git a/TortoiseProc/GitStatusListCtrlHelpers.cpp b/TortoiseProc/GitStatusListCtrlHelpers.cpp
new file mode 100644 (file)
index 0000000..c8e3e15
--- /dev/null
@@ -0,0 +1,1080 @@
+// TortoiseSVN - a Windows shell extension for easy version control\r
+\r
+// Copyright (C) 2008 - TortoiseSVN\r
+\r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// as published by the Free Software Foundation; either version 2\r
+// of the License, or (at your option) any later version.\r
+\r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+// GNU General Public License for more details.\r
+\r
+// You should have received a copy of the GNU General Public License\r
+// along with this program; if not, write to the Free Software Foundation,\r
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+//\r
+\r
+#include "stdafx.h"\r
+#include ".\resource.h"\r
+#include "GitStatusListCtrl.h"\r
+#include <iterator>\r
+// assign property list\r
+#if 0\r
+CGitStatusListCtrl::PropertyList& \r
+CGitStatusListCtrl::PropertyList::operator= (const char* rhs)\r
+{\r
+       // do you really want to replace the property list?\r
+\r
+       assert (properties.empty());\r
+       properties.clear();\r
+\r
+       // add all properties in the list\r
+\r
+       while ((rhs != NULL) && (*rhs != 0))\r
+       {\r
+               const char* next = strchr (rhs, ' ');\r
+\r
+               CString name (rhs, static_cast<int>(next == NULL ? strlen (rhs) : next - rhs));\r
+               properties.insert (std::make_pair (name, CString()));\r
+\r
+               rhs = next == NULL ? NULL : next+1;\r
+       }\r
+\r
+       // done\r
+\r
+       return *this;\r
+}\r
+\r
+// collect property names in a set\r
+\r
+void CGitStatusListCtrl::PropertyList::GetPropertyNames (std::set<CString>& names)\r
+{\r
+       for ( CIT iter = properties.begin(), end = properties.end()\r
+               ; iter != end\r
+               ; ++iter)\r
+       {\r
+               names.insert (iter->first);\r
+       }\r
+}\r
+\r
+// get a property value. \r
+\r
+CString CGitStatusListCtrl::PropertyList::operator[](const CString& name) const\r
+{\r
+       CIT iter = properties.find (name);\r
+\r
+       return iter == properties.end()\r
+               ? CString()\r
+               : iter->second;\r
+}\r
+\r
+// set a property value.\r
+\r
+CString& CGitStatusListCtrl::PropertyList::operator[](const CString& name)\r
+{\r
+       return properties[name];\r
+}\r
+\r
+/// check whether that property has been set on this item.\r
+\r
+bool CGitStatusListCtrl::PropertyList::HasProperty (const CString& name) const\r
+{\r
+       return properties.find (name) != properties.end();\r
+}\r
+\r
+// due to frequent use: special check for svn:needs-lock\r
+\r
+bool CGitStatusListCtrl::PropertyList::IsNeedsLockSet() const\r
+{\r
+       static const CString svnNeedsLock = _T("svn:needs-lock");\r
+       return HasProperty (svnNeedsLock);\r
+}\r
+\r
+#endif\r
+// registry access\r
+\r
+void CGitStatusListCtrl::ColumnManager::ReadSettings \r
+    ( DWORD defaultColumns\r
+    , const CString& containerName)\r
+{\r
+    // defaults\r
+\r
+    DWORD selectedStandardColumns = defaultColumns;\r
+\r
+    columns.resize (SVNSLC_NUMCOLUMNS);\r
+    for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)\r
+    {\r
+        columns[i].index = static_cast<int>(i);\r
+        columns[i].width = 0;\r
+        columns[i].visible = true;\r
+        columns[i].relevant = true;\r
+    }\r
+\r
+    userProps.clear();\r
+\r
+    // where the settings are stored within the registry\r
+\r
+    registryPrefix \r
+        = _T("Software\\TortoiseGit\\StatusColumns\\") + containerName;\r
+\r
+    // we accept settings version 2 only\r
+    // (version 1 used different placement of hidden columns)\r
+\r
+       bool valid = (DWORD)CRegDWORD (registryPrefix + _T("Version"), 0xff) == 2;\r
+    if (valid)\r
+    {\r
+        // read (possibly different) column selection\r
+\r
+               selectedStandardColumns \r
+            = CRegDWORD (registryPrefix, selectedStandardColumns);\r
+\r
+        // read user-prop lists\r
+\r
+        CString userPropList \r
+            = CRegString (registryPrefix + _T("UserProps"));\r
+        CString shownUserProps \r
+            = CRegString (registryPrefix + _T("ShownUserProps"));\r
+\r
+        ParseUserPropSettings (userPropList, shownUserProps);\r
+\r
+        // read column widths\r
+\r
+        CString colWidths\r
+            = CRegString (registryPrefix + _T("_Width"));\r
+\r
+        ParseWidths (colWidths);\r
+    }\r
+\r
+    // process old-style visibility setting\r
+\r
+    SetStandardColumnVisibility (selectedStandardColumns);\r
+\r
+       // clear all previously set header columns\r
+\r
+       int c = ((CHeaderCtrl*)(control->GetDlgItem(0)))->GetItemCount()-1;\r
+       while (c>=0)\r
+               control->DeleteColumn(c--);\r
+\r
+    // create columns\r
+\r
+    for (int i = 0, count = GetColumnCount(); i < count; ++i)\r
+               control->InsertColumn (i, GetName(i), LVCFMT_LEFT, IsVisible(i) ? -1 : GetVisibleWidth(i, false));\r
+\r
+    // restore column ordering\r
+\r
+    if (valid)\r
+        ParseColumnOrder (CRegString (registryPrefix + _T("_Order")));\r
+    else\r
+        ParseColumnOrder (CString());\r
+\r
+    ApplyColumnOrder();\r
+\r
+    // auto-size the columns so we can see them while fetching status\r
+    // (seems the same values will not take affect in InsertColumn)\r
+\r
+    for (int i = 0, count = GetColumnCount(); i < count; ++i)\r
+        if (IsVisible(i))\r
+                   control->SetColumnWidth (i, GetVisibleWidth (i, true));\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::WriteSettings() const\r
+{\r
+    // we are version 2\r
+\r
+       CRegDWORD regVersion (registryPrefix + _T("Version"), 0, TRUE);\r
+    regVersion = 2;\r
+\r
+    // write (possibly different) column selection\r
+\r
+    CRegDWORD regStandardColumns (registryPrefix, 0, TRUE);\r
+    regStandardColumns = GetSelectedStandardColumns();\r
+\r
+    // write user-prop lists\r
+\r
+    CRegString regUserProps (registryPrefix + _T("UserProps"), CString(), TRUE);\r
+    regUserProps = GetUserPropList();\r
+\r
+    CRegString regShownUserProps (registryPrefix + _T("ShownUserProps"), CString(), TRUE);\r
+    regShownUserProps = GetShownUserProps();\r
+\r
+    // write column widths\r
+\r
+    CRegString regWidths (registryPrefix + _T("_Width"), CString(), TRUE);\r
+    regWidths = GetWidthString();\r
+\r
+    // write column ordering\r
+\r
+    CRegString regColumnOrder (registryPrefix + _T("_Order"), CString(), TRUE);\r
+    regColumnOrder = GetColumnOrderString();\r
+}\r
+\r
+// read column definitions\r
+\r
+int CGitStatusListCtrl::ColumnManager::GetColumnCount() const\r
+{\r
+    return static_cast<int>(columns.size());\r
+}\r
+\r
+bool CGitStatusListCtrl::ColumnManager::IsVisible (int column) const\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (columns.size() > index);\r
+\r
+    return columns[index].visible;\r
+}\r
+\r
+int CGitStatusListCtrl::ColumnManager::GetInvisibleCount() const\r
+{\r
+       int invisibleCount = 0;\r
+       for (std::vector<ColumnInfo>::const_iterator it = columns.begin(); it != columns.end(); ++it)\r
+       {\r
+               if (!it->visible)\r
+                       invisibleCount++;\r
+       }\r
+       return invisibleCount;\r
+}\r
+\r
+bool CGitStatusListCtrl::ColumnManager::IsRelevant (int column) const\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (columns.size() > index);\r
+\r
+    return columns[index].relevant;\r
+}\r
+\r
+bool CGitStatusListCtrl::ColumnManager::IsUserProp (int column) const\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (columns.size() > index);\r
+\r
+    return columns[index].index >= SVNSLC_USERPROPCOLOFFSET;\r
+}\r
+\r
+CString CGitStatusListCtrl::ColumnManager::GetName (int column) const\r
+{\r
+    static const UINT standardColumnNames[SVNSLC_NUMCOLUMNS] \r
+        = { IDS_STATUSLIST_COLFILE\r
+\r
+          , IDS_STATUSLIST_COLFILENAME\r
+          , IDS_STATUSLIST_COLEXT\r
+                 , IDS_STATUSLIST_COLSTATUS\r
+\r
+                 , IDS_STATUSLIST_COLREMOTESTATUS\r
+                 , IDS_STATUSLIST_COLTEXTSTATUS\r
+                 , IDS_STATUSLIST_COLPROPSTATUS\r
+\r
+                 , IDS_STATUSLIST_COLREMOTETEXTSTATUS\r
+                 , IDS_STATUSLIST_COLREMOTEPROPSTATUS\r
+                 , IDS_STATUSLIST_COLURL\r
+\r
+                 , IDS_STATUSLIST_COLLOCK\r
+                 , IDS_STATUSLIST_COLLOCKCOMMENT\r
+                 , IDS_STATUSLIST_COLAUTHOR\r
+\r
+                 , IDS_STATUSLIST_COLREVISION\r
+                 , IDS_STATUSLIST_COLREMOTEREVISION\r
+                 , IDS_STATUSLIST_COLDATE\r
+                 , IDS_STATUSLIST_COLSVNLOCK\r
+\r
+                 , IDS_STATUSLIST_COLCOPYFROM\r
+          , IDS_STATUSLIST_COLMODIFICATIONDATE};\r
+\r
+    // standard columns\r
+\r
+    size_t index = static_cast<size_t>(column);\r
+    if (index < SVNSLC_NUMCOLUMNS)\r
+    {\r
+        CString result;\r
+        result.LoadString (standardColumnNames[index]);\r
+        return result;\r
+    }\r
+\r
+    // user-prop columns\r
+\r
+    if (index < columns.size())\r
+        return userProps[columns[index].index - SVNSLC_USERPROPCOLOFFSET].name;\r
+\r
+    // default: empty\r
+\r
+    return CString();\r
+}\r
+\r
+int CGitStatusListCtrl::ColumnManager::GetWidth (int column, bool useDefaults) const\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (columns.size() > index);\r
+\r
+    int width = columns[index].width;\r
+    if ((width == 0) && useDefaults)\r
+        width = LVSCW_AUTOSIZE_USEHEADER;\r
+\r
+    return width;\r
+}\r
+\r
+int CGitStatusListCtrl::ColumnManager::GetVisibleWidth (int column, bool useDefaults) const\r
+{\r
+    return IsVisible (column)\r
+        ? GetWidth (column, useDefaults)\r
+        : 0;\r
+}\r
+\r
+// switch columns on and off\r
+\r
+void CGitStatusListCtrl::ColumnManager::SetVisible \r
+    ( int column\r
+    , bool visible)\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (index < columns.size());\r
+       \r
+    if (columns[index].visible != visible)\r
+    {\r
+        columns[index].visible = visible;\r
+        columns[index].relevant |= visible;\r
+        if (!visible)\r
+            columns[index].width = 0; \r
+\r
+        control->SetColumnWidth (column, GetVisibleWidth (column, true));\r
+        ApplyColumnOrder();\r
+\r
+        control->Invalidate (FALSE);\r
+    }\r
+}\r
+\r
+// tracking column modifications\r
+\r
+void CGitStatusListCtrl::ColumnManager::ColumnMoved (int column, int position)\r
+{\r
+    // in front of what column has it been inserted?\r
+\r
+    int index = columns[column].index;\r
+\r
+    std::vector<int> gridColumnOrder = GetGridColumnOrder();\r
+\r
+    size_t visiblePosition = static_cast<size_t>(position);\r
+    size_t columnCount = gridColumnOrder.size();\r
+\r
+    for (;    (visiblePosition < columnCount) \r
+           && !columns[gridColumnOrder[visiblePosition]].visible\r
+         ; ++visiblePosition )\r
+    {\r
+    }\r
+\r
+    int next = visiblePosition == columnCount\r
+             ? -1 \r
+             : gridColumnOrder[visiblePosition];\r
+\r
+    // move logical column index just in front of that "next" column\r
+\r
+    columnOrder.erase (std::find ( columnOrder.begin()\r
+                                 , columnOrder.end()\r
+                                 , index));\r
+    columnOrder.insert ( std::find ( columnOrder.begin()\r
+                                   , columnOrder.end()\r
+                                   , next)\r
+                       , index);\r
+\r
+    // make sure, invisible columns are still put in front of all others\r
+\r
+    ApplyColumnOrder();\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::ColumnResized (int column)\r
+{\r
+    size_t index = static_cast<size_t>(column);\r
+    assert (index < columns.size());\r
+    assert (columns[index].visible);\r
+       \r
+    int width = control->GetColumnWidth (column);\r
+    columns[index].width = width;\r
+\r
+    int propertyIndex = columns[index].index;\r
+    if (propertyIndex >= SVNSLC_USERPROPCOLOFFSET)\r
+        userProps[propertyIndex - SVNSLC_USERPROPCOLOFFSET].width = width;\r
+\r
+    control->Invalidate  (FALSE);\r
+}\r
+\r
+// call these to update the user-prop list\r
+// (will also auto-insert /-remove new list columns)\r
+\r
+void CGitStatusListCtrl::ColumnManager::UpdateUserPropList \r
+    (const std::vector<FileEntry*>& files)\r
+{\r
+    // collect all user-defined props\r
+#if 0\r
+    std::set<CString> aggregatedProps;\r
+    for (size_t i = 0, count = files.size(); i < count; ++i)\r
+        files[i]->present_props.GetPropertyNames (aggregatedProps);\r
+\r
+    aggregatedProps.erase (_T("svn:needs-lock"));\r
+    itemProps = aggregatedProps;\r
+\r
+    // add new ones to the internal list\r
+\r
+    std::set<CString> newProps = aggregatedProps;\r
+    for (size_t i = 0, count = userProps.size(); i < count; ++i)\r
+        newProps.erase (userProps[i].name);\r
+\r
+    while (   newProps.size() + userProps.size()\r
+            > SVNSLC_MAXCOLUMNCOUNT - SVNSLC_USERPROPCOLOFFSET)\r
+        newProps.erase (--newProps.end());\r
+\r
+    typedef std::set<CString>::const_iterator CIT;\r
+    for ( CIT iter = newProps.begin(), end = newProps.end()\r
+        ; iter != end\r
+        ; ++iter)\r
+    {\r
+        int index = static_cast<int>(userProps.size()) \r
+                  + SVNSLC_USERPROPCOLOFFSET;\r
+        columnOrder.push_back (index);\r
+\r
+        UserProp userProp;\r
+        userProp.name = *iter;\r
+        userProp.width = 0;\r
+\r
+        userProps.push_back (userProp);\r
+    }\r
+\r
+    // remove unused columns from control.\r
+    // remove used ones from the set of aggregatedProps.\r
+\r
+    for (size_t i = columns.size(); i > 0; --i)\r
+        if (   (columns[i-1].index >= SVNSLC_USERPROPCOLOFFSET)\r
+            && (aggregatedProps.erase (GetName ((int)i-1)) == 0))\r
+        {\r
+            // this user-prop has not been set on any item\r
+\r
+            if (!columns[i-1].visible)\r
+            {\r
+                control->DeleteColumn (static_cast<int>(i-1));\r
+                columns.erase (columns.begin() + i-1);\r
+            }\r
+        }\r
+\r
+    // aggregatedProps now contains new columns only.\r
+    // we can't use newProps here because some props may have been used\r
+    // earlier but were not in the recent list of used props.\r
+    // -> they are neither in columns[] nor in newProps.\r
+\r
+    for ( CIT iter = aggregatedProps.begin(), end = aggregatedProps.end()\r
+        ; iter != end\r
+        ; ++iter)\r
+    {\r
+        // get the logical column index / ID\r
+\r
+        int index = -1;\r
+        int width = 0;\r
+        for (size_t i = 0, count = userProps.size(); i < count; ++i)\r
+            if (userProps[i].name == *iter)\r
+            {\r
+                index = static_cast<int>(i) + SVNSLC_USERPROPCOLOFFSET;\r
+                width = userProps[i].width;\r
+                break;\r
+            }\r
+\r
+        assert (index != -1);\r
+\r
+        // find insertion position\r
+\r
+        std::vector<ColumnInfo>::iterator columnIter = columns.begin();\r
+        std::vector<ColumnInfo>::iterator end = columns.end();\r
+        for (; (columnIter != end) && columnIter->index < index; ++columnIter);\r
+        int pos = static_cast<int>(columnIter - columns.begin());\r
+\r
+        ColumnInfo column;\r
+        column.index = index;\r
+        column.width = width;\r
+        column.visible = false;\r
+\r
+        columns.insert (columnIter, column);\r
+\r
+        // update control\r
+\r
+        int result = control->InsertColumn (pos, *iter, LVCFMT_LEFT, GetVisibleWidth(pos, false));\r
+        assert (result != -1);\r
+               UNREFERENCED_PARAMETER(result);\r
+    }\r
+\r
+    // update column order\r
+\r
+    ApplyColumnOrder();\r
+\r
+#endif\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::UpdateRelevance \r
+    ( const std::vector<FileEntry*>& files\r
+    , const std::vector<size_t>& visibleFiles)\r
+{\r
+    // collect all user-defined props that belong to shown files\r
+#if 0\r
+    std::set<CString> aggregatedProps;\r
+    for (size_t i = 0, count = visibleFiles.size(); i < count; ++i)\r
+        files[visibleFiles[i]]->present_props.GetPropertyNames (aggregatedProps);\r
+\r
+    aggregatedProps.erase (_T("svn:needs-lock"));\r
+    itemProps = aggregatedProps;\r
+\r
+    // invisible columns for unused props are not relevant\r
+\r
+    for (int i = 0, count = GetColumnCount(); i < count; ++i)\r
+        if (IsUserProp(i) && !IsVisible(i))\r
+        {\r
+            columns[i].relevant \r
+                = aggregatedProps.find (GetName(i)) != aggregatedProps.end();\r
+        }\r
+#endif\r
+}\r
+\r
+// don't clutter the context menu with irrelevant prop info\r
+\r
+bool CGitStatusListCtrl::ColumnManager::AnyUnusedProperties() const\r
+{\r
+    return columns.size() < userProps.size() + SVNSLC_NUMCOLUMNS;\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::RemoveUnusedProps()\r
+{\r
+    // determine what column indexes / IDs to keep.\r
+    // map them onto new IDs (we may delete some IDs in between)\r
+\r
+    std::map<int, int> validIndices;\r
+    int userPropID = SVNSLC_USERPROPCOLOFFSET;\r
+\r
+    for (size_t i = 0, count = columns.size(); i < count; ++i)\r
+    {\r
+        int index = columns[i].index;\r
+\r
+        if (   itemProps.find (GetName((int)i)) != itemProps.end()\r
+            || columns[i].visible\r
+            || index < SVNSLC_USERPROPCOLOFFSET)\r
+        {\r
+            validIndices[index] = index < SVNSLC_USERPROPCOLOFFSET\r
+                                ? index\r
+                                : userPropID++;\r
+        }\r
+    }\r
+\r
+    // remove everything else:\r
+\r
+    // remove from columns and control.\r
+    // also update index values in columns\r
+\r
+    for (size_t i = columns.size(); i > 0; --i)\r
+    {\r
+        std::map<int, int>::const_iterator iter \r
+            = validIndices.find (columns[i-1].index);\r
+\r
+        if (iter == validIndices.end())\r
+        {\r
+            control->DeleteColumn (static_cast<int>(i-1));\r
+            columns.erase (columns.begin() + i-1);\r
+        }\r
+        else\r
+        {\r
+            columns[i-1].index = iter->second;\r
+        }\r
+    }\r
+\r
+    // remove from user props\r
+\r
+    for (size_t i = userProps.size(); i > 0; --i)\r
+    {\r
+        int index = static_cast<int>(i)-1 + SVNSLC_USERPROPCOLOFFSET;\r
+        if (validIndices.find (index) == validIndices.end())\r
+            userProps.erase (userProps.begin() + i-1);\r
+    }\r
+\r
+    // remove from and update column order\r
+\r
+    for (size_t i = columnOrder.size(); i > 0; --i)\r
+    {\r
+        std::map<int, int>::const_iterator iter \r
+            = validIndices.find (columnOrder[i-1]);\r
+\r
+        if (iter == validIndices.end())\r
+            columnOrder.erase (columnOrder.begin() + i-1);\r
+        else\r
+            columnOrder[i-1] = iter->second;\r
+    }\r
+}\r
+\r
+// bring everything back to its "natural" order\r
+\r
+void CGitStatusListCtrl::ColumnManager::ResetColumns (DWORD defaultColumns)\r
+{\r
+    // update internal data\r
+\r
+    std::sort (columnOrder.begin(), columnOrder.end());\r
+\r
+    for (size_t i = 0, count = columns.size(); i < count; ++i)\r
+    {\r
+        columns[i].width = 0;\r
+        columns[i].visible = (i < 32) && (((defaultColumns >> i) & 1) != 0);\r
+    }\r
+\r
+    for (size_t i = 0, count = userProps.size(); i < count; ++i)\r
+        userProps[i].width = 0;\r
+\r
+    // update UI\r
+\r
+    for (int i = 0, count = GetColumnCount(); i < count; ++i)\r
+        control->SetColumnWidth (i, GetVisibleWidth (i, true));\r
+\r
+    ApplyColumnOrder();\r
+\r
+    control->Invalidate (FALSE);\r
+}\r
+\r
+// initialization utilities\r
+\r
+void CGitStatusListCtrl::ColumnManager::ParseUserPropSettings \r
+    ( const CString& userPropList\r
+    , const CString& shownUserProps)\r
+{\r
+    assert (userProps.empty());\r
+\r
+    static CString delimiters (_T(" "));\r
+\r
+    // parse list of visible user-props\r
+\r
+    std::set<CString> visibles;\r
+\r
+    int pos = 0;\r
+    CString name = shownUserProps.Tokenize (delimiters, pos);\r
+    while (!name.IsEmpty())\r
+    {\r
+        visibles.insert (name);\r
+        name = shownUserProps.Tokenize (delimiters, pos);\r
+    }\r
+\r
+    // create list of all user-props\r
+\r
+    pos = 0;\r
+    name = userPropList.Tokenize (delimiters, pos);\r
+    while (!name.IsEmpty())\r
+    {\r
+        bool visible = visibles.find (name) != visibles.end();\r
+\r
+        UserProp newEntry;\r
+        newEntry.name = name;\r
+        newEntry.width = 0;\r
+\r
+        userProps.push_back (newEntry);\r
+\r
+        // auto-create columns for visible user-props\r
+        // (others may be added later)\r
+\r
+        if (visible)\r
+        {\r
+            ColumnInfo newColumn;\r
+            newColumn.width = 0;\r
+            newColumn.visible = true;\r
+            newColumn.relevant = true;\r
+            newColumn.index = static_cast<int>(userProps.size()) \r
+                            + SVNSLC_USERPROPCOLOFFSET - 1;\r
+\r
+            columns.push_back (newColumn);\r
+        }\r
+\r
+        name = userPropList.Tokenize (delimiters, pos);\r
+    }\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::ParseWidths (const CString& widths)\r
+{\r
+    for (int i = 0, count = widths.GetLength() / 8; i < count; ++i)\r
+    {\r
+               long width = _tcstol (widths.Mid (i*8, 8), NULL, 16);\r
+        if (i < SVNSLC_NUMCOLUMNS)\r
+        {\r
+            // a standard column\r
+\r
+            columns[i].width = width;\r
+        }\r
+        else if (i >= SVNSLC_USERPROPCOLOFFSET)\r
+        {\r
+            // a user-prop column\r
+\r
+            size_t index = static_cast<size_t>(i - SVNSLC_USERPROPCOLOFFSET);\r
+            assert (index < userProps.size());\r
+            userProps[index].width = width;\r
+\r
+            for (size_t k = 0, count = columns.size(); k < count; ++k)\r
+                if (columns[k].index == i)\r
+                    columns[k].width = width;\r
+        }\r
+        else\r
+        {\r
+            // there is no such column \r
+\r
+            assert (width == 0);\r
+        }\r
+    }\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::SetStandardColumnVisibility \r
+    (DWORD visibility)\r
+{\r
+    for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)\r
+    {\r
+        columns[i].visible = (visibility & 1) > 0;\r
+        visibility /= 2;\r
+    }\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::ParseColumnOrder \r
+    (const CString& widths)\r
+{\r
+    std::set<int> alreadyPlaced;\r
+    columnOrder.clear();\r
+\r
+    // place columns according to valid entries in orderString\r
+\r
+    int limit = static_cast<int>(SVNSLC_USERPROPCOLOFFSET + userProps.size());\r
+    for (int i = 0, count = widths.GetLength() / 2; i < count; ++i)\r
+    {\r
+               int index = _tcstol (widths.Mid (i*2, 2), NULL, 16);\r
+        if (   (index < SVNSLC_NUMCOLUMNS)\r
+            || ((index >= SVNSLC_USERPROPCOLOFFSET) && (index < limit)))\r
+        {\r
+            alreadyPlaced.insert (index);\r
+            columnOrder.push_back (index);\r
+        }\r
+    }\r
+\r
+    // place the remaining colums behind it\r
+\r
+    for (int i = 0; i < SVNSLC_NUMCOLUMNS; ++i)\r
+        if (alreadyPlaced.find (i) == alreadyPlaced.end())\r
+            columnOrder.push_back (i);\r
+\r
+    for (int i = SVNSLC_USERPROPCOLOFFSET; i < limit; ++i)\r
+        if (alreadyPlaced.find (i) == alreadyPlaced.end())\r
+            columnOrder.push_back (i);\r
+}\r
+\r
+// map internal column order onto visible column order\r
+// (all invisibles in front)\r
+\r
+std::vector<int> CGitStatusListCtrl::ColumnManager::GetGridColumnOrder()\r
+{\r
+    // extract order of used columns from order of all columns\r
+\r
+    std::vector<int> result;\r
+    result.reserve (SVNSLC_MAXCOLUMNCOUNT+1);\r
+\r
+    size_t colCount = columns.size();\r
+    bool visible = false;\r
+\r
+    do\r
+    {\r
+        // put invisible cols in front\r
+\r
+        for (size_t i = 0, count = columnOrder.size(); i < count; ++i)\r
+        {\r
+            int index = columnOrder[i];\r
+            for (size_t k = 0; k < colCount; ++k)\r
+            {\r
+                const ColumnInfo& column = columns[k];\r
+                if ((column.index == index) && (column.visible == visible))\r
+                    result.push_back (static_cast<int>(k));\r
+            }\r
+        }\r
+\r
+        visible = !visible;\r
+    }\r
+    while (visible);\r
+\r
+    return result;\r
+}\r
+\r
+void CGitStatusListCtrl::ColumnManager::ApplyColumnOrder()\r
+{\r
+    // extract order of used columns from order of all columns\r
+\r
+    int order[SVNSLC_MAXCOLUMNCOUNT+1];\r
+    SecureZeroMemory (order, sizeof (order));\r
+\r
+    std::vector<int> gridColumnOrder = GetGridColumnOrder();\r
+       std::copy (gridColumnOrder.begin(), gridColumnOrder.end(), stdext::checked_array_iterator<int*>(&order[0], sizeof(order)));\r
+\r
+    // we must have placed all columns or something is really fishy ..\r
+\r
+    assert (gridColumnOrder.size() == columns.size());\r
+       assert (GetColumnCount() == ((CHeaderCtrl*)(control->GetDlgItem(0)))->GetItemCount());\r
+\r
+    // o.k., apply our column ordering\r
+\r
+    control->SetColumnOrderArray (GetColumnCount(), order);\r
+}\r
+\r
+// utilities used when writing data to the registry\r
+\r
+DWORD CGitStatusListCtrl::ColumnManager::GetSelectedStandardColumns() const\r
+{\r
+    DWORD result = 0;\r
+    for (size_t i = SVNSLC_NUMCOLUMNS; i > 0; --i)\r
+        result = result * 2 + (columns[i-1].visible ? 1 : 0);\r
+\r
+    return result;\r
+}\r
+\r
+CString CGitStatusListCtrl::ColumnManager::GetUserPropList() const\r
+{\r
+    CString result;\r
+\r
+    for (size_t i = 0, count = userProps.size(); i < count; ++i)\r
+        result += userProps[i].name + _T(' ');\r
+\r
+    return result;\r
+}\r
+\r
+CString CGitStatusListCtrl::ColumnManager::GetShownUserProps() const\r
+{\r
+    CString result;\r
+\r
+    for (size_t i = 0, count = columns.size(); i < count; ++i)\r
+    {\r
+        size_t index = static_cast<size_t>(columns[i].index);\r
+        if (columns[i].visible && (index >= SVNSLC_USERPROPCOLOFFSET))\r
+            result += userProps[index - SVNSLC_USERPROPCOLOFFSET].name \r
+                    + _T(' ');\r
+    }\r
+\r
+    return result;\r
+}\r
+\r
+CString CGitStatusListCtrl::ColumnManager::GetWidthString() const\r
+{\r
+    CString result;\r
+\r
+    // regular columns\r
+\r
+       TCHAR buf[10];\r
+    for (size_t i = 0; i < SVNSLC_NUMCOLUMNS; ++i)\r
+       {\r
+               _stprintf_s (buf, 10, _T("%08X"), columns[i].width);\r
+               result += buf;\r
+       }\r
+\r
+    // range with no column IDs\r
+\r
+    result += CString ('0', 8 * (SVNSLC_USERPROPCOLOFFSET - SVNSLC_NUMCOLUMNS));\r
+\r
+    // user-prop columns\r
+\r
+    for (size_t i = 0, count = userProps.size(); i < count; ++i)\r
+       {\r
+               _stprintf_s (buf, 10, _T("%08X"), userProps[i].width);\r
+               result += buf;\r
+       }\r
+\r
+    return result;\r
+}\r
+\r
+CString CGitStatusListCtrl::ColumnManager::GetColumnOrderString() const\r
+{\r
+    CString result;\r
+\r
+       TCHAR buf[3];\r
+    for (size_t i = 0, count = columnOrder.size(); i < count; ++i)\r
+       {\r
+               _stprintf_s (buf, 3, _T("%02X"), columnOrder[i]);\r
+               result += buf;\r
+       }\r
+\r
+    return result;\r
+}\r
+\r
+// sorter utility class\r
+\r
+CGitStatusListCtrl::CSorter::CSorter ( ColumnManager* columnManager\r
+                                                                         , int sortedColumn\r
+                                                                         , bool ascending)\r
+                                                                         : columnManager (columnManager)\r
+                                                                         , sortedColumn (sortedColumn)\r
+                                                                         , ascending (ascending)\r
+{\r
+}\r
+\r
+bool CGitStatusListCtrl::CSorter::operator()\r
+( const FileEntry* entry1\r
+ , const FileEntry* entry2) const\r
+{\r
+#define SGN(x) ((x)==0?0:((x)>0?1:-1))\r
+\r
+       int result = 0;\r
+       switch (sortedColumn)\r
+       {\r
+       case 18:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               __int64 writetime1 = entry1->GetPath().GetLastWriteTime();\r
+                               __int64 writetime2 = entry2->GetPath().GetLastWriteTime();\r
+\r
+                               FILETIME* filetime1 = (FILETIME*)(__int64*)&writetime1;\r
+                               FILETIME* filetime2 = (FILETIME*)(__int64*)&writetime2;\r
+\r
+                               result = CompareFileTime(filetime1,filetime2);\r
+                       }\r
+               }\r
+       case 17:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->copyfrom_url.CompareNoCase(entry2->copyfrom_url);\r
+                       }\r
+               }\r
+       case 16:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = SGN(entry1->needslock - entry2->needslock);\r
+                       }\r
+               }\r
+       case 15:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = SGN(entry1->last_commit_date - entry2->last_commit_date);\r
+                       }\r
+               }\r
+       case 14:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->remoterev - entry2->remoterev;\r
+                       }\r
+               }\r
+       case 13:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->last_commit_rev - entry2->last_commit_rev;\r
+                       }\r
+               }\r
+       case 12:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->last_commit_author.CompareNoCase(entry2->last_commit_author);\r
+                       }\r
+               }\r
+       case 11:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->lock_comment.CompareNoCase(entry2->lock_comment);\r
+                       }\r
+               }\r
+       case 10:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->lock_owner.CompareNoCase(entry2->lock_owner);\r
+                       }\r
+               }\r
+       case 9:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->url.CompareNoCase(entry2->url);\r
+                       }\r
+               }\r
+       case 8:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->remotepropstatus - entry2->remotepropstatus;\r
+                       }\r
+               }\r
+       case 7:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->remotetextstatus - entry2->remotetextstatus;\r
+                       }\r
+               }\r
+       case 6:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->propstatus - entry2->propstatus;\r
+                       }\r
+               }\r
+       case 5:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+//                             result = entry1->textstatus - entry2->textstatus;\r
+                       }\r
+               }\r
+       case 4:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+       //                      result = entry1->remotestatus - entry2->remotestatus;\r
+                       }\r
+               }\r
+       case 3:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->status - entry2->status;\r
+                       }\r
+               }\r
+       case 2:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->path.GetFileExtension().CompareNoCase(entry2->path.GetFileExtension());\r
+                       }\r
+               }\r
+       case 1:\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = entry1->path.GetFileOrDirectoryName().CompareNoCase(entry2->path.GetFileOrDirectoryName());\r
+                       }\r
+               }\r
+       case 0:         // path column\r
+               {\r
+                       if (result == 0)\r
+                       {\r
+                               result = CTGitPath::Compare(entry1->path, entry2->path);\r
+                       }\r
+               }\r
+       default:\r
+               if ((result == 0) && (sortedColumn > 0))\r
+               {\r
+                       // N/A props are "less than" empty props\r
+\r
+                       const CString& propName = columnManager->GetName (sortedColumn);\r
+\r
+//                     bool entry1HasProp = entry1->present_props.HasProperty (propName);\r
+//                     bool entry2HasProp = entry2->present_props.HasProperty (propName);\r
+\r
+//                     if (entry1HasProp)\r
+//                     {\r
+//                             result = entry2HasProp\r
+//                                     ? entry1->present_props[propName].Compare \r
+//                                     (entry2->present_props[propName])\r
+//                                     : 1;\r
+//                     }\r
+//                     else\r
+//                     {\r
+//                             result = entry2HasProp ? -1 : 0;\r
+//                     }\r
+               }\r
+       } // switch (m_nSortedColumn)\r
+       if (!ascending)\r
+               result = -result;\r
+\r
+       return result < 0;\r
+}\r
index 04651d7..d2dd044 100644 (file)
@@ -21,7 +21,7 @@
 #include "StandAloneDlg.h"\r
 #include "SciEdit.h"\r
 #include "ProjectProperties.h"\r
-\r
+#include "resource.h"\r
 /**\r
  * \ingroup TortoiseProc\r
  * Helper dialog to ask for various text inputs.\r
index 5c62f76..31556cf 100644 (file)
@@ -1,6 +1,6 @@
-// TortoiseSVN - a Windows shell extension for easy version control\r
+// TortoiseGit - a Windows shell extension for easy version control\r
 \r
-// Copyright (C) 2003-2008 - TortoiseSVN\r
+// Copyright (C) 2003-2008 - TortoiseGit\r
 \r
 // This program is free software; you can redistribute it and/or\r
 // modify it under the terms of the GNU General Public License\r
 #pragma once\r
 \r
 #include "resource.h"\r
-#include "svn.h"\r
+#include "Git.h"\r
 #include "ProjectProperties.h"\r
 #include "StandAloneDlg.h"\r
-#include "TSVNPath.h"\r
+#include "TGitPath.h"\r
 #include "registry.h"\r
 #include "SplitterControl.h"\r
 #include "Colors.h"\r
 #include "MenuButton.h"\r
 #include "LogDlgHelper.h"\r
 #include "FilterEdit.h"\r
-#include "SVNRev.h"\r
+#include "GitRev.h"\r
 #include "Tooltip.h"\r
 #include "HintListCtrl.h"\r
 \r
@@ -59,7 +59,7 @@ typedef int (__cdecl *GENERICCOMPAREFN)(const void * elem1, const void * elem2);
  * \ingroup TortoiseProc\r
  * Shows log messages of a single file or folder in a listbox. \r
  */\r
-class CLogDlg : public CResizableStandAloneDialog, public SVN, IFilterEditValidator\r
+class CLogDlg : public CResizableStandAloneDialog, public Git, IFilterEditValidator\r
 {\r
        DECLARE_DYNAMIC(CLogDlg)\r
        \r
@@ -70,23 +70,23 @@ public:
        virtual ~CLogDlg();\r
 \r
 \r
-       void SetParams(const CTSVNPath& path, SVNRev pegrev, SVNRev startrev, SVNRev endrev, int limit, \r
-               BOOL bStrict = CRegDWORD(_T("Software\\TortoiseSVN\\LastLogStrict"), FALSE), BOOL bSaveStrict = TRUE);\r
+       void SetParams(const CTGitPath& path, GitRev pegrev, GitRev startrev, GitRev endrev, int limit, \r
+               BOOL bStrict = CRegDWORD(_T("Software\\TortoiseGit\\LastLogStrict"), FALSE), BOOL bSaveStrict = TRUE);\r
        void SetIncludeMerge(bool bInclude = true) {m_bIncludeMerges = bInclude;}\r
-       void SetProjectPropertiesPath(const CTSVNPath& path) {m_ProjectProperties.ReadProps(path);}\r
+       void SetProjectPropertiesPath(const CTGitPath& path) {m_ProjectProperties.ReadProps(path);}\r
        bool IsThreadRunning() {return !!m_bThreadRunning;}\r
        void SetDialogTitle(const CString& sTitle) {m_sTitle = sTitle;}\r
        void SetSelect(bool bSelect) {m_bSelect = bSelect;}\r
        void ContinuousSelection(bool bCont = true) {m_bSelectionMustBeContinuous = bCont;}\r
-       void SetMergePath(const CTSVNPath& mergepath) {m_mergePath = mergepath;}\r
+       void SetMergePath(const CTGitPath& mergepath) {m_mergePath = mergepath;}\r
 \r
-       const SVNRevRangeArray& GetSelectedRevRanges() {return m_selectedRevs;}\r
+       const GitRevRangeArray& GetSelectedRevRanges() {return m_selectedRevs;}\r
 \r
 // Dialog Data\r
        enum { IDD = IDD_LOGMESSAGE };\r
 \r
 protected:\r
-       //implement the virtual methods from SVN base class\r
+       //implement the virtual methods from Git base class\r
        virtual BOOL Log(svn_revnum_t rev, const CString& author, const CString& date, const CString& message, LogChangedPathArray * cpaths, apr_time_t time, int filechanges, BOOL copies, DWORD actions, BOOL haschildren);\r
        virtual BOOL Cancel();\r
        virtual bool Validate(LPCTSTR string);\r
@@ -155,7 +155,7 @@ private:
        BOOL IsEntryInDateRange(int i);\r
        void CopySelectionToClipBoard();\r
        void CopyChangedSelectionToClipBoard();\r
-       CTSVNPathList GetChangedPathsFromSelectedRevisions(bool bRelativePaths = false, bool bUseFilter = true);\r
+       CTGitPathList GetChangedPathsFromSelectedRevisions(bool bRelativePaths = false, bool bUseFilter = true);\r
     void SortShownListArray();\r
        void RecalculateShownList(CPtrArray * pShownlist);\r
     void SetSortArrow(CListCtrl * control, int nColumn, bool bAscending);\r
@@ -203,15 +203,15 @@ private:
        CFilterEdit                     m_cFilter;\r
        CProgressCtrl           m_LogProgress;\r
        CMenuButton                     m_btnShow;\r
-       CTSVNPath                       m_path;\r
-       CTSVNPath                       m_mergePath;\r
-       SVNRev                          m_pegrev;\r
-       SVNRev                          m_startrev;\r
-       SVNRev                          m_LogRevision;\r
-       SVNRev                          m_endrev;\r
-       SVNRev                          m_wcRev;\r
-       SVNRevRangeArray        m_selectedRevs;\r
-       SVNRevRangeArray        m_selectedRevsOneRange;\r
+       CTGitPath                       m_path;\r
+       CTGitPath                       m_mergePath;\r
+       GitRev                          m_pegrev;\r
+       GitRev                          m_startrev;\r
+       GitRev                          m_LogRevision;\r
+       GitRev                          m_endrev;\r
+       GitRev                          m_wcRev;\r
+       GitRevRangeArray        m_selectedRevs;\r
+       GitRevRangeArray        m_selectedRevsOneRange;\r
        bool                            m_bSelectionMustBeContinuous;\r
        long                            m_logcounter;\r
        bool                            m_bCancelled;\r
@@ -223,7 +223,7 @@ private:
        BOOL                            m_bSaveStrict;\r
        LogChangedPathArray * m_currentChangedArray;\r
        LogChangedPathArray m_CurrentFilteredChangedArray;\r
-       CTSVNPathList           m_currentChangedPathList;\r
+       CTGitPathList           m_currentChangedPathList;\r
        CPtrArray                       m_arShownList;\r
        bool                            m_hasWC;\r
        int                                     m_nSearchIndex;\r
@@ -282,6 +282,6 @@ private:
        CXPTheme                        theme;\r
        bool                            m_bVista;\r
 };\r
-static UINT WM_REVSELECTED = RegisterWindowMessage(_T("TORTOISESVN_REVSELECTED_MSG"));\r
-static UINT WM_REVLIST = RegisterWindowMessage(_T("TORTOISESVN_REVLIST_MSG"));\r
-static UINT WM_REVLISTONERANGE = RegisterWindowMessage(_T("TORTOISESVN_REVLISTONERANGE_MSG"));\r
+static UINT WM_REVSELECTED = RegisterWindowMessage(_T("TORTOISEGit_REVSELECTED_MSG"));\r
+static UINT WM_REVLIST = RegisterWindowMessage(_T("TORTOISEGit_REVLIST_MSG"));\r
+static UINT WM_REVLISTONERANGE = RegisterWindowMessage(_T("TORTOISEGit_REVLISTONERANGE_MSG"));\r
index 3fa16e5..7d41711 100644 (file)
@@ -1,6 +1,6 @@
-// TortoiseSVN - a Windows shell extension for easy version control\r
+// TortoiseGit - a Windows shell extension for easy version control\r
 \r
-// Copyright (C) 2003-2007 - TortoiseSVN\r
+// Copyright (C) 2003-2007 - TortoiseGit\r
 \r
 // This program is free software; you can redistribute it and/or\r
 // modify it under the terms of the GNU General Public License\r
@@ -17,7 +17,7 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
 //\r
 #pragma once\r
-#include "SVN.h"\r
+#include "Git.h"\r
 \r
 class CLogDlg;\r
 \r
@@ -42,7 +42,7 @@ protected:
  */\r
 typedef struct LogEntryData\r
 {   \r
-       svn_revnum_t Rev;\r
+       git_revnum_t Rev;\r
        __time64_t tmDate;\r
        CString sDate;\r
        CString sAuthor;\r
index bd58aa0..5984023 100644 (file)
@@ -18,7 +18,7 @@
 //\r
 #pragma once\r
 \r
-#include "SVNRev.h"\r
+#include "GitRev.h"\r
 #include "HistoryCombo.h"\r
 #include "Tooltip.h"\r
 #include "XPImageButton.h"\r
@@ -32,7 +32,7 @@ class CRepositoryTree;
 class IRepo\r
 {\r
 public:\r
-       virtual bool ChangeToUrl(CString& url, SVNRev& rev, bool bAlreadyChecked) = 0;\r
+       virtual bool ChangeToUrl(CString& url, GitRev& rev, bool bAlreadyChecked) = 0;\r
        virtual CString GetRepoRoot() = 0;\r
 };\r
 \r
@@ -63,7 +63,7 @@ public:
        /**\r
         * Show the given \a svn_url in the URL combo and the revision button.\r
         */\r
-       void ShowUrl(const CString& url, SVNRev rev);\r
+       void ShowUrl(const CString& url, GitRev rev);\r
 \r
        /**\r
         * Show the given \a svn_url in the URL combo and the revision button,\r
@@ -71,7 +71,7 @@ public:
         * is given, the current values are used (which effectively refreshes\r
         * the tree).\r
         */\r
-       void GotoUrl(const CString& url = CString(), SVNRev rev = SVNRev(), bool bAlreadyChecked = false);\r
+       void GotoUrl(const CString& url = CString(), GitRev rev = GitRev(), bool bAlreadyChecked = false);\r
 \r
        /**\r
         * Returns the current URL.\r
@@ -81,7 +81,7 @@ public:
        /**\r
         * Returns the current revision\r
         */\r
-       SVNRev GetCurrentRev() const;\r
+       GitRev GetCurrentRev() const;\r
 \r
        /**\r
         * Saves the URL history of the HistoryCombo.\r
@@ -91,13 +91,13 @@ public:
        /**\r
         * Set the revision\r
         */\r
-       void SetRevision(SVNRev rev);\r
+       void SetRevision(GitRev rev);\r
 \r
        void SetFocusToURL();\r
 \r
        void SetIRepo(IRepo * pRepo) {m_pRepo = pRepo;}\r
 \r
-       void SetHeadRevision(const SVNRev& rev) {m_headRev = rev;}\r
+       void SetHeadRevision(const GitRev& rev) {m_headRev = rev;}\r
        afx_msg void OnGoUp();\r
 protected:\r
        virtual BOOL PreTranslateMessage(MSG* pMsg);\r
@@ -109,7 +109,7 @@ protected:
 \r
 private:\r
        CString m_url;\r
-       SVNRev m_rev;\r
+       GitRev m_rev;\r
 \r
        IRepo * m_pRepo;\r
 \r
@@ -124,7 +124,7 @@ private:
        CButton m_btnRevision;\r
        CXPImageButton m_btnUp;\r
 \r
-       SVNRev  m_headRev;\r
+       GitRev  m_headRev;\r
        CToolTips m_tooltips;\r
        HICON   m_UpIcon;\r
 };\r
index 258aed7..96534b0 100644 (file)
@@ -22,7 +22,7 @@
 #include <deque>\r
 \r
 #include "resource.h"\r
-#include "TSVNPath.h"\r
+#include "TGitPath.h"\r
 #include "RepositoryBar.h"\r
 #include "StandAloneDlg.h"\r
 #include "ProjectProperties.h"\r
index 11c91ec..acbef18 100644 (file)
@@ -32,6 +32,7 @@
 //#include "SoundUtils.h"\r
 //#include "SVN.h"\r
 #include "GitAdminDir.h"\r
+#include "Git.h"\r
 //#include "SVNGlobal.h"\r
 //#include "svn_types.h"\r
 //#include "svn_dso.h"\r
@@ -73,6 +74,8 @@ CTortoiseProcApp::CTortoiseProcApp()
        m_bLoadUserToolbars = FALSE;\r
        m_bSaveState = FALSE;\r
        retSuccess = false;\r
+       CGit git;\r
+       git.GetUserName();\r
 }\r
 \r
 CTortoiseProcApp::~CTortoiseProcApp()\r
index 79a06b2..0d1ecee 100644 (file)
                        <Filter\r
                                Name="General"\r
                                >\r
+                               <File\r
+                                       RelativePath=".\AppUtils.cpp"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Colors.cpp"\r
+                                       >\r
+                               </File>\r
                        </Filter>\r
                        <Filter\r
                                Name="UI"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\copy.ico"\r
+                               RelativePath=".\copy.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\copy.ico"\r
+                               RelativePath="..\Resources\copy.ico"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\explorer.ico"\r
+                               RelativePath=".\explorer.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\explorer.ico"\r
+                               RelativePath="..\Resources\explorer.ico"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\newfolder.ico"\r
+                               RelativePath="..\Resources\newfolder.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\newfolder.ico"\r
+                               RelativePath=".\newfolder.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\open.ico"\r
+                               RelativePath="..\Resources\open.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\open.ico"\r
+                               RelativePath=".\open.ico"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\refresh.ico"\r
+                               RelativePath=".\refresh.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\refresh.ico"\r
+                               RelativePath="..\Resources\refresh.ico"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\save.ico"\r
+                               RelativePath=".\save.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\save.ico"\r
+                               RelativePath="..\Resources\save.ico"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\up.ico"\r
+                               RelativePath="..\Resources\up.ico"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\Resources\up.ico"\r
+                               RelativePath=".\up.ico"\r
                                >\r
                        </File>\r
                        <File\r
                        Name="Utility Dialogs"\r
                        >\r
                </Filter>\r
+               <Filter\r
+                       Name="Git"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\Git\GitStatusListCtrl.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\Git\GitStatusListCtrl.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\GitStatusListCtrlHelpers.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
                <File\r
                        RelativePath="Resource.h"\r
                        >\r
index fd8c50d..5d52142 100644 (file)
Binary files a/TortoiseShell/TortoiseShell.suo and b/TortoiseShell/TortoiseShell.suo differ
index e754b29..22f497e 100644 (file)
@@ -41,10 +41,10 @@ public:
         * \param path         if set, the temp file will have the same file extension\r
         *                     as this path.\r
         */\r
-       CTSVNPath               GetTempFilePath(bool bRemoveAtEnd, const CTSVNPath& path = CTSVNPath(), const SVNRev revision = SVNRev());\r
+       CTGitPath               GetTempFilePath(bool bRemoveAtEnd, const CTGitPath& path = CTGitPath(), const GitRev revision = GitRev());\r
 \r
 private:\r
 \r
 private:\r
-       CTSVNPathList m_TempFileList;\r
+       CTGitPathList m_TempFileList;\r
 };\r
diff --git a/Utils/resource.rc b/Utils/resource.rc
new file mode 100644 (file)
index 0000000..86ca8f5
--- /dev/null
@@ -0,0 +1,93 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Chinese (P.R.C.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED\r
+#pragma code_page(936)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // Chinese (P.R.C.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDS_SCIEDIT_ADDWORD     "add word"\r
+    IDS_SCIEDIT_UNDO        "undo"\r
+    IDS_SCIEDIT_REDO        "redo"\r
+    IDS_SCIEDIT_CUT         "cut"\r
+    IDS_SCIEDIT_COPY        "copy"\r
+    IDS_SCIEDIT_PASTE       "past"\r
+    IDS_SCIEDIT_SELECTALL   "select all"\r
+    IDS_SCIEDIT_SPLITLINES  "split"\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/ext/hunspell/license.hunspell b/ext/hunspell/license.hunspell
new file mode 100644 (file)
index 0000000..8b4127a
--- /dev/null
@@ -0,0 +1,55 @@
+/* ***** BEGIN LICENSE BLOCK *****\r
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ * http://www.mozilla.org/MPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ *\r
+ * The Original Code is Hunspell, based on MySpell.\r
+ *\r
+ * The Initial Developers of the Original Code are\r
+ * Kevin Hendricks (MySpell) and Németh László (Hunspell).\r
+ * Portions created by the Initial Developers are Copyright (C) 2002-2005\r
+ * the Initial Developers. All Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * David Einstein \r
+ * Davide Prina\r
+ * Giuseppe Modugno \r
+ * Gianluca Turconi\r
+ * Simon Brouwer\r
+ * Noll János\r
+ * Bíró Árpád\r
+ * Goldman Eleonóra\r
+ * Sarlós Tamás\r
+ * Bencsáth Boldizsár\r
+ * Halácsy Péter\r
+ * Dvornik László\r
+ * Gefferth András\r
+ * Nagy Viktor\r
+ * Varga Dániel\r
+ * Chris Halls\r
+ * Rene Engelhard\r
+ * Bram Moolenaar\r
+ * Dafydd Jones\r
+ * Harri Pitkänen\r
+ *\r
+ * Alternatively, the contents of this file may be used under the terms of\r
+ * either the GNU General Public License Version 2 or later (the "GPL"), or\r
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),\r
+ * in which case the provisions of the GPL or the LGPL are applicable instead\r
+ * of those above. If you wish to allow use of your version of this file only\r
+ * under the terms of either the GPL or the LGPL, and not to allow others to\r
+ * use your version of this file under the terms of the MPL, indicate your\r
+ * decision by deleting the provisions above and replace them with the notice\r
+ * and other provisions required by the GPL or the LGPL. If you do not delete\r
+ * the provisions above, a recipient may use your version of this file under\r
+ * the terms of any one of the MPL, the GPL or the LGPL.\r
+ *\r
+ * ***** END LICENSE BLOCK ***** */\r
diff --git a/ext/hunspell/license.myspell b/ext/hunspell/license.myspell
new file mode 100644 (file)
index 0000000..de506b4
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+ * Copyright 2002 Kevin B. Hendricks, Stratford, Ontario, Canada\r
+ * And Contributors.  All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ *\r
+ * 3. All modifications to the source code must be clearly marked as\r
+ *    such.  Binary redistributions based on modified source code\r
+ *    must be clearly marked as modified versions in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY KEVIN B. HENDRICKS AND CONTRIBUTORS \r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT \r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS \r
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL \r
+ * KEVIN B. HENDRICKS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, \r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, \r
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; \r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ * SUCH DAMAGE.\r
+ *\r
+ *\r
+ * NOTE: A special thanks and credit goes to Geoff Kuenning\r
+ * the creator of ispell.  MySpell's affix algorithms were\r
+ * based on those of ispell which should be noted is\r
+ * copyright Geoff Kuenning et.al. and now available\r
+ * under a BSD style license. For more information on ispell\r
+ * and affix compression in general, please see:\r
+ * http://www.cs.ucla.edu/ficus-members/geoff/ispell.html\r
+ * (the home page for ispell)\r
+ *\r
+ * An almost complete rewrite  of MySpell for use by  \r
+ * the Mozilla project has been developed by David Einstein \r
+ * (Deinst@world.std.com).  David and I are now \r
+ * working on parallel development tracks to help \r
+ * our respective projects (Mozilla and OpenOffice.org \r
+ * and we will maintain full affix file and dictionary \r
+ * file compatibility and work on merging our versions \r
+ * of MySpell back into a single tree. David has been \r
+ * a significant help in improving MySpell.\r
+ * \r
+ * Special thanks also go to La'szlo' Ne'meth \r
+ * <nemethl@gyorsposta.hu> who is the author of the \r
+ * Hungarian dictionary and who developed and contributed \r
+ * the code to support compound words in MySpell \r
+ * and fixed numerous problems with the encoding \r
+ * case conversion tables.\r
+ *\r
+ */\r