OSDN Git Service

Fix crash when input character at filter box
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / ProgressDlg.cpp
1 // ProgressDlg.cpp : implementation file\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "TortoiseProc.h"\r
6 #include "ProgressDlg.h"\r
7 #include "Git.h"\r
8 #include "atlconv.h"\r
9 // CProgressDlg dialog\r
10 \r
11 IMPLEMENT_DYNAMIC(CProgressDlg, CResizableStandAloneDialog)\r
12 \r
13 CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)\r
14         : CResizableStandAloneDialog(CProgressDlg::IDD, pParent), m_bShowCommand(true), m_bAutoCloseOnSuccess(false), m_bAbort(false), m_bDone(false)\r
15 {\r
16         m_pThread = NULL;\r
17         m_bAltAbortPress=false;\r
18         m_bBufferAll=false;\r
19 }\r
20 \r
21 CProgressDlg::~CProgressDlg()\r
22 {\r
23         if(m_pThread != NULL)\r
24         {\r
25                 delete m_pThread;\r
26         }\r
27 }\r
28 \r
29 void CProgressDlg::DoDataExchange(CDataExchange* pDX)\r
30 {\r
31         CDialog::DoDataExchange(pDX);\r
32         DDX_Control(pDX, IDC_CURRENT, this->m_CurrentWork);\r
33         DDX_Control(pDX, IDC_TITLE_ANIMATE, this->m_Animate);\r
34         DDX_Control(pDX, IDC_RUN_PROGRESS, this->m_Progress);\r
35         DDX_Control(pDX, IDC_LOG, this->m_Log);\r
36 }\r
37 \r
38 \r
39 BEGIN_MESSAGE_MAP(CProgressDlg, CResizableStandAloneDialog)\r
40         ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)\r
41         ON_BN_CLICKED(IDOK, &CProgressDlg::OnBnClickedOk)\r
42         ON_BN_CLICKED(IDC_PROGRESS_BUTTON1,&CProgressDlg::OnBnClickedButton1)\r
43 END_MESSAGE_MAP()\r
44 \r
45 BOOL CProgressDlg::OnInitDialog()\r
46 {\r
47         CResizableStandAloneDialog::OnInitDialog();\r
48 \r
49         AddAnchor(IDC_TITLE_ANIMATE, TOP_LEFT, TOP_RIGHT);\r
50         AddAnchor(IDC_RUN_PROGRESS, TOP_LEFT,TOP_RIGHT);\r
51         AddAnchor(IDC_LOG, TOP_LEFT,BOTTOM_RIGHT);\r
52 \r
53         AddAnchor(IDOK,BOTTOM_RIGHT);\r
54         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
55         AddAnchor(IDC_PROGRESS_BUTTON1,BOTTOM_RIGHT);\r
56 \r
57         this->GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_HIDE);\r
58         m_Animate.Open(IDR_DOWNLOAD);\r
59         \r
60         CString InitialText;\r
61         if ( !m_PreText.IsEmpty() )\r
62         {\r
63                 InitialText = m_PreText + _T("\r\n");\r
64         }\r
65 #if 0\r
66         if (m_bShowCommand && (!m_GitCmd.IsEmpty() ))\r
67         {\r
68                 InitialText += m_GitCmd+_T("\r\n\r\n");\r
69         }\r
70 #endif\r
71         m_Log.SetWindowTextW(InitialText);\r
72         m_CurrentWork.SetWindowTextW(_T(""));\r
73 \r
74         m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
75         if (m_pThread==NULL)\r
76         {\r
77 //              ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));\r
78         }\r
79         else\r
80         {\r
81                 m_pThread->m_bAutoDelete = FALSE;\r
82                 m_pThread->ResumeThread();\r
83         }\r
84 \r
85         if(!m_Title.IsEmpty())\r
86                 this->SetWindowText(m_Title);\r
87         return TRUE;\r
88 }\r
89 \r
90 UINT CProgressDlg::ProgressThreadEntry(LPVOID pVoid)\r
91 {\r
92         return ((CProgressDlg*)pVoid)->ProgressThread();\r
93 }\r
94 \r
95 //static function, Share with SyncDialog\r
96 UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,std::vector<TCHAR>*pdata)\r
97 {\r
98         UINT ret=0;\r
99 \r
100         PROCESS_INFORMATION pi;\r
101         HANDLE hRead;\r
102 \r
103         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_START,0);\r
104 \r
105         if(pdata)\r
106                 pdata->clear();\r
107                  \r
108         for(int i=0;i<cmdlist.size();i++)\r
109         {\r
110                 if(cmdlist[i].IsEmpty())\r
111                         continue;\r
112 \r
113                 if (bShowCommand)\r
114                 {\r
115                         CString str;\r
116                         str+= cmdlist[i]+_T("\n\n");\r
117                         for(int j=0;j<str.GetLength();j++)\r
118                         {\r
119                                 if(pdata)\r
120                                         pdata->push_back(str[j]);\r
121                                 else\r
122                                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);\r
123                         }\r
124                         if(pdata)\r
125                                 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);\r
126                 }\r
127 \r
128                 g_Git.RunAsync(cmdlist[i],&pi, &hRead,pfilename);\r
129 \r
130                 DWORD readnumber;\r
131                 char buffer[2];\r
132                 CString output;\r
133                 while(ReadFile(hRead,buffer,1,&readnumber,NULL))\r
134                 {\r
135                         buffer[readnumber]=0;\r
136                         \r
137                         if(pdata)\r
138                         {\r
139                                 pdata->push_back((TCHAR)buffer[0]);\r
140 \r
141                                 if(buffer[0] == '\r' || buffer[0] == '\n')\r
142                                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);\r
143                         }else\r
144                                 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,buffer[0]);\r
145                 }\r
146         \r
147                 CloseHandle(pi.hThread);\r
148 \r
149                 WaitForSingleObject(pi.hProcess, INFINITE);\r
150                 \r
151                 DWORD status=0;\r
152                 if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)\r
153                 {\r
154                         CloseHandle(pi.hProcess);\r
155 \r
156                         CloseHandle(hRead);\r
157 \r
158                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_FAILED,0);\r
159                         return GIT_ERROR_GET_EXIT_CODE;\r
160                 }\r
161                 ret |= status;\r
162         }\r
163 \r
164         CloseHandle(pi.hProcess);\r
165 \r
166         CloseHandle(hRead);\r
167 \r
168         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_END,0);\r
169 \r
170         return ret;\r
171 \r
172 }\r
173 \r
174 UINT CProgressDlg::ProgressThread()\r
175 {\r
176         \r
177         m_GitCmdList.push_back(m_GitCmd);\r
178 \r
179         CString *pfilename;\r
180 \r
181         if(m_LogFile.IsEmpty())\r
182                 pfilename=NULL;\r
183         else\r
184                 pfilename=&m_LogFile;   \r
185 \r
186         m_GitStatus = RunCmdList(this,m_GitCmdList,m_bShowCommand,pfilename,&m_bAbort,&this->m_Databuf);;\r
187         return 0;\r
188 }\r
189 \r
190 LRESULT CProgressDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)\r
191 {\r
192         if(wParam == MSG_PROGRESSDLG_START)\r
193         {\r
194                 m_BufStart = 0 ;\r
195                 m_Animate.Play(0,-1,-1);\r
196                 this->DialogEnableWindow(IDOK,FALSE);\r
197         }\r
198         if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)\r
199         {\r
200                 if(m_bBufferAll)\r
201                 {\r
202                         m_Databuf.push_back(0);\r
203                         InsertCRLF();\r
204                         m_Log.SetWindowText(&m_Databuf[0]);\r
205                 }\r
206                 m_BufStart=0;\r
207                 this->m_Databuf.clear();\r
208 \r
209                 m_bDone = true;\r
210                 m_Animate.Stop();\r
211                 m_Progress.SetPos(100);\r
212                 this->DialogEnableWindow(IDOK,TRUE);\r
213 \r
214                 CString err;\r
215                 err.Format(_T("\r\nFailed 0x%x(git return wrong reture code at sometime )\r\n"),m_GitStatus);\r
216                 if(this->m_GitStatus)\r
217                         InsertColorText(this->m_Log,err,RGB(255,0,0));\r
218                 else\r
219                         InsertColorText(this->m_Log,_T("\r\nSuccess\r\n"),RGB(0,0,255));\r
220 \r
221                 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)\r
222                 {\r
223                         if(m_bAutoCloseOnSuccess)\r
224                                 EndDialog(IDOK);\r
225 \r
226                         if(!m_changeAbortButtonOnSuccessTo.IsEmpty())\r
227                         {\r
228                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->SetWindowText(m_changeAbortButtonOnSuccessTo);\r
229                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);\r
230                                 GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE);\r
231                                 //Set default button is "close" rather than "push"\r
232                                 this->SendMessage(WM_NEXTDLGCTL, (WPARAM)GetDlgItem(IDOK)->m_hWnd, TRUE);\r
233                         }\r
234                         else\r
235                                 DialogEnableWindow(IDCANCEL, FALSE);\r
236                 }\r
237                 else\r
238                         DialogEnableWindow(IDCANCEL, FALSE);\r
239         }\r
240 \r
241         if(!m_bBufferAll)\r
242         {\r
243                 if(lParam == 0)\r
244                 {\r
245                         for(int i=this->m_BufStart;i<this->m_Databuf.size();i++)\r
246                         {\r
247                                 ParserCmdOutput(this->m_Databuf[m_BufStart]);\r
248                                 m_BufStart++;\r
249                         }\r
250                 }else\r
251                         ParserCmdOutput((TCHAR)lParam);\r
252         }\r
253         return 0;\r
254 }\r
255 \r
256 //static function, Share with SyncDialog\r
257 int CProgressDlg::FindPercentage(CString &log)\r
258 {\r
259         int s1=log.Find(_T('%'));\r
260         if(s1<0)\r
261                 return -1;\r
262 \r
263         int s2=s1-1;\r
264         for(int i=s1-1;i>=0;i--)\r
265         {\r
266                 if(log[i]>=_T('0') && log[i]<=_T('9'))\r
267                         s2=i;\r
268                 else\r
269                         break;\r
270         }\r
271         return _ttol(log.Mid(s2,s1-s2));\r
272 }\r
273 \r
274 #if 0\r
275 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
276 {\r
277         TRACE(_T("%c"),ch);\r
278         if( ch == _T('\r') || ch == _T('\n'))\r
279         {\r
280                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
281                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
282 \r
283                 int lines=m_Log.GetLineCount();\r
284 \r
285                 if(ch == _T('\r'))\r
286                 {       \r
287                         int start=m_Log.LineIndex(lines-1);\r
288                         int length=m_Log.LineLength(lines-1);\r
289                         m_Log.SetSel( start,start+length);\r
290                         m_Log.ReplaceSel(m_LogText);\r
291 \r
292                 }else\r
293                 {\r
294                         m_Log.SetSel(m_Log.GetWindowTextLength(),\r
295                                              m_Log.GetWindowTextLength());\r
296                         m_Log.ReplaceSel(CString(_T("\r\n"))+m_LogText);\r
297                 }\r
298                 \r
299                 if( lines > 500 ) //limited log length\r
300                 {\r
301                         int end=m_Log.LineIndex(1);\r
302                         m_Log.SetSel(0,end);\r
303                         m_Log.ReplaceSel(_T(""));\r
304                 }\r
305                 m_Log.LineScroll(m_Log.GetLineCount());\r
306 \r
307                 int s1=m_LogText.Find(_T(':'));\r
308                 int s2=m_LogText.Find(_T('%'));\r
309                 if(s1>0 && s2>0)\r
310                 {\r
311                         this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));\r
312                         int pos=FindPercentage(m_LogText);\r
313                         TRACE(_T("Pos %d\r\n"),pos);\r
314                         if(pos>0)\r
315                                 this->m_Progress.SetPos(pos);\r
316                 }\r
317 \r
318                 m_LogText=_T("");\r
319 \r
320         }else\r
321         {\r
322                 m_LogText+=ch;\r
323         }\r
324 \r
325 }\r
326 #endif\r
327 \r
328 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
329 {\r
330         ParserCmdOutput(this->m_Log,this->m_Progress,this->m_LogText,ch,&this->m_CurrentWork);\r
331 }\r
332 void CProgressDlg::ParserCmdOutput(CRichEditCtrl &log,CProgressCtrl &progressctrl,CString &oneline, TCHAR ch, CWnd *CurrentWork)\r
333 {\r
334         //TRACE(_T("%c"),ch);\r
335         TRACE(_T("%c"),ch);\r
336         if( ch == _T('\r') || ch == _T('\n'))\r
337         {\r
338                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
339                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
340 \r
341                 int lines=log.GetLineCount();\r
342 \r
343                 if(ch == _T('\r'))\r
344                 {       \r
345                         int start=log.LineIndex(lines-1);\r
346                         int length=log.LineLength(lines-1);\r
347                         log.SetSel( start,start+length);\r
348                         log.ReplaceSel(oneline);\r
349 \r
350                 }else\r
351                 {\r
352                         log.SetSel(log.GetWindowTextLength(),\r
353                                              log.GetWindowTextLength());\r
354                         log.ReplaceSel(CString(_T("\r\n"))+oneline);\r
355                 }\r
356                 \r
357                 if( lines > 500 ) //limited log length\r
358                 {\r
359                         int end=log.LineIndex(1);\r
360                         log.SetSel(0,end);\r
361                         log.ReplaceSel(_T(""));\r
362                 }\r
363                 log.LineScroll(log.GetLineCount());\r
364 \r
365                 int s1=oneline.Find(_T(':'));\r
366                 int s2=oneline.Find(_T('%'));\r
367                 if(s1>0 && s2>0)\r
368                 {\r
369                         if(CurrentWork)\r
370                                 CurrentWork->SetWindowTextW(oneline.Left(s1));\r
371 \r
372                         int pos=FindPercentage(oneline);\r
373                         TRACE(_T("Pos %d\r\n"),pos);\r
374                         if(pos>0)\r
375                                 progressctrl.SetPos(pos);\r
376                 }\r
377 \r
378                 oneline=_T("");\r
379 \r
380         }else\r
381         {\r
382                 oneline+=ch;\r
383         }\r
384 \r
385 }\r
386 void CProgressDlg::RemoveLastLine(CString &str)\r
387 {\r
388         int start;\r
389         start=str.ReverseFind(_T('\n'));\r
390         if(start>0)\r
391                 str=str.Left(start);\r
392         return;\r
393 }\r
394 // CProgressDlg message handlers\r
395 \r
396 void CProgressDlg::OnBnClickedOk()\r
397 {\r
398         // TODO: Add your control notification handler code here\r
399         m_Log.GetWindowText(this->m_LogText);\r
400         OnOK();\r
401 }\r
402 \r
403 void CProgressDlg::OnBnClickedButton1()\r
404 {\r
405         this->EndDialog(IDC_PROGRESS_BUTTON1);\r
406         \r
407 }\r
408 void CProgressDlg::OnCancel()\r
409 {\r
410         m_bAbort = true;\r
411         if(m_bDone)\r
412         {\r
413                 CResizableStandAloneDialog::OnCancel();\r
414                 return;\r
415         }\r
416 \r
417         if( g_Git.m_CurrentGitPi.hProcess )\r
418         {\r
419                 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))\r
420                 {\r
421                         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
422                 }else\r
423                 {\r
424                         int error=::GetLastError();\r
425                 }\r
426 \r
427                 HANDLE  hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE,g_Git.m_CurrentGitPi.dwProcessId);\r
428                 if( hProcessHandle )\r
429                         if(!::TerminateProcess(hProcessHandle,-1) )\r
430                         {\r
431                                 int error =::GetLastError();\r
432                         }\r
433         }\r
434         \r
435         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
436         CResizableStandAloneDialog::OnCancel();\r
437 \r
438 }\r
439 \r
440 void CProgressDlg::InsertCRLF()\r
441 {\r
442         for(int i=0;i<m_Databuf.size();i++)\r
443         {\r
444                 if(m_Databuf[i]==_T('\n'))\r
445                 {\r
446                         if(i==0 || m_Databuf[i-1]!= _T('\r'))\r
447                         {\r
448                                 m_Databuf.insert(m_Databuf.begin()+i,_T('\r'));\r
449                                 i++;\r
450                         }\r
451                 }\r
452         }\r
453 }\r
454 \r
455 void CProgressDlg::InsertColorText(CRichEditCtrl &edit,CString text,COLORREF rgb)\r
456 {\r
457         CHARFORMAT old,cf;\r
458         edit.GetDefaultCharFormat(cf);\r
459         old=cf;\r
460         cf.dwMask|=CFM_COLOR;\r
461         cf.crTextColor=rgb;\r
462         cf.dwEffects|=CFE_BOLD;\r
463         cf.dwEffects &= ~CFE_AUTOCOLOR ;\r
464         edit.SetSel(edit.GetTextLength()-1,edit.GetTextLength());\r
465         edit.ReplaceSel(text);\r
466         edit.SetSel(edit.LineIndex(edit.GetLineCount()-2),edit.GetTextLength());\r
467         edit.SetSelectionCharFormat(cf);\r
468         edit.SetSel(edit.GetTextLength(),edit.GetTextLength());\r
469         edit.SetDefaultCharFormat(old);\r
470         edit.LineScroll(edit.GetLineCount());\r
471 }\r
472 \r