SynchronizeChecklist.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  1. //---------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include <Common.h>
  5. #include "WinInterface.h"
  6. #include "SynchronizeChecklist.h"
  7. #include <Terminal.h>
  8. #include <TextsWin.h>
  9. #include <CoreMain.h>
  10. #include <VCLCommon.h>
  11. #include <Tools.h>
  12. #include <BaseUtils.hpp>
  13. #include <Math.hpp>
  14. #include <WinConfiguration.h>
  15. #include <GUITools.h>
  16. #include <TerminalManager.h>
  17. #include <System.IOUtils.hpp>
  18. #include <System.StrUtils.hpp>
  19. //---------------------------------------------------------------------
  20. #pragma link "IEListView"
  21. #pragma link "NortonLikeListView"
  22. #pragma link "PngImageList"
  23. #ifndef NO_RESOURCES
  24. #pragma resource "*.dfm"
  25. #endif
  26. //---------------------------------------------------------------------
  27. const int ImageColumnIndex = 4;
  28. //---------------------------------------------------------------------
  29. bool __fastcall DoSynchronizeChecklistDialog(TSynchronizeChecklist * Checklist,
  30. TSynchronizeMode Mode, int Params,
  31. const UnicodeString LocalDirectory, const UnicodeString RemoteDirectory,
  32. TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
  33. TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove,
  34. void * Token)
  35. {
  36. std::unique_ptr<TSynchronizeChecklistDialog> Dialog(
  37. new TSynchronizeChecklistDialog(
  38. Application, Mode, Params, LocalDirectory, RemoteDirectory, OnCustomCommandMenu, OnSynchronize,
  39. OnSynchronizeChecklistCalculateSize, OnSynchronizeMove, Token));
  40. return Dialog->Execute(Checklist);
  41. }
  42. //---------------------------------------------------------------------
  43. __fastcall TSynchronizeChecklistDialog::TSynchronizeChecklistDialog(
  44. TComponent * AOwner, TSynchronizeMode Mode, int Params,
  45. const UnicodeString & LocalDirectory, const UnicodeString & RemoteDirectory,
  46. TCustomCommandMenuEvent OnCustomCommandMenu, TFullSynchronizeEvent OnSynchronize,
  47. TSynchronizeChecklistCalculateSize OnSynchronizeChecklistCalculateSize, TSynchronizeMoveEvent OnSynchronizeMove, void * Token)
  48. : TForm(AOwner)
  49. {
  50. FFormRestored = false;
  51. FMode = Mode;
  52. FParams = Params;
  53. FLocalDirectory = ExcludeTrailingBackslash(LocalDirectory);
  54. FRemoteDirectory = UnixExcludeTrailingBackslash(RemoteDirectory);
  55. FOnCustomCommandMenu = OnCustomCommandMenu;
  56. FOnSynchronizeChecklistCalculateSize = OnSynchronizeChecklistCalculateSize;
  57. FOnSynchronizeMove = OnSynchronizeMove;
  58. DebugAssert(OnSynchronize != NULL);
  59. FOnSynchronize = OnSynchronize;
  60. FToken = Token;
  61. UseSystemSettings(this);
  62. UseDesktopFont(ListView);
  63. UseDesktopFont(StatusBar);
  64. FChecklist = NULL;
  65. FChangingItem = NULL;
  66. FChangingItemIgnore = false;
  67. FChangingItemMass = false;
  68. FGeneralHint = StatusBar->Hint;
  69. FSynchronizing = false;
  70. SelectScaledImageList(ActionImages);
  71. FOrigListViewWindowProc = ListView->WindowProc;
  72. ListView->WindowProc = ListViewWindowProc;
  73. UpdateImages();
  74. CustomCommandsAction->Visible = (FOnCustomCommandMenu != NULL);
  75. // button visibility cannot be bound to action visibility
  76. CustomCommandsButton2->Visible = CustomCommandsAction->Visible;
  77. MenuButton(CustomCommandsButton2);
  78. }
  79. //---------------------------------------------------------------------
  80. __fastcall TSynchronizeChecklistDialog::~TSynchronizeChecklistDialog()
  81. {
  82. ListView->WindowProc = FOrigListViewWindowProc;
  83. }
  84. //---------------------------------------------------------------------
  85. bool __fastcall TSynchronizeChecklistDialog::Execute(TSynchronizeChecklist * Checklist)
  86. {
  87. FChecklist = Checklist;
  88. bool Result = (ShowModal() == DefaultResult(this));
  89. if (Result)
  90. {
  91. TSynchronizeChecklistConfiguration FormConfiguration =
  92. CustomWinConfiguration->SynchronizeChecklist;
  93. FormConfiguration.ListParams = ListView->ColProperties->ParamsStr;
  94. UnicodeString WindowParams = FormConfiguration.WindowParams;
  95. // if there is no main window, keep previous "custom pos" indication,
  96. bool CustomPos = (StrToIntDef(CutToChar(WindowParams, L';', true), 0) != 0);
  97. if (!IsMainFormLike(this))
  98. {
  99. CustomPos = (Application->MainForm->BoundsRect != BoundsRect);
  100. }
  101. FormConfiguration.WindowParams =
  102. FORMAT(L"%d;%s", ((CustomPos ? 1 : 0), StoreForm(this)));
  103. CustomWinConfiguration->SynchronizeChecklist = FormConfiguration;
  104. }
  105. if (FException.get() != NULL)
  106. {
  107. RethrowException(FException.get());
  108. }
  109. return Result;
  110. }
  111. //---------------------------------------------------------------------
  112. void __fastcall TSynchronizeChecklistDialog::UpdateCaption()
  113. {
  114. TTerminalManager * Manager = TTerminalManager::Instance();
  115. UnicodeString Title = Manager->GetAppProgressTitle();
  116. UnicodeString StatusTitle = LoadStr(FSynchronizing ? SYNCHRONIZE_PROGRESS_SYNCHRONIZE2 : SYNCHRONIZE_CHECKLIST_CAPTION);
  117. if (Title.Pos(StatusTitle) <= 0)
  118. {
  119. AddToList(Title, StatusTitle, L" - ");
  120. }
  121. Caption = FormatFormCaption(this, Title);
  122. }
  123. //---------------------------------------------------------------------
  124. void __fastcall TSynchronizeChecklistDialog::UpdateControls()
  125. {
  126. UpdateCaption();
  127. StatusBar->Invalidate();
  128. bool AllChecked = true;
  129. bool AllUnchecked = true;
  130. bool AnyBoth = false;
  131. bool AnyNonBoth = false;
  132. bool AnyDirectory = false;
  133. TListItem * Item = ListView->Selected;
  134. while (Item != NULL)
  135. {
  136. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  137. TSynchronizeChecklist::TAction Action = GetChecklistItemAction(ChecklistItem);
  138. if ((Action == TSynchronizeChecklist::saUploadUpdate) ||
  139. (Action == TSynchronizeChecklist::saDownloadUpdate))
  140. {
  141. AnyBoth = true;
  142. }
  143. else
  144. {
  145. AnyNonBoth = true;
  146. }
  147. if (Item->Checked)
  148. {
  149. AllUnchecked = false;
  150. }
  151. else
  152. {
  153. AllChecked = false;
  154. }
  155. if (ChecklistItem->IsDirectory)
  156. {
  157. AnyDirectory = true;
  158. }
  159. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  160. }
  161. EnableControl(OkButton, (FChecked[0] > 0) && !FSynchronizing);
  162. EnableControl(CancelButton, !FSynchronizing);
  163. EnableControl(HelpButton, !FSynchronizing);
  164. CheckAction->Enabled = !AllChecked && !FSynchronizing;
  165. UncheckAction->Enabled = !AllUnchecked && !FSynchronizing;
  166. CheckAllAction->Enabled = (FChecked[0] < FTotals[0]) && !FSynchronizing;
  167. UncheckAllAction->Enabled = (FChecked[0] > 0) && !FSynchronizing;
  168. CheckDirectoryAction->Enabled = CheckAllAction->Enabled; // sic
  169. UncheckDirectoryAction->Enabled = UncheckAllAction->Enabled; // sic
  170. CustomCommandsAction->Enabled = AnyBoth && !AnyNonBoth && DebugAlwaysTrue(!FSynchronizing);
  171. ReverseAction->Enabled = (ListView->SelCount > 0) && DebugAlwaysTrue(!FSynchronizing);
  172. MoveAction->Enabled = (GetMoveItems() != TSynchronizeMoveItems());
  173. CalculateSizeAction->Enabled = (ListView->SelCount > 0) && AnyDirectory && DebugAlwaysTrue(!FSynchronizing);
  174. SelectAllAction->Enabled = (ListView->SelCount < ListView->Items->Count) && !FSynchronizing;
  175. }
  176. //---------------------------------------------------------------------------
  177. bool __fastcall TSynchronizeChecklistDialog::GetWindowParams(UnicodeString & WindowParams)
  178. {
  179. WindowParams = CustomWinConfiguration->SynchronizeChecklist.WindowParams;
  180. bool CustomPos = (StrToIntDef(CutToChar(WindowParams, L';', true), 0) != 0);
  181. return CustomPos || IsMainFormLike(this);
  182. }
  183. //---------------------------------------------------------------------------
  184. void __fastcall TSynchronizeChecklistDialog::CreateParams(TCreateParams & Params)
  185. {
  186. UnicodeString WindowParams;
  187. if (GetWindowParams(WindowParams))
  188. {
  189. // This is only to set correct TForm::Position. Actual bounds are set later after DPI scaling
  190. RestoreForm(WindowParams, this, true);
  191. }
  192. TForm::CreateParams(Params);
  193. }
  194. //---------------------------------------------------------------------------
  195. void __fastcall TSynchronizeChecklistDialog::HelpButtonClick(TObject * /*Sender*/)
  196. {
  197. FormHelp(this);
  198. }
  199. //---------------------------------------------------------------------------
  200. void __fastcall TSynchronizeChecklistDialog::AddSubItem(TListItem * Item, int & Index, const UnicodeString & S)
  201. {
  202. if (Index < Item->SubItems->Count)
  203. {
  204. Item->SubItems->Strings[Index] = S;
  205. }
  206. else
  207. {
  208. DebugAssert(Index == Item->SubItems->Count);
  209. Item->SubItems->Add(S);
  210. }
  211. Index++;
  212. }
  213. //---------------------------------------------------------------------------
  214. void __fastcall TSynchronizeChecklistDialog::LoadItem(TListItem * Item)
  215. {
  216. UnicodeString S;
  217. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  218. if (ChecklistItem->ImageIndex >= 0)
  219. {
  220. Item->ImageIndex = ChecklistItem->ImageIndex;
  221. }
  222. else
  223. {
  224. Item->ImageIndex = FakeFileImageIndex(ChecklistItem->GetFileName(),
  225. FLAGMASK(ChecklistItem->IsDirectory, FILE_ATTRIBUTE_DIRECTORY));
  226. }
  227. S = ChecklistItem->GetFileName();
  228. if (ChecklistItem->IsDirectory)
  229. {
  230. S = IncludeTrailingBackslash(S);
  231. }
  232. Item->Caption = S;
  233. int Index = 0;
  234. TSynchronizeChecklist::TAction Action = GetChecklistItemAction(ChecklistItem);
  235. if (Action == TSynchronizeChecklist::saDeleteRemote)
  236. {
  237. AddSubItem(Item, Index, L"");
  238. AddSubItem(Item, Index, L"");
  239. AddSubItem(Item, Index, L"");
  240. }
  241. else
  242. {
  243. S = ChecklistItem->Local.Directory;
  244. if (AnsiSameText(FLocalDirectory, S.SubString(1, FLocalDirectory.Length())))
  245. {
  246. S[1] = L'.';
  247. S.Delete(2, FLocalDirectory.Length() - 1);
  248. }
  249. else
  250. {
  251. DebugFail();
  252. }
  253. AddSubItem(Item, Index, S);
  254. if (Action == TSynchronizeChecklist::saDownloadNew)
  255. {
  256. AddSubItem(Item, Index, L"");
  257. AddSubItem(Item, Index, L"");
  258. }
  259. else
  260. {
  261. if (!ChecklistItem->HasSize())
  262. {
  263. AddSubItem(Item, Index, L"");
  264. }
  265. else
  266. {
  267. AddSubItem(Item, Index,
  268. FormatPanelBytes(ChecklistItem->Local.Size, WinConfiguration->FormatSizeBytes));
  269. }
  270. AddSubItem(Item, Index,
  271. UserModificationStr(ChecklistItem->Local.Modification,
  272. ChecklistItem->Local.ModificationFmt));
  273. }
  274. }
  275. AddSubItem(Item, Index, L"");
  276. DebugAssert(Index == ImageColumnIndex);
  277. if (Action == TSynchronizeChecklist::saDeleteLocal)
  278. {
  279. AddSubItem(Item, Index, L"");
  280. AddSubItem(Item, Index, L"");
  281. AddSubItem(Item, Index, L"");
  282. }
  283. else
  284. {
  285. S = ChecklistItem->Remote.Directory;
  286. if (AnsiSameText(FRemoteDirectory, S.SubString(1, FRemoteDirectory.Length())))
  287. {
  288. S[1] = L'.';
  289. S.Delete(2, FRemoteDirectory.Length() - 1);
  290. }
  291. else
  292. {
  293. DebugFail();
  294. }
  295. AddSubItem(Item, Index, S);
  296. if (Action == TSynchronizeChecklist::saUploadNew)
  297. {
  298. AddSubItem(Item, Index, L"");
  299. AddSubItem(Item, Index, L"");
  300. }
  301. else
  302. {
  303. if (!ChecklistItem->HasSize())
  304. {
  305. AddSubItem(Item, Index, L"");
  306. }
  307. else
  308. {
  309. AddSubItem(Item, Index,
  310. FormatPanelBytes(ChecklistItem->Remote.Size, WinConfiguration->FormatSizeBytes));
  311. }
  312. AddSubItem(Item, Index, UserModificationStr(ChecklistItem->Remote.Modification,
  313. ChecklistItem->Remote.ModificationFmt));
  314. }
  315. }
  316. }
  317. //---------------------------------------------------------------------------
  318. void __fastcall TSynchronizeChecklistDialog::CountItemSize(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor)
  319. {
  320. TSynchronizeChecklist::TAction Action = GetChecklistItemAction(ChecklistItem);
  321. int ActionIndex = int(Action);
  322. __int64 ItemSize = ChecklistItem->GetSize(Action);
  323. FCheckedSize[ActionIndex] += Factor * ItemSize;
  324. FCheckedSize[0] += Factor * ItemSize;
  325. }
  326. //---------------------------------------------------------------------------
  327. void __fastcall TSynchronizeChecklistDialog::CountItem(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor)
  328. {
  329. int ActionIndex = int(GetChecklistItemAction(ChecklistItem));
  330. FChecked[ActionIndex] += Factor;
  331. FChecked[0] += Factor;
  332. CountItemSize(ChecklistItem, Factor);
  333. }
  334. //---------------------------------------------------------------------------
  335. void __fastcall TSynchronizeChecklistDialog::CountItemTotal(const TSynchronizeChecklist::TItem * ChecklistItem, int Factor)
  336. {
  337. FTotals[0] += Factor;
  338. int ActionIndex = int(GetChecklistItemAction(ChecklistItem));
  339. FTotals[ActionIndex] += Factor;
  340. }
  341. //---------------------------------------------------------------------------
  342. void __fastcall TSynchronizeChecklistDialog::LoadList()
  343. {
  344. memset(&FTotals, 0, sizeof(FTotals));
  345. memset(&FChecked, 0, sizeof(FChecked));
  346. memset(&FCheckedSize, 0, sizeof(FCheckedSize));
  347. ListView->Items->BeginUpdate();
  348. try
  349. {
  350. ListView->Items->Clear();
  351. for (int Index = 0; Index < FChecklist->Count; Index++)
  352. {
  353. const TSynchronizeChecklist::TItem * ChecklistItem =
  354. FChecklist->Item[ListView->Items->Count];
  355. FChangingItemIgnore = true;
  356. try
  357. {
  358. TListItem * Item = ListView->Items->Add();
  359. TSynchronizeChecklist::TAction Action = ChecklistItem->Action;
  360. FActions.insert(std::make_pair(ChecklistItem, Action));
  361. FChecklistToListViewMap.insert(std::make_pair(ChecklistItem, Item));
  362. Item->Data = const_cast<TSynchronizeChecklist::TItem *>(ChecklistItem);
  363. Item->Checked = ChecklistItem->Checked;
  364. LoadItem(Item);
  365. }
  366. __finally
  367. {
  368. FChangingItemIgnore = false;
  369. }
  370. CountItemTotal(ChecklistItem, 1);
  371. if (ChecklistItem->Checked)
  372. {
  373. CountItem(ChecklistItem, 1);
  374. }
  375. }
  376. }
  377. __finally
  378. {
  379. ListView->Items->EndUpdate();
  380. }
  381. ListView->AlphaSort();
  382. UpdateControls();
  383. }
  384. //---------------------------------------------------------------------------
  385. void __fastcall TSynchronizeChecklistDialog::FormShow(TObject * /*Sender*/)
  386. {
  387. // Moved here from CreateParams (see also TEditorForm::CreateParams), because there it breaks per-monitor DPI.
  388. // For example BoundsRect is matched to the main form too soon, so it gets rescaled later.
  389. // Also it happens before constructor, what causes UseDesktopFont-flagged controls to rescale twice.
  390. // But Position is already set in the CreateParams, as it cannot be set here anymore.
  391. if (!FFormRestored)
  392. {
  393. FFormRestored = True;
  394. UnicodeString WindowParams;
  395. if (GetWindowParams(WindowParams))
  396. {
  397. RestoreForm(WindowParams, this);
  398. }
  399. else
  400. {
  401. BoundsRect = Application->MainForm->BoundsRect;
  402. }
  403. FlashOnBackground();
  404. }
  405. ListView->ColProperties->ParamsStr = CustomWinConfiguration->SynchronizeChecklist.ListParams;
  406. LoadList();
  407. UpdateStatusBarSize();
  408. }
  409. //---------------------------------------------------------------------------
  410. TRect __fastcall TSynchronizeChecklistDialog::GetColumnHeaderRect(int Index)
  411. {
  412. HWND HeaderHandle = ListView_GetHeader(ListView->Handle);
  413. TRect R;
  414. Header_GetItemRect(HeaderHandle, Index, &R);
  415. // Can be simplified using GetScrollPos
  416. TScrollInfo ScrollInfo;
  417. ZeroMemory(&ScrollInfo, sizeof(ScrollInfo));
  418. ScrollInfo.cbSize = sizeof(ScrollInfo);
  419. ScrollInfo.fMask = SIF_POS;
  420. GetScrollInfo(ListView->Handle, SB_HORZ, &ScrollInfo);
  421. R.Left -= ScrollInfo.nPos;
  422. R.Right -= ScrollInfo.nPos;
  423. return R;
  424. }
  425. //---------------------------------------------------------------------------
  426. void __fastcall TSynchronizeChecklistDialog::ListViewWindowProc(TMessage & Message)
  427. {
  428. if (Message.Msg == CN_NOTIFY)
  429. {
  430. TWMNotify & NotifyMessage = reinterpret_cast<TWMNotify &>(Message);
  431. if (NotifyMessage.NMHdr->code == NM_CUSTOMDRAW)
  432. {
  433. // workaround
  434. // Due to a bug in VCL, OnAdvancedCustomDrawSubItem is not called for any
  435. // other stage except for cdPrePaint. So we must call it ourselves.
  436. TNMLVCustomDraw * CustomDraw =
  437. reinterpret_cast<TNMLVCustomDraw *>(NotifyMessage.NMHdr);
  438. if (FLAGSET(CustomDraw->nmcd.dwDrawStage, CDDS_ITEM) &&
  439. FLAGSET(CustomDraw->nmcd.dwDrawStage, CDDS_SUBITEM) &&
  440. FLAGSET(CustomDraw->nmcd.dwDrawStage, CDDS_ITEMPOSTPAINT) &&
  441. (CustomDraw->iSubItem == ImageColumnIndex) &&
  442. (ActionImages->Width <= ListView->Columns->Items[CustomDraw->iSubItem]->Width))
  443. {
  444. TListItem * Item = ListView->Items->Item[CustomDraw->nmcd.dwItemSpec];
  445. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  446. TRect HeaderR = GetColumnHeaderRect(CustomDraw->iSubItem);
  447. TRect R = Item->DisplayRect(drBounds);
  448. R.Left = HeaderR.Left + (HeaderR.Width() - ActionImages->Width) / 2;
  449. R.Right = HeaderR.Right;
  450. // workaround
  451. // doing this from ListViewAdvancedCustomDraw corrupts list view on Windows 7
  452. ImageList_Draw(reinterpret_cast<HIMAGELIST>(ActionImages->Handle),
  453. int(GetChecklistItemAction(ChecklistItem)), CustomDraw->nmcd.hdc,
  454. R.Left, ((R.Top + R.Bottom - ActionImages->Height) / 2), ILD_TRANSPARENT);
  455. }
  456. }
  457. }
  458. FOrigListViewWindowProc(Message);
  459. }
  460. //---------------------------------------------------------------------------
  461. void __fastcall TSynchronizeChecklistDialog::ListViewAdvancedCustomDrawSubItem(
  462. TCustomListView * /*Sender*/, TListItem * /*Item*/, int /*SubItem*/,
  463. TCustomDrawState /*State*/, TCustomDrawStage /*Stage*/, bool & /*DefaultDraw*/)
  464. {
  465. // this is just fake handler that makes the list view request custom draw notification above
  466. }
  467. //---------------------------------------------------------------------------
  468. void __fastcall TSynchronizeChecklistDialog::StatusBarDrawPanel(
  469. TStatusBar * StatusBar, TStatusPanel * Panel, const TRect & Rect)
  470. {
  471. bool Possible;
  472. int ActionIndex = Panel->Index;
  473. TSynchronizeChecklist::TAction Action = TSynchronizeChecklist::TAction(ActionIndex);
  474. if (FTotals[ActionIndex] > 0)
  475. {
  476. // if direction is overriden to an action that is otherwise not possible
  477. // in given synchronization mode, we still want to show the stats
  478. Possible = true;
  479. }
  480. else
  481. {
  482. switch (Action)
  483. {
  484. case TSynchronizeChecklist::saNone:
  485. Possible = true;
  486. break;
  487. case TSynchronizeChecklist::saUploadNew:
  488. Possible = ((FMode == smRemote) || (FMode == smBoth)) &&
  489. FLAGCLEAR(FParams, TTerminal::spTimestamp);
  490. break;
  491. case TSynchronizeChecklist::saDownloadNew:
  492. Possible = ((FMode == smLocal) || (FMode == smBoth)) &&
  493. FLAGCLEAR(FParams, TTerminal::spTimestamp);
  494. break;
  495. case TSynchronizeChecklist::saUploadUpdate:
  496. Possible =
  497. ((FMode == smRemote) || (FMode == smBoth)) &&
  498. (FLAGCLEAR(FParams, TTerminal::spNotByTime) || FLAGSET(FParams, TTerminal::spBySize));
  499. break;
  500. case TSynchronizeChecklist::saDownloadUpdate:
  501. Possible =
  502. ((FMode == smLocal) || (FMode == smBoth)) &&
  503. (FLAGCLEAR(FParams, TTerminal::spNotByTime) || FLAGSET(FParams, TTerminal::spBySize));
  504. break;
  505. case TSynchronizeChecklist::saDeleteRemote:
  506. Possible = (FMode == smRemote) &&
  507. FLAGCLEAR(FParams, TTerminal::spTimestamp);
  508. break;
  509. case TSynchronizeChecklist::saDeleteLocal:
  510. Possible = (FMode == smLocal) &&
  511. FLAGCLEAR(FParams, TTerminal::spTimestamp);
  512. break;
  513. default:
  514. DebugFail();
  515. Possible = false;
  516. break;
  517. }
  518. }
  519. UnicodeString PanelText;
  520. if (Possible)
  521. {
  522. PanelText = FORMAT(LoadStrPart(SYNCHRONIZE_SELECTED_ACTIONS, 1),
  523. (FormatNumber(FChecked[ActionIndex]),
  524. FormatNumber(FTotals[ActionIndex])));
  525. if ((FChecked[ActionIndex] > 0) &&
  526. ((ActionIndex == 0) || !TSynchronizeChecklist::IsItemSizeIrrelevant(Action)))
  527. {
  528. PanelText += FORMAT(L" (%s)", (FormatBytes(FCheckedSize[ActionIndex])));
  529. }
  530. }
  531. else
  532. {
  533. PanelText = LoadStrPart(SYNCHRONIZE_SELECTED_ACTIONS, 2);
  534. }
  535. int TextHeight = StatusBar->Canvas->TextHeight(PanelText);
  536. int X = Rect.Left + ActionImages->Width + 4;
  537. int Y = (Rect.Top + Rect.Bottom - TextHeight) / 2;
  538. StatusBar->Canvas->TextRect(Rect, X, Y, PanelText);
  539. X = Rect.Left + 1;
  540. Y = ((Rect.Top + Rect.Bottom - ActionImages->Height) / 2);
  541. int ImageIndex = ActionIndex;
  542. ActionImages->Draw(StatusBar->Canvas, X, Y, ImageIndex, Possible);
  543. }
  544. //---------------------------------------------------------------------------
  545. int __fastcall TSynchronizeChecklistDialog::PanelCount()
  546. {
  547. // last "panel" is technical
  548. return StatusBar->Panels->Count - 1;
  549. }
  550. //---------------------------------------------------------------------------
  551. int __fastcall TSynchronizeChecklistDialog::PanelAt(int X)
  552. {
  553. int Result = 0;
  554. while ((X > StatusBar->Panels->Items[Result]->Width) &&
  555. (Result < PanelCount()))
  556. {
  557. X -= StatusBar->Panels->Items[Result]->Width;
  558. Result++;
  559. }
  560. return ((Result < StatusBar->Panels->Count - 1) ? Result : -1);
  561. }
  562. //---------------------------------------------------------------------------
  563. void __fastcall TSynchronizeChecklistDialog::StatusBarMouseMove(
  564. TObject * /*Sender*/, TShiftState /*Shift*/, int X, int /*Y*/)
  565. {
  566. UnicodeString Hint;
  567. int IPanel = PanelAt(X);
  568. if (IPanel >= 0)
  569. {
  570. Hint = StatusBar->Panels->Items[IPanel]->Text;
  571. if (IPanel > 0)
  572. {
  573. Hint = FORMAT(L"%s\n%s", (Hint, FGeneralHint));
  574. }
  575. }
  576. if (Hint != StatusBar->Hint)
  577. {
  578. Application->CancelHint();
  579. StatusBar->Hint = Hint;
  580. }
  581. }
  582. //---------------------------------------------------------------------------
  583. void __fastcall TSynchronizeChecklistDialog::ListViewChange(
  584. TObject * /*Sender*/, TListItem * Item, TItemChange Change)
  585. {
  586. if ((Change == ctState) && (FChangingItem == Item) && (FChangingItem != NULL))
  587. {
  588. if (!FChangingItemIgnore)
  589. {
  590. DebugAssert(Item->Data != NULL);
  591. if ((FChangingItemChecked != Item->Checked) && (Item->Data != NULL))
  592. {
  593. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  594. CountItem(ChecklistItem, Item->Checked ? 1 : -1);
  595. if (!FChangingItemMass)
  596. {
  597. UpdateControls();
  598. }
  599. }
  600. }
  601. FChangingItem = NULL;
  602. }
  603. }
  604. //---------------------------------------------------------------------------
  605. void __fastcall TSynchronizeChecklistDialog::ListViewChanging(
  606. TObject * /*Sender*/, TListItem * Item, TItemChange Change,
  607. bool & /*AllowChange*/)
  608. {
  609. if (Change == ctState)
  610. {
  611. FChangingItem = Item;
  612. FChangingItemChecked = Item->Checked;
  613. }
  614. else
  615. {
  616. DebugAssert(FChangingItem == NULL);
  617. FChangingItem = NULL;
  618. }
  619. }
  620. //---------------------------------------------------------------------------
  621. void __fastcall TSynchronizeChecklistDialog::CheckAll(bool Check)
  622. {
  623. FChangingItemMass = true;
  624. try
  625. {
  626. for (int Index = 0; Index < ListView->Items->Count; Index++)
  627. {
  628. ListView->Items->Item[Index]->Checked = Check;
  629. }
  630. }
  631. __finally
  632. {
  633. FChangingItemMass = false;
  634. }
  635. UpdateControls();
  636. }
  637. //---------------------------------------------------------------------------
  638. void __fastcall TSynchronizeChecklistDialog::CheckAllActionExecute(TObject * /*Sender*/)
  639. {
  640. CheckAll(true);
  641. }
  642. //---------------------------------------------------------------------------
  643. void __fastcall TSynchronizeChecklistDialog::UncheckAllActionExecute(TObject * /*Sender*/)
  644. {
  645. CheckAll(false);
  646. }
  647. //---------------------------------------------------------------------------
  648. void __fastcall TSynchronizeChecklistDialog::Check(bool Check)
  649. {
  650. FChangingItemMass = true;
  651. try
  652. {
  653. TListItem * Item = ListView->Selected;
  654. while (Item != NULL)
  655. {
  656. Item->Checked = Check;
  657. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  658. }
  659. }
  660. __finally
  661. {
  662. FChangingItemMass = false;
  663. }
  664. UpdateControls();
  665. }
  666. //---------------------------------------------------------------------------
  667. void __fastcall TSynchronizeChecklistDialog::CheckActionExecute(TObject * /*Sender*/)
  668. {
  669. Check(true);
  670. }
  671. //---------------------------------------------------------------------------
  672. void __fastcall TSynchronizeChecklistDialog::UncheckActionExecute(TObject * /*Sender*/)
  673. {
  674. Check(false);
  675. }
  676. //---------------------------------------------------------------------------
  677. void __fastcall TSynchronizeChecklistDialog::ListViewSelectItem(
  678. TObject * /*Sender*/, TListItem * /*Item*/, bool /*Selected*/)
  679. {
  680. // Delayed update of button status in case many items are being selected at once
  681. // Also change of selection causes buttons to flash, as for short period of time,
  682. // no item is selected
  683. UpdateTimer->Enabled = true;
  684. }
  685. //---------------------------------------------------------------------------
  686. void __fastcall TSynchronizeChecklistDialog::UpdateTimerTimer(
  687. TObject * /*Sender*/)
  688. {
  689. UpdateTimer->Enabled = false;
  690. UpdateControls();
  691. }
  692. //---------------------------------------------------------------------------
  693. TListItem * __fastcall TSynchronizeChecklistDialog::SelectAll(bool Select, int Action,
  694. bool OnlyTheAction)
  695. {
  696. TListItem * Result = NULL;
  697. for (int Index = 0; Index < ListView->Items->Count; Index++)
  698. {
  699. TListItem * Item = ListView->Items->Item[Index];
  700. if (Action == 0)
  701. {
  702. Item->Selected = Select;
  703. if (Result == NULL)
  704. {
  705. Result = Item;
  706. }
  707. }
  708. else
  709. {
  710. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  711. bool WantedAction = (int(GetChecklistItemAction(ChecklistItem)) == Action);
  712. if (WantedAction || !OnlyTheAction)
  713. {
  714. Item->Selected = Select && WantedAction;
  715. if (WantedAction && (Result == NULL))
  716. {
  717. Result = Item;
  718. }
  719. }
  720. }
  721. }
  722. return Result;
  723. }
  724. //---------------------------------------------------------------------------
  725. void __fastcall TSynchronizeChecklistDialog::SelectAllActionExecute(
  726. TObject * /*Sender*/)
  727. {
  728. SelectAll(true);
  729. }
  730. //---------------------------------------------------------------------------
  731. void __fastcall TSynchronizeChecklistDialog::StatusBarMouseDown(
  732. TObject * /*Sender*/, TMouseButton /*Button*/, TShiftState Shift, int X,
  733. int /*Y*/)
  734. {
  735. int IPanel = PanelAt(X);
  736. if (IPanel >= 0)
  737. {
  738. TListItem * Item = SelectAll(true, IPanel, Shift.Contains(ssCtrl));
  739. if (Item != NULL)
  740. {
  741. Item->MakeVisible(false);
  742. Item->Focused = true;
  743. ListView->SetFocus();
  744. }
  745. }
  746. }
  747. //---------------------------------------------------------------------------
  748. int __fastcall TSynchronizeChecklistDialog::CompareNumber(__int64 Value1,
  749. __int64 Value2)
  750. {
  751. int Result;
  752. if (Value1 < Value2)
  753. {
  754. Result = -1;
  755. }
  756. else if (Value1 == Value2)
  757. {
  758. Result = 0;
  759. }
  760. else
  761. {
  762. Result = 1;
  763. }
  764. return Result;
  765. }
  766. //---------------------------------------------------------------------------
  767. void __fastcall TSynchronizeChecklistDialog::ListViewCompare(
  768. TObject * /*Sender*/, TListItem * Item1, TListItem * Item2, int /*Data*/,
  769. int & Compare)
  770. {
  771. const TSynchronizeChecklist::TItem * ChecklistItem1 = GetChecklistItem(Item1);
  772. const TSynchronizeChecklist::TItem * ChecklistItem2 = GetChecklistItem(Item2);
  773. TIEListViewColProperties * ColProperties =
  774. dynamic_cast<TIEListViewColProperties *>(ListView->ColProperties);
  775. switch (ColProperties->SortColumn)
  776. {
  777. case 0: // name
  778. Compare = AnsiCompareText(ChecklistItem1->GetFileName(), ChecklistItem2->GetFileName());
  779. break;
  780. // sorting by local and remote dir is the same
  781. case 1: // local dir
  782. case 5: // remote dir
  783. Compare = 0; // default sorting
  784. break;
  785. case 2: // local size
  786. Compare = CompareNumber(ChecklistItem1->Local.Size, ChecklistItem2->Local.Size);
  787. break;
  788. case 3: // local changed
  789. Compare = CompareFileTime(ChecklistItem1->Local.Modification,
  790. ChecklistItem2->Local.Modification);
  791. break;
  792. case ImageColumnIndex: // action
  793. Compare = CompareNumber(GetChecklistItemAction(ChecklistItem1), GetChecklistItemAction(ChecklistItem2));
  794. break;
  795. case 6: // remote size
  796. Compare = CompareNumber(ChecklistItem1->Remote.Size, ChecklistItem2->Remote.Size);
  797. break;
  798. case 7: // remote changed
  799. Compare = CompareFileTime(ChecklistItem1->Remote.Modification,
  800. ChecklistItem2->Remote.Modification);
  801. break;
  802. }
  803. if (Compare == 0)
  804. {
  805. if (!ChecklistItem1->Local.Directory.IsEmpty())
  806. {
  807. Compare = AnsiCompareText(ChecklistItem1->Local.Directory, ChecklistItem2->Local.Directory);
  808. }
  809. else
  810. {
  811. DebugAssert(!ChecklistItem1->Remote.Directory.IsEmpty());
  812. Compare = AnsiCompareText(ChecklistItem1->Remote.Directory, ChecklistItem2->Remote.Directory);
  813. }
  814. if (Compare == 0)
  815. {
  816. Compare = AnsiCompareText(ChecklistItem1->GetFileName(), ChecklistItem2->GetFileName());
  817. }
  818. }
  819. if (!ColProperties->SortAscending)
  820. {
  821. Compare = -Compare;
  822. }
  823. }
  824. //---------------------------------------------------------------------------
  825. void __fastcall TSynchronizeChecklistDialog::ListViewSecondaryColumnHeader(
  826. TCustomIEListView * /*Sender*/, int Index, int & SecondaryColumn)
  827. {
  828. // "remote dir" column is sorting alias for "local dir" column
  829. if (Index == 5)
  830. {
  831. SecondaryColumn = 1;
  832. }
  833. else
  834. {
  835. SecondaryColumn = -1;
  836. }
  837. }
  838. //---------------------------------------------------------------------------
  839. void __fastcall TSynchronizeChecklistDialog::ListViewContextPopup(
  840. TObject * Sender, TPoint & MousePos, bool & Handled)
  841. {
  842. // to update source popup menu before TBX menu is created
  843. UpdateControls();
  844. MenuPopup(Sender, MousePos, Handled);
  845. }
  846. //---------------------------------------------------------------------------
  847. void __fastcall TSynchronizeChecklistDialog::CustomCommandsActionExecute(
  848. TObject * /*Sender*/)
  849. {
  850. TStrings * LocalFileList = new TStringList();
  851. TStrings * RemoteFileList = new TStringList();
  852. try
  853. {
  854. TListItem * Item = ListView->Selected;
  855. DebugAssert(Item != NULL);
  856. while (Item != NULL)
  857. {
  858. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  859. DebugAssert((GetChecklistItemAction(ChecklistItem) == TSynchronizeChecklist::saUploadUpdate) ||
  860. (GetChecklistItemAction(ChecklistItem) == TSynchronizeChecklist::saDownloadUpdate));
  861. DebugAssert(ChecklistItem->RemoteFile != NULL);
  862. UnicodeString LocalPath =
  863. IncludeTrailingBackslash(ChecklistItem->Local.Directory) +
  864. ChecklistItem->Local.FileName;
  865. LocalFileList->Add(LocalPath);
  866. UnicodeString RemotePath =
  867. UnixIncludeTrailingBackslash(ChecklistItem->Remote.Directory) +
  868. ChecklistItem->Remote.FileName;
  869. RemoteFileList->AddObject(RemotePath, ChecklistItem->RemoteFile);
  870. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  871. }
  872. }
  873. catch(...)
  874. {
  875. delete LocalFileList;
  876. delete RemoteFileList;
  877. throw;
  878. }
  879. DebugAssert(FOnCustomCommandMenu != NULL);
  880. FOnCustomCommandMenu(CustomCommandsAction, LocalFileList, RemoteFileList);
  881. }
  882. //---------------------------------------------------------------------------
  883. void __fastcall TSynchronizeChecklistDialog::UpdateStatusBarSize()
  884. {
  885. int PanelWidth = Min(StatusBar->Width / PanelCount(), ScaleByTextHeight(this, 160));
  886. for (int Index = 0; Index < PanelCount(); Index++)
  887. {
  888. StatusBar->Panels->Items[Index]->Width = PanelWidth;
  889. }
  890. }
  891. //---------------------------------------------------------------------------
  892. void __fastcall TSynchronizeChecklistDialog::StatusBarResize(TObject * /*Sender*/)
  893. {
  894. UpdateStatusBarSize();
  895. }
  896. //---------------------------------------------------------------------------
  897. const TSynchronizeChecklist::TItem * TSynchronizeChecklistDialog::GetChecklistItem(
  898. TListItem * Item)
  899. {
  900. return static_cast<const TSynchronizeChecklist::TItem *>(Item->Data);
  901. }
  902. //---------------------------------------------------------------------------
  903. TSynchronizeChecklist::TAction & TSynchronizeChecklistDialog::GetChecklistItemAction(
  904. const TSynchronizeChecklist::TItem * ChecklistItem)
  905. {
  906. TActions::iterator i = FActions.find(ChecklistItem);
  907. if (i == FActions.end())
  908. {
  909. throw EInvalidOperation(L"");
  910. }
  911. return i->second;
  912. }
  913. //---------------------------------------------------------------------------
  914. void __fastcall TSynchronizeChecklistDialog::ReverseActionExecute(TObject * /*Sender*/)
  915. {
  916. TAutoFlag Flag(FChangingItemMass);
  917. TListItem * Item = ListView->Selected;
  918. while (Item != NULL)
  919. {
  920. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  921. TSynchronizeChecklist::TAction & Action = GetChecklistItemAction(ChecklistItem);
  922. TSynchronizeChecklist::TAction NewAction = TSynchronizeChecklist::Reverse(Action);
  923. if (DebugAlwaysTrue(Action != NewAction))
  924. {
  925. CountItemTotal(ChecklistItem, -1);
  926. if (Item->Checked)
  927. {
  928. CountItem(ChecklistItem, -1);
  929. }
  930. Action = NewAction;
  931. CountItemTotal(ChecklistItem, 1);
  932. if (Item->Checked)
  933. {
  934. // item size may differ with action (0 for delete, but non-0 for new file transfer)
  935. CountItem(ChecklistItem, 1);
  936. }
  937. LoadItem(Item);
  938. }
  939. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  940. }
  941. Flag.Release();
  942. UpdateControls();
  943. }
  944. //---------------------------------------------------------------------------
  945. void __fastcall TSynchronizeChecklistDialog::ListViewClick(TObject * /*Sender*/)
  946. {
  947. TKeyboardState KeyState;
  948. GetKeyboardState(KeyState);
  949. TShiftState ShiftState = KeyboardStateToShiftState(KeyState);
  950. // when selecting, do not reverse, even when user clicked on action column
  951. if (!ShiftState.Contains(ssShift) && !ShiftState.Contains(ssCtrl))
  952. {
  953. TPoint P = ListView->ScreenToClient(Mouse->CursorPos);
  954. TRect R = GetColumnHeaderRect(ImageColumnIndex);
  955. if ((R.Left <= P.x) && (P.x <= R.Right))
  956. {
  957. // If no item was selected before the click, the action is not enabled yet here,
  958. // and Execute would be noop, force update
  959. UpdateControls();
  960. ReverseAction->Execute();
  961. }
  962. }
  963. }
  964. //---------------------------------------------------------------------------
  965. void __fastcall TSynchronizeChecklistDialog::Dispatch(void * AMessage)
  966. {
  967. TMessage & Message = *reinterpret_cast<TMessage *>(AMessage);
  968. if (Message.Msg == WM_SYSCOMMAND)
  969. {
  970. if (!HandleMinimizeSysCommand(Message))
  971. {
  972. TForm::Dispatch(AMessage);
  973. }
  974. }
  975. else if (Message.Msg == CM_DPICHANGED)
  976. {
  977. CMDpiChanged(Message);
  978. }
  979. else if (Message.Msg == WM_WANTS_MOUSEWHEEL_INACTIVE)
  980. {
  981. Message.Result = FSynchronizing ? 1 : 0;
  982. }
  983. else if (Message.Msg == WM_MANAGES_CAPTION)
  984. {
  985. // calling UpdateControls would cause status bar flicker
  986. UpdateCaption();
  987. Message.Result = 1;
  988. }
  989. else
  990. {
  991. TForm::Dispatch(AMessage);
  992. }
  993. }
  994. //---------------------------------------------------------------------------
  995. void __fastcall TSynchronizeChecklistDialog::UpdateImages()
  996. {
  997. ListView->SmallImages = ShellImageListForControl(this, ilsSmall);
  998. }
  999. //---------------------------------------------------------------------------
  1000. void __fastcall TSynchronizeChecklistDialog::CMDpiChanged(TMessage & Message)
  1001. {
  1002. TForm::Dispatch(&Message);
  1003. UpdateImages();
  1004. }
  1005. //---------------------------------------------------------------------------
  1006. void __fastcall TSynchronizeChecklistDialog::ProcessedItem(void * /*Token*/, const TSynchronizeChecklist::TItem * ChecklistItem)
  1007. {
  1008. TListItem * Item = FChecklistToListViewMap[ChecklistItem];
  1009. DebugAssert(Item->Checked);
  1010. Item->Checked = false;
  1011. Item->MakeVisible(false);
  1012. }
  1013. //---------------------------------------------------------------------------
  1014. void __fastcall TSynchronizeChecklistDialog::UpdatedSynchronizationChecklistItems(
  1015. const TSynchronizeChecklist::TItemList & Items)
  1016. {
  1017. TSynchronizeChecklist::TItemList::const_iterator Iter = Items.begin();
  1018. while (Iter != Items.end())
  1019. {
  1020. const TSynchronizeChecklist::TItem * ChecklistItem = *Iter;
  1021. TListItem * Item = FChecklistToListViewMap[ChecklistItem];
  1022. LoadItem(Item);
  1023. // When called from FOnSynchronize, we rely on a caller never to update size of an item that had size already,
  1024. // otherwise we get it counted twice here.
  1025. if (Item->Checked)
  1026. {
  1027. CountItemSize(ChecklistItem, 1);
  1028. }
  1029. Iter++;
  1030. }
  1031. UpdateControls();
  1032. }
  1033. //---------------------------------------------------------------------------
  1034. void __fastcall TSynchronizeChecklistDialog::OkButtonClick(TObject * /*Sender*/)
  1035. {
  1036. ListView->SelectAll(smNone);
  1037. for (int Index = 0; Index < ListView->Items->Count; Index++)
  1038. {
  1039. TListItem * Item = ListView->Items->Item[Index];
  1040. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  1041. FChecklist->Update(ChecklistItem, Item->Checked, GetChecklistItemAction(ChecklistItem));
  1042. }
  1043. TAutoFlag Flag(FSynchronizing);
  1044. UpdateControls();
  1045. try
  1046. {
  1047. FOnSynchronize(FToken, ProcessedItem, UpdatedSynchronizationChecklistItems);
  1048. }
  1049. catch (Exception & E)
  1050. {
  1051. FException.reset(CloneException(&E));
  1052. }
  1053. }
  1054. //---------------------------------------------------------------------------
  1055. void __fastcall TSynchronizeChecklistDialog::CalculateSizeActionExecute(TObject * /*Sender*/)
  1056. {
  1057. TItemStates States;
  1058. if (!IsKeyPressed(VK_CONTROL))
  1059. {
  1060. States << isSelected;
  1061. }
  1062. TSynchronizeChecklist::TItemList Items;
  1063. TListItem * Item = NULL;
  1064. while ((Item = ListView->GetNextItem(Item, sdAll, States)) != NULL)
  1065. {
  1066. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  1067. Items.push_back(ChecklistItem);
  1068. if (Item->Checked)
  1069. {
  1070. CountItemSize(ChecklistItem, -1);
  1071. }
  1072. }
  1073. try
  1074. {
  1075. FOnSynchronizeChecklistCalculateSize(FChecklist, Items, FToken);
  1076. }
  1077. __finally
  1078. {
  1079. UpdatedSynchronizationChecklistItems(Items);
  1080. }
  1081. }
  1082. //---------------------------------------------------------------------------
  1083. void __fastcall TSynchronizeChecklistDialog::CalculateSizeAllActionExecute(TObject * Sender)
  1084. {
  1085. DebugAssert(IsKeyPressed(VK_CONTROL));
  1086. CalculateSizeActionExecute(Sender);
  1087. }
  1088. //---------------------------------------------------------------------------
  1089. TSynchronizeChecklistDialog::TSynchronizeMoveItems __fastcall TSynchronizeChecklistDialog::GetMoveItems()
  1090. {
  1091. if ((ListView->SelCount != 2) || DebugAlwaysFalse(FSynchronizing))
  1092. {
  1093. return TSynchronizeMoveItems();
  1094. }
  1095. else
  1096. {
  1097. TListItem * Item1 = ListView->Selected;
  1098. const TSynchronizeChecklist::TItem * ChecklistItem1 = GetChecklistItem(DebugNotNull(Item1));
  1099. TListItem * Item2 = ListView->GetNextItem(ListView->Selected, sdAll, TItemStates() << isSelected);
  1100. const TSynchronizeChecklist::TItem * ChecklistItem2 = GetChecklistItem(DebugNotNull(Item2));
  1101. if (ChecklistItem1->IsDirectory != ChecklistItem2->IsDirectory)
  1102. {
  1103. return TSynchronizeMoveItems();
  1104. }
  1105. else
  1106. {
  1107. TSynchronizeChecklist::TAction Action1 = GetChecklistItemAction(ChecklistItem1);
  1108. TSynchronizeChecklist::TAction Action2 = GetChecklistItemAction(ChecklistItem2);
  1109. if ((Action1 == TSynchronizeChecklist::saUploadNew) && (Action2 == TSynchronizeChecklist::saDeleteRemote))
  1110. {
  1111. return TSynchronizeMoveItems(ChecklistItem1, ChecklistItem2);
  1112. }
  1113. else if ((Action1 == TSynchronizeChecklist::saDownloadNew) && (Action2 == TSynchronizeChecklist::saDeleteLocal))
  1114. {
  1115. return TSynchronizeMoveItems(ChecklistItem1, ChecklistItem2);
  1116. }
  1117. else if ((Action1 == TSynchronizeChecklist::saDeleteRemote) && (Action2 == TSynchronizeChecklist::saUploadNew))
  1118. {
  1119. return TSynchronizeMoveItems(ChecklistItem2, ChecklistItem1);
  1120. }
  1121. else if ((Action1 == TSynchronizeChecklist::saDeleteLocal) && (Action2 == TSynchronizeChecklist::saDownloadNew))
  1122. {
  1123. return TSynchronizeMoveItems(ChecklistItem2, ChecklistItem1);
  1124. }
  1125. else
  1126. {
  1127. return TSynchronizeMoveItems();
  1128. }
  1129. }
  1130. }
  1131. }
  1132. //---------------------------------------------------------------------------
  1133. void __fastcall TSynchronizeChecklistDialog::DeleteItem(TListItem * Item)
  1134. {
  1135. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  1136. CountItemTotal(ChecklistItem, -1);
  1137. if (Item->Checked)
  1138. {
  1139. CountItem(ChecklistItem, -1);
  1140. }
  1141. FActions.erase(ChecklistItem);
  1142. FChecklistToListViewMap.erase(ChecklistItem);
  1143. FChecklist->Delete(ChecklistItem);
  1144. ListView->Items->Delete(Item->Index);
  1145. }
  1146. //---------------------------------------------------------------------------
  1147. void __fastcall TSynchronizeChecklistDialog::MoveActionExecute(TObject *)
  1148. {
  1149. TSynchronizeMoveItems MoveItems = GetMoveItems();
  1150. TSynchronizeChecklist::TAction Action2 = GetChecklistItemAction(MoveItems.second);
  1151. TOperationSide Side;
  1152. UnicodeString FileName;
  1153. UnicodeString NewFileName;
  1154. TRemoteFile * RemoteFile;
  1155. if (Action2 == TSynchronizeChecklist::saDeleteRemote)
  1156. {
  1157. Side = osRemote;
  1158. FileName = UnixCombinePaths(MoveItems.second->Remote.Directory, MoveItems.second->Remote.FileName);
  1159. NewFileName = UnixCombinePaths(MoveItems.first->Remote.Directory, MoveItems.first->Local.FileName);
  1160. RemoteFile = MoveItems.second->RemoteFile;
  1161. }
  1162. else if (Action2 == TSynchronizeChecklist::saDeleteLocal)
  1163. {
  1164. Side = osLocal;
  1165. FileName = TPath::Combine(MoveItems.second->Local.Directory, MoveItems.second->Local.FileName);
  1166. NewFileName = TPath::Combine(MoveItems.first->Local.Directory, MoveItems.first->Remote.FileName);
  1167. RemoteFile = NULL;
  1168. }
  1169. else
  1170. {
  1171. DebugFail();
  1172. Abort();
  1173. }
  1174. FOnSynchronizeMove(Side, FileName, NewFileName, RemoteFile);
  1175. TListItem * Item1 = DebugNotNull(ListView->FindData(0, const_cast<TSynchronizeChecklist::TItem *>(MoveItems.first), true, false));
  1176. TListItem * Item2 = DebugNotNull(ListView->FindData(0, const_cast<TSynchronizeChecklist::TItem *>(MoveItems.second), true, false));
  1177. DeleteItem(Item1);
  1178. DeleteItem(Item2);
  1179. }
  1180. //---------------------------------------------------------------------------
  1181. void __fastcall TSynchronizeChecklistDialog::CheckDirectory(bool Check)
  1182. {
  1183. std::unique_ptr<TStringList> Directories(new TStringList());
  1184. TListItem * Item = ListView->Selected;
  1185. while (Item != NULL)
  1186. {
  1187. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  1188. // It does not matter if we use local or remote directory
  1189. Directories->Add(IncludeTrailingBackslash(ChecklistItem->Local.Directory));
  1190. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  1191. }
  1192. TAutoFlag ChangingItemMassSwitch(FChangingItemMass);
  1193. for (int Index = 0; Index < ListView->Items->Count; Index++)
  1194. {
  1195. TListItem * Item = ListView->Items->Item[Index];
  1196. const TSynchronizeChecklist::TItem * ChecklistItem = GetChecklistItem(Item);
  1197. UnicodeString Directory = IncludeTrailingBackslash(ChecklistItem->Local.Directory);
  1198. for (int Index2 = 0; Index2 < Directories->Count; Index2++)
  1199. {
  1200. if (StartsText(Directories->Strings[Index2], Directory))
  1201. {
  1202. Item->Checked = Check;
  1203. }
  1204. }
  1205. }
  1206. ChangingItemMassSwitch.Release();
  1207. UpdateControls();
  1208. }
  1209. //---------------------------------------------------------------------------
  1210. void __fastcall TSynchronizeChecklistDialog::CheckDirectoryActionExecute(TObject *)
  1211. {
  1212. CheckDirectory(true);
  1213. }
  1214. //---------------------------------------------------------------------------
  1215. void __fastcall TSynchronizeChecklistDialog::UncheckDirectoryActionExecute(TObject *)
  1216. {
  1217. CheckDirectory(false);
  1218. }
  1219. //---------------------------------------------------------------------------