FileOperationProgress.cpp 14 KB

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