OSDN Git Service

Unified SyncDlg and progressdlg log handle
[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                 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)\r
215                 {\r
216                         if(m_bAutoCloseOnSuccess)\r
217                                 EndDialog(IDOK);\r
218 \r
219                         if(!m_changeAbortButtonOnSuccessTo.IsEmpty())\r
220                         {\r
221                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->SetWindowText(m_changeAbortButtonOnSuccessTo);\r
222                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);\r
223                                 GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE);\r
224                                 //Set default button is "close" rather than "push"\r
225                                 this->SendMessage(WM_NEXTDLGCTL, (WPARAM)GetDlgItem(IDOK)->m_hWnd, TRUE);\r
226                         }\r
227                         else\r
228                                 DialogEnableWindow(IDCANCEL, FALSE);\r
229                 }\r
230                 else\r
231                         DialogEnableWindow(IDCANCEL, FALSE);\r
232         }\r
233 \r
234         if(!m_bBufferAll)\r
235         {\r
236                 if(lParam == 0)\r
237                 {\r
238                         for(int i=this->m_BufStart;i<this->m_Databuf.size();i++)\r
239                         {\r
240                                 ParserCmdOutput(this->m_Databuf[m_BufStart]);\r
241                                 m_BufStart++;\r
242                         }\r
243                 }else\r
244                         ParserCmdOutput((TCHAR)lParam);\r
245         }\r
246         return 0;\r
247 }\r
248 \r
249 //static function, Share with SyncDialog\r
250 int CProgressDlg::FindPercentage(CString &log)\r
251 {\r
252         int s1=log.Find(_T('%'));\r
253         if(s1<0)\r
254                 return -1;\r
255 \r
256         int s2=s1-1;\r
257         for(int i=s1-1;i>=0;i--)\r
258         {\r
259                 if(log[i]>=_T('0') && log[i]<=_T('9'))\r
260                         s2=i;\r
261                 else\r
262                         break;\r
263         }\r
264         return _ttol(log.Mid(s2,s1-s2));\r
265 }\r
266 \r
267 #if 0\r
268 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
269 {\r
270         TRACE(_T("%c"),ch);\r
271         if( ch == _T('\r') || ch == _T('\n'))\r
272         {\r
273                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
274                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
275 \r
276                 int lines=m_Log.GetLineCount();\r
277 \r
278                 if(ch == _T('\r'))\r
279                 {       \r
280                         int start=m_Log.LineIndex(lines-1);\r
281                         int length=m_Log.LineLength(lines-1);\r
282                         m_Log.SetSel( start,start+length);\r
283                         m_Log.ReplaceSel(m_LogText);\r
284 \r
285                 }else\r
286                 {\r
287                         m_Log.SetSel(m_Log.GetWindowTextLength(),\r
288                                              m_Log.GetWindowTextLength());\r
289                         m_Log.ReplaceSel(CString(_T("\r\n"))+m_LogText);\r
290                 }\r
291                 \r
292                 if( lines > 500 ) //limited log length\r
293                 {\r
294                         int end=m_Log.LineIndex(1);\r
295                         m_Log.SetSel(0,end);\r
296                         m_Log.ReplaceSel(_T(""));\r
297                 }\r
298                 m_Log.LineScroll(m_Log.GetLineCount());\r
299 \r
300                 int s1=m_LogText.Find(_T(':'));\r
301                 int s2=m_LogText.Find(_T('%'));\r
302                 if(s1>0 && s2>0)\r
303                 {\r
304                         this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));\r
305                         int pos=FindPercentage(m_LogText);\r
306                         TRACE(_T("Pos %d\r\n"),pos);\r
307                         if(pos>0)\r
308                                 this->m_Progress.SetPos(pos);\r
309                 }\r
310 \r
311                 m_LogText=_T("");\r
312 \r
313         }else\r
314         {\r
315                 m_LogText+=ch;\r
316         }\r
317 \r
318 }\r
319 #endif\r
320 \r
321 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
322 {\r
323         ParserCmdOutput(this->m_Log,this->m_Progress,this->m_LogText,ch);\r
324 }\r
325 void CProgressDlg::ParserCmdOutput(CRichEditCtrl &log,CProgressCtrl &progressctrl,CString &oneline, TCHAR ch)\r
326 {\r
327         //TRACE(_T("%c"),ch);\r
328         TRACE(_T("%c"),ch);\r
329         if( ch == _T('\r') || ch == _T('\n'))\r
330         {\r
331                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
332                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
333 \r
334                 int lines=log.GetLineCount();\r
335 \r
336                 if(ch == _T('\r'))\r
337                 {       \r
338                         int start=log.LineIndex(lines-1);\r
339                         int length=log.LineLength(lines-1);\r
340                         log.SetSel( start,start+length);\r
341                         log.ReplaceSel(oneline);\r
342 \r
343                 }else\r
344                 {\r
345                         log.SetSel(log.GetWindowTextLength(),\r
346                                              log.GetWindowTextLength());\r
347                         log.ReplaceSel(CString(_T("\r\n"))+oneline);\r
348                 }\r
349                 \r
350                 if( lines > 500 ) //limited log length\r
351                 {\r
352                         int end=log.LineIndex(1);\r
353                         log.SetSel(0,end);\r
354                         log.ReplaceSel(_T(""));\r
355                 }\r
356                 log.LineScroll(log.GetLineCount());\r
357 \r
358                 int s1=oneline.Find(_T(':'));\r
359                 int s2=oneline.Find(_T('%'));\r
360                 if(s1>0 && s2>0)\r
361                 {\r
362                         //this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));\r
363                         int pos=FindPercentage(oneline);\r
364                         TRACE(_T("Pos %d\r\n"),pos);\r
365                         if(pos>0)\r
366                                 progressctrl.SetPos(pos);\r
367                 }\r
368 \r
369                 oneline=_T("");\r
370 \r
371         }else\r
372         {\r
373                 oneline+=ch;\r
374         }\r
375 \r
376 }\r
377 void CProgressDlg::RemoveLastLine(CString &str)\r
378 {\r
379         int start;\r
380         start=str.ReverseFind(_T('\n'));\r
381         if(start>0)\r
382                 str=str.Left(start);\r
383         return;\r
384 }\r
385 // CProgressDlg message handlers\r
386 \r
387 void CProgressDlg::OnBnClickedOk()\r
388 {\r
389         // TODO: Add your control notification handler code here\r
390         m_Log.GetWindowText(this->m_LogText);\r
391         OnOK();\r
392 }\r
393 \r
394 void CProgressDlg::OnBnClickedButton1()\r
395 {\r
396         this->EndDialog(IDC_PROGRESS_BUTTON1);\r
397         \r
398 }\r
399 void CProgressDlg::OnCancel()\r
400 {\r
401         m_bAbort = true;\r
402         if(m_bDone)\r
403         {\r
404                 CResizableStandAloneDialog::OnCancel();\r
405                 return;\r
406         }\r
407 \r
408         if( g_Git.m_CurrentGitPi.hProcess )\r
409         {\r
410                 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))\r
411                 {\r
412                         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
413                 }else\r
414                 {\r
415                         int error=::GetLastError();\r
416                 }\r
417 \r
418                 HANDLE  hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE,g_Git.m_CurrentGitPi.dwProcessId);\r
419                 if( hProcessHandle )\r
420                         if(!::TerminateProcess(hProcessHandle,-1) )\r
421                         {\r
422                                 int error =::GetLastError();\r
423                         }\r
424         }\r
425         \r
426         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
427         CResizableStandAloneDialog::OnCancel();\r
428 \r
429 }\r
430 \r
431 void CProgressDlg::InsertCRLF()\r
432 {\r
433         for(int i=0;i<m_Databuf.size();i++)\r
434         {\r
435                 if(m_Databuf[i]==_T('\n'))\r
436                 {\r
437                         if(i==0 || m_Databuf[i-1]!= _T('\r'))\r
438                         {\r
439                                 m_Databuf.insert(m_Databuf.begin()+i,_T('\r'));\r
440                                 i++;\r
441                         }\r
442                 }\r
443         }\r
444 }