| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 | //---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop#include "Common.h"#include "FileOperationProgress.h"#include "CoreMain.h"//---------------------------------------------------------------------------#define TRANSFER_BUF_SIZE 32768//---------------------------------------------------------------------------__fastcall TFileOperationProgressType::TFileOperationProgressType(){  FOnProgress = NULL;  FOnFinished = NULL;  Clear();}//---------------------------------------------------------------------------__fastcall TFileOperationProgressType::TFileOperationProgressType(  TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished){  FOnProgress = AOnProgress;  FOnFinished = AOnFinished;  FReset = false;  Clear();}//---------------------------------------------------------------------------__fastcall TFileOperationProgressType::~TFileOperationProgressType(){  DebugAssert(!InProgress || FReset);  DebugAssert(!Suspended || FReset);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::AssignButKeepSuspendState(const TFileOperationProgressType & Other){  TValueRestorer<unsigned int> SuspendTimeRestorer(FSuspendTime);  TValueRestorer<bool> SuspendedRestorer(FSuspended);  *this = Other;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Clear(){  FFileName = L"";  FFullFileName = L"";  FDirectory = L"";  FAsciiTransfer = false;  FCount = -1;  FFilesFinished = 0;  FStartTime = Now();  FSuspended = false;  FSuspendTime = 0;  FInProgress = false;  FFileInProgress = false;  FTotalTransferred = 0;  FTotalSkipped = 0;  FTotalSize = 0;  FSkippedSize = 0;  FTotalSizeSet = false;  FOperation = foNone;  FTemp = false;  FSkipToAll = false;  FBatchOverwrite = boNo;  // to bypass check in ClearTransfer()  FTransferSize = 0;  FCPSLimit = 0;  FTicks.clear();  FTotalTransferredThen.clear();  FCounterSet = false;  ClearTransfer();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::ClearTransfer(){  if ((TransferSize > 0) && (TransferredSize < TransferSize))  {    __int64 RemainingSize = (TransferSize - TransferredSize);    FTotalSkipped += RemainingSize;  }  FLocalSize = 0;  FTransferSize = 0;  FLocallyUsed = 0;  FSkippedSize = 0;  FTransferredSize = 0;  FTransferringFile = false;  FLastSecond = 0;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,  TOperationSide ASide, int ACount){  Start(AOperation, ASide, ACount, false, L"", 0);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,  TOperationSide ASide, int ACount, bool ATemp,  const UnicodeString ADirectory, unsigned long ACPSLimit){  Clear();  FOperation = AOperation;  FSide = ASide;  FCount = ACount;  FInProgress = true;  FCancel = csContinue;  FDirectory = ADirectory;  FTemp = ATemp;  FCPSLimit = ACPSLimit;  try  {    DoProgress();  }  catch (...)  {    // connection can be lost during progress callbacks    ClearTransfer();    FInProgress = false;    throw;  }}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Reset(){  FReset = true;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Stop(){  // added to include remaining bytes to TotalSkipped, in case  // the progress happens to update before closing  ClearTransfer();  FInProgress = false;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Suspend(){  DebugAssert(!Suspended);  FSuspended = true;  FSuspendTime = GetTickCount();  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Resume(){  DebugAssert(Suspended);  FSuspended = false;  // shift timestamps for CPS calculation in advance  // by the time the progress was suspended  unsigned long Stopped = (GetTickCount() - FSuspendTime);  size_t i = 0;  while (i < FTicks.size())  {    FTicks[i] += Stopped;    ++i;  }  DoProgress();}//---------------------------------------------------------------------------int __fastcall TFileOperationProgressType::OperationProgress(){  DebugAssert(FCount > 0);  int Result = (FFilesFinished * 100)/FCount;  return Result;}//---------------------------------------------------------------------------int __fastcall TFileOperationProgressType::TransferProgress(){  int Result;  if (TransferSize)  {    Result = (int)((TransferredSize * 100)/TransferSize);  }  else  {    Result = 0;  }  return Result;}//---------------------------------------------------------------------------int __fastcall TFileOperationProgressType::TotalTransferProgress(){  DebugAssert(TotalSizeSet);  int Result = TotalSize > 0 ? (int)(((TotalTransferred + TotalSkipped) * 100)/TotalSize) : 0;  return Result < 100 ? Result : 100;}//---------------------------------------------------------------------------int __fastcall TFileOperationProgressType::OverallProgress(){  if (TotalSizeSet)  {    DebugAssert((Operation == foCopy) || (Operation == foMove));    return TotalTransferProgress();  }  else  {    return OperationProgress();  }}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Progress(){  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::DoProgress(){  SetThreadExecutionState(ES_SYSTEM_REQUIRED);  FOnProgress(*this);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::Finish(UnicodeString FileName,  bool Success, TOnceDoneOperation & OnceDoneOperation){  DebugAssert(InProgress);  FOnFinished(Operation, Side, Temp, FileName,    /* TODO : There wasn't 'Success' condition, was it by mistake or by purpose? */    Success && (Cancel == csContinue), OnceDoneOperation);  FFilesFinished++;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetFile(UnicodeString AFileName, bool AFileInProgress){  FFullFileName = AFileName;  if (Side == osRemote)  {    // historically set were passing filename-only for remote site operations,    // now we need to collect a full paths, so we pass in full path,    // but still want to have filename-only in FileName    AFileName = UnixExtractFileName(AFileName);  }  FFileName = AFileName;  FFileInProgress = AFileInProgress;  ClearTransfer();  FFileStartTime = Now();  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetFileInProgress(){  DebugAssert(!FileInProgress);  FFileInProgress = true;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetLocalSize(__int64 ASize){  FLocalSize = ASize;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::AddLocallyUsed(__int64 ASize){  FLocallyUsed += ASize;  if (LocallyUsed > LocalSize)  {    FLocalSize = LocallyUsed;  }  DoProgress();}//---------------------------------------------------------------------------bool __fastcall TFileOperationProgressType::IsLocallyDone(){  DebugAssert(LocallyUsed <= LocalSize);  return (LocallyUsed == LocalSize);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetSpeedCounters(){  if ((CPSLimit > 0) && !FCounterSet)  {    FCounterSet = true;    Configuration->Usage->Inc(L"SpeedLimitUses");  }}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::ThrottleToCPSLimit(  unsigned long Size){  unsigned long Remaining = Size;  while (Remaining > 0)  {    Remaining -= AdjustToCPSLimit(Remaining);  }}//---------------------------------------------------------------------------unsigned long __fastcall TFileOperationProgressType::AdjustToCPSLimit(  unsigned long Size){  SetSpeedCounters();  if (CPSLimit > 0)  {    // we must not return 0, hence, if we reach zero,    // we wait until the next second    do    {      unsigned int Second = (GetTickCount() / MSecsPerSec);      if (Second != FLastSecond)      {        FRemainingCPS = CPSLimit;        FLastSecond = Second;      }      if (FRemainingCPS == 0)      {        SleepEx(100, true);        DoProgress();      }    }    while ((CPSLimit > 0) && (FRemainingCPS == 0));    // CPSLimit may have been dropped in DoProgress    if (CPSLimit > 0)    {      if (FRemainingCPS < Size)      {        Size = FRemainingCPS;      }      FRemainingCPS -= Size;    }  }  return Size;}//---------------------------------------------------------------------------unsigned long __fastcall TFileOperationProgressType::LocalBlockSize(){  unsigned long Result = TRANSFER_BUF_SIZE;  if (LocallyUsed + Result > LocalSize)  {    Result = (unsigned long)(LocalSize - LocallyUsed);  }  Result = AdjustToCPSLimit(Result);  return Result;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize){  FTotalSize = ASize;  FTotalSizeSet = true;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetTransferSize(__int64 ASize){  FTransferSize = ASize;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetTransferringFile(bool ATransferringFile){  FTransferringFile = ATransferringFile;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetCancel(TCancelStatus ACancel){  FCancel = ACancel;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetCancelAtLeast(TCancelStatus ACancel){  if (FCancel < ACancel)  {    FCancel = ACancel;  }}//---------------------------------------------------------------------------bool __fastcall TFileOperationProgressType::ClearCancelFile(){  bool Result = (Cancel == csCancelFile);  if (Result)  {    SetCancel(csContinue);  }  return Result;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetCPSLimit(unsigned long ACPSLimit){  FCPSLimit = ACPSLimit;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetBatchOverwrite(TBatchOverwrite ABatchOverwrite){  FBatchOverwrite = ABatchOverwrite;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetSkipToAll(){  FSkipToAll = true;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize){  // reflect change on file size (due to text transfer mode conversion particulary)  // on total transfer size  if (TotalSizeSet)  {    FTotalSize += (ASize - TransferSize);  }  FTransferSize = ASize;  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::RollbackTransfer(){  FTransferredSize -= SkippedSize;  DebugAssert(TransferredSize <= TotalTransferred);  FTotalTransferred -= TransferredSize;  DebugAssert(SkippedSize <= TotalSkipped);  FTicks.clear();  FTotalTransferredThen.clear();  FTotalSkipped -= SkippedSize;  FSkippedSize = 0;  FTransferredSize = 0;  FTransferSize = 0;  FLocallyUsed = 0;}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::AddTransferred(__int64 ASize,  bool AddToTotals){  FTransferredSize += ASize;  if (TransferredSize > TransferSize)  {    // this can happen with SFTP when downloading file that    // grows while being downloaded    if (TotalSizeSet)    {      // we should probably guard this with AddToTotals      FTotalSize += (TransferredSize - TransferSize);    }    FTransferSize = TransferredSize;  }  if (AddToTotals)  {    FTotalTransferred += ASize;    unsigned long Ticks = GetTickCount();    if (FTicks.empty() ||        (FTicks.back() > Ticks) || // ticks wrap after 49.7 days        ((Ticks - FTicks.back()) >= MSecsPerSec))    {      FTicks.push_back(Ticks);      FTotalTransferredThen.push_back(TotalTransferred);    }    if (FTicks.size() > 10)    {      FTicks.erase(FTicks.begin());      FTotalTransferredThen.erase(FTotalTransferredThen.begin());    }  }  DoProgress();}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize){  FTotalSkipped += ASize;  FSkippedSize += ASize;  AddTransferred(ASize, false);  AddLocallyUsed(ASize);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::AddSkippedFileSize(__int64 ASize){  FTotalSkipped += ASize;  DoProgress();}//---------------------------------------------------------------------------unsigned long __fastcall TFileOperationProgressType::TransferBlockSize(){  unsigned long Result = TRANSFER_BUF_SIZE;  if (TransferredSize + Result > TransferSize)  {    Result = (unsigned long)(TransferSize - TransferredSize);  }  Result = AdjustToCPSLimit(Result);  return Result;}//---------------------------------------------------------------------------unsigned long __fastcall TFileOperationProgressType::StaticBlockSize(){  return TRANSFER_BUF_SIZE;}//---------------------------------------------------------------------------bool __fastcall TFileOperationProgressType::IsTransferDone(){  DebugAssert(TransferredSize <= TransferSize);  return (TransferredSize == TransferSize);}//---------------------------------------------------------------------------void __fastcall TFileOperationProgressType::SetAsciiTransfer(bool AAsciiTransfer){  FAsciiTransfer = AAsciiTransfer;  DoProgress();}//---------------------------------------------------------------------------TDateTime __fastcall TFileOperationProgressType::TimeElapsed(){  return Now() - StartTime;}//---------------------------------------------------------------------------unsigned int __fastcall TFileOperationProgressType::CPS(){  unsigned int Result;  if (FTicks.empty())  {    Result = 0;  }  else  {    unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount());    unsigned long TimeSpan;    if (Ticks < FTicks.front())    {      // clocks has wrapped, guess 10 seconds difference      TimeSpan = 10000;    }    else    {      TimeSpan = (Ticks - FTicks.front());    }    if (TimeSpan == 0)    {      Result = 0;    }    else    {      __int64 Transferred = (TotalTransferred - FTotalTransferredThen.front());      Result = (unsigned int)(Transferred * MSecsPerSec / TimeSpan);    }  }  return Result;}//---------------------------------------------------------------------------TDateTime __fastcall TFileOperationProgressType::TimeExpected(){  unsigned int CurCps = CPS();  if (CurCps)  {    return TDateTime((double)(((double)(TransferSize - TransferredSize)) / CurCps) / SecsPerDay);  }  else  {    return 0;  }}//---------------------------------------------------------------------------TDateTime __fastcall TFileOperationProgressType::TotalTimeLeft(){  DebugAssert(TotalSizeSet);  unsigned int CurCps = CPS();  // sanity check  if ((CurCps > 0) && (TotalSize > TotalSkipped + TotalTransferred))  {    return TDateTime((double)((double)(TotalSize - TotalSkipped - TotalTransferred) / CurCps) /      SecsPerDay);  }  else  {    return 0;  }}
 |