Browse Source

Found files can be deleted on the Find dialog + Fixing selection management bug when deleting a single item/file in view (could probably manifest when local file was deleted externally)

Source commit: db63d72d979a6adfb9f308f36f933f181ea152e9
Martin Prikryl 9 năm trước cách đây
mục cha
commit
ae83e7e1d4

+ 34 - 14
source/forms/CustomScpExplorer.cpp

@@ -169,6 +169,7 @@ __fastcall TCustomScpExplorerForm::TCustomScpExplorerForm(TComponent* Owner):
   DebugAssert(NonVisualDataModule && !NonVisualDataModule->ScpExplorer);
   NonVisualDataModule->ScpExplorer = this;
   FAutoOperation = false;
+  FOnFileOperationFinished = NULL;
   FForceExecution = false;
   FIgnoreNextDialogChar = 0;
   FErrorList = NULL;
@@ -1418,22 +1419,21 @@ void __fastcall TCustomScpExplorerForm::DoOperationFinished(
         Visible && (Operation != foCalculateSize) &&
         (Operation != foGetProperties) && (Operation != foCalculateChecksum))
     {
-      TCustomDirView * DView = DirView(Side);
-      UnicodeString FileNameOnly = ExtractFileName(FileName, (Side == osRemote));
-      TListItem *Item = DView->FindFileItem(FileNameOnly);
-      // this can happen when local drive is unplugged in the middle of the operation
-      if (Item != NULL)
+      if (FOnFileOperationFinished != NULL)
       {
-        if (Success) Item->Selected = false;
-        if (DView->ViewStyle == vsReport)
+        FOnFileOperationFinished(FileName, Success);
+      }
+      else
+      {
+        TCustomDirView * DView = DirView(Side);
+        UnicodeString FileNameOnly = ExtractFileName(FileName, (Side == osRemote));
+        TListItem *Item = DView->FindFileItem(FileNameOnly);
+        // this can happen when local drive is unplugged in the middle of the operation
+        if (Item != NULL)
         {
-          TRect DisplayRect = Item->DisplayRect(drBounds);
-          if (DisplayRect.Bottom > DView->ClientHeight)
-          {
-            DView->Scroll(0, Item->Top - DView->TopItem->Top);
-          }
+          if (Success) Item->Selected = false;
+          DView->MakeProgressVisible(Item);
         }
-        Item->MakeVisible(false);
       }
     }
 
@@ -8685,10 +8685,30 @@ void __fastcall TCustomScpExplorerForm::DoFocusRemotePath(TTerminal * ATerminal,
   }
 }
 //---------------------------------------------------------------------------
+void __fastcall TCustomScpExplorerForm::DoDeleteFoundFiles(
+  TTerminal * ATerminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished)
+{
+  if (!NonVisualDataModule->Busy)
+  {
+    TTerminalManager::Instance()->ActiveTerminal = ATerminal;
+
+    DebugAssert(FOnFileOperationFinished == NULL);
+    FOnFileOperationFinished = OnFileOperationFinished;
+    try
+    {
+      ExecuteFileOperation(foDelete, osRemote, FileList, false, NULL);
+    }
+    __finally
+    {
+      FOnFileOperationFinished = NULL;
+    }
+  }
+}
+//---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::RemoteFindFiles()
 {
   FFileFindTerminal = Terminal;
-  ShowFileFindDialog(Terminal, RemoteDirView->Path, DoFindFiles, DoFocusRemotePath);
+  ShowFileFindDialog(Terminal, RemoteDirView->Path, DoFindFiles, DoFocusRemotePath, DoDeleteFoundFiles);
 }
 //---------------------------------------------------------------------------
 void __fastcall TCustomScpExplorerForm::UpdateTaskbarList(ITaskbarList3 * TaskbarList)

+ 2 - 0
source/forms/CustomScpExplorer.h

@@ -198,6 +198,7 @@ private:
   bool FQueueItemInvalidated;
   bool FFormRestored;
   bool FAutoOperation;
+  TFileOperationFinishedEvent FOnFileOperationFinished;
   bool FForceExecution;
   unsigned short FIgnoreNextDialogChar;
   TStringList * FErrorList;
@@ -520,6 +521,7 @@ protected:
   void __fastcall DoFindFiles(TTerminal * Terminal, UnicodeString Directory, const TFileMasks & FileMask,
     TFileFoundEvent OnFileFound, TFindingFileEvent OnFindingFile);
   virtual void __fastcall DoFocusRemotePath(TTerminal * Terminal, const UnicodeString & Path);
+  void __fastcall DoDeleteFoundFiles(TTerminal * Terminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished);
   bool __fastcall ExecuteFileOperation(TFileOperation Operation, TOperationSide Side,
     bool OnFocused, bool NoConfirmation = false, void * Param = NULL);
   void __fastcall UpdateCopyParamCounters(const TCopyParamType & CopyParam);

+ 80 - 12
source/forms/FileFind.cpp

@@ -25,13 +25,13 @@
 TFileFindDialog * FileFindDialog = NULL;
 //---------------------------------------------------------------------------
 void __fastcall ShowFileFindDialog(
-  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile)
+  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles)
 {
   if (FileFindDialog == NULL)
   {
     FileFindDialog = new TFileFindDialog(Application);
   }
-  FileFindDialog->Init(Terminal, Directory, OnFind, OnFocusFile);
+  FileFindDialog->Init(Terminal, Directory, OnFind, OnFocusFile, OnDeleteFiles);
   FileFindDialog->Show();
 }
 //---------------------------------------------------------------------------
@@ -39,7 +39,7 @@ void __fastcall HideFileFindDialog()
 {
   if (FileFindDialog != NULL)
   {
-    FileFindDialog->Close();
+    delete FileFindDialog;
   }
 }
 //---------------------------------------------------------------------------
@@ -109,8 +109,11 @@ void __fastcall TFileFindDialog::UpdateControls()
   }
   StartStopButton->Caption = StartStopCaption;
   EnableControl(FilterGroup, !Finding);
-  EnableControl(FocusButton, (FileView->ItemFocused != NULL));
-  EnableControl(CopyButton, (FileView->Items->Count > 0));
+  FocusAction->Enabled = (FileView->ItemFocused != NULL);
+  DeleteAction->Enabled = (FileView->SelCount > 0);
+  CopyAction->Enabled = (FileView->Items->Count > 0);
+  SelectAllAction->Enabled = (FileView->SelCount < FileView->Items->Count);
+
   switch (FState)
   {
     case ffInit:
@@ -141,6 +144,9 @@ void __fastcall TFileFindDialog::UpdateControls()
       DebugFail();
       break;
   }
+
+  FocusButton->Default = FileView->Focused() && (FState != ffInit);
+  StartStopButton->Default = !FocusButton->Default;
 }
 //---------------------------------------------------------------------------
 void __fastcall TFileFindDialog::ControlChange(TObject * /*Sender*/)
@@ -149,7 +155,7 @@ void __fastcall TFileFindDialog::ControlChange(TObject * /*Sender*/)
 }
 //---------------------------------------------------------------------------
 void __fastcall TFileFindDialog::Init(
-  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile)
+  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles)
 {
   if (FTerminal != Terminal)
   {
@@ -162,6 +168,7 @@ void __fastcall TFileFindDialog::Init(
 
   FOnFind = OnFind;
   FOnFocusFile = OnFocusFile;
+  FOnDeleteFiles = OnDeleteFiles;
 
   MaskEdit->Text = WinConfiguration->SelectMask;
   RemoteDirectoryEdit->Text = UnixExcludeTrailingBackslash(Directory);
@@ -174,14 +181,18 @@ void __fastcall TFileFindDialog::CreateParams(TCreateParams & Params)
   Params.WndParent = GetDesktopWindow();
 }
 //---------------------------------------------------------------------------
+void __fastcall TFileFindDialog::ClearItem(TListItem * Item)
+{
+  TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
+  Item->Data = NULL;
+  delete File;
+}
+//---------------------------------------------------------------------------
 void __fastcall TFileFindDialog::Clear()
 {
   for (int Index = 0; Index < FileView->Items->Count; Index++)
   {
-    TListItem * Item = FileView->Items->Item[Index];
-    TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
-    Item->Data = NULL;
-    delete File;
+    ClearItem(FileView->Items->Item[Index]);
   }
 
   FileView->Items->Clear();
@@ -456,7 +467,7 @@ void __fastcall TFileFindDialog::FileViewDblClick(TObject * /*Sender*/)
   }
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileFindDialog::FocusButtonClick(TObject * /*Sender*/)
+void __fastcall TFileFindDialog::FocusActionExecute(TObject * /*Sender*/)
 {
   FocusFile();
 }
@@ -489,7 +500,7 @@ void __fastcall TFileFindDialog::CopyToClipboard()
   ::CopyToClipboard(Strings.get());
 }
 //---------------------------------------------------------------------------
-void __fastcall TFileFindDialog::CopyButtonClick(TObject * /*Sender*/)
+void __fastcall TFileFindDialog::CopyActionExecute(TObject * /*Sender*/)
 {
   CopyToClipboard();
 }
@@ -500,3 +511,60 @@ void __fastcall TFileFindDialog::FormClose(TObject * /*Sender*/, TCloseAction &
   Action = caFree;
 }
 //---------------------------------------------------------------------------
+void __fastcall TFileFindDialog::FileViewContextPopup(TObject * Sender, TPoint & MousePos, bool & Handled)
+{
+  // to update source popup menu before TBX menu is created
+  UpdateControls();
+  MenuPopup(Sender, MousePos, Handled);
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileFindDialog::FileDeleteFinished(const UnicodeString & FileName, bool Success)
+{
+  TFileItemMap::iterator I = FFileItemMap.find(FileName);
+
+  if (DebugAlwaysTrue(I != FFileItemMap.end()))
+  {
+    TListItem * Item = I->second;
+    FileView->MakeProgressVisible(Item);
+    if (Success)
+    {
+      ClearItem(Item);
+      Item->Delete();
+    }
+
+    FFileItemMap.erase(I);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileFindDialog::DeleteActionExecute(TObject * /*Sender*/)
+{
+  std::unique_ptr<TStrings> FileList(new TStringList());
+
+  DebugAssert(FFileItemMap.empty());
+  TListItem * Item = FileView->Selected;
+  while (Item != NULL)
+  {
+    TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
+    FileList->AddObject(File->FullFileName, File);
+    FFileItemMap.insert(std::make_pair(File->FullFileName, Item));
+    Item = FileView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
+  }
+
+  try
+  {
+    FOnDeleteFiles(FTerminal, FileList.get(), FileDeleteFinished);
+  }
+  __finally
+  {
+    // can be non-empty only when not all files were deleted
+    FFileItemMap.clear();
+  }
+
+  UpdateControls();
+}
+//---------------------------------------------------------------------------
+void __fastcall TFileFindDialog::SelectAllActionExecute(TObject * /*Sender*/)
+{
+  FileView->SelectAll(smAll);
+}
+//---------------------------------------------------------------------------

+ 81 - 20
source/forms/FileFind.dfm

@@ -1371,13 +1371,13 @@ object FileFindDialog: TFileFindDialog
   object FilterGroup: TGroupBox
     Left = 8
     Top = 6
-    Width = 461
+    Width = 434
     Height = 127
     Anchors = [akLeft, akTop, akRight]
     Caption = 'Filter'
     TabOrder = 0
     DesignSize = (
-      461
+      434
       127)
     object MaskLabel: TLabel
       Left = 49
@@ -1404,7 +1404,7 @@ object FileFindDialog: TFileFindDialog
     object RemoteDirectoryEdit: THistoryComboBox
       Left = 49
       Top = 87
-      Width = 401
+      Width = 374
       Height = 21
       AutoComplete = False
       Anchors = [akLeft, akTop, akRight]
@@ -1416,7 +1416,7 @@ object FileFindDialog: TFileFindDialog
     object MaskEdit: THistoryComboBox
       Left = 49
       Top = 36
-      Width = 315
+      Width = 288
       Height = 21
       AutoComplete = False
       Anchors = [akLeft, akTop, akRight]
@@ -1427,7 +1427,7 @@ object FileFindDialog: TFileFindDialog
       OnExit = MaskEditExit
     end
     object MaskHintText: TStaticText
-      Left = 240
+      Left = 213
       Top = 59
       Width = 124
       Height = 17
@@ -1439,7 +1439,7 @@ object FileFindDialog: TFileFindDialog
       TabStop = True
     end
     object MaskButton: TButton
-      Left = 370
+      Left = 343
       Top = 33
       Width = 80
       Height = 25
@@ -1450,9 +1450,9 @@ object FileFindDialog: TFileFindDialog
     end
   end
   object StartStopButton: TButton
-    Left = 476
+    Left = 448
     Top = 11
-    Width = 80
+    Width = 108
     Height = 25
     Anchors = [akTop, akRight]
     Caption = '&StartX'
@@ -1461,9 +1461,9 @@ object FileFindDialog: TFileFindDialog
     OnClick = StartStopButtonClick
   end
   object HelpButton: TButton
-    Left = 476
+    Left = 448
     Top = 42
-    Width = 80
+    Width = 108
     Height = 25
     Anchors = [akTop, akRight]
     Caption = '&Help'
@@ -1473,16 +1473,19 @@ object FileFindDialog: TFileFindDialog
   object FileView: TIEListView
     Left = 8
     Top = 142
-    Width = 461
+    Width = 434
     Height = 252
     Anchors = [akLeft, akTop, akRight, akBottom]
     ColumnClick = False
     FullDrag = True
     ReadOnly = True
     RowSelect = True
+    PopupMenu = FileViewPopupMenu
     TabOrder = 3
     ViewStyle = vsReport
     OnDblClick = FileViewDblClick
+    OnEnter = ControlChange
+    OnExit = ControlChange
     NortonLike = nlOff
     Columns = <
       item
@@ -1502,7 +1505,7 @@ object FileFindDialog: TFileFindDialog
         Caption = 'Changed'
         Width = 90
       end>
-    MultiSelect = False
+    OnContextPopup = FileViewContextPopup
     OnSelectItem = FileViewSelectItem
   end
   object StatusBar: TStatusBar
@@ -1514,23 +1517,81 @@ object FileFindDialog: TFileFindDialog
     SimplePanel = True
   end
   object FocusButton: TButton
-    Left = 476
+    Left = 448
     Top = 142
-    Width = 80
+    Width = 108
     Height = 25
+    Action = FocusAction
     Anchors = [akTop, akRight]
-    Caption = 'Fo&cus'
     TabOrder = 4
-    OnClick = FocusButtonClick
   end
   object CopyButton: TButton
-    Left = 475
+    Left = 448
+    Top = 369
+    Width = 106
+    Height = 25
+    Action = CopyAction
+    Anchors = [akRight, akBottom]
+    TabOrder = 6
+  end
+  object DeleteButton: TButton
+    Left = 448
     Top = 173
-    Width = 80
+    Width = 108
     Height = 25
+    Action = DeleteAction
     Anchors = [akTop, akRight]
-    Caption = '&Copy'
     TabOrder = 5
-    OnClick = CopyButtonClick
+  end
+  object FileViewPopupMenu: TPopupMenu
+    Left = 478
+    Top = 237
+    object Focus1: TMenuItem
+      Action = FocusAction
+      Default = True
+    end
+    object N1: TMenuItem
+      Caption = '-'
+    end
+    object Delete1: TMenuItem
+      Action = DeleteAction
+    end
+    object N2: TMenuItem
+      Caption = '-'
+    end
+    object SelectAllItem: TMenuItem
+      Action = SelectAllAction
+    end
+    object N3: TMenuItem
+      Caption = '-'
+    end
+    object CopyResults1: TMenuItem
+      Action = CopyAction
+    end
+  end
+  object ActionList: TActionList
+    Left = 478
+    Top = 293
+    object DeleteAction: TAction
+      Caption = '&Delete'
+      SecondaryShortCuts.Strings = (
+        'F8')
+      ShortCut = 46
+      OnExecute = DeleteActionExecute
+    end
+    object FocusAction: TAction
+      Caption = '&Focus'
+      OnExecute = FocusActionExecute
+    end
+    object SelectAllAction: TAction
+      Caption = 'Select &All'
+      ShortCut = 16449
+      OnExecute = SelectAllActionExecute
+    end
+    object CopyAction: TAction
+      Caption = '&Copy Results'
+      ShortCut = 16451
+      OnExecute = CopyActionExecute
+    end
   end
 end

+ 28 - 3
source/forms/FileFind.h

@@ -17,6 +17,9 @@
 #include <Vcl.Imaging.pngimage.hpp>
 #include <Vcl.ImgList.hpp>
 #include "PngImageList.hpp"
+#include <System.Actions.hpp>
+#include <Vcl.ActnList.hpp>
+#include <Vcl.Menus.hpp>
 //---------------------------------------------------------------------------
 class TFileFindDialog : public TForm
 {
@@ -35,6 +38,20 @@ __published:
   TButton *MaskButton;
   TPaintBox *AnimationPaintBox;
   TButton *CopyButton;
+  TButton *DeleteButton;
+  TPopupMenu *FileViewPopupMenu;
+  TMenuItem *N2;
+  TMenuItem *SelectAllItem;
+  TActionList *ActionList;
+  TAction *SelectAllAction;
+  TAction *DeleteAction;
+  TAction *FocusAction;
+  TAction *CopyAction;
+  TMenuItem *Focus1;
+  TMenuItem *Delete1;
+  TMenuItem *N1;
+  TMenuItem *N3;
+  TMenuItem *CopyResults1;
   void __fastcall ControlChange(TObject *Sender);
   void __fastcall StartStopButtonClick(TObject *Sender);
   void __fastcall StopButtonClick(TObject *Sender);
@@ -45,19 +62,22 @@ __published:
           TShiftState Shift);
   void __fastcall MaskEditExit(TObject *Sender);
   void __fastcall FileViewDblClick(TObject *Sender);
-  void __fastcall FocusButtonClick(TObject *Sender);
   void __fastcall FileViewSelectItem(TObject *Sender, TListItem *Item,
           bool Selected);
   void __fastcall MaskButtonClick(TObject *Sender);
-  void __fastcall CopyButtonClick(TObject *Sender);
   void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
+  void __fastcall FileViewContextPopup(TObject *Sender, TPoint &MousePos, bool &Handled);
+  void __fastcall DeleteActionExecute(TObject *Sender);
+  void __fastcall CopyActionExecute(TObject *Sender);
+  void __fastcall FocusActionExecute(TObject *Sender);
+  void __fastcall SelectAllActionExecute(TObject *Sender);
 
 public:
   __fastcall TFileFindDialog(TComponent * Owner);
   virtual __fastcall ~TFileFindDialog();
 
   void __fastcall Init(
-    TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile);
+    TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles);
 
 protected:
   void __fastcall Clear();
@@ -81,9 +101,12 @@ private:
   UnicodeString FWindowParams;
   TFindEvent FOnFind;
   TFocusFileEvent FOnFocusFile;
+  TDeleteFilesEvent FOnDeleteFiles;
   TImageList * FSystemImageList;
   TFrameAnimation FFrameAnimation;
   UnicodeString FFocusPath;
+  typedef std::map<UnicodeString, TListItem *> TFileItemMap;
+  TFileItemMap FFileItemMap;
 
   void __fastcall FileFound(TTerminal * Terminal,
     const UnicodeString FileName, const TRemoteFile * File, bool & Cancel);
@@ -93,6 +116,8 @@ private:
   void __fastcall FocusFile();
   void __fastcall DoFocusFile(const UnicodeString & Path);
   void __fastcall CMDialogKey(TWMKeyDown & Message);
+  void __fastcall ClearItem(TListItem * Item);
+  void __fastcall FileDeleteFinished(const UnicodeString & FileName, bool Success);
 };
 //---------------------------------------------------------------------------
 #endif

+ 34 - 2
source/packages/my/NortonLikeListView.pas

@@ -89,6 +89,7 @@ type
     procedure SelectCurrentItem(FocusNext: Boolean);
     function GetNextItem(StartItem: TListItem; Direction: TSearchDirection;
       States: TItemStates): TListItem;
+    procedure MakeProgressVisible(Item: TListItem);
 
     property ColProperties: TCustomListViewColProperties read FColProperties write FColProperties stored False;
 
@@ -216,10 +217,24 @@ begin
 end;
 
 procedure TCustomNortonLikeListView.Delete(Item: TListItem);
+var
+  Index: Integer;
 begin
-  if (FLastDeletedItem <> Item) and Item.Selected then
+  if FLastDeletedItem <> Item then
   begin
-    ItemUnselected(Item, -1);
+    Index := Item.Index;
+
+    if Item.Selected then
+      ItemUnselected(Item, Index);
+
+    if FManageSelection then
+    begin
+      if (FLastSelected >= 0) and (Index <= FLastSelected) then
+        Dec(FLastSelected);
+
+      if (FFirstSelected >= 0) and (Index <= FFirstSelected) then
+        Dec(FFirstSelected);
+    end;
   end;
   FLastDeletedItem := Item;
   inherited;
@@ -961,4 +976,21 @@ begin
     Message.Result := 1;
 end;
 
+procedure TCustomNortonLikeListView.MakeProgressVisible(Item: TListItem);
+var
+  DisplayRect: TRect;
+begin
+  if ViewStyle = vsReport then
+  begin
+    DisplayRect := Item.DisplayRect(drBounds);
+
+    if DisplayRect.Bottom > ClientHeight then
+    begin
+      Scroll(0, Item.Top - TopItem.Top);
+    end;
+  end;
+
+  Item.MakeVisible(False);
+end;
+
 end.

+ 5 - 1
source/windows/WinInterface.h

@@ -416,8 +416,12 @@ typedef void __fastcall (__closure *TFindEvent)
    TFileFoundEvent OnFileFound, TFindingFileEvent OnFindingFile);
 typedef void __fastcall (__closure *TFocusFileEvent)
   (TTerminal * Terminal, const UnicodeString & Path);
+typedef void __fastcall (__closure *TFileOperationFinishedEvent)
+  (const UnicodeString & FileName, bool Success);
+typedef void __fastcall (__closure *TDeleteFilesEvent)
+  (TTerminal * Terminal, TStrings * FileList, TFileOperationFinishedEvent OnFileOperationFinished);
 void __fastcall ShowFileFindDialog(
-  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile);
+  TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles);
 void __fastcall HideFileFindDialog();
 
 // forms\GenerateUrl.cpp