Fix tortoiseshell build error and fix ESC[F at progressdlg
[TortoiseGit.git] / src / TortoiseProc / ProgressDlg.cpp
blobd11a2ccb079dbbe8182f5129e5d927f4384b242c
1 // ProgressDlg.cpp : implementation file
2 //
4 #include "stdafx.h"
5 #include "TortoiseProc.h"
6 #include "ProgressDlg.h"
7 #include "Git.h"
8 #include "atlconv.h"
9 #include "UnicodeUtils.h"
10 // CProgressDlg dialog
12 IMPLEMENT_DYNAMIC(CProgressDlg, CResizableStandAloneDialog)
14 CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)
15 : CResizableStandAloneDialog(CProgressDlg::IDD, pParent), m_bShowCommand(true), m_bAutoCloseOnSuccess(false), m_bAbort(false), m_bDone(false)
17 m_pThread = NULL;
18 m_bAltAbortPress=false;
19 m_bBufferAll=false;
22 CProgressDlg::~CProgressDlg()
24 if(m_pThread != NULL)
26 delete m_pThread;
30 void CProgressDlg::DoDataExchange(CDataExchange* pDX)
32 CDialog::DoDataExchange(pDX);
33 DDX_Control(pDX, IDC_CURRENT, this->m_CurrentWork);
34 DDX_Control(pDX, IDC_TITLE_ANIMATE, this->m_Animate);
35 DDX_Control(pDX, IDC_RUN_PROGRESS, this->m_Progress);
36 DDX_Control(pDX, IDC_LOG, this->m_Log);
37 DDX_Control(pDX, IDC_PROGRESS_BUTTON1, this->m_ctrlPostCmd);
41 BEGIN_MESSAGE_MAP(CProgressDlg, CResizableStandAloneDialog)
42 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
43 ON_BN_CLICKED(IDOK, &CProgressDlg::OnBnClickedOk)
44 ON_BN_CLICKED(IDC_PROGRESS_BUTTON1,&CProgressDlg::OnBnClickedButton1)
45 END_MESSAGE_MAP()
47 BOOL CProgressDlg::OnInitDialog()
49 CResizableStandAloneDialog::OnInitDialog();
51 AddAnchor(IDC_TITLE_ANIMATE, TOP_LEFT, TOP_RIGHT);
52 AddAnchor(IDC_RUN_PROGRESS, TOP_LEFT,TOP_RIGHT);
53 AddAnchor(IDC_LOG, TOP_LEFT,BOTTOM_RIGHT);
55 AddAnchor(IDOK,BOTTOM_RIGHT);
56 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
57 AddAnchor(IDC_PROGRESS_BUTTON1,BOTTOM_LEFT);
58 AddAnchor(IDC_CURRENT,TOP_LEFT);
60 this->GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_HIDE);
61 m_Animate.Open(IDR_DOWNLOAD);
63 CString InitialText;
64 if ( !m_PreText.IsEmpty() )
66 InitialText = m_PreText + _T("\r\n");
68 #if 0
69 if (m_bShowCommand && (!m_GitCmd.IsEmpty() ))
71 InitialText += m_GitCmd+_T("\r\n\r\n");
73 #endif
74 m_Log.SetWindowTextW(InitialText);
75 m_CurrentWork.SetWindowTextW(_T(""));
77 EnableSaveRestore(_T("ProgressDlg"));
79 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
80 if (m_pThread==NULL)
82 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
84 else
86 m_pThread->m_bAutoDelete = FALSE;
87 m_pThread->ResumeThread();
90 if(!m_Title.IsEmpty())
91 this->SetWindowText(m_Title);
93 if(m_PostCmdList.GetCount()>0)
94 m_ctrlPostCmd.AddEntries(m_PostCmdList);
96 return TRUE;
99 UINT CProgressDlg::ProgressThreadEntry(LPVOID pVoid)
101 return ((CProgressDlg*)pVoid)->ProgressThread();
104 //static function, Share with SyncDialog
105 UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,CGitByteArray *pdata)
107 UINT ret=0;
109 PROCESS_INFORMATION pi;
110 HANDLE hRead;
112 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_START,0);
114 if(pdata)
115 pdata->clear();
117 for(int i=0;i<cmdlist.size();i++)
119 if(cmdlist[i].IsEmpty())
120 continue;
122 if (bShowCommand)
124 CString str;
125 str+= cmdlist[i]+_T("\n\n");
126 for(int j=0;j<str.GetLength();j++)
128 if(pdata)
130 pdata->m_critSec.Lock();
131 pdata->push_back(str[j]);
132 pdata->m_critSec.Unlock();
134 else
135 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);
137 if(pdata)
138 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
141 g_Git.RunAsync(cmdlist[i],&pi, &hRead,pfilename);
143 DWORD readnumber;
144 char byte;
145 CString output;
146 while(ReadFile(hRead,&byte,1,&readnumber,NULL))
148 if(pdata)
150 if(byte == 0)
151 byte = '\n';
153 pdata->m_critSec.Lock();
154 pdata->push_back( byte);
155 pdata->m_critSec.Unlock();
157 if(byte == '\r' || byte == '\n')
158 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
159 }else
160 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,byte);
163 CloseHandle(pi.hThread);
165 WaitForSingleObject(pi.hProcess, INFINITE);
167 DWORD status=0;
168 if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)
170 CloseHandle(pi.hProcess);
172 CloseHandle(hRead);
174 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_FAILED,0);
175 return GIT_ERROR_GET_EXIT_CODE;
177 ret |= status;
180 CloseHandle(pi.hProcess);
182 CloseHandle(hRead);
184 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_END,0);
186 return ret;
190 UINT CProgressDlg::ProgressThread()
193 m_GitCmdList.push_back(m_GitCmd);
195 CString *pfilename;
197 if(m_LogFile.IsEmpty())
198 pfilename=NULL;
199 else
200 pfilename=&m_LogFile;
202 m_GitStatus = RunCmdList(this,m_GitCmdList,m_bShowCommand,pfilename,&m_bAbort,&this->m_Databuf);;
203 return 0;
206 LRESULT CProgressDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
208 if(wParam == MSG_PROGRESSDLG_START)
210 m_BufStart = 0 ;
211 m_Animate.Play(0,-1,-1);
212 this->DialogEnableWindow(IDOK,FALSE);
214 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
216 if(m_bBufferAll)
218 m_Databuf.m_critSec.Lock();
219 m_Databuf.push_back(0);
220 m_Databuf.m_critSec.Unlock();
221 InsertCRLF();
222 m_Databuf.m_critSec.Lock();
223 m_Log.SetWindowText(Convert2UnionCode((char*)&m_Databuf[0]));
224 m_Databuf.m_critSec.Unlock();
225 m_Log.LineScroll(m_Log.GetLineCount() - m_Log.GetFirstVisibleLine() - 4);
227 m_BufStart=0;
228 m_Databuf.m_critSec.Lock();
229 this->m_Databuf.clear();
230 m_Databuf.m_critSec.Unlock();
232 m_bDone = true;
233 m_Animate.Stop();
234 m_Progress.SetPos(100);
235 this->DialogEnableWindow(IDOK,TRUE);
237 CString err;
238 err.Format(_T("\r\nFailed 0x%x(git return wrong reture code at sometime )\r\n"),m_GitStatus);
239 if(this->m_GitStatus)
241 //InsertColorText(this->m_Log,err,RGB(255,0,0));
243 else
244 InsertColorText(this->m_Log,_T("\r\nSuccess\r\n"),RGB(0,0,255));
246 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)
248 if(m_bAutoCloseOnSuccess)
249 EndDialog(IDOK);
251 if(m_PostCmdList.GetCount() > 0)
253 //GetDlgItem(IDC_PROGRESS_BUTTON1)->SetWindowText(m_changeAbortButtonOnSuccessTo);
254 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
255 //GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE);
256 //Set default button is "close" rather than "push"
257 this->SendMessage(WM_NEXTDLGCTL, (WPARAM)GetDlgItem(IDOK)->m_hWnd, TRUE);
259 else
260 DialogEnableWindow(IDCANCEL, FALSE);
262 else
263 DialogEnableWindow(IDCANCEL, FALSE);
266 if(!m_bBufferAll)
268 if(lParam == 0)
270 m_Databuf.m_critSec.Lock();
271 for(int i=this->m_BufStart;i<this->m_Databuf.size();i++)
273 char c = this->m_Databuf[m_BufStart];
274 m_BufStart++;
275 m_Databuf.m_critSec.Unlock();
277 ParserCmdOutput(c);
279 m_Databuf.m_critSec.Lock();
282 if(m_BufStart>1000)
284 m_Databuf.empty();
285 m_BufStart =0;
287 m_Databuf.m_critSec.Unlock();
289 }else
290 ParserCmdOutput((char)lParam);
292 return 0;
295 //static function, Share with SyncDialog
296 int CProgressDlg::FindPercentage(CString &log)
298 int s1=log.Find(_T('%'));
299 if(s1<0)
300 return -1;
302 int s2=s1-1;
303 for(int i=s1-1;i>=0;i--)
305 if(log[i]>=_T('0') && log[i]<=_T('9'))
306 s2=i;
307 else
308 break;
310 return _ttol(log.Mid(s2,s1-s2));
313 #if 0
314 void CProgressDlg::ParserCmdOutput(TCHAR ch)
316 TRACE(_T("%c"),ch);
317 if( ch == _T('\r') || ch == _T('\n'))
319 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));
320 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));
322 int lines=m_Log.GetLineCount();
324 if(ch == _T('\r'))
326 int start=m_Log.LineIndex(lines-1);
327 int length=m_Log.LineLength(lines-1);
328 m_Log.SetSel( start,start+length);
329 m_Log.ReplaceSel(m_LogText);
331 }else
333 m_Log.SetSel(m_Log.GetWindowTextLength(),
334 m_Log.GetWindowTextLength());
335 m_Log.ReplaceSel(CString(_T("\r\n"))+m_LogText);
338 if( lines > 500 ) //limited log length
340 int end=m_Log.LineIndex(1);
341 m_Log.SetSel(0,end);
342 m_Log.ReplaceSel(_T(""));
344 m_Log.LineScroll(m_Log.GetLineCount());
346 int s1=m_LogText.Find(_T(':'));
347 int s2=m_LogText.Find(_T('%'));
348 if(s1>0 && s2>0)
350 this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));
351 int pos=FindPercentage(m_LogText);
352 TRACE(_T("Pos %d\r\n"),pos);
353 if(pos>0)
354 this->m_Progress.SetPos(pos);
357 m_LogText=_T("");
359 }else
361 m_LogText+=ch;
365 #endif
367 void CProgressDlg::ParserCmdOutput(char ch)
369 ParserCmdOutput(this->m_Log,this->m_Progress,this->m_LogTextA,ch,&this->m_CurrentWork);
371 void CProgressDlg::ClearESC(CStringA &str)
373 int start=0;
374 str.Replace("\033[K","");
376 void CProgressDlg::ParserCmdOutput(CRichEditCtrl &log,CProgressCtrl &progressctrl,CStringA &oneline, char ch, CWnd *CurrentWork)
378 //TRACE(_T("%c"),ch);
379 TRACE(_T("%c"),ch);
380 CString str;
381 if( ch == ('\r') || ch == ('\n'))
383 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));
384 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));
386 ClearESC(oneline);
388 int lines=log.GetLineCount();
389 g_Git.StringAppend(&str,(BYTE*)oneline.GetBuffer(),CP_ACP);
391 if(ch == ('\r'))
393 int start=log.LineIndex(lines-1);
394 int length=log.LineLength(lines-1);
395 log.SetSel( start,start+length);
396 log.ReplaceSel(str);
398 }else
400 log.SetSel(log.GetWindowTextLength(),
401 log.GetWindowTextLength());
402 log.ReplaceSel(CString(_T("\r\n"))+str);
405 if( lines > 500 ) //limited log length
407 int end=log.LineIndex(1);
408 log.SetSel(0,end);
409 log.ReplaceSel(_T(""));
411 log.LineScroll(log.GetLineCount() - log.GetFirstVisibleLine() - 4);
413 int s1=oneline.Find(_T(':'));
414 int s2=oneline.Find(_T('%'));
415 if(s1>0 && s2>0)
417 if(CurrentWork)
418 CurrentWork->SetWindowTextW(str.Left(s1));
420 int pos=FindPercentage(str);
421 TRACE(_T("Pos %d\r\n"),pos);
422 if(pos>0)
423 progressctrl.SetPos(pos);
426 oneline="";
428 }else
430 oneline+=ch;
434 void CProgressDlg::RemoveLastLine(CString &str)
436 int start;
437 start=str.ReverseFind(_T('\n'));
438 if(start>0)
439 str=str.Left(start);
440 return;
442 // CProgressDlg message handlers
444 void CProgressDlg::OnBnClickedOk()
446 // TODO: Add your control notification handler code here
447 m_Log.GetWindowText(this->m_LogText);
448 OnOK();
451 void CProgressDlg::OnBnClickedButton1()
453 this->EndDialog(IDC_PROGRESS_BUTTON1 + this->m_ctrlPostCmd.GetCurrentEntry());
456 void CProgressDlg::OnCancel()
458 m_bAbort = true;
459 if(m_bDone)
461 CResizableStandAloneDialog::OnCancel();
462 return;
465 if( g_Git.m_CurrentGitPi.hProcess )
467 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))
469 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
470 }else
472 int error=::GetLastError();
475 HANDLE hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE,g_Git.m_CurrentGitPi.dwProcessId);
476 if( hProcessHandle )
477 if(!::TerminateProcess(hProcessHandle,-1) )
479 int error =::GetLastError();
483 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
484 CResizableStandAloneDialog::OnCancel();
488 void CProgressDlg::InsertCRLF()
490 m_Databuf.m_critSec.Lock();
491 for(int i=0;i<m_Databuf.size();i++)
493 if(m_Databuf[i]==('\n'))
495 if(i==0 || m_Databuf[i-1]!= ('\r'))
497 m_Databuf.insert(m_Databuf.begin()+i,('\r'));
498 i++;
502 m_Databuf.m_critSec.Unlock();
505 void CProgressDlg::InsertColorText(CRichEditCtrl &edit,CString text,COLORREF rgb)
507 CHARFORMAT old,cf;
508 edit.GetDefaultCharFormat(cf);
509 old=cf;
510 cf.dwMask|=CFM_COLOR;
511 cf.crTextColor=rgb;
512 cf.dwEffects|=CFE_BOLD;
513 cf.dwEffects &= ~CFE_AUTOCOLOR ;
514 edit.SetSel(edit.GetTextLength()-1,edit.GetTextLength());
515 edit.ReplaceSel(text);
516 edit.SetSel(edit.LineIndex(edit.GetLineCount()-2),edit.GetTextLength());
517 edit.SetSelectionCharFormat(cf);
518 edit.SetSel(edit.GetTextLength(),edit.GetTextLength());
519 edit.SetDefaultCharFormat(old);
520 edit.LineScroll(edit.GetLineCount() - edit.GetFirstVisibleLine() - 4);
523 CString CCommitProgressDlg::Convert2UnionCode(char *buff, int size)
525 CString str;
527 CString cmd,output;
528 int cp=CP_UTF8;
530 cmd=_T("git.exe config i18n.logOutputEncoding");
531 if(g_Git.Run(cmd,&output,CP_ACP))
532 cp=CP_UTF8;
534 int start=0;
535 output=output.Tokenize(_T("\n"),start);
536 cp=CUnicodeUtils::GetCPCode(output);
538 start =0;
539 if(size == -1)
540 size=strlen(buff);
542 for(int i=0;i<size;i++)
544 if(buff[i] == ']')
545 start = i;
546 if( start >0 && buff[i] =='\n' )
548 start =i;
549 break;
553 str.Empty();
554 g_Git.StringAppend(&str, (BYTE*)buff, cp, start);
555 g_Git.StringAppend(&str, (BYTE*)buff+start, CP_ACP,size - start);
557 return str;