1 // ProgressDialog2.cpp
2
3 #include "StdAfx.h"
4
5 #include "Common/IntToString.h"
6
7 #include "ProgressDialog2.h"
8
9 using namespace NWindows;
10
11 static const UINT_PTR kTimerID = 3;
12 static const UINT kTimerElapse = 100;
13
14 #ifdef LANG
15 #include "LangUtils.h"
16 #endif
17
18 #ifdef LANG
19 static CIDLangPair kIDLangPairs[] =
20 {
21 { IDCANCEL, 0x02000C00 },
22 { IDC_PROGRESS_ELAPSED, 0x02000C01 },
23 { IDC_PROGRESS_REMAINING, 0x02000C02 },
24 { IDC_PROGRESS_TOTAL, 0x02000C03 },
25 { IDC_PROGRESS_SPEED, 0x02000C04 },
26 { IDC_PROGRESS_UNPACKED, 0x02000C05 },
27 { IDC_PROGRESS_PACKED, 0x02000323 },
28 { IDC_PROGRESS_RATIO, 0x02000C06 },
29 { IDC_PROGRESS_SPEED, 0x02000C04 },
30 { IDC_PROGRESS_FILES, 0x02000320 },
31 { IDC_BUTTON_PROGRESS_PRIORITY, 0x02000C10 },
32 { IDC_BUTTON_PAUSE, 0x02000C12 },
33 { IDCANCEL, 0x02000711 },
34 };
35 #endif
36
ProcessStopAndPause()37 HRESULT CProgressSynch::ProcessStopAndPause()
38 {
39 for (;;)
40 {
41 if (GetStopped())
42 return E_ABORT;
43 if (!GetPaused())
44 break;
45 ::Sleep(100);
46 }
47 return S_OK;
48 }
49
SetPosAndCheckPaused(UInt64 completed)50 HRESULT CProgressSynch::SetPosAndCheckPaused(UInt64 completed)
51 {
52 RINOK(ProcessStopAndPause());
53 SetPos(completed);
54 return S_OK;
55 }
56
57 #ifndef _SFX
~CProgressDialog()58 CProgressDialog::~CProgressDialog()
59 {
60 AddToTitle(L"");
61 }
AddToTitle(LPCWSTR s)62 void CProgressDialog::AddToTitle(LPCWSTR s)
63 {
64 if (MainWindow != 0)
65 {
66 CWindow window(MainWindow);
67 window.SetText(s + UString(MainTitle));
68 }
69 }
70
71 static const int kTitleFileNameSizeLimit = 40;
72 static const int kCurrentFileNameSizeLimit = 82;
73
ReduceString(UString & s,int size)74 static void ReduceString(UString &s, int size)
75 {
76 if (s.Length() > size)
77 s = s.Left(size / 2) + UString(L" ... ") + s.Right(size / 2);
78 }
79 #endif
80
OnInit()81 bool CProgressDialog::OnInit()
82 {
83 _range = (UInt64)(Int64)(-1);
84 _prevPercentValue = UInt32(-1);
85 _prevElapsedSec = UInt32(-1);
86 _prevRemainingSec = UInt32(-1);
87 _prevSpeed = UInt32(-1);
88 _prevMode = kSpeedBytes;
89 _prevTime = ::GetTickCount();
90 _elapsedTime = 0;
91 _foreground = true;
92
93 #ifdef LANG
94 // LangSetWindowText(HWND(*this), 0x02000C00);
95 LangSetDlgItemsText(HWND(*this), kIDLangPairs, sizeof(kIDLangPairs) / sizeof(kIDLangPairs[0]));
96 #endif
97
98
99 CWindow window(GetItem(IDC_BUTTON_PROGRESS_PRIORITY));
100 window.GetText(backgroundString);
101 backgroundedString = backgroundString;
102 backgroundedString.Replace(L"&", L"");
103
104 window = GetItem(IDC_BUTTON_PAUSE);
105 window.GetText(pauseString);
106
107 foregroundString = LangString(IDS_PROGRESS_FOREGROUND, 0x02000C11);
108 continueString = LangString(IDS_PROGRESS_CONTINUE, 0x02000C13);
109 pausedString = LangString(IDS_PROGRESS_PAUSED, 0x02000C20);
110
111 m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
112 _timer = SetTimer(kTimerID, kTimerElapse);
113 _dialogCreatedEvent.Set();
114 SetText(_title);
115 SetPauseText();
116 SetPriorityText();
117 return CModalDialog::OnInit();
118 }
119
OnCancel()120 void CProgressDialog::OnCancel()
121 {
122 ProgressSynch.SetStopped(true);
123 }
124
ConvertSizeToString(UInt64 value,wchar_t * s)125 static void ConvertSizeToString(UInt64 value, wchar_t *s)
126 {
127 const wchar_t *kModif = L" KM";
128 for (int i = 0; ; i++)
129 if (i == 2 || value < (UInt64(10000) << (i * 10)))
130 {
131 ConvertUInt64ToString(value >> (i * 10), s);
132 s += wcslen(s);
133 *s++ = ' ';
134 if (i != 0)
135 *s++ = kModif[i];
136 *s++ = L'B';
137 *s++ = L'\0';
138 return;
139 }
140 }
141
SetRange(UInt64 range)142 void CProgressDialog::SetRange(UInt64 range)
143 {
144 _range = range;
145 _previousPos = (UInt64)(Int64)-1;
146 _converter.Init(range);
147 m_ProgressBar.SetRange32(0, _converter.Count(range)); // Test it for 100%
148 }
149
SetPos(UInt64 pos)150 void CProgressDialog::SetPos(UInt64 pos)
151 {
152 bool redraw = true;
153 if (pos < _range && pos > _previousPos)
154 {
155 if (pos - _previousPos < (_range >> 10))
156 redraw = false;
157 }
158 if(redraw)
159 {
160 m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100%
161 _previousPos = pos;
162 }
163 }
164
GetTimeString(UInt64 timeValue,TCHAR * s)165 static void GetTimeString(UInt64 timeValue, TCHAR *s)
166 {
167 wsprintf(s, TEXT("%02d:%02d:%02d"),
168 UInt32(timeValue / 3600),
169 UInt32((timeValue / 60) % 60),
170 UInt32(timeValue % 60));
171 }
172
ShowSize(int id,UInt64 value)173 void CProgressDialog::ShowSize(int id, UInt64 value)
174 {
175 wchar_t s[40];
176 s[0] = 0;
177 if (value != (UInt64)(Int64)-1)
178 ConvertSizeToString(value, s);
179 SetItemText(id, s);
180 }
181
OnTimer(WPARAM,LPARAM)182 bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
183 {
184 if (ProgressSynch.GetPaused())
185 return true;
186 UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
187 bool bytesProgressMode;
188 ProgressSynch.GetProgress(total, completed, totalFiles, completedFiles, inSize, outSize, bytesProgressMode);
189
190 UInt32 curTime = ::GetTickCount();
191
192 UInt64 progressTotal = bytesProgressMode ? total : totalFiles;
193 UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles;
194
195 if (progressTotal != _range)
196 SetRange(progressTotal);
197 if (progressTotal == (UInt64)(Int64)-1)
198 {
199 SetPos(0);
200 SetRange(progressCompleted);
201 }
202 else
203 SetPos(progressCompleted);
204
205 wchar_t s[32] = { 0 };
206 if (total != (UInt64)(Int64)-1)
207 ConvertSizeToString(total, s);
208 SetItemText(IDC_PROGRESS_TOTAL_VALUE, s);
209
210 _elapsedTime += (curTime - _prevTime);
211 _prevTime = curTime;
212
213 UInt32 elapsedSec = _elapsedTime / 1000;
214
215 bool elapsedChanged = false;
216 if (elapsedSec != _prevElapsedSec)
217 {
218 TCHAR s[40];
219 GetTimeString(elapsedSec, s);
220 SetItemText(IDC_PROGRESS_ELAPSED_VALUE, s);
221 _prevElapsedSec = elapsedSec;
222 elapsedChanged = true;
223 }
224
225 if (elapsedChanged)
226 {
227 if (completed != 0)
228 {
229
230 if (total == (UInt64)(Int64)-1)
231 {
232 SetItemText(IDC_PROGRESS_REMAINING_VALUE, L"");
233 }
234 else
235 {
236 UInt64 remainingTime = 0;
237 if (completed < total)
238 remainingTime = _elapsedTime * (total - completed) / completed;
239 UInt64 remainingSec = remainingTime / 1000;
240 if (remainingSec != _prevRemainingSec)
241 {
242 TCHAR s[40];
243 GetTimeString(remainingSec, s);
244 SetItemText(IDC_PROGRESS_REMAINING_VALUE, s);
245 _prevRemainingSec = remainingSec;
246 }
247 }
248 // if (elapsedChanged)
249 {
250 UInt32 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;
251 UInt64 speedB = (completed * 1000) / elapsedTime;
252 UInt64 speedKB = speedB / 1024;
253 UInt64 speedMB = speedKB / 1024;
254 const UInt32 kLimit1 = 10;
255 TCHAR s[40];
256 bool needRedraw = false;
257 if (speedMB >= kLimit1)
258 {
259 if (_prevMode != kSpeedMBytes || speedMB != _prevSpeed)
260 {
261 ConvertUInt64ToString(speedMB, s);
262 lstrcat(s, TEXT(" MB/s"));
263 _prevMode = kSpeedMBytes;
264 _prevSpeed = speedMB;
265 needRedraw = true;
266 }
267 }
268 else if (speedKB >= kLimit1)
269 {
270 if (_prevMode != kSpeedKBytes || speedKB != _prevSpeed)
271 {
272 ConvertUInt64ToString(speedKB, s);
273 lstrcat(s, TEXT(" KB/s"));
274 _prevMode = kSpeedKBytes;
275 _prevSpeed = speedKB;
276 needRedraw = true;
277 }
278 }
279 else
280 {
281 if (_prevMode != kSpeedBytes || speedB != _prevSpeed)
282 {
283 ConvertUInt64ToString(speedB, s);
284 lstrcat(s, TEXT(" B/s"));
285 _prevMode = kSpeedBytes;
286 _prevSpeed = speedB;
287 needRedraw = true;
288 }
289 }
290 if (needRedraw)
291 SetItemText(IDC_PROGRESS_SPEED_VALUE, s);
292 }
293 }
294
295 if (total == 0)
296 total = 1;
297 UInt32 percentValue = (UInt32)(completed * 100 / total);
298 UString titleName;
299 ProgressSynch.GetTitleFileName(titleName);
300 if (percentValue != _prevPercentValue || _prevTitleName != titleName)
301 {
302 _prevPercentValue = percentValue;
303 SetTitleText();
304 _prevTitleName = titleName;
305 }
306
307 TCHAR s[64];
308 ConvertUInt64ToString(completedFiles, s);
309 if (totalFiles != (UInt64)(Int64)-1)
310 {
311 lstrcat(s, TEXT(" / "));
312 ConvertUInt64ToString(totalFiles, s + lstrlen(s));
313 }
314
315 SetItemText(IDC_PROGRESS_FILES_VALUE, s);
316
317 const UInt64 packSize = CompressingMode ? outSize : inSize;
318 const UInt64 unpackSize = CompressingMode ? inSize : outSize;
319
320 if (unpackSize == (UInt64)(Int64)-1 && packSize == (UInt64)(Int64)-1)
321 {
322 ShowSize(IDC_PROGRESS_UNPACKED_VALUE, completed);
323 SetItemText(IDC_PROGRESS_PACKED_VALUE, L"");
324 }
325 else
326 {
327 ShowSize(IDC_PROGRESS_UNPACKED_VALUE, unpackSize);
328 ShowSize(IDC_PROGRESS_PACKED_VALUE, packSize);
329
330 if (packSize != (UInt64)(Int64)-1 && unpackSize != (UInt64)(Int64)-1 && unpackSize != 0)
331 {
332 UInt64 ratio = packSize * 100 / unpackSize;
333 ConvertUInt64ToString(ratio, s);
334 lstrcat(s, TEXT("%"));
335 SetItemText(IDC_PROGRESS_RATIO_VALUE, s);
336 }
337 }
338 }
339
340
341 UString fileName;
342 ProgressSynch.GetCurrentFileName(fileName);
343 if (_prevFileName != fileName)
344 {
345 int slashPos = fileName.ReverseFind(WCHAR_PATH_SEPARATOR);
346 UString s1, s2;
347 if (slashPos >= 0)
348 {
349 s1 = fileName.Left(slashPos + 1);
350 s2 = fileName.Mid(slashPos + 1);
351 }
352 else
353 s2 = fileName;
354 ReduceString(s1, kCurrentFileNameSizeLimit);
355 ReduceString(s2, kCurrentFileNameSizeLimit);
356 UString s = s1 + L"\n" + s2;
357 SetItemText(IDC_PROGRESS_FILE_NAME, s);
358 _prevFileName == fileName;
359 }
360
361 return true;
362 }
363
364
365 ////////////////////
366 // CU64ToI32Converter
367
368 static const UInt64 kMaxIntValue = 0x7FFFFFFF;
369
Init(UInt64 range)370 void CU64ToI32Converter::Init(UInt64 range)
371 {
372 _numShiftBits = 0;
373 while(range > kMaxIntValue)
374 {
375 range >>= 1;
376 _numShiftBits++;
377 }
378 }
379
Count(UInt64 aValue)380 int CU64ToI32Converter::Count(UInt64 aValue)
381 {
382 return int(aValue >> _numShiftBits);
383 }
384
385 const UINT CProgressDialog::kCloseMessage = WM_USER + 1;
386
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)387 bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
388 {
389 switch(message)
390 {
391 case kCloseMessage:
392 {
393 KillTimer(_timer);
394 _timer = 0;
395 End(0);
396 return true;
397 }
398 case WM_SETTEXT:
399 {
400 if (_timer == 0)
401 return true;
402 }
403 }
404 return CModalDialog::OnMessage(message, wParam, lParam);
405 }
406
SetTitleText()407 void CProgressDialog::SetTitleText()
408 {
409 UString title;
410 if (ProgressSynch.GetPaused())
411 {
412 title = pausedString;
413 title += L" ";
414 }
415 if (_prevPercentValue != UInt32(-1))
416 {
417 wchar_t s[64];
418 ConvertUInt64ToString(_prevPercentValue, s);
419 title += s;
420 title += L"%";
421 }
422 if (!_foreground)
423 {
424 title += L" ";
425 title += backgroundedString;
426 }
427 title += L" ";
428 UString totalTitle = title + _title;
429 UString fileName;
430 ProgressSynch.GetTitleFileName(fileName);
431 if (!fileName.IsEmpty())
432 {
433 ReduceString(fileName, kTitleFileNameSizeLimit);
434 totalTitle += L" ";
435 totalTitle += fileName;
436 }
437 SetText(totalTitle);
438 #ifndef _SFX
439 AddToTitle(title + MainAddTitle);
440 #endif
441 }
442
SetPauseText()443 void CProgressDialog::SetPauseText()
444 {
445 SetItemText(IDC_BUTTON_PAUSE, ProgressSynch.GetPaused() ?
446 continueString : pauseString);
447 SetTitleText();
448 }
449
OnPauseButton()450 void CProgressDialog::OnPauseButton()
451 {
452 bool paused = !ProgressSynch.GetPaused();
453 ProgressSynch.SetPaused(paused);
454 UInt32 curTime = ::GetTickCount();
455 if (paused)
456 _elapsedTime += (curTime - _prevTime);
457 _prevTime = curTime;
458 SetPauseText();
459 }
460
SetPriorityText()461 void CProgressDialog::SetPriorityText()
462 {
463 SetItemText(IDC_BUTTON_PROGRESS_PRIORITY, _foreground ?
464 backgroundString :
465 foregroundString);
466 SetTitleText();
467 }
468
OnPriorityButton()469 void CProgressDialog::OnPriorityButton()
470 {
471 _foreground = !_foreground;
472 SetPriorityClass(GetCurrentProcess(), _foreground ?
473 NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS);
474 SetPriorityText();
475 }
476
OnButtonClicked(int buttonID,HWND buttonHWND)477 bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
478 {
479 switch(buttonID)
480 {
481 case IDCANCEL:
482 {
483 bool paused = ProgressSynch.GetPaused();;
484 // ProgressSynch.SetPaused(true);
485 if (!paused)
486 OnPauseButton();
487 int res = ::MessageBoxW(HWND(*this),
488 LangString(IDS_PROGRESS_ASK_CANCEL, 0x02000C30),
489 _title, MB_YESNOCANCEL);
490 // ProgressSynch.SetPaused(paused);
491 if (!paused)
492 OnPauseButton();
493 if (res == IDCANCEL || res == IDNO)
494 return true;
495 break;
496 }
497 case IDC_BUTTON_PAUSE:
498 OnPauseButton();
499 return true;
500 case IDC_BUTTON_PROGRESS_PRIORITY:
501 {
502 OnPriorityButton();
503 return true;
504 }
505 }
506 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
507 }
508