OSDN Git Service

b2e0879dff9314b3a1faf2744eea3abfc816b999
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / CommitDlg.cpp
1 // TortoiseGit - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseGit\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "CommitDlg.h"\r
22 #include "DirFileEnum.h"\r
23 //#include "GitConfig.h"\r
24 //#include "GitProperties.h"\r
25 #include "MessageBox.h"\r
26 #include "AppUtils.h"\r
27 #include "PathUtils.h"\r
28 #include "Git.h"\r
29 #include "Registry.h"\r
30 #include "GitStatus.h"\r
31 #include "HistoryDlg.h"\r
32 #include "Hooks.h"\r
33 #include "CommonResource.h"\r
34 #include "UnicodeUtils.h"\r
35 #include "ProgressDlg.h"\r
36 #include "ShellUpdater.h"\r
37 \r
38 #ifdef _DEBUG\r
39 #define new DEBUG_NEW\r
40 #undef THIS_FILE\r
41 static char THIS_FILE[] = __FILE__;\r
42 #endif\r
43 \r
44 UINT CCommitDlg::WM_AUTOLISTREADY = RegisterWindowMessage(_T("TORTOISEGIT_AUTOLISTREADY_MSG"));\r
45 \r
46 IMPLEMENT_DYNAMIC(CCommitDlg, CResizableStandAloneDialog)\r
47 CCommitDlg::CCommitDlg(CWnd* pParent /*=NULL*/)\r
48         : CResizableStandAloneDialog(CCommitDlg::IDD, pParent)\r
49         , m_bRecursive(FALSE)\r
50         , m_bShowUnversioned(FALSE)\r
51         , m_bBlock(FALSE)\r
52         , m_bThreadRunning(FALSE)\r
53         , m_bRunThread(FALSE)\r
54         , m_pThread(NULL)\r
55         , m_bWholeProject(FALSE)\r
56         , m_bKeepChangeList(TRUE)\r
57         , m_itemsCount(0)\r
58         , m_bSelectFilesForCommit(TRUE)\r
59 {\r
60 }\r
61 \r
62 CCommitDlg::~CCommitDlg()\r
63 {\r
64         if(m_pThread != NULL)\r
65         {\r
66                 delete m_pThread;\r
67         }\r
68 }\r
69 \r
70 void CCommitDlg::DoDataExchange(CDataExchange* pDX)\r
71 {\r
72         CResizableStandAloneDialog::DoDataExchange(pDX);\r
73         DDX_Control(pDX, IDC_FILELIST, m_ListCtrl);\r
74         DDX_Control(pDX, IDC_LOGMESSAGE, m_cLogMessage);\r
75         DDX_Check(pDX, IDC_SHOWUNVERSIONED, m_bShowUnversioned);\r
76         DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);\r
77         DDX_Text(pDX, IDC_BUGID, m_sBugID);\r
78         DDX_Check(pDX, IDC_WHOLE_PROJECT, m_bWholeProject);\r
79         DDX_Control(pDX, IDC_SPLITTER, m_wndSplitter);\r
80         DDX_Check(pDX, IDC_KEEPLISTS, m_bKeepChangeList);\r
81         DDX_Check(pDX,IDC_COMMIT_AMEND,m_bCommitAmend);\r
82 }\r
83 \r
84 BEGIN_MESSAGE_MAP(CCommitDlg, CResizableStandAloneDialog)\r
85         ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)\r
86         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
87         ON_BN_CLICKED(IDC_SHOWUNVERSIONED, OnBnClickedShowunversioned)\r
88 //      ON_BN_CLICKED(IDC_HISTORY, OnBnClickedHistory)\r
89         ON_BN_CLICKED(IDC_BUGTRAQBUTTON, OnBnClickedBugtraqbutton)\r
90         ON_EN_CHANGE(IDC_LOGMESSAGE, OnEnChangeLogmessage)\r
91         ON_REGISTERED_MESSAGE(CGitStatusListCtrl::SVNSLNM_ITEMCOUNTCHANGED, OnGitStatusListCtrlItemCountChanged)\r
92         ON_REGISTERED_MESSAGE(CGitStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnGitStatusListCtrlNeedsRefresh)\r
93         ON_REGISTERED_MESSAGE(CGitStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)\r
94         ON_REGISTERED_MESSAGE(CGitStatusListCtrl::SVNSLNM_CHECKCHANGED, &CCommitDlg::OnGitStatusListCtrlCheckChanged)\r
95         ON_REGISTERED_MESSAGE(WM_AUTOLISTREADY, OnAutoListReady) \r
96         ON_WM_TIMER()\r
97     ON_WM_SIZE()\r
98         ON_STN_CLICKED(IDC_EXTERNALWARNING, &CCommitDlg::OnStnClickedExternalwarning)\r
99         ON_BN_CLICKED(IDC_SIGNOFF, &CCommitDlg::OnBnClickedSignOff)\r
100         ON_STN_CLICKED(IDC_COMMITLABEL, &CCommitDlg::OnStnClickedCommitlabel)\r
101     ON_BN_CLICKED(IDC_COMMIT_AMEND, &CCommitDlg::OnBnClickedCommitAmend)\r
102     ON_BN_CLICKED(IDC_WHOLE_PROJECT, &CCommitDlg::OnBnClickedWholeProject)\r
103 END_MESSAGE_MAP()\r
104 \r
105 BOOL CCommitDlg::OnInitDialog()\r
106 {\r
107         CResizableStandAloneDialog::OnInitDialog();\r
108         \r
109         m_regAddBeforeCommit = CRegDWORD(_T("Software\\TortoiseGit\\AddBeforeCommit"), TRUE);\r
110         m_bShowUnversioned = m_regAddBeforeCommit;\r
111 \r
112         m_History.SetMaxHistoryItems((LONG)CRegDWORD(_T("Software\\TortoiseGit\\MaxHistoryItems"), 25));\r
113 \r
114         m_regKeepChangelists = CRegDWORD(_T("Software\\TortoiseGit\\KeepChangeLists"), FALSE);\r
115         m_bKeepChangeList = m_regKeepChangelists;\r
116 \r
117 //      GitConfig config;\r
118 //      m_bWholeProject = config.KeepLocks();\r
119 \r
120         UpdateData(FALSE);\r
121         \r
122         m_ListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLSTATUS , _T("CommitDlg"));\r
123         m_ListCtrl.SetSelectButton(&m_SelectAll);\r
124         m_ListCtrl.SetStatLabel(GetDlgItem(IDC_STATISTICS));\r
125         m_ListCtrl.SetCancelBool(&m_bCancelled);\r
126         m_ListCtrl.SetEmptyString(IDS_COMMITDLG_NOTHINGTOCOMMIT);\r
127         m_ListCtrl.EnableFileDrop();\r
128         m_ListCtrl.SetBackgroundImage(IDI_COMMIT_BKG);\r
129         \r
130         //this->DialogEnableWindow(IDC_COMMIT_AMEND,FALSE);\r
131 //      m_ProjectProperties.ReadPropsPathList(m_pathList);\r
132         m_cLogMessage.Init(m_ProjectProperties);\r
133         m_cLogMessage.SetFont((CString)CRegString(_T("Software\\TortoiseGit\\LogFontName"), _T("Courier New")), (DWORD)CRegDWORD(_T("Software\\TortoiseGit\\LogFontSize"), 8));\r
134         m_cLogMessage.RegisterContextMenuHandler(this);\r
135 \r
136         OnEnChangeLogmessage();\r
137 \r
138         m_tooltips.Create(this);\r
139         m_tooltips.AddTool(IDC_EXTERNALWARNING, IDS_COMMITDLG_EXTERNALS);\r
140         m_tooltips.AddTool(IDC_COMMIT_AMEND,IDS_COMMIT_AMEND_TT);\r
141 //      m_tooltips.AddTool(IDC_HISTORY, IDS_COMMITDLG_HISTORY_TT);\r
142         \r
143         m_SelectAll.SetCheck(BST_INDETERMINATE);\r
144 \r
145 #if 0\r
146         CBugTraqAssociations bugtraq_associations;\r
147         bugtraq_associations.Load();\r
148 \r
149         if (bugtraq_associations.FindProvider(m_pathList, &m_bugtraq_association))\r
150         {\r
151                 GetDlgItem(IDC_BUGID)->ShowWindow(SW_HIDE);\r
152                 GetDlgItem(IDC_BUGIDLABEL)->ShowWindow(SW_HIDE);\r
153 \r
154                 CComPtr<IBugTraqProvider> pProvider;\r
155                 HRESULT hr = pProvider.CoCreateInstance(m_bugtraq_association.GetProviderClass());\r
156                 if (SUCCEEDED(hr))\r
157                 {\r
158                         m_BugTraqProvider = pProvider;\r
159                         BSTR temp = NULL;\r
160                         if (SUCCEEDED(hr = pProvider->GetLinkText(GetSafeHwnd(), m_bugtraq_association.GetParameters().AllocSysString(), &temp)))\r
161                         {\r
162                                 SetDlgItemText(IDC_BUGTRAQBUTTON, temp);\r
163                                 GetDlgItem(IDC_BUGTRAQBUTTON)->EnableWindow(TRUE);\r
164                                 GetDlgItem(IDC_BUGTRAQBUTTON)->ShowWindow(SW_SHOW);\r
165                         }\r
166 \r
167                         SysFreeString(temp);\r
168                 }\r
169 \r
170                 GetDlgItem(IDC_LOGMESSAGE)->SetFocus();\r
171         }\r
172         else if (!m_ProjectProperties.sMessage.IsEmpty())\r
173         {\r
174                 GetDlgItem(IDC_BUGID)->ShowWindow(SW_SHOW);\r
175                 GetDlgItem(IDC_BUGIDLABEL)->ShowWindow(SW_SHOW);\r
176                 if (!m_ProjectProperties.sLabel.IsEmpty())\r
177                         SetDlgItemText(IDC_BUGIDLABEL, m_ProjectProperties.sLabel);\r
178                 GetDlgItem(IDC_BUGTRAQBUTTON)->ShowWindow(SW_HIDE);\r
179                 GetDlgItem(IDC_BUGTRAQBUTTON)->EnableWindow(FALSE);\r
180                 GetDlgItem(IDC_BUGID)->SetFocus();\r
181                 CString sBugID = m_ProjectProperties.GetBugIDFromLog(m_sLogMessage);\r
182                 if (!sBugID.IsEmpty())\r
183                 {\r
184                         SetDlgItemText(IDC_BUGID, sBugID);\r
185                 }\r
186         }\r
187         else\r
188 #endif\r
189         {\r
190                 GetDlgItem(IDC_BUGID)->ShowWindow(SW_HIDE);\r
191                 GetDlgItem(IDC_BUGIDLABEL)->ShowWindow(SW_HIDE);\r
192                 GetDlgItem(IDC_BUGTRAQBUTTON)->ShowWindow(SW_HIDE);\r
193                 GetDlgItem(IDC_BUGTRAQBUTTON)->EnableWindow(FALSE);\r
194                 GetDlgItem(IDC_LOGMESSAGE)->SetFocus();\r
195         }\r
196 \r
197         if (!m_sLogMessage.IsEmpty())\r
198                 m_cLogMessage.SetText(m_sLogMessage);\r
199                 \r
200         GetWindowText(m_sWindowTitle);\r
201         \r
202         AdjustControlSize(IDC_SHOWUNVERSIONED);\r
203         AdjustControlSize(IDC_SELECTALL);\r
204         AdjustControlSize(IDC_WHOLE_PROJECT);\r
205 \r
206         GetClientRect(m_DlgOrigRect);\r
207         m_cLogMessage.GetClientRect(m_LogMsgOrigRect);\r
208 \r
209         AddAnchor(IDC_COMMITLABEL, TOP_LEFT, TOP_RIGHT);\r
210         AddAnchor(IDC_BUGIDLABEL, TOP_RIGHT);\r
211         AddAnchor(IDC_BUGID, TOP_RIGHT);\r
212         AddAnchor(IDC_BUGTRAQBUTTON, TOP_RIGHT);\r
213         AddAnchor(IDC_COMMIT_TO, TOP_LEFT, TOP_RIGHT);\r
214         AddAnchor(IDC_MESSAGEGROUP, TOP_LEFT, TOP_RIGHT);\r
215 //      AddAnchor(IDC_HISTORY, TOP_LEFT);\r
216         AddAnchor(IDC_LOGMESSAGE, TOP_LEFT, TOP_RIGHT);\r
217         AddAnchor(IDC_SIGNOFF,   TOP_RIGHT);\r
218         AddAnchor(IDC_LISTGROUP, TOP_LEFT, BOTTOM_RIGHT);\r
219         AddAnchor(IDC_SPLITTER, TOP_LEFT, TOP_RIGHT);\r
220         AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);\r
221         AddAnchor(IDC_SHOWUNVERSIONED, BOTTOM_LEFT);\r
222         AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);\r
223         AddAnchor(IDC_EXTERNALWARNING, BOTTOM_RIGHT);\r
224         AddAnchor(IDC_STATISTICS, BOTTOM_LEFT, BOTTOM_RIGHT);\r
225         AddAnchor(IDC_WHOLE_PROJECT, BOTTOM_LEFT);\r
226         AddAnchor(IDC_KEEPLISTS, BOTTOM_LEFT);\r
227         AddAnchor(IDOK, BOTTOM_RIGHT);\r
228         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
229         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
230         AddAnchor(IDC_COMMIT_AMEND,TOP_LEFT);\r
231         \r
232         if (hWndExplorer)\r
233                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
234         EnableSaveRestore(_T("CommitDlg"));\r
235         DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\CommitDlgSizer"));\r
236         RECT rcDlg, rcLogMsg, rcFileList;\r
237         GetClientRect(&rcDlg);\r
238         m_cLogMessage.GetWindowRect(&rcLogMsg);\r
239         ScreenToClient(&rcLogMsg);\r
240         m_ListCtrl.GetWindowRect(&rcFileList);\r
241         ScreenToClient(&rcFileList);\r
242         if (yPos)\r
243         {\r
244                 RECT rectSplitter;\r
245                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
246                 ScreenToClient(&rectSplitter);\r
247                 int delta = yPos - rectSplitter.top;\r
248                 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))\r
249                 {\r
250                         m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);\r
251                         DoSize(delta);\r
252                 }\r
253         }\r
254 \r
255         // add all directories to the watcher\r
256         for (int i=0; i<m_pathList.GetCount(); ++i)\r
257         {\r
258                 if (m_pathList[i].IsDirectory())\r
259                         m_pathwatcher.AddPath(m_pathList[i]);\r
260         }\r
261 \r
262         m_updatedPathList = m_pathList;\r
263 \r
264         //first start a thread to obtain the file list with the status without\r
265         //blocking the dialog\r
266         InterlockedExchange(&m_bBlock, TRUE);\r
267         m_pThread = AfxBeginThread(StatusThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
268         if (m_pThread==NULL)\r
269         {\r
270                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
271                 InterlockedExchange(&m_bBlock, FALSE);\r
272         }\r
273         else\r
274         {\r
275                 m_pThread->m_bAutoDelete = FALSE;\r
276                 m_pThread->ResumeThread();\r
277         }\r
278         CRegDWORD err = CRegDWORD(_T("Software\\TortoiseGit\\ErrorOccurred"), FALSE);\r
279         CRegDWORD historyhint = CRegDWORD(_T("Software\\TortoiseGit\\HistoryHintShown"), FALSE);\r
280         if ((((DWORD)err)!=FALSE)&&((((DWORD)historyhint)==FALSE)))\r
281         {\r
282                 historyhint = TRUE;\r
283 //              ShowBalloon(IDC_HISTORY, IDS_COMMITDLG_HISTORYHINT_TT, IDI_INFORMATION);\r
284         }\r
285         err = FALSE;\r
286 \r
287         this->UpdateData(TRUE);\r
288         this->m_bCommitAmend=FALSE;\r
289         this->UpdateData(FALSE);\r
290 \r
291         return FALSE;  // return TRUE unless you set the focus to a control\r
292         // EXCEPTION: OCX Property Pages should return FALSE\r
293 }\r
294 \r
295 void CCommitDlg::OnOK()\r
296 {\r
297         if (m_bBlock)\r
298                 return;\r
299         if (m_bThreadRunning)\r
300         {\r
301                 m_bCancelled = true;\r
302                 InterlockedExchange(&m_bRunThread, FALSE);\r
303                 WaitForSingleObject(m_pThread->m_hThread, 1000);\r
304                 if (m_bThreadRunning)\r
305                 {\r
306                         // we gave the thread a chance to quit. Since the thread didn't\r
307                         // listen to us we have to kill it.\r
308                         TerminateThread(m_pThread->m_hThread, (DWORD)-1);\r
309                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
310                 }\r
311         }\r
312         this->UpdateData();\r
313 \r
314         CString id;\r
315         GetDlgItemText(IDC_BUGID, id);\r
316         if (!m_ProjectProperties.CheckBugID(id))\r
317         {\r
318                 ShowBalloon(IDC_BUGID, IDS_COMMITDLG_ONLYNUMBERS, IDI_EXCLAMATION);\r
319                 return;\r
320         }\r
321         m_sLogMessage = m_cLogMessage.GetText();\r
322         if ( m_sLogMessage.IsEmpty() )\r
323         {\r
324                 // no message entered, go round again\r
325                 CMessageBox::Show(this->m_hWnd, IDS_COMMITDLG_NOMESSAGE, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
326                 return;\r
327         }\r
328         if ((m_ProjectProperties.bWarnIfNoIssue) && (id.IsEmpty() && !m_ProjectProperties.HasBugID(m_sLogMessage)))\r
329         {\r
330                 if (CMessageBox::Show(this->m_hWnd, IDS_COMMITDLG_NOISSUEWARNING, IDS_APPNAME, MB_YESNO | MB_ICONWARNING)!=IDYES)\r
331                         return;\r
332         }\r
333 \r
334 #if 0\r
335         CRegDWORD regUnversionedRecurse (_T("Software\\TortoiseGit\\UnversionedRecurse"), TRUE);\r
336         if (!(DWORD)regUnversionedRecurse)\r
337         {\r
338                 // Find unversioned directories which are marked for commit. The user might expect them\r
339                 // to be added recursively since he cannot the the files. Let's ask the user if he knows\r
340                 // what he is doing.\r
341                 int nListItems = m_ListCtrl.GetItemCount();\r
342                 for (int j=0; j<nListItems; j++)\r
343                 {\r
344                         const CGitStatusListCtrl::FileEntry * entry = m_ListCtrl.GetListEntry(j);\r
345                         if (entry->IsChecked() && (entry->status == Git_wc_status_unversioned) && entry->IsFolder() )\r
346                         {\r
347                                 if (CMessageBox::Show(this->m_hWnd, IDS_COMMITDLG_UNVERSIONEDFOLDERWARNING, IDS_APPNAME, MB_YESNO | MB_ICONWARNING)!=IDYES)\r
348                                         return;\r
349                         }\r
350                 }\r
351         }\r
352 #endif\r
353         m_pathwatcher.Stop();\r
354         InterlockedExchange(&m_bBlock, TRUE);\r
355         CDWordArray arDeleted;\r
356         //first add all the unversioned files the user selected\r
357         //and check if all versioned files are selected\r
358         int nchecked = 0;\r
359         m_bRecursive = true;\r
360         int nListItems = m_ListCtrl.GetItemCount();\r
361 \r
362         CTGitPathList itemsToAdd;\r
363         CTGitPathList itemsToRemove;\r
364         //std::set<CString> checkedLists;\r
365         //std::set<CString> uncheckedLists;\r
366 \r
367         //CString checkedfiles;\r
368         //CString uncheckedfiles;\r
369 \r
370         CString cmd;\r
371         CString out;\r
372 \r
373         for (int j=0; j<nListItems; j++)\r
374         {\r
375                 //const CGitStatusListCtrl::FileEntry * entry = m_ListCtrl.GetListEntry(j);\r
376                 CTGitPath *entry = (CTGitPath*)m_ListCtrl.GetItemData(j);\r
377                 if (entry->m_Checked)\r
378                 {\r
379 #if 0\r
380                         if (entry->status == Git_wc_status_unversioned)\r
381                         {\r
382                                 itemsToAdd.AddPath(entry->GetPath());\r
383                         }\r
384                         if (entry->status == Git_wc_status_conflicted)\r
385                         {\r
386                                 bHasConflicted = true;\r
387                         }\r
388                         if (entry->status == Git_wc_status_missing)\r
389                         {\r
390                                 itemsToRemove.AddPath(entry->GetPath());\r
391                         }\r
392                         if (entry->status == Git_wc_status_deleted)\r
393                         {\r
394                                 arDeleted.Add(j);\r
395                         }\r
396                         if (entry->IsInExternal())\r
397                         {\r
398                                 bCheckedInExternal = true;\r
399                         }\r
400 #endif\r
401                         if( entry->m_Action & CTGitPath::LOGACTIONS_UNVER)\r
402                                 cmd.Format(_T("git.exe add -f -- \"%s\""),entry->GetGitPathString());\r
403                         else if ( entry->m_Action & CTGitPath::LOGACTIONS_DELETED)\r
404                                 cmd.Format(_T("git.exe update-index --remove -- \"%s\""),entry->GetGitPathString());\r
405                         else\r
406                                 cmd.Format(_T("git.exe update-index  -- \"%s\""),entry->GetGitPathString());\r
407 \r
408                         g_Git.Run(cmd,&out,CP_OEMCP);\r
409                         nchecked++;\r
410 \r
411                         //checkedLists.insert(entry->GetGitPathString());\r
412 //                      checkedfiles += _T("\"")+entry->GetGitPathString()+_T("\" ");\r
413                 }\r
414                 else\r
415                 {\r
416                         //uncheckedLists.insert(entry->GetGitPathString());\r
417                         if(entry->m_Action & CTGitPath::LOGACTIONS_ADDED)\r
418                         {       //To init git repository, there are not HEAD, so we can use git reset command\r
419                                 cmd.Format(_T("git.exe rm --cache -- \"%s\""),entry->GetGitPathString());\r
420                                 g_Git.Run(cmd,&out,CP_OEMCP);   \r
421                         }\r
422                         else\r
423                         {\r
424                                 cmd.Format(_T("git.exe reset -- %s"),entry->GetGitPathString());\r
425                                 g_Git.Run(cmd,&out,CP_OEMCP);\r
426                         }\r
427 \r
428                 //      uncheckedfiles += _T("\"")+entry->GetGitPathString()+_T("\" ");\r
429 #if 0\r
430                         if ((entry->status != Git_wc_status_unversioned)        &&\r
431                                 (entry->status != Git_wc_status_ignored))\r
432                         {\r
433                                 nUnchecked++;\r
434                                 uncheckedLists.insert(entry->GetChangeList());\r
435                                 if (m_bRecursive)\r
436                                 {\r
437                                         // This algorithm is for the sake of simplicity of the complexity O(N?\r
438                                         for (int k=0; k<nListItems; k++)\r
439                                         {\r
440                                                 const CGitStatusListCtrl::FileEntry * entryK = m_ListCtrl.GetListEntry(k);\r
441                                                 if (entryK->IsChecked() && entryK->GetPath().IsAncestorOf(entry->GetPath())  )\r
442                                                 {\r
443                                                         // Fall back to a non-recursive commit to prevent items being\r
444                                                         // committed which aren't checked although its parent is checked\r
445                                                         // (property change, directory deletion, ... )\r
446                                                         m_bRecursive = false;\r
447                                                         break;\r
448                                                 }\r
449                                         }\r
450                                 }\r
451                         }\r
452 #endif\r
453                 }\r
454 \r
455                 CShellUpdater::Instance().AddPathForUpdate(*entry);\r
456         }\r
457 \r
458         //if(uncheckedfiles.GetLength()>0)\r
459         //{\r
460         //      cmd.Format(_T("git.exe reset -- %s"),uncheckedfiles);\r
461         //      g_Git.Run(cmd,&out);\r
462         //}\r
463 \r
464         //if(checkedfiles.GetLength()>0)\r
465         if(nchecked||m_bCommitAmend)\r
466         {\r
467         //      cmd.Format(_T("git.exe update-index -- %s"),checkedfiles);\r
468         //      g_Git.Run(cmd,&out);\r
469 \r
470                 CString tempfile=::GetTempFile();\r
471                 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );\r
472                 CStringA log=CUnicodeUtils::GetUTF8( m_sLogMessage);\r
473                 file.Write(log,log.GetLength());\r
474                 //file.WriteString(m_sLogMessage);\r
475                 file.Close();\r
476         \r
477                 out =_T("");\r
478                 CString amend;\r
479                 if(this->m_bCommitAmend)\r
480                 {\r
481                         amend=_T("--amend");\r
482                 }\r
483                 cmd.Format(_T("git.exe commit %s -F \"%s\""),amend, tempfile);\r
484                 \r
485                 CProgressDlg progress;\r
486                 progress.m_GitCmd=cmd;\r
487                 progress.m_bShowCommand = FALSE;        // don't show the commit command\r
488                 progress.m_PreText = out;                       // show any output already generated in log window\r
489                 progress.DoModal();\r
490         \r
491                 CFile::Remove(tempfile);\r
492         }else\r
493                 CMessageBox::Show(this->m_hWnd, _T("Nothing Commit"), _T("Commit Finish"), MB_OK | MB_ICONINFORMATION);\r
494 #if 0\r
495         if (m_pathwatcher.GetNumberOfChangedPaths() && m_bRecursive)\r
496         {\r
497                 // There are paths which got changed (touched at least).\r
498                 // We have to find out if this affects the selection in the commit dialog\r
499                 // If it could affect the selection, revert back to a non-recursive commit\r
500                 CTGitPathList changedList = m_pathwatcher.GetChangedPaths();\r
501                 changedList.RemoveDuplicates();\r
502                 for (int i=0; i<changedList.GetCount(); ++i)\r
503                 {\r
504                         if (changedList[i].IsAdminDir())\r
505                         {\r
506                                 // something inside an admin dir was changed.\r
507                                 // if it's the entries file, then we have to fully refresh because\r
508                                 // files may have been added/removed from version control\r
509                                 if ((changedList[i].GetWinPathString().Right(7).CompareNoCase(_T("entries")) == 0) &&\r
510                                         (changedList[i].GetWinPathString().Find(_T("\\tmp\\"))<0))\r
511                                 {\r
512                                         m_bRecursive = false;\r
513                                         break;\r
514                                 }\r
515                         }\r
516                         else if (!m_ListCtrl.IsPathShown(changedList[i]))\r
517                         {\r
518                                 // a path which is not shown in the list has changed\r
519                                 CGitStatusListCtrl::FileEntry * entry = m_ListCtrl.GetListEntry(changedList[i]);\r
520                                 if (entry)\r
521                                 {\r
522                                         // check if the changed path would get committed by a recursive commit\r
523                                         if ((!entry->IsFromDifferentRepository()) &&\r
524                                                 (!entry->IsInExternal()) &&\r
525                                                 (!entry->IsNested()) && \r
526                                                 (!entry->IsChecked()))\r
527                                         {\r
528                                                 m_bRecursive = false;\r
529                                                 break;\r
530                                         }\r
531                                 }\r
532                         }\r
533                 }\r
534         }\r
535 \r
536 \r
537         // Now, do all the adds - make sure that the list is sorted so that parents \r
538         // are added before their children\r
539         itemsToAdd.SortByPathname();\r
540         Git Git;\r
541         if (!Git.Add(itemsToAdd, &m_ProjectProperties, Git_depth_empty, FALSE, FALSE, TRUE))\r
542         {\r
543                 CMessageBox::Show(m_hWnd, Git.GetLastErrorMessage(), _T("TortoiseGit"), MB_ICONERROR);\r
544                 InterlockedExchange(&m_bBlock, FALSE);\r
545                 Refresh();\r
546                 return;\r
547         }\r
548 \r
549         // Remove any missing items\r
550         // Not sure that this sort is really necessary - indeed, it might be better to do a reverse sort at this point\r
551         itemsToRemove.SortByPathname();\r
552         Git.Remove(itemsToRemove, TRUE);\r
553 \r
554         //the next step: find all deleted files and check if they're \r
555         //inside a deleted folder. If that's the case, then remove those\r
556         //files from the list since they'll get deleted by the parent\r
557         //folder automatically.\r
558         m_ListCtrl.Block(TRUE, FALSE);\r
559         INT_PTR nDeleted = arDeleted.GetCount();\r
560         for (INT_PTR i=0; i<arDeleted.GetCount(); i++)\r
561         {\r
562                 if (m_ListCtrl.GetCheck(arDeleted.GetAt(i)))\r
563                 {\r
564                         const CTGitPath& path = m_ListCtrl.GetListEntry(arDeleted.GetAt(i))->GetPath();\r
565                         if (path.IsDirectory())\r
566                         {\r
567                                 //now find all children of this directory\r
568                                 for (int j=0; j<arDeleted.GetCount(); j++)\r
569                                 {\r
570                                         if (i!=j)\r
571                                         {\r
572                                                 CGitStatusListCtrl::FileEntry* childEntry = m_ListCtrl.GetListEntry(arDeleted.GetAt(j));\r
573                                                 if (childEntry->IsChecked())\r
574                                                 {\r
575                                                         if (path.IsAncestorOf(childEntry->GetPath()))\r
576                                                         {\r
577                                                                 m_ListCtrl.SetEntryCheck(childEntry, arDeleted.GetAt(j), false);\r
578                                                                 nDeleted--;\r
579                                                         }\r
580                                                 }\r
581                                         }\r
582                                 }\r
583                         }\r
584                 }\r
585         } \r
586         m_ListCtrl.Block(FALSE, FALSE);\r
587 \r
588         if ((nUnchecked != 0)||(bCheckedInExternal)||(bHasConflicted)||(!m_bRecursive))\r
589         {\r
590                 //save only the files the user has checked into the temporary file\r
591                 m_ListCtrl.WriteCheckedNamesToPathList(m_pathList);\r
592         }\r
593         m_ListCtrl.WriteCheckedNamesToPathList(m_selectedPathList);\r
594         // the item count is used in the progress dialog to show the overall commit\r
595         // progress.\r
596         // deleted items only send one notification event, all others send two\r
597         m_itemsCount = ((m_selectedPathList.GetCount() - nDeleted - itemsToRemove.GetCount()) * 2) + nDeleted + itemsToRemove.GetCount();\r
598 \r
599         if ((m_bRecursive)&&(checkedLists.size() == 1))\r
600         {\r
601                 // all checked items belong to the same changelist\r
602                 // find out if there are any unchecked items which belong to that changelist\r
603                 if (uncheckedLists.find(*checkedLists.begin()) == uncheckedLists.end())\r
604                         m_sChangeList = *checkedLists.begin();\r
605         }\r
606 #endif\r
607         UpdateData();\r
608         m_regAddBeforeCommit = m_bShowUnversioned;\r
609         if (!GetDlgItem(IDC_WHOLE_PROJECT)->IsWindowEnabled())\r
610                 m_bWholeProject = FALSE;\r
611         m_regKeepChangelists = m_bKeepChangeList;\r
612         if (!GetDlgItem(IDC_KEEPLISTS)->IsWindowEnabled())\r
613                 m_bKeepChangeList = FALSE;\r
614         InterlockedExchange(&m_bBlock, FALSE);\r
615         m_sBugID.Trim();\r
616         if (!m_sBugID.IsEmpty())\r
617         {\r
618                 m_sBugID.Replace(_T(", "), _T(","));\r
619                 m_sBugID.Replace(_T(" ,"), _T(","));\r
620                 CString sBugID = m_ProjectProperties.sMessage;\r
621                 sBugID.Replace(_T("%BUGID%"), m_sBugID);\r
622                 if (m_ProjectProperties.bAppend)\r
623                         m_sLogMessage += _T("\n") + sBugID + _T("\n");\r
624                 else\r
625                         m_sLogMessage = sBugID + _T("\n") + m_sLogMessage;\r
626         }\r
627         m_History.AddEntry(m_sLogMessage);\r
628         m_History.Save();\r
629 \r
630         SaveSplitterPos();\r
631 \r
632         CResizableStandAloneDialog::OnOK();\r
633 \r
634         CShellUpdater::Instance().Flush();\r
635 }\r
636 \r
637 void CCommitDlg::SaveSplitterPos()\r
638 {\r
639         if (!IsIconic())\r
640         {\r
641                 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\CommitDlgSizer"));\r
642                 RECT rectSplitter;\r
643                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
644                 ScreenToClient(&rectSplitter);\r
645                 regPos = rectSplitter.top;\r
646         }\r
647 }\r
648 \r
649 UINT CCommitDlg::StatusThreadEntry(LPVOID pVoid)\r
650 {\r
651         return ((CCommitDlg*)pVoid)->StatusThread();\r
652 }\r
653 \r
654 UINT CCommitDlg::StatusThread()\r
655 {\r
656         //get the status of all selected file/folders recursively\r
657         //and show the ones which have to be committed to the user\r
658         //in a list control. \r
659         InterlockedExchange(&m_bBlock, TRUE);\r
660         InterlockedExchange(&m_bThreadRunning, TRUE);// so the main thread knows that this thread is still running\r
661         InterlockedExchange(&m_bRunThread, TRUE);       // if this is set to FALSE, the thread should stop\r
662         m_bCancelled = false;\r
663 \r
664         DialogEnableWindow(IDOK, false);\r
665         DialogEnableWindow(IDC_SHOWUNVERSIONED, false);\r
666     DialogEnableWindow(IDC_WHOLE_PROJECT, false);\r
667         DialogEnableWindow(IDC_SELECTALL, false);\r
668         GetDlgItem(IDC_EXTERNALWARNING)->ShowWindow(SW_HIDE);\r
669         DialogEnableWindow(IDC_EXTERNALWARNING, false);\r
670     // read the list of recent log entries before querying the WC for status\r
671     // -> the user may select one and modify / update it while we are crawling the WC\r
672 #if 0\r
673         if (m_History.GetCount()==0)\r
674         {\r
675                 CString reg;\r
676                 if (m_ListCtrl.m_sUUID.IsEmpty() && m_pathList.GetCount()>0)\r
677                 {\r
678                         Git Git;\r
679                         reg.Format(_T("Software\\TortoiseGit\\History\\commit%s"), (LPCTSTR)Git.GetUUIDFromPath(m_pathList[0]));\r
680                 }\r
681                 else\r
682                         reg.Format(_T("Software\\TortoiseGit\\History\\commit%s"), (LPCTSTR)m_ListCtrl.m_sUUID);\r
683                 m_History.Load(reg, _T("logmsgs"));\r
684         }\r
685 #endif\r
686     // Initialise the list control with the status of the files/folders below us\r
687         m_ListCtrl.Clear();\r
688         BOOL success;\r
689     if(m_bWholeProject)\r
690         success=m_ListCtrl.GetStatus(NULL);\r
691     else\r
692         success=m_ListCtrl.GetStatus(&m_pathList);\r
693 \r
694         //m_ListCtrl.UpdateFileList(git_revnum_t(GIT_REV_ZERO));\r
695         if(this->m_bShowUnversioned)\r
696                 m_ListCtrl.UpdateFileList(CGitStatusListCtrl::FILELIST_UNVER,true,&m_pathList);\r
697         \r
698         m_ListCtrl.CheckIfChangelistsArePresent(false);\r
699 \r
700         DWORD dwShow = SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS | SVNSLC_SHOWLOCKS | SVNSLC_SHOWINCHANGELIST;\r
701         dwShow |= DWORD(m_regAddBeforeCommit) ? SVNSLC_SHOWUNVERSIONED : 0;\r
702         if (success)\r
703         {\r
704                 if (m_checkedPathList.GetCount())\r
705                         m_ListCtrl.Show(dwShow, m_checkedPathList);\r
706                 else\r
707                 {\r
708                         DWORD dwCheck = m_bSelectFilesForCommit ? dwShow : 0;\r
709                         dwCheck &=~(CTGitPath::LOGACTIONS_UNVER); //don't check unversion file default. \r
710                         m_ListCtrl.Show(dwShow, dwCheck);\r
711                         m_bSelectFilesForCommit = true;\r
712                 }\r
713 \r
714                 if (m_ListCtrl.HasExternalsFromDifferentRepos())\r
715                 {\r
716                         GetDlgItem(IDC_EXTERNALWARNING)->ShowWindow(SW_SHOW);\r
717                         DialogEnableWindow(IDC_EXTERNALWARNING, TRUE);\r
718                 }\r
719                 \r
720                 SetDlgItemText(IDC_COMMIT_TO, g_Git.GetCurrentBranch());\r
721                 m_tooltips.AddTool(GetDlgItem(IDC_STATISTICS), m_ListCtrl.GetStatisticsString());\r
722         }\r
723         CString logmsg;\r
724         GetDlgItemText(IDC_LOGMESSAGE, logmsg);\r
725         DialogEnableWindow(IDOK, logmsg.GetLength() >= m_ProjectProperties.nMinLogSize);\r
726         if (!success)\r
727         {\r
728                 if (!m_ListCtrl.GetLastErrorMessage().IsEmpty())\r
729                         m_ListCtrl.SetEmptyString(m_ListCtrl.GetLastErrorMessage());\r
730                 m_ListCtrl.Show(dwShow);\r
731         }\r
732         if ((m_ListCtrl.GetItemCount()==0)&&(m_ListCtrl.HasUnversionedItems()))\r
733         {\r
734                 if (CMessageBox::Show(m_hWnd, IDS_COMMITDLG_NOTHINGTOCOMMITUNVERSIONED, IDS_APPNAME, MB_ICONINFORMATION | MB_YESNO)==IDYES)\r
735                 {\r
736                         m_bShowUnversioned = TRUE;\r
737                         GetDlgItem(IDC_SHOWUNVERSIONED)->SendMessage(BM_SETCHECK, BST_CHECKED);\r
738                         DWORD dwShow = (DWORD)(SVNSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS | SVNSLC_SHOWUNVERSIONED | SVNSLC_SHOWLOCKS);\r
739                         m_ListCtrl.UpdateFileList(CGitStatusListCtrl::FILELIST_UNVER);\r
740                         m_ListCtrl.Show(dwShow,dwShow&(~CTGitPath::LOGACTIONS_UNVER));\r
741                 }\r
742         }\r
743 \r
744         CTGitPath commonDir = m_ListCtrl.GetCommonDirectory(false);\r
745 \r
746     if(this->m_bWholeProject)   \r
747         SetWindowText(m_sWindowTitle + _T(" - ") + CString(_T("Whole Project")));\r
748     else\r
749             SetWindowText(m_sWindowTitle + _T(" - ") + commonDir.GetWinPathString());\r
750 \r
751         m_autolist.clear();\r
752         // we don't have to block the commit dialog while we fetch the\r
753         // auto completion list.\r
754         m_pathwatcher.ClearChangedPaths();\r
755         InterlockedExchange(&m_bBlock, FALSE);\r
756         if ((DWORD)CRegDWORD(_T("Software\\TortoiseGit\\Autocompletion"), TRUE)==TRUE)\r
757         {\r
758                 m_ListCtrl.Block(TRUE, TRUE);\r
759                 GetAutocompletionList();\r
760                 m_ListCtrl.Block(FALSE, FALSE);\r
761         }\r
762         if (m_bRunThread)\r
763         {\r
764                 DialogEnableWindow(IDC_SHOWUNVERSIONED, true);\r
765         DialogEnableWindow(IDC_WHOLE_PROJECT, true);\r
766                 DialogEnableWindow(IDC_SELECTALL, true);\r
767                 if (m_ListCtrl.HasChangeLists())\r
768                         DialogEnableWindow(IDC_KEEPLISTS, true);\r
769                 if (m_ListCtrl.HasLocks())\r
770                         DialogEnableWindow(IDC_WHOLE_PROJECT, true);\r
771                 // we have the list, now signal the main thread about it\r
772                 SendMessage(WM_AUTOLISTREADY);  // only send the message if the thread wasn't told to quit!\r
773         }\r
774 \r
775         InterlockedExchange(&m_bRunThread, FALSE);\r
776         InterlockedExchange(&m_bThreadRunning, FALSE);\r
777         // force the cursor to normal\r
778         RefreshCursor();\r
779 \r
780         return 0;\r
781 }\r
782 \r
783 void CCommitDlg::OnCancel()\r
784 {\r
785         m_bCancelled = true;\r
786         if (m_bBlock)\r
787                 return;\r
788         m_pathwatcher.Stop();\r
789         if (m_bThreadRunning)\r
790         {\r
791                 InterlockedExchange(&m_bRunThread, FALSE);\r
792                 WaitForSingleObject(m_pThread->m_hThread, 1000);\r
793                 if (m_bThreadRunning)\r
794                 {\r
795                         // we gave the thread a chance to quit. Since the thread didn't\r
796                         // listen to us we have to kill it.\r
797                         TerminateThread(m_pThread->m_hThread, (DWORD)-1);\r
798                         InterlockedExchange(&m_bThreadRunning, FALSE);\r
799                 }\r
800         }\r
801         UpdateData();\r
802         m_sBugID.Trim();\r
803         m_sLogMessage = m_cLogMessage.GetText();\r
804         if (!m_sBugID.IsEmpty())\r
805         {\r
806                 m_sBugID.Replace(_T(", "), _T(","));\r
807                 m_sBugID.Replace(_T(" ,"), _T(","));\r
808                 CString sBugID = m_ProjectProperties.sMessage;\r
809                 sBugID.Replace(_T("%BUGID%"), m_sBugID);\r
810                 if (m_ProjectProperties.bAppend)\r
811                         m_sLogMessage += _T("\n") + sBugID + _T("\n");\r
812                 else\r
813                         m_sLogMessage = sBugID + _T("\n") + m_sLogMessage;\r
814         }\r
815         if (m_ProjectProperties.sLogTemplate.Compare(m_sLogMessage) != 0)\r
816                 m_History.AddEntry(m_sLogMessage);\r
817         m_History.Save();\r
818         SaveSplitterPos();\r
819         CResizableStandAloneDialog::OnCancel();\r
820 }\r
821 \r
822 void CCommitDlg::OnBnClickedSelectall()\r
823 {\r
824         m_tooltips.Pop();       // hide the tooltips\r
825         UINT state = (m_SelectAll.GetState() & 0x0003);\r
826         if (state == BST_INDETERMINATE)\r
827         {\r
828                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
829                 // We will force this on to the unchecked state\r
830                 state = BST_UNCHECKED;\r
831                 m_SelectAll.SetCheck(state);\r
832         }\r
833         m_ListCtrl.SelectAll(state == BST_CHECKED);\r
834 }\r
835 \r
836 BOOL CCommitDlg::PreTranslateMessage(MSG* pMsg)\r
837 {\r
838         if (!m_bBlock)\r
839                 m_tooltips.RelayEvent(pMsg);\r
840         if (pMsg->message == WM_KEYDOWN)\r
841         {\r
842                 switch (pMsg->wParam)\r
843                 {\r
844                 case VK_F5:\r
845                         {\r
846                                 if (m_bBlock)\r
847                                         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
848                                 Refresh();\r
849                         }\r
850                         break;\r
851                 case VK_RETURN:\r
852                         {\r
853                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
854                                 {\r
855                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
856                                         {\r
857                                                 PostMessage(WM_COMMAND, IDOK);\r
858                                         }\r
859                                         return TRUE;\r
860                                 }\r
861                                 if ( GetFocus()==GetDlgItem(IDC_BUGID) )\r
862                                 {\r
863                                         // Pressing RETURN in the bug id control\r
864                                         // moves the focus to the message\r
865                                         GetDlgItem(IDC_LOGMESSAGE)->SetFocus();\r
866                                         return TRUE;\r
867                                 }\r
868                         }\r
869                         break;\r
870                 }\r
871         }\r
872 \r
873         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
874 }\r
875 \r
876 void CCommitDlg::Refresh()\r
877 {\r
878         if (m_bThreadRunning)\r
879                 return;\r
880 \r
881         InterlockedExchange(&m_bBlock, TRUE);\r
882         m_pThread = AfxBeginThread(StatusThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
883         if (m_pThread==NULL)\r
884         {\r
885                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
886                 InterlockedExchange(&m_bBlock, FALSE);\r
887         }\r
888         else\r
889         {\r
890                 m_pThread->m_bAutoDelete = FALSE;\r
891                 m_pThread->ResumeThread();\r
892         }\r
893 }\r
894 \r
895 void CCommitDlg::OnBnClickedHelp()\r
896 {\r
897         OnHelp();\r
898 }\r
899 \r
900 void CCommitDlg::OnBnClickedShowunversioned()\r
901 {\r
902         m_tooltips.Pop();       // hide the tooltips\r
903         UpdateData();\r
904         m_regAddBeforeCommit = m_bShowUnversioned;\r
905         if (!m_bBlock)\r
906         {\r
907                 DWORD dwShow = m_ListCtrl.GetShowFlags();\r
908                 if (DWORD(m_regAddBeforeCommit))\r
909                         dwShow |= SVNSLC_SHOWUNVERSIONED;\r
910                 else\r
911                         dwShow &= ~SVNSLC_SHOWUNVERSIONED;\r
912                 if(dwShow & SVNSLC_SHOWUNVERSIONED)\r
913                 {\r
914             if(m_bWholeProject)\r
915                 m_ListCtrl.GetStatus(NULL,false,false,true);\r
916             else\r
917                             m_ListCtrl.GetStatus(&this->m_pathList,false,false,true);\r
918                 }\r
919                 m_ListCtrl.Show(dwShow);\r
920         }\r
921 }\r
922 \r
923 void CCommitDlg::OnStnClickedExternalwarning()\r
924 {\r
925         m_tooltips.Popup();\r
926 }\r
927 \r
928 void CCommitDlg::OnEnChangeLogmessage()\r
929 {\r
930         UpdateOKButton();\r
931 }\r
932 \r
933 LRESULT CCommitDlg::OnGitStatusListCtrlItemCountChanged(WPARAM, LPARAM)\r
934 {\r
935 #if 0\r
936         if ((m_ListCtrl.GetItemCount() == 0)&&(m_ListCtrl.HasUnversionedItems())&&(!m_bShowUnversioned))\r
937         {\r
938                 if (CMessageBox::Show(*this, IDS_COMMITDLG_NOTHINGTOCOMMITUNVERSIONED, IDS_APPNAME, MB_ICONINFORMATION | MB_YESNO)==IDYES)\r
939                 {\r
940                         m_bShowUnversioned = TRUE;\r
941                         DWORD dwShow = GitSLC_SHOWVERSIONEDBUTNORMALANDEXTERNALSFROMDIFFERENTREPOS | GitSLC_SHOWUNVERSIONED | GitSLC_SHOWLOCKS;\r
942                         m_ListCtrl.Show(dwShow);\r
943                         UpdateData(FALSE);\r
944                 }\r
945         }\r
946 #endif\r
947         return 0;\r
948 }\r
949 \r
950 LRESULT CCommitDlg::OnGitStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
951 {\r
952         Refresh();\r
953         return 0;\r
954 }\r
955 \r
956 LRESULT CCommitDlg::OnFileDropped(WPARAM, LPARAM /*lParam*/)\r
957 {\r
958 #if 0\r
959         BringWindowToTop();\r
960         SetForegroundWindow();\r
961         SetActiveWindow();\r
962         // if multiple files/folders are dropped\r
963         // this handler is called for every single item\r
964         // separately.\r
965         // To avoid creating multiple refresh threads and\r
966         // causing crashes, we only add the items to the\r
967         // list control and start a timer.\r
968         // When the timer expires, we start the refresh thread,\r
969         // but only if it isn't already running - otherwise we\r
970         // restart the timer.\r
971         CTGitPath path;\r
972         path.SetFromWin((LPCTSTR)lParam);\r
973 \r
974         // just add all the items we get here.\r
975         // if the item is versioned, the add will fail but nothing\r
976         // more will happen.\r
977         Git Git;\r
978         Git.Add(CTGitPathList(path), &m_ProjectProperties, Git_depth_empty, false, true, true);\r
979 \r
980         if (!m_ListCtrl.HasPath(path))\r
981         {\r
982                 if (m_pathList.AreAllPathsFiles())\r
983                 {\r
984                         m_pathList.AddPath(path);\r
985                         m_pathList.RemoveDuplicates();\r
986                         m_updatedPathList.AddPath(path);\r
987                         m_updatedPathList.RemoveDuplicates();\r
988                 }\r
989                 else\r
990                 {\r
991                         // if the path list contains folders, we have to check whether\r
992                         // our just (maybe) added path is a child of one of those. If it is\r
993                         // a child of a folder already in the list, we must not add it. Otherwise\r
994                         // that path could show up twice in the list.\r
995                         bool bHasParentInList = false;\r
996                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
997                         {\r
998                                 if (m_pathList[i].IsAncestorOf(path))\r
999                                 {\r
1000                                         bHasParentInList = true;\r
1001                                         break;\r
1002                                 }\r
1003                         }\r
1004                         if (!bHasParentInList)\r
1005                         {\r
1006                                 m_pathList.AddPath(path);\r
1007                                 m_pathList.RemoveDuplicates();\r
1008                                 m_updatedPathList.AddPath(path);\r
1009                                 m_updatedPathList.RemoveDuplicates();\r
1010                         }\r
1011                 }\r
1012         }\r
1013         \r
1014         // Always start the timer, since the status of an existing item might have changed\r
1015         SetTimer(REFRESHTIMER, 200, NULL);\r
1016         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
1017 #endif\r
1018         return 0;\r
1019 }\r
1020 \r
1021 LRESULT CCommitDlg::OnAutoListReady(WPARAM, LPARAM)\r
1022 {\r
1023         m_cLogMessage.SetAutoCompletionList(m_autolist, '*');\r
1024         return 0;\r
1025 }\r
1026 \r
1027 //////////////////////////////////////////////////////////////////////////\r
1028 // functions which run in the status thread\r
1029 //////////////////////////////////////////////////////////////////////////\r
1030 \r
1031 void CCommitDlg::ParseRegexFile(const CString& sFile, std::map<CString, CString>& mapRegex)\r
1032 {\r
1033         CString strLine;\r
1034         try\r
1035         {\r
1036                 CStdioFile file(sFile, CFile::typeText | CFile::modeRead | CFile::shareDenyWrite);\r
1037                 while (m_bRunThread && file.ReadString(strLine))\r
1038                 {\r
1039                         int eqpos = strLine.Find('=');\r
1040                         CString rgx;\r
1041                         rgx = strLine.Mid(eqpos+1).Trim();\r
1042 \r
1043                         int pos = -1;\r
1044                         while (((pos = strLine.Find(','))>=0)&&(pos < eqpos))\r
1045                         {\r
1046                                 mapRegex[strLine.Left(pos)] = rgx;\r
1047                                 strLine = strLine.Mid(pos+1).Trim();\r
1048                         }\r
1049                         mapRegex[strLine.Left(strLine.Find('=')).Trim()] = rgx;\r
1050                 }\r
1051                 file.Close();\r
1052         }\r
1053         catch (CFileException* pE)\r
1054         {\r
1055                 TRACE("CFileException loading auto list regex file\n");\r
1056                 pE->Delete();\r
1057                 return;\r
1058         }\r
1059 }\r
1060 void CCommitDlg::GetAutocompletionList()\r
1061 {\r
1062         // the auto completion list is made of strings from each selected files.\r
1063         // the strings used are extracted from the files with regexes found\r
1064         // in the file "autolist.txt".\r
1065         // the format of that file is:\r
1066         // file extensions separated with commas '=' regular expression to use\r
1067         // example:\r
1068         // .h, .hpp = (?<=class[\s])\b\w+\b|(\b\w+(?=[\s ]?\(\);))\r
1069         // .cpp = (?<=[^\s]::)\b\w+\b\r
1070         \r
1071         std::map<CString, CString> mapRegex;\r
1072         CString sRegexFile = CPathUtils::GetAppDirectory();\r
1073         CRegDWORD regtimeout = CRegDWORD(_T("Software\\TortoiseGit\\AutocompleteParseTimeout"), 5);\r
1074         DWORD timeoutvalue = regtimeout*1000;\r
1075         sRegexFile += _T("autolist.txt");\r
1076         if (!m_bRunThread)\r
1077                 return;\r
1078         ParseRegexFile(sRegexFile, mapRegex);\r
1079         SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, sRegexFile.GetBuffer(MAX_PATH+1));\r
1080         sRegexFile.ReleaseBuffer();\r
1081         sRegexFile += _T("\\TortoiseGit\\autolist.txt");\r
1082         if (PathFileExists(sRegexFile))\r
1083         {\r
1084                 ParseRegexFile(sRegexFile, mapRegex);\r
1085         }\r
1086         DWORD starttime = GetTickCount();\r
1087 \r
1088         // now we have two arrays of strings, where the first array contains all\r
1089         // file extensions we can use and the second the corresponding regex strings\r
1090         // to apply to those files.\r
1091 \r
1092         // the next step is to go over all files shown in the commit dialog\r
1093         // and scan them for strings we can use\r
1094         int nListItems = m_ListCtrl.GetItemCount();\r
1095 \r
1096         for (int i=0; i<nListItems && m_bRunThread; ++i)\r
1097         {\r
1098                 // stop parsing after timeout\r
1099                 if ((!m_bRunThread) || (GetTickCount() - starttime > timeoutvalue))\r
1100                         return;\r
1101 \r
1102                 CTGitPath *path = (CTGitPath*)m_ListCtrl.GetItemData(i);\r
1103 \r
1104                 if(path == NULL)\r
1105                         continue;\r
1106 \r
1107                 CString sPartPath =path->GetGitPathString();\r
1108                 m_autolist.insert(sPartPath);\r
1109 \r
1110 //              const CGitStatusListCtrl::FileEntry * entry = m_ListCtrl.GetListEntry(i);\r
1111 //              if (!entry)\r
1112 //                      continue;\r
1113                 \r
1114                 // add the path parts to the auto completion list too\r
1115 //              CString sPartPath = entry->GetRelativeGitPath();\r
1116 //              m_autolist.insert(sPartPath);\r
1117 \r
1118 \r
1119                 int pos = 0;\r
1120                 int lastPos = 0;\r
1121                 while ((pos = sPartPath.Find('/', pos)) >= 0)\r
1122                 {\r
1123                         pos++;\r
1124                         lastPos = pos;\r
1125                         m_autolist.insert(sPartPath.Mid(pos));\r
1126                 }\r
1127 \r
1128                 // Last inserted entry is a file name.\r
1129                 // Some users prefer to also list file name without extension.\r
1130                 if (CRegDWORD(_T("Software\\TortoiseGit\\AutocompleteRemovesExtensions"), FALSE))\r
1131                 {\r
1132                         int dotPos = sPartPath.ReverseFind('.');\r
1133                         if ((dotPos >= 0) && (dotPos > lastPos))\r
1134                                 m_autolist.insert(sPartPath.Mid(lastPos, dotPos - lastPos));\r
1135                 }\r
1136 #if 0\r
1137                 if ((entry->status <= Git_wc_status_normal)||(entry->status == Git_wc_status_ignored))\r
1138                         continue;\r
1139 \r
1140                 CString sExt = entry->GetPath().GetFileExtension();\r
1141                 sExt.MakeLower();\r
1142                 // find the regex string which corresponds to the file extension\r
1143                 CString rdata = mapRegex[sExt];\r
1144                 if (rdata.IsEmpty())\r
1145                         continue;\r
1146 \r
1147                 ScanFile(entry->GetPath().GetWinPathString(), rdata);\r
1148                 if ((entry->textstatus != Git_wc_status_unversioned) &&\r
1149                         (entry->textstatus != Git_wc_status_none) &&\r
1150                         (entry->textstatus != Git_wc_status_ignored) &&\r
1151                         (entry->textstatus != Git_wc_status_added) &&\r
1152                         (entry->textstatus != Git_wc_status_normal))\r
1153                 {\r
1154                         CTGitPath basePath = Git::GetPristinePath(entry->GetPath());\r
1155                         if (!basePath.IsEmpty())\r
1156                                 ScanFile(basePath.GetWinPathString(), rdata);\r
1157                 }\r
1158 #endif\r
1159         }\r
1160         ATLTRACE(_T("Auto completion list loaded in %d msec\n"), GetTickCount() - starttime);\r
1161 }\r
1162 \r
1163 void CCommitDlg::ScanFile(const CString& sFilePath, const CString& sRegex)\r
1164 {\r
1165         wstring sFileContent;\r
1166         HANDLE hFile = CreateFile(sFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);\r
1167         if (hFile != INVALID_HANDLE_VALUE)\r
1168         {\r
1169                 DWORD size = GetFileSize(hFile, NULL);\r
1170                 if (size > 1000000L)\r
1171                 {\r
1172                         // no files bigger than 1 Meg\r
1173                         CloseHandle(hFile);\r
1174                         return;\r
1175                 }\r
1176                 // allocate memory to hold file contents\r
1177                 char * buffer = new char[size];\r
1178                 DWORD readbytes;\r
1179                 ReadFile(hFile, buffer, size, &readbytes, NULL);\r
1180                 CloseHandle(hFile);\r
1181                 int opts = 0;\r
1182                 IsTextUnicode(buffer, readbytes, &opts);\r
1183                 if (opts & IS_TEXT_UNICODE_NULL_BYTES)\r
1184                 {\r
1185                         delete [] buffer;\r
1186                         return;\r
1187                 }\r
1188                 if (opts & IS_TEXT_UNICODE_UNICODE_MASK)\r
1189                 {\r
1190                         sFileContent = wstring((wchar_t*)buffer, readbytes/sizeof(WCHAR));\r
1191                 }\r
1192                 if ((opts & IS_TEXT_UNICODE_NOT_UNICODE_MASK)||(opts == 0))\r
1193                 {\r
1194                         int ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)buffer, readbytes, NULL, 0);\r
1195                         wchar_t * pWideBuf = new wchar_t[ret];\r
1196                         int ret2 = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)buffer, readbytes, pWideBuf, ret);\r
1197                         if (ret2 == ret)\r
1198                                 sFileContent = wstring(pWideBuf, ret);\r
1199                         delete [] pWideBuf;\r
1200                 }\r
1201                 delete [] buffer;\r
1202         }\r
1203         if (sFileContent.empty()|| !m_bRunThread)\r
1204         {\r
1205                 return;\r
1206         }\r
1207 \r
1208         try\r
1209         {\r
1210                 const tr1::wregex regCheck(sRegex, tr1::regex_constants::icase | tr1::regex_constants::ECMAScript);\r
1211                 const tr1::wsregex_iterator end;\r
1212                 wstring s = sFileContent;\r
1213                 for (tr1::wsregex_iterator it(s.begin(), s.end(), regCheck); it != end; ++it)\r
1214                 {\r
1215                         const tr1::wsmatch match = *it;\r
1216                         for (size_t i=1; i<match.size(); ++i)\r
1217                         {\r
1218                                 if (match[i].second-match[i].first)\r
1219                                 {\r
1220                                         ATLTRACE(_T("matched keyword : %s\n"), wstring(match[i]).c_str());\r
1221                                         m_autolist.insert(wstring(match[i]).c_str());\r
1222                                 }\r
1223                         }\r
1224                 }\r
1225         }\r
1226         catch (exception) {}\r
1227 }\r
1228 \r
1229 // CSciEditContextMenuInterface\r
1230 void CCommitDlg::InsertMenuItems(CMenu& mPopup, int& nCmd)\r
1231 {\r
1232         CString sMenuItemText(MAKEINTRESOURCE(IDS_COMMITDLG_POPUP_PASTEFILELIST));\r
1233         m_nPopupPasteListCmd = nCmd++;\r
1234         mPopup.AppendMenu(MF_STRING | MF_ENABLED, m_nPopupPasteListCmd, sMenuItemText);\r
1235 }\r
1236 \r
1237 bool CCommitDlg::HandleMenuItemClick(int /*cmd*/, CSciEdit * /*pSciEdit*/)\r
1238 {\r
1239 #if 0\r
1240         if (m_bBlock)\r
1241                 return false;\r
1242         if (cmd == m_nPopupPasteListCmd)\r
1243         {\r
1244                 CString logmsg;\r
1245                 TCHAR buf[MAX_STATUS_STRING_LENGTH];\r
1246                 int nListItems = m_ListCtrl.GetItemCount();\r
1247                 for (int i=0; i<nListItems; ++i)\r
1248                 {\r
1249                         CGitStatusListCtrl::FileEntry * entry = m_ListCtrl.GetListEntry(i);\r
1250                         if (entry->IsChecked())\r
1251                         {\r
1252                                 CString line;\r
1253                                 Git_wc_status_kind status = entry->status;\r
1254                                 if (status == Git_wc_status_unversioned)\r
1255                                         status = Git_wc_status_added;\r
1256                                 if (status == Git_wc_status_missing)\r
1257                                         status = Git_wc_status_deleted;\r
1258                                 WORD langID = (WORD)CRegStdWORD(_T("Software\\TortoiseGit\\LanguageID"), GetUserDefaultLangID());\r
1259                                 if (m_ProjectProperties.bFileListInEnglish)\r
1260                                         langID = 1033;\r
1261                                 GitStatus::GetStatusString(AfxGetResourceHandle(), status, buf, sizeof(buf)/sizeof(TCHAR), langID);\r
1262                                 line.Format(_T("%-10s %s\r\n"), buf, (LPCTSTR)m_ListCtrl.GetItemText(i,0));\r
1263                                 logmsg += line;\r
1264                         }\r
1265                 }\r
1266                 pSciEdit->InsertText(logmsg);\r
1267                 return true;\r
1268         }\r
1269 #endif\r
1270         return false;\r
1271 }\r
1272 \r
1273 void CCommitDlg::OnTimer(UINT_PTR nIDEvent)\r
1274 {\r
1275         switch (nIDEvent)\r
1276         {\r
1277         case ENDDIALOGTIMER:\r
1278                 KillTimer(ENDDIALOGTIMER);\r
1279                 EndDialog(0);\r
1280                 break;\r
1281         case REFRESHTIMER:\r
1282                 if (m_bThreadRunning)\r
1283                 {\r
1284                         SetTimer(REFRESHTIMER, 200, NULL);\r
1285                         ATLTRACE("Wait some more before refreshing\n");\r
1286                 }\r
1287                 else\r
1288                 {\r
1289                         KillTimer(REFRESHTIMER);\r
1290                         ATLTRACE("Refreshing after items dropped\n");\r
1291                         Refresh();\r
1292                 }\r
1293                 break;\r
1294         }\r
1295         __super::OnTimer(nIDEvent);\r
1296 }\r
1297 \r
1298 void CCommitDlg::OnBnClickedHistory()\r
1299 {\r
1300         m_tooltips.Pop();       // hide the tooltips\r
1301         if (m_pathList.GetCount() == 0)\r
1302                 return;\r
1303 #if 0\r
1304         CHistoryDlg historyDlg;\r
1305         historyDlg.SetHistory(m_History);\r
1306         if (historyDlg.DoModal() != IDOK)\r
1307                 return;\r
1308 \r
1309         CString sMsg = historyDlg.GetSelectedText();\r
1310         if (sMsg != m_cLogMessage.GetText().Left(sMsg.GetLength()))\r
1311         {\r
1312                 CString sBugID = m_ProjectProperties.GetBugIDFromLog(sMsg);\r
1313                 if (!sBugID.IsEmpty())\r
1314                 {\r
1315                         SetDlgItemText(IDC_BUGID, sBugID);\r
1316                 }\r
1317                 if (m_ProjectProperties.sLogTemplate.Compare(m_cLogMessage.GetText())!=0)\r
1318                         m_cLogMessage.InsertText(sMsg, !m_cLogMessage.GetText().IsEmpty());\r
1319                 else\r
1320                         m_cLogMessage.SetText(sMsg);\r
1321         }\r
1322 \r
1323         UpdateOKButton();\r
1324         GetDlgItem(IDC_LOGMESSAGE)->SetFocus();\r
1325 #endif\r
1326 }\r
1327 \r
1328 void CCommitDlg::OnBnClickedBugtraqbutton()\r
1329 {\r
1330 #if 0\r
1331         m_tooltips.Pop();       // hide the tooltips\r
1332         CString sMsg = m_cLogMessage.GetText();\r
1333 \r
1334         if (m_BugTraqProvider == NULL)\r
1335                 return;\r
1336 \r
1337         BSTR parameters = m_bugtraq_association.GetParameters().AllocSysString();\r
1338         BSTR commonRoot = SysAllocString(m_pathList.GetCommonRoot().GetDirectory().GetWinPath());\r
1339         SAFEARRAY *pathList = SafeArrayCreateVector(VT_BSTR, 0, m_pathList.GetCount());\r
1340 \r
1341         for (LONG index = 0; index < m_pathList.GetCount(); ++index)\r
1342                 SafeArrayPutElement(pathList, &index, m_pathList[index].GetGitPathString().AllocSysString());\r
1343 \r
1344         BSTR originalMessage = sMsg.AllocSysString();\r
1345         BSTR temp = NULL;\r
1346 \r
1347         // first try the IBugTraqProvider2 interface\r
1348         CComPtr<IBugTraqProvider2> pProvider2 = NULL;\r
1349         HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider2);\r
1350         if (SUCCEEDED(hr))\r
1351         {\r
1352                 CString common = m_ListCtrl.GetCommonURL(false).GetGitPathString();\r
1353                 BSTR repositoryRoot = common.AllocSysString();\r
1354                 if (FAILED(hr = pProvider2->GetCommitMessage2(GetSafeHwnd(), parameters, repositoryRoot, commonRoot, pathList, originalMessage, &temp)))\r
1355                 {\r
1356                         CString sErr;\r
1357                         sErr.Format(IDS_ERR_FAILEDISSUETRACKERCOM, m_bugtraq_association.GetProviderName(), _com_error(hr).ErrorMessage());\r
1358                         CMessageBox::Show(m_hWnd, sErr, _T("TortoiseGit"), MB_ICONERROR);\r
1359                 }\r
1360                 else\r
1361                         m_cLogMessage.SetText(temp);\r
1362         }\r
1363         else\r
1364         {\r
1365                 // if IBugTraqProvider2 failed, try IBugTraqProvider\r
1366                 CComPtr<IBugTraqProvider> pProvider = NULL;\r
1367                 HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider);\r
1368                 if (FAILED(hr))\r
1369                 {\r
1370                         CString sErr;\r
1371                         sErr.Format(IDS_ERR_FAILEDISSUETRACKERCOM, (LPCTSTR)m_bugtraq_association.GetProviderName(), _com_error(hr).ErrorMessage());\r
1372                         CMessageBox::Show(m_hWnd, sErr, _T("TortoiseGit"), MB_ICONERROR);\r
1373                         return;\r
1374                 }\r
1375 \r
1376                 if (FAILED(hr = pProvider->GetCommitMessage(GetSafeHwnd(), parameters, commonRoot, pathList, originalMessage, &temp)))\r
1377                 {\r
1378                         CString sErr;\r
1379                         sErr.Format(IDS_ERR_FAILEDISSUETRACKERCOM, m_bugtraq_association.GetProviderName(), _com_error(hr).ErrorMessage());\r
1380                         CMessageBox::Show(m_hWnd, sErr, _T("TortoiseGit"), MB_ICONERROR);\r
1381                 }\r
1382                 else\r
1383                         m_cLogMessage.SetText(temp);\r
1384         }\r
1385 \r
1386         m_cLogMessage.SetFocus();\r
1387 \r
1388         SysFreeString(temp);\r
1389 #endif\r
1390 }\r
1391 \r
1392 LRESULT CCommitDlg::OnGitStatusListCtrlCheckChanged(WPARAM, LPARAM)\r
1393 {\r
1394         UpdateOKButton();\r
1395         return 0;\r
1396 }\r
1397 \r
1398 void CCommitDlg::UpdateOKButton()\r
1399 {\r
1400 #if 0\r
1401         BOOL bValidLogSize = FALSE;\r
1402 \r
1403     if (m_cLogMessage.GetText().GetLength() >= m_ProjectProperties.nMinLogSize)\r
1404                 bValidLogSize = !m_bBlock;\r
1405 \r
1406         LONG nSelectedItems = m_ListCtrl.GetSelected();\r
1407         DialogEnableWindow(IDOK, bValidLogSize && nSelectedItems>0);\r
1408 #endif\r
1409 }\r
1410 \r
1411 \r
1412 LRESULT CCommitDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)\r
1413 {\r
1414         switch (message) {\r
1415         case WM_NOTIFY:\r
1416                 if (wParam == IDC_SPLITTER)\r
1417                 { \r
1418                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
1419                         DoSize(pHdr->delta);\r
1420                 }\r
1421                 break;\r
1422         }\r
1423 \r
1424         return __super::DefWindowProc(message, wParam, lParam);\r
1425 }\r
1426 \r
1427 void CCommitDlg::SetSplitterRange()\r
1428 {\r
1429         if ((m_ListCtrl)&&(m_cLogMessage))\r
1430         {\r
1431                 CRect rcTop;\r
1432                 m_cLogMessage.GetWindowRect(rcTop);\r
1433                 ScreenToClient(rcTop);\r
1434                 CRect rcMiddle;\r
1435                 m_ListCtrl.GetWindowRect(rcMiddle);\r
1436                 ScreenToClient(rcMiddle);\r
1437                 if (rcMiddle.Height() && rcMiddle.Width())\r
1438                         m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);\r
1439         }\r
1440 }\r
1441 \r
1442 void CCommitDlg::DoSize(int delta)\r
1443 {\r
1444         RemoveAnchor(IDC_MESSAGEGROUP);\r
1445         RemoveAnchor(IDC_LOGMESSAGE);\r
1446         RemoveAnchor(IDC_SPLITTER);\r
1447         RemoveAnchor(IDC_SIGNOFF);\r
1448         RemoveAnchor(IDC_COMMIT_AMEND);\r
1449         RemoveAnchor(IDC_LISTGROUP);\r
1450         RemoveAnchor(IDC_FILELIST);\r
1451         CSplitterControl::ChangeHeight(&m_cLogMessage, delta, CW_TOPALIGN);\r
1452         CSplitterControl::ChangeHeight(GetDlgItem(IDC_MESSAGEGROUP), delta, CW_TOPALIGN);\r
1453         CSplitterControl::ChangeHeight(&m_ListCtrl, -delta, CW_BOTTOMALIGN);\r
1454         CSplitterControl::ChangeHeight(GetDlgItem(IDC_LISTGROUP), -delta, CW_BOTTOMALIGN);\r
1455         CSplitterControl::ChangePos(GetDlgItem(IDC_SIGNOFF),0,delta);\r
1456         CSplitterControl::ChangePos(GetDlgItem(IDC_COMMIT_AMEND),0,delta);\r
1457         AddAnchor(IDC_MESSAGEGROUP, TOP_LEFT, TOP_RIGHT);\r
1458         AddAnchor(IDC_LOGMESSAGE, TOP_LEFT, TOP_RIGHT);\r
1459         AddAnchor(IDC_SPLITTER, TOP_LEFT, TOP_RIGHT);\r
1460         AddAnchor(IDC_LISTGROUP, TOP_LEFT, BOTTOM_RIGHT);\r
1461         AddAnchor(IDC_FILELIST, TOP_LEFT, BOTTOM_RIGHT);\r
1462         AddAnchor(IDC_SIGNOFF,TOP_RIGHT);\r
1463         AddAnchor(IDC_COMMIT_AMEND,TOP_LEFT);\r
1464         ArrangeLayout();\r
1465         // adjust the minimum size of the dialog to prevent the resizing from\r
1466         // moving the list control too far down.\r
1467         CRect rcLogMsg;\r
1468         m_cLogMessage.GetClientRect(rcLogMsg);\r
1469         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_LogMsgOrigRect.Height()+rcLogMsg.Height()));\r
1470 \r
1471         SetSplitterRange();\r
1472         m_cLogMessage.Invalidate();\r
1473         GetDlgItem(IDC_LOGMESSAGE)->Invalidate();\r
1474 }\r
1475 \r
1476 void CCommitDlg::OnSize(UINT nType, int cx, int cy)\r
1477 {\r
1478     // first, let the resizing take place\r
1479     __super::OnSize(nType, cx, cy);\r
1480 \r
1481     //set range\r
1482     SetSplitterRange();\r
1483 }\r
1484 \r
1485 \r
1486 void CCommitDlg::OnBnClickedSignOff()\r
1487 {\r
1488         // TODO: Add your control notification handler code here\r
1489         CString str;\r
1490         CString username;\r
1491         CString email;\r
1492         username=g_Git.GetUserName();\r
1493         email=g_Git.GetUserEmail();\r
1494         username.Remove(_T('\n'));\r
1495         email.Remove(_T('\n'));\r
1496         str.Format(_T("Signed-off-by: %s <%s>\n"),username,email);\r
1497 \r
1498         m_cLogMessage.SetText(m_cLogMessage.GetText()+_T("\r\n\r\n")+str);\r
1499 }\r
1500 \r
1501 void CCommitDlg::OnStnClickedCommitlabel()\r
1502 {\r
1503         // TODO: Add your control notification handler code here\r
1504 }\r
1505 \r
1506 void CCommitDlg::OnBnClickedCommitAmend()\r
1507 {\r
1508     // TODO: Add your control notification handler code here\r
1509         this->UpdateData();\r
1510         if(this->m_bCommitAmend && this->m_AmendStr.IsEmpty())\r
1511         {\r
1512                 GitRev rev;\r
1513                 BYTE_VECTOR vector;\r
1514                 CString head(_T("HEAD"));\r
1515                 g_Git.GetLog(vector,head,NULL,1);\r
1516                 rev.ParserFromLog(vector);\r
1517                 m_AmendStr=rev.m_Subject+_T("\n\n")+rev.m_Body;\r
1518         }\r
1519 \r
1520         if(this->m_bCommitAmend)\r
1521         {\r
1522                 this->m_NoAmendStr=this->m_cLogMessage.GetText();\r
1523                 m_cLogMessage.SetText(m_AmendStr);\r
1524 \r
1525         }else\r
1526         {\r
1527                 this->m_AmendStr=this->m_cLogMessage.GetText();\r
1528                 m_cLogMessage.SetText(m_NoAmendStr);\r
1529 \r
1530         }\r
1531 \r
1532 }\r
1533 \r
1534 void CCommitDlg::OnBnClickedWholeProject()\r
1535 {\r
1536     // TODO: Add your control notification handler code here\r
1537     m_tooltips.Pop();   // hide the tooltips\r
1538         UpdateData();\r
1539     m_ListCtrl.Clear();\r
1540         if (!m_bBlock)\r
1541         {\r
1542             if(m_bWholeProject)\r
1543             m_ListCtrl.GetStatus(NULL,true,false,true);\r
1544         else\r
1545                     m_ListCtrl.GetStatus(&this->m_pathList,true,false,true);\r
1546                 \r
1547                 m_ListCtrl.Show(m_ListCtrl.GetShowFlags());\r
1548         }\r
1549 \r
1550         CTGitPath commonDir = m_ListCtrl.GetCommonDirectory(false);\r
1551 \r
1552     if(this->m_bWholeProject)   \r
1553         SetWindowText(m_sWindowTitle + _T(" - ") + CString(_T("Whole Project")));\r
1554     else\r
1555             SetWindowText(m_sWindowTitle + _T(" - ") + commonDir.GetWinPathString());\r
1556 \r
1557 }\r