Synchronize.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include "WinInterface.h"
  6. #include "Synchronize.h"
  7. #include "VCLCommon.h"
  8. #include "CopyParams.h"
  9. #include "Terminal.h"
  10. #include "GUITools.h"
  11. #include <CoreMain.h>
  12. #include <Configuration.h>
  13. #include <TextsWin.h>
  14. #include <HelpWin.h>
  15. #include <CustomWinConfiguration.h>
  16. //---------------------------------------------------------------------------
  17. #pragma package(smart_init)
  18. #pragma link "HistoryComboBox"
  19. #pragma link "GrayedCheckBox"
  20. #pragma resource "*.dfm"
  21. //---------------------------------------------------------------------------
  22. const int WM_USER_STOP = WM_WINSCP_USER + 2;
  23. //---------------------------------------------------------------------------
  24. bool __fastcall DoSynchronizeDialog(TSynchronizeParamType & Params,
  25. const TCopyParamType * CopyParams, TSynchronizeStartStopEvent OnStartStop,
  26. bool & SaveSettings, int Options, int CopyParamAttrs,
  27. TGetSynchronizeOptionsEvent OnGetOptions, bool Start)
  28. {
  29. bool Result;
  30. TSynchronizeDialog * Dialog = new TSynchronizeDialog(Application,
  31. OnStartStop, OnGetOptions, Start);
  32. try
  33. {
  34. Dialog->Options = Options;
  35. Dialog->CopyParamAttrs = CopyParamAttrs;
  36. Dialog->Params = Params;
  37. Dialog->CopyParams = *CopyParams;
  38. Dialog->SaveSettings = SaveSettings;
  39. Result = Dialog->Execute();
  40. if (Result)
  41. {
  42. SaveSettings = Dialog->SaveSettings;
  43. Params = Dialog->Params;
  44. }
  45. }
  46. __finally
  47. {
  48. delete Dialog;
  49. }
  50. return Result;
  51. }
  52. //---------------------------------------------------------------------------
  53. const TSynchronizeDialog::MaxLogItems = 1000;
  54. //---------------------------------------------------------------------------
  55. __fastcall TSynchronizeDialog::TSynchronizeDialog(TComponent * Owner,
  56. TSynchronizeStartStopEvent OnStartStop, TGetSynchronizeOptionsEvent OnGetOptions,
  57. bool StartImmediatelly)
  58. : TForm(Owner)
  59. {
  60. UseSystemSettings(this);
  61. FOptions = 0;
  62. FSynchronizing = false;
  63. FMinimizedByMe = false;
  64. FPresetsMenu = new TPopupMenu(this);
  65. FOnStartStop = OnStartStop;
  66. FOnGetOptions = OnGetOptions;
  67. FSynchronizeOptions = NULL;
  68. FStartImmediatelly = StartImmediatelly;
  69. InstallPathWordBreakProc(LocalDirectoryEdit);
  70. InstallPathWordBreakProc(RemoteDirectoryEdit);
  71. if (!IsGlobalMinimizeHandler())
  72. {
  73. SetGlobalMinimizeHandler(GlobalMinimize);
  74. };
  75. }
  76. //---------------------------------------------------------------------------
  77. __fastcall TSynchronizeDialog::~TSynchronizeDialog()
  78. {
  79. // if application is closing OnCloseQuery might not get called
  80. // (this particularly happens if last terminal is disconnected while dialog is
  81. // open)
  82. if (FSynchronizing)
  83. {
  84. OnlyStop();
  85. }
  86. if (GetGlobalMinimizeHandler() == GlobalMinimize)
  87. {
  88. SetGlobalMinimizeHandler(NULL);
  89. }
  90. delete FSynchronizeOptions;
  91. delete FPresetsMenu;
  92. }
  93. //---------------------------------------------------------------------------
  94. void __fastcall TSynchronizeDialog::UpdateControls()
  95. {
  96. EnableControl(StartButton, !LocalDirectoryEdit->Text.IsEmpty() &&
  97. !RemoteDirectoryEdit->Text.IsEmpty());
  98. TButton * OldButton = FSynchronizing ? StartButton : StopButton;
  99. TButton * NewButton = FSynchronizing ? StopButton : StartButton;
  100. if (!NewButton->Visible || OldButton->Visible)
  101. {
  102. NewButton->Visible = true;
  103. if (OldButton->Focused())
  104. {
  105. NewButton->SetFocus();
  106. }
  107. OldButton->Default = false;
  108. NewButton->Default = true;
  109. OldButton->Visible = false;
  110. // some of the above steps hides accelerators when start button is pressed with mouse
  111. ResetSystemSettings(this);
  112. }
  113. Caption = LoadStr(FSynchronizing ? SYNCHRONIZE_SYCHRONIZING : SYNCHRONIZE_TITLE);
  114. EnableControl(TransferSettingsButton, !FSynchronizing);
  115. CancelButton->Visible = !FSynchronizing || FLAGSET(FOptions, soNoMinimize);
  116. EnableControl(CancelButton, !FSynchronizing);
  117. EnableControl(DirectoriesGroup, !FSynchronizing);
  118. EnableControl(OptionsGroup, !FSynchronizing);
  119. EnableControl(CopyParamGroup, !FSynchronizing);
  120. MinimizeButton->Visible = FSynchronizing && FLAGCLEAR(FOptions, soNoMinimize);
  121. EnableControl(SynchronizeSelectedOnlyCheck,
  122. OptionsGroup->Enabled && FLAGSET(FOptions, soAllowSelectedOnly));
  123. AnsiString InfoStr = CopyParams.GetInfoStr("; ", ActualCopyParamAttrs());
  124. CopyParamLabel->Caption = InfoStr;
  125. CopyParamLabel->Hint = InfoStr;
  126. CopyParamLabel->ShowHint =
  127. (CopyParamLabel->Canvas->TextWidth(InfoStr) > (CopyParamLabel->Width * 3 / 2));
  128. if (LogPanel->Visible != FSynchronizing)
  129. {
  130. if (FSynchronizing)
  131. {
  132. LogPanel->Visible = true;
  133. ClientHeight = ClientHeight + LogPanel->Height;
  134. }
  135. else
  136. {
  137. ClientHeight = ClientHeight - LogPanel->Height;
  138. LogPanel->Visible = false;
  139. }
  140. }
  141. }
  142. //---------------------------------------------------------------------------
  143. void __fastcall TSynchronizeDialog::ControlChange(TObject * /*Sender*/)
  144. {
  145. UpdateControls();
  146. }
  147. //---------------------------------------------------------------------------
  148. bool __fastcall TSynchronizeDialog::Execute()
  149. {
  150. // at start assume that copy param is current preset
  151. FPreset = GUIConfiguration->CopyParamCurrent;
  152. LocalDirectoryEdit->Items = CustomWinConfiguration->History["LocalDirectory"];
  153. RemoteDirectoryEdit->Items = CustomWinConfiguration->History["RemoteDirectory"];
  154. ShowModal();
  155. return true;
  156. }
  157. //---------------------------------------------------------------------------
  158. void __fastcall TSynchronizeDialog::SetParams(const TSynchronizeParamType& value)
  159. {
  160. FParams = value;
  161. RemoteDirectoryEdit->Text = value.RemoteDirectory;
  162. LocalDirectoryEdit->Text = value.LocalDirectory;
  163. SynchronizeDeleteCheck->Checked = FLAGSET(value.Params, spDelete);
  164. SynchronizeExistingOnlyCheck->Checked = FLAGSET(value.Params, spExistingOnly);
  165. SynchronizeSelectedOnlyCheck->Checked = FLAGSET(value.Params, spSelectedOnly);
  166. SynchronizeRecursiveCheck->Checked = FLAGSET(value.Options, soRecurse);
  167. SynchronizeSynchronizeCheck->State =
  168. FLAGSET(value.Options, soSynchronizeAsk) ? cbGrayed :
  169. (FLAGSET(value.Options, soSynchronize) ? cbChecked : cbUnchecked);
  170. }
  171. //---------------------------------------------------------------------------
  172. TSynchronizeParamType __fastcall TSynchronizeDialog::GetParams()
  173. {
  174. TSynchronizeParamType Result = FParams;
  175. Result.RemoteDirectory = RemoteDirectoryEdit->Text;
  176. Result.LocalDirectory = LocalDirectoryEdit->Text;
  177. Result.Params =
  178. (Result.Params & ~(spDelete | spExistingOnly | spSelectedOnly | spTimestamp)) |
  179. FLAGMASK(SynchronizeDeleteCheck->Checked, spDelete) |
  180. FLAGMASK(SynchronizeExistingOnlyCheck->Checked, spExistingOnly) |
  181. FLAGMASK(SynchronizeSelectedOnlyCheck->Checked, spSelectedOnly);
  182. Result.Options =
  183. (Result.Options & ~(soRecurse | soSynchronize | soSynchronizeAsk)) |
  184. FLAGMASK(SynchronizeRecursiveCheck->Checked, soRecurse) |
  185. FLAGMASK(SynchronizeSynchronizeCheck->State == cbChecked, soSynchronize) |
  186. FLAGMASK(SynchronizeSynchronizeCheck->State == cbGrayed, soSynchronizeAsk);
  187. return Result;
  188. }
  189. //---------------------------------------------------------------------------
  190. void __fastcall TSynchronizeDialog::LocalDirectoryBrowseButtonClick(
  191. TObject * /*Sender*/)
  192. {
  193. AnsiString Directory = LocalDirectoryEdit->Text;
  194. if (SelectDirectory(Directory, LoadStr(SELECT_LOCAL_DIRECTORY), false))
  195. {
  196. LocalDirectoryEdit->Text = Directory;
  197. }
  198. }
  199. //---------------------------------------------------------------------------
  200. void __fastcall TSynchronizeDialog::SetOptions(int value)
  201. {
  202. if (Options != value)
  203. {
  204. FOptions = value;
  205. UpdateControls();
  206. }
  207. }
  208. //---------------------------------------------------------------------------
  209. void __fastcall TSynchronizeDialog::TransferSettingsButtonClick(
  210. TObject * /*Sender*/)
  211. {
  212. if (FLAGCLEAR(FOptions, soDoNotUsePresets))
  213. {
  214. CopyParamListPopup(
  215. TransferSettingsButton->ClientToScreen(TPoint(0, TransferSettingsButton->Height)),
  216. FPresetsMenu, FCopyParams, FPreset, CopyParamClick, cplCustomize);
  217. }
  218. else
  219. {
  220. CopyParamGroupDblClick(NULL);
  221. }
  222. }
  223. //---------------------------------------------------------------------------
  224. void __fastcall TSynchronizeDialog::DoStartStop(bool Start, bool Synchronize)
  225. {
  226. if (FOnStartStop)
  227. {
  228. TSynchronizeParamType SParams = GetParams();
  229. SParams.Options =
  230. (SParams.Options & ~(soSynchronize | soSynchronizeAsk)) |
  231. FLAGMASK(Synchronize, soSynchronize);
  232. if (Start)
  233. {
  234. delete FSynchronizeOptions;
  235. FSynchronizeOptions = new TSynchronizeOptions;
  236. FOnGetOptions(SParams.Params, *FSynchronizeOptions);
  237. }
  238. FOnStartStop(this, Start, SParams, CopyParams, FSynchronizeOptions, DoAbort,
  239. NULL, DoLog);
  240. }
  241. }
  242. //---------------------------------------------------------------------------
  243. void __fastcall TSynchronizeDialog::Dispatch(void * Message)
  244. {
  245. assert(Message);
  246. if ((reinterpret_cast<TMessage *>(Message)->Msg == WM_USER_STOP) && FAbort)
  247. {
  248. if (FSynchronizing)
  249. {
  250. Stop();
  251. }
  252. if (FClose)
  253. {
  254. FClose = false;
  255. ModalResult = mrCancel;
  256. }
  257. }
  258. else
  259. {
  260. TForm::Dispatch(Message);
  261. }
  262. }
  263. //---------------------------------------------------------------------------
  264. void __fastcall TSynchronizeDialog::DoAbort(TObject * /*Sender*/, bool Close)
  265. {
  266. FAbort = true;
  267. FClose = Close;
  268. PostMessage(Handle, WM_USER_STOP, 0, 0);
  269. }
  270. //---------------------------------------------------------------------------
  271. void __fastcall TSynchronizeDialog::DoLog(TSynchronizeController * /*Controller*/,
  272. TSynchronizeLogEntry Entry, const AnsiString Message)
  273. {
  274. LogView->Items->BeginUpdate();
  275. try
  276. {
  277. TListItem * Item = LogView->Items->Add();
  278. Item->Caption = Now().TimeString();
  279. Item->SubItems->Add(Message);
  280. Item->MakeVisible(false);
  281. while (LogView->Items->Count > MaxLogItems)
  282. {
  283. LogView->Items->Delete(0);
  284. }
  285. }
  286. __finally
  287. {
  288. LogView->Items->EndUpdate();
  289. if (Entry == slScan)
  290. {
  291. // redraw log before the scanning block update
  292. LogView->Repaint();
  293. }
  294. }
  295. }
  296. //---------------------------------------------------------------------------
  297. void __fastcall TSynchronizeDialog::StartButtonClick(TObject * /*Sender*/)
  298. {
  299. bool Synchronize;
  300. bool Continue = true;
  301. if (SynchronizeSynchronizeCheck->State == cbGrayed)
  302. {
  303. TMessageParams Params(mpNeverAskAgainCheck);
  304. switch (MoreMessageDialog(LoadStr(SYNCHRONISE_BEFORE_KEEPUPTODATE),
  305. NULL, qtConfirmation, qaYes | qaNo | qaCancel, HELP_KEEPUPTODATE_SYNCHRONIZE,
  306. &Params))
  307. {
  308. case qaNeverAskAgain:
  309. SynchronizeSynchronizeCheck->State = cbChecked;
  310. // fall thru
  311. case qaYes:
  312. Synchronize = true;
  313. break;
  314. case qaNo:
  315. Synchronize = false;
  316. break;
  317. default:
  318. case qaCancel:
  319. Continue = false;
  320. break;
  321. };
  322. }
  323. else
  324. {
  325. Synchronize = SynchronizeSynchronizeCheck->Checked;
  326. }
  327. if (Continue)
  328. {
  329. assert(!FSynchronizing);
  330. LocalDirectoryEdit->SaveToHistory();
  331. CustomWinConfiguration->History["LocalDirectory"] = LocalDirectoryEdit->Items;
  332. RemoteDirectoryEdit->SaveToHistory();
  333. CustomWinConfiguration->History["RemoteDirectory"] = RemoteDirectoryEdit->Items;
  334. FSynchronizing = true;
  335. try
  336. {
  337. UpdateControls();
  338. Repaint();
  339. FAbort = false;
  340. DoStartStop(true, Synchronize);
  341. }
  342. catch(...)
  343. {
  344. FSynchronizing = false;
  345. UpdateControls();
  346. throw;
  347. }
  348. }
  349. }
  350. //---------------------------------------------------------------------------
  351. void __fastcall TSynchronizeDialog::StopButtonClick(TObject * /*Sender*/)
  352. {
  353. Stop();
  354. }
  355. //---------------------------------------------------------------------------
  356. void __fastcall TSynchronizeDialog::OnlyStop()
  357. {
  358. FSynchronizing = false;
  359. DoStartStop(false, false);
  360. }
  361. //---------------------------------------------------------------------------
  362. void __fastcall TSynchronizeDialog::Stop()
  363. {
  364. OnlyStop();
  365. UpdateControls();
  366. Repaint();
  367. if (IsIconic(Application->Handle) && FMinimizedByMe)
  368. {
  369. FMinimizedByMe = false;
  370. Application->Restore();
  371. Application->BringToFront();
  372. }
  373. }
  374. //---------------------------------------------------------------------------
  375. void __fastcall TSynchronizeDialog::MinimizeButtonClick(TObject * /*Sender*/)
  376. {
  377. MinimizeApp();
  378. }
  379. //---------------------------------------------------------------------------
  380. void __fastcall TSynchronizeDialog::GlobalMinimize(TObject * /*Sender*/)
  381. {
  382. MinimizeApp();
  383. }
  384. //---------------------------------------------------------------------------
  385. void __fastcall TSynchronizeDialog::MinimizeApp()
  386. {
  387. Application->Minimize();
  388. FMinimizedByMe = true;
  389. }
  390. //---------------------------------------------------------------------------
  391. void __fastcall TSynchronizeDialog::SetSaveSettings(bool value)
  392. {
  393. SaveSettingsCheck->Checked = value;
  394. }
  395. //---------------------------------------------------------------------------
  396. bool __fastcall TSynchronizeDialog::GetSaveSettings()
  397. {
  398. return SaveSettingsCheck->Checked;
  399. }
  400. //---------------------------------------------------------------------------
  401. void __fastcall TSynchronizeDialog::FormShow(TObject * /*Sender*/)
  402. {
  403. ClearLog();
  404. UpdateControls();
  405. if (FStartImmediatelly)
  406. {
  407. StartButtonClick(NULL);
  408. }
  409. }
  410. //---------------------------------------------------------------------------
  411. void __fastcall TSynchronizeDialog::FormCloseQuery(TObject * /*Sender*/,
  412. bool & /*CanClose*/)
  413. {
  414. if (FSynchronizing)
  415. {
  416. Stop();
  417. }
  418. }
  419. //---------------------------------------------------------------------------
  420. TCopyParamType __fastcall TSynchronizeDialog::GetCopyParams()
  421. {
  422. TCopyParamType Result = FCopyParams;
  423. Result.PreserveTime = true;
  424. return Result;
  425. }
  426. //---------------------------------------------------------------------------
  427. void __fastcall TSynchronizeDialog::SetCopyParams(const TCopyParamType & value)
  428. {
  429. FCopyParams = value;
  430. UpdateControls();
  431. }
  432. //---------------------------------------------------------------------------
  433. int __fastcall TSynchronizeDialog::ActualCopyParamAttrs()
  434. {
  435. return FCopyParamAttrs | cpaNoPreserveTime;
  436. }
  437. //---------------------------------------------------------------------------
  438. void __fastcall TSynchronizeDialog::CopyParamClick(TObject * Sender)
  439. {
  440. assert(FLAGCLEAR(FOptions, soDoNotUsePresets));
  441. // PreserveTime is forced for some settings, but avoid hard-setting it until
  442. // user really confirms it on custom dialog
  443. TCopyParamType ACopyParams = CopyParams;
  444. if (CopyParamListPopupClick(Sender, ACopyParams, FPreset,
  445. ActualCopyParamAttrs()))
  446. {
  447. FCopyParams = ACopyParams;
  448. UpdateControls();
  449. }
  450. }
  451. //---------------------------------------------------------------------------
  452. void __fastcall TSynchronizeDialog::CopyParamGroupContextPopup(
  453. TObject * /*Sender*/, TPoint & MousePos, bool & Handled)
  454. {
  455. if (FLAGCLEAR(FOptions, soDoNotUsePresets))
  456. {
  457. // We pass in FCopyParams, although it may not be the exact copy param
  458. // that will be used (because of Preservetime). The reason is to
  459. // display checkbox next to user-selected preset
  460. CopyParamListPopup(CopyParamGroup->ClientToScreen(MousePos), FPresetsMenu,
  461. FCopyParams, FPreset, CopyParamClick, cplCustomize | cplCustomizeDefault);
  462. Handled = true;
  463. }
  464. }
  465. //---------------------------------------------------------------------------
  466. void __fastcall TSynchronizeDialog::CopyParamGroupDblClick(TObject * /*Sender*/)
  467. {
  468. // PreserveTime is forced for some settings, but avoid hard-setting it until
  469. // user really confirms it on cutom dialog
  470. TCopyParamType ACopyParams = CopyParams;
  471. if (DoCopyParamCustomDialog(ACopyParams, ActualCopyParamAttrs()))
  472. {
  473. FCopyParams = ACopyParams;
  474. UpdateControls();
  475. }
  476. }
  477. //---------------------------------------------------------------------------
  478. void __fastcall TSynchronizeDialog::HelpButtonClick(TObject * /*Sender*/)
  479. {
  480. FormHelp(this);
  481. }
  482. //---------------------------------------------------------------------------
  483. void __fastcall TSynchronizeDialog::ClearLog()
  484. {
  485. // TListItems::Clear() does nothing without allocated handle
  486. LogView->HandleNeeded();
  487. LogView->Items->Clear();
  488. }
  489. //---------------------------------------------------------------------------
  490. void __fastcall TSynchronizeDialog::CopyLog()
  491. {
  492. AnsiString Content;
  493. for (int i = 0; i < LogView->Items->Count; i++)
  494. {
  495. TListItem * Item = LogView->Items->Item[i];
  496. Content += Item->Caption + "\t" + Item->SubItems->Strings[0] + "\r\n";
  497. }
  498. CopyToClipboard(Content);
  499. }
  500. //---------------------------------------------------------------------------
  501. void __fastcall TSynchronizeDialog::LogViewKeyDown(TObject * /*Sender*/,
  502. WORD & Key, TShiftState Shift)
  503. {
  504. if (Key == VK_DELETE)
  505. {
  506. ClearLog();
  507. Key = 0;
  508. }
  509. else if ((Key == 'C') && Shift.Contains(ssCtrl) && (LogView->Items->Count > 0))
  510. {
  511. CopyLog();
  512. Key = 0;
  513. }
  514. }
  515. //---------------------------------------------------------------------------
  516. void __fastcall TSynchronizeDialog::FormKeyDown(TObject * /*Sender*/, WORD & Key,
  517. TShiftState /*Shift*/)
  518. {
  519. if ((Key == VK_ESCAPE) && FSynchronizing)
  520. {
  521. Stop();
  522. Key = 0;
  523. }
  524. }
  525. //---------------------------------------------------------------------------