Drop unused msysgit dialog of installer
[TortoiseGit.git] / src / TortoiseProc / ProgressDlg.cpp
blob620b2e312b65a7b52fa0b0bbeeb456205e57f5cb
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // ProgressDlg.cpp : implementation file
22 #include "stdafx.h"
23 #include "TortoiseProc.h"
24 #include "ProgressDlg.h"
25 #include "Git.h"
26 #include "atlconv.h"
27 #include "UnicodeUtils.h"
28 #include "IconMenu.h"
29 #include "LoglistCommonResource.h"
30 #include <Tlhelp32.h>
31 #include "AppUtils.h"
32 #include "SmartHandle.h"
33 #include "../TGitCache/CacheInterface.h"
34 #include "LoglistUtils.h"
35 #include "SoundUtils.h"
36 #include "Win7.h"
37 #include "MessageBox.h"
38 #include "LogFile.h"
39 #include "CmdLineParser.h"
41 // CProgressDlg dialog
43 IMPLEMENT_DYNAMIC(CProgressDlg, CResizableStandAloneDialog)
45 CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)
46 : CResizableStandAloneDialog(CProgressDlg::IDD, pParent)
47 , m_bShowCommand(true)
48 , m_bAbort(false)
49 , m_bDone(false)
50 , m_startTick(GetTickCount())
51 , m_BufStart(0)
52 , m_Git(&g_Git)
54 m_pThread = NULL;
55 m_bBufferAll=false;
56 m_GitStatus = (DWORD)-1;
57 int autoClose = CRegDWORD(_T("Software\\TortoiseGit\\AutoCloseGitProgress"), 0);
58 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
59 if (parser.HasKey(_T("closeonend")))
60 autoClose = parser.GetLongVal(_T("closeonend"));
61 switch (autoClose)
63 case 1:
64 m_AutoClose = AUTOCLOSE_IF_NO_OPTIONS;
65 break;
66 case 2:
67 m_AutoClose = AUTOCLOSE_IF_NO_ERRORS;
68 break;
69 default:
70 m_AutoClose = AUTOCLOSE_NO;
71 break;
75 CProgressDlg::~CProgressDlg()
77 if(m_pThread != NULL)
79 delete m_pThread;
83 void CProgressDlg::DoDataExchange(CDataExchange* pDX)
85 CDialog::DoDataExchange(pDX);
86 DDX_Control(pDX, IDC_CURRENT, this->m_CurrentWork);
87 DDX_Control(pDX, IDC_TITLE_ANIMATE, this->m_Animate);
88 DDX_Control(pDX, IDC_RUN_PROGRESS, this->m_Progress);
89 DDX_Control(pDX, IDC_LOG, this->m_Log);
90 DDX_Control(pDX, IDC_PROGRESS_BUTTON1, this->m_ctrlPostCmd);
93 BEGIN_MESSAGE_MAP(CProgressDlg, CResizableStandAloneDialog)
94 ON_WM_CLOSE()
95 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
96 ON_BN_CLICKED(IDOK, &CProgressDlg::OnBnClickedOk)
97 ON_BN_CLICKED(IDC_PROGRESS_BUTTON1,&CProgressDlg::OnBnClickedButton1)
98 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
99 END_MESSAGE_MAP()
101 BOOL CProgressDlg::OnInitDialog()
103 CResizableStandAloneDialog::OnInitDialog();
105 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
106 // do this, Explorer would be unable to send that message to our window if we
107 // were running elevated. It's OK to make the call all the time, since if we're
108 // not elevated, this is a no-op.
109 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
110 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
111 CAutoLibrary hUser = AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
112 if (hUser)
114 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
115 if (pfnChangeWindowMessageFilterEx)
117 pfnChangeWindowMessageFilterEx(m_hWnd, WM_TASKBARBTNCREATED, MSGFLT_ALLOW, &cfs);
120 m_pTaskbarList.Release();
121 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
122 m_pTaskbarList = nullptr;
124 AddAnchor(IDC_TITLE_ANIMATE, TOP_LEFT, TOP_RIGHT);
125 AddAnchor(IDC_RUN_PROGRESS, TOP_LEFT,TOP_RIGHT);
126 AddAnchor(IDC_LOG, TOP_LEFT,BOTTOM_RIGHT);
128 AddAnchor(IDOK,BOTTOM_RIGHT);
129 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
130 AddAnchor(IDC_PROGRESS_BUTTON1,BOTTOM_LEFT);
131 AddAnchor(IDC_CURRENT,TOP_LEFT);
133 this->GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_HIDE);
134 m_Animate.Open(IDR_DOWNLOAD);
136 CFont m_logFont;
137 CAppUtils::CreateFontForLogs(m_logFont);
138 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
139 m_Log.SetFont(&m_logFont);
141 CString InitialText;
142 if ( !m_PreText.IsEmpty() )
144 InitialText = m_PreText + _T("\r\n");
146 #if 0
147 if (m_bShowCommand && (!m_GitCmd.IsEmpty() ))
149 InitialText += m_GitCmd+_T("\r\n\r\n");
151 #endif
152 m_Log.SetWindowTextW(InitialText);
153 m_CurrentWork.SetWindowTextW(_T(""));
155 EnableSaveRestore(_T("ProgressDlg"));
157 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
158 if (m_pThread==NULL)
160 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);
161 DialogEnableWindow(IDCANCEL, TRUE);
163 else
165 m_pThread->m_bAutoDelete = FALSE;
166 m_pThread->ResumeThread();
169 CString sWindowTitle;
170 GetWindowText(sWindowTitle);
171 CAppUtils::SetWindowTitle(m_hWnd, m_Git->m_CurrentDir, sWindowTitle);
173 // Make sure this dialog is shown in foreground (see issue #1536)
174 SetForegroundWindow();
176 return TRUE;
179 static void EnsurePostMessage(CWnd *pWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
181 redo:
182 if (!pWnd->PostMessage(Msg, wParam, lParam))
184 if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA)
186 Sleep(20);
187 goto redo;
189 else
190 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Message %d-%d could not be sent (error %d; %s)\n"), wParam, lParam, GetLastError(), (CString)CFormatMessageWrapper());
194 UINT CProgressDlg::ProgressThreadEntry(LPVOID pVoid)
196 return ((CProgressDlg*)pVoid)->ProgressThread();
199 //static function, Share with SyncDialog
200 UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,CGitByteArray *pdata, CGit *git)
202 UINT ret=0;
204 PROCESS_INFORMATION pi;
205 HANDLE hRead = 0;
207 memset(&pi,0,sizeof(PROCESS_INFORMATION));
209 CBlockCacheForPath cacheBlock(git->m_CurrentDir);
211 EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_START, 0);
213 if(pdata)
214 pdata->clear();
216 for (size_t i = 0; i < cmdlist.size(); ++i)
218 if(cmdlist[i].IsEmpty())
219 continue;
221 if (bShowCommand)
223 CStringA str = CUnicodeUtils::GetMulti(cmdlist[i].Trim() + _T("\r\n\r\n"), CP_UTF8);
224 for (int j = 0; j < str.GetLength(); ++j)
226 if(pdata)
228 pdata->m_critSec.Lock();
229 pdata->push_back(str[j]);
230 pdata->m_critSec.Unlock();
232 else
233 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);
235 if(pdata)
236 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
239 git->RunAsync(cmdlist[i].Trim(),&pi, &hRead, NULL, pfilename);
241 DWORD readnumber;
242 char lastByte = '\0';
243 char byte;
244 CString output;
245 while(ReadFile(hRead,&byte,1,&readnumber,NULL))
247 if(pdata)
249 if(byte == 0)
250 byte = '\n';
252 pdata->m_critSec.Lock();
253 if (byte == '\n' && lastByte != '\r')
254 pdata->push_back('\r');
255 pdata->push_back( byte);
256 lastByte = byte;
257 pdata->m_critSec.Unlock();
259 if(byte == '\r' || byte == '\n')
260 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
262 else
263 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,byte);
265 if (pdata)
267 pdata->m_critSec.Lock();
268 bool post = !pdata->empty();
269 pdata->m_critSec.Unlock();
270 if (post)
271 EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_RUN, 0);
274 CloseHandle(pi.hThread);
276 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": waiting for process to finish (%s), aborted: %d\n"), cmdlist[i], *bAbort);
278 WaitForSingleObject(pi.hProcess, INFINITE);
280 DWORD status=0;
281 if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)
283 CloseHandle(pi.hProcess);
285 CloseHandle(hRead);
287 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": process %s finished, status code could not be fetched, (error %d; %s), aborted: %d\n"), cmdlist[i], GetLastError(), (CString)CFormatMessageWrapper(), *bAbort);
289 EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_FAILED, status);
290 return TGIT_GIT_ERROR_GET_EXIT_CODE;
292 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": process %s finished with code %d\n"), cmdlist[i], status);
293 ret |= status;
296 CloseHandle(pi.hProcess);
298 CloseHandle(hRead);
300 EnsurePostMessage(pWnd, MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_END, ret);
302 return ret;
305 UINT CProgressDlg::ProgressThread()
308 m_GitCmdList.push_back(m_GitCmd);
310 CString *pfilename;
312 if(m_LogFile.IsEmpty())
313 pfilename=NULL;
314 else
315 pfilename=&m_LogFile;
317 m_startTick = GetTickCount();
318 m_GitStatus = RunCmdList(this, m_GitCmdList, m_bShowCommand, pfilename, &m_bAbort, &this->m_Databuf, m_Git);
319 return 0;
322 LRESULT CProgressDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
324 if(wParam == MSG_PROGRESSDLG_START)
326 m_BufStart = 0 ;
327 m_Animate.Play(0, INT_MAX, INT_MAX);
328 DialogEnableWindow(IDCANCEL, TRUE);
329 if (m_pTaskbarList)
331 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
332 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 100);
335 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
337 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": got message: %d\n"), wParam);
338 DWORD tickSpent = GetTickCount() - m_startTick;
339 CString strEndTime = CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE, true, false);
341 if(m_bBufferAll)
343 m_Databuf.m_critSec.Lock();
344 m_Databuf.push_back(0);
345 m_Log.SetWindowText(Convert2UnionCode((char*)&m_Databuf[0]));
346 m_Databuf.m_critSec.Unlock();
347 m_Log.LineScroll(m_Log.GetLineCount() - m_Log.GetFirstVisibleLine() - 4);
349 m_BufStart=0;
350 m_Databuf.m_critSec.Lock();
351 this->m_Databuf.clear();
352 m_Databuf.m_critSec.Unlock();
354 m_bDone = true;
355 m_Animate.Stop();
356 m_Progress.SetPos(100);
357 this->DialogEnableWindow(IDOK,TRUE);
359 m_GitStatus = (DWORD)lParam;
361 // detect crashes of perl when performing git svn actions
362 if (m_GitStatus == 0 && m_GitCmd.Find(_T(" svn ")) > 1)
364 CString log;
365 m_Log.GetWindowText(log);
366 if (log.GetLength() > 18 && log.Mid(log.GetLength() - 18) == _T("perl.exe.stackdump"))
367 m_GitStatus = (DWORD)-1;
370 if(this->m_GitStatus)
372 if (m_pTaskbarList)
374 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
375 m_pTaskbarList->SetProgressValue(m_hWnd, 100, 100);
377 CString log;
378 log.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT, m_GitStatus);
379 CString err;
380 err.Format(_T("\r\n\r\n%s (%lu ms @ %s)\r\n"), log, tickSpent, strEndTime);
381 InsertColorText(this->m_Log, err, RGB(255,0,0));
382 CSoundUtils::PlayTGitError();
384 else {
385 if (m_pTaskbarList)
386 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
387 CString temp;
388 temp.LoadString(IDS_SUCCESS);
389 CString log;
390 log.Format(_T("\r\n%s (%lu ms @ %s)\r\n"), temp, tickSpent, strEndTime);
391 InsertColorText(this->m_Log, log, RGB(0,0,255));
392 this->DialogEnableWindow(IDCANCEL,FALSE);
395 if (wParam == MSG_PROGRESSDLG_END)
397 if (m_PostCmdCallback) // new handling method using callback
399 m_PostCmdCallback();
401 if (!m_PostCmdList.IsEmpty())
403 m_ctrlPostCmd.AddEntries(m_PostCmdList);
404 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
407 else if (m_GitStatus == 0) // default old behaviour on success
409 if (!m_PostCmdList.IsEmpty())
411 m_ctrlPostCmd.AddEntries(m_PostCmdList);
412 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
415 else // simple method to show buttons on failed
417 if (!m_PostFailCmdList.IsEmpty())
419 m_ctrlPostCmd.AddEntries(m_PostFailCmdList);
420 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
425 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)
427 if (m_AutoClose == AUTOCLOSE_IF_NO_OPTIONS && m_PostCmdList.IsEmpty() || m_AutoClose == AUTOCLOSE_IF_NO_ERRORS)
428 PostMessage(WM_COMMAND, 1, (LPARAM)GetDlgItem(IDOK)->m_hWnd);
432 if(!m_bBufferAll)
434 if(lParam == 0)
436 m_Databuf.m_critSec.Lock();
437 for (size_t i = this->m_BufStart; i < this->m_Databuf.size(); ++i)
439 char c = this->m_Databuf[m_BufStart];
440 ++m_BufStart;
441 m_Databuf.m_critSec.Unlock();
442 ParserCmdOutput(c);
444 m_Databuf.m_critSec.Lock();
447 if(m_BufStart>1000)
449 m_Databuf.erase(m_Databuf.begin(), m_Databuf.begin()+m_BufStart);
450 m_BufStart =0;
452 m_Databuf.m_critSec.Unlock();
455 else
456 ParserCmdOutput((char)lParam);
458 return 0;
461 //static function, Share with SyncDialog
462 int CProgressDlg::FindPercentage(CString &log)
464 int s1=log.Find(_T('%'));
465 if(s1<0)
466 return -1;
468 int s2=s1-1;
469 for(int i=s1-1;i>=0;i--)
471 if(log[i]>=_T('0') && log[i]<=_T('9'))
472 s2=i;
473 else
474 break;
476 return _ttol(log.Mid(s2,s1-s2));
479 void CProgressDlg::ParserCmdOutput(char ch)
481 ParserCmdOutput(this->m_Log,this->m_Progress,this->m_hWnd,this->m_pTaskbarList,this->m_LogTextA,ch,&this->m_CurrentWork);
483 void CProgressDlg::ClearESC(CString &str)
485 // see http://ascii-table.com/ansi-escape-sequences.php and http://tldp.org/HOWTO/Bash-Prompt-HOWTO/c327.html
486 str.Replace(_T("\033[K"), _T("")); // erase until end of line; no need to care for this, because we always clear the whole line
488 // drop colors
489 while (true)
491 int escapePosition = str.Find(_T('\033'));
492 if (escapePosition >= 0 && str.GetLength() >= escapePosition + 3)
494 if (str.Mid(escapePosition, 2) == _T("\033["))
496 int colorEnd = str.Find(_T('m'), escapePosition + 2);
497 if (colorEnd > 0)
499 bool found = true;
500 for (int i = escapePosition + 2; i < colorEnd; ++i)
502 if (str[i] != _T(';') && (str[i] < _T('0') && str[i] > _T('9')))
504 found = false;
505 break;
508 if (found)
510 if (escapePosition > 0)
511 str = str.Left(escapePosition) + str.Mid(colorEnd + 1);
512 else
513 str = str.Mid(colorEnd);
514 continue;
519 break;
522 void CProgressDlg::ParserCmdOutput(CRichEditCtrl &log,CProgressCtrl &progressctrl,HWND m_hWnd,CComPtr<ITaskbarList3> m_pTaskbarList,CStringA &oneline, char ch, CWnd *CurrentWork)
524 //TRACE(_T("%c"),ch);
525 if( ch == ('\r') || ch == ('\n'))
527 CString str;
529 // TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));
530 // TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));
532 int lines = log.GetLineCount();
533 g_Git.StringAppend(&str, (BYTE*)oneline.GetBuffer(), CP_UTF8);
534 str.Trim();
535 // TRACE(_T("%s"), str);
537 ClearESC(str);
539 if(ch == ('\r'))
541 int start=log.LineIndex(lines-1);
542 log.SetSel(start, log.GetTextLength());
543 log.ReplaceSel(str);
545 else
547 int length = log.GetWindowTextLength();
548 log.SetSel(length, length);
549 if (length > 0)
550 log.ReplaceSel(_T("\r\n") + str);
551 else
552 log.ReplaceSel(str);
555 if (lines > 500) //limited log length
557 int end=log.LineIndex(1);
558 log.SetSel(0,end);
559 log.ReplaceSel(_T(""));
561 log.LineScroll(log.GetLineCount() - log.GetFirstVisibleLine() - 4);
563 int s1=oneline.ReverseFind(_T(':'));
564 int s2=oneline.Find(_T('%'));
565 if (s1 > 0 && s2 > 0)
567 if(CurrentWork)
568 CurrentWork->SetWindowTextW(str.Left(s1));
570 int pos=FindPercentage(str);
571 TRACE(_T("Pos %d\r\n"),pos);
572 if(pos>0)
574 progressctrl.SetPos(pos);
575 if (m_pTaskbarList)
577 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
578 m_pTaskbarList->SetProgressValue(m_hWnd, pos, 100);
583 oneline="";
586 else
588 oneline+=ch;
591 void CProgressDlg::RemoveLastLine(CString &str)
593 int start;
594 start=str.ReverseFind(_T('\n'));
595 if(start>0)
596 str=str.Left(start);
597 return;
599 // CProgressDlg message handlers
601 void CProgressDlg::WriteLog() const
603 CLogFile logfile(g_Git.m_CurrentDir);
604 if (logfile.Open())
606 logfile.AddTimeLine();
607 CString text = GetLogText();
608 LPTSTR psz_string = text.GetBuffer();
609 while (*psz_string)
611 if (*psz_string == '\r')
613 ++psz_string;
614 continue;
616 size_t i_len = wcscspn(psz_string, L"\n");
617 logfile.AddLine(CString(psz_string, (int)i_len));
618 psz_string += i_len;
619 if (*psz_string == '\n')
620 ++psz_string;
622 if (m_bAbort)
624 CString canceled;
625 canceled.LoadString(IDS_SVN_USERCANCELLED);
626 logfile.AddLine(canceled);
628 logfile.Close();
632 void CProgressDlg::OnBnClickedOk()
634 if (m_pThread) // added here because Close-button is "called" from thread by PostMessage
635 ::WaitForSingleObject(m_pThread->m_hThread, 5000);
636 m_Log.GetWindowText(this->m_LogText);
637 WriteLog();
638 OnOK();
641 void CProgressDlg::OnBnClickedButton1()
643 WriteLog();
644 this->EndDialog((int)(IDC_PROGRESS_BUTTON1 + this->m_ctrlPostCmd.GetCurrentEntry()));
647 void CProgressDlg::OnClose()
649 DialogEnableWindow(IDCANCEL, TRUE);
650 __super::OnClose();
653 void CProgressDlg::OnCancel()
655 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": User canceled\n"));
656 m_bAbort = true;
657 if(m_bDone)
659 WriteLog();
660 CResizableStandAloneDialog::OnCancel();
661 return;
664 if( m_Git->m_CurrentGitPi.hProcess )
666 DWORD dwConfirmKillProcess = CRegDWORD(_T("Software\\TortoiseGit\\ConfirmKillProcess"));
667 if (dwConfirmKillProcess && CMessageBox::Show(m_hWnd, IDS_PROC_CONFIRMKILLPROCESS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION) != IDYES)
668 return;
669 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))
671 ::WaitForSingleObject(m_Git->m_CurrentGitPi.hProcess ,10000);
674 KillProcessTree(m_Git->m_CurrentGitPi.dwProcessId);
677 ::WaitForSingleObject(m_Git->m_CurrentGitPi.hProcess ,10000);
678 if (m_pThread)
679 ::WaitForSingleObject(m_pThread->m_hThread, 5000);
680 WriteLog();
681 CResizableStandAloneDialog::OnCancel();
684 void CProgressDlg::KillProcessTree(DWORD dwProcessId, unsigned int depth)
686 // recursively kills a process tree
687 // This is not optimized, but works and isn't called very often ;)
689 if (!dwProcessId || depth > 20)
690 return;
692 PROCESSENTRY32 pe;
693 memset(&pe, 0, sizeof(PROCESSENTRY32));
694 pe.dwSize = sizeof(PROCESSENTRY32);
696 CAutoGeneralHandle hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
698 if (::Process32First(hSnap, &pe))
702 if (pe.th32ParentProcessID == dwProcessId)
703 KillProcessTree(pe.th32ProcessID, depth + 1);
704 } while (::Process32Next(hSnap, &pe));
706 CAutoGeneralHandle hProc = ::OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
707 if (hProc)
708 ::TerminateProcess(hProc, 1);
712 void CProgressDlg::InsertColorText(CRichEditCtrl &edit,CString text,COLORREF rgb)
714 CHARFORMAT old,cf;
715 edit.GetDefaultCharFormat(cf);
716 old=cf;
717 cf.dwMask|=CFM_COLOR;
718 cf.crTextColor=rgb;
719 cf.dwEffects|=CFE_BOLD;
720 cf.dwEffects &= ~CFE_AUTOCOLOR ;
721 edit.SetSel(edit.GetTextLength()-1,edit.GetTextLength());
722 edit.ReplaceSel(text);
723 edit.SetSel(edit.LineIndex(edit.GetLineCount()-2),edit.GetTextLength());
724 edit.SetSelectionCharFormat(cf);
725 edit.SetSel(edit.GetTextLength(),edit.GetTextLength());
726 edit.SetDefaultCharFormat(old);
727 edit.LineScroll(edit.GetLineCount() - edit.GetFirstVisibleLine() - 4);
730 CString CCommitProgressDlg::Convert2UnionCode(char *buff, int size)
732 int start=0;
733 if(size == -1)
734 size = (int)strlen(buff);
736 for (int i = 0; i < size; ++i)
738 if(buff[i] == ']')
739 start = i;
740 if( start >0 && buff[i] =='\n' )
742 start =i;
743 break;
747 CString str;
748 g_Git.StringAppend(&str, (BYTE*)buff, g_Git.m_LogEncode, start);
749 g_Git.StringAppend(&str, (BYTE*)buff + start, CP_UTF8, size - start);
751 ClearESC(str);
753 return str;
756 LRESULT CProgressDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
758 m_pTaskbarList.Release();
759 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
760 SetUUIDOverlayIcon(m_hWnd);
761 return 0;
764 BOOL CProgressDlg::PreTranslateMessage(MSG* pMsg)
766 if (pMsg->message == WM_KEYDOWN)
768 if (pMsg->wParam == VK_ESCAPE)
770 // pressing the ESC key should close the dialog. But since we disabled the escape
771 // key (so the user doesn't get the idea that he could simply undo an e.g. update)
772 // this won't work.
773 // So if the user presses the ESC key, change it to VK_RETURN so the dialog gets
774 // the impression that the OK button was pressed.
775 if ((!GetDlgItem(IDCANCEL)->IsWindowEnabled())
776 &&(GetDlgItem(IDOK)->IsWindowEnabled())&&(GetDlgItem(IDOK)->IsWindowVisible()))
778 // since we convert ESC to RETURN, make sure the OK button has the focus.
779 GetDlgItem(IDOK)->SetFocus();
780 pMsg->wParam = VK_RETURN;
784 else if (pMsg->message == WM_CONTEXTMENU || pMsg->message == WM_RBUTTONDOWN)
786 CWnd * pWnd = (CWnd*) GetDlgItem(IDC_LOG);
787 if (pWnd == GetFocus())
789 CIconMenu popup;
790 if (popup.CreatePopupMenu())
792 popup.AppendMenuIcon(WM_COPY, IDS_SCIEDIT_COPY, IDI_COPYCLIP);
793 if (m_Log.GetSelText().IsEmpty())
794 popup.EnableMenuItem(WM_COPY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
795 popup.AppendMenu(MF_SEPARATOR);
796 popup.AppendMenuIcon(EM_SETSEL, IDS_SCIEDIT_SELECTALL);
797 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, pMsg->pt.x, pMsg->pt.y, this);
798 switch (cmd)
800 case 0: // no command selected
801 break;
802 case EM_SETSEL:
803 case WM_COPY:
804 ::SendMessage(GetDlgItem(IDC_LOG)->GetSafeHwnd(), cmd, 0, -1);
805 break;
807 return TRUE;
811 return __super::PreTranslateMessage(pMsg);