Progress.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. //---------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include <CoreMain.h>
  6. #include <TextsWin.h>
  7. #include <HelpWin.h>
  8. #include <WinInterface.h>
  9. #include <VCLCommon.h>
  10. #include <CustomWinConfiguration.h>
  11. #include <GUITools.h>
  12. #include <BaseUtils.hpp>
  13. #include <DateUtils.hpp>
  14. #include "Progress.h"
  15. //---------------------------------------------------------------------
  16. #pragma link "HistoryComboBox"
  17. #pragma link "PathLabel"
  18. #ifndef NO_RESOURCES
  19. #pragma resource "*.dfm"
  20. #endif
  21. //---------------------------------------------------------------------
  22. UnicodeString __fastcall TProgressForm::OperationName(TFileOperation Operation)
  23. {
  24. static const int Captions[] = { PROGRESS_COPY, PROGRESS_MOVE, PROGRESS_DELETE,
  25. PROGRESS_SETPROPERTIES, 0, PROGRESS_CUSTOM_COMAND, PROGRESS_CALCULATE_SIZE,
  26. PROGRESS_REMOTE_MOVE, PROGRESS_REMOTE_COPY, PROGRESS_GETPROPERTIES,
  27. PROGRESS_CALCULATE_CHECKSUM };
  28. assert((unsigned int)Operation >= 1 && ((unsigned int)Operation - 1) < LENOF(Captions));
  29. return LoadStr(Captions[(int)Operation - 1]);
  30. }
  31. //---------------------------------------------------------------------
  32. __fastcall TProgressForm::TProgressForm(TComponent* AOwner)
  33. : FData(), TForm(AOwner)
  34. {
  35. FLastOperation = foNone;
  36. FLastTotalSizeSet = false;
  37. FDataReceived = false;
  38. FAsciiTransferChanged = false;
  39. FResumeStatusChanged = false;
  40. FCancel = csContinue;
  41. FMinimizedByMe = false;
  42. FUpdateCounter = 0;
  43. FLastUpdate = 0;
  44. FDeleteToRecycleBin = false;
  45. FReadOnly = false;
  46. FShowAsModalStorage = NULL;
  47. UseSystemSettings(this);
  48. ResetOnceDoneOperation();
  49. if (CustomWinConfiguration->OperationProgressOnTop)
  50. {
  51. FOperationProgress = TopProgress;
  52. FFileProgress = BottomProgress;
  53. }
  54. else
  55. {
  56. FOperationProgress = BottomProgress;
  57. FFileProgress = TopProgress;
  58. }
  59. if (!IsGlobalMinimizeHandler())
  60. {
  61. SetGlobalMinimizeHandler(GlobalMinimize);
  62. };
  63. }
  64. //---------------------------------------------------------------------------
  65. __fastcall TProgressForm::~TProgressForm()
  66. {
  67. // to prevent raising assertion (e.g. IsProgress == True)
  68. FData.Clear();
  69. if (GetGlobalMinimizeHandler() == GlobalMinimize)
  70. {
  71. SetGlobalMinimizeHandler(NULL);
  72. }
  73. if (IsApplicationMinimized() && FMinimizedByMe)
  74. {
  75. ShowNotification(NULL, LoadStr(BALLOON_OPERATION_COMPLETE), qtInformation);
  76. }
  77. ReleaseAsModal(this, FShowAsModalStorage);
  78. }
  79. //---------------------------------------------------------------------
  80. void __fastcall TProgressForm::UpdateControls()
  81. {
  82. assert((FData.Operation >= foCopy) && (FData.Operation <= foCalculateChecksum) &&
  83. FData.Operation != foRename );
  84. CancelButton->Enabled = !FReadOnly;
  85. OnceDoneOperationCombo->Enabled =
  86. !FReadOnly && (FData.Operation != foCalculateSize) &&
  87. (FData.Operation != foGetProperties) &&
  88. (FData.Operation != foCalculateChecksum);
  89. OnceDoneOperationLabel->Enabled = OnceDoneOperationCombo->Enabled;
  90. bool TransferOperation =
  91. ((FData.Operation == foCopy) || (FData.Operation == foMove));
  92. if (FData.Operation != FLastOperation)
  93. {
  94. bool AVisible;
  95. THandle ShellModule;
  96. try
  97. {
  98. AVisible = true;
  99. switch (FData.Operation) {
  100. case foCopy:
  101. case foMove:
  102. case foRemoteMove:
  103. case foRemoteCopy:
  104. if (FData.Count == 1) Animate->CommonAVI = aviCopyFile;
  105. else Animate->CommonAVI = aviCopyFiles;
  106. break;
  107. case foDelete:
  108. Animate->CommonAVI = (DeleteToRecycleBin ? aviRecycleFile : aviDeleteFile);
  109. break;
  110. case foSetProperties:
  111. case foGetProperties:
  112. ShellModule = SafeLoadLibrary(L"shell32.dll");
  113. if (!ShellModule)
  114. {
  115. Abort();
  116. }
  117. // workaround, VCL is not able to set both ResId and ResHandle otherwise
  118. Animate->Active = false;
  119. Animate->ResHandle = 0;
  120. Animate->ComponentState << csLoading;
  121. Animate->ResId = 165;
  122. Animate->ResHandle = ShellModule;
  123. Animate->ComponentState >> csLoading;
  124. Animate->Active = true;
  125. break;
  126. default:
  127. assert(FData.Operation == foCustomCommand ||
  128. FData.Operation == foCalculateSize ||
  129. FData.Operation == foCalculateChecksum);
  130. Animate->CommonAVI = aviNone;
  131. AVisible = false;
  132. }
  133. }
  134. catch (...)
  135. {
  136. AVisible = false;
  137. };
  138. int Delta = 0;
  139. if (AVisible && !Animate->Visible) Delta = Animate->Height;
  140. else
  141. if (!AVisible && Animate->Visible) Delta = -Animate->Height;
  142. MainPanel->Top = MainPanel->Top + Delta;
  143. TransferPanel->Top = TransferPanel->Top + Delta;
  144. SpeedPanel->Top = SpeedPanel->Top + Delta;
  145. Animate->Visible = AVisible;
  146. Animate->Active = AVisible;
  147. if (TransferOperation && !TransferPanel->Visible) Delta += TransferPanel->Height;
  148. else
  149. if (!TransferOperation && TransferPanel->Visible) Delta += -TransferPanel->Height;
  150. TransferPanel->Visible = TransferOperation;
  151. SpeedPanel->Visible = TransferOperation;
  152. ClientHeight = ClientHeight + Delta;
  153. Caption = OperationName(FData.Operation);
  154. TargetLabel->Visible = TransferOperation;
  155. TargetPathLabel->Visible = TransferOperation;
  156. TargetPathLabel->UnixPath = (FData.Side == osLocal);
  157. FileLabel->UnixPath = (FData.Side == osRemote);
  158. FLastOperation = FData.Operation;
  159. FLastTotalSizeSet = !FData.TotalSizeSet;
  160. };
  161. if (FLastTotalSizeSet != FData.TotalSizeSet)
  162. {
  163. StartTimeLabelLabel->Visible = !FData.TotalSizeSet;
  164. StartTimeLabel->Visible = !FData.TotalSizeSet;
  165. TimeLeftLabelLabel->Visible = FData.TotalSizeSet;
  166. TimeLeftLabel->Visible = FData.TotalSizeSet;
  167. FLastTotalSizeSet = FData.TotalSizeSet;
  168. }
  169. if ((FData.Side == osRemote) || !FData.Temp)
  170. {
  171. FileLabel->Caption = FData.FileName;
  172. }
  173. else
  174. {
  175. FileLabel->Caption = ExtractFileName(FData.FileName);
  176. }
  177. int OverallProgress = FData.OverallProgress();
  178. FOperationProgress->Position = OverallProgress;
  179. FOperationProgress->Hint = FORMAT(L"%d%%", (OverallProgress));
  180. Caption = FORMAT(L"%d%% %s", (OverallProgress, OperationName(FData.Operation)));
  181. if (TransferOperation)
  182. {
  183. if ((FData.Side == osLocal) || !FData.Temp)
  184. {
  185. TargetPathLabel->Caption = FData.Directory;
  186. }
  187. else
  188. {
  189. TargetPathLabel->Caption = LoadStr(PROGRESS_TEMP_DIR);
  190. }
  191. StartTimeLabel->Caption = FData.StartTime.TimeString();
  192. if (FData.TotalSizeSet)
  193. {
  194. TimeLeftLabel->Caption = FormatDateTimeSpan(Configuration->TimeFormat,
  195. FData.TotalTimeLeft());
  196. }
  197. TimeElapsedLabel->Caption = FormatDateTimeSpan(Configuration->TimeFormat, FData.TimeElapsed());
  198. BytesTransferedLabel->Caption = FormatBytes(FData.TotalTransfered);
  199. CPSLabel->Caption = FORMAT(L"%s/s", (FormatBytes(FData.CPS())));
  200. FFileProgress->Position = FData.TransferProgress();
  201. FFileProgress->Hint = FORMAT(L"%d%%", (FFileProgress->Position));
  202. }
  203. }
  204. //---------------------------------------------------------------------
  205. void __fastcall TProgressForm::SetProgressData(TFileOperationProgressType & AData)
  206. {
  207. bool InstantUpdate = false;
  208. // workaround: to force displaing first file data immediatelly,
  209. // otherwise form dialog uses to be blank for first second
  210. // (until UpdateTimerTimer)
  211. if (FileLabel->Caption.IsEmpty() && !AData.FileName.IsEmpty())
  212. {
  213. InstantUpdate = true;
  214. }
  215. if (!FAsciiTransferChanged && FData.AsciiTransfer != AData.AsciiTransfer)
  216. {
  217. FAsciiTransferChanged = true;
  218. InstantUpdate = true;
  219. }
  220. if (!FResumeStatusChanged && FData.ResumeStatus != AData.ResumeStatus)
  221. {
  222. FResumeStatusChanged = true;
  223. InstantUpdate = true;
  224. }
  225. FData = AData;
  226. // delay showing the progress until the application is restored,
  227. // otherwise the form popups up unminimized
  228. if (!FDataReceived && !IsApplicationMinimized())
  229. {
  230. FDataReceived = true;
  231. // CPS limit is set set only once from TFileOperationProgressType::Start
  232. FCPSLimit = AData.CPSLimit;
  233. SpeedCombo->Text = SetSpeedLimit(FCPSLimit);
  234. ShowAsModal(this, FShowAsModalStorage);
  235. // particularly needed for the case, when we are showing the form delayed
  236. // because application was minimized when operation started
  237. InstantUpdate = true;
  238. }
  239. if (InstantUpdate)
  240. {
  241. UpdateControls();
  242. Application->ProcessMessages();
  243. }
  244. TDateTime N = Now();
  245. static double UpdateInterval = static_cast<double>(OneSecond*5); // 1/5 sec
  246. if ((FUpdateCounter % 5 == 0) ||
  247. (double(N) - double(FLastUpdate) > UpdateInterval))
  248. {
  249. FLastUpdate = N;
  250. FUpdateCounter = 0;
  251. Application->ProcessMessages();
  252. }
  253. FUpdateCounter++;
  254. AData.CPSLimit = FCPSLimit;
  255. }
  256. //---------------------------------------------------------------------------
  257. void __fastcall TProgressForm::UpdateTimerTimer(TObject * /*Sender*/)
  258. {
  259. if (FDataReceived) UpdateControls();
  260. }
  261. //---------------------------------------------------------------------------
  262. void __fastcall TProgressForm::FormShow(TObject * /*Sender*/)
  263. {
  264. UpdateTimer->Enabled = true;
  265. SpeedCombo->Items = CustomWinConfiguration->History[L"SpeedLimit"];
  266. if (FDataReceived) UpdateControls();
  267. FLastUpdate = 0;
  268. }
  269. //---------------------------------------------------------------------------
  270. void __fastcall TProgressForm::FormHide(TObject * /*Sender*/)
  271. {
  272. // This is to counter the "infinite" timestamp in
  273. // TTerminalManager::ApplicationShowHint.
  274. // Because if form disappears on its own, hint is not hidden.
  275. Application->CancelHint();
  276. CustomWinConfiguration->History[L"SpeedLimit"] = SpeedCombo->Items;
  277. UpdateTimer->Enabled = false;
  278. }
  279. //---------------------------------------------------------------------------
  280. void __fastcall TProgressForm::CancelButtonClick(TObject * /*Sender*/)
  281. {
  282. CancelOperation();
  283. }
  284. //---------------------------------------------------------------------------
  285. void __fastcall TProgressForm::MinimizeButtonClick(TObject * Sender)
  286. {
  287. GetGlobalMinimizeHandler()(Sender);
  288. }
  289. //---------------------------------------------------------------------------
  290. void __fastcall TProgressForm::CancelOperation()
  291. {
  292. // partially duplicated in TWinSCPFileSystem::CancelConfiguration (far\WinSCPFileSystem)
  293. assert(FDataReceived);
  294. if (!FData.Suspended)
  295. {
  296. // mostly useless, as suspend is called over copy of actual progress data
  297. FData.Suspend();
  298. UpdateControls();
  299. try
  300. {
  301. TCancelStatus ACancel;
  302. int Result;
  303. if (FData.TransferingFile &&
  304. (FData.TimeExpected() > GUIConfiguration->IgnoreCancelBeforeFinish))
  305. {
  306. Result = MessageDialog(LoadStr(CANCEL_OPERATION_FATAL), qtWarning,
  307. qaYes | qaNo | qaCancel, HELP_PROGRESS_CANCEL);
  308. }
  309. else
  310. {
  311. Result = MessageDialog(LoadStr(CANCEL_OPERATION), qtConfirmation,
  312. qaOK | qaCancel, HELP_PROGRESS_CANCEL);
  313. }
  314. switch (Result) {
  315. case qaYes:
  316. ACancel = csCancelTransfer; break;
  317. case qaOK:
  318. case qaNo:
  319. ACancel = csCancel; break;
  320. default:
  321. ACancel = csContinue; break;
  322. }
  323. if (FCancel < ACancel)
  324. {
  325. FCancel = ACancel;
  326. }
  327. }
  328. __finally
  329. {
  330. FData.Resume();
  331. }
  332. }
  333. }
  334. //---------------------------------------------------------------------------
  335. void __fastcall TProgressForm::MinimizeApp()
  336. {
  337. Application->Minimize();
  338. FMinimizedByMe = true;
  339. }
  340. //---------------------------------------------------------------------------
  341. void __fastcall TProgressForm::GlobalMinimize(TObject * /*Sender*/)
  342. {
  343. MinimizeApp();
  344. }
  345. //---------------------------------------------------------------------------
  346. void __fastcall TProgressForm::SetOnceDoneOperation(TOnceDoneOperation value)
  347. {
  348. int Index = 0;
  349. switch (value)
  350. {
  351. case odoIdle:
  352. Index = 0;
  353. break;
  354. case odoDisconnect:
  355. Index = 1;
  356. break;
  357. case odoShutDown:
  358. Index = 2;
  359. break;
  360. default:
  361. assert(false);
  362. }
  363. OnceDoneOperationCombo->ItemIndex = Index;
  364. OnceDoneOperationComboSelect(NULL);
  365. }
  366. //---------------------------------------------------------------------------
  367. bool __fastcall TProgressForm::GetAllowMinimize()
  368. {
  369. return MinimizeButton->Visible;
  370. }
  371. //---------------------------------------------------------------------------
  372. void __fastcall TProgressForm::SetAllowMinimize(bool value)
  373. {
  374. MinimizeButton->Visible = value;
  375. }
  376. //---------------------------------------------------------------------------
  377. void __fastcall TProgressForm::SetReadOnly(bool value)
  378. {
  379. if (FReadOnly != value)
  380. {
  381. FReadOnly = value;
  382. if (!value)
  383. {
  384. ResetOnceDoneOperation();
  385. }
  386. UpdateControls();
  387. }
  388. }
  389. //---------------------------------------------------------------------------
  390. void __fastcall TProgressForm::ApplyCPSLimit()
  391. {
  392. try
  393. {
  394. FCPSLimit = GetSpeedLimit(SpeedCombo->Text);
  395. }
  396. catch(...)
  397. {
  398. SpeedCombo->SetFocus();
  399. throw;
  400. }
  401. SpeedCombo->Text = SetSpeedLimit(FCPSLimit);
  402. // visualize application
  403. SpeedCombo->SelectAll();
  404. CancelButton->SetFocus();
  405. }
  406. //---------------------------------------------------------------------------
  407. void __fastcall TProgressForm::SpeedComboExit(TObject * /*Sender*/)
  408. {
  409. SpeedCombo->Text = SetSpeedLimit(FCPSLimit);
  410. }
  411. //---------------------------------------------------------------------------
  412. void __fastcall TProgressForm::SpeedComboSelect(TObject * /*Sender*/)
  413. {
  414. ApplyCPSLimit();
  415. }
  416. //---------------------------------------------------------------------------
  417. void __fastcall TProgressForm::SpeedComboKeyPress(TObject * /*Sender*/,
  418. wchar_t & Key)
  419. {
  420. // using OnKeyPress instead of OnKeyDown to catch "enter" prevents
  421. // system beep for unhandled key
  422. if (Key == L'\r')
  423. {
  424. Key = L'\0';
  425. ApplyCPSLimit();
  426. }
  427. }
  428. //---------------------------------------------------------------------------
  429. void __fastcall TProgressForm::ResetOnceDoneOperation()
  430. {
  431. OnceDoneOperationCombo->ItemIndex = 0;
  432. OnceDoneOperationComboSelect(NULL);
  433. }
  434. //---------------------------------------------------------------------------
  435. void __fastcall TProgressForm::OnceDoneOperationComboSelect(TObject * /*Sender*/)
  436. {
  437. switch (OnceDoneOperationCombo->ItemIndex)
  438. {
  439. case 0:
  440. FOnceDoneOperation = odoIdle;
  441. break;
  442. case 1:
  443. FOnceDoneOperation = odoDisconnect;
  444. break;
  445. case 2:
  446. FOnceDoneOperation = odoShutDown;
  447. break;
  448. default:
  449. assert(false);
  450. }
  451. }
  452. //---------------------------------------------------------------------------
  453. void __fastcall TProgressForm::OnceDoneOperationComboCloseUp(TObject * /*Sender*/)
  454. {
  455. CancelButton->SetFocus();
  456. }
  457. //---------------------------------------------------------------------------
  458. #pragma warn -8080