Browse Source

Local-local copy options dialog, including an operation mask support

Source commit: 3187d463d0b664039658d333b42b3a15d79af909
Martin Prikryl 5 năm trước cách đây
mục cha
commit
5156f7cbcb

+ 7 - 0
source/ScpForms.cbproj

@@ -104,6 +104,13 @@
 			<BuildOrder>23</BuildOrder>
 		</CppCompile>
 		<FormResources Include="forms\Copy.dfm"/>
+		<CppCompile Include="forms\CopyLocal.cpp">
+			<Form>CopyLocalDialog</Form>
+			<FormType>dfm</FormType>
+			<DependentOn>forms\CopyLocal.h</DependentOn>
+			<BuildOrder>37</BuildOrder>
+		</CppCompile>
+		<FormResources Include="forms\CopyLocal.dfm"/>
 		<CppCompile Include="forms\CopyParamCustom.cpp">
 			<BuildOrder>32</BuildOrder>
 			<Form>CopyParamCustomDialog</Form>

+ 51 - 29
source/forms/Copy.cpp

@@ -62,6 +62,54 @@ bool __fastcall DoCopyDialog(
   return Result;
 }
 //---------------------------------------------------------------------------
+bool CopyDialogValidateLocalDirectory(const UnicodeString & Directory, THistoryComboBox * DirectoryEdit)
+{
+  bool Result = true;
+  UnicodeString Drive = ExtractFileDrive(Directory);
+  if (!DirectoryExistsFix(Directory))
+  {
+    if (MessageDialog(MainInstructions(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Directory))),
+          qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel)
+    {
+      if (!ForceDirectories(ApiPath(Directory)))
+      {
+        SimpleErrorDialog(FMTLOAD(CREATE_LOCAL_DIR_ERROR, (Directory)));
+        Result = false;
+      }
+    }
+    else
+    {
+      Result = False;
+    }
+  }
+
+  if (!Result)
+  {
+    DirectoryEdit->SelectAll();
+    DirectoryEdit->SetFocus();
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+bool CopyDialogValidateFileMask(
+  const UnicodeString & FileMask, THistoryComboBox * DirectoryEdit, bool MultipleFiles, bool RemotePaths)
+{
+  bool Result = true;
+  if (!IsFileNameMask(FileMask) && MultipleFiles)
+  {
+    UnicodeString Message =
+      FormatMultiFilesToOneConfirmation(DirectoryEdit->Text, RemotePaths);
+    Result = (MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel);
+  }
+
+  if (!Result)
+  {
+    DirectoryEdit->SelectAll();
+    DirectoryEdit->SetFocus();
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
 __fastcall TCopyDialog::TCopyDialog(
   TComponent* Owner, bool ToRemote, bool Move, TStrings * FileList, int Options,
   int CopyParamAttrs, TSessionData * SessionData) : TForm(Owner)
@@ -407,38 +455,12 @@ void __fastcall TCopyDialog::FormCloseQuery(TObject * /*Sender*/,
 
     if (!RemotePaths() && ((FOptions & coTemp) == 0))
     {
-      UnicodeString Dir = Directory;
-      UnicodeString Drive = ExtractFileDrive(Dir);
-      if (!DirectoryExists(ApiPath(Dir)))
-      {
-        if (MessageDialog(MainInstructions(FMTLOAD(CREATE_LOCAL_DIRECTORY, (Dir))),
-              qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel)
-        {
-          if (!ForceDirectories(ApiPath(Dir)))
-          {
-            SimpleErrorDialog(FMTLOAD(CREATE_LOCAL_DIR_ERROR, (Dir)));
-            CanClose = false;
-          }
-        }
-        else
-        {
-          CanClose = False;
-        }
-      }
-
-      if (!CanClose)
-      {
-        DirectoryEdit->SelectAll();
-        DirectoryEdit->SetFocus();
-      }
+      CanClose = CopyDialogValidateLocalDirectory(Directory, DirectoryEdit);
     }
 
-    if (CanClose && !IsFileNameMask(GetFileMask()) && (FFileList->Count > 1))
+    if (CanClose)
     {
-      UnicodeString Message =
-        FormatMultiFilesToOneConfirmation(DirectoryEdit->Text, RemotePaths());
-      CanClose =
-        (MessageDialog(Message, qtConfirmation, qaOK | qaCancel, HELP_NONE) != qaCancel);
+      CanClose = CopyDialogValidateFileMask(GetFileMask(), DirectoryEdit, (FFileList->Count > 1), RemotePaths());
     }
   }
 }

+ 156 - 0
source/forms/CopyLocal.cpp

@@ -0,0 +1,156 @@
+//---------------------------------------------------------------------------
+#include <vcl.h>
+#pragma hdrstop
+
+#include <Common.h>
+#include "CopyLocal.h"
+#include "VCLCommon.h"
+#include "TextsWin.h"
+#include "GUITools.h"
+#include "Tools.h"
+#include "WinInterface.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma link "HistoryComboBox"
+#pragma resource "*.dfm"
+//---------------------------------------------------------------------------
+bool DoCopyLocalDialog(bool Move, int Options, UnicodeString & TargetDirectory, UnicodeString & FileMask, int & OutputOptions)
+{
+  std::unique_ptr<TCopyLocalDialog> Dialog(new TCopyLocalDialog(GetFormOwner(), Move, Options));
+  return Dialog->Execute(TargetDirectory, FileMask, OutputOptions);
+}
+//---------------------------------------------------------------------------
+TCopyLocalDialog::TCopyLocalDialog(TComponent * Owner, bool Move, int Options)
+  : TForm(Owner)
+{
+
+  FOptions = Options;
+  UnicodeString ACaption;
+  UnicodeString ImageName;
+  if (!Move)
+  {
+    ImageName = L"Upload File"; // TODO
+    ACaption = LoadStr(COPY_LOCAL_COPY_CAPTION);
+  }
+  else
+  {
+    ImageName = L"Upload File Remove Original"; // TODO
+    ACaption = LoadStr(COPY_LOCAL_MOVE_CAPTION);
+  }
+  Caption = ACaption;
+  LoadDialogImage(Image, ImageName);
+
+  HotTrackLabel(ShortCutHintLabel);
+  if (FLAGCLEAR(FOptions, cloShortCutHint) || CustomWinConfiguration->CopyShortCutHintShown)
+  {
+    ShortCutHintPanel->Visible = false;
+    ClientHeight = ClientHeight - ShortCutHintPanel->Height;
+  }
+
+  UseSystemSettings(this);
+}
+//---------------------------------------------------------------------------
+bool TCopyLocalDialog::Execute(UnicodeString & TargetDirectory, UnicodeString & FileMask, int & OutputOptions)
+{
+  DirectoryEdit->Items = CustomWinConfiguration->History[L"LocalTarget"];
+  SetDirectoryAndFileMask(TargetDirectory, FileMask);
+  NeverShowAgainCheck->Checked = FLAGSET(OutputOptions, clooDoNotShowAgain);
+  DebugAssert((OutputOptions & ~clooDoNotShowAgain) == 0);
+  bool Result = (ShowModal() == DefaultResult(this));
+  if (Result)
+  {
+    ValidateDirectoryEdit();
+
+    DirectoryEdit->SaveToHistory();
+    CustomWinConfiguration->History[L"LocalTarget"] = DirectoryEdit->Items;
+
+    FileMask = GetFileMask();
+    TargetDirectory = GetDirectory();
+    OutputOptions = FLAGMASK(NeverShowAgainCheck->Checked, clooDoNotShowAgain);
+
+    if (ShortCutHintPanel->Visible)
+    {
+      CustomWinConfiguration->CopyShortCutHintShown = true;
+    }
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::ShortCutHintLabelClick(TObject *)
+{
+  DoPreferencesDialog(pmCommander);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::FormShow(TObject *)
+{
+  InstallPathWordBreakProc(DirectoryEdit);
+  // Does not work when set from a contructor
+  ShortCutHintPanel->Color = Application->HintColor;
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void TCopyLocalDialog::UpdateControls()
+{
+}
+//---------------------------------------------------------------------------
+void TCopyLocalDialog::ValidateDirectoryEdit()
+{
+  if (DirectoryExistsFix(DirectoryEdit->Text))
+  {
+    DirectoryEdit->Text = IncludeTrailingBackslash(DirectoryEdit->Text) + AnyMask;
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::DirectoryEditExit(TObject *)
+{
+  ValidateDirectoryEdit();
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::FormCloseQuery(TObject *, bool & CanClose)
+{
+  if (ModalResult == DefaultResult(this))
+  {
+    ExitActiveControl(this);
+
+    CanClose =
+      CopyDialogValidateLocalDirectory(GetDirectory(), DirectoryEdit) &&
+      CopyDialogValidateFileMask(GetFileMask(), DirectoryEdit, FLAGSET(FOptions, cloMultipleFiles), false);
+  }
+}
+//---------------------------------------------------------------------------
+void TCopyLocalDialog::SetDirectoryAndFileMask(const UnicodeString & Directory, const UnicodeString & FileMask)
+{
+  DirectoryEdit->Text = IncludeTrailingBackslash(Directory) + FileMask;
+}
+//---------------------------------------------------------------------------
+UnicodeString TCopyLocalDialog::GetDirectory()
+{
+  UnicodeString Result = DirectoryEdit->Text;
+  Result = ExtractFilePath(Result);
+  if (!Result.IsEmpty())
+  {
+    Result = IncludeTrailingBackslash(Result);
+  }
+  return Result;
+}
+//---------------------------------------------------------------------------
+UnicodeString TCopyLocalDialog::GetFileMask()
+{
+  return ExtractFileName(DirectoryEdit->Text);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::HelpButtonClick(TObject *)
+{
+  FormHelp(this);
+}
+//---------------------------------------------------------------------------
+void __fastcall TCopyLocalDialog::LocalDirectoryBrowseButtonClick(TObject *)
+{
+  UnicodeString ADirectory = GetDirectory();
+  if (SelectDirectory(ADirectory, LoadStr(SELECT_LOCAL_DIRECTORY), false))
+  {
+    SetDirectoryAndFileMask(ADirectory, GetFileMask());
+    UpdateControls();
+  }
+}
+//---------------------------------------------------------------------------

+ 121 - 0
source/forms/CopyLocal.dfm

@@ -0,0 +1,121 @@
+object CopyLocalDialog: TCopyLocalDialog
+  Left = 0
+  Top = 0
+  HelpType = htKeyword
+  HelpKeyword = 'ui_copy_local'
+  BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp]
+  BorderStyle = bsDialog
+  Caption = 'CopyLocalDialog'
+  ClientHeight = 121
+  ClientWidth = 511
+  Color = clBtnFace
+  ParentFont = True
+  OldCreateOrder = False
+  Position = poOwnerFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  DesignSize = (
+    511
+    121)
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Image: TImage
+    Left = 8
+    Top = 11
+    Width = 32
+    Height = 32
+    AutoSize = True
+  end
+  object DirectoryLabel: TLabel
+    Left = 46
+    Top = 8
+    Width = 61
+    Height = 13
+    Caption = '&Target path:'
+  end
+  object DirectoryEdit: THistoryComboBox
+    Left = 46
+    Top = 25
+    Width = 372
+    Height = 21
+    AutoComplete = False
+    Anchors = [akLeft, akTop, akRight]
+    DropDownCount = 16
+    TabOrder = 0
+    Text = 'DirectoryEdit'
+    OnExit = DirectoryEditExit
+  end
+  object OkButton: TButton
+    Left = 260
+    Top = 55
+    Width = 75
+    Height = 25
+    Anchors = [akTop, akRight]
+    Caption = 'OK'
+    Default = True
+    ModalResult = 1
+    TabOrder = 3
+  end
+  object CancelButton: TButton
+    Left = 343
+    Top = 55
+    Width = 75
+    Height = 25
+    Anchors = [akTop, akRight]
+    Cancel = True
+    Caption = 'Cancel'
+    ModalResult = 2
+    TabOrder = 4
+  end
+  object LocalDirectoryBrowseButton: TButton
+    Left = 427
+    Top = 23
+    Width = 75
+    Height = 25
+    Caption = 'B&rowse...'
+    TabOrder = 1
+    OnClick = LocalDirectoryBrowseButtonClick
+  end
+  object HelpButton: TButton
+    Left = 427
+    Top = 55
+    Width = 75
+    Height = 25
+    Anchors = [akTop, akRight]
+    Caption = '&Help'
+    TabOrder = 5
+    OnClick = HelpButtonClick
+  end
+  object NeverShowAgainCheck: TCheckBox
+    Left = 12
+    Top = 58
+    Width = 242
+    Height = 17
+    Caption = '&Do not show this dialog box again'
+    TabOrder = 2
+  end
+  object ShortCutHintPanel: TPanel
+    Left = 0
+    Top = 87
+    Width = 511
+    Height = 34
+    Align = alBottom
+    BevelOuter = bvNone
+    ParentBackground = False
+    TabOrder = 6
+    object ShortCutHintLabel: TLabel
+      Left = 12
+      Top = 3
+      Width = 490
+      Height = 28
+      AutoSize = False
+      Caption = 
+        'In Commander interface the keyboard shortcut F5 is used to trans' +
+        'fer files. Should you want to use it to refresh a file panel, cl' +
+        'ick here to go to preferences.'
+      ShowAccelChar = False
+      WordWrap = True
+      OnClick = ShortCutHintLabelClick
+    end
+  end
+end

+ 47 - 0
source/forms/CopyLocal.h

@@ -0,0 +1,47 @@
+//---------------------------------------------------------------------------
+#ifndef CopyLocalH
+#define CopyLocalH
+//---------------------------------------------------------------------------
+#include <System.Classes.hpp>
+#include <Vcl.Controls.hpp>
+#include <Vcl.StdCtrls.hpp>
+#include <Vcl.Forms.hpp>
+#include "HistoryComboBox.hpp"
+#include <Vcl.ExtCtrls.hpp>
+//---------------------------------------------------------------------------
+class TCopyLocalDialog : public TForm
+{
+__published:
+  TImage *Image;
+  TLabel *DirectoryLabel;
+  THistoryComboBox *DirectoryEdit;
+  TButton *OkButton;
+  TButton *CancelButton;
+  TButton *LocalDirectoryBrowseButton;
+  TButton *HelpButton;
+  TCheckBox *NeverShowAgainCheck;
+  TPanel *ShortCutHintPanel;
+  TLabel *ShortCutHintLabel;
+  void __fastcall ShortCutHintLabelClick(TObject *Sender);
+  void __fastcall FormShow(TObject *Sender);
+  void __fastcall DirectoryEditExit(TObject *Sender);
+  void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
+  void __fastcall HelpButtonClick(TObject *Sender);
+  void __fastcall LocalDirectoryBrowseButtonClick(TObject *Sender);
+
+private:
+  int FOptions;
+
+  void UpdateControls();
+  void ValidateDirectoryEdit();
+  UnicodeString GetDirectory();
+  UnicodeString GetFileMask();
+  void SetDirectoryAndFileMask(const UnicodeString & Directory, const UnicodeString & FileMask);
+
+public:
+  TCopyLocalDialog(TComponent * Owner, bool Move, int Options);
+
+  bool Execute(UnicodeString & TargetDirectory, UnicodeString & FileMask, int & OutputOptions);
+};
+//---------------------------------------------------------------------------
+#endif

+ 44 - 30
source/forms/CustomScpExplorer.cpp

@@ -1111,6 +1111,40 @@ void __fastcall TCustomScpExplorerForm::CopyParamDialogAfter(
   // noop
 }
 //---------------------------------------------------------------------------
+bool TCustomScpExplorerForm::GetDoNotShowCopyDialogDefault(bool DragDrop)
+{
+  return DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto);
+}
+//---------------------------------------------------------------------------
+void TCustomScpExplorerForm::HandleDoNotShowCopyDialogAgain(bool DragDrop, bool DoNotShowAgain)
+{
+  if (DoNotShowAgain)
+  {
+    if (DragDrop)
+    {
+      if (WinConfiguration->DDTransferConfirmation == asAuto)
+      {
+        PopupTrayBalloon(
+          NULL, LoadStr(DD_TRANSFER_CONFIRM_OFF2), qtInformation, NULL, 0, EnableDDTransferConfirmation, NULL);
+      }
+      WinConfiguration->DDTransferConfirmation = asOff;
+    }
+    else
+    {
+      WinConfiguration->ConfirmTransferring = false;
+    }
+  }
+  else
+  {
+    // User explicitly unchecked "do not show again",
+    // so show him the dialog the next time
+    if (DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto))
+    {
+      WinConfiguration->DDTransferConfirmation = asOn;
+    }
+  }
+}
+//---------------------------------------------------------------------------
 bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
   TTransferDirection Direction, TTransferType Type, bool Temp,
   TStrings * FileList, UnicodeString & TargetDirectory, TGUICopyParamType & CopyParam,
@@ -1136,9 +1170,7 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
     int CopyParamAttrs = (Direction == tdToRemote ?
       UsableCopyParamAttrs.Upload : UsableCopyParamAttrs.Download) |
       FLAGMASK(DisableNewerOnly, cpaNoNewerOnly);
-    int OutputOptions =
-      FLAGMASK(DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto),
-        cooDoNotShowAgain);
+    int OutputOptions = FLAGMASK(GetDoNotShowCopyDialogDefault(DragDrop), cooDoNotShowAgain);
     std::unique_ptr<TSessionData> SessionData(SessionDataForCode());
     FlashOnBackground(); // Particularly when called from ClipboardFakeCreated
     Result = DoCopyDialog(Direction == tdToRemote, Type == ttMove,
@@ -1146,31 +1178,7 @@ bool __fastcall TCustomScpExplorerForm::CopyParamDialog(
 
     if (Result)
     {
-      if (FLAGSET(OutputOptions, cooDoNotShowAgain))
-      {
-        if (DragDrop)
-        {
-          if (WinConfiguration->DDTransferConfirmation == asAuto)
-          {
-            PopupTrayBalloon(NULL, LoadStr(DD_TRANSFER_CONFIRM_OFF2), qtInformation,
-              NULL, 0, EnableDDTransferConfirmation, NULL);
-          }
-          WinConfiguration->DDTransferConfirmation = asOff;
-        }
-        else
-        {
-          WinConfiguration->ConfirmTransferring = false;
-        }
-      }
-      else
-      {
-        // User explicitly unchecked "do not show again",
-        // so show him the dialog the next time
-        if (DragDrop && (WinConfiguration->DDTransferConfirmation == asAuto))
-        {
-          WinConfiguration->DDTransferConfirmation = asOn;
-        }
-      }
+      HandleDoNotShowCopyDialogAgain(DragDrop, FLAGSET(OutputOptions, cooDoNotShowAgain));
 
       CopyParamDialogAfter(Direction, Temp, TargetDirectory);
     }
@@ -5350,7 +5358,7 @@ void __fastcall TCustomScpExplorerForm::DoDirViewExecFile(TObject * Sender,
         {
           if (IsLocalBrowserMode())
           {
-            LocalLocalCopy(foCopy, Side, true, !WinConfiguration->CopyOnDoubleClickConfirmation);
+            LocalLocalCopy(foCopy, Side, true, !WinConfiguration->CopyOnDoubleClickConfirmation, false, 0);
           }
           else
           {
@@ -11039,7 +11047,13 @@ bool __fastcall TCustomScpExplorerForm::HasActiveTerminal()
 }
 //---------------------------------------------------------------------------
 void TCustomScpExplorerForm::LocalLocalCopy(
-  TFileOperation, TOperationSide, bool DebugUsedArg(OnFocused), bool DebugUsedArg(NoConfirmation))
+  TFileOperation, TOperationSide, bool DebugUsedArg(OnFocused), bool DebugUsedArg(NoConfirmation),
+  bool DebugUsedArg(DragDrop), unsigned int DebugUsedArg(Flags))
 {
   DebugFail();
 }
+//---------------------------------------------------------------------------
+void TCustomScpExplorerForm::LocalLocalCopyCommand(TFileOperation Operation, TOperationSide Side, bool OnFocused, unsigned int Flags)
+{
+  LocalLocalCopy(Operation, Side, OnFocused, !WinConfiguration->ConfirmTransferring, false, Flags);
+}

+ 5 - 1
source/forms/CustomScpExplorer.h

@@ -715,6 +715,8 @@ protected:
     TTBXComboBoxItem * Sender, const UnicodeString AText, int AIndex, int & ImageIndex);
   virtual void __fastcall DoRemotePathComboBoxCancel(TObject * Sender);
   virtual void __fastcall DoRemotePathComboBoxItemClick(TObject * Sender);
+  bool GetDoNotShowCopyDialogDefault(bool DragDrop);
+  void HandleDoNotShowCopyDialogAgain(bool DragDrop, bool DoNotShowAgain);
 
 public:
   virtual __fastcall ~TCustomScpExplorerForm();
@@ -730,7 +732,9 @@ public:
     bool OnFocused, bool NoConfirmation = false, void * Param = NULL);
   void __fastcall ExecuteCopyOperationCommand(
     TOperationSide Side, bool OnFocused, unsigned int Flags);
-  virtual void LocalLocalCopy(TFileOperation Operation, TOperationSide Side, bool OnFocused, bool NoConfirmation);
+  virtual void LocalLocalCopy(
+    TFileOperation Operation, TOperationSide Side, bool OnFocused, bool NoConfirmation, bool DragDrop, unsigned int Flags);
+  void LocalLocalCopyCommand(TFileOperation Operation, TOperationSide Side, bool OnFocused, unsigned int Flags);
   void __fastcall AdHocCustomCommand(bool OnFocused);
   virtual TCustomDirView * __fastcall DirView(TOperationSide Side);
   virtual bool __fastcall DirViewEnabled(TOperationSide Side);

+ 6 - 6
source/forms/NonVisual.cpp

@@ -561,17 +561,17 @@ void __fastcall TNonVisualDataModule::ExplorerActionsExecute(
     EXE(LocalPropertiesAction2, ScpExplorer->ExecuteFileOperationCommand(foSetProperties, osLocal, false))
     EXE(LocalAddEditLinkAction3, ScpExplorer->AddEditLink(osLocal, false))
     EXE(LocalNewFileAction, ScpExplorer->EditNew(osLocal))
-    EXE(LocalLocalCopyAction, ScpExplorer->LocalLocalCopy(foCopy, osLocal, false, false))
-    EXE(LocalLocalMoveAction, ScpExplorer->LocalLocalCopy(foMove, osLocal, false, false))
-    EXE(LocalOtherCopyAction, ScpExplorer->LocalLocalCopy(foCopy, osOther, false, false))
-    EXE(LocalOtherMoveAction, ScpExplorer->LocalLocalCopy(foMove, osOther, false, false))
+    EXE(LocalLocalCopyAction, ScpExplorer->LocalLocalCopyCommand(foCopy, osLocal, false, ShortCutFlag))
+    EXE(LocalLocalMoveAction, ScpExplorer->LocalLocalCopyCommand(foMove, osLocal, false, ShortCutFlag))
+    EXE(LocalOtherCopyAction, ScpExplorer->LocalLocalCopyCommand(foCopy, osOther, false, ShortCutFlag))
+    EXE(LocalOtherMoveAction, ScpExplorer->LocalLocalCopyCommand(foMove, osOther, false, ShortCutFlag))
     // local focused operation
     EXE(LocalCopyFocusedAction, ScpExplorer->ExecuteCopyOperationCommand(osLocal, true, ShortCutFlag))
     EXE(LocalCopyFocusedQueueAction, ScpExplorer->ExecuteCopyOperationCommand(osLocal, true, cocQueue))
     EXE(LocalCopyFocusedNonQueueAction, ScpExplorer->ExecuteCopyOperationCommand(osLocal, true, cocNonQueue))
     EXE(LocalMoveFocusedAction, ScpExplorer->ExecuteFileOperationCommand(foMove, osLocal, true))
-    EXE(LocalLocalCopyFocusedAction, ScpExplorer->LocalLocalCopy(foCopy, osCurrent, true, false))
-    EXE(LocalLocalMoveFocusedAction, ScpExplorer->LocalLocalCopy(foMove, osCurrent, true, false))
+    EXE(LocalLocalCopyFocusedAction, ScpExplorer->LocalLocalCopyCommand(foCopy, osCurrent, true, ShortCutFlag))
+    EXE(LocalLocalMoveFocusedAction, ScpExplorer->LocalLocalCopyCommand(foMove, osCurrent, true, ShortCutFlag))
     // remote selected operation
     EXE(RemoteCopyAction, ScpExplorer->ExecuteCopyOperationCommand(osRemote, false, ShortCutFlag))
     EXE(RemoteCopyQueueAction, ScpExplorer->ExecuteCopyOperationCommand(osRemote, false, cocQueue))

+ 41 - 18
source/forms/ScpCommander.cpp

@@ -2619,16 +2619,19 @@ void __fastcall TScpCommanderForm::LocalDriveViewNeedHiddenDirectories(TObject *
 }
 //---------------------------------------------------------------------------
 void TScpCommanderForm::LocalLocalCopy(
-  ::TFileOperation Operation, TOperationSide Side, bool OnFocused, bool DebugUsedArg(NoConfirmation))
+  ::TFileOperation Operation, TOperationSide Side, bool OnFocused, bool NoConfirmation, bool DragDrop, unsigned int Flags)
 {
   std::unique_ptr<TFileOperator> FileOperator(new TFileOperator(NULL));
+  bool Move;
   switch (Operation)
   {
     case ::foCopy:
       FileOperator->Operation = Fileoperator::foCopy;
+      Move = false;
       break;
     case ::foMove:
       FileOperator->Operation = Fileoperator::foMove;
+      Move = true;
       break;
     default:
       DebugFail();
@@ -2651,29 +2654,49 @@ void TScpCommanderForm::LocalLocalCopy(
 
   TCustomDirView * SourceDirView = DirView(Side);
   UnicodeString DestinationDir = DirView(OtherSide)->PathName;
-  FileOperator->Flags = FileOperator->Flags << foMultiDestFiles;
   SourceDirView->CreateFileList(OnFocused, true, FileOperator->OperandFrom);
-  for (int Index = 0; Index < FileOperator->OperandFrom->Count; Index++)
-  {
-    UnicodeString SourcePath = FileOperator->OperandFrom->Strings[Index];
-    UnicodeString DestinationPath = TPath::Combine(DestinationDir, TPath::GetFileName(SourcePath));
-    FileOperator->OperandTo->Add(DestinationPath);
-  }
 
-  SourceDirView->ClearSelection();
+  int OutputOptions =
+    FLAGMASK(GetDoNotShowCopyDialogDefault(DragDrop), clooDoNotShowAgain);
+  bool MultipleFiles = (FileOperator->OperandFrom->Count > 1);
+  int Options =
+    FLAGMASK(FLAGSET(Flags, cocShortCutHint), cloShortCutHint) |
+    FLAGMASK(MultipleFiles, cloMultipleFiles);
+  UnicodeString FileMask = AnyMask;
 
-  {
-    TAutoBatch AutoBatch(this);
-    FileOperator->Execute();
-  }
+  bool Confirmed =
+    NoConfirmation ||
+    DoCopyLocalDialog(Move, Options, DestinationDir, FileMask, OutputOptions);
 
-  ReloadLocalDirectory(DestinationDir);
-  if (Operation == ::foMove)
+  if (Confirmed)
   {
-    UnicodeString SourceDir = SourceDirView->PathName;
-    if (!SamePaths(SourceDir, DestinationDir))
+    HandleDoNotShowCopyDialogAgain(DragDrop, FLAGSET(OutputOptions, clooDoNotShowAgain));
+
+    FileOperator->Flags = FileOperator->Flags << foMultiDestFiles;
+    for (int Index = 0; Index < FileOperator->OperandFrom->Count; Index++)
+    {
+      UnicodeString SourcePath = FileOperator->OperandFrom->Strings[Index];
+      UnicodeString FileName = TPath::GetFileName(SourcePath);
+      FileName = MaskFileName(FileName, FileMask);
+      UnicodeString DestinationPath = TPath::Combine(DestinationDir, FileName);
+      FileOperator->OperandTo->Add(DestinationPath);
+    }
+
+    SourceDirView->ClearSelection();
+
     {
-      ReloadLocalDirectory(SourceDir);
+      TAutoBatch AutoBatch(this);
+      FileOperator->Execute();
+    }
+
+    ReloadLocalDirectory(DestinationDir);
+    if (Operation == ::foMove)
+    {
+      UnicodeString SourceDir = SourceDirView->PathName;
+      if (!SamePaths(SourceDir, DestinationDir))
+      {
+        ReloadLocalDirectory(SourceDir);
+      }
     }
   }
 }

+ 2 - 1
source/forms/ScpCommander.h

@@ -649,7 +649,8 @@ public:
   virtual void __fastcall BrowseFile();
   virtual bool IsSideLocalBrowser(TOperationSide Side);
   virtual bool IsLocalBrowserMode();
-  virtual void LocalLocalCopy(::TFileOperation Operation, TOperationSide Side, bool OnFocused, bool NoConfirmation);
+  virtual void LocalLocalCopy(
+    ::TFileOperation Operation, TOperationSide Side, bool OnFocused, bool NoConfirmation, bool DragDrop, unsigned int Flags);
 
   __property double LeftPanelWidth = { read = GetLeftPanelWidth, write = SetLeftPanelWidth };
 };

+ 2 - 0
source/resource/TextsWin.h

@@ -644,6 +644,8 @@
 #define REMOTE_MENU_CAPTION     6035
 #define LEFT_MENU_CAPTION       6036
 #define RIGHT_MENU_CAPTION      6037
+#define COPY_LOCAL_COPY_CAPTION 6038
+#define COPY_LOCAL_MOVE_CAPTION 6039
 
 // 2xxx is reserved for TextsFileZilla.h
 

+ 2 - 0
source/resource/TextsWin1.rc

@@ -649,6 +649,8 @@ BEGIN
         REMOTE_MENU_CAPTION, "&Remote"
         LEFT_MENU_CAPTION, "&Left"
         RIGHT_MENU_CAPTION, "&Right"
+        COPY_LOCAL_COPY_CAPTION, "Copy"
+        COPY_LOCAL_MOVE_CAPTION, "Move"
 
         WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
         WINSCP_COPYRIGHT, "Copyright © 2000-2020 Martin Prikryl"

+ 10 - 0
source/windows/WinInterface.h

@@ -9,6 +9,7 @@
 #include <Terminal.h>
 #include <SynchronizeController.h>
 #include <Script.h>
+#include "HistoryComboBox.hpp"
 
 #ifdef LOCALINTERFACE
 #include <LocalInterface.h>
@@ -223,6 +224,15 @@ bool __fastcall DoCopyDialog(
   bool ToRemote, bool Move, TStrings * FileList, UnicodeString & TargetDirectory,
   TGUICopyParamType * Params, int Options, int CopyParamAttrs,
   TSessionData * SessionData, int * OutputOptions, int AutoSubmit);
+bool CopyDialogValidateLocalDirectory(const UnicodeString & Directory, THistoryComboBox * DirectoryEdit);
+bool CopyDialogValidateFileMask(
+  const UnicodeString & FileMask, THistoryComboBox * DirectoryEdit, bool MultipleFiles, bool RemotePaths);
+
+// forms\CopyLocal.cpp
+const cloShortCutHint = 0x01;
+const cloMultipleFiles = 0x02;
+const clooDoNotShowAgain = 0x01;
+bool DoCopyLocalDialog(bool Move, int Options, UnicodeString & TargetDirectory, UnicodeString & FileMask, int & OutputOptions);
 
 // forms\CreateDirectory.cpp
 bool __fastcall DoCreateDirectoryDialog(UnicodeString & Directory,