1 // ProgressDialog2.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7
8 #include "../../../Windows/Control/Static.h"
9 #include "../../../Windows/ErrorMsg.h"
10
11 #include "ProgressDialog2.h"
12 #include "DialogSize.h"
13
14 #include "ProgressDialog2Res.h"
15
16 #include "../GUI/ExtractRes.h"
17
18 using namespace NWindows;
19
20 extern HINSTANCE g_hInstance;
21
22 static const UINT_PTR kTimerID = 3;
23
24 static const UINT kCloseMessage = WM_APP + 1;
25 // we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog
26
27 static const UINT kTimerElapse =
28 #ifdef UNDER_CE
29 500
30 #else
31 100
32 #endif
33 ;
34
35 static const UINT kCreateDelay =
36 #ifdef UNDER_CE
37 2500
38 #else
39 500
40 #endif
41 ;
42
43 static const DWORD kPauseSleepTime = 100;
44
45 #include "LangUtils.h"
46
47 #ifdef LANG
48
49 static const UInt32 kLangIDs[] =
50 {
51 IDT_PROGRESS_ELAPSED,
52 IDT_PROGRESS_REMAINING,
53 IDT_PROGRESS_TOTAL,
54 IDT_PROGRESS_SPEED,
55 IDT_PROGRESS_PROCESSED,
56 IDT_PROGRESS_RATIO,
57 IDT_PROGRESS_ERRORS,
58 IDB_PROGRESS_BACKGROUND,
59 IDB_PAUSE
60 };
61
62 static const UInt32 kLangIDs_Colon[] =
63 {
64 IDT_PROGRESS_PACKED,
65 IDT_PROGRESS_FILES
66 };
67
68 #endif
69
70
71 #define UNDEFINED_VAL ((UInt64)(Int64)-1)
72 #define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL;
73 #define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL)
74 #define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL)
75
CProgressSync()76 CProgressSync::CProgressSync():
77 _stopped(false), _paused(false),
78 _bytesProgressMode(true),
79 _totalBytes(UNDEFINED_VAL), _completedBytes(0),
80 _totalFiles(UNDEFINED_VAL), _curFiles(0),
81 _inSize(UNDEFINED_VAL),
82 _outSize(UNDEFINED_VAL),
83 _isDir(false)
84 {}
85
86 #define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK;
87 #define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs);
88
Get_Paused()89 bool CProgressSync::Get_Paused()
90 {
91 CRITICAL_LOCK
92 return _paused;
93 }
94
CheckStop()95 HRESULT CProgressSync::CheckStop()
96 {
97 for (;;)
98 {
99 {
100 CRITICAL_LOCK
101 CHECK_STOP
102 }
103 ::Sleep(kPauseSleepTime);
104 }
105 }
106
ScanProgress(UInt64 numFiles,UInt64 totalSize,const UString & fileName,bool isDir)107 HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const UString &fileName, bool isDir)
108 {
109 {
110 CRITICAL_LOCK
111 _totalFiles = numFiles;
112 _totalBytes = totalSize;
113 _filePath = fileName;
114 _isDir = isDir;
115 // _completedBytes = 0;
116 CHECK_STOP
117 }
118 return CheckStop();
119 }
120
Set_NumFilesTotal(UInt64 val)121 void CProgressSync::Set_NumFilesTotal(UInt64 val)
122 {
123 CRITICAL_LOCK
124 _totalFiles = val;
125 }
126
Set_NumBytesTotal(UInt64 val)127 void CProgressSync::Set_NumBytesTotal(UInt64 val)
128 {
129 CRITICAL_LOCK
130 _totalBytes = val;
131 }
132
Set_NumFilesCur(UInt64 val)133 void CProgressSync::Set_NumFilesCur(UInt64 val)
134 {
135 CRITICAL_LOCK
136 _curFiles = val;
137 }
138
Set_NumBytesCur(const UInt64 * val)139 HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val)
140 {
141 {
142 CRITICAL_LOCK
143 if (val)
144 _completedBytes = *val;
145 CHECK_STOP
146 }
147 return CheckStop();
148 }
149
Set_NumBytesCur(UInt64 val)150 HRESULT CProgressSync::Set_NumBytesCur(UInt64 val)
151 {
152 {
153 CRITICAL_LOCK
154 _completedBytes = val;
155 CHECK_STOP
156 }
157 return CheckStop();
158 }
159
Set_Ratio(const UInt64 * inSize,const UInt64 * outSize)160 void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize)
161 {
162 CRITICAL_LOCK
163 if (inSize)
164 _inSize = *inSize;
165 if (outSize)
166 _outSize = *outSize;
167 }
168
Set_TitleFileName(const UString & fileName)169 void CProgressSync::Set_TitleFileName(const UString &fileName)
170 {
171 CRITICAL_LOCK
172 _titleFileName = fileName;
173 }
Set_Status(const UString & s)174 void CProgressSync::Set_Status(const UString &s)
175 {
176 CRITICAL_LOCK
177 _status = s;
178 }
179
Set_FilePath(const UString & path,bool isDir)180 void CProgressSync::Set_FilePath(const UString &path, bool isDir)
181 {
182 CRITICAL_LOCK
183 _filePath = path;
184 _isDir = isDir;
185 }
186
187
AddError_Message(const wchar_t * message)188 void CProgressSync::AddError_Message(const wchar_t *message)
189 {
190 CRITICAL_LOCK
191 Messages.Add(message);
192 }
193
AddError_Message_Name(const wchar_t * message,const wchar_t * name)194 void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name)
195 {
196 UString s;
197 if (name && *name != 0)
198 s += name;
199 if (message && *message != 0 )
200 {
201 if (!s.IsEmpty())
202 s += L'\n';
203 s += message;
204 if (!s.IsEmpty() && s.Back() == L'\n')
205 s.DeleteBack();
206 }
207 AddError_Message(s);
208 }
209
AddError_Code_Name(DWORD systemError,const wchar_t * name)210 void CProgressSync::AddError_Code_Name(DWORD systemError, const wchar_t *name)
211 {
212 UString s = NError::MyFormatMessage(systemError);
213 if (systemError == 0)
214 s = L"Error";
215 AddError_Message_Name(s, name);
216 }
217
CProgressDialog()218 CProgressDialog::CProgressDialog(): _timer(0), CompressingMode(true), MainWindow(0)
219 {
220 _isDir = false;
221
222 _numMessages = 0;
223 IconID = -1;
224 MessagesDisplayed = false;
225 _wasCreated = false;
226 _needClose = false;
227 _inCancelMessageBox = false;
228 _externalCloseMessageWasReceived = false;
229
230 _numPostedMessages = 0;
231 _numAutoSizeMessages = 0;
232 _errorsWereDisplayed = false;
233 _waitCloseByCancelButton = false;
234 _cancelWasPressed = false;
235 ShowCompressionInfo = true;
236 WaitMode = false;
237 if (_dialogCreatedEvent.Create() != S_OK)
238 throw 1334987;
239 if (_createDialogEvent.Create() != S_OK)
240 throw 1334987;
241 #ifdef __ITaskbarList3_INTERFACE_DEFINED__
242 CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList);
243 if (_taskbarList)
244 _taskbarList->HrInit();
245 #endif
246 }
247
248 #ifndef _SFX
249
~CProgressDialog()250 CProgressDialog::~CProgressDialog()
251 {
252 #ifdef __ITaskbarList3_INTERFACE_DEFINED__
253 SetTaskbarProgressState(TBPF_NOPROGRESS);
254 #endif
255 AddToTitle(L"");
256 }
AddToTitle(LPCWSTR s)257 void CProgressDialog::AddToTitle(LPCWSTR s)
258 {
259 if (MainWindow != 0)
260 {
261 CWindow window(MainWindow);
262 window.SetText((UString)s + MainTitle);
263 }
264 }
265
266 #endif
267
268
SetTaskbarProgressState()269 void CProgressDialog::SetTaskbarProgressState()
270 {
271 #ifdef __ITaskbarList3_INTERFACE_DEFINED__
272 if (_taskbarList && _hwndForTaskbar)
273 {
274 TBPFLAG tbpFlags;
275 if (Sync.Get_Paused())
276 tbpFlags = TBPF_PAUSED;
277 else
278 tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL;
279 SetTaskbarProgressState(tbpFlags);
280 }
281 #endif
282 }
283
284 static const unsigned kTitleFileNameSizeLimit = 36;
285 static const unsigned kCurrentFileNameSizeLimit = 82;
286
ReduceString(UString & s,unsigned size)287 static void ReduceString(UString &s, unsigned size)
288 {
289 if (s.Len() <= size)
290 return;
291 s.Delete(size / 2, s.Len() - size);
292 s.Insert(size / 2, L" ... ");
293 }
294
EnableErrorsControls(bool enable)295 void CProgressDialog::EnableErrorsControls(bool enable)
296 {
297 ShowItem_Bool(IDT_PROGRESS_ERRORS, enable);
298 ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable);
299 ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable);
300 }
301
OnInit()302 bool CProgressDialog::OnInit()
303 {
304 _hwndForTaskbar = MainWindow;
305 if (!_hwndForTaskbar)
306 _hwndForTaskbar = GetParent();
307 if (!_hwndForTaskbar)
308 _hwndForTaskbar = *this;
309
310 INIT_AS_UNDEFINED(_progressBar_Range);
311 INIT_AS_UNDEFINED(_progressBar_Pos);
312
313 INIT_AS_UNDEFINED(_prevPercentValue);
314 INIT_AS_UNDEFINED(_prevElapsedSec);
315 INIT_AS_UNDEFINED(_prevRemainingSec);
316
317 INIT_AS_UNDEFINED(_prevSpeed);
318 _prevSpeed_MoveBits = 0;
319
320 _prevTime = ::GetTickCount();
321 _elapsedTime = 0;
322
323 INIT_AS_UNDEFINED(_totalBytes_Prev);
324 INIT_AS_UNDEFINED(_processed_Prev);
325 INIT_AS_UNDEFINED(_packed_Prev);
326 INIT_AS_UNDEFINED(_ratio_Prev);
327 _filesStr_Prev.Empty();
328
329 _foreground = true;
330
331 m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
332 _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));
333 _messageList.SetUnicodeFormat();
334
335 _wasCreated = true;
336 _dialogCreatedEvent.Set();
337
338 #ifdef LANG
339 LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
340 LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon));
341 #endif
342
343 CWindow window(GetItem(IDB_PROGRESS_BACKGROUND));
344 window.GetText(_background_String);
345 _backgrounded_String = _background_String;
346 _backgrounded_String.RemoveChar(L'&');
347
348 window = GetItem(IDB_PAUSE);
349 window.GetText(_pause_String);
350
351 LangString(IDS_PROGRESS_FOREGROUND, _foreground_String);
352 LangString(IDS_CONTINUE, _continue_String);
353 LangString(IDS_PROGRESS_PAUSED, _paused_String);
354
355 SetText(_title);
356 SetPauseText();
357 SetPriorityText();
358
359 _messageList.InsertColumn(0, L"", 30);
360 _messageList.InsertColumn(1, L"", 600);
361
362 _messageList.SetColumnWidthAuto(0);
363 _messageList.SetColumnWidthAuto(1);
364
365 EnableErrorsControls(false);
366
367 GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY);
368 _numReduceSymbols = kCurrentFileNameSizeLimit;
369 NormalizeSize(true);
370
371 if (!ShowCompressionInfo)
372 {
373 HideItem(IDT_PROGRESS_PACKED);
374 HideItem(IDT_PROGRESS_PACKED_VAL);
375 HideItem(IDT_PROGRESS_RATIO);
376 HideItem(IDT_PROGRESS_RATIO_VAL);
377 }
378
379 if (IconID >= 0)
380 {
381 HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
382 // SetIcon(ICON_SMALL, icon);
383 SetIcon(ICON_BIG, icon);
384 }
385 _timer = SetTimer(kTimerID, kTimerElapse);
386 #ifdef UNDER_CE
387 Foreground();
388 #endif
389
390 CheckNeedClose();
391
392 SetTaskbarProgressState();
393
394 return CModalDialog::OnInit();
395 }
396
397 static const UINT kIDs[] =
398 {
399 IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL,
400 IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL,
401 IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL,
402 IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL,
403 IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL,
404
405 IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL,
406 IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL,
407 IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL,
408 IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL
409 };
410
OnSize(WPARAM,int xSize,int ySize)411 bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
412 {
413 int sY;
414 int sStep;
415 int mx, my;
416 {
417 RECT r;
418 GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r);
419 mx = r.left;
420 my = r.top;
421 sY = RECT_SIZE_Y(r);
422 GetClientRectOfItem(IDT_PROGRESS_REMAINING, r);
423 sStep = r.top - my;
424 }
425
426 InvalidateRect(NULL);
427
428 int xSizeClient = xSize - mx * 2;
429
430 {
431 int i;
432 for (i = 800; i > 40; i = i * 9 / 10)
433 if (Units_To_Pixels_X(i) <= xSizeClient)
434 break;
435 _numReduceSymbols = i / 4;
436 }
437
438 int yPos = ySize - my - _buttonSizeY;
439
440 ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2);
441 ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2);
442 ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2);
443
444 int bSizeX = _buttonSizeX;
445 int mx2 = mx;
446 for (;; mx2--)
447 {
448 int bSize2 = bSizeX * 3 + mx2 * 2;
449 if (bSize2 <= xSizeClient)
450 break;
451 if (mx2 < 5)
452 {
453 bSizeX = (xSizeClient - mx2 * 2) / 3;
454 break;
455 }
456 }
457 if (bSizeX < 2)
458 bSizeX = 2;
459
460 {
461 RECT r;
462 GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r);
463 int y = r.top;
464 int ySize2 = yPos - my - y;
465 const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4;
466 int xx = xSize - mx * 2;
467 if (ySize2 < kMinYSize)
468 {
469 ySize2 = kMinYSize;
470 if (xx > bSizeX * 2)
471 xx -= bSizeX;
472 }
473
474 _messageList.Move(mx, y, xx, ySize2);
475 }
476
477 {
478 int xPos = xSize - mx;
479 xPos -= bSizeX;
480 MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY);
481 xPos -= (mx2 + bSizeX);
482 MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY);
483 xPos -= (mx2 + bSizeX);
484 MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY);
485 }
486
487 int valueSize;
488 int labelSize;
489 int padSize;
490
491 labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN);
492 valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS);
493 padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS);
494 int requiredSize = (labelSize + valueSize) * 2 + padSize;
495
496 int gSize;
497 {
498 if (requiredSize < xSizeClient)
499 {
500 int incr = (xSizeClient - requiredSize) / 3;
501 labelSize += incr;
502 }
503 else
504 labelSize = (xSizeClient - valueSize * 2 - padSize) / 2;
505 if (labelSize < 0)
506 labelSize = 0;
507
508 gSize = labelSize + valueSize;
509 padSize = xSizeClient - gSize * 2;
510 }
511
512 labelSize = gSize - valueSize;
513
514 yPos = my;
515 for (int i = 0; i < ARRAY_SIZE(kIDs); i += 2)
516 {
517 int x = mx;
518 const int kNumColumn1Items = 5 * 2;
519 if (i >= kNumColumn1Items)
520 {
521 if (i == kNumColumn1Items)
522 yPos = my;
523 x = mx + gSize + padSize;
524 }
525 MoveItem(kIDs[i], x, yPos, labelSize, sY);
526 MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY);
527 yPos += sStep;
528 }
529 return false;
530 }
531
OnCancel()532 void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); }
OnOK()533 void CProgressDialog::OnOK() { }
534
SetProgressRange(UInt64 range)535 void CProgressDialog::SetProgressRange(UInt64 range)
536 {
537 if (range == _progressBar_Range)
538 return;
539 _progressBar_Range = range;
540 INIT_AS_UNDEFINED(_progressBar_Pos);
541 _progressConv.Init(range);
542 m_ProgressBar.SetRange32(0, _progressConv.Count(range));
543 }
544
SetProgressPos(UInt64 pos)545 void CProgressDialog::SetProgressPos(UInt64 pos)
546 {
547 if (pos >= _progressBar_Range ||
548 pos <= _progressBar_Pos ||
549 pos - _progressBar_Pos >= (_progressBar_Range >> 10))
550 {
551 m_ProgressBar.SetPos(_progressConv.Count(pos));
552 #ifdef __ITaskbarList3_INTERFACE_DEFINED__
553 if (_taskbarList && _hwndForTaskbar)
554 _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range);
555 #endif
556 _progressBar_Pos = pos;
557 }
558 }
559
560 #define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; }
561
GetTimeString(UInt64 timeValue,wchar_t * s)562 void GetTimeString(UInt64 timeValue, wchar_t *s)
563 {
564 UInt64 hours = timeValue / 3600;
565 UInt32 seconds = (UInt32)(timeValue - hours * 3600);
566 UInt32 minutes = seconds / 60;
567 seconds %= 60;
568 if (hours > 99)
569 {
570 ConvertUInt64ToString(hours, s);
571 for (; *s != 0; s++);
572 }
573 else
574 {
575 UInt32 hours32 = (UInt32)hours;
576 UINT_TO_STR_2(hours32);
577 }
578 *s++ = ':'; UINT_TO_STR_2(minutes);
579 *s++ = ':'; UINT_TO_STR_2(seconds);
580 *s = 0;
581 }
582
ConvertSizeToString(UInt64 v,wchar_t * s)583 static void ConvertSizeToString(UInt64 v, wchar_t *s)
584 {
585 Byte c = 0;
586 if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; }
587 else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; }
588 else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; }
589 ConvertUInt64ToString(v, s);
590 if (c != 0)
591 {
592 s += MyStringLen(s);
593 *s++ = ' ';
594 *s++ = c;
595 *s++ = 0;
596 }
597 }
598
ShowSize(int id,UInt64 val,UInt64 & prev)599 void CProgressDialog::ShowSize(int id, UInt64 val, UInt64 &prev)
600 {
601 if (val == prev)
602 return;
603 prev = val;
604 wchar_t s[40];
605 s[0] = 0;
606 if (IS_DEFINED_VAL(val))
607 ConvertSizeToString(val, s);
608 SetItemText(id, s);
609 }
610
GetChangedString(const UString & newStr,UString & prevStr,bool & hasChanged)611 static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged)
612 {
613 hasChanged = !(prevStr == newStr);
614 if (hasChanged)
615 prevStr = newStr;
616 }
617
GetPower32(UInt32 val)618 static unsigned GetPower32(UInt32 val)
619 {
620 const unsigned kStart = 32;
621 UInt32 mask = ((UInt32)1 << (kStart - 1));
622 for (unsigned i = kStart;; i--)
623 {
624 if (i == 0 || (val & mask) != 0)
625 return i;
626 mask >>= 1;
627 }
628 }
629
GetPower64(UInt64 val)630 static unsigned GetPower64(UInt64 val)
631 {
632 UInt32 high = (UInt32)(val >> 32);
633 if (high == 0)
634 return GetPower32((UInt32)val);
635 return GetPower32(high) + 32;
636
637 }
638
MyMultAndDiv(UInt64 mult1,UInt64 mult2,UInt64 divider)639 static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
640 {
641 unsigned pow1 = GetPower64(mult1);
642 unsigned pow2 = GetPower64(mult2);
643 while (pow1 + pow2 > 64)
644 {
645 if (pow1 > pow2) { pow1--; mult1 >>= 1; }
646 else { pow2--; mult2 >>= 1; }
647 divider >>= 1;
648 }
649 UInt64 res = mult1 * mult2;
650 if (divider != 0)
651 res /= divider;
652 return res;
653 }
654
UpdateStatInfo(bool showAll)655 void CProgressDialog::UpdateStatInfo(bool showAll)
656 {
657 UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
658 bool bytesProgressMode;
659
660 bool titleFileName_Changed;
661 bool curFilePath_Changed;
662 bool status_Changed;
663 unsigned numErrors;
664 {
665 NSynchronization::CCriticalSectionLock lock(Sync._cs);
666 total = Sync._totalBytes;
667 completed = Sync._completedBytes;
668 totalFiles = Sync._totalFiles;
669 completedFiles = Sync._curFiles;
670 inSize = Sync._inSize;
671 outSize = Sync._outSize;
672 bytesProgressMode = Sync._bytesProgressMode;
673
674 GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed);
675 GetChangedString(Sync._filePath, _filePath, curFilePath_Changed);
676 GetChangedString(Sync._status, _status, status_Changed);
677 if (_isDir != Sync._isDir)
678 {
679 curFilePath_Changed = true;
680 _isDir = Sync._isDir;
681 }
682 numErrors = Sync.Messages.Size();
683 }
684
685 UInt32 curTime = ::GetTickCount();
686
687 {
688 UInt64 progressTotal = bytesProgressMode ? total : totalFiles;
689 UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles;
690
691 if (IS_UNDEFINED_VAL(progressTotal))
692 {
693 // SetPos(0);
694 // SetRange(progressCompleted);
695 }
696 else
697 {
698 if (_progressBar_Pos != 0 || progressCompleted != 0 ||
699 (_progressBar_Range == 0 && progressTotal != 0))
700 {
701 SetProgressRange(progressTotal);
702 SetProgressPos(progressCompleted);
703 }
704 }
705 }
706
707 ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev);
708
709 _elapsedTime += (curTime - _prevTime);
710 _prevTime = curTime;
711 UInt64 elapsedSec = _elapsedTime / 1000;
712 bool elapsedChanged = false;
713 if (elapsedSec != _prevElapsedSec)
714 {
715 _prevElapsedSec = elapsedSec;
716 elapsedChanged = true;
717 wchar_t s[40];
718 GetTimeString(elapsedSec, s);
719 SetItemText(IDT_PROGRESS_ELAPSED_VAL, s);
720 }
721
722 bool needSetTitle = false;
723 if (elapsedChanged || showAll)
724 {
725 if (numErrors > _numPostedMessages)
726 {
727 UpdateMessagesDialog();
728 wchar_t s[32];
729 ConvertUInt64ToString(numErrors, s);
730 SetItemText(IDT_PROGRESS_ERRORS_VAL, s);
731 if (!_errorsWereDisplayed)
732 {
733 _errorsWereDisplayed = true;
734 EnableErrorsControls(true);
735 SetTaskbarProgressState();
736 }
737 }
738
739 if (completed != 0)
740 {
741 if (IS_UNDEFINED_VAL(total))
742 {
743 if (IS_DEFINED_VAL(_prevRemainingSec))
744 {
745 INIT_AS_UNDEFINED(_prevRemainingSec);
746 SetItemText(IDT_PROGRESS_REMAINING_VAL, L"");
747 }
748 }
749 else
750 {
751 UInt64 remainingTime = 0;
752 if (completed < total)
753 remainingTime = MyMultAndDiv(_elapsedTime, total - completed, completed);
754 UInt64 remainingSec = remainingTime / 1000;
755 if (remainingSec != _prevRemainingSec)
756 {
757 _prevRemainingSec = remainingSec;
758 wchar_t s[40];
759 GetTimeString(remainingSec, s);
760 SetItemText(IDT_PROGRESS_REMAINING_VAL, s);
761 }
762 }
763 {
764 UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;
765 UInt64 v = (completed * 1000) / elapsedTime;
766 Byte c = 0;
767 unsigned moveBits = 0;
768 if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; }
769 else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; }
770 v >>= moveBits;
771 if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed)
772 {
773 _prevSpeed_MoveBits = moveBits;
774 _prevSpeed = v;
775 wchar_t s[40];
776 ConvertUInt64ToString(v, s);
777 unsigned pos = MyStringLen(s);
778 s[pos++] = ' ';
779 if (moveBits != 0)
780 s[pos++] = c;
781 s[pos++] = 'B';
782 s[pos++] = '/';
783 s[pos++] = 's';
784 s[pos++] = 0;
785 SetItemText(IDT_PROGRESS_SPEED_VAL, s);
786 }
787 }
788 }
789
790 {
791 UInt64 percent = 0;
792 {
793 if (IS_DEFINED_VAL(total))
794 {
795 percent = completed * 100;
796 if (total != 0)
797 percent /= total;
798 }
799 }
800 if (percent != _prevPercentValue)
801 {
802 _prevPercentValue = percent;
803 needSetTitle = true;
804 }
805 }
806
807 {
808 wchar_t s[64];
809 ConvertUInt64ToString(completedFiles, s);
810 if (IS_DEFINED_VAL(totalFiles))
811 {
812 wcscat(s, L" / ");
813 ConvertUInt64ToString(totalFiles, s + wcslen(s));
814 }
815 if (_filesStr_Prev != s)
816 {
817 _filesStr_Prev = s;
818 SetItemText(IDT_PROGRESS_FILES_VAL, s);
819 }
820 }
821
822 const UInt64 packSize = CompressingMode ? outSize : inSize;
823 const UInt64 unpackSize = CompressingMode ? inSize : outSize;
824
825 if (IS_UNDEFINED_VAL(unpackSize) &&
826 IS_UNDEFINED_VAL(packSize))
827 {
828 ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev);
829 ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev);
830 }
831 else
832 {
833 ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev);
834 ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev);
835
836 if (IS_DEFINED_VAL(packSize) &&
837 IS_DEFINED_VAL(unpackSize) &&
838 unpackSize != 0)
839 {
840 wchar_t s[32];
841 UInt64 ratio = packSize * 100 / unpackSize;
842 if (_ratio_Prev != ratio)
843 {
844 _ratio_Prev = ratio;
845 ConvertUInt64ToString(ratio, s);
846 wcscat(s, L"%");
847 SetItemText(IDT_PROGRESS_RATIO_VAL, s);
848 }
849 }
850 }
851 }
852
853 if (needSetTitle || titleFileName_Changed)
854 SetTitleText();
855
856 if (status_Changed)
857 {
858 UString s = _status;
859 ReduceString(s, _numReduceSymbols);
860 SetItemText(IDT_PROGRESS_STATUS, _status);
861 }
862
863 if (curFilePath_Changed)
864 {
865 UString s1, s2;
866 if (_isDir)
867 s1 = _filePath;
868 else
869 {
870 int slashPos = _filePath.ReverseFind(WCHAR_PATH_SEPARATOR);
871 if (slashPos >= 0)
872 {
873 s1.SetFrom(_filePath, slashPos + 1);
874 s2 = _filePath.Ptr(slashPos + 1);
875 }
876 else
877 s2 = _filePath;
878 }
879 ReduceString(s1, _numReduceSymbols);
880 ReduceString(s2, _numReduceSymbols);
881 s1 += L'\n';
882 s1 += s2;
883 SetItemText(IDT_PROGRESS_FILE_NAME, s1);
884 }
885 }
886
OnTimer(WPARAM,LPARAM)887 bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
888 {
889 if (Sync.Get_Paused())
890 return true;
891 CheckNeedClose();
892 UpdateStatInfo(false);
893 return true;
894 }
895
896 struct CWaitCursor
897 {
898 HCURSOR _waitCursor;
899 HCURSOR _oldCursor;
CWaitCursorCWaitCursor900 CWaitCursor()
901 {
902 _waitCursor = LoadCursor(NULL, IDC_WAIT);
903 if (_waitCursor != NULL)
904 _oldCursor = SetCursor(_waitCursor);
905 }
~CWaitCursorCWaitCursor906 ~CWaitCursor()
907 {
908 if (_waitCursor != NULL)
909 SetCursor(_oldCursor);
910 }
911 };
912
Create(const UString & title,NWindows::CThread & thread,HWND wndParent)913 INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent)
914 {
915 INT_PTR res = 0;
916 try
917 {
918 if (WaitMode)
919 {
920 CWaitCursor waitCursor;
921 HANDLE h[] = { thread, _createDialogEvent };
922
923 WRes res = WaitForMultipleObjects(ARRAY_SIZE(h), h, FALSE, kCreateDelay);
924 if (res == WAIT_OBJECT_0 && !Sync.ThereIsMessage())
925 return 0;
926 }
927 _title = title;
928 BIG_DIALOG_SIZE(360, 192);
929 res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent);
930 }
931 catch(...)
932 {
933 _wasCreated = true;
934 _dialogCreatedEvent.Set();
935 res = res;
936 }
937 thread.Wait();
938 if (!MessagesDisplayed)
939 MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR);
940 return res;
941 }
942
OnExternalCloseMessage()943 bool CProgressDialog::OnExternalCloseMessage()
944 {
945 // it doesn't work if there is MessageBox.
946 #ifdef __ITaskbarList3_INTERFACE_DEFINED__
947 SetTaskbarProgressState(TBPF_NOPROGRESS);
948 #endif
949 // AddToTitle(L"Finished ");
950 // SetText(L"Finished2 ");
951
952 UpdateStatInfo(true);
953
954 SetItemText(IDCANCEL, LangString(IDS_CLOSE));
955 ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));
956 HideItem(IDB_PROGRESS_BACKGROUND);
957 HideItem(IDB_PAUSE);
958
959 bool thereAreMessages;
960 CProgressFinalMessage fm;
961 {
962 NSynchronization::CCriticalSectionLock lock(Sync._cs);
963 thereAreMessages = !Sync.Messages.IsEmpty();
964 fm = Sync.FinalMessage;
965 }
966 if (!fm.ErrorMessage.Message.IsEmpty())
967 {
968 MessagesDisplayed = true;
969 if (fm.ErrorMessage.Title.IsEmpty())
970 fm.ErrorMessage.Title = L"7-Zip";
971 MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR);
972 }
973 else if (!thereAreMessages)
974 {
975 MessagesDisplayed = true;
976 if (!fm.OkMessage.Message.IsEmpty())
977 {
978 if (fm.OkMessage.Title.IsEmpty())
979 fm.OkMessage.Title = L"7-Zip";
980 MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);
981 }
982 }
983
984 if (thereAreMessages && !_cancelWasPressed)
985 {
986 _waitCloseByCancelButton = true;
987 UpdateMessagesDialog();
988 return true;
989 }
990
991 End(0);
992 return true;
993 }
994
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)995 bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
996 {
997 switch (message)
998 {
999 case kCloseMessage:
1000 {
1001 KillTimer(_timer);
1002 _timer = 0;
1003 if (_inCancelMessageBox)
1004 {
1005 _externalCloseMessageWasReceived = true;
1006 break;
1007 }
1008 return OnExternalCloseMessage();
1009 }
1010 /*
1011 case WM_SETTEXT:
1012 {
1013 if (_timer == 0)
1014 return true;
1015 break;
1016 }
1017 */
1018 }
1019 return CModalDialog::OnMessage(message, wParam, lParam);
1020 }
1021
SetTitleText()1022 void CProgressDialog::SetTitleText()
1023 {
1024 UString s;
1025 if (Sync.Get_Paused())
1026 {
1027 s += _paused_String;
1028 s += L' ';
1029 }
1030 if (IS_DEFINED_VAL(_prevPercentValue))
1031 {
1032 wchar_t temp[32];
1033 ConvertUInt64ToString(_prevPercentValue, temp);
1034 s += temp;
1035 s += L'%';
1036 }
1037 if (!_foreground)
1038 {
1039 s += L' ';
1040 s += _backgrounded_String;
1041 }
1042
1043 s += L' ';
1044 #ifndef _SFX
1045 {
1046 unsigned len = s.Len();
1047 s += MainAddTitle;
1048 AddToTitle(s);
1049 s.DeleteFrom(len);
1050 }
1051 #endif
1052
1053 s += _title;
1054 if (!_titleFileName.IsEmpty())
1055 {
1056 UString fileName = _titleFileName;
1057 ReduceString(fileName, kTitleFileNameSizeLimit);
1058 s += L' ';
1059 s += fileName;
1060 }
1061 SetText(s);
1062 }
1063
SetPauseText()1064 void CProgressDialog::SetPauseText()
1065 {
1066 SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String);
1067 SetTitleText();
1068 }
1069
OnPauseButton()1070 void CProgressDialog::OnPauseButton()
1071 {
1072 bool paused = !Sync.Get_Paused();
1073 Sync.Set_Paused(paused);
1074 UInt32 curTime = ::GetTickCount();
1075 if (paused)
1076 _elapsedTime += (curTime - _prevTime);
1077 SetTaskbarProgressState();
1078 _prevTime = curTime;
1079 SetPauseText();
1080 }
1081
SetPriorityText()1082 void CProgressDialog::SetPriorityText()
1083 {
1084 SetItemText(IDB_PROGRESS_BACKGROUND, _foreground ?
1085 _background_String :
1086 _foreground_String);
1087 SetTitleText();
1088 }
1089
OnPriorityButton()1090 void CProgressDialog::OnPriorityButton()
1091 {
1092 _foreground = !_foreground;
1093 #ifndef UNDER_CE
1094 SetPriorityClass(GetCurrentProcess(), _foreground ? NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS);
1095 #endif
1096 SetPriorityText();
1097 }
1098
AddMessageDirect(LPCWSTR message,bool needNumber)1099 void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber)
1100 {
1101 int itemIndex = _messageList.GetItemCount();
1102 wchar_t sz[16];
1103 sz[0] = 0;
1104 if (needNumber)
1105 ConvertUInt32ToString(_numMessages + 1, sz);
1106 _messageList.InsertItem(itemIndex, sz);
1107 _messageList.SetSubItem(itemIndex, 1, message);
1108 }
1109
AddMessage(LPCWSTR message)1110 void CProgressDialog::AddMessage(LPCWSTR message)
1111 {
1112 UString s = message;
1113 bool needNumber = true;
1114 while (!s.IsEmpty())
1115 {
1116 int pos = s.Find(L'\n');
1117 if (pos < 0)
1118 break;
1119 AddMessageDirect(s.Left(pos), needNumber);
1120 needNumber = false;
1121 s.DeleteFrontal(pos + 1);
1122 }
1123 AddMessageDirect(s, needNumber);
1124 _numMessages++;
1125 }
1126
GetNumDigits(UInt32 val)1127 static unsigned GetNumDigits(UInt32 val)
1128 {
1129 unsigned i;
1130 for (i = 0; val >= 10; i++)
1131 val /= 10;
1132 return i;
1133 }
1134
UpdateMessagesDialog()1135 void CProgressDialog::UpdateMessagesDialog()
1136 {
1137 UStringVector messages;
1138 {
1139 NSynchronization::CCriticalSectionLock lock(Sync._cs);
1140 unsigned num = Sync.Messages.Size();
1141 if (num > _numPostedMessages)
1142 {
1143 messages.ClearAndReserve(num - _numPostedMessages);
1144 for (unsigned i = _numPostedMessages; i < num; i++)
1145 messages.AddInReserved(Sync.Messages[i]);
1146 _numPostedMessages = num;
1147 }
1148 }
1149 if (!messages.IsEmpty())
1150 {
1151 FOR_VECTOR (i, messages)
1152 AddMessage(messages[i]);
1153 if (_numAutoSizeMessages < 256 || GetNumDigits(_numPostedMessages) > GetNumDigits(_numAutoSizeMessages))
1154 {
1155 _messageList.SetColumnWidthAuto(0);
1156 _messageList.SetColumnWidthAuto(1);
1157 _numAutoSizeMessages = _numPostedMessages;
1158 }
1159 }
1160 }
1161
1162
OnButtonClicked(int buttonID,HWND buttonHWND)1163 bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
1164 {
1165 switch (buttonID)
1166 {
1167 // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON
1168 case IDCANCEL:
1169 {
1170 if (_waitCloseByCancelButton)
1171 {
1172 MessagesDisplayed = true;
1173 End(IDCLOSE);
1174 break;
1175 }
1176
1177 bool paused = Sync.Get_Paused();
1178 if (!paused)
1179 OnPauseButton();
1180 _inCancelMessageBox = true;
1181 int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL);
1182 _inCancelMessageBox = false;
1183 if (!paused)
1184 OnPauseButton();
1185 if (res == IDCANCEL || res == IDNO)
1186 {
1187 if (_externalCloseMessageWasReceived)
1188 OnExternalCloseMessage();
1189 return true;
1190 }
1191
1192 _cancelWasPressed = true;
1193 MessagesDisplayed = true;
1194 break;
1195 }
1196
1197 case IDB_PAUSE:
1198 OnPauseButton();
1199 return true;
1200 case IDB_PROGRESS_BACKGROUND:
1201 OnPriorityButton();
1202 return true;
1203 }
1204 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
1205 }
1206
CheckNeedClose()1207 void CProgressDialog::CheckNeedClose()
1208 {
1209 if (_needClose)
1210 {
1211 PostMessage(kCloseMessage);
1212 _needClose = false;
1213 }
1214 }
1215
ProcessWasFinished()1216 void CProgressDialog::ProcessWasFinished()
1217 {
1218 // Set Window title here.
1219 if (!WaitMode)
1220 WaitCreating();
1221
1222 if (_wasCreated)
1223 PostMessage(kCloseMessage);
1224 else
1225 _needClose = true;
1226 }
1227
1228
Create(const UString & title,HWND parentWindow)1229 HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow)
1230 {
1231 NWindows::CThread thread;
1232 RINOK(thread.Create(MyThreadFunction, this));
1233 ProgressDialog.Create(title, thread, parentWindow);
1234 return S_OK;
1235 }
1236
AddMessageToString(UString & dest,const UString & src)1237 static void AddMessageToString(UString &dest, const UString &src)
1238 {
1239 if (!src.IsEmpty())
1240 {
1241 if (!dest.IsEmpty())
1242 dest += L'\n';
1243 dest += src;
1244 }
1245 }
1246
Process()1247 void CProgressThreadVirt::Process()
1248 {
1249 CProgressCloser closer(ProgressDialog);
1250 UString m;
1251 try { Result = ProcessVirt(); }
1252 catch(const wchar_t *s) { m = s; }
1253 catch(const UString &s) { m = s; }
1254 catch(const char *s) { m = GetUnicodeString(s); }
1255 catch(int v)
1256 {
1257 wchar_t s[16];
1258 ConvertUInt32ToString(v, s);
1259 m = L"Error #";
1260 m += s;
1261 }
1262 catch(...) { m = L"Error"; }
1263 if (Result != E_ABORT)
1264 {
1265 if (m.IsEmpty() && Result != S_OK)
1266 m = HResultToMessage(Result);
1267 }
1268 AddMessageToString(m, FinalMessage.ErrorMessage.Message);
1269 AddMessageToString(m, fs2us(ErrorPath1));
1270 AddMessageToString(m, fs2us(ErrorPath2));
1271
1272 CProgressSync &sync = ProgressDialog.Sync;
1273 NSynchronization::CCriticalSectionLock lock(sync._cs);
1274 if (m.IsEmpty())
1275 {
1276 if (!FinalMessage.OkMessage.Message.IsEmpty())
1277 sync.FinalMessage.OkMessage = FinalMessage.OkMessage;
1278 }
1279 else
1280 {
1281 sync.FinalMessage.ErrorMessage.Message = m;
1282 if (Result == S_OK)
1283 Result = E_FAIL;
1284 }
1285 }
1286
HResultToMessage(HRESULT errorCode)1287 UString HResultToMessage(HRESULT errorCode)
1288 {
1289 if (errorCode == E_OUTOFMEMORY)
1290 return LangString(IDS_MEM_ERROR);
1291 else
1292 return NError::MyFormatMessage(errorCode);
1293 }
1294