OSDN Git Service

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