Pārlūkot izejas kodu

Calculating sizes of all synchronization transfers at the very beginning and showing the sizes on checklist + Not calculating size of transfers again, if they were calculated already on the checklist

Source commit: 08ed8201139d023e0a1e0794a7c4a426d9d4ad6c
Martin Prikryl 7 gadi atpakaļ
vecāks
revīzija
19f9225b37

+ 5 - 0
source/core/CopyParam.cpp

@@ -57,6 +57,7 @@ void __fastcall TCopyParamType::Default()
   EncryptNewFiles = true;
   ExcludeHiddenFiles = false;
   ExcludeEmptyDirectories = false;
+  Size = -1;
 }
 //---------------------------------------------------------------------------
 UnicodeString __fastcall TCopyParamType::GetInfoStr(
@@ -557,6 +558,7 @@ void __fastcall TCopyParamType::Assign(const TCopyParamType * Source)
   COPY(EncryptNewFiles);
   COPY(ExcludeHiddenFiles);
   COPY(ExcludeEmptyDirectories);
+  COPY(Size);
   #undef COPY
 }
 //---------------------------------------------------------------------------
@@ -880,6 +882,7 @@ void __fastcall TCopyParamType::Load(THierarchicalStorage * Storage)
   EncryptNewFiles = Storage->ReadBool(L"EncryptNewFiles", EncryptNewFiles);
   ExcludeHiddenFiles = Storage->ReadBool(L"ExcludeHiddenFiles", ExcludeHiddenFiles);
   ExcludeEmptyDirectories = Storage->ReadBool(L"ExcludeEmptyDirectories", ExcludeEmptyDirectories);
+  Size = -1;
 }
 //---------------------------------------------------------------------------
 void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage, const TCopyParamType * Defaults) const
@@ -926,6 +929,7 @@ void __fastcall TCopyParamType::Save(THierarchicalStorage * Storage, const TCopy
   WRITE_DATA(Bool, EncryptNewFiles);
   WRITE_DATA(Bool, ExcludeHiddenFiles);
   WRITE_DATA(Bool, ExcludeEmptyDirectories);
+  DebugAssert(Size < 0);
 }
 //---------------------------------------------------------------------------
 #define C(Property) (Property == rhp.Property)
@@ -960,6 +964,7 @@ bool __fastcall TCopyParamType::operator==(const TCopyParamType & rhp) const
     C(EncryptNewFiles) &&
     C(ExcludeHiddenFiles) &&
     C(ExcludeEmptyDirectories) &&
+    C(Size) &&
     true;
 }
 #undef C

+ 2 - 0
source/core/CopyParam.h

@@ -66,6 +66,7 @@ private:
   bool FEncryptNewFiles;
   bool FExcludeHiddenFiles;
   bool FExcludeEmptyDirectories;
+  __int64 FSize;
   static const wchar_t TokenPrefix = L'%';
   static const wchar_t NoReplacement = wchar_t(false);
   static const wchar_t TokenReplacement = wchar_t(true);
@@ -142,6 +143,7 @@ public:
   __property bool EncryptNewFiles = { read = FEncryptNewFiles, write = FEncryptNewFiles };
   __property bool ExcludeHiddenFiles = { read = FExcludeHiddenFiles, write = FExcludeHiddenFiles };
   __property bool ExcludeEmptyDirectories = { read = FExcludeEmptyDirectories, write = FExcludeEmptyDirectories };
+  __property __int64 Size = { read = FSize, write = FSize };
 };
 //---------------------------------------------------------------------------
 unsigned long __fastcall GetSpeedLimit(const UnicodeString & Text);

+ 44 - 0
source/core/RemoteFiles.cpp

@@ -2720,6 +2720,36 @@ const UnicodeString& TSynchronizeChecklist::TItem::GetFileName() const
   }
 }
 //---------------------------------------------------------------------------
+__int64 __fastcall TSynchronizeChecklist::TItem::GetSize() const
+{
+  return GetSize(Action);
+}
+//---------------------------------------------------------------------------
+__int64 __fastcall TSynchronizeChecklist::TItem::GetSize(TAction AAction) const
+{
+  if (IsItemSizeIrrelevant(AAction))
+  {
+    return 0;
+  }
+  else
+  {
+    switch (AAction)
+    {
+      case saUploadNew:
+      case saUploadUpdate:
+        return Local.Size;
+
+      case saDownloadNew:
+      case saDownloadUpdate:
+        return Remote.Size;
+
+      default:
+        DebugFail();
+        return 0;
+    }
+  }
+}
+//---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 TSynchronizeChecklist::TSynchronizeChecklist() :
   FList(new TList())
@@ -2842,3 +2872,17 @@ TSynchronizeChecklist::TAction __fastcall TSynchronizeChecklist::Reverse(TSynchr
       return saNone;
   }
 }
+//---------------------------------------------------------------------------
+bool __fastcall TSynchronizeChecklist::IsItemSizeIrrelevant(TAction Action)
+{
+  switch (Action)
+  {
+    case saNone:
+    case saDeleteRemote:
+    case saDeleteLocal:
+      return true;
+
+    default:
+      return false;
+  }
+}

+ 5 - 0
source/core/RemoteFiles.h

@@ -475,6 +475,8 @@ public:
     bool IsRemoteOnly() const { return (Action == saDownloadNew) || (Action == saDeleteRemote); }
     bool IsLocalOnly() const { return (Action == saUploadNew) || (Action == saDeleteLocal); }
     bool HasSize() const { return !IsDirectory || FDirectoryHasSize; }
+    __int64 __fastcall GetSize() const;
+    __int64 __fastcall GetSize(TAction AAction) const;
 
     ~TItem();
 
@@ -485,12 +487,15 @@ public:
     TItem();
   };
 
+  typedef std::vector<const TSynchronizeChecklist::TItem *> TItemList;
+
   ~TSynchronizeChecklist();
 
   void __fastcall Update(const TItem * Item, bool Check, TAction Action);
   void __fastcall UpdateDirectorySize(const TItem * Item, __int64 Size);
 
   static TAction __fastcall Reverse(TAction Action);
+  static bool __fastcall IsItemSizeIrrelevant(TAction Action);
 
   __property int Count = { read = GetCount };
   __property const TItem * Item[int Index] = { read = GetItem };

+ 2 - 2
source/core/Script.cpp

@@ -1973,7 +1973,7 @@ void __fastcall TScript::SynchronizeProc(TScriptProcParams * Parameters)
         else
         {
           PrintLine(LoadStr(SCRIPT_SYNCHRONIZE_SYNCHRONIZING));
-          FTerminal->SynchronizeApply(Checklist, &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory, NULL);
+          FTerminal->SynchronizeApply(Checklist, &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory, NULL, NULL);
         }
       }
       else
@@ -2007,7 +2007,7 @@ void __fastcall TScript::Synchronize(const UnicodeString LocalDirectory,
     {
       if (AChecklist->Count > 0)
       {
-        FTerminal->SynchronizeApply(AChecklist, &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory, NULL);
+        FTerminal->SynchronizeApply(AChecklist, &CopyParam, SynchronizeParams, OnTerminalSynchronizeDirectory, NULL, NULL);
       }
     }
     __finally

+ 181 - 19
source/core/Terminal.cpp

@@ -5878,7 +5878,8 @@ void __fastcall TTerminal::DoSynchronizeCollectFile(const UnicodeString FileName
 void __fastcall TTerminal::SynchronizeApply(
   TSynchronizeChecklist * Checklist,
   const TCopyParamType * CopyParam, int Params,
-  TSynchronizeDirectory OnSynchronizeDirectory, TProcessedItem OnProcessedItem)
+  TSynchronizeDirectory OnSynchronizeDirectory, TProcessedItem OnProcessedItem,
+  TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems)
 {
   TSynchronizeData Data;
 
@@ -5895,6 +5896,31 @@ void __fastcall TTerminal::SynchronizeApply(
     SyncCopyParam.PreserveTime = true;
   }
 
+  if (SyncCopyParam.CalculateSize)
+  {
+    // If we fail to collect the sizes, do not try again during an actual transfer
+    SyncCopyParam.CalculateSize = false;
+
+    TSynchronizeChecklist::TItemList Items;
+    for (int Index = 0; Index < Checklist->Count; Index++)
+    {
+      const TSynchronizeChecklist::TItem * ChecklistItem = Checklist->Item[Index];
+      // TSynchronizeChecklistDialog relies on us not to update a size of an item that had size already
+      // See TSynchronizeChecklistDialog::UpdatedSynchronizationChecklistItems
+      if (ChecklistItem->Checked && !TSynchronizeChecklist::IsItemSizeIrrelevant(ChecklistItem->Action) &&
+          !ChecklistItem->HasSize() && DebugAlwaysTrue(ChecklistItem->IsDirectory))
+      {
+        Items.push_back(ChecklistItem);
+      }
+    }
+
+    SynchronizeChecklistCalculateSize(Checklist, Items, &SyncCopyParam);
+    if (OnUpdatedSynchronizationChecklistItems != NULL)
+    {
+      OnUpdatedSynchronizationChecklistItems(Items);
+    }
+  }
+
   DebugAssert(FOnProcessedItem == NULL);
   FOnProcessedItem = OnProcessedItem;
 
@@ -5911,6 +5937,8 @@ void __fastcall TTerminal::SynchronizeApply(
       std::unique_ptr<TStringList> DeleteRemoteList(new TStringList());
       std::unique_ptr<TStringList> UploadList(new TStringList());
       std::unique_ptr<TStringList> DeleteLocalList(new TStringList());
+      __int64 DownloadSize = 0;
+      __int64 UploadSize = 0;
 
       ChecklistItem = Checklist->Item[IIndex];
 
@@ -5963,6 +5991,14 @@ void __fastcall TTerminal::SynchronizeApply(
                 DownloadList->AddObject(
                   UnixIncludeTrailingBackslash(ChecklistItem->Remote.Directory) + ChecklistItem->Remote.FileName,
                   ChecklistItem->RemoteFile);
+                if ((DownloadSize >= 0) && ChecklistItem->HasSize())
+                {
+                  DownloadSize += ChecklistItem->GetSize();
+                }
+                else
+                {
+                  DownloadSize = -1;
+                }
                 break;
 
               case TSynchronizeChecklist::saDeleteRemote:
@@ -5976,6 +6012,14 @@ void __fastcall TTerminal::SynchronizeApply(
                 UploadList->AddObject(
                   IncludeTrailingBackslash(ChecklistItem->Local.Directory) + ChecklistItem->Local.FileName,
                   ChecklistItemToken);
+                if ((UploadSize >= 0) && ChecklistItem->HasSize())
+                {
+                  UploadSize += ChecklistItem->GetSize();
+                }
+                else
+                {
+                  UploadSize = -1;
+                }
                 break;
 
               case TSynchronizeChecklist::saDeleteLocal:
@@ -6014,10 +6058,14 @@ void __fastcall TTerminal::SynchronizeApply(
         }
         else
         {
-          if ((DownloadList->Count > 0) &&
-              !CopyToLocal(DownloadList.get(), Data.LocalDirectory, &SyncCopyParam, CopyParams, NULL))
+          if (DownloadList->Count > 0)
           {
-            Abort();
+            TCopyParamType DownloadCopyParam = SyncCopyParam;
+            DownloadCopyParam.Size = DownloadSize;
+            if (!CopyToLocal(DownloadList.get(), Data.LocalDirectory, &DownloadCopyParam, CopyParams, NULL))
+            {
+              Abort();
+            }
           }
 
           if ((DeleteRemoteList->Count > 0) &&
@@ -6026,10 +6074,14 @@ void __fastcall TTerminal::SynchronizeApply(
             Abort();
           }
 
-          if ((UploadList->Count > 0) &&
-              !CopyToRemote(UploadList.get(), Data.RemoteDirectory, &SyncCopyParam, CopyParams, NULL))
+          if (UploadList->Count > 0)
           {
-            Abort();
+            TCopyParamType UploadCopyParam = SyncCopyParam;
+            UploadCopyParam.Size = UploadSize;
+            if (!CopyToRemote(UploadList.get(), Data.RemoteDirectory, &UploadCopyParam, CopyParams, NULL))
+            {
+              Abort();
+            }
           }
 
           if ((DeleteLocalList->Count > 0) &&
@@ -6049,6 +6101,98 @@ void __fastcall TTerminal::SynchronizeApply(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TTerminal::SynchronizeChecklistCalculateSize(
+  TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items,
+  const TCopyParamType * CopyParam)
+{
+  std::unique_ptr<TStrings> RemoteFileList(new TStringList());
+  std::unique_ptr<TStrings> LocalFileList(new TStringList());
+
+  for (size_t Index = 0; Index < Items.size(); Index++)
+  {
+    const TSynchronizeChecklist::TItem * ChecklistItem = Items[Index];
+    if (ChecklistItem->IsDirectory)
+    {
+      if (ChecklistItem->IsRemoteOnly())
+      {
+        RemoteFileList->AddObject(ChecklistItem->RemoteFile->FullFileName, ChecklistItem->RemoteFile);
+      }
+      else if (ChecklistItem->IsLocalOnly())
+      {
+        LocalFileList->Add(IncludeTrailingBackslash(ChecklistItem->Local.Directory) + ChecklistItem->Local.FileName);
+      }
+      else
+      {
+        // "update" actions are not relevant for directories
+        DebugFail();
+      }
+    }
+  }
+
+  TCalculatedSizes RemoteCalculatedSizes;
+  TCalculatedSizes LocalCalculatedSizes;
+
+  try
+  {
+    bool Result = true;
+    if (LocalFileList->Count > 0)
+    {
+      __int64 LocalSize = 0;
+      Result = CalculateLocalFilesSize(LocalFileList.get(), LocalSize, CopyParam, true, NULL, &LocalCalculatedSizes);
+    }
+    if (Result && (RemoteFileList->Count > 0))
+    {
+      __int64 RemoteSize = 0;
+      TCalculateSizeStats RemoteStats;
+      RemoteStats.CalculatedSizes = &RemoteCalculatedSizes;
+      CalculateFilesSize(RemoteFileList.get(), RemoteSize, 0, CopyParam, true, RemoteStats);
+    }
+  }
+  __finally
+  {
+    size_t LocalIndex = 0;
+    size_t RemoteIndex = 0;
+
+    for (size_t Index = 0; Index < Items.size(); Index++)
+    {
+      const TSynchronizeChecklist::TItem * ChecklistItem = Items[Index];
+      if (ChecklistItem->IsDirectory)
+      {
+        __int64 Size = -1;
+        if (ChecklistItem->IsRemoteOnly())
+        {
+          if (RemoteIndex < RemoteCalculatedSizes.size())
+          {
+            Size = RemoteCalculatedSizes[RemoteIndex];
+          }
+          RemoteIndex++;
+        }
+        else if (ChecklistItem->IsLocalOnly())
+        {
+          if (LocalIndex < LocalCalculatedSizes.size())
+          {
+            Size = LocalCalculatedSizes[LocalIndex];
+          }
+          LocalIndex++;
+        }
+        else
+        {
+          // "update" actions are not relevant for directories
+          DebugFail();
+        }
+
+        if (Size >= 0)
+        {
+          Checklist->UpdateDirectorySize(ChecklistItem, Size);
+        }
+      }
+    }
+
+    DebugAssert(RemoteIndex >= RemoteCalculatedSizes.size());
+    DebugAssert(LocalIndex >= LocalCalculatedSizes.size());
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TTerminal::DoSynchronizeProgress(const TSynchronizeData & Data,
   bool Collect)
 {
@@ -6523,8 +6667,17 @@ bool __fastcall TTerminal::CopyToRemote(
       Files.reset(new TStringList());
       Files->OwnsObjects = true;
     }
-    bool CalculatedSize =
-      CalculateLocalFilesSize(FilesToCopy, Size, CopyParam, CopyParam->CalculateSize, Files.get(), NULL);
+    bool CalculatedSize;
+    if ((CopyParam->Size >= 0) &&
+        DebugAlwaysTrue(Files.get() == NULL)) // Size is set for sync only and we never use parallel transfer for sync
+    {
+      Size = CopyParam->Size;
+      CalculatedSize = true;
+    }
+    else
+    {
+      CalculatedSize = CalculateLocalFilesSize(FilesToCopy, Size, CopyParam, CopyParam->CalculateSize, Files.get(), NULL);
+    }
 
     FLastProgressLogged = GetTickCount();
     TFileOperationProgressType OperationProgress(&DoProgress, &DoFinished);
@@ -6955,19 +7108,28 @@ bool __fastcall TTerminal::CopyToLocal(
       Files->OwnsObjects = true;
     }
 
-    ExceptionOnFail = true;
-    try
+    if ((CopyParam->Size >= 0) &&
+        DebugAlwaysTrue(Files.get() == NULL)) // Size is set for sync only and we never use parallel transfer for sync
     {
-      TCalculateSizeStats Stats;
-      Stats.FoundFiles = Files.get();
-      if (CalculateFilesSize(FilesToCopy, TotalSize, csIgnoreErrors, CopyParam, CopyParam->CalculateSize, Stats))
-      {
-        TotalSizeKnown = true;
-      }
+      TotalSize = CopyParam->Size;
+      TotalSizeKnown = true;
     }
-    __finally
+    else
     {
-      ExceptionOnFail = false;
+      ExceptionOnFail = true;
+      try
+      {
+        TCalculateSizeStats Stats;
+        Stats.FoundFiles = Files.get();
+        if (CalculateFilesSize(FilesToCopy, TotalSize, csIgnoreErrors, CopyParam, CopyParam->CalculateSize, Stats))
+        {
+          TotalSizeKnown = true;
+        }
+      }
+      __finally
+      {
+        ExceptionOnFail = false;
+      }
     }
 
     OperationProgress.Start((Params & cpDelete ? foMove : foCopy), osRemote,

+ 8 - 3
source/core/Terminal.h

@@ -8,12 +8,11 @@
 #include "Interface.h"
 #include "FileOperationProgress.h"
 #include "FileMasks.h"
+#include "RemoteFiles.h"
 #include "Exceptions.h"
 //---------------------------------------------------------------------------
 class TCopyParamType;
 class TFileOperationProgressType;
-class TRemoteDirectory;
-class TRemoteFile;
 class TCustomFileSystem;
 class TTunnelThread;
 class TSecureShell;
@@ -56,6 +55,8 @@ typedef int __fastcall (__closure *TFileOperationEvent)
 typedef void __fastcall (__closure *TSynchronizeDirectory)
   (const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,
    bool & Continue, bool Collect);
+typedef void __fastcall (__closure *TUpdatedSynchronizationChecklistItems)(
+  const TSynchronizeChecklist::TItemList & Items);
 typedef void __fastcall (__closure *TProcessedItem)(const void * Token);
 typedef void __fastcall (__closure *TDeleteLocalFileEvent)(
   const UnicodeString FileName, bool Alternative);
@@ -559,7 +560,11 @@ public:
   void __fastcall SynchronizeApply(
     TSynchronizeChecklist * Checklist,
     const TCopyParamType * CopyParam, int Params,
-    TSynchronizeDirectory OnSynchronizeDirectory, TProcessedItem OnProcessedItem);
+    TSynchronizeDirectory OnSynchronizeDirectory, TProcessedItem OnProcessedItem,
+    TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
+  void __fastcall SynchronizeChecklistCalculateSize(
+    TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items,
+    const TCopyParamType * CopyParam);
   void __fastcall FilesFind(UnicodeString Directory, const TFileMasks & FileMask,
     TFileFoundEvent OnFileFound, TFindingFileEvent OnFindingFile);
   void __fastcall SpaceAvailable(const UnicodeString Path, TSpaceAvailable & ASpaceAvailable);

+ 10 - 93
source/forms/CustomScpExplorer.cpp

@@ -5239,7 +5239,7 @@ void __fastcall TCustomScpExplorerForm::Synchronize(const UnicodeString LocalDir
     }
 
     // No need to call if !AnyOperation
-    Terminal->SynchronizeApply(AChecklist, &CopyParam, Params | TTerminal::spNoConfirmation, TerminalSynchronizeDirectory, NULL);
+    Terminal->SynchronizeApply(AChecklist, &CopyParam, Params | TTerminal::spNoConfirmation, TerminalSynchronizeDirectory, NULL, NULL);
   }
   __finally
   {
@@ -5341,7 +5341,8 @@ struct TSynchronizeParams
   TDateTime * StartTime;
 };
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::FullSynchronize(TSynchronizeParams & Params, TProcessedItem OnProcessedItem)
+void __fastcall TCustomScpExplorerForm::FullSynchronize(
+  TSynchronizeParams & Params, TProcessedItem OnProcessedItem, TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems)
 {
   DebugAssert(!FAutoOperation);
   void * BatchStorage;
@@ -5355,7 +5356,7 @@ void __fastcall TCustomScpExplorerForm::FullSynchronize(TSynchronizeParams & Par
 
     Terminal->SynchronizeApply(
       Params.Checklist, Params.CopyParam, Params.Params | TTerminal::spNoConfirmation,
-      TerminalSynchronizeDirectory, OnProcessedItem);
+      TerminalSynchronizeDirectory, OnProcessedItem, OnUpdatedSynchronizationChecklistItems);
   }
   __finally
   {
@@ -5366,106 +5367,22 @@ void __fastcall TCustomScpExplorerForm::FullSynchronize(TSynchronizeParams & Par
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TCustomScpExplorerForm::DoFullSynchronize(void * Token, TProcessedItem OnProcessedItem)
+void __fastcall TCustomScpExplorerForm::DoFullSynchronize(
+  void * Token, TProcessedItem OnProcessedItem, TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems)
 {
   TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);
   *Params.StartTime = Now();
-  FullSynchronize(Params, OnProcessedItem);
+  FullSynchronize(Params, OnProcessedItem, OnUpdatedSynchronizationChecklistItems);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::DoSynchronizeChecklistCalculateSize(
-  TSynchronizeChecklist * Checklist, const TSynchronizeChecklistItemList & Items, void * Token)
+  TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token)
 {
   // terminal can be already closed (e.g. dropped connection)
   if (Terminal != NULL)
   {
     TSynchronizeParams & Params = *static_cast<TSynchronizeParams *>(Token);
-    std::unique_ptr<TStrings> RemoteFileList(new TStringList());
-    std::unique_ptr<TStrings> LocalFileList(new TStringList());
-
-    for (size_t Index = 0; Index < Items.size(); Index++)
-    {
-      const TSynchronizeChecklist::TItem * ChecklistItem = Items[Index];
-      if (ChecklistItem->IsDirectory)
-      {
-        if (ChecklistItem->IsRemoteOnly())
-        {
-          RemoteFileList->AddObject(ChecklistItem->RemoteFile->FullFileName, ChecklistItem->RemoteFile);
-        }
-        else if (ChecklistItem->IsLocalOnly())
-        {
-          LocalFileList->Add(IncludeTrailingBackslash(ChecklistItem->Local.Directory) + ChecklistItem->Local.FileName);
-        }
-        else
-        {
-          // "update" actions are not relevant for directories
-          DebugFail();
-        }
-      }
-    }
-
-    TCalculatedSizes RemoteCalculatedSizes;
-    TCalculatedSizes LocalCalculatedSizes;
-
-    try
-    {
-      bool Result = true;
-      if (LocalFileList->Count > 0)
-      {
-        __int64 LocalSize = 0;
-        Result = Terminal->CalculateLocalFilesSize(LocalFileList.get(), LocalSize, Params.CopyParam, true, NULL, &LocalCalculatedSizes);
-      }
-      if (Result && (RemoteFileList->Count > 0))
-      {
-        __int64 RemoteSize = 0;
-        TCalculateSizeStats RemoteStats;
-        RemoteStats.CalculatedSizes = &RemoteCalculatedSizes;
-        Terminal->CalculateFilesSize(RemoteFileList.get(), RemoteSize, 0, Params.CopyParam, true, RemoteStats);
-      }
-    }
-    __finally
-    {
-      size_t LocalIndex = 0;
-      size_t RemoteIndex = 0;
-
-      for (size_t Index = 0; Index < Items.size(); Index++)
-      {
-        const TSynchronizeChecklist::TItem * ChecklistItem = Items[Index];
-        if (ChecklistItem->IsDirectory)
-        {
-          __int64 Size = -1;
-          if (ChecklistItem->IsRemoteOnly())
-          {
-            if (RemoteIndex < RemoteCalculatedSizes.size())
-            {
-              Size = RemoteCalculatedSizes[RemoteIndex];
-            }
-            RemoteIndex++;
-          }
-          else if (ChecklistItem->IsLocalOnly())
-          {
-            if (LocalIndex < LocalCalculatedSizes.size())
-            {
-              Size = LocalCalculatedSizes[LocalIndex];
-            }
-            LocalIndex++;
-          }
-          else
-          {
-            // "update" actions are not relevant for directories
-            DebugFail();
-          }
-
-          if (Size >= 0)
-          {
-            Checklist->UpdateDirectorySize(ChecklistItem, Size);
-          }
-        }
-      }
-
-      DebugAssert(RemoteIndex >= RemoteCalculatedSizes.size());
-      DebugAssert(LocalIndex >= LocalCalculatedSizes.size());
-    }
+    Terminal->SynchronizeChecklistCalculateSize(Checklist, Items, Params.CopyParam);
   }
 }
 //---------------------------------------------------------------------------
@@ -5551,7 +5468,7 @@ bool __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
         }
         else
         {
-          FullSynchronize(SynchronizeParams, NULL);
+          FullSynchronize(SynchronizeParams, NULL, NULL);
         }
       }
     }

+ 6 - 3
source/forms/CustomScpExplorer.h

@@ -605,10 +605,13 @@ protected:
   void __fastcall UpdatePixelsPerInchMainWindowCounter();
   void __fastcall CopyPopup(TControl * DestControl, TControl * SourceControl);
   void __fastcall CreateRemoteDirectory(const UnicodeString & Path, TRemoteProperties & Properties);
-  void __fastcall DoFullSynchronize(void * Token, TProcessedItem OnProcessedItem);
+  void __fastcall DoFullSynchronize(
+    void * Token, TProcessedItem OnProcessedItem, TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
   void __fastcall DoSynchronizeChecklistCalculateSize(
-    TSynchronizeChecklist * Checklist, const TSynchronizeChecklistItemList & Items, void * Token);
-  void __fastcall FullSynchronize(TSynchronizeParams & Params, TProcessedItem OnProcessedItem);
+    TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token);
+  void __fastcall FullSynchronize(
+    TSynchronizeParams & Params, TProcessedItem OnProcessedItem,
+    TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
   void __fastcall CreateOpenDirMenuList(TTBCustomItem * Menu, TOperationSide Side, TBookmarkList * BookmarkList);
   void __fastcall CreateOpenDirMenu(TTBCustomItem * Menu, TOperationSide Side);
 

+ 28 - 60
source/forms/SynchronizeChecklist.cpp

@@ -322,8 +322,9 @@ void __fastcall TSynchronizeChecklistDialog::LoadItem(TListItem * Item)
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklistDialog::CountItemSize(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor)
 {
-  int ActionIndex = int(GetChecklistItemAction(ChecklistItem));
-  __int64 ItemSize = GetItemSize(ChecklistItem);
+  TSynchronizeChecklist::TAction Action = GetChecklistItemAction(ChecklistItem);
+  int ActionIndex = int(Action);
+  __int64 ItemSize = ChecklistItem->GetSize(Action);
   FCheckedSize[ActionIndex] += Factor * ItemSize;
   FCheckedSize[0] += Factor * ItemSize;
 }
@@ -358,6 +359,7 @@ void __fastcall TSynchronizeChecklistDialog::LoadList()
         TListItem * Item = ListView->Items->Add();
         TSynchronizeChecklist::TAction Action = ChecklistItem->Action;
         FActions.insert(std::make_pair(ChecklistItem, Action));
+        FChecklistToListViewMap.insert(std::make_pair(ChecklistItem, Item));
         Item->Data = const_cast<TSynchronizeChecklist::TItem *>(ChecklistItem);
         Item->Checked = ChecklistItem->Checked;
         LoadItem(Item);
@@ -384,46 +386,6 @@ void __fastcall TSynchronizeChecklistDialog::LoadList()
   UpdateControls();
 }
 //---------------------------------------------------------------------------
-bool __fastcall TSynchronizeChecklistDialog::IsItemSizeIrrelevant(TSynchronizeChecklist::TAction Action)
-{
-  switch (Action)
-  {
-    case TSynchronizeChecklist::saNone:
-    case TSynchronizeChecklist::saDeleteRemote:
-    case TSynchronizeChecklist::saDeleteLocal:
-      return true;
-
-    default:
-      return false;
-  }
-}
-//---------------------------------------------------------------------------
-__int64 __fastcall TSynchronizeChecklistDialog::GetItemSize(const TSynchronizeChecklist::TItem * Item)
-{
-  TSynchronizeChecklist::TAction Action = GetChecklistItemAction(Item);
-  if (IsItemSizeIrrelevant(Action))
-  {
-    return 0;
-  }
-  else
-  {
-    switch (Action)
-    {
-      case TSynchronizeChecklist::saUploadNew:
-      case TSynchronizeChecklist::saUploadUpdate:
-        return Item->Local.Size;
-
-      case TSynchronizeChecklist::saDownloadNew:
-      case TSynchronizeChecklist::saDownloadUpdate:
-        return Item->Remote.Size;
-
-      default:
-        DebugFail();
-        return 0;
-    }
-  }
-}
-//---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklistDialog::FormShow(TObject * /*Sender*/)
 {
   // Moved here from CreateParams (see also TEditorForm::CreateParams), because there it breaks per-monitor DPI.
@@ -581,7 +543,7 @@ void __fastcall TSynchronizeChecklistDialog::StatusBarDrawPanel(
       (FormatNumber(FChecked[ActionIndex]),
        FormatNumber(FTotals[ActionIndex])));
     if ((FChecked[ActionIndex] > 0) &&
-        ((ActionIndex == 0) || !IsItemSizeIrrelevant(Action)))
+        ((ActionIndex == 0) || !TSynchronizeChecklist::IsItemSizeIrrelevant(Action)))
     {
       PanelText += FORMAT(L" (%s)", (FormatBytes(FCheckedSize[ActionIndex])));
     }
@@ -1105,6 +1067,26 @@ void __fastcall TSynchronizeChecklistDialog::ProcessedItem(const void * Token)
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TSynchronizeChecklistDialog::UpdatedSynchronizationChecklistItems(
+  const TSynchronizeChecklist::TItemList & Items)
+{
+  TSynchronizeChecklist::TItemList::const_iterator Iter = Items.begin();
+  while (Iter != Items.end())
+  {
+    const TSynchronizeChecklist::TItem * ChecklistItem = *Iter;
+    TListItem * Item = FChecklistToListViewMap[ChecklistItem];
+    LoadItem(Item);
+    // When called from FOnSynchronize, we rely on a caller never to update size of an item that had size already,
+    // otherwise we get it counted twice here.
+    if (Item->Checked)
+    {
+      CountItemSize(ChecklistItem, 1);
+    }
+    Iter++;
+  }
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklistDialog::OkButtonClick(TObject * /*Sender*/)
 {
   ListView->SelectAll(smNone);
@@ -1125,7 +1107,7 @@ void __fastcall TSynchronizeChecklistDialog::OkButtonClick(TObject * /*Sender*/)
   UpdateControls();
   try
   {
-    FOnSynchronize(FToken, ProcessedItem);
+    FOnSynchronize(FToken, ProcessedItem, UpdatedSynchronizationChecklistItems);
   }
   catch (Exception & E)
   {
@@ -1135,13 +1117,11 @@ void __fastcall TSynchronizeChecklistDialog::OkButtonClick(TObject * /*Sender*/)
 //---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklistDialog::CalculateSizeActionExecute(TObject * /*Sender*/)
 {
-  std::map<const TSynchronizeChecklist::TItem *, TListItem *> ChecklistToListViewMap;
-  TSynchronizeChecklistItemList Items;
+  TSynchronizeChecklist::TItemList Items;
   TListItem * Item = ListView->Selected;
   while (Item != NULL)
   {
     const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
-    ChecklistToListViewMap.insert(std::make_pair(ChecklistItem, Item));
     Items.push_back(ChecklistItem);
     if (Item->Checked)
     {
@@ -1156,19 +1136,7 @@ void __fastcall TSynchronizeChecklistDialog::CalculateSizeActionExecute(TObject
   }
   __finally
   {
-    TSynchronizeChecklistItemList::const_iterator Iter = Items.begin();
-    while (Iter != Items.end())
-    {
-      const TSynchronizeChecklist::TItem * ChecklistItem = *Iter;
-      TListItem * Item = ChecklistToListViewMap[ChecklistItem];
-      LoadItem(Item);
-      if (Item->Checked)
-      {
-        CountItemSize(ChecklistItem, 1);
-      }
-      Iter++;
-    }
-    UpdateControls();
+    UpdatedSynchronizationChecklistItems(Items);
   }
 }
 //---------------------------------------------------------------------------

+ 2 - 2
source/forms/SynchronizeChecklist.h

@@ -126,6 +126,7 @@ protected:
   TTokens FTokens;
   bool FSynchronizing;
   std::unique_ptr<Exception> FException;
+  std::map<const TSynchronizeChecklist::TItem *, TListItem *> FChecklistToListViewMap;
 
   void __fastcall UpdateControls();
   virtual void __fastcall CreateParams(TCreateParams & Params);
@@ -137,8 +138,6 @@ protected:
   void __fastcall Check(bool Check);
   TListItem * __fastcall SelectAll(bool Select, int Action = 0,
     bool OnlyTheAction = true);
-  bool __fastcall IsItemSizeIrrelevant(TSynchronizeChecklist::TAction Action);
-  __int64 __fastcall GetItemSize(const TSynchronizeChecklist::TItem * Item);
   void __fastcall UpdateStatusBarSize();
   int __fastcall PanelCount();
   inline const TSynchronizeChecklist::TItem * GetChecklistItem(TListItem * Item);
@@ -151,6 +150,7 @@ protected:
   void __fastcall CMDpiChanged(TMessage & Message);
   bool __fastcall GetWindowParams(UnicodeString & WindowParams);
   void __fastcall ProcessedItem(const void * Token);
+  void __fastcall UpdatedSynchronizationChecklistItems(const TSynchronizeChecklist::TItemList & Items);
   void __fastcall CountItemSize(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor);
   void __fastcall CountItem(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor);
   static int __fastcall CompareNumber(__int64 Value1, __int64 Value2);

+ 3 - 3
source/windows/WinInterface.h

@@ -351,10 +351,10 @@ bool __fastcall DoFullSynchronizeDialog(TSynchronizeMode & Mode, int & Params,
 class TSynchronizeChecklist;
 typedef void __fastcall (__closure *TCustomCommandMenuEvent)
   (TAction * Action, TStrings * LocalFileList, TStrings * RemoteFileList);
-typedef void __fastcall (__closure *TFullSynchronizeEvent)(void * Token, TProcessedItem OnProcessedItem);
-typedef std::vector<const TSynchronizeChecklist::TItem *> TSynchronizeChecklistItemList;
+typedef void __fastcall (__closure *TFullSynchronizeEvent)(
+  void * Token, TProcessedItem OnProcessedItem, TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
 typedef void __fastcall (__closure *TSynchronizeChecklistCalculateSize)
-  (TSynchronizeChecklist * Checklist, const TSynchronizeChecklistItemList & Items, void * Token);
+  (TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token);
 bool __fastcall DoSynchronizeChecklistDialog(TSynchronizeChecklist * Checklist,
   TSynchronizeMode Mode, int Params,
   const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,