FileFind.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include <WinInterface.h>
  6. #include <VCLCommon.h>
  7. #include <TextsWin.h>
  8. #include <WinConfiguration.h>
  9. #include <CoreMain.h>
  10. #include <Tools.h>
  11. #include <BaseUtils.hpp>
  12. #include <Terminal.h>
  13. #include "FileFind.h"
  14. //---------------------------------------------------------------------------
  15. #pragma package(smart_init)
  16. #pragma link "HistoryComboBox"
  17. #pragma link "IEListView"
  18. #pragma link "NortonLikeListView"
  19. #pragma link "PngImageList"
  20. #ifndef NO_RESOURCES
  21. #pragma resource "*.dfm"
  22. #endif
  23. //---------------------------------------------------------------------------
  24. TFileFindDialog * FileFindDialog = NULL;
  25. //---------------------------------------------------------------------------
  26. void __fastcall ShowFileFindDialog(
  27. TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles)
  28. {
  29. if (FileFindDialog == NULL)
  30. {
  31. FileFindDialog = new TFileFindDialog(Application);
  32. }
  33. FileFindDialog->Init(Terminal, Directory, OnFind, OnFocusFile, OnDeleteFiles);
  34. FileFindDialog->Show();
  35. }
  36. //---------------------------------------------------------------------------
  37. void __fastcall HideFileFindDialog()
  38. {
  39. if (FileFindDialog != NULL)
  40. {
  41. delete FileFindDialog;
  42. }
  43. }
  44. //---------------------------------------------------------------------------
  45. __fastcall TFileFindDialog::TFileFindDialog(TComponent * Owner)
  46. : TForm(Owner)
  47. {
  48. UseSystemSettings(this);
  49. FState = ffInit;
  50. FixComboBoxResizeBug(MaskEdit);
  51. FixComboBoxResizeBug(RemoteDirectoryEdit);
  52. HintLabel(MaskHintText,
  53. FORMAT(L"%s\n \n%s\n \n%s\n \n%s\n \n%s\n \n%s", (LoadStr(MASK_HINT2),
  54. LoadStr(FILE_MASK_EX_HINT), LoadStr(COMBINING_MASKS_HINT),
  55. LoadStr(PATH_MASK_HINT2), LoadStr(DIRECTORY_MASK_HINT),
  56. LoadStr(MASK_HELP))));
  57. FSystemImageList = SharedSystemImageList(false);
  58. FileView->SmallImages = FSystemImageList;
  59. FileView->ShowColumnIcon = false;
  60. UseDesktopFont(FileView);
  61. UseDesktopFont(StatusBar);
  62. FFrameAnimation.Init(AnimationPaintBox, L"Find");
  63. FixFormIcons(this);
  64. }
  65. //---------------------------------------------------------------------------
  66. __fastcall TFileFindDialog::~TFileFindDialog()
  67. {
  68. TFindFileConfiguration FormConfiguration = CustomWinConfiguration->FindFile;
  69. FormConfiguration.ListParams = FileView->ColProperties->ParamsStr;
  70. UnicodeString WindowParams = StoreFormSize(this);
  71. // this is particularly to prevent saving the form state
  72. // for the first time, keeping default positioning by a system
  73. if (!FWindowParams.IsEmpty() && (FWindowParams != WindowParams))
  74. {
  75. FormConfiguration.WindowParams = WindowParams;
  76. }
  77. CustomWinConfiguration->FindFile = FormConfiguration;
  78. Clear();
  79. delete FSystemImageList;
  80. DebugAssert(FileFindDialog == this);
  81. FileFindDialog = NULL;
  82. }
  83. //---------------------------------------------------------------------------
  84. bool __fastcall TFileFindDialog::IsFinding()
  85. {
  86. return (FState == ffFinding) || (FState == ffAborting);
  87. }
  88. //---------------------------------------------------------------------------
  89. void __fastcall TFileFindDialog::UpdateControls()
  90. {
  91. bool Finding = IsFinding();
  92. Caption = FORMAT("%s - %s", (LoadStr(Finding ? FIND_FILE_FINDING : FIND_FILE_TITLE), FTerminalName));
  93. UnicodeString StartStopCaption;
  94. if (Finding)
  95. {
  96. EnableControl(StartStopButton, true);
  97. StartStopCaption = LoadStr(FIND_FILE_STOP);
  98. }
  99. else
  100. {
  101. EnableControl(StartStopButton, !RemoteDirectoryEdit->Text.IsEmpty());
  102. StartStopCaption = LoadStr(FIND_FILE_START);
  103. }
  104. StartStopButton->Caption = StartStopCaption;
  105. EnableControl(FilterGroup, !Finding);
  106. FocusAction->Enabled = (FileView->ItemFocused != NULL);
  107. DeleteAction->Enabled = (FileView->SelCount > 0);
  108. CopyAction->Enabled = (FileView->Items->Count > 0);
  109. SelectAllAction->Enabled = (FileView->SelCount < FileView->Items->Count);
  110. switch (FState)
  111. {
  112. case ffInit:
  113. StatusBar->SimpleText = L"";
  114. break;
  115. case ffFinding:
  116. case ffAborting:
  117. if (!FFindingInDirectory.IsEmpty())
  118. {
  119. StatusBar->SimpleText = FMTLOAD(FIND_FILE_IN_DIRECTORY, (FFindingInDirectory));
  120. }
  121. else
  122. {
  123. StatusBar->SimpleText = L"";
  124. }
  125. break;
  126. case ffAborted:
  127. StatusBar->SimpleText = LoadStr(FIND_FILE_ABORTED);
  128. break;
  129. case ffDone:
  130. StatusBar->SimpleText = LoadStr(FIND_FILE_DONE);
  131. break;
  132. default:
  133. DebugFail();
  134. break;
  135. }
  136. FocusButton->Default = FileView->Focused() && (FState != ffInit);
  137. StartStopButton->Default = !FocusButton->Default;
  138. }
  139. //---------------------------------------------------------------------------
  140. void __fastcall TFileFindDialog::ControlChange(TObject * /*Sender*/)
  141. {
  142. UpdateControls();
  143. }
  144. //---------------------------------------------------------------------------
  145. void __fastcall TFileFindDialog::Init(
  146. TTerminal * Terminal, UnicodeString Directory, TFindEvent OnFind, TFocusFileEvent OnFocusFile, TDeleteFilesEvent OnDeleteFiles)
  147. {
  148. if (FTerminal != Terminal)
  149. {
  150. FTerminal = Terminal;
  151. FTerminalName = Terminal->SessionData->SessionName;
  152. Clear();
  153. FState = ffInit;
  154. ActiveControl = MaskEdit;
  155. }
  156. FOnFind = OnFind;
  157. FOnFocusFile = OnFocusFile;
  158. FOnDeleteFiles = OnDeleteFiles;
  159. MaskEdit->Text = WinConfiguration->SelectMask;
  160. RemoteDirectoryEdit->Text = UnixExcludeTrailingBackslash(Directory);
  161. UpdateControls();
  162. }
  163. //---------------------------------------------------------------------------
  164. void __fastcall TFileFindDialog::CreateParams(TCreateParams & Params)
  165. {
  166. TForm::CreateParams(Params);
  167. Params.WndParent = GetDesktopWindow();
  168. }
  169. //---------------------------------------------------------------------------
  170. void __fastcall TFileFindDialog::ClearItem(TListItem * Item)
  171. {
  172. TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
  173. Item->Data = NULL;
  174. delete File;
  175. }
  176. //---------------------------------------------------------------------------
  177. void __fastcall TFileFindDialog::Clear()
  178. {
  179. for (int Index = 0; Index < FileView->Items->Count; Index++)
  180. {
  181. ClearItem(FileView->Items->Item[Index]);
  182. }
  183. FileView->Items->Clear();
  184. }
  185. //---------------------------------------------------------------------------
  186. void __fastcall TFileFindDialog::Start()
  187. {
  188. if (MaskEdit->Focused())
  189. {
  190. MaskEditExit(NULL);
  191. }
  192. RemoteDirectoryEdit->SaveToHistory();
  193. CustomWinConfiguration->History[L"RemoteDirectory"] = RemoteDirectoryEdit->Items;
  194. MaskEdit->SaveToHistory();
  195. WinConfiguration->History[L"Mask"] = MaskEdit->Items;
  196. WinConfiguration->SelectMask = MaskEdit->Text;
  197. DebugAssert(FState != ffFinding);
  198. FState = ffFinding;
  199. try
  200. {
  201. FFrameAnimation.Start();
  202. UpdateControls();
  203. Repaint();
  204. TOperationVisualizer Visualizer;
  205. DebugAssert(FOnFind != NULL);
  206. UnicodeString Directory = UnixExcludeTrailingBackslash(RemoteDirectoryEdit->Text);
  207. FDirectory = Directory;
  208. if (FDirectory == ROOTDIRECTORY)
  209. {
  210. FDirectory = UnicodeString();
  211. }
  212. FOnFind(FTerminal, Directory, MaskEdit->Text, FileFound, FindingFile);
  213. }
  214. __finally
  215. {
  216. FFindingInDirectory = L"";
  217. if (FState == ffFinding)
  218. {
  219. FState = ffDone;
  220. }
  221. if (FState == ffAborting)
  222. {
  223. FState = ffAborted;
  224. }
  225. FFrameAnimation.Stop();
  226. if (WindowState == wsMinimized)
  227. {
  228. ShowNotification(
  229. NULL, MainInstructions(LoadStr(BALLOON_OPERATION_COMPLETE)),
  230. qtInformation);
  231. }
  232. if (!FFocusPath.IsEmpty())
  233. {
  234. UnicodeString FocusPath = FFocusPath;
  235. FFocusPath = L"";
  236. DoFocusFile(FocusPath);
  237. }
  238. UpdateControls();
  239. }
  240. }
  241. //---------------------------------------------------------------------------
  242. void __fastcall TFileFindDialog::FileFound(TTerminal * /*Terminal*/,
  243. const UnicodeString FileName, const TRemoteFile * AFile, bool & Cancel)
  244. {
  245. TListItem * Item = FileView->Items->Add();
  246. TRemoteFile * File = AFile->Duplicate(true);
  247. Item->Data = File;
  248. Item->ImageIndex = File->IconIndex;
  249. UnicodeString Caption = File->FileName;
  250. if (File->IsDirectory)
  251. {
  252. Caption = UnixIncludeTrailingBackslash(Caption);
  253. }
  254. Item->Caption = Caption;
  255. UnicodeString Directory = UnixExtractFilePath(File->FullFileName);
  256. if (AnsiSameText(FDirectory, Directory.SubString(1, FDirectory.Length())))
  257. {
  258. Directory = L"." + Directory.SubString(FDirectory.Length() + 1, Directory.Length() - FDirectory.Length());
  259. }
  260. else
  261. {
  262. DebugFail();
  263. }
  264. Item->SubItems->Add(Directory);
  265. if (File->IsDirectory)
  266. {
  267. Item->SubItems->Add(L"");
  268. }
  269. else
  270. {
  271. Item->SubItems->Add(
  272. FormatPanelBytes(File->Size, WinConfiguration->FormatSizeBytes));
  273. }
  274. Item->SubItems->Add(UserModificationStr(File->Modification, File->ModificationFmt));
  275. UpdateControls();
  276. Cancel = (FState == ffAborting);
  277. Application->ProcessMessages();
  278. }
  279. //---------------------------------------------------------------------------
  280. void __fastcall TFileFindDialog::FindingFile(TTerminal * /*Terminal*/,
  281. const UnicodeString Directory, bool & Cancel)
  282. {
  283. if (!Directory.IsEmpty() && (FFindingInDirectory != Directory))
  284. {
  285. FFindingInDirectory = Directory;
  286. UpdateControls();
  287. }
  288. Cancel = (FState == ffAborting);
  289. Application->ProcessMessages();
  290. }
  291. //---------------------------------------------------------------------------
  292. void __fastcall TFileFindDialog::StartStopButtonClick(TObject * /*Sender*/)
  293. {
  294. if (IsFinding())
  295. {
  296. Stop();
  297. }
  298. else
  299. {
  300. Clear();
  301. if (ActiveControl->Parent == FilterGroup)
  302. {
  303. FileView->SetFocus();
  304. }
  305. Start();
  306. }
  307. }
  308. //---------------------------------------------------------------------------
  309. void __fastcall TFileFindDialog::StopButtonClick(TObject * /*Sender*/)
  310. {
  311. Stop();
  312. }
  313. //---------------------------------------------------------------------------
  314. void __fastcall TFileFindDialog::Stop()
  315. {
  316. FState = ffAborting;
  317. UpdateControls();
  318. }
  319. //---------------------------------------------------------------------------
  320. void __fastcall TFileFindDialog::FormShow(TObject * /*Sender*/)
  321. {
  322. InstallPathWordBreakProc(MaskEdit);
  323. InstallPathWordBreakProc(RemoteDirectoryEdit);
  324. // have to set history after value, to prevent autocompletition
  325. MaskEdit->Items = WinConfiguration->History[L"Mask"];
  326. RemoteDirectoryEdit->Items = CustomWinConfiguration->History[L"RemoteDirectory"];
  327. UpdateFormPosition(this, poOwnerFormCenter);
  328. RestoreFormSize(CustomWinConfiguration->FindFile.WindowParams, this);
  329. FileView->ColProperties->ParamsStr = CustomWinConfiguration->FindFile.ListParams;
  330. DebugAssert(FWindowParams.IsEmpty());
  331. if (FWindowParams.IsEmpty())
  332. {
  333. FWindowParams = StoreFormSize(this);
  334. }
  335. UpdateControls();
  336. }
  337. //---------------------------------------------------------------------------
  338. bool __fastcall TFileFindDialog::StopIfFinding()
  339. {
  340. bool Result = IsFinding();
  341. if (Result)
  342. {
  343. Stop();
  344. }
  345. return Result;
  346. }
  347. //---------------------------------------------------------------------------
  348. void __fastcall TFileFindDialog::FormCloseQuery(TObject * /*Sender*/,
  349. bool & /*CanClose*/)
  350. {
  351. StopIfFinding();
  352. }
  353. //---------------------------------------------------------------------------
  354. void __fastcall TFileFindDialog::HelpButtonClick(TObject * /*Sender*/)
  355. {
  356. FormHelp(this);
  357. }
  358. //---------------------------------------------------------------------------
  359. void __fastcall TFileFindDialog::Dispatch(void * Message)
  360. {
  361. TMessage * M = reinterpret_cast<TMessage*>(Message);
  362. if (M->Msg == CM_DIALOGKEY)
  363. {
  364. CMDialogKey(*((TWMKeyDown *)Message));
  365. }
  366. else
  367. {
  368. TForm::Dispatch(Message);
  369. }
  370. }
  371. //---------------------------------------------------------------------------
  372. void __fastcall TFileFindDialog::CMDialogKey(TWMKeyDown & Message)
  373. {
  374. // Handling VK_ESCAPE in FormKeyDown causes a beep when any "edit" has focus.
  375. // Moreover FormKeyDown is called when the the "esc" is pressed while drop down list is unrolled.
  376. if (Message.CharCode == VK_ESCAPE)
  377. {
  378. Close();
  379. Message.Result = 1;
  380. return;
  381. }
  382. TForm::Dispatch(&Message);
  383. }
  384. //---------------------------------------------------------------------------
  385. void __fastcall TFileFindDialog::FormKeyDown(TObject * /*Sender*/, WORD & Key,
  386. TShiftState Shift)
  387. {
  388. if ((Key == L'C') && Shift.Contains(ssCtrl) &&
  389. (dynamic_cast<TCustomCombo *>(ActiveControl) == NULL))
  390. {
  391. CopyToClipboard();
  392. Key = 0;
  393. }
  394. else if ((Key == VK_F10) && Shift.Empty())
  395. {
  396. Key = 0;
  397. StopIfFinding();
  398. Close();
  399. }
  400. }
  401. //---------------------------------------------------------------------------
  402. void __fastcall TFileFindDialog::MaskEditExit(TObject * /*Sender*/)
  403. {
  404. ValidateMaskEdit(MaskEdit);
  405. }
  406. //---------------------------------------------------------------------------
  407. void __fastcall TFileFindDialog::DoFocusFile(const UnicodeString & Path)
  408. {
  409. FOnFocusFile(FTerminal, Path);
  410. }
  411. //---------------------------------------------------------------------------
  412. void __fastcall TFileFindDialog::FocusFile()
  413. {
  414. UnicodeString Path = static_cast<TRemoteFile *>(FileView->ItemFocused->Data)->FullFileName;
  415. // To make focussing directories work,
  416. // otherwise it would try to focus "empty-named file" in the Path
  417. Path = UnixExcludeTrailingBackslash(Path);
  418. if (StopIfFinding())
  419. {
  420. FFocusPath = Path;
  421. }
  422. else
  423. {
  424. DoFocusFile(Path);
  425. }
  426. }
  427. //---------------------------------------------------------------------------
  428. void __fastcall TFileFindDialog::FileViewDblClick(TObject * /*Sender*/)
  429. {
  430. if (FileView->ItemFocused != NULL)
  431. {
  432. FocusFile();
  433. }
  434. }
  435. //---------------------------------------------------------------------------
  436. void __fastcall TFileFindDialog::FocusActionExecute(TObject * /*Sender*/)
  437. {
  438. FocusFile();
  439. }
  440. //---------------------------------------------------------------------------
  441. void __fastcall TFileFindDialog::FileViewSelectItem(TObject * /*Sender*/,
  442. TListItem * /*Item*/, bool /*Selected*/)
  443. {
  444. UpdateControls();
  445. }
  446. //---------------------------------------------------------------------------
  447. void __fastcall TFileFindDialog::MaskButtonClick(TObject * /*Sender*/)
  448. {
  449. TFileMasks Masks = MaskEdit->Text;
  450. if (DoEditMaskDialog(Masks))
  451. {
  452. MaskEdit->Text = Masks.Masks;
  453. }
  454. }
  455. //---------------------------------------------------------------------------
  456. void __fastcall TFileFindDialog::CopyToClipboard()
  457. {
  458. TInstantOperationVisualizer Visualizer;
  459. std::unique_ptr<TStrings> Strings(new TStringList());
  460. for (int Index = 0; Index < FileView->Items->Count; Index++)
  461. {
  462. TListItem * Item = FileView->Items->Item[Index];
  463. TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
  464. Strings->Add(File->FullFileName);
  465. }
  466. ::CopyToClipboard(Strings.get());
  467. }
  468. //---------------------------------------------------------------------------
  469. void __fastcall TFileFindDialog::CopyActionExecute(TObject * /*Sender*/)
  470. {
  471. CopyToClipboard();
  472. }
  473. //---------------------------------------------------------------------------
  474. void __fastcall TFileFindDialog::FormClose(TObject * /*Sender*/, TCloseAction & Action)
  475. {
  476. StopIfFinding();
  477. Action = caFree;
  478. }
  479. //---------------------------------------------------------------------------
  480. void __fastcall TFileFindDialog::FileViewContextPopup(TObject * Sender, TPoint & MousePos, bool & Handled)
  481. {
  482. // to update source popup menu before TBX menu is created
  483. UpdateControls();
  484. MenuPopup(Sender, MousePos, Handled);
  485. }
  486. //---------------------------------------------------------------------------
  487. void __fastcall TFileFindDialog::FileDeleteFinished(const UnicodeString & FileName, bool Success)
  488. {
  489. TFileItemMap::iterator I = FFileItemMap.find(FileName);
  490. if (DebugAlwaysTrue(I != FFileItemMap.end()))
  491. {
  492. TListItem * Item = I->second;
  493. FileView->MakeProgressVisible(Item);
  494. if (Success)
  495. {
  496. ClearItem(Item);
  497. Item->Delete();
  498. }
  499. FFileItemMap.erase(I);
  500. }
  501. }
  502. //---------------------------------------------------------------------------
  503. void __fastcall TFileFindDialog::DeleteActionExecute(TObject * /*Sender*/)
  504. {
  505. std::unique_ptr<TStrings> FileList(new TStringList());
  506. DebugAssert(FFileItemMap.empty());
  507. TListItem * Item = FileView->Selected;
  508. while (Item != NULL)
  509. {
  510. TRemoteFile * File = static_cast<TRemoteFile *>(Item->Data);
  511. FileList->AddObject(File->FullFileName, File);
  512. FFileItemMap.insert(std::make_pair(File->FullFileName, Item));
  513. Item = FileView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  514. }
  515. try
  516. {
  517. FOnDeleteFiles(FTerminal, FileList.get(), FileDeleteFinished);
  518. }
  519. __finally
  520. {
  521. // can be non-empty only when not all files were deleted
  522. FFileItemMap.clear();
  523. }
  524. UpdateControls();
  525. }
  526. //---------------------------------------------------------------------------
  527. void __fastcall TFileFindDialog::SelectAllActionExecute(TObject * /*Sender*/)
  528. {
  529. FileView->SelectAll(smAll);
  530. }
  531. //---------------------------------------------------------------------------