OSDN Git Service

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