OSDN Git Service

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