OSDN Git Service

Basic Fixed issue #122: Garbage text in "Git Command Progress" / suspected buffer...
[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 }\r
19 \r
20 CProgressDlg::~CProgressDlg()\r
21 {\r
22         if(m_pThread != NULL)\r
23         {\r
24                 delete m_pThread;\r
25         }\r
26 }\r
27 \r
28 void CProgressDlg::DoDataExchange(CDataExchange* pDX)\r
29 {\r
30         CDialog::DoDataExchange(pDX);\r
31         DDX_Control(pDX, IDC_CURRENT, this->m_CurrentWork);\r
32         DDX_Control(pDX, IDC_TITLE_ANIMATE, this->m_Animate);\r
33         DDX_Control(pDX, IDC_RUN_PROGRESS, this->m_Progress);\r
34         DDX_Control(pDX, IDC_LOG, this->m_Log);\r
35 }\r
36 \r
37 \r
38 BEGIN_MESSAGE_MAP(CProgressDlg, CResizableStandAloneDialog)\r
39         ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)\r
40         ON_BN_CLICKED(IDOK, &CProgressDlg::OnBnClickedOk)\r
41         ON_BN_CLICKED(IDC_PROGRESS_BUTTON1,&CProgressDlg::OnBnClickedButton1)\r
42 END_MESSAGE_MAP()\r
43 \r
44 BOOL CProgressDlg::OnInitDialog()\r
45 {\r
46         CResizableStandAloneDialog::OnInitDialog();\r
47 \r
48         AddAnchor(IDC_TITLE_ANIMATE, TOP_LEFT, TOP_RIGHT);\r
49         AddAnchor(IDC_RUN_PROGRESS, TOP_LEFT,TOP_RIGHT);\r
50         AddAnchor(IDC_LOG, TOP_LEFT,BOTTOM_RIGHT);\r
51 \r
52         AddAnchor(IDOK,BOTTOM_RIGHT);\r
53         AddAnchor(IDCANCEL,BOTTOM_RIGHT);\r
54         AddAnchor(IDC_PROGRESS_BUTTON1,BOTTOM_RIGHT);\r
55 \r
56         this->GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_HIDE);\r
57         m_Animate.Open(IDR_DOWNLOAD);\r
58         \r
59         CString InitialText;\r
60         if ( !m_PreText.IsEmpty() )\r
61         {\r
62                 InitialText = m_PreText + _T("\r\n");\r
63         }\r
64 #if 0\r
65         if (m_bShowCommand && (!m_GitCmd.IsEmpty() ))\r
66         {\r
67                 InitialText += m_GitCmd+_T("\r\n\r\n");\r
68         }\r
69 #endif\r
70         m_Log.SetWindowTextW(InitialText);\r
71         m_CurrentWork.SetWindowTextW(_T(""));\r
72 \r
73         m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
74         if (m_pThread==NULL)\r
75         {\r
76 //              ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));\r
77         }\r
78         else\r
79         {\r
80                 m_pThread->m_bAutoDelete = FALSE;\r
81                 m_pThread->ResumeThread();\r
82         }\r
83 \r
84         if(!m_Title.IsEmpty())\r
85                 this->SetWindowText(m_Title);\r
86         return TRUE;\r
87 }\r
88 \r
89 UINT CProgressDlg::ProgressThreadEntry(LPVOID pVoid)\r
90 {\r
91         return ((CProgressDlg*)pVoid)->ProgressThread();\r
92 }\r
93 \r
94 //static function, Share with SyncDialog\r
95 UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,std::vector<TCHAR>*pdata)\r
96 {\r
97         UINT ret=0;\r
98 \r
99         PROCESS_INFORMATION pi;\r
100         HANDLE hRead;\r
101 \r
102         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_START,0);\r
103 \r
104         if(pdata)\r
105                 pdata->clear();\r
106                  \r
107         for(int i=0;i<cmdlist.size();i++)\r
108         {\r
109                 if(cmdlist[i].IsEmpty())\r
110                         continue;\r
111 \r
112                 if (bShowCommand)\r
113                 {\r
114                         CString str;\r
115                         str+= cmdlist[i]+_T("\n\n");\r
116                         for(int j=0;j<str.GetLength();j++)\r
117                         {\r
118                                 if(pdata)\r
119                                         pdata->push_back(str[j]);\r
120                                 else\r
121                                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);\r
122                         }\r
123                         if(pdata)\r
124                                 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);\r
125                 }\r
126 \r
127                 g_Git.RunAsync(cmdlist[i],&pi, &hRead,pfilename);\r
128 \r
129                 DWORD readnumber;\r
130                 char buffer[2];\r
131                 CString output;\r
132                 while(ReadFile(hRead,buffer,1,&readnumber,NULL))\r
133                 {\r
134                         buffer[readnumber]=0;\r
135                         \r
136                         if(pdata)\r
137                         {\r
138                                 pdata->push_back((TCHAR)buffer[0]);\r
139 \r
140                                 if(buffer[0] == '\r' || buffer[0] == '\n')\r
141                                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);\r
142                         }else\r
143                                 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,buffer[0]);\r
144                 }\r
145         \r
146                 CloseHandle(pi.hThread);\r
147 \r
148                 WaitForSingleObject(pi.hProcess, INFINITE);\r
149                 \r
150                 DWORD status=0;\r
151                 if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)\r
152                 {\r
153                         CloseHandle(pi.hProcess);\r
154 \r
155                         CloseHandle(hRead);\r
156 \r
157                         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_FAILED,0);\r
158                         return GIT_ERROR_GET_EXIT_CODE;\r
159                 }\r
160                 ret |= status;\r
161         }\r
162 \r
163         CloseHandle(pi.hProcess);\r
164 \r
165         CloseHandle(hRead);\r
166 \r
167         pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_END,0);\r
168 \r
169         return ret;\r
170 \r
171 }\r
172 \r
173 UINT CProgressDlg::ProgressThread()\r
174 {\r
175         \r
176         m_GitCmdList.push_back(m_GitCmd);\r
177 \r
178         CString *pfilename;\r
179 \r
180         if(m_LogFile.IsEmpty())\r
181                 pfilename=NULL;\r
182         else\r
183                 pfilename=&m_LogFile;   \r
184 \r
185         m_GitStatus = RunCmdList(this,m_GitCmdList,m_bShowCommand,pfilename,&m_bAbort,&this->m_Databuf);;\r
186         return 0;\r
187 }\r
188 \r
189 LRESULT CProgressDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)\r
190 {\r
191         if(wParam == MSG_PROGRESSDLG_START)\r
192         {\r
193                 m_BufStart = 0 ;\r
194                 m_Animate.Play(0,-1,-1);\r
195                 this->DialogEnableWindow(IDOK,FALSE);\r
196         }\r
197         if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)\r
198         {\r
199                 m_BufStart=0;\r
200                 this->m_Databuf.clear();\r
201 \r
202                 m_bDone = true;\r
203                 m_Animate.Stop();\r
204                 m_Progress.SetPos(100);\r
205                 this->DialogEnableWindow(IDOK,TRUE);\r
206 \r
207                 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)\r
208                 {\r
209                         if(m_bAutoCloseOnSuccess)\r
210                                 EndDialog(IDOK);\r
211 \r
212                         if(!m_changeAbortButtonOnSuccessTo.IsEmpty())\r
213                         {\r
214                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->SetWindowText(m_changeAbortButtonOnSuccessTo);\r
215                                 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);\r
216                                 GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE);\r
217                                 //Set default button is "close" rather than "push"\r
218                                 this->SendMessage(WM_NEXTDLGCTL, (WPARAM)GetDlgItem(IDOK)->m_hWnd, TRUE);\r
219                         }\r
220                         else\r
221                                 DialogEnableWindow(IDCANCEL, FALSE);\r
222                 }\r
223                 else\r
224                         DialogEnableWindow(IDCANCEL, FALSE);\r
225         }\r
226 \r
227         if(lParam == 0)\r
228         {\r
229                 for(int i=this->m_BufStart;i<this->m_Databuf.size();i++)\r
230                 {\r
231                         ParserCmdOutput(this->m_Databuf[m_BufStart]);\r
232                         m_BufStart++;\r
233                 }\r
234         }else\r
235                 ParserCmdOutput((TCHAR)lParam);\r
236 \r
237         return 0;\r
238 }\r
239 \r
240 //static function, Share with SyncDialog\r
241 int CProgressDlg::FindPercentage(CString &log)\r
242 {\r
243         int s1=log.Find(_T('%'));\r
244         if(s1<0)\r
245                 return -1;\r
246 \r
247         int s2=s1-1;\r
248         for(int i=s1-1;i>=0;i--)\r
249         {\r
250                 if(log[i]>=_T('0') && log[i]<=_T('9'))\r
251                         s2=i;\r
252                 else\r
253                         break;\r
254         }\r
255         return _ttol(log.Mid(s2,s1-s2));\r
256 }\r
257 \r
258 void CProgressDlg::ParserCmdOutput(TCHAR ch)\r
259 {\r
260         TRACE(_T("%c"),ch);\r
261         if( ch == _T('\r') || ch == _T('\n'))\r
262         {\r
263                 TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));\r
264                 TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));\r
265 \r
266                 CString text;\r
267                 m_Log.GetWindowTextW(text);\r
268                 if(ch == _T('\r'))\r
269                 {\r
270                         RemoveLastLine(text);\r
271                 }\r
272                 text+=_T("\r\n")+m_LogText;\r
273                 m_Log.SetWindowTextW(text);\r
274                 \r
275                 m_Log.LineScroll(m_Log.GetLineCount());\r
276 \r
277                 int s1=m_LogText.Find(_T(':'));\r
278                 int s2=m_LogText.Find(_T('%'));\r
279                 if(s1>0 && s2>0)\r
280                 {\r
281                         this->m_CurrentWork.SetWindowTextW(m_LogText.Left(s1));\r
282                         int pos=FindPercentage(m_LogText);\r
283                         TRACE(_T("Pos %d\r\n"),pos);\r
284                         if(pos>0)\r
285                                 this->m_Progress.SetPos(pos);\r
286                 }\r
287 \r
288                 m_LogText=_T("");\r
289 \r
290         }else\r
291         {\r
292                 m_LogText+=ch;\r
293         }\r
294 \r
295 }\r
296 void CProgressDlg::RemoveLastLine(CString &str)\r
297 {\r
298         int start;\r
299         start=str.ReverseFind(_T('\n'));\r
300         if(start>0)\r
301                 str=str.Left(start);\r
302         return;\r
303 }\r
304 // CProgressDlg message handlers\r
305 \r
306 void CProgressDlg::OnBnClickedOk()\r
307 {\r
308         // TODO: Add your control notification handler code here\r
309         m_Log.GetWindowText(this->m_LogText);\r
310         OnOK();\r
311 }\r
312 \r
313 void CProgressDlg::OnBnClickedButton1()\r
314 {\r
315         this->EndDialog(IDC_PROGRESS_BUTTON1);\r
316         \r
317 }\r
318 void CProgressDlg::OnCancel()\r
319 {\r
320         if(m_bDone)\r
321         {\r
322                 CResizableStandAloneDialog::OnCancel();\r
323                 return;\r
324         }\r
325         \r
326         m_bAbort = true;\r
327 }\r