FileOperationProgress.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "Common.h"
  5. #include "FileOperationProgress.h"
  6. //---------------------------------------------------------------------------
  7. #define TRANSFER_BUF_SIZE 4096
  8. //---------------------------------------------------------------------------
  9. __fastcall TFileOperationProgressType::TFileOperationProgressType()
  10. {
  11. FOnProgress = NULL;
  12. FOnFinished = NULL;
  13. Clear();
  14. }
  15. //---------------------------------------------------------------------------
  16. __fastcall TFileOperationProgressType::TFileOperationProgressType(
  17. TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished)
  18. {
  19. FOnProgress = AOnProgress;
  20. FOnFinished = AOnFinished;
  21. FReset = false;
  22. Clear();
  23. }
  24. //---------------------------------------------------------------------------
  25. __fastcall TFileOperationProgressType::~TFileOperationProgressType()
  26. {
  27. assert(!InProgress || FReset);
  28. assert(!Suspended || FReset);
  29. }
  30. //---------------------------------------------------------------------------
  31. void __fastcall TFileOperationProgressType::Clear()
  32. {
  33. FileName = "";
  34. AsciiTransfer = false;
  35. ResumeStatus = rsNotAvailable;
  36. Count = 0;
  37. FFilesFinished = 0;
  38. StartTime = Now();
  39. Suspended = false;
  40. FSuspendTime = 0;
  41. InProgress = false;
  42. FileInProgress = false;
  43. TotalTransfered = 0;
  44. TotalSkipped = 0;
  45. TotalSize = 0;
  46. SkippedSize = 0;
  47. TotalSizeSet = false;
  48. Operation = foNone;
  49. Temp = false;
  50. SkipToAll = false;
  51. BatchOverwrite = boNo;
  52. // to bypass check in ClearTransfer()
  53. TransferSize = 0;
  54. CPSLimit = 0;
  55. FTicks.clear();
  56. FTotalTransferredThen.clear();
  57. ClearTransfer();
  58. }
  59. //---------------------------------------------------------------------------
  60. void __fastcall TFileOperationProgressType::ClearTransfer()
  61. {
  62. if ((TransferSize > 0) && (TransferedSize < TransferSize))
  63. {
  64. __int64 RemainingSize = (TransferSize - TransferedSize);
  65. TotalSkipped += RemainingSize;
  66. }
  67. LocalSize = 0;
  68. TransferSize = 0;
  69. LocalyUsed = 0;
  70. SkippedSize = 0;
  71. TransferedSize = 0;
  72. TransferingFile = false;
  73. FLastSecond = 0;
  74. }
  75. //---------------------------------------------------------------------------
  76. void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
  77. TOperationSide ASide, int ACount)
  78. {
  79. Start(AOperation, ASide, ACount, false, "", 0);
  80. }
  81. //---------------------------------------------------------------------------
  82. void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
  83. TOperationSide ASide, int ACount, bool ATemp,
  84. const AnsiString ADirectory, unsigned long ACPSLimit)
  85. {
  86. Clear();
  87. Operation = AOperation;
  88. Side = ASide;
  89. Count = ACount;
  90. InProgress = true;
  91. Cancel = csContinue;
  92. Directory = ADirectory;
  93. Temp = ATemp;
  94. CPSLimit = ACPSLimit;
  95. DoProgress();
  96. }
  97. //---------------------------------------------------------------------------
  98. void __fastcall TFileOperationProgressType::Reset()
  99. {
  100. FReset = true;
  101. }
  102. //---------------------------------------------------------------------------
  103. void __fastcall TFileOperationProgressType::Stop()
  104. {
  105. // added to include remaining bytes to TotalSkipped, in case
  106. // the progress happes to update before closing
  107. ClearTransfer();
  108. InProgress = false;
  109. DoProgress();
  110. }
  111. //---------------------------------------------------------------------------
  112. void __fastcall TFileOperationProgressType::Suspend()
  113. {
  114. assert(!Suspended);
  115. Suspended = true;
  116. FSuspendTime = GetTickCount();
  117. DoProgress();
  118. }
  119. //---------------------------------------------------------------------------
  120. void __fastcall TFileOperationProgressType::Resume()
  121. {
  122. assert(Suspended);
  123. Suspended = false;
  124. // shift timestamps for CPS calculation in advance
  125. // by the time the progress was suspended
  126. unsigned long Stopped = (GetTickCount() - FSuspendTime);
  127. size_t i = 0;
  128. while (i < FTicks.size())
  129. {
  130. FTicks[i] += Stopped;
  131. ++i;
  132. }
  133. DoProgress();
  134. }
  135. //---------------------------------------------------------------------------
  136. int __fastcall TFileOperationProgressType::OperationProgress()
  137. {
  138. assert(Count);
  139. int Result = (FFilesFinished * 100)/Count;
  140. return Result;
  141. }
  142. //---------------------------------------------------------------------------
  143. int __fastcall TFileOperationProgressType::TransferProgress()
  144. {
  145. int Result;
  146. if (TransferSize) Result = (int)((TransferedSize * 100)/TransferSize);
  147. else Result = 0;
  148. return Result;
  149. }
  150. //---------------------------------------------------------------------------
  151. int __fastcall TFileOperationProgressType::TotalTransferProgress()
  152. {
  153. assert(TotalSizeSet);
  154. int Result = TotalSize > 0 ? (int)(((TotalTransfered + TotalSkipped) * 100)/TotalSize) : 0;
  155. return Result < 100 ? Result : 100;
  156. }
  157. //---------------------------------------------------------------------------
  158. int __fastcall TFileOperationProgressType::OverallProgress()
  159. {
  160. if (TotalSizeSet)
  161. {
  162. assert((Operation == foCopy) || (Operation == foMove));
  163. return TotalTransferProgress();
  164. }
  165. else
  166. {
  167. return OperationProgress();
  168. }
  169. }
  170. //---------------------------------------------------------------------------
  171. void __fastcall TFileOperationProgressType::DoProgress()
  172. {
  173. SetThreadExecutionState(ES_SYSTEM_REQUIRED);
  174. FOnProgress(*this, Cancel);
  175. }
  176. //---------------------------------------------------------------------------
  177. void __fastcall TFileOperationProgressType::Finish(AnsiString FileName,
  178. bool Success, TOnceDoneOperation & OnceDoneOperation)
  179. {
  180. assert(InProgress);
  181. FOnFinished(Operation, Side, Temp, FileName,
  182. /* TODO : There wasn't 'Success' condition, was it by mistake or by purpose? */
  183. Success && (Cancel == csContinue), OnceDoneOperation);
  184. FFilesFinished++;
  185. DoProgress();
  186. }
  187. //---------------------------------------------------------------------------
  188. void __fastcall TFileOperationProgressType::SetFile(AnsiString AFileName, bool AFileInProgress)
  189. {
  190. FileName = AFileName;
  191. FileInProgress = AFileInProgress;
  192. ClearTransfer();
  193. FFileStartTime = Now();
  194. DoProgress();
  195. }
  196. //---------------------------------------------------------------------------
  197. void __fastcall TFileOperationProgressType::SetFileInProgress()
  198. {
  199. assert(!FileInProgress);
  200. FileInProgress = true;
  201. DoProgress();
  202. }
  203. //---------------------------------------------------------------------------
  204. void __fastcall TFileOperationProgressType::SetLocalSize(__int64 ASize)
  205. {
  206. LocalSize = ASize;
  207. DoProgress();
  208. }
  209. //---------------------------------------------------------------------------
  210. void __fastcall TFileOperationProgressType::AddLocalyUsed(__int64 ASize)
  211. {
  212. LocalyUsed += ASize;
  213. if (LocalyUsed > LocalSize)
  214. {
  215. LocalSize = LocalyUsed;
  216. }
  217. DoProgress();
  218. }
  219. //---------------------------------------------------------------------------
  220. bool __fastcall TFileOperationProgressType::IsLocalyDone()
  221. {
  222. assert(LocalyUsed <= LocalSize);
  223. return (LocalyUsed == LocalSize);
  224. }
  225. //---------------------------------------------------------------------------
  226. unsigned long __fastcall TFileOperationProgressType::AdjustToCPSLimit(
  227. unsigned long Size)
  228. {
  229. if (CPSLimit > 0)
  230. {
  231. // we must not return 0, hence, if we reach zero,
  232. // we wait until the next second
  233. do
  234. {
  235. unsigned int Second = (GetTickCount() / 1000);
  236. if (Second != FLastSecond)
  237. {
  238. FRemainingCPS = CPSLimit;
  239. FLastSecond = Second;
  240. }
  241. if (FRemainingCPS == 0)
  242. {
  243. SleepEx(100, true);
  244. DoProgress();
  245. }
  246. }
  247. while ((CPSLimit > 0) && (FRemainingCPS == 0));
  248. // CPSLimit may have been dropped in DoProgress
  249. if (CPSLimit > 0)
  250. {
  251. if (FRemainingCPS < Size)
  252. {
  253. Size = FRemainingCPS;
  254. }
  255. FRemainingCPS -= Size;
  256. }
  257. }
  258. return Size;
  259. }
  260. //---------------------------------------------------------------------------
  261. unsigned long __fastcall TFileOperationProgressType::LocalBlockSize()
  262. {
  263. unsigned long Result = TRANSFER_BUF_SIZE;
  264. if (LocalyUsed + Result > LocalSize) Result = (unsigned long)(LocalSize - LocalyUsed);
  265. Result = AdjustToCPSLimit(Result);
  266. return Result;
  267. }
  268. //---------------------------------------------------------------------------
  269. void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize)
  270. {
  271. TotalSize = ASize;
  272. TotalSizeSet = true;
  273. DoProgress();
  274. }
  275. //---------------------------------------------------------------------------
  276. void __fastcall TFileOperationProgressType::SetTransferSize(__int64 ASize)
  277. {
  278. TransferSize = ASize;
  279. DoProgress();
  280. }
  281. //---------------------------------------------------------------------------
  282. void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize)
  283. {
  284. // reflect change on file size (due to text transfer mode conversion particulary)
  285. // on total transfer size
  286. if (TotalSizeSet)
  287. {
  288. TotalSize += (ASize - TransferSize);
  289. }
  290. TransferSize = ASize;
  291. DoProgress();
  292. }
  293. //---------------------------------------------------------------------------
  294. void __fastcall TFileOperationProgressType::RollbackTransfer()
  295. {
  296. TransferedSize -= SkippedSize;
  297. assert(TransferedSize <= TotalTransfered);
  298. TotalTransfered -= TransferedSize;
  299. assert(SkippedSize <= TotalSkipped);
  300. FTicks.clear();
  301. FTotalTransferredThen.clear();
  302. TotalSkipped -= SkippedSize;
  303. SkippedSize = 0;
  304. TransferedSize = 0;
  305. TransferSize = 0;
  306. LocalyUsed = 0;
  307. }
  308. //---------------------------------------------------------------------------
  309. void __fastcall TFileOperationProgressType::AddTransfered(__int64 ASize,
  310. bool AddToTotals)
  311. {
  312. TransferedSize += ASize;
  313. if (TransferedSize > TransferSize)
  314. {
  315. // this can happen with SFTP when downloading file that
  316. // grows while being downloaded
  317. if (TotalSizeSet)
  318. {
  319. TotalSize += (TransferedSize - TransferSize);
  320. }
  321. TransferSize = TransferedSize;
  322. }
  323. if (AddToTotals)
  324. {
  325. TotalTransfered += ASize;
  326. unsigned long Ticks = GetTickCount();
  327. if (FTicks.empty() ||
  328. (FTicks.back() > Ticks) || // ticks wrap after 49.7 days
  329. ((Ticks - FTicks.back()) >= 1000))
  330. {
  331. FTicks.push_back(Ticks);
  332. FTotalTransferredThen.push_back(TotalTransfered);
  333. }
  334. if (FTicks.size() > 10)
  335. {
  336. FTicks.erase(FTicks.begin());
  337. FTotalTransferredThen.erase(FTotalTransferredThen.begin());
  338. }
  339. }
  340. DoProgress();
  341. }
  342. //---------------------------------------------------------------------------
  343. void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize)
  344. {
  345. TotalSkipped += ASize;
  346. SkippedSize += ASize;
  347. AddTransfered(ASize, false);
  348. AddLocalyUsed(ASize);
  349. }
  350. //---------------------------------------------------------------------------
  351. unsigned long __fastcall TFileOperationProgressType::TransferBlockSize()
  352. {
  353. unsigned long Result = TRANSFER_BUF_SIZE;
  354. if (TransferedSize + Result > TransferSize) Result = (unsigned long)(TransferSize - TransferedSize);
  355. Result = AdjustToCPSLimit(Result);
  356. return Result;
  357. }
  358. //---------------------------------------------------------------------------
  359. unsigned long __fastcall TFileOperationProgressType::StaticBlockSize()
  360. {
  361. return TRANSFER_BUF_SIZE;
  362. }
  363. //---------------------------------------------------------------------------
  364. bool __fastcall TFileOperationProgressType::IsTransferDone()
  365. {
  366. assert(TransferedSize <= TransferSize);
  367. return (TransferedSize == TransferSize);
  368. }
  369. //---------------------------------------------------------------------------
  370. void __fastcall TFileOperationProgressType::SetAsciiTransfer(bool AAsciiTransfer)
  371. {
  372. AsciiTransfer = AAsciiTransfer;
  373. DoProgress();
  374. }
  375. //---------------------------------------------------------------------------
  376. void __fastcall TFileOperationProgressType::SetResumeStatus(TResumeStatus AResumeStatus)
  377. {
  378. ResumeStatus = AResumeStatus;
  379. DoProgress();
  380. }
  381. //---------------------------------------------------------------------------
  382. TDateTime __fastcall TFileOperationProgressType::TimeElapsed()
  383. {
  384. return Now() - StartTime;
  385. }
  386. //---------------------------------------------------------------------------
  387. unsigned int __fastcall TFileOperationProgressType::CPS()
  388. {
  389. unsigned int Result;
  390. if (FTicks.empty())
  391. {
  392. Result = 0;
  393. }
  394. else
  395. {
  396. unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount());
  397. unsigned long TimeSpan;
  398. if (Ticks < FTicks.front())
  399. {
  400. // clocks has wrapped, guess 10 seconds difference
  401. TimeSpan = 10000;
  402. }
  403. else
  404. {
  405. TimeSpan = (Ticks - FTicks.front());
  406. }
  407. if (TimeSpan == 0)
  408. {
  409. Result = 0;
  410. }
  411. else
  412. {
  413. __int64 Transferred = (TotalTransfered - FTotalTransferredThen.front());
  414. Result = (unsigned int)(Transferred * 1000 / TimeSpan);
  415. }
  416. }
  417. return Result;
  418. }
  419. //---------------------------------------------------------------------------
  420. TDateTime __fastcall TFileOperationProgressType::TimeExpected()
  421. {
  422. unsigned int CurCps = CPS();
  423. if (CurCps) return TDateTime((double)(((double)(TransferSize - TransferedSize)) / CurCps) / (24 * 60 * 60));
  424. else return 0;
  425. }
  426. //---------------------------------------------------------------------------
  427. TDateTime __fastcall TFileOperationProgressType::TotalTimeExpected()
  428. {
  429. assert(TotalSizeSet);
  430. unsigned int CurCps = CPS();
  431. // sanity check
  432. if ((CurCps > 0) && (TotalSize > TotalSkipped))
  433. {
  434. return TDateTime((double)((double)(TotalSize - TotalSkipped) / CurCps) /
  435. (24 * 60 * 60));
  436. }
  437. else
  438. {
  439. return 0;
  440. }
  441. }
  442. //---------------------------------------------------------------------------
  443. TDateTime __fastcall TFileOperationProgressType::TotalTimeLeft()
  444. {
  445. assert(TotalSizeSet);
  446. unsigned int CurCps = CPS();
  447. // sanity check
  448. if ((CurCps > 0) && (TotalSize > TotalSkipped + TotalTransfered))
  449. {
  450. return TDateTime((double)((double)(TotalSize - TotalSkipped - TotalTransfered) / CurCps) /
  451. (24 * 60 * 60));
  452. }
  453. else
  454. {
  455. return 0;
  456. }
  457. }