Selaa lähdekoodia

File/directory rename can be resolved on Synchronization checklist window

Source commit: a2e0c76a2586ab0584f68dbc81081d6b0912058c
Martin Prikryl 7 vuotta sitten
vanhempi
sitoutus
2389dd4a1c

+ 8 - 0
source/core/RemoteFiles.cpp

@@ -2832,6 +2832,14 @@ void __fastcall TSynchronizeChecklist::Update(const TItem * Item, bool Check, TA
   MutableItem->Action = Action;
 }
 //---------------------------------------------------------------------------
+void TSynchronizeChecklist::Delete(const TItem * Item)
+{
+  // See comment in Update()
+  TItem * MutableItem = const_cast<TItem *>(Item);
+  FList->Extract(MutableItem);
+  delete Item;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklist::UpdateDirectorySize(const TItem * Item, __int64 Size)
 {
   // See comment in Update

+ 1 - 0
source/core/RemoteFiles.h

@@ -493,6 +493,7 @@ public:
 
   void __fastcall Update(const TItem * Item, bool Check, TAction Action);
   void __fastcall UpdateDirectorySize(const TItem * Item, __int64 Size);
+  void Delete(const TItem * Item);
 
   static TAction __fastcall Reverse(TAction Action);
   static bool __fastcall IsItemSizeIrrelevant(TAction Action);

+ 62 - 1
source/forms/CustomScpExplorer.cpp

@@ -125,6 +125,25 @@ private:
   TCustomScpExplorerForm * FForm;
 };
 //---------------------------------------------------------------------------
+class TAutoBatch
+{
+public:
+  TAutoBatch(TCustomScpExplorerForm * Form) :
+    FForm(Form)
+  {
+    FForm->BatchStart(FBatchStorage);
+  }
+
+  ~TAutoBatch()
+  {
+    FForm->BatchEnd(FBatchStorage);
+  }
+
+private:
+  TCustomScpExplorerForm * FForm;
+  void * FBatchStorage;
+};
+//---------------------------------------------------------------------------
 struct TTransferOperationParam
 {
   TTransferOperationParam();
@@ -5532,6 +5551,48 @@ void __fastcall TCustomScpExplorerForm::DoSynchronizeChecklistCalculateSize(
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::DoSynchronizeMove(
+  TOperationSide Side, const UnicodeString & FileName, const UnicodeString & NewFileName, TRemoteFile * RemoteFile)
+{
+  TAutoBatch AutoBatch(this);
+  TAutoFlag AutoOperationFlag(FAutoOperation);
+
+  if (Side == osRemote)
+  {
+    std::unique_ptr<TStrings> FileList(new TStringList());
+    FileList->AddObject(FileName, RemoteFile);
+    UnicodeString Target = UnixExtractFileDir(NewFileName);
+    UnicodeString FileMask = DelimitFileNameMask(UnixExtractFileName(NewFileName));
+
+    RemoteDirView->SaveSelection();
+    RemoteDirView->SaveSelectedNames();
+    try
+    {
+      Terminal->MoveFiles(FileList.get(), Target, FileMask);
+    }
+    catch(...)
+    {
+      RemoteDirView->DiscardSavedSelection();
+      throw;
+    }
+    RemoteDirView->RestoreSelection();
+  }
+  else if (DebugAlwaysTrue(Side == osLocal))
+  {
+    if (!MoveFile(FileName.c_str(), NewFileName.c_str()))
+    {
+      throw EOSExtException(FMTLOAD(RENAME_FILE_ERROR, (FileName, NewFileName)));
+    }
+    UnicodeString Directory = ExtractFileDir(FileName);
+    ReloadLocalDirectory(Directory);
+    UnicodeString NewDirectory = ExtractFileDir(NewFileName);
+    if (!SamePaths(Directory, NewDirectory))
+    {
+      ReloadLocalDirectory(NewDirectory);
+    }
+  }
+}
+//---------------------------------------------------------------------------
 int __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
   UnicodeString & LocalDirectory, UnicodeString & RemoteDirectory,
   TSynchronizeMode & Mode, bool & SaveMode, bool UseDefaults)
@@ -5607,7 +5668,7 @@ int __fastcall TCustomScpExplorerForm::DoFullSynchronizeDirectories(
         {
           if (!DoSynchronizeChecklistDialog(
                 Checklist, Mode, Params, LocalDirectory, RemoteDirectory, CustomCommandMenu, DoFullSynchronize,
-                DoSynchronizeChecklistCalculateSize, &SynchronizeParams))
+                DoSynchronizeChecklistCalculateSize, DoSynchronizeMove, &SynchronizeParams))
           {
             Result = -1;
           }

+ 3 - 0
source/forms/CustomScpExplorer.h

@@ -62,6 +62,7 @@ enum TCustomCommandListType { ccltAll, ccltBoth, ccltNonFile, ccltFile };
 //---------------------------------------------------------------------------
 class TCustomScpExplorerForm : public TForm
 {
+friend class TAutoBatch;
 __published:
   TPanel *RemotePanel;
   TTBXStatusBar *RemoteStatusBar;
@@ -621,6 +622,8 @@ protected:
     TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
   void __fastcall DoSynchronizeChecklistCalculateSize(
     TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token);
+  void __fastcall DoSynchronizeMove(
+    TOperationSide Side, const UnicodeString & FileName, const UnicodeString & NewFileName, TRemoteFile * RemoteFile);
   void __fastcall FullSynchronize(
     TSynchronizeParams & Params, TProcessedSynchronizationChecklistItem OnProcessedItem,
     TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);

+ 117 - 8
source/forms/SynchronizeChecklist.cpp

@@ -18,6 +18,7 @@
 #include <WinConfiguration.h>
 #include <GUITools.h>
 #include <TerminalManager.h>
+#include <System.IOUtils.hpp>
 //---------------------------------------------------------------------
 #pragma link "IEListView"
 #pragma link "NortonLikeListView"
@@ -32,12 +33,13 @@ bool __fastcall DoSynchronizeChecklistDialog(TSynchronizeChecklist * Checklist,
   TSynchronizeMode Mode, int Params,
   const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,
   TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
-  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, void * Token)
+  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove,
+  void * Token)
 {
   std::unique_ptr<TSynchronizeChecklistDialog> Dialog(
     new TSynchronizeChecklistDialog(
       Application, Mode, Params, LocalDirectory, RemoteDirectory, OnCustomCommandMenu, OnSynchronize,
-      OnSynchronizeChecklistCalculateSize, Token));
+      OnSynchronizeChecklistCalculateSize, OnSynchronizeMove, Token));
   return Dialog->Execute(Checklist);
 }
 //---------------------------------------------------------------------
@@ -45,7 +47,7 @@ __fastcall TSynchronizeChecklistDialog::TSynchronizeChecklistDialog(
   TComponent * AOwner, TSynchronizeMode Mode, int Params,
   const UnicodeString & LocalDirectory, const UnicodeString & RemoteDirectory,
   TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
-  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, void * Token)
+  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove, void * Token)
   : TForm(AOwner)
 {
   FFormRestored = false;
@@ -55,6 +57,7 @@ __fastcall TSynchronizeChecklistDialog::TSynchronizeChecklistDialog(
   FRemoteDirectory = UnixExcludeTrailingBackslash(RemoteDirectory);
   FOnCustomCommandMenu = OnCustomCommandMenu;
   FOnSynchronizeChecklistCalculateSize = OnSynchronizeChecklistCalculateSize;
+  FOnSynchronizeMove = OnSynchronizeMove;
   DebugAssert(OnSynchronize != NULL);
   FOnSynchronize = OnSynchronize;
   FToken = Token;
@@ -181,6 +184,7 @@ void __fastcall TSynchronizeChecklistDialog::UpdateControls()
   UncheckAllAction->Enabled = (FChecked[0] > 0) && !FSynchronizing;
   CustomCommandsAction->Enabled = AnyBoth && !AnyNonBoth && DebugAlwaysTrue(!FSynchronizing);
   ReverseAction->Enabled = (ListView->SelCount > 0) && DebugAlwaysTrue(!FSynchronizing);
+  MoveAction->Enabled = (GetMoveItems() != TSynchronizeMoveItems());
   CalculateSizeAction->Enabled = (ListView->SelCount > 0) && AnyDirectory && DebugAlwaysTrue(!FSynchronizing);
 
   SelectAllAction->Enabled = (ListView->SelCount < ListView->Items->Count) && !FSynchronizing;
@@ -351,12 +355,18 @@ void __fastcall TSynchronizeChecklistDialog::CountItem(const TSynchronizeCheckli
   CountItemSize(ChecklistItem, Factor);
 }
 //---------------------------------------------------------------------------
+void __fastcall TSynchronizeChecklistDialog::CountItemTotal(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor)
+{
+  FTotals[0] += Factor;
+  int ActionIndex = int(GetChecklistItemAction(ChecklistItem));
+  FTotals[ActionIndex] += Factor;
+}
+//---------------------------------------------------------------------------
 void __fastcall TSynchronizeChecklistDialog::LoadList()
 {
   memset(&FTotals, 0, sizeof(FTotals));
   memset(&FChecked, 0, sizeof(FChecked));
   memset(&FCheckedSize, 0, sizeof(FCheckedSize));
-  FTotals[0] = FChecklist->Count;
 
   ListView->Items->BeginUpdate();
   try
@@ -382,8 +392,7 @@ void __fastcall TSynchronizeChecklistDialog::LoadList()
         FChangingItemIgnore = false;
       }
 
-      int ActionIndex = int(GetChecklistItemAction(ChecklistItem));
-      FTotals[ActionIndex]++;
+      CountItemTotal(ChecklistItem, 1);
       if (ChecklistItem->Checked)
       {
         CountItem(ChecklistItem, 1);
@@ -986,7 +995,7 @@ void __fastcall TSynchronizeChecklistDialog::ReverseActionExecute(TObject * /*Se
     {
       int ActionIndex = int(Action);
 
-      FTotals[ActionIndex]--;
+      CountItemTotal(ChecklistItem, -1);
       if (Item->Checked)
       {
         CountItem(ChecklistItem, -1);
@@ -995,7 +1004,7 @@ void __fastcall TSynchronizeChecklistDialog::ReverseActionExecute(TObject * /*Se
       Action = NewAction;
       ActionIndex = int(Action);
 
-      FTotals[ActionIndex]++;
+      CountItemTotal(ChecklistItem, 1);
       if (Item->Checked)
       {
         // item size may differ with action (0 for delete, but non-0 for new file transfer)
@@ -1159,3 +1168,103 @@ void __fastcall TSynchronizeChecklistDialog::CalculateSizeAllActionExecute(TObje
   CalculateSizeActionExecute(Sender);
 }
 //---------------------------------------------------------------------------
+TSynchronizeChecklistDialog::TSynchronizeMoveItems __fastcall TSynchronizeChecklistDialog::GetMoveItems()
+{
+  if ((ListView->SelCount != 2) || DebugAlwaysFalse(FSynchronizing))
+  {
+    return TSynchronizeMoveItems();
+  }
+  else
+  {
+    TListItem * Item1 = ListView->Selected;
+    const TSynchronizeChecklist::TItem * ChecklistItem1 = GetChecklistItem(DebugNotNull(ListView->Selected));
+    TListItem * Item2 = ListView->GetNextItem(ListView->Selected, sdAll, TItemStates() << isSelected);
+    const TSynchronizeChecklist::TItem * ChecklistItem2 = GetChecklistItem(DebugNotNull(Item2));
+
+    if (ChecklistItem1->IsDirectory != ChecklistItem2->IsDirectory)
+    {
+      return TSynchronizeMoveItems();
+    }
+    else
+    {
+      TSynchronizeChecklist::TAction Action1 = GetChecklistItemAction(ChecklistItem1);
+      TSynchronizeChecklist::TAction Action2 = GetChecklistItemAction(ChecklistItem2);
+
+      if ((Action1 == TSynchronizeChecklist::saUploadNew) && (Action2 == TSynchronizeChecklist::saDeleteRemote))
+      {
+        return TSynchronizeMoveItems(ChecklistItem1, ChecklistItem2);
+      }
+      else if ((Action1 == TSynchronizeChecklist::saDownloadNew) && (Action2 == TSynchronizeChecklist::saDeleteLocal))
+      {
+        return TSynchronizeMoveItems(ChecklistItem1, ChecklistItem2);
+      }
+      else if ((Action1 == TSynchronizeChecklist::saDeleteRemote) && (Action2 == TSynchronizeChecklist::saUploadNew))
+      {
+        return TSynchronizeMoveItems(ChecklistItem2, ChecklistItem1);
+      }
+      else if ((Action1 == TSynchronizeChecklist::saDeleteLocal) && (Action2 == TSynchronizeChecklist::saDownloadNew))
+      {
+        return TSynchronizeMoveItems(ChecklistItem2, ChecklistItem1);
+      }
+      else
+      {
+        return TSynchronizeMoveItems();
+      }
+    }
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeChecklistDialog::DeleteItem(TListItem * Item)
+{
+  const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
+  CountItemTotal(ChecklistItem, -1);
+  if (Item->Checked)
+  {
+    CountItem(ChecklistItem, -1);
+  }
+
+  FActions.erase(ChecklistItem);
+  FChecklistToListViewMap.erase(ChecklistItem);
+
+  FChecklist->Delete(ChecklistItem);
+  ListView->Items->Delete(Item->Index);
+}
+//---------------------------------------------------------------------------
+void __fastcall TSynchronizeChecklistDialog::MoveActionExecute(TObject *)
+{
+  TSynchronizeMoveItems MoveItems = GetMoveItems();
+  TSynchronizeChecklist::TAction Action2 = GetChecklistItemAction(MoveItems.second);
+
+  TOperationSide Side;
+  UnicodeString FileName;
+  UnicodeString NewFileName;
+  TRemoteFile * RemoteFile;
+  if (Action2 == TSynchronizeChecklist::saDeleteRemote)
+  {
+    Side = osRemote;
+    FileName = UnixCombinePaths(MoveItems.second->Remote.Directory, MoveItems.second->Remote.FileName);
+    NewFileName = UnixCombinePaths(MoveItems.first->Remote.Directory, MoveItems.first->Local.FileName);
+    RemoteFile = MoveItems.second->RemoteFile;
+  }
+  else if (Action2 == TSynchronizeChecklist::saDeleteLocal)
+  {
+    Side = osLocal;
+    FileName = TPath::Combine(MoveItems.second->Local.Directory, MoveItems.second->Local.FileName);
+    NewFileName = TPath::Combine(MoveItems.first->Local.Directory, MoveItems.first->Remote.FileName);
+    RemoteFile = NULL;
+  }
+  else
+  {
+    DebugFail();
+    Abort();
+  }
+
+  FOnSynchronizeMove(Side, FileName, NewFileName, RemoteFile);
+
+  TListItem * Item1 = DebugNotNull(ListView->FindData(0, const_cast<TSynchronizeChecklist::TItem *>(MoveItems.first), true, false));
+  TListItem * Item2 = DebugNotNull(ListView->FindData(0, const_cast<TSynchronizeChecklist::TItem *>(MoveItems.second), true, false));
+
+  DeleteItem(Item1);
+  DeleteItem(Item2);
+}
+//---------------------------------------------------------------------------

+ 21 - 4
source/forms/SynchronizeChecklist.dfm

@@ -1443,13 +1443,13 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     end
     object CustomCommandsButton2: TButton
       Left = 8
-      Top = 322
+      Top = 353
       Width = 108
       Height = 25
       Action = CustomCommandsAction
       Anchors = [akLeft, akTop, akRight]
       Caption = 'Co&mmands'
-      TabOrder = 8
+      TabOrder = 9
     end
     object ReverseButton: TButton
       Left = 8
@@ -1462,12 +1462,21 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     end
     object CalculateSizeButton: TButton
       Left = 8
-      Top = 291
+      Top = 322
       Width = 108
       Height = 25
       Action = CalculateSizeAction
       Anchors = [akLeft, akTop, akRight]
-      TabOrder = 9
+      TabOrder = 10
+    end
+    object MoveButton: TButton
+      Left = 8
+      Top = 291
+      Width = 108
+      Height = 25
+      Action = MoveAction
+      Anchors = [akLeft, akTop, akRight]
+      TabOrder = 8
     end
   end
   object ListView: TIEListView
@@ -2334,6 +2343,9 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
     object ReverseItem: TMenuItem
       Action = ReverseAction
     end
+    object MoveItem: TMenuItem
+      Action = MoveAction
+    end
     object Calculate1: TMenuItem
       Action = CalculateSizeAction
     end
@@ -2396,6 +2408,11 @@ object SynchronizeChecklistDialog: TSynchronizeChecklistDialog
       ShortCut = 49217
       OnExecute = CalculateSizeAllActionExecute
     end
+    object MoveAction: TAction
+      Caption = '&Move'
+      ShortCut = 117
+      OnExecute = MoveActionExecute
+    end
   end
   object ActionImages120: TPngImageList
     Height = 20

+ 11 - 1
source/forms/SynchronizeChecklist.h

@@ -56,6 +56,9 @@ __published:
   TMenuItem *Calculate1;
   TButton *CalculateSizeButton;
   TAction *CalculateSizeAllAction;
+  TAction *MoveAction;
+  TButton *MoveButton;
+  TMenuItem *MoveItem;
   void __fastcall HelpButtonClick(TObject * Sender);
   void __fastcall FormShow(TObject * Sender);
   void __fastcall StatusBarDrawPanel(TStatusBar *StatusBar,
@@ -91,13 +94,15 @@ __published:
   void __fastcall OkButtonClick(TObject *Sender);
   void __fastcall CalculateSizeActionExecute(TObject *Sender);
   void __fastcall CalculateSizeAllActionExecute(TObject *Sender);
+  void __fastcall MoveActionExecute(TObject *Sender);
 
 public:
   __fastcall TSynchronizeChecklistDialog(
     TComponent * AOwner, TSynchronizeMode Mode, int Params,
     const UnicodeString & LocalDirectory, const UnicodeString & RemoteDirectory,
     TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
-    TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, void * Token);
+    TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove,
+    void * Token);
   virtual __fastcall ~TSynchronizeChecklistDialog();
 
   bool __fastcall Execute(TSynchronizeChecklist * Checklist);
@@ -120,6 +125,7 @@ protected:
   UnicodeString FGeneralHint;
   TCustomCommandMenuEvent FOnCustomCommandMenu;
   TSynchronizeChecklistCalculateSize FOnSynchronizeChecklistCalculateSize;
+  TSynchronizeMoveEvent FOnSynchronizeMove;
   typedef std::map<const TSynchronizeChecklist::TItem *, TSynchronizeChecklist::TAction> TActions;
   TActions FActions;
   TFullSynchronizeEvent FOnSynchronize;
@@ -154,6 +160,10 @@ protected:
   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);
+  void __fastcall CountItemTotal(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor);
+  typedef std::pair<const TSynchronizeChecklist::TItem *, const TSynchronizeChecklist::TItem *> TSynchronizeMoveItems;
+  TSynchronizeMoveItems __fastcall GetMoveItems();
+  void __fastcall DeleteItem(TListItem * Item);
   static int __fastcall CompareNumber(__int64 Value1, __int64 Value2);
 };
 //----------------------------------------------------------------------------

+ 4 - 1
source/windows/WinInterface.h

@@ -357,11 +357,14 @@ typedef void __fastcall (__closure *TFullSynchronizeEvent)(
   TUpdatedSynchronizationChecklistItems OnUpdatedSynchronizationChecklistItems);
 typedef void __fastcall (__closure *TSynchronizeChecklistCalculateSize)
   (TSynchronizeChecklist * Checklist, const TSynchronizeChecklist::TItemList & Items, void * Token);
+typedef void __fastcall (__closure *TSynchronizeMoveEvent)(
+  TOperationSide Side, const UnicodeString & FileName, const UnicodeString & NewFileName, TRemoteFile * RemoteFile);
 bool __fastcall DoSynchronizeChecklistDialog(TSynchronizeChecklist * Checklist,
   TSynchronizeMode Mode, int Params,
   const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,
   TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
-  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, void * Token);
+  TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove,
+  void * Token);
 
 // forms\Editor.cpp
 typedef void __fastcall (__closure *TFileClosedEvent)