OSDN Git Service

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