1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/core/FileOperationProgress.cpp
Martin Prikryl e5efed8955 Refactoring old-style casts
Source commit: 3c37b3a958525c595ad44b081b2e0f3b288b8eb0
2025-12-18 01:20:33 +01:00

1019 lines
30 KiB
C++

//---------------------------------------------------------------------------
#include <CorePCH.h>
#pragma hdrstop
#include "FileOperationProgress.h"
//---------------------------------------------------------------------------
#define TRANSFER_BUF_SIZE 32768
//---------------------------------------------------------------------------
TFileOperationStatistics::TFileOperationStatistics()
{
memset(this, 0, sizeof(*this));
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
TFileOperationProgressType::TPersistence::TPersistence()
{
FStatistics = NULL;
Clear(true, true);
}
//---------------------------------------------------------------------------
bool TFileOperationProgressType::IsIndeterminateOperation(TFileOperation Operation)
{
return (Operation == foCalculateSize);
}
//---------------------------------------------------------------------------
bool TFileOperationProgressType::IsTransferOperation(TFileOperation Operation)
{
return (Operation == foCopy) || (Operation == foMove);
}
//---------------------------------------------------------------------------
void TFileOperationProgressType::TPersistence::Clear(bool Batch, bool Speed)
{
if (Batch)
{
TotalTransferred = 0;
StartTime = Now();
SkipToAll = false;
BatchOverwrite = boNo;
CPSLimit = 0;
CounterSet = false;
}
if (Speed)
{
Ticks.clear();
TotalTransferredThen.clear();
}
}
//---------------------------------------------------------------------------
__fastcall TFileOperationProgressType::TFileOperationProgressType()
{
FOnProgress = NULL;
FOnFinished = NULL;
FParent = NULL;
Init();
Clear();
}
//---------------------------------------------------------------------------
__fastcall TFileOperationProgressType::TFileOperationProgressType(
TFileOperationProgressEvent AOnProgress, TFileOperationFinished AOnFinished,
TFileOperationProgressType * Parent)
{
FOnProgress = AOnProgress;
FOnFinished = AOnFinished;
FParent = Parent;
FReset = false;
Init();
Clear();
}
//---------------------------------------------------------------------------
__fastcall TFileOperationProgressType::~TFileOperationProgressType()
{
DebugAssert(!InProgress || FReset);
DebugAssert(!Suspended || FReset);
SAFE_DESTROY(FSection);
SAFE_DESTROY(FUserSelectionsSection);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Init()
{
FSection = new TCriticalSection();
FUserSelectionsSection = new TCriticalSection();
FRestored = false;
FPersistence.Side = osCurrent; // = undefined value
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Assign(const TFileOperationProgressType & Other)
{
TValueRestorer<TCriticalSection *> SectionRestorer(FSection);
TValueRestorer<TCriticalSection *> UserSelectionsSectionRestorer(FUserSelectionsSection);
TGuard Guard(FSection);
TGuard OtherGuard(Other.FSection);
*this = Other;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AssignButKeepSuspendState(const TFileOperationProgressType & Other)
{
TGuard Guard(FSection);
TValueRestorer<unsigned int> SuspendTimeRestorer(FSuspendTime);
TValueRestorer<bool> SuspendedRestorer(FSuspended);
Assign(Other);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::DoClear(bool Batch, bool Speed)
{
FFileName = L"";
FFullFileName = L"";
FDirectory = L"";
FAsciiTransfer = false;
FCount = -1;
FFilesFinished = 0;
FFilesFinishedSuccessfully = 0;
FSuspended = false;
FSuspendTime = 0;
FInProgress = false;
FDone = false;
FFileInProgress = false;
FTotalSkipped = 0;
FTotalSize = 0;
FSkippedSize = 0;
FTotalSizeSet = false;
FOperation = foNone;
FTemp = false;
FPersistence.Clear(Batch, Speed);
// to bypass check in ClearTransfer()
FTransferSize = 0;
ClearTransfer();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Clear()
{
DoClear(true, true);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::ClearTransfer()
{
if ((TransferSize > 0) && (TransferredSize < TransferSize))
{
TGuard Guard(FSection);
__int64 RemainingSize = (TransferSize - TransferredSize);
AddSkipped(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, odoIdle);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Start(TFileOperation AOperation,
TOperationSide ASide, int ACount, bool ATemp,
const UnicodeString ADirectory, unsigned long ACPSLimit, TOnceDoneOperation InitialOnceDoneOperation)
{
{
TGuard Guard(FSection); // not really needed, just for consistency
DoClear(!FRestored, (FPersistence.Side != osCurrent) && (FPersistence.Side != ASide));
FTotalTransferBase = FPersistence.TotalTransferred;
FOperation = AOperation;
FPersistence.Side = ASide;
FCount = ACount;
FInProgress = true;
FCancel = csContinue;
FDirectory = ADirectory;
FTemp = ATemp;
FInitialOnceDoneOperation = InitialOnceDoneOperation;
FPersistence.CPSLimit = 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::SetDone()
{
FDone = true;
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Suspend()
{
{
TGuard Guard(FSection);
DebugAssert(!Suspended);
FSuspended = true;
FSuspendTime = GetTickCount();
}
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Resume()
{
{
TGuard Guard(FSection);
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 < FPersistence.Ticks.size())
{
FPersistence.Ticks[i] += Stopped;
++i;
}
}
DoProgress();
}
//---------------------------------------------------------------------------
int __fastcall TFileOperationProgressType::OperationProgress() const
{
int Result;
if (FCount > 0)
{
Result = (FFilesFinished * 100)/FCount;
}
else
{
Result = 0;
}
return Result;
}
//---------------------------------------------------------------------------
int __fastcall TFileOperationProgressType::TransferProgress()
{
int Result;
if (TransferSize)
{
Result = static_cast<int>((TransferredSize * 100)/TransferSize);
}
else
{
Result = 0;
}
return Result;
}
//---------------------------------------------------------------------------
int __fastcall TFileOperationProgressType::TotalTransferProgress() const
{
TGuard Guard(FSection);
DebugAssert(TotalSizeSet);
int Result;
if (FTotalSize > 0)
{
Result = static_cast<int>(((FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped) * 100)/FTotalSize);
}
else
{
Result = 0;
}
return Result < 100 ? Result : 100;
}
//---------------------------------------------------------------------------
int __fastcall TFileOperationProgressType::OverallProgress() const
{
if (TotalSizeSet)
{
DebugAssert(IsTransfer());
return TotalTransferProgress();
}
else
{
return OperationProgress();
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Progress()
{
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::DoProgress()
{
SystemRequired();
FOnProgress(*this);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Finish(UnicodeString FileName,
bool Success, TOnceDoneOperation & OnceDoneOperation)
{
DebugAssert(InProgress);
// Cancel reader is guarded
bool NotCancelled = (Cancel == csContinue);
FOnFinished(Operation, Side, Temp, FileName, Success, NotCancelled, OnceDoneOperation);
FFilesFinished++;
if (Success)
{
FFilesFinishedSuccessfully++;
}
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Succeeded(int Count)
{
if (FPersistence.Statistics != NULL)
{
if (IsTransfer())
{
__int64 Transferred = FTransferredSize - FSkippedSize;
if (Side == osLocal)
{
FPersistence.Statistics->FilesUploaded += Count;
FPersistence.Statistics->TotalUploaded += Transferred;
}
else
{
FPersistence.Statistics->FilesDownloaded += Count;
FPersistence.Statistics->TotalDownloaded += Transferred;
}
}
else if (Operation == foDelete)
{
if (Side == osLocal)
{
FPersistence.Statistics->FilesDeletedLocal += Count;
}
else
{
FPersistence.Statistics->FilesDeletedRemote += Count;
}
}
}
}
//---------------------------------------------------------------------------
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) && !FPersistence.CounterSet)
{
FPersistence.CounterSet = true;
Configuration->Usage->Inc(L"SpeedLimitUses");
}
}
//---------------------------------------------------------------------------
// Used in WebDAV and S3 protocols
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();
// CPSLimit reader is guarded, we cannot block whole method as it can last long.
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;
}
//---------------------------------------------------------------------------
// Use in SCP protocol only
unsigned long __fastcall TFileOperationProgressType::LocalBlockSize()
{
unsigned long Result = TRANSFER_BUF_SIZE;
if (LocallyUsed + Result > LocalSize)
{
Result = static_cast<unsigned long>(LocalSize - LocallyUsed);
}
Result = AdjustToCPSLimit(Result);
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetTotalSize(__int64 ASize)
{
TGuard Guard(FSection); // not really needed, just for consistency
FTotalSize = ASize;
FTotalSizeSet = true;
// parent has its own totals
if (FParent != NULL)
{
DebugAssert(FParent->TotalSizeSet);
}
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetTransferSize(__int64 ASize)
{
FTransferSize = ASize;
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetTransferringFile(bool ATransferringFile)
{
FTransferringFile = ATransferringFile;
}
//---------------------------------------------------------------------------
bool __fastcall TFileOperationProgressType::PassCancelToParent(TCancelStatus ACancel)
{
bool Result;
if (ACancel < csCancel)
{
// do not propagate csCancelFile,
// though it's not supported for queue atm, so we do not expect it here
DebugFail();
Result = false;
}
else if (ACancel == csCancel)
{
Result = true;
}
else
{
// csCancelTransfer and csRemoteAbort are used with SCP only, which does not use parallel transfers
DebugFail();
Result = false;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetCancel(TCancelStatus ACancel)
{
TGuard Guard(FSection);
FCancel = ACancel;
if ((FParent != NULL) && PassCancelToParent(ACancel))
{
FParent->SetCancel(ACancel);
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetCancelAtLeast(TCancelStatus ACancel)
{
TGuard Guard(FSection);
if (FCancel < ACancel)
{
FCancel = ACancel;
}
if ((FParent != NULL) && PassCancelToParent(ACancel))
{
FParent->SetCancelAtLeast(ACancel);
}
}
//---------------------------------------------------------------------------
TCancelStatus __fastcall TFileOperationProgressType::GetCancel()
{
TCancelStatus Result = FCancel;
if (FParent != NULL)
{
TGuard Guard(FSection);
TCancelStatus ParentCancel = FParent->Cancel;
if (ParentCancel > Result)
{
Result = ParentCancel;
}
}
return Result;
}
//---------------------------------------------------------------------------
bool __fastcall TFileOperationProgressType::ClearCancelFile()
{
TGuard Guard(FSection);
// Not propagated to parent, as this is local flag, see also PassCancelToParent
bool Result = (Cancel == csCancelFile);
if (Result)
{
FCancel = csContinue;
}
return Result;
}
//---------------------------------------------------------------------------
unsigned long __fastcall TFileOperationProgressType::GetCPSLimit()
{
unsigned int Result;
if (FParent != NULL)
{
Result = FParent->CPSLimit;
}
else
{
TGuard Guard(FSection);
Result = FPersistence.CPSLimit;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetCPSLimit(unsigned long ACPSLimit)
{
if (FParent != NULL)
{
FParent->SetCPSLimit(ACPSLimit);
}
else
{
TGuard Guard(FSection);
FPersistence.CPSLimit = ACPSLimit;
}
}
//---------------------------------------------------------------------------
TBatchOverwrite __fastcall TFileOperationProgressType::GetBatchOverwrite()
{
TBatchOverwrite Result;
if (FParent != NULL)
{
Result = FParent->BatchOverwrite;
}
else
{
TGuard Guard(FSection); // not really needed
Result = FPersistence.BatchOverwrite;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetBatchOverwrite(TBatchOverwrite ABatchOverwrite)
{
if (FParent != NULL)
{
FParent->SetBatchOverwrite(ABatchOverwrite);
}
else
{
TGuard Guard(FSection); // not really needed
FPersistence.BatchOverwrite = ABatchOverwrite;;
}
}
//---------------------------------------------------------------------------
bool __fastcall TFileOperationProgressType::GetSkipToAll()
{
bool Result;
if (FParent != NULL)
{
Result = FParent->SkipToAll;
}
else
{
TGuard Guard(FSection); // not really needed
Result = FPersistence.SkipToAll;
}
return Result;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetSkipToAll()
{
if (FParent != NULL)
{
FParent->SetSkipToAll();
}
else
{
TGuard Guard(FSection); // not really needed
FPersistence.SkipToAll = true;
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::ChangeTransferSize(__int64 ASize)
{
// reflect change on file size (due to text transfer mode conversion particularly)
// on total transfer size
if (TotalSizeSet)
{
AddTotalSize(ASize - TransferSize);
}
FTransferSize = ASize;
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::RollbackTransferFromTotals(__int64 ATransferredSize, __int64 ASkippedSize)
{
TGuard Guard(FSection);
DebugAssert(ATransferredSize <= FPersistence.TotalTransferred - FTotalTransferBase);
DebugAssert(ASkippedSize <= FTotalSkipped);
FPersistence.TotalTransferred -= ATransferredSize;
FPersistence.Ticks.clear();
FPersistence.TotalTransferredThen.clear();
FTotalSkipped -= ASkippedSize;
if (FParent != NULL)
{
FParent->RollbackTransferFromTotals(ATransferredSize, ASkippedSize);
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::RollbackTransfer()
{
FTransferredSize -= FSkippedSize;
RollbackTransferFromTotals(FTransferredSize, FSkippedSize);
FSkippedSize = 0;
FTransferredSize = 0;
FTransferSize = 0;
FLocallyUsed = 0;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AddTransferredToTotals(__int64 ASize)
{
TGuard Guard(FSection);
FPersistence.TotalTransferred += ASize;
if (ASize >= 0)
{
unsigned long Ticks = GetTickCount();
if (FPersistence.Ticks.empty() ||
(FPersistence.Ticks.back() > Ticks) || // ticks wrap after 49.7 days
((Ticks - FPersistence.Ticks.back()) >= MSecsPerSec))
{
FPersistence.Ticks.push_back(Ticks);
FPersistence.TotalTransferredThen.push_back(FPersistence.TotalTransferred);
}
if (FPersistence.Ticks.size() > 10)
{
FPersistence.Ticks.erase(FPersistence.Ticks.begin());
FPersistence.TotalTransferredThen.erase(FPersistence.TotalTransferredThen.begin());
}
}
else
{
FPersistence.Ticks.clear();
}
if (FParent != NULL)
{
FParent->AddTransferredToTotals(ASize);
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AddTotalSize(__int64 ASize)
{
if (ASize != 0)
{
TGuard Guard(FSection);
FTotalSize += ASize;
if (FParent != NULL)
{
FParent->AddTotalSize(ASize);
}
}
}
//---------------------------------------------------------------------------
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
AddTotalSize(TransferredSize - TransferSize);
}
FTransferSize = TransferredSize;
}
if (AddToTotals)
{
AddTransferredToTotals(ASize);
}
DoProgress();
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AddSkipped(__int64 ASize)
{
TGuard Guard(FSection);
FTotalSkipped += ASize;
if (FParent != NULL)
{
FParent->AddSkipped(ASize);
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AddResumed(__int64 ASize)
{
AddSkipped(ASize);
FSkippedSize += ASize;
AddTransferred(ASize, false);
AddLocallyUsed(ASize);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::AddSkippedFileSize(__int64 ASize)
{
AddSkipped(ASize);
DoProgress();
}
//---------------------------------------------------------------------------
// Use in SCP protocol only
unsigned long __fastcall TFileOperationProgressType::TransferBlockSize()
{
unsigned long Result = TRANSFER_BUF_SIZE;
if (TransferredSize + Result > TransferSize)
{
Result = static_cast<unsigned long>(TransferSize - TransferredSize);
}
Result = AdjustToCPSLimit(Result);
return Result;
}
//---------------------------------------------------------------------------
unsigned long __fastcall TFileOperationProgressType::StaticBlockSize()
{
return TRANSFER_BUF_SIZE;
}
//---------------------------------------------------------------------------
bool TFileOperationProgressType::IsTransferDoneChecked()
{
DebugAssert(TransferredSize <= TransferSize);
return IsTransferDone();
}
//---------------------------------------------------------------------------
// Note that this does not work correctly, if the file is larger than expected (at least with the FTP protocol)
bool TFileOperationProgressType::IsTransferDone()
{
return (TransferredSize == TransferSize);
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::SetAsciiTransfer(bool AAsciiTransfer)
{
FAsciiTransfer = AAsciiTransfer;
DoProgress();
}
//---------------------------------------------------------------------------
TDateTime __fastcall TFileOperationProgressType::TimeElapsed()
{
return Now() - StartTime;
}
//---------------------------------------------------------------------------
unsigned int __fastcall TFileOperationProgressType::CPS()
{
TGuard Guard(FSection);
return GetCPS();
}
//---------------------------------------------------------------------------
inline static unsigned int CalculateCPS(__int64 Transferred, unsigned int MSecElapsed)
{
unsigned int Result;
if (MSecElapsed == 0)
{
Result = 0;
}
else
{
Result = static_cast<unsigned int>(Transferred * MSecsPerSec / MSecElapsed);
}
return Result;
}
//---------------------------------------------------------------------------
// Has to be called from a guarded method
unsigned int __fastcall TFileOperationProgressType::GetCPS()
{
unsigned int Result;
if (FPersistence.Ticks.empty())
{
Result = 0;
}
else
{
unsigned long Ticks = (Suspended ? FSuspendTime : GetTickCount());
unsigned long TimeSpan;
if (Ticks < FPersistence.Ticks.front())
{
// clocks has wrapped, guess 10 seconds difference
TimeSpan = 10000;
}
else
{
TimeSpan = (Ticks - FPersistence.Ticks.front());
}
__int64 Transferred = (FPersistence.TotalTransferred - FPersistence.TotalTransferredThen.front());
Result = CalculateCPS(Transferred, TimeSpan);
}
return Result;
}
//---------------------------------------------------------------------------
TDateTime __fastcall TFileOperationProgressType::TimeExpected()
{
unsigned int CurCps = CPS();
if (CurCps)
{
return TDateTime(static_cast<double>(static_cast<double>(TransferSize - TransferredSize) / CurCps) / SecsPerDay);
}
else
{
return 0;
}
}
//---------------------------------------------------------------------------
TDateTime __fastcall TFileOperationProgressType::TotalTimeLeft()
{
TGuard Guard(FSection);
DebugAssert(FTotalSizeSet);
unsigned int CurCps = GetCPS();
// sanity check
__int64 Processed = FTotalSkipped + FPersistence.TotalTransferred - FTotalTransferBase;
if ((CurCps > 0) && (FTotalSize > Processed))
{
return TDateTime(static_cast<double>(static_cast<double>(FTotalSize - Processed) / CurCps) / SecsPerDay);
}
else
{
return 0;
}
}
//---------------------------------------------------------------------------
__int64 __fastcall TFileOperationProgressType::GetTotalTransferred()
{
TGuard Guard(FSection);
return FPersistence.TotalTransferred;
}
//---------------------------------------------------------------------------
__int64 __fastcall TFileOperationProgressType::GetOperationTransferred() const
{
TGuard Guard(FSection);
return FPersistence.TotalTransferred - FTotalTransferBase + FTotalSkipped;
}
//---------------------------------------------------------------------------
__int64 __fastcall TFileOperationProgressType::GetTotalSize()
{
TGuard Guard(FSection);
return FTotalSize;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::LockUserSelections()
{
if (FParent != NULL)
{
FParent->LockUserSelections();
}
else
{
FUserSelectionsSection->Enter();
}
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::UnlockUserSelections()
{
if (FParent != NULL)
{
FParent->UnlockUserSelections();
}
else
{
FUserSelectionsSection->Leave();
}
}
//---------------------------------------------------------------------------
UnicodeString __fastcall TFileOperationProgressType::GetLogStr(bool Done)
{
UnicodeString Transferred = FormatSize(TotalTransferred);
TDateTime Time;
UnicodeString TimeLabel;
if (!Done && TotalSizeSet)
{
Time = TotalTimeLeft();
TimeLabel = L"Left";
}
else
{
Time = TimeElapsed();
TimeLabel = L"Elapsed";
}
UnicodeString TimeStr = FormatDateTimeSpan(Time);
unsigned int ACPS;
if (!Done)
{
ACPS = CPS();
}
else
{
unsigned int Elapsed = TimeToMSec(TimeElapsed());
ACPS = CalculateCPS(TotalTransferred, Elapsed);
}
UnicodeString CPSStr = FormatSize(ACPS);
return FORMAT(L"Transferred: %s, %s: %s, CPS: %s/s", (Transferred, TimeLabel, TimeStr, CPSStr));
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Store(TPersistence & Persistence)
{
// in this current use, we do not need this to be guarded actually, as it's used only for a single-threaded synchronization
TGuard Guard(FSection);
Persistence = FPersistence;
}
//---------------------------------------------------------------------------
void __fastcall TFileOperationProgressType::Restore(TPersistence & Persistence)
{
TGuard Guard(FSection);
FPersistence = Persistence;
FRestored = true;
}
//---------------------------------------------------------------------------
bool TFileOperationProgressType::IsIndeterminate() const
{
return
IsIndeterminateOperation(FOperation) ||
(!TotalSizeSet && (FCount == 1));
}
//---------------------------------------------------------------------------
bool TFileOperationProgressType::IsTransfer() const
{
return IsTransferOperation(Operation);
}