OSDN Git Service

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