OSDN Git Service

Fixed issue #209: High CPU usage in tortoiseproc.exe & limit line number
[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 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
268 {\r
269         TRACE(_T("%c"),ch);\r
270         if( ch == _T('\r') || ch == _T('\n'))\r
271         {\r
272                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
273                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
274 \r
275                 int lines=m_Log.GetLineCount();\r
276 \r
277                 if(ch == _T('\r'))\r
278                 {       \r
279                         int start=m_Log.LineIndex(lines-1);\r
280                         int length=m_Log.LineLength(lines-1);\r
281                         m_Log.SetSel( start,start+length);\r
282                         m_Log.ReplaceSel(m_LogText);\r
283 \r
284                 }else\r
285                 {\r
286                         m_Log.SetSel(m_Log.GetWindowTextLength(),\r
287                                              m_Log.GetWindowTextLength());\r
288                         m_Log.ReplaceSel(CString(_T("\r\n"))+m_LogText);\r
289                 }\r
290                 \r
291                 if( lines > 500 ) //limited log length\r
292                 {\r
293                         int end=m_Log.LineIndex(1);\r
294                         m_Log.SetSel(0,end);\r
295                         m_Log.ReplaceSel(_T(""));\r
296                 }\r
297                 m_Log.LineScroll(m_Log.GetLineCount());\r
298 \r
299                 int s1=m_LogText.Find(_T(':'));\r
300                 int s2=m_LogText.Find(_T('%'));\r
301                 if(s1>0 && s2>0)\r
302                 {\r
303                         this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));\r
304                         int pos=FindPercentage(m_LogText);\r
305                         TRACE(_T("Pos %d\r\n"),pos);\r
306                         if(pos>0)\r
307                                 this->m_Progress.SetPos(pos);\r
308                 }\r
309 \r
310                 m_LogText=_T("");\r
311 \r
312         }else\r
313         {\r
314                 m_LogText+=ch;\r
315         }\r
316 \r
317 }\r
318 void CProgressDlg::RemoveLastLine(CString &str)\r
319 {\r
320         int start;\r
321         start=str.ReverseFind(_T('\n'));\r
322         if(start>0)\r
323                 str=str.Left(start);\r
324         return;\r
325 }\r
326 // CProgressDlg message handlers\r
327 \r
328 void CProgressDlg::OnBnClickedOk()\r
329 {\r
330         // TODO: Add your control notification handler code here\r
331         m_Log.GetWindowText(this->m_LogText);\r
332         OnOK();\r
333 }\r
334 \r
335 void CProgressDlg::OnBnClickedButton1()\r
336 {\r
337         this->EndDialog(IDC_PROGRESS_BUTTON1);\r
338         \r
339 }\r
340 void CProgressDlg::OnCancel()\r
341 {\r
342         m_bAbort = true;\r
343         if(m_bDone)\r
344         {\r
345                 CResizableStandAloneDialog::OnCancel();\r
346                 return;\r
347         }\r
348 \r
349         if( g_Git.m_CurrentGitPi.hProcess )\r
350         {\r
351                 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))\r
352                 {\r
353                         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
354                 }else\r
355                 {\r
356                         int error=::GetLastError();\r
357                 }\r
358 \r
359                 HANDLE  hProcessHandle = ::OpenProcess( PROCESS_TERMINATE, FALSE,g_Git.m_CurrentGitPi.dwProcessId);\r
360                 if( hProcessHandle )\r
361                         if(!::TerminateProcess(hProcessHandle,-1) )\r
362                         {\r
363                                 int error =::GetLastError();\r
364                         }\r
365         }\r
366         \r
367         ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);\r
368         CResizableStandAloneDialog::OnCancel();\r
369 \r
370 }\r
371 \r
372 void CProgressDlg::InsertCRLF()\r
373 {\r
374         for(int i=0;i<m_Databuf.size();i++)\r
375         {\r
376                 if(m_Databuf[i]==_T('\n'))\r
377                 {\r
378                         if(i==0 || m_Databuf[i-1]!= _T('\r'))\r
379                         {\r
380                                 m_Databuf.insert(m_Databuf.begin()+i,_T('\r'));\r
381                                 i++;\r
382                         }\r
383                 }\r
384         }\r
385 }