Bookmarks.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. //---------------------------------------------------------------------------
  2. #include <CorePCH.h>
  3. #pragma hdrstop
  4. #include "NamedObjs.h"
  5. #include "Bookmarks.h"
  6. #include "Configuration.h"
  7. #include "HierarchicalStorage.h"
  8. //---------------------------------------------------------------------------
  9. #pragma package(smart_init)
  10. //---------------------------------------------------------------------------
  11. __fastcall TBookmarks::TBookmarks(): TObject()
  12. {
  13. FSharedKey = TNamedObjectList::HiddenPrefix + L"shared";
  14. FBookmarkLists = CreateSortedStringList(false, Types::dupError);
  15. }
  16. //---------------------------------------------------------------------------
  17. __fastcall TBookmarks::~TBookmarks()
  18. {
  19. Clear();
  20. SAFE_DESTROY(FBookmarkLists);
  21. }
  22. //---------------------------------------------------------------------------
  23. void __fastcall TBookmarks::Clear()
  24. {
  25. for (int i = 0; i < FBookmarkLists->Count; i++)
  26. {
  27. delete FBookmarkLists->Objects[i];
  28. }
  29. FBookmarkLists->Clear();
  30. }
  31. //---------------------------------------------------------------------------
  32. UnicodeString TBookmarks::Keys[] = { L"Local", L"Remote", L"ShortCuts", L"Options" };
  33. //---------------------------------------------------------------------------
  34. void __fastcall TBookmarks::Load(THierarchicalStorage * Storage)
  35. {
  36. for (int i = 0; i <= 3; i++)
  37. {
  38. if (Storage->OpenSubKey(Keys[i], false))
  39. {
  40. TStrings * BookmarkKeys = new TStringList();
  41. try
  42. {
  43. Storage->GetSubKeyNames(BookmarkKeys);
  44. for (int Index = 0; Index < BookmarkKeys->Count; Index++)
  45. {
  46. UnicodeString Key = BookmarkKeys->Strings[Index];
  47. if (Storage->OpenSubKey(Key, false))
  48. {
  49. TBookmarkList * BookmarkList = Bookmarks[Key];
  50. if (!BookmarkList)
  51. {
  52. BookmarkList = new TBookmarkList();
  53. FBookmarkLists->AddObject(Key, BookmarkList);
  54. }
  55. if (i < 3)
  56. {
  57. LoadLevel(Storage, L"", i, BookmarkList);
  58. }
  59. else
  60. {
  61. BookmarkList->LoadOptions(Storage);
  62. }
  63. Storage->CloseSubKey();
  64. }
  65. }
  66. }
  67. __finally
  68. {
  69. delete BookmarkKeys;
  70. }
  71. Storage->CloseSubKey();
  72. }
  73. }
  74. ModifyAll(false);
  75. }
  76. //---------------------------------------------------------------------------
  77. void __fastcall TBookmarks::LoadLevel(THierarchicalStorage * Storage, const UnicodeString Key,
  78. int Index, TBookmarkList * BookmarkList)
  79. {
  80. TStrings * Names = new TStringList();
  81. try
  82. {
  83. Storage->GetValueNames(Names);
  84. UnicodeString Name;
  85. UnicodeString Directory;
  86. TShortCut ShortCut = TShortCut();
  87. for (int i = 0; i < Names->Count; i++)
  88. {
  89. Name = Names->Strings[i];
  90. bool IsDirectory = (Index == 0) || (Index == 1);
  91. if (IsDirectory)
  92. {
  93. Directory = Storage->ReadString(Name, L"");
  94. }
  95. else
  96. {
  97. Directory = L""; // use only in case of malformed config
  98. ShortCut = (TShortCut)Storage->ReadInteger(Name, 0);
  99. }
  100. TBookmark * Bookmark;
  101. if (IsNumber(Name))
  102. {
  103. DebugAssert(IsDirectory); // unless malformed
  104. Name = Directory;
  105. }
  106. if (!Name.IsEmpty())
  107. {
  108. Bookmark = BookmarkList->FindByName(Key, Name);
  109. bool New;
  110. New = (Bookmark == NULL);
  111. if (New)
  112. {
  113. Bookmark = new TBookmark();
  114. Bookmark->Node = Key;
  115. Bookmark->Name = Name;
  116. }
  117. switch (Index)
  118. {
  119. case 0:
  120. Bookmark->Local = Directory;
  121. break;
  122. case 1:
  123. Bookmark->Remote = Directory;
  124. break;
  125. case 2:
  126. Bookmark->ShortCut = ShortCut;
  127. break;
  128. }
  129. if (New)
  130. {
  131. BookmarkList->Add(Bookmark);
  132. }
  133. }
  134. }
  135. Storage->GetSubKeyNames(Names);
  136. for (int i = 0; i < Names->Count; i++)
  137. {
  138. Name = Names->Strings[i];
  139. if (Storage->OpenSubKey(Name, false))
  140. {
  141. LoadLevel(Storage, Key + (Key.IsEmpty() ? L"" : L"/") + Name, Index, BookmarkList);
  142. Storage->CloseSubKey();
  143. }
  144. }
  145. }
  146. __finally
  147. {
  148. delete Names;
  149. }
  150. }
  151. //---------------------------------------------------------------------------
  152. void __fastcall TBookmarks::Save(THierarchicalStorage * Storage, bool All)
  153. {
  154. for (int i = 0; i <= 3; i++)
  155. {
  156. if (Storage->OpenSubKey(Keys[i], true))
  157. {
  158. for (int Index = 0; Index < FBookmarkLists->Count; Index++)
  159. {
  160. TBookmarkList * BookmarkList = dynamic_cast<TBookmarkList *>(FBookmarkLists->Objects[Index]);
  161. if (All || BookmarkList->Modified)
  162. {
  163. UnicodeString Key = FBookmarkLists->Strings[Index];
  164. Storage->RecursiveDeleteSubKey(Key);
  165. if (Storage->OpenSubKey(Key, true))
  166. {
  167. if (i < 3)
  168. {
  169. for (int IndexB = 0; IndexB < BookmarkList->Count; IndexB++)
  170. {
  171. TBookmark * Bookmark = BookmarkList->Bookmarks[IndexB];
  172. // avoid creating empty subfolder if there's no shortcut
  173. if ((i == 0) || (i == 1) ||
  174. ((i == 2) && (Bookmark->ShortCut != 0)))
  175. {
  176. bool HasNode = !Bookmark->Node.IsEmpty();
  177. if (!HasNode || Storage->OpenSubKey(Bookmark->Node, true))
  178. {
  179. switch (i)
  180. {
  181. case 0:
  182. Storage->WriteString(Bookmark->Name, Bookmark->Local);
  183. break;
  184. case 1:
  185. Storage->WriteString(Bookmark->Name, Bookmark->Remote);
  186. break;
  187. case 2:
  188. DebugAssert(Bookmark->ShortCut != 0);
  189. Storage->WriteInteger(Bookmark->Name, Bookmark->ShortCut);
  190. break;
  191. }
  192. if (HasNode)
  193. {
  194. Storage->CloseSubKey();
  195. }
  196. }
  197. }
  198. }
  199. }
  200. else
  201. {
  202. BookmarkList->SaveOptions(Storage);
  203. }
  204. Storage->CloseSubKey();
  205. }
  206. }
  207. }
  208. Storage->CloseSubKey();
  209. }
  210. }
  211. if (!All)
  212. {
  213. ModifyAll(false);
  214. }
  215. }
  216. //---------------------------------------------------------------------------
  217. void __fastcall TBookmarks::ModifyAll(bool Modify)
  218. {
  219. TBookmarkList * BookmarkList;
  220. for (int i = 0; i < FBookmarkLists->Count; i++)
  221. {
  222. BookmarkList = dynamic_cast<TBookmarkList *>(FBookmarkLists->Objects[i]);
  223. DebugAssert(BookmarkList);
  224. BookmarkList->Modified = Modify;
  225. }
  226. }
  227. //---------------------------------------------------------------------------
  228. TBookmarkList * __fastcall TBookmarks::GetBookmarks(UnicodeString Index)
  229. {
  230. int I = FBookmarkLists->IndexOf(Index);
  231. if (I >= 0)
  232. {
  233. return dynamic_cast<TBookmarkList *>(FBookmarkLists->Objects[I]);
  234. }
  235. else
  236. {
  237. return NULL;
  238. }
  239. }
  240. //---------------------------------------------------------------------------
  241. void __fastcall TBookmarks::SetBookmarks(UnicodeString Index, TBookmarkList * value)
  242. {
  243. int I = FBookmarkLists->IndexOf(Index);
  244. if (I >= 0)
  245. {
  246. TBookmarkList * BookmarkList;
  247. BookmarkList = dynamic_cast<TBookmarkList *>(FBookmarkLists->Objects[I]);
  248. BookmarkList->Assign(value);
  249. }
  250. else
  251. {
  252. TBookmarkList * BookmarkList = new TBookmarkList();
  253. BookmarkList->Assign(value);
  254. FBookmarkLists->AddObject(Index, BookmarkList);
  255. }
  256. }
  257. //---------------------------------------------------------------------------
  258. TBookmarkList * __fastcall TBookmarks::GetSharedBookmarks()
  259. {
  260. return GetBookmarks(FSharedKey);
  261. }
  262. //---------------------------------------------------------------------------
  263. void __fastcall TBookmarks::SetSharedBookmarks(TBookmarkList * value)
  264. {
  265. SetBookmarks(FSharedKey, value);
  266. }
  267. //---------------------------------------------------------------------------
  268. //---------------------------------------------------------------------------
  269. __fastcall TBookmarkList::TBookmarkList(): TPersistent()
  270. {
  271. FModified = false;
  272. FBookmarks = new TStringList();
  273. FBookmarks->CaseSensitive = false;
  274. FOpenedNodes = CreateSortedStringList();
  275. }
  276. //---------------------------------------------------------------------------
  277. __fastcall TBookmarkList::~TBookmarkList()
  278. {
  279. Clear();
  280. SAFE_DESTROY(FBookmarks);
  281. SAFE_DESTROY(FOpenedNodes);
  282. }
  283. //---------------------------------------------------------------------------
  284. void __fastcall TBookmarkList::Clear()
  285. {
  286. for (int i = 0; i < FBookmarks->Count; i++)
  287. {
  288. delete FBookmarks->Objects[i];
  289. }
  290. FBookmarks->Clear();
  291. FOpenedNodes->Clear();
  292. }
  293. //---------------------------------------------------------------------------
  294. void __fastcall TBookmarkList::Assign(TPersistent * Source)
  295. {
  296. TBookmarkList * SourceList;
  297. SourceList = dynamic_cast<TBookmarkList *>(Source);
  298. if (SourceList)
  299. {
  300. Clear();
  301. for (int i = 0; i < SourceList->FBookmarks->Count; i++)
  302. {
  303. TBookmark * Bookmark = new TBookmark();
  304. Bookmark->Assign(dynamic_cast<TBookmark *>(SourceList->FBookmarks->Objects[i]));
  305. Add(Bookmark);
  306. }
  307. FOpenedNodes->Assign(SourceList->FOpenedNodes);
  308. Modified = SourceList->Modified;
  309. }
  310. else
  311. {
  312. TPersistent::Assign(Source);
  313. }
  314. }
  315. //---------------------------------------------------------------------------
  316. void __fastcall TBookmarkList::LoadOptions(THierarchicalStorage * Storage)
  317. {
  318. FOpenedNodes->CommaText = Storage->ReadString(L"OpenedNodes", L"");
  319. }
  320. //---------------------------------------------------------------------------
  321. void __fastcall TBookmarkList::SaveOptions(THierarchicalStorage * Storage)
  322. {
  323. Storage->WriteString(L"OpenedNodes", FOpenedNodes->CommaText);
  324. }
  325. //---------------------------------------------------------------------------
  326. void __fastcall TBookmarkList::Add(TBookmark * Bookmark)
  327. {
  328. Insert(Count, Bookmark);
  329. }
  330. //---------------------------------------------------------------------------
  331. void __fastcall TBookmarkList::InsertBefore(TBookmark * BeforeBookmark, TBookmark * Bookmark)
  332. {
  333. DebugAssert(BeforeBookmark);
  334. int I = FBookmarks->IndexOf(BeforeBookmark->Key);
  335. DebugAssert(I >= 0);
  336. Insert(I, Bookmark);
  337. }
  338. //---------------------------------------------------------------------------
  339. void __fastcall TBookmarkList::MoveTo(TBookmark * ToBookmark,
  340. TBookmark * Bookmark, bool Before)
  341. {
  342. DebugAssert(ToBookmark != NULL);
  343. int NewIndex = FBookmarks->IndexOf(ToBookmark->Key);
  344. DebugAssert(Bookmark != NULL);
  345. int OldIndex = FBookmarks->IndexOf(Bookmark->Key);
  346. if (Before && (NewIndex > OldIndex))
  347. {
  348. // otherwise item is moved after the item in the target index
  349. NewIndex--;
  350. }
  351. else if (!Before && (NewIndex < OldIndex))
  352. {
  353. NewIndex++;
  354. }
  355. FModified = true;
  356. FBookmarks->Move(OldIndex, NewIndex);
  357. }
  358. //---------------------------------------------------------------------------
  359. void __fastcall TBookmarkList::Insert(int Index, TBookmark * Bookmark)
  360. {
  361. DebugAssert(Bookmark);
  362. DebugAssert(!Bookmark->FOwner);
  363. DebugAssert(!Bookmark->Name.IsEmpty());
  364. FModified = true;
  365. Bookmark->FOwner = this;
  366. if (FBookmarks->IndexOf(Bookmark->Key) >= 0)
  367. {
  368. throw Exception(FMTLOAD(DUPLICATE_BOOKMARK, (Bookmark->Name)));
  369. }
  370. FBookmarks->InsertObject(Index, Bookmark->Key, Bookmark);
  371. }
  372. //---------------------------------------------------------------------------
  373. void __fastcall TBookmarkList::Delete(TBookmark * Bookmark)
  374. {
  375. DebugAssert(Bookmark);
  376. DebugAssert(Bookmark->FOwner == this);
  377. int I = IndexOf(Bookmark);
  378. DebugAssert(I >= 0);
  379. FModified = true;
  380. Bookmark->FOwner = NULL;
  381. FBookmarks->Delete(I);
  382. delete Bookmark;
  383. }
  384. //---------------------------------------------------------------------------
  385. int __fastcall TBookmarkList::IndexOf(TBookmark * Bookmark)
  386. {
  387. return FBookmarks->IndexOf(Bookmark->Key);
  388. }
  389. //---------------------------------------------------------------------------
  390. void __fastcall TBookmarkList::KeyChanged(int Index)
  391. {
  392. DebugAssert(Index < Count);
  393. TBookmark * Bookmark = dynamic_cast<TBookmark *>(FBookmarks->Objects[Index]);
  394. DebugAssert(FBookmarks->Strings[Index] != Bookmark->Key);
  395. if (FBookmarks->IndexOf(Bookmark->Key) >= 0)
  396. {
  397. throw Exception(FMTLOAD(DUPLICATE_BOOKMARK, (Bookmark->Name)));
  398. }
  399. FBookmarks->Strings[Index] = Bookmark->Key;
  400. }
  401. //---------------------------------------------------------------------------
  402. TBookmark * __fastcall TBookmarkList::FindByName(const UnicodeString Node, const UnicodeString Name)
  403. {
  404. int I = FBookmarks->IndexOf(TBookmark::BookmarkKey(Node, Name));
  405. TBookmark * Bookmark = I >= 0 ? dynamic_cast<TBookmark *>(FBookmarks->Objects[I]) : NULL;
  406. DebugAssert(!Bookmark || (Bookmark->Node == Node && Bookmark->Name == Name));
  407. return Bookmark;
  408. }
  409. //---------------------------------------------------------------------------
  410. TBookmark * __fastcall TBookmarkList::FindByShortCut(TShortCut ShortCut)
  411. {
  412. for (int Index = 0; Index < FBookmarks->Count; Index++)
  413. {
  414. if (Bookmarks[Index]->ShortCut == ShortCut)
  415. {
  416. return Bookmarks[Index];
  417. }
  418. }
  419. return NULL;
  420. }
  421. //---------------------------------------------------------------------------
  422. int __fastcall TBookmarkList::GetCount()
  423. {
  424. return FBookmarks->Count;
  425. }
  426. //---------------------------------------------------------------------------
  427. TBookmark * __fastcall TBookmarkList::GetBookmarks(int Index)
  428. {
  429. TBookmark * Bookmark = dynamic_cast<TBookmark *>(FBookmarks->Objects[Index]);
  430. DebugAssert(Bookmark);
  431. return Bookmark;
  432. }
  433. //---------------------------------------------------------------------------
  434. bool __fastcall TBookmarkList::GetNodeOpened(UnicodeString Index)
  435. {
  436. return (FOpenedNodes->IndexOf(Index) >= 0);
  437. }
  438. //---------------------------------------------------------------------------
  439. void __fastcall TBookmarkList::SetNodeOpened(UnicodeString Index, bool value)
  440. {
  441. int I = FOpenedNodes->IndexOf(Index);
  442. if ((I >= 0) != value)
  443. {
  444. if (value)
  445. {
  446. FOpenedNodes->Add(Index);
  447. }
  448. else
  449. {
  450. FOpenedNodes->Delete(I);
  451. }
  452. FModified = true;
  453. }
  454. }
  455. //---------------------------------------------------------------------------
  456. void __fastcall TBookmarkList::ShortCuts(TShortCuts & ShortCuts)
  457. {
  458. for (int Index = 0; Index < Count; Index++)
  459. {
  460. TBookmark * Bookmark = Bookmarks[Index];
  461. if (Bookmark->ShortCut != 0)
  462. {
  463. ShortCuts.Add(Bookmark->ShortCut);
  464. }
  465. }
  466. }
  467. //---------------------------------------------------------------------------
  468. //---------------------------------------------------------------------------
  469. __fastcall TBookmark::TBookmark()
  470. {
  471. FOwner = NULL;
  472. }
  473. //---------------------------------------------------------------------------
  474. void __fastcall TBookmark::Assign(TPersistent * Source)
  475. {
  476. TBookmark * SourceBookmark;
  477. SourceBookmark = dynamic_cast<TBookmark *>(Source);
  478. if (SourceBookmark)
  479. {
  480. Name = SourceBookmark->Name;
  481. Local = SourceBookmark->Local;
  482. Remote = SourceBookmark->Remote;
  483. Node = SourceBookmark->Node;
  484. ShortCut = SourceBookmark->ShortCut;
  485. }
  486. else
  487. {
  488. TPersistent::Assign(Source);
  489. }
  490. }
  491. //---------------------------------------------------------------------------
  492. void __fastcall TBookmark::SetName(const UnicodeString value)
  493. {
  494. if (Name != value)
  495. {
  496. int OldIndex = FOwner ? FOwner->IndexOf(this) : -1;
  497. UnicodeString OldName = FName;
  498. FName = value;
  499. try
  500. {
  501. Modify(OldIndex);
  502. }
  503. catch(...)
  504. {
  505. FName = OldName;
  506. throw;
  507. }
  508. }
  509. }
  510. //---------------------------------------------------------------------------
  511. void __fastcall TBookmark::SetLocal(const UnicodeString value)
  512. {
  513. if (Local != value)
  514. {
  515. FLocal = value;
  516. Modify(-1);
  517. }
  518. }
  519. //---------------------------------------------------------------------------
  520. void __fastcall TBookmark::SetRemote(const UnicodeString value)
  521. {
  522. if (Remote != value)
  523. {
  524. FRemote = value;
  525. Modify(-1);
  526. }
  527. }
  528. //---------------------------------------------------------------------------
  529. void __fastcall TBookmark::SetNode(const UnicodeString value)
  530. {
  531. if (Node != value)
  532. {
  533. int OldIndex = FOwner ? FOwner->IndexOf(this) : -1;
  534. FNode = value;
  535. Modify(OldIndex);
  536. }
  537. }
  538. //---------------------------------------------------------------------------
  539. void __fastcall TBookmark::SetShortCut(TShortCut value)
  540. {
  541. if (ShortCut != value)
  542. {
  543. FShortCut = value;
  544. Modify(-1);
  545. }
  546. }
  547. //---------------------------------------------------------------------------
  548. void __fastcall TBookmark::Modify(int OldIndex)
  549. {
  550. if (FOwner)
  551. {
  552. FOwner->Modified = true;
  553. if (OldIndex >= 0)
  554. {
  555. FOwner->KeyChanged(OldIndex);
  556. }
  557. }
  558. }
  559. //---------------------------------------------------------------------------
  560. UnicodeString __fastcall TBookmark::BookmarkKey(const UnicodeString Node, const UnicodeString Name)
  561. {
  562. return FORMAT(L"%s\1%s", (Node, Name));
  563. }
  564. //---------------------------------------------------------------------------
  565. UnicodeString __fastcall TBookmark::GetKey()
  566. {
  567. return BookmarkKey(Node, Name);
  568. }
  569. //---------------------------------------------------------------------------
  570. UnicodeString __fastcall TBookmark::GetSideDirectory(TOperationSide Side)
  571. {
  572. return (Side == osLocal) ? Local : Remote;
  573. }