Properties.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. //---------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #include "WinInterface.h"
  5. #include "Properties.h"
  6. #include <VCLCommon.h>
  7. #include <Common.h>
  8. #include <Terminal.h>
  9. #include <TextsWin.h>
  10. #include <GUITools.h>
  11. #include <CoreMain.h>
  12. #include <Tools.h>
  13. #include <BaseUtils.hpp>
  14. //---------------------------------------------------------------------
  15. #pragma link "PathLabel"
  16. #pragma link "Rights"
  17. #pragma resource "*.dfm"
  18. //---------------------------------------------------------------------
  19. bool __fastcall DoPropertiesDialog(TStrings * FileList,
  20. const UnicodeString Directory, const TRemoteTokenList * GroupList,
  21. const TRemoteTokenList * UserList, TStrings * ChecksumAlgs,
  22. TRemoteProperties * Properties,
  23. int AllowedChanges, bool UserGroupByID, TCalculateSizeEvent OnCalculateSize,
  24. TCalculateChecksumEvent OnCalculateChecksum)
  25. {
  26. bool Result;
  27. TPropertiesDialog * PropertiesDialog = new TPropertiesDialog(Application,
  28. FileList, Directory, GroupList, UserList, ChecksumAlgs, AllowedChanges, UserGroupByID,
  29. OnCalculateSize, OnCalculateChecksum);
  30. try
  31. {
  32. Result = PropertiesDialog->Execute(*Properties);
  33. }
  34. __finally
  35. {
  36. delete PropertiesDialog;
  37. }
  38. return Result;
  39. }
  40. //---------------------------------------------------------------------
  41. __fastcall TPropertiesDialog::TPropertiesDialog(TComponent* AOwner,
  42. TStrings * FileList, const UnicodeString Directory,
  43. const TRemoteTokenList * GroupList, const TRemoteTokenList * UserList,
  44. TStrings * ChecksumAlgs,
  45. int AllowedChanges, bool UserGroupByID, TCalculateSizeEvent OnCalculateSize,
  46. TCalculateChecksumEvent OnCalculateChecksum)
  47. : TForm(AOwner)
  48. {
  49. FOnCalculateSize = OnCalculateSize;
  50. FOnCalculateChecksum = OnCalculateChecksum;
  51. RightsFrame->OnChange = ControlChange;
  52. FFileList = new TStringList();
  53. FFileList->Assign(FileList);
  54. FAllowedChanges = AllowedChanges;
  55. if (FLAGSET(FAllowedChanges, cpAcl))
  56. {
  57. DebugAssert(FLAGCLEAR(FAllowedChanges, cpMode));
  58. RightsLabel->Caption = LoadStr(PROPERTIES_ACL);
  59. RightsFrame->DisplayAsAcl();
  60. }
  61. FUserGroupByID = UserGroupByID;
  62. FAllowCalculateStats = false;
  63. FStatsNotCalculated = false;
  64. FChecksumLoaded = false;
  65. FMultipleChecksum = false;
  66. LocationLabel->Text = Directory;
  67. FGroupList = GroupList;
  68. FUserList = UserList;
  69. FChecksumAlgs = ChecksumAlgs;
  70. ReadOnlyControl(ChecksumEdit);
  71. ReadOnlyControl(OwnerView);
  72. ReadOnlyControl(GroupView);
  73. ReadOnlyControl(FileLabel);
  74. ReadOnlyControl(LocationLabel);
  75. ReadOnlyControl(SizeLabel);
  76. ReadOnlyControl(LinksToLabel);
  77. ChecksumUnknownLabel->Caption = LoadStr(PROPERTIES_CHECKSUM_UNKNOWN);
  78. LoadInfo();
  79. UseSystemSettings(this);
  80. }
  81. //---------------------------------------------------------------------------
  82. __fastcall TPropertiesDialog::~TPropertiesDialog()
  83. {
  84. delete FFileList;
  85. FFileList = NULL;
  86. }
  87. //---------------------------------------------------------------------
  88. bool __fastcall TPropertiesDialog::Execute(TRemoteProperties & Properties)
  89. {
  90. SetFileProperties(Properties);
  91. PageControl->ActivePage = CommonSheet;
  92. if (OwnerComboBox->Visible && OwnerComboBox->Enabled)
  93. {
  94. ActiveControl = OwnerComboBox;
  95. }
  96. else if (GroupComboBox->Visible && GroupComboBox->Enabled)
  97. {
  98. ActiveControl = GroupComboBox;
  99. }
  100. else if (RightsFrame->Visible && RightsFrame->Enabled)
  101. {
  102. ActiveControl = RightsFrame;
  103. }
  104. else if (DebugAlwaysTrue(CancelButton->Visible && CancelButton->Enabled))
  105. {
  106. ActiveControl = CancelButton;
  107. }
  108. if (DebugAlwaysTrue(FChecksumAlgs != NULL))
  109. {
  110. ChecksumAlgEdit->Items->Assign(FChecksumAlgs);
  111. int ChecksumIndex = FChecksumAlgs->IndexOf(GUIConfiguration->ChecksumAlg);
  112. if (ChecksumIndex < 0)
  113. {
  114. ChecksumIndex = 0;
  115. }
  116. ChecksumAlgEdit->ItemIndex = ChecksumIndex;
  117. }
  118. ResetChecksum();
  119. UpdateControls();
  120. bool Result = (ShowModal() == DefaultResult());
  121. if (Result)
  122. {
  123. Properties = GetFileProperties();
  124. }
  125. return Result;
  126. }
  127. //---------------------------------------------------------------------------
  128. TModalResult __fastcall TPropertiesDialog::DefaultResult()
  129. {
  130. // Fallback when ChecksumButton is default
  131. return ::DefaultResult(this, OkButton);
  132. }
  133. //---------------------------------------------------------------------------
  134. UnicodeString __fastcall TPropertiesDialog::LoadRemoteToken(
  135. const TRemoteToken & Token)
  136. {
  137. UnicodeString Result;
  138. if (FUserGroupByID)
  139. {
  140. if (Token.IDValid)
  141. {
  142. if (Token.NameValid)
  143. {
  144. Result = FORMAT(L"%s [%d]", (Token.Name, int(Token.ID)));
  145. }
  146. else
  147. {
  148. Result = FORMAT(L"[%d]", (int(Token.ID)));
  149. }
  150. }
  151. else
  152. {
  153. // be it valid or not
  154. Result = Token.Name;
  155. }
  156. }
  157. else
  158. {
  159. // what if name is not filled in?
  160. Result = Token.Name;
  161. }
  162. return Result;
  163. }
  164. //---------------------------------------------------------------------------
  165. void __fastcall TPropertiesDialog::LoadRemoteToken(
  166. TComboBox * ComboBox, TEdit * View, TLabel * Label, bool Valid, const TRemoteToken & Token, int Change)
  167. {
  168. UnicodeString Value = Valid ? LoadRemoteToken(Token) : EmptyStr;
  169. ComboBox->Text = Value;
  170. View->Text = Value;
  171. bool AllowedChange = FLAGSET(FAllowedChanges, Change);
  172. ComboBox->Visible = AllowedChange;
  173. View->Visible = Valid && !AllowedChange;
  174. Label->FocusControl = AllowedChange ? static_cast<TWinControl *>(ComboBox) : static_cast<TWinControl *>(View);
  175. Label->Visible = Label->FocusControl->Visible;
  176. }
  177. //---------------------------------------------------------------------------
  178. void __fastcall TPropertiesDialog::LoadRemoteTokens(TComboBox * ComboBox,
  179. const TRemoteTokenList * List)
  180. {
  181. TStrings * Items = ComboBox->Items;
  182. Items->BeginUpdate();
  183. try
  184. {
  185. Items->Clear();
  186. if (List != NULL)
  187. {
  188. int Count = List->Count();
  189. for (int Index = 0; Index < Count; Index++)
  190. {
  191. Items->Add(LoadRemoteToken(*List->Token(Index)));
  192. }
  193. }
  194. }
  195. __finally
  196. {
  197. Items->EndUpdate();
  198. }
  199. }
  200. //---------------------------------------------------------------------------
  201. void __fastcall TPropertiesDialog::LoadInfo()
  202. {
  203. DebugAssert(FFileList->Count > 0);
  204. FMultiple = FFileList->Count > 1;
  205. FMultipleChecksum = FMultiple;
  206. FAllowCalculateStats = false;
  207. FStatsNotCalculated = false;
  208. __int64 FilesSize = 0;
  209. TCalculateSizeStats Stats;
  210. for (int Index = 0; Index < FFileList->Count; Index++)
  211. {
  212. TRemoteFile * File = (TRemoteFile *)(FFileList->Objects[Index]);
  213. if (File->IsDirectory)
  214. {
  215. Stats.Directories++;
  216. // we should use TTerminal::CanRecurseToDirectory instead
  217. if (!File->IsSymLink)
  218. {
  219. FAllowCalculateStats = true;
  220. FStatsNotCalculated = true;
  221. FMultipleChecksum = true;
  222. }
  223. }
  224. else
  225. {
  226. Stats.Files++;
  227. }
  228. if (File->IsSymLink)
  229. {
  230. Stats.SymLinks++;
  231. }
  232. FilesSize += File->Size;
  233. }
  234. LoadRemoteTokens(GroupComboBox, FGroupList);
  235. LoadRemoteTokens(OwnerComboBox, FUserList);
  236. FAnyDirectories = (Stats.Directories > 0);
  237. RightsFrame->AllowAddXToDirectories = FAnyDirectories;
  238. if (!FMultiple)
  239. {
  240. // Show only file name, if we have only single file/directory.
  241. // For directory, this changes, once "Calculate" button is pressed
  242. Stats = TCalculateSizeStats();
  243. }
  244. LoadStats(FilesSize, Stats);
  245. RightsFrame->AllowUndef = FMultiple;
  246. if (!FMultiple)
  247. {
  248. TRemoteFile * File = (TRemoteFile *)(FFileList->Objects[0]);
  249. DebugAssert(File);
  250. UpdateFileImage();
  251. LinksToLabelLabel->Visible = File->IsSymLink;
  252. LinksToLabel->Visible = File->IsSymLink;
  253. if (File->IsSymLink)
  254. {
  255. LinksToLabel->Text = File->LinkTo;
  256. }
  257. Caption = FMTLOAD(PROPERTIES_FILE_CAPTION, (File->FileName));
  258. }
  259. else
  260. {
  261. Caption = FMTLOAD(PROPERTIES_FILES_CAPTION, (FFileList->Strings[0]));
  262. LinksToLabelLabel->Hide();
  263. LinksToLabel->Hide();
  264. LoadDialogImage(FileIconImage, L"Multiple Files");
  265. }
  266. ChecksumGroup->Visible = !FMultipleChecksum;
  267. ChecksumView->Visible = FMultipleChecksum;
  268. }
  269. //---------------------------------------------------------------------------
  270. void __fastcall TPropertiesDialog::UpdateFileImage()
  271. {
  272. TImageList * ImageList = ShellImageListForControl(this, ilsLarge);
  273. FileIconImage->Picture->Bitmap = NULL;
  274. TRemoteFile * File = (TRemoteFile *)(FFileList->Objects[0]);
  275. // shell image list does not have fixed large icon size
  276. // (it is probably 32x32 min, but can be larger, on xp it is 48x48 if
  277. // large icons are enabled, on vista can be even larger).
  278. // so we stretch (shrink) the icon to 32x32 here to be sure.
  279. Graphics::TBitmap * Bitmap = new Graphics::TBitmap;
  280. try
  281. {
  282. ImageList->GetBitmap(File->IconIndex, Bitmap);
  283. int Size = DialogImageSize(this);
  284. // Use exact DPI-scaled size, not approximate scaling by font size.
  285. // Otherwise we stretch icons unnecessarily because the canvas
  286. // is one or two pixels off the icon size
  287. FileIconImage->Width = Size;
  288. FileIconImage->Height = Size;
  289. FileIconImage->Picture->Bitmap->Width = Size;
  290. FileIconImage->Picture->Bitmap->Height = Size;
  291. FileIconImage->Picture->Bitmap->Canvas->StretchDraw(
  292. TRect(0, 0, Size, Size),
  293. Bitmap);
  294. }
  295. __finally
  296. {
  297. delete Bitmap;
  298. }
  299. }
  300. //---------------------------------------------------------------------------
  301. void __fastcall TPropertiesDialog::LoadStats(__int64 FilesSize,
  302. const TCalculateSizeStats & Stats)
  303. {
  304. UnicodeString SizeStr;
  305. UnicodeString FilesStr;
  306. if (FStatsNotCalculated)
  307. {
  308. SizeStr = LoadStr(PROPERTIES_UNKNOWN_SIZE);
  309. }
  310. else
  311. {
  312. SizeStr = FormatBytes(FilesSize);
  313. UnicodeString SizeUnorderedStr = FormatBytes(FilesSize, fbNone);
  314. if (SizeStr != SizeUnorderedStr)
  315. {
  316. SizeStr = FORMAT(L"%s (%s)", (SizeStr, SizeUnorderedStr));
  317. }
  318. }
  319. if (((Stats.Files + Stats.Directories) == 0) && !FMultiple)
  320. {
  321. TRemoteFile * File = (TRemoteFile *)(FFileList->Objects[0]);
  322. DebugAssert(File != NULL);
  323. FilesStr = File->FileName;
  324. }
  325. else
  326. {
  327. if (Stats.Files > 0)
  328. {
  329. FilesStr = (Stats.Files == 1) ? FMTLOAD(PROPERTIES_FILE, (Stats.Files)) :
  330. FMTLOAD(PROPERTIES_FILES, (Stats.Files));
  331. if (Stats.Directories > 0)
  332. {
  333. FilesStr = FORMAT(L"%s, ", (FilesStr));
  334. }
  335. }
  336. if (Stats.Directories > 0)
  337. {
  338. FilesStr += (Stats.Directories == 1) ? FMTLOAD(PROPERTIES_DIRECTORY, (Stats.Directories)) :
  339. FMTLOAD(PROPERTIES_DIRECTORIES, (Stats.Directories));
  340. }
  341. if (Stats.SymLinks > 0)
  342. {
  343. UnicodeString SymLinksStr;
  344. SymLinksStr = (Stats.SymLinks == 1) ? FMTLOAD(PROPERTIES_SYMLINK, (Stats.SymLinks)) :
  345. FMTLOAD(PROPERTIES_SYMLINKS, (Stats.SymLinks));
  346. FilesStr = FORMAT(L"%s (%s)", (FilesStr, SymLinksStr));
  347. }
  348. }
  349. SizeLabel->Text = SizeStr;
  350. FileLabel->Text = FilesStr;
  351. }
  352. //---------------------------------------------------------------------------
  353. void __fastcall TPropertiesDialog::SetFileProperties(const TRemoteProperties & value)
  354. {
  355. TValidProperties Valid;
  356. if (value.Valid.Contains(vpRights) && (FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl)))
  357. {
  358. Valid << vpRights;
  359. }
  360. if (value.Valid.Contains(vpOwner) && FLAGSET(FAllowedChanges, cpOwner))
  361. {
  362. Valid << vpOwner;
  363. }
  364. if (value.Valid.Contains(vpGroup) && FLAGSET(FAllowedChanges, cpGroup))
  365. {
  366. Valid << vpGroup;
  367. }
  368. FOrigProperties = value;
  369. FOrigProperties.Valid = Valid;
  370. FOrigProperties.Recursive = false;
  371. bool HasRights = value.Valid.Contains(vpRights);
  372. RightsFrame->Visible = HasRights;
  373. RightsLabel->Visible = RightsFrame->Visible;
  374. if (HasRights)
  375. {
  376. RightsFrame->Rights = value.Rights;
  377. RightsFrame->AddXToDirectories = value.AddXToDirectories;
  378. }
  379. else
  380. {
  381. RightsFrame->Rights = TRights();
  382. RightsFrame->AddXToDirectories = false;
  383. }
  384. // Not necesarily true, let's find the scenario when it is not and then decide how to render that (shift group up?)
  385. DebugAssert(value.Valid.Contains(vpOwner) || !value.Valid.Contains(vpGroup));
  386. LoadRemoteToken(GroupComboBox, GroupView, GroupLabel, value.Valid.Contains(vpGroup), value.Group, cpGroup);
  387. LoadRemoteToken(OwnerComboBox, OwnerView, OwnerLabel, value.Valid.Contains(vpOwner), value.Owner, cpOwner);
  388. bool HasAnything = GroupLabel->Visible || OwnerLabel->Visible || HasRights;
  389. // Not necesarily true, let's find the scenario when it is not and then decide how to render that (shift rights up?)
  390. DebugAssert((GroupLabel->Visible || OwnerLabel->Visible) || !HasRights);
  391. GroupOwnerRightsBevel->Visible = HasAnything;
  392. RecursiveCheck2->Checked = value.Recursive;
  393. RecursiveCheck2->Visible =
  394. (GroupComboBox->Visible ||
  395. OwnerComboBox->Visible ||
  396. // Recursion is always supported for permissions and never for ACL.
  397. // If this ever changes we will have to introduce respective capability check.
  398. (HasRights && !FLAGSET(FAllowedChanges, cpAcl))) &&
  399. FAnyDirectories;
  400. RecursiveBevel->Visible = RecursiveCheck2->Visible || HasRights;
  401. UpdateControls();
  402. }
  403. //---------------------------------------------------------------------------
  404. void __fastcall TPropertiesDialog::StoreRemoteToken(unsigned int ID,
  405. const UnicodeString & Text, const TRemoteTokenList * List, TRemoteToken & Result)
  406. {
  407. DebugAssert(List != NULL);
  408. const TRemoteToken * Token = List->Find(ID);
  409. if (Token == NULL)
  410. {
  411. Result.ID = ID;
  412. Result.Name = Text;
  413. }
  414. else
  415. {
  416. Result = *Token;
  417. }
  418. }
  419. //---------------------------------------------------------------------------
  420. TRemoteToken __fastcall TPropertiesDialog::StoreRemoteToken(const TRemoteToken & Orig,
  421. UnicodeString Text, int Message, const TRemoteTokenList * List)
  422. {
  423. TRemoteToken Result;
  424. Text = Text.Trim();
  425. if (!Text.IsEmpty())
  426. {
  427. if (FUserGroupByID)
  428. {
  429. DebugAssert(List != NULL);
  430. int IDStart = Text.LastDelimiter(L"[");
  431. if (!Text.IsEmpty() && (IDStart >= 0) && (Text[Text.Length()] == L']'))
  432. {
  433. int ID;
  434. UnicodeString IDStr = Text.SubString(IDStart + 1, Text.Length() - IDStart - 1);
  435. if (!TryStrToInt(IDStr, ID))
  436. {
  437. throw Exception(Message);
  438. }
  439. else
  440. {
  441. StoreRemoteToken(ID, Text.SubString(1, IDStart - 1).Trim(), List, Result);
  442. }
  443. }
  444. else
  445. {
  446. const TRemoteToken * Token = List->Find(Text);
  447. if (Token == NULL)
  448. {
  449. int ID;
  450. if (TryStrToInt(Text, ID))
  451. {
  452. StoreRemoteToken(ID, Text, List, Result);
  453. }
  454. else
  455. {
  456. throw Exception(MainInstructions(FMTLOAD(PROPERTIES_UNKNOWN_TOKEN, (Text))));
  457. }
  458. }
  459. else
  460. {
  461. Result = *Token;
  462. }
  463. }
  464. }
  465. else
  466. {
  467. Result.Name = Text;
  468. }
  469. }
  470. if (LoadRemoteToken(Result) == LoadRemoteToken(Orig))
  471. {
  472. Result = Orig;
  473. }
  474. return Result;
  475. }
  476. //---------------------------------------------------------------------------
  477. void __fastcall TPropertiesDialog::StoreRemoteToken(TComboBox * ComboBox,
  478. int ChangeFlag, TValidProperty PropertyFlag, const TRemoteToken & Orig,
  479. TRemoteToken & Token, int Message, const TRemoteTokenList * List,
  480. TRemoteProperties & Properties)
  481. {
  482. UnicodeString Text = ComboBox->Text.Trim();
  483. if (FLAGSET(FAllowedChanges, ChangeFlag))
  484. {
  485. Token = StoreRemoteToken(Orig, Text, Message, List);
  486. if (Token.IsSet)
  487. {
  488. Properties.Valid << PropertyFlag;
  489. }
  490. }
  491. }
  492. //---------------------------------------------------------------------------
  493. TRemoteProperties __fastcall TPropertiesDialog::GetFileProperties()
  494. {
  495. TRemoteProperties Result;
  496. if (FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl))
  497. {
  498. Result.Valid << vpRights;
  499. Result.Rights = RightsFrame->Rights;
  500. Result.AddXToDirectories = RightsFrame->AddXToDirectories;
  501. }
  502. StoreRemoteToken(GroupComboBox, cpGroup, vpGroup, FOrigProperties.Group,
  503. Result.Group, PROPERTIES_INVALID_GROUP, FGroupList, Result);
  504. StoreRemoteToken(OwnerComboBox, cpOwner, vpOwner, FOrigProperties.Owner,
  505. Result.Owner, PROPERTIES_INVALID_OWNER, FUserList, Result);
  506. Result.Recursive = RecursiveCheck2->Checked;
  507. return Result;
  508. }
  509. //---------------------------------------------------------------------------
  510. void __fastcall TPropertiesDialog::ControlChange(TObject * /*Sender*/)
  511. {
  512. if (Visible)
  513. {
  514. UpdateControls();
  515. }
  516. }
  517. //---------------------------------------------------------------------------
  518. void __fastcall TPropertiesDialog::UpdateControls()
  519. {
  520. // No point enabling recursive check if there's no change allowed (supported),
  521. // i.e. with WebDAV.
  522. bool AnyAllowedChanges =
  523. FLAGSET(FAllowedChanges, cpGroup) || FLAGSET(FAllowedChanges, cpOwner) ||
  524. FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl);
  525. EnableControl(RecursiveCheck2, AnyAllowedChanges);
  526. bool Allow;
  527. try
  528. {
  529. Allow =
  530. !TRemoteProperties::ChangedProperties(FOrigProperties, GetFileProperties()).Valid.Empty() ||
  531. (RecursiveCheck2->Enabled && RecursiveCheck2->Checked);
  532. }
  533. catch(...)
  534. {
  535. // when properties are invalid allow submitting the form,
  536. // because that reveals the cause to the user, otherwise he/she
  537. // may not be able to tell what is wrong
  538. Allow = true;
  539. }
  540. EnableControl(OkButton, Allow);
  541. EnableControl(GroupComboBox, FLAGSET(FAllowedChanges, cpGroup));
  542. EnableControl(OwnerComboBox, FLAGSET(FAllowedChanges, cpOwner));
  543. EnableControl(RightsFrame, FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl));
  544. CalculateSizeButton->Visible = FAllowCalculateStats;
  545. if (!FMultiple)
  546. {
  547. // when setting properties for one file only, allow undef state
  548. // only when the input right explicitly requires it or
  549. // when "recursive" is on (possible for directory only).
  550. bool AllowUndef =
  551. (FOrigProperties.Valid.Contains(vpRights) &&
  552. FOrigProperties.Rights.AllowUndef) ||
  553. (RecursiveCheck2->Checked);
  554. if (!AllowUndef)
  555. {
  556. // when disallowing undef state, make sure, all undef are turned into unset
  557. RightsFrame->Rights = TRights(RightsFrame->Rights.NumberSet);
  558. }
  559. RightsFrame->AllowUndef = AllowUndef;
  560. }
  561. EnableControl(ChecksumSheet, ChecksumSupported());
  562. EnableControl(ChecksumButton, ChecksumSheet->Enabled &&
  563. !ChecksumAlgEdit->Text.IsEmpty());
  564. ChecksumEdit->Visible = !ChecksumEdit->Text.IsEmpty();
  565. ChecksumUnknownLabel->Visible = !ChecksumEdit->Visible;
  566. DefaultButton(ChecksumButton, ChecksumAlgEdit->Focused());
  567. DefaultButton(OkButton, !ChecksumAlgEdit->Focused());
  568. }
  569. //---------------------------------------------------------------------------
  570. void __fastcall TPropertiesDialog::FormCloseQuery(TObject * /*Sender*/,
  571. bool & /*CanClose*/)
  572. {
  573. if (ModalResult == DefaultResult())
  574. {
  575. ExitActiveControl(this);
  576. }
  577. }
  578. //---------------------------------------------------------------------------
  579. void __fastcall TPropertiesDialog::CalculateSizeButtonClick(
  580. TObject * /*Sender*/)
  581. {
  582. DebugAssert(FOnCalculateSize != NULL);
  583. bool DoClose = false;
  584. Enabled = false;
  585. try
  586. {
  587. __int64 Size;
  588. TCalculateSizeStats Stats;
  589. FOnCalculateSize(FFileList, Size, Stats, DoClose);
  590. FStatsNotCalculated = false;
  591. LoadStats(Size, Stats);
  592. }
  593. __finally
  594. {
  595. Enabled = true;
  596. if (DoClose)
  597. {
  598. Close();
  599. }
  600. }
  601. }
  602. //---------------------------------------------------------------------------
  603. void __fastcall TPropertiesDialog::HelpButtonClick(TObject * /*Sender*/)
  604. {
  605. FormHelp(this);
  606. }
  607. //---------------------------------------------------------------------------
  608. void __fastcall TPropertiesDialog::ResetChecksum()
  609. {
  610. ChecksumView->Items->Clear();
  611. ChecksumEdit->Text = UnicodeString();
  612. AutoSizeListColumnsWidth(ChecksumView);
  613. }
  614. //---------------------------------------------------------------------------
  615. void __fastcall TPropertiesDialog::CalculateChecksum()
  616. {
  617. DebugAssert(FOnCalculateChecksum != NULL);
  618. ResetChecksum();
  619. FChecksumLoaded = true;
  620. FAlgUsed = UnicodeString();
  621. bool DoClose = false;
  622. try
  623. {
  624. FOnCalculateChecksum(ChecksumAlgEdit->Text, FFileList, CalculatedChecksum, DoClose);
  625. }
  626. __finally
  627. {
  628. if (DoClose)
  629. {
  630. Close();
  631. }
  632. }
  633. // If we successfully used the selected checksum, remember it (in normalized form)
  634. if (!FAlgUsed.IsEmpty())
  635. {
  636. GUIConfiguration->ChecksumAlg = FAlgUsed;
  637. }
  638. AutoSizeListColumnsWidth(ChecksumView);
  639. }
  640. //---------------------------------------------------------------------------
  641. void __fastcall TPropertiesDialog::CalculatedChecksum(
  642. const UnicodeString & FileName, const UnicodeString & Alg,
  643. const UnicodeString & Hash)
  644. {
  645. if (FMultipleChecksum)
  646. {
  647. TListItem * Item = ChecksumView->Items->Add();
  648. Item->Caption = FileName;
  649. Item->SubItems->Add(Hash);
  650. // optimization
  651. int TopIndex = ListView_GetTopIndex(ChecksumView->Handle);
  652. int Index = Item->Index;
  653. if ((TopIndex <= Index) &&
  654. (Index <= TopIndex + ChecksumView->VisibleRowCount))
  655. {
  656. AutoSizeListColumnsWidth(ChecksumView);
  657. }
  658. }
  659. else
  660. {
  661. ChecksumEdit->Text = Hash;
  662. }
  663. FAlgUsed = Alg;
  664. UpdateControls();
  665. }
  666. //---------------------------------------------------------------------------
  667. void __fastcall TPropertiesDialog::NeedChecksum()
  668. {
  669. if (!FChecksumLoaded && ChecksumSupported())
  670. {
  671. CalculateChecksum();
  672. }
  673. }
  674. //---------------------------------------------------------------------------
  675. bool __fastcall TPropertiesDialog::ChecksumSupported()
  676. {
  677. return (FOnCalculateChecksum != NULL);
  678. }
  679. //---------------------------------------------------------------------------
  680. void __fastcall TPropertiesDialog::ChecksumButtonClick(TObject * /*Sender*/)
  681. {
  682. CalculateChecksum();
  683. }
  684. //---------------------------------------------------------------------------
  685. void __fastcall TPropertiesDialog::PageControlChange(TObject * /*Sender*/)
  686. {
  687. if (PageControl->ActivePage == ChecksumSheet)
  688. {
  689. NeedChecksum();
  690. }
  691. }
  692. //---------------------------------------------------------------------------
  693. void __fastcall TPropertiesDialog::ChecksumAlgEditChange(TObject * /*Sender*/)
  694. {
  695. ResetChecksum();
  696. UpdateControls();
  697. }
  698. //---------------------------------------------------------------------------
  699. void __fastcall TPropertiesDialog::CopyClick(TObject * Sender)
  700. {
  701. TInstantOperationVisualizer Visualizer;
  702. TListView * ListView = dynamic_cast<TListView *>(GetPopupComponent(Sender));
  703. DebugAssert(ListView != NULL);
  704. int Count = 0;
  705. UnicodeString SingleText;
  706. UnicodeString Text;
  707. TListItem * Item = ListView->GetNextItem(NULL, sdAll, TItemStates() << isSelected);
  708. while (Item != NULL)
  709. {
  710. DebugAssert(Item->Selected);
  711. SingleText = Item->SubItems->Strings[0];
  712. Text += FORMAT(L"%s = %s\r\n", (Item->Caption, Item->SubItems->Strings[0]));
  713. Count++;
  714. Item = ListView->GetNextItem(Item, sdAll, TItemStates() << isSelected);
  715. }
  716. CopyToClipboard(Count == 1 ? SingleText : Text);
  717. }
  718. //---------------------------------------------------------------------------
  719. void __fastcall TPropertiesDialog::ChecksumViewContextPopup(
  720. TObject * Sender, TPoint & MousePos, bool & Handled)
  721. {
  722. MenuPopup(Sender, MousePos, Handled);
  723. }
  724. //---------------------------------------------------------------------------
  725. void __fastcall TPropertiesDialog::ValidateRemoteToken(
  726. const TRemoteToken & Orig, int Message, TComboBox * ComboBox,
  727. const TRemoteTokenList * List)
  728. {
  729. if (!IsCancelButtonBeingClicked(this))
  730. {
  731. try
  732. {
  733. ComboBox->Text =
  734. LoadRemoteToken(StoreRemoteToken(Orig, ComboBox->Text, Message, List));
  735. }
  736. catch(...)
  737. {
  738. ComboBox->SetFocus();
  739. throw;
  740. }
  741. }
  742. }
  743. //---------------------------------------------------------------------------
  744. void __fastcall TPropertiesDialog::GroupComboBoxExit(TObject * Sender)
  745. {
  746. ValidateRemoteToken(FOrigProperties.Group, PROPERTIES_INVALID_GROUP,
  747. dynamic_cast<TComboBox *>(Sender), FGroupList);
  748. }
  749. //---------------------------------------------------------------------------
  750. void __fastcall TPropertiesDialog::OwnerComboBoxExit(TObject * Sender)
  751. {
  752. ValidateRemoteToken(FOrigProperties.Owner, PROPERTIES_INVALID_OWNER,
  753. dynamic_cast<TComboBox *>(Sender), FUserList);
  754. }
  755. //---------------------------------------------------------------------------
  756. void __fastcall TPropertiesDialog::FormShow(TObject * /*Sender*/)
  757. {
  758. UpdateControls();
  759. }
  760. //---------------------------------------------------------------------------
  761. void __fastcall TPropertiesDialog::CMDpiChanged(TMessage & Message)
  762. {
  763. TForm::Dispatch(&Message);
  764. if (!FMultiple)
  765. {
  766. UpdateFileImage();
  767. }
  768. // WORKAROUND: Mere presence of the RightsFrame breaks automatic layout on DPI change in some situation, fixing it manually.
  769. // (opening on a secondary display with 100%, while primary display has 150%)
  770. SizeLabel->Width = CalculateSizeButton->Left - ScaleByTextHeight(this, 8) - SizeLabel->Left;
  771. Bevel1->Width = CommonSheet->ClientWidth - (Bevel1->Left * 2);
  772. Bevel2->Width = Bevel1->Width;
  773. GroupOwnerRightsBevel->Width = Bevel1->Width;
  774. RecursiveBevel->Width = Bevel1->Width;
  775. }
  776. //---------------------------------------------------------------------------
  777. void __fastcall TPropertiesDialog::Dispatch(void * Message)
  778. {
  779. TMessage * M = reinterpret_cast<TMessage*>(Message);
  780. if (M->Msg == CM_DPICHANGED)
  781. {
  782. CMDpiChanged(*M);
  783. }
  784. else
  785. {
  786. TForm::Dispatch(Message);
  787. }
  788. }
  789. //---------------------------------------------------------------------------