OSDN Git Service

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