OSDN Git Service

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