1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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
23 #include "TortoiseProc.h"
24 #include "ProgressDlg.h"
25 #include "UnicodeUtils.h"
27 #include "LoglistCommonResource.h"
30 #include "SmartHandle.h"
31 #include "../TGitCache/CacheInterface.h"
32 #include "LoglistUtils.h"
34 #include "MessageBox.h"
36 #include "CmdLineParser.h"
38 // CProgressDlg dialog
40 IMPLEMENT_DYNAMIC(CProgressDlg
, CResizableStandAloneDialog
)
42 CProgressDlg::CProgressDlg(CWnd
* pParent
/*=NULL*/)
43 : CResizableStandAloneDialog(CProgressDlg::IDD
, pParent
)
44 , m_bShowCommand(true)
47 , m_startTick(GetTickCount())
53 m_GitStatus
= (DWORD
)-1;
54 int autoClose
= CRegDWORD(_T("Software\\TortoiseGit\\AutoCloseGitProgress"), 0);
55 CCmdLineParser
parser(AfxGetApp()->m_lpCmdLine
);
56 if (parser
.HasKey(_T("closeonend")))
57 autoClose
= parser
.GetLongVal(_T("closeonend"));
61 m_AutoClose
= AUTOCLOSE_IF_NO_OPTIONS
;
64 m_AutoClose
= AUTOCLOSE_IF_NO_ERRORS
;
67 m_AutoClose
= AUTOCLOSE_NO
;
72 CProgressDlg::~CProgressDlg()
80 void CProgressDlg::DoDataExchange(CDataExchange
* pDX
)
82 CDialog::DoDataExchange(pDX
);
83 DDX_Control(pDX
, IDC_CURRENT
, this->m_CurrentWork
);
84 DDX_Control(pDX
, IDC_TITLE_ANIMATE
, this->m_Animate
);
85 DDX_Control(pDX
, IDC_RUN_PROGRESS
, this->m_Progress
);
86 DDX_Control(pDX
, IDC_LOG
, this->m_Log
);
87 DDX_Control(pDX
, IDC_PROGRESS_BUTTON1
, this->m_ctrlPostCmd
);
90 BEGIN_MESSAGE_MAP(CProgressDlg
, CResizableStandAloneDialog
)
92 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI
, OnProgressUpdateUI
)
93 ON_BN_CLICKED(IDOK
, &CProgressDlg::OnBnClickedOk
)
94 ON_BN_CLICKED(IDC_PROGRESS_BUTTON1
,&CProgressDlg::OnBnClickedButton1
)
95 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED
, OnTaskbarBtnCreated
)
98 BOOL
CProgressDlg::OnInitDialog()
100 CResizableStandAloneDialog::OnInitDialog();
102 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
103 // do this, Explorer would be unable to send that message to our window if we
104 // were running elevated. It's OK to make the call all the time, since if we're
105 // not elevated, this is a no-op.
106 CHANGEFILTERSTRUCT cfs
= { sizeof(CHANGEFILTERSTRUCT
) };
107 typedef BOOL STDAPICALLTYPE
ChangeWindowMessageFilterExDFN(HWND hWnd
, UINT message
, DWORD action
, PCHANGEFILTERSTRUCT pChangeFilterStruct
);
108 CAutoLibrary hUser
= AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
111 ChangeWindowMessageFilterExDFN
*pfnChangeWindowMessageFilterEx
= (ChangeWindowMessageFilterExDFN
*)GetProcAddress(hUser
, "ChangeWindowMessageFilterEx");
112 if (pfnChangeWindowMessageFilterEx
)
114 pfnChangeWindowMessageFilterEx(m_hWnd
, WM_TASKBARBTNCREATED
, MSGFLT_ALLOW
, &cfs
);
117 m_pTaskbarList
.Release();
118 if (FAILED(m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
119 m_pTaskbarList
= nullptr;
121 AddAnchor(IDC_TITLE_ANIMATE
, TOP_LEFT
, TOP_RIGHT
);
122 AddAnchor(IDC_RUN_PROGRESS
, TOP_LEFT
,TOP_RIGHT
);
123 AddAnchor(IDC_LOG
, TOP_LEFT
,BOTTOM_RIGHT
);
125 AddAnchor(IDOK
,BOTTOM_RIGHT
);
126 AddAnchor(IDCANCEL
,BOTTOM_RIGHT
);
127 AddAnchor(IDC_PROGRESS_BUTTON1
,BOTTOM_LEFT
);
128 AddAnchor(IDC_CURRENT
,TOP_LEFT
);
130 this->GetDlgItem(IDC_PROGRESS_BUTTON1
)->ShowWindow(SW_HIDE
);
131 m_Animate
.Open(IDR_DOWNLOAD
);
134 CAppUtils::CreateFontForLogs(m_logFont
);
135 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
136 m_Log
.SetFont(&m_logFont
);
139 if ( !m_PreText
.IsEmpty() )
141 InitialText
= m_PreText
+ _T("\r\n");
144 if (m_bShowCommand
&& (!m_GitCmd
.IsEmpty() ))
146 InitialText
+= m_GitCmd
+_T("\r\n\r\n");
149 m_Log
.SetWindowTextW(InitialText
);
150 m_CurrentWork
.SetWindowTextW(_T(""));
152 EnableSaveRestore(_T("ProgressDlg"));
154 m_pThread
= AfxBeginThread(ProgressThreadEntry
, this, THREAD_PRIORITY_NORMAL
,0,CREATE_SUSPENDED
);
157 CMessageBox::Show(this->m_hWnd
, IDS_ERR_THREADSTARTFAILED
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
158 DialogEnableWindow(IDCANCEL
, TRUE
);
162 m_pThread
->m_bAutoDelete
= FALSE
;
163 m_pThread
->ResumeThread();
166 CString sWindowTitle
;
167 GetWindowText(sWindowTitle
);
168 CAppUtils::SetWindowTitle(m_hWnd
, m_Git
->m_CurrentDir
, sWindowTitle
);
170 // Make sure this dialog is shown in foreground (see issue #1536)
171 SetForegroundWindow();
176 static void EnsurePostMessage(CWnd
*pWnd
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
179 if (!pWnd
->PostMessage(Msg
, wParam
, lParam
))
181 if (GetLastError() == ERROR_NOT_ENOUGH_QUOTA
)
187 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": Message %d-%d could not be sent (error %d; %s)\n"), wParam
, lParam
, GetLastError(), (CString
)CFormatMessageWrapper());
191 UINT
CProgressDlg::ProgressThreadEntry(LPVOID pVoid
)
193 return ((CProgressDlg
*)pVoid
)->ProgressThread();
196 //static function, Share with SyncDialog
197 UINT
CProgressDlg::RunCmdList(CWnd
* pWnd
, STRING_VECTOR
& cmdlist
, STRING_VECTOR
& dirlist
, bool bShowCommand
, CString
* pfilename
, bool* bAbort
, CGitGuardedByteArray
* pdata
, CGit
* git
)
201 std::vector
<std::unique_ptr
<CBlockCacheForPath
>> cacheBlockList
;
202 std::vector
<std::unique_ptr
<CGit
>> gitList
;
204 cacheBlockList
.push_back(std::unique_ptr
<CBlockCacheForPath
>(new CBlockCacheForPath(git
->m_CurrentDir
)));
207 for (auto dir
: dirlist
)
209 CGit
*pGit
= new CGit
;
210 pGit
->m_CurrentDir
= dir
;
211 gitList
.push_back(std::unique_ptr
<CGit
>(pGit
));
212 cacheBlockList
.push_back(std::unique_ptr
<CBlockCacheForPath
>(new CBlockCacheForPath(dir
)));
216 EnsurePostMessage(pWnd
, MSG_PROGRESSDLG_UPDATE_UI
, MSG_PROGRESSDLG_START
, 0);
221 for (size_t i
= 0; i
< cmdlist
.size(); ++i
)
223 if(cmdlist
[i
].IsEmpty())
229 if (gitList
.empty() || gitList
.size() == 1 && gitList
[0]->m_CurrentDir
== git
->m_CurrentDir
)
230 str
= CUnicodeUtils::GetMulti(cmdlist
[i
].Trim() + _T("\r\n\r\n"), CP_UTF8
);
232 str
= CUnicodeUtils::GetMulti((i
> 0 ? _T("\r\n") : _T("")) + gitList
[i
]->m_CurrentDir
+ _T("\r\n") + cmdlist
[i
].Trim() + _T("\r\n\r\n"), CP_UTF8
);
233 for (int j
= 0; j
< str
.GetLength(); ++j
)
237 pdata
->m_critSec
.Lock();
238 pdata
->push_back(str
[j
]);
239 pdata
->m_critSec
.Unlock();
242 pWnd
->PostMessage(MSG_PROGRESSDLG_UPDATE_UI
,MSG_PROGRESSDLG_RUN
,str
[j
]);
245 pWnd
->PostMessage(MSG_PROGRESSDLG_UPDATE_UI
,MSG_PROGRESSDLG_RUN
,0);
248 PROCESS_INFORMATION pi
;
249 CAutoGeneralHandle hRead
;
250 int runAsyncRet
= -1;
252 runAsyncRet
= git
->RunAsync(cmdlist
[i
].Trim(), &pi
, hRead
.GetPointer(), nullptr, pfilename
);
254 runAsyncRet
= gitList
[i
]->RunAsync(cmdlist
[i
].Trim(), &pi
, hRead
.GetPointer(), nullptr, pfilename
);
257 EnsurePostMessage(pWnd
, MSG_PROGRESSDLG_UPDATE_UI
, MSG_PROGRESSDLG_FAILED
, -1 * runAsyncRet
);
261 CAutoGeneralHandle
piProcess(pi
.hProcess
);
262 CAutoGeneralHandle
piThread(pi
.hThread
);
264 char lastByte
= '\0';
267 while(ReadFile(hRead
,&byte
,1,&readnumber
,NULL
))
274 pdata
->m_critSec
.Lock();
275 if (byte
== '\n' && lastByte
!= '\r')
276 pdata
->push_back('\r');
277 pdata
->push_back( byte
);
279 pdata
->m_critSec
.Unlock();
281 if(byte
== '\r' || byte
== '\n')
282 pWnd
->PostMessage(MSG_PROGRESSDLG_UPDATE_UI
,MSG_PROGRESSDLG_RUN
,0);
285 pWnd
->PostMessage(MSG_PROGRESSDLG_UPDATE_UI
,MSG_PROGRESSDLG_RUN
,byte
);
289 pdata
->m_critSec
.Lock();
290 bool post
= !pdata
->empty();
291 pdata
->m_critSec
.Unlock();
293 EnsurePostMessage(pWnd
, MSG_PROGRESSDLG_UPDATE_UI
, MSG_PROGRESSDLG_RUN
, 0);
296 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": waiting for process to finish (%s), aborted: %d\n"), cmdlist
[i
], *bAbort
);
298 WaitForSingleObject(pi
.hProcess
, INFINITE
);
301 if(!GetExitCodeProcess(pi
.hProcess
,&status
) || *bAbort
)
303 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
);
305 EnsurePostMessage(pWnd
, MSG_PROGRESSDLG_UPDATE_UI
, MSG_PROGRESSDLG_FAILED
, status
);
306 return TGIT_GIT_ERROR_GET_EXIT_CODE
;
308 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": process %s finished with code %d\n"), cmdlist
[i
], status
);
312 EnsurePostMessage(pWnd
, MSG_PROGRESSDLG_UPDATE_UI
, MSG_PROGRESSDLG_END
, ret
);
317 UINT
CProgressDlg::ProgressThread()
320 m_GitCmdList
.push_back(m_GitCmd
);
324 if(m_LogFile
.IsEmpty())
327 pfilename
=&m_LogFile
;
329 m_startTick
= GetTickCount();
330 m_GitStatus
= RunCmdList(this, m_GitCmdList
, m_GitDirList
, m_bShowCommand
, pfilename
, &m_bAbort
, &this->m_Databuf
, m_Git
);
334 LRESULT
CProgressDlg::OnProgressUpdateUI(WPARAM wParam
,LPARAM lParam
)
336 if(wParam
== MSG_PROGRESSDLG_START
)
339 m_Animate
.Play(0, INT_MAX
, INT_MAX
);
340 DialogEnableWindow(IDCANCEL
, TRUE
);
343 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
344 m_pTaskbarList
->SetProgressValue(m_hWnd
, 0, 100);
347 if(wParam
== MSG_PROGRESSDLG_END
|| wParam
== MSG_PROGRESSDLG_FAILED
)
349 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": got message: %d\n"), wParam
);
350 DWORD tickSpent
= GetTickCount() - m_startTick
;
351 CString strEndTime
= CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE
, true, false);
355 m_Databuf
.m_critSec
.Lock();
356 m_Databuf
.push_back(0);
357 m_Log
.SetWindowText(Convert2UnionCode((char*)&m_Databuf
[0]));
358 m_Databuf
.m_critSec
.Unlock();
359 m_Log
.LineScroll(m_Log
.GetLineCount() - m_Log
.GetFirstVisibleLine() - 4);
362 m_Databuf
.m_critSec
.Lock();
363 this->m_Databuf
.clear();
364 m_Databuf
.m_critSec
.Unlock();
368 m_Progress
.SetPos(100);
369 this->DialogEnableWindow(IDOK
,TRUE
);
371 m_GitStatus
= (DWORD
)lParam
;
373 // detect crashes of perl when performing git svn actions
374 if (m_GitStatus
== 0 && m_GitCmd
.Find(_T(" svn ")) > 1)
377 m_Log
.GetWindowText(log
);
378 if (log
.GetLength() > 18 && log
.Mid(log
.GetLength() - 18) == _T("perl.exe.stackdump"))
379 m_GitStatus
= (DWORD
)-1;
382 if(this->m_GitStatus
)
386 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_ERROR
);
387 m_pTaskbarList
->SetProgressValue(m_hWnd
, 100, 100);
390 log
.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT
, m_GitStatus
);
392 if (CRegDWORD(_T("Software\\TortoiseGit\\ShowGitexeTimings"), TRUE
))
393 err
.Format(_T("\r\n\r\n%s (%lu ms @ %s)\r\n"), log
, tickSpent
, strEndTime
);
395 err
.Format(_T("\r\n\r\n%s\r\n"), log
);
396 InsertColorText(this->m_Log
, err
, RGB(255,0,0));
397 if (CRegDWORD(_T("Software\\TortoiseGit\\NoSounds"), FALSE
) == FALSE
)
398 PlaySound((LPCTSTR
)SND_ALIAS_SYSTEMEXCLAMATION
, NULL
, SND_ALIAS_ID
| SND_ASYNC
);
402 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
);
404 temp
.LoadString(IDS_SUCCESS
);
406 if (CRegDWORD(_T("Software\\TortoiseGit\\ShowGitexeTimings"), TRUE
))
407 log
.Format(_T("\r\n%s (%lu ms @ %s)\r\n"), temp
, tickSpent
, strEndTime
);
409 log
.Format(_T("\r\n%s\r\n"), temp
);
410 InsertColorText(this->m_Log
, log
, RGB(0,0,255));
411 this->DialogEnableWindow(IDCANCEL
,FALSE
);
414 if (wParam
== MSG_PROGRESSDLG_END
)
416 if (m_PostCmdCallback
) // new handling method using callback
418 m_PostCmdCallback(m_GitStatus
, m_PostCmdList
);
420 if (!m_PostCmdList
.empty())
422 for (auto it
= m_PostCmdList
.cbegin(); it
!= m_PostCmdList
.cend(); ++it
)
423 m_ctrlPostCmd
.AddEntry((*it
).icon
, (*it
).label
);
424 GetDlgItem(IDC_PROGRESS_BUTTON1
)->ShowWindow(SW_SHOW
);
429 if(wParam
== MSG_PROGRESSDLG_END
&& m_GitStatus
== 0)
431 if (m_AutoClose
== AUTOCLOSE_IF_NO_OPTIONS
&& m_PostCmdList
.empty() || m_AutoClose
== AUTOCLOSE_IF_NO_ERRORS
)
432 PostMessage(WM_COMMAND
, 1, (LPARAM
)GetDlgItem(IDOK
)->m_hWnd
);
440 m_Databuf
.m_critSec
.Lock();
441 for (size_t i
= this->m_BufStart
; i
< this->m_Databuf
.size(); ++i
)
443 char c
= this->m_Databuf
[m_BufStart
];
445 m_Databuf
.m_critSec
.Unlock();
448 m_Databuf
.m_critSec
.Lock();
453 m_Databuf
.erase(m_Databuf
.begin(), m_Databuf
.begin()+m_BufStart
);
456 m_Databuf
.m_critSec
.Unlock();
460 ParserCmdOutput((char)lParam
);
465 //static function, Share with SyncDialog
466 int CProgressDlg::FindPercentage(CString
&log
)
468 int s1
=log
.Find(_T('%'));
473 for(int i
=s1
-1;i
>=0;i
--)
475 if(log
[i
]>=_T('0') && log
[i
]<=_T('9'))
480 return _ttol(log
.Mid(s2
,s1
-s2
));
483 void CProgressDlg::ParserCmdOutput(char ch
)
485 ParserCmdOutput(this->m_Log
,this->m_Progress
,this->m_hWnd
,this->m_pTaskbarList
,this->m_LogTextA
,ch
,&this->m_CurrentWork
);
487 void CProgressDlg::ClearESC(CString
&str
)
489 // see http://ascii-table.com/ansi-escape-sequences.php and http://tldp.org/HOWTO/Bash-Prompt-HOWTO/c327.html
490 str
.Replace(_T("\033[K"), _T("")); // erase until end of line; no need to care for this, because we always clear the whole line
495 int escapePosition
= str
.Find(_T('\033'));
496 if (escapePosition
>= 0 && str
.GetLength() >= escapePosition
+ 3)
498 if (str
.Mid(escapePosition
, 2) == _T("\033["))
500 int colorEnd
= str
.Find(_T('m'), escapePosition
+ 2);
504 for (int i
= escapePosition
+ 2; i
< colorEnd
; ++i
)
506 if (str
[i
] != _T(';') && (str
[i
] < _T('0') && str
[i
] > _T('9')))
514 if (escapePosition
> 0)
515 str
= str
.Left(escapePosition
) + str
.Mid(colorEnd
+ 1);
517 str
= str
.Mid(colorEnd
);
526 void CProgressDlg::ParserCmdOutput(CRichEditCtrl
&log
,CProgressCtrl
&progressctrl
,HWND m_hWnd
,CComPtr
<ITaskbarList3
> m_pTaskbarList
,CStringA
&oneline
, char ch
, CWnd
*CurrentWork
)
528 //TRACE(_T("%c"),ch);
529 if( ch
== ('\r') || ch
== ('\n'))
531 CString str
= CUnicodeUtils::GetUnicode(oneline
);
533 // TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));
534 // TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));
536 int lines
= log
.GetLineCount();
538 // TRACE(_T("%s"), str);
544 int start
=log
.LineIndex(lines
-1);
545 log
.SetSel(start
, log
.GetTextLength());
550 int length
= log
.GetWindowTextLength();
551 log
.SetSel(length
, length
);
553 log
.ReplaceSel(_T("\r\n") + str
);
558 if (lines
> 500) //limited log length
560 int end
=log
.LineIndex(1);
562 log
.ReplaceSel(_T(""));
564 log
.LineScroll(log
.GetLineCount() - log
.GetFirstVisibleLine() - 4);
566 int s1
=oneline
.ReverseFind(_T(':'));
567 int s2
=oneline
.Find(_T('%'));
568 if (s1
> 0 && s2
> 0)
571 CurrentWork
->SetWindowTextW(str
.Left(s1
));
573 int pos
=FindPercentage(str
);
574 TRACE(_T("Pos %d\r\n"),pos
);
577 progressctrl
.SetPos(pos
);
580 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
581 m_pTaskbarList
->SetProgressValue(m_hWnd
, pos
, 100);
594 void CProgressDlg::RemoveLastLine(CString
&str
)
597 start
=str
.ReverseFind(_T('\n'));
602 // CProgressDlg message handlers
604 void CProgressDlg::WriteLog() const
606 CLogFile
logfile(g_Git
.m_CurrentDir
);
609 logfile
.AddTimeLine();
610 CString text
= GetLogText();
611 LPCTSTR psz_string
= text
;
614 if (*psz_string
== '\r')
619 size_t i_len
= wcscspn(psz_string
, L
"\n");
620 logfile
.AddLine(CString(psz_string
, (int)i_len
));
622 if (*psz_string
== '\n')
628 canceled
.LoadString(IDS_USERCANCELLED
);
629 logfile
.AddLine(canceled
);
635 void CProgressDlg::OnBnClickedOk()
637 if (m_pThread
) // added here because Close-button is "called" from thread by PostMessage
638 ::WaitForSingleObject(m_pThread
->m_hThread
, 5000);
639 m_Log
.GetWindowText(this->m_LogText
);
644 void CProgressDlg::OnBnClickedButton1()
648 m_PostCmdList
.at(m_ctrlPostCmd
.GetCurrentEntry()).action();
652 void CProgressDlg::OnClose()
654 DialogEnableWindow(IDCANCEL
, TRUE
);
658 void CProgressDlg::OnCancel()
660 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) _T(": User canceled\n"));
665 CResizableStandAloneDialog::OnCancel();
669 if( m_Git
->m_CurrentGitPi
.hProcess
)
671 DWORD dwConfirmKillProcess
= CRegDWORD(_T("Software\\TortoiseGit\\ConfirmKillProcess"));
672 if (dwConfirmKillProcess
&& CMessageBox::Show(m_hWnd
, IDS_PROC_CONFIRMKILLPROCESS
, IDS_APPNAME
, MB_YESNO
| MB_ICONQUESTION
) != IDYES
)
674 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT
,0))
676 ::WaitForSingleObject(m_Git
->m_CurrentGitPi
.hProcess
,10000);
679 KillProcessTree(m_Git
->m_CurrentGitPi
.dwProcessId
);
682 ::WaitForSingleObject(m_Git
->m_CurrentGitPi
.hProcess
,10000);
684 ::WaitForSingleObject(m_pThread
->m_hThread
, 5000);
686 CResizableStandAloneDialog::OnCancel();
689 void CProgressDlg::KillProcessTree(DWORD dwProcessId
, unsigned int depth
)
691 // recursively kills a process tree
692 // This is not optimized, but works and isn't called very often ;)
694 if (!dwProcessId
|| depth
> 20)
698 memset(&pe
, 0, sizeof(PROCESSENTRY32
));
699 pe
.dwSize
= sizeof(PROCESSENTRY32
);
701 CAutoGeneralHandle hSnap
= ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0);
703 if (::Process32First(hSnap
, &pe
))
707 if (pe
.th32ParentProcessID
== dwProcessId
)
708 KillProcessTree(pe
.th32ProcessID
, depth
+ 1);
709 } while (::Process32Next(hSnap
, &pe
));
711 CAutoGeneralHandle hProc
= ::OpenProcess(PROCESS_TERMINATE
, FALSE
, dwProcessId
);
713 ::TerminateProcess(hProc
, 1);
717 void CProgressDlg::InsertColorText(CRichEditCtrl
&edit
,CString text
,COLORREF rgb
)
720 edit
.GetDefaultCharFormat(cf
);
722 cf
.dwMask
|=CFM_COLOR
;
724 cf
.dwEffects
|=CFE_BOLD
;
725 cf
.dwEffects
&= ~CFE_AUTOCOLOR
;
726 edit
.SetSel(edit
.GetTextLength()-1,edit
.GetTextLength());
727 edit
.ReplaceSel(text
);
728 edit
.SetSel(edit
.LineIndex(edit
.GetLineCount()-2),edit
.GetTextLength());
729 edit
.SetSelectionCharFormat(cf
);
730 edit
.SetSel(edit
.GetTextLength(),edit
.GetTextLength());
731 edit
.SetDefaultCharFormat(old
);
732 edit
.LineScroll(edit
.GetLineCount() - edit
.GetFirstVisibleLine() - 4);
735 CString
CCommitProgressDlg::Convert2UnionCode(char *buff
, int size
)
739 size
= (int)strlen(buff
);
741 for (int i
= 0; i
< size
; ++i
)
745 if( start
>0 && buff
[i
] =='\n' )
753 CGit::StringAppend(&str
, (BYTE
*)buff
, g_Git
.m_LogEncode
, start
);
754 CGit::StringAppend(&str
, (BYTE
*)buff
+ start
, CP_UTF8
, size
- start
);
761 LRESULT
CProgressDlg::OnTaskbarBtnCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
763 m_pTaskbarList
.Release();
764 m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
);
765 SetUUIDOverlayIcon(m_hWnd
);
769 BOOL
CProgressDlg::PreTranslateMessage(MSG
* pMsg
)
771 if (pMsg
->message
== WM_KEYDOWN
)
773 if (pMsg
->wParam
== VK_ESCAPE
)
775 // pressing the ESC key should close the dialog. But since we disabled the escape
776 // key (so the user doesn't get the idea that he could simply undo an e.g. update)
778 // So if the user presses the ESC key, change it to VK_RETURN so the dialog gets
779 // the impression that the OK button was pressed.
780 if ((!GetDlgItem(IDCANCEL
)->IsWindowEnabled())
781 &&(GetDlgItem(IDOK
)->IsWindowEnabled())&&(GetDlgItem(IDOK
)->IsWindowVisible()))
783 // since we convert ESC to RETURN, make sure the OK button has the focus.
784 GetDlgItem(IDOK
)->SetFocus();
785 pMsg
->wParam
= VK_RETURN
;
789 else if (pMsg
->message
== WM_CONTEXTMENU
|| pMsg
->message
== WM_RBUTTONDOWN
)
791 CWnd
* pWnd
= (CWnd
*) GetDlgItem(IDC_LOG
);
792 if (pWnd
== GetFocus())
795 if (popup
.CreatePopupMenu())
797 long start
= -1, end
= -1;
798 auto pEdit
= (CRichEditCtrl
*)GetDlgItem(IDC_LOG
);
799 pEdit
->GetSel(start
, end
);
800 popup
.AppendMenuIcon(WM_COPY
, IDS_SCIEDIT_COPY
, IDI_COPYCLIP
);
802 popup
.EnableMenuItem(WM_COPY
, MF_BYCOMMAND
| MF_DISABLED
| MF_GRAYED
);
803 popup
.AppendMenu(MF_SEPARATOR
);
804 popup
.AppendMenuIcon(EM_SETSEL
, IDS_STATUSLIST_CONTEXT_COPYEXT
, IDI_COPYCLIP
);
805 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
, pMsg
->pt
.x
, pMsg
->pt
.y
, this);
808 case 0: // no command selected
812 pEdit
->SetRedraw(FALSE
);
813 int oldLine
= pEdit
->GetFirstVisibleLine();
814 pEdit
->SetSel(0, -1);
816 pEdit
->SetSel(start
, end
);
817 int newLine
= pEdit
->GetFirstVisibleLine();
818 pEdit
->LineScroll(oldLine
- newLine
);
819 pEdit
->SetRedraw(TRUE
);
820 pEdit
->RedrawWindow();
824 ::SendMessage(GetDlgItem(IDC_LOG
)->GetSafeHwnd(), cmd
, 0, -1);
831 return __super::PreTranslateMessage(pMsg
);