bookmark_undo_service.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/undo/bookmark_undo_service.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/memory/raw_ptr.h"
  10. #include "components/bookmarks/browser/bookmark_node_data.h"
  11. #include "components/bookmarks/browser/bookmark_undo_provider.h"
  12. #include "components/bookmarks/browser/bookmark_utils.h"
  13. #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
  14. #include "components/strings/grit/components_strings.h"
  15. #include "components/undo/undo_operation.h"
  16. using bookmarks::BookmarkModel;
  17. using bookmarks::BookmarkNode;
  18. using bookmarks::BookmarkNodeData;
  19. using bookmarks::BookmarkUndoProvider;
  20. namespace {
  21. // BookmarkUndoOperation ------------------------------------------------------
  22. // Base class for all bookmark related UndoOperations that facilitates access to
  23. // the BookmarkUndoService.
  24. class BookmarkUndoOperation : public UndoOperation {
  25. public:
  26. explicit BookmarkUndoOperation(BookmarkModel* bookmark_model)
  27. : bookmark_model_(bookmark_model) {}
  28. ~BookmarkUndoOperation() override {}
  29. BookmarkModel* bookmark_model() { return bookmark_model_; }
  30. private:
  31. raw_ptr<BookmarkModel> bookmark_model_;
  32. };
  33. // BookmarkAddOperation -------------------------------------------------------
  34. // Handles the undo of the insertion of a bookmark or folder.
  35. class BookmarkAddOperation : public BookmarkUndoOperation {
  36. public:
  37. BookmarkAddOperation(BookmarkModel* bookmark_model,
  38. const BookmarkNode* parent,
  39. size_t index);
  40. BookmarkAddOperation(const BookmarkAddOperation&) = delete;
  41. BookmarkAddOperation& operator=(const BookmarkAddOperation&) = delete;
  42. ~BookmarkAddOperation() override {}
  43. // UndoOperation:
  44. void Undo() override;
  45. int GetUndoLabelId() const override;
  46. int GetRedoLabelId() const override;
  47. private:
  48. int64_t parent_id_;
  49. const size_t index_;
  50. };
  51. BookmarkAddOperation::BookmarkAddOperation(BookmarkModel* bookmark_model,
  52. const BookmarkNode* parent,
  53. size_t index)
  54. : BookmarkUndoOperation(bookmark_model),
  55. parent_id_(parent->id()),
  56. index_(index) {}
  57. void BookmarkAddOperation::Undo() {
  58. BookmarkModel* model = bookmark_model();
  59. const BookmarkNode* parent =
  60. bookmarks::GetBookmarkNodeByID(model, parent_id_);
  61. DCHECK(parent);
  62. model->Remove(parent->children()[index_].get());
  63. }
  64. int BookmarkAddOperation::GetUndoLabelId() const {
  65. return IDS_BOOKMARK_BAR_UNDO_ADD;
  66. }
  67. int BookmarkAddOperation::GetRedoLabelId() const {
  68. return IDS_BOOKMARK_BAR_REDO_DELETE;
  69. }
  70. // BookmarkRemoveOperation ----------------------------------------------------
  71. // Handles the undo of the deletion of a bookmark node. For a bookmark folder,
  72. // the information for all descendant bookmark nodes is maintained.
  73. //
  74. // The BookmarkModel allows only single bookmark node to be removed.
  75. class BookmarkRemoveOperation : public BookmarkUndoOperation {
  76. public:
  77. BookmarkRemoveOperation(BookmarkModel* model,
  78. BookmarkUndoProvider* undo_provider,
  79. const BookmarkNode* parent,
  80. size_t index,
  81. std::unique_ptr<BookmarkNode> node);
  82. BookmarkRemoveOperation(const BookmarkRemoveOperation&) = delete;
  83. BookmarkRemoveOperation& operator=(const BookmarkRemoveOperation&) = delete;
  84. ~BookmarkRemoveOperation() override;
  85. // UndoOperation:
  86. void Undo() override;
  87. int GetUndoLabelId() const override;
  88. int GetRedoLabelId() const override;
  89. private:
  90. raw_ptr<BookmarkUndoProvider> undo_provider_;
  91. const int64_t parent_node_id_;
  92. const size_t index_;
  93. std::unique_ptr<BookmarkNode> node_;
  94. };
  95. BookmarkRemoveOperation::BookmarkRemoveOperation(
  96. BookmarkModel* model,
  97. BookmarkUndoProvider* undo_provider,
  98. const BookmarkNode* parent,
  99. size_t index,
  100. std::unique_ptr<BookmarkNode> node)
  101. : BookmarkUndoOperation(model),
  102. undo_provider_(undo_provider),
  103. parent_node_id_(parent->id()),
  104. index_(index),
  105. node_(std::move(node)) {}
  106. BookmarkRemoveOperation::~BookmarkRemoveOperation() {
  107. }
  108. void BookmarkRemoveOperation::Undo() {
  109. DCHECK(node_);
  110. const BookmarkNode* parent = bookmarks::GetBookmarkNodeByID(
  111. bookmark_model(), parent_node_id_);
  112. DCHECK(parent);
  113. undo_provider_->RestoreRemovedNode(parent, index_, std::move(node_));
  114. }
  115. int BookmarkRemoveOperation::GetUndoLabelId() const {
  116. return IDS_BOOKMARK_BAR_UNDO_DELETE;
  117. }
  118. int BookmarkRemoveOperation::GetRedoLabelId() const {
  119. return IDS_BOOKMARK_BAR_REDO_ADD;
  120. }
  121. // BookmarkEditOperation ------------------------------------------------------
  122. // Handles the undo of the modification of a bookmark node.
  123. class BookmarkEditOperation : public BookmarkUndoOperation {
  124. public:
  125. BookmarkEditOperation(BookmarkModel* bookmark_model,
  126. const BookmarkNode* node);
  127. BookmarkEditOperation(const BookmarkEditOperation&) = delete;
  128. BookmarkEditOperation& operator=(const BookmarkEditOperation&) = delete;
  129. ~BookmarkEditOperation() override {}
  130. // UndoOperation:
  131. void Undo() override;
  132. int GetUndoLabelId() const override;
  133. int GetRedoLabelId() const override;
  134. private:
  135. int64_t node_id_;
  136. BookmarkNodeData original_bookmark_;
  137. };
  138. BookmarkEditOperation::BookmarkEditOperation(
  139. BookmarkModel* bookmark_model,
  140. const BookmarkNode* node)
  141. : BookmarkUndoOperation(bookmark_model),
  142. node_id_(node->id()),
  143. original_bookmark_(node) {
  144. }
  145. void BookmarkEditOperation::Undo() {
  146. DCHECK(original_bookmark_.is_valid());
  147. BookmarkModel* model = bookmark_model();
  148. const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, node_id_);
  149. DCHECK(node);
  150. model->SetTitle(node, original_bookmark_.elements[0].title);
  151. if (original_bookmark_.elements[0].is_url)
  152. model->SetURL(node, original_bookmark_.elements[0].url);
  153. }
  154. int BookmarkEditOperation::GetUndoLabelId() const {
  155. return IDS_BOOKMARK_BAR_UNDO_EDIT;
  156. }
  157. int BookmarkEditOperation::GetRedoLabelId() const {
  158. return IDS_BOOKMARK_BAR_REDO_EDIT;
  159. }
  160. // BookmarkMoveOperation ------------------------------------------------------
  161. // Handles the undo of a bookmark being moved to a new location.
  162. class BookmarkMoveOperation : public BookmarkUndoOperation {
  163. public:
  164. BookmarkMoveOperation(BookmarkModel* bookmark_model,
  165. const BookmarkNode* old_parent,
  166. size_t old_index,
  167. const BookmarkNode* new_parent,
  168. size_t new_index);
  169. BookmarkMoveOperation(const BookmarkMoveOperation&) = delete;
  170. BookmarkMoveOperation& operator=(const BookmarkMoveOperation&) = delete;
  171. ~BookmarkMoveOperation() override {}
  172. int GetUndoLabelId() const override;
  173. int GetRedoLabelId() const override;
  174. // UndoOperation:
  175. void Undo() override;
  176. private:
  177. int64_t old_parent_id_;
  178. int64_t new_parent_id_;
  179. size_t old_index_;
  180. size_t new_index_;
  181. };
  182. BookmarkMoveOperation::BookmarkMoveOperation(BookmarkModel* bookmark_model,
  183. const BookmarkNode* old_parent,
  184. size_t old_index,
  185. const BookmarkNode* new_parent,
  186. size_t new_index)
  187. : BookmarkUndoOperation(bookmark_model),
  188. old_parent_id_(old_parent->id()),
  189. new_parent_id_(new_parent->id()),
  190. old_index_(old_index),
  191. new_index_(new_index) {}
  192. void BookmarkMoveOperation::Undo() {
  193. BookmarkModel* model = bookmark_model();
  194. const BookmarkNode* old_parent =
  195. bookmarks::GetBookmarkNodeByID(model, old_parent_id_);
  196. const BookmarkNode* new_parent =
  197. bookmarks::GetBookmarkNodeByID(model, new_parent_id_);
  198. DCHECK(old_parent);
  199. DCHECK(new_parent);
  200. const BookmarkNode* node = new_parent->children()[new_index_].get();
  201. size_t destination_index = old_index_;
  202. // If the bookmark was moved up within the same parent then the destination
  203. // index needs to be incremented since the old index did not account for the
  204. // moved bookmark.
  205. if (old_parent == new_parent && new_index_ < old_index_)
  206. ++destination_index;
  207. model->Move(node, old_parent, destination_index);
  208. }
  209. int BookmarkMoveOperation::GetUndoLabelId() const {
  210. return IDS_BOOKMARK_BAR_UNDO_MOVE;
  211. }
  212. int BookmarkMoveOperation::GetRedoLabelId() const {
  213. return IDS_BOOKMARK_BAR_REDO_MOVE;
  214. }
  215. // BookmarkReorderOperation ---------------------------------------------------
  216. // Handle the undo of reordering of bookmarks that can happen as a result of
  217. // sorting a bookmark folder by name or the undo of that operation. The change
  218. // of order is not recursive so only the order of the immediate children of the
  219. // folder need to be restored.
  220. class BookmarkReorderOperation : public BookmarkUndoOperation {
  221. public:
  222. BookmarkReorderOperation(BookmarkModel* bookmark_model,
  223. const BookmarkNode* parent);
  224. BookmarkReorderOperation(const BookmarkReorderOperation&) = delete;
  225. BookmarkReorderOperation& operator=(const BookmarkReorderOperation&) = delete;
  226. ~BookmarkReorderOperation() override;
  227. // UndoOperation:
  228. void Undo() override;
  229. int GetUndoLabelId() const override;
  230. int GetRedoLabelId() const override;
  231. private:
  232. int64_t parent_id_;
  233. std::vector<int64_t> ordered_bookmarks_;
  234. };
  235. BookmarkReorderOperation::BookmarkReorderOperation(
  236. BookmarkModel* bookmark_model,
  237. const BookmarkNode* parent)
  238. : BookmarkUndoOperation(bookmark_model),
  239. parent_id_(parent->id()) {
  240. ordered_bookmarks_.resize(parent->children().size());
  241. std::transform(parent->children().cbegin(), parent->children().cend(),
  242. ordered_bookmarks_.begin(),
  243. [](const auto& child) { return child->id(); });
  244. }
  245. BookmarkReorderOperation::~BookmarkReorderOperation() {
  246. }
  247. void BookmarkReorderOperation::Undo() {
  248. BookmarkModel* model = bookmark_model();
  249. const BookmarkNode* parent =
  250. bookmarks::GetBookmarkNodeByID(model, parent_id_);
  251. DCHECK(parent);
  252. std::vector<const BookmarkNode*> ordered_nodes;
  253. for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) {
  254. ordered_nodes.push_back(
  255. bookmarks::GetBookmarkNodeByID(model, ordered_bookmarks_[i]));
  256. }
  257. model->ReorderChildren(parent, ordered_nodes);
  258. }
  259. int BookmarkReorderOperation::GetUndoLabelId() const {
  260. return IDS_BOOKMARK_BAR_UNDO_REORDER;
  261. }
  262. int BookmarkReorderOperation::GetRedoLabelId() const {
  263. return IDS_BOOKMARK_BAR_REDO_REORDER;
  264. }
  265. } // namespace
  266. // BookmarkUndoService --------------------------------------------------------
  267. BookmarkUndoService::BookmarkUndoService() : model_(nullptr) {}
  268. BookmarkUndoService::~BookmarkUndoService() {
  269. }
  270. void BookmarkUndoService::Start(BookmarkModel* model) {
  271. DCHECK(!model_);
  272. model_ = model;
  273. scoped_observation_.Observe(model);
  274. model->SetUndoDelegate(this);
  275. }
  276. void BookmarkUndoService::Shutdown() {
  277. DCHECK(model_);
  278. DCHECK(scoped_observation_.IsObserving());
  279. scoped_observation_.Reset();
  280. model_->SetUndoDelegate(nullptr);
  281. }
  282. void BookmarkUndoService::BookmarkModelLoaded(BookmarkModel* model,
  283. bool ids_reassigned) {
  284. undo_manager_.RemoveAllOperations();
  285. }
  286. void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel* model) {
  287. undo_manager_.RemoveAllOperations();
  288. }
  289. void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel* model,
  290. const BookmarkNode* old_parent,
  291. size_t old_index,
  292. const BookmarkNode* new_parent,
  293. size_t new_index) {
  294. std::unique_ptr<UndoOperation> op(new BookmarkMoveOperation(
  295. model, old_parent, old_index, new_parent, new_index));
  296. undo_manager()->AddUndoOperation(std::move(op));
  297. }
  298. void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model,
  299. const BookmarkNode* parent,
  300. size_t index) {
  301. std::unique_ptr<UndoOperation> op(
  302. new BookmarkAddOperation(model, parent, index));
  303. undo_manager()->AddUndoOperation(std::move(op));
  304. }
  305. void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel* model,
  306. const BookmarkNode* node) {
  307. std::unique_ptr<UndoOperation> op(new BookmarkEditOperation(model, node));
  308. undo_manager()->AddUndoOperation(std::move(op));
  309. }
  310. void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel* model,
  311. const BookmarkNode* node) {
  312. std::unique_ptr<UndoOperation> op(new BookmarkReorderOperation(model, node));
  313. undo_manager()->AddUndoOperation(std::move(op));
  314. }
  315. void BookmarkUndoService::GroupedBookmarkChangesBeginning(
  316. BookmarkModel* model) {
  317. undo_manager()->StartGroupingActions();
  318. }
  319. void BookmarkUndoService::GroupedBookmarkChangesEnded(BookmarkModel* model) {
  320. undo_manager()->EndGroupingActions();
  321. }
  322. void BookmarkUndoService::SetUndoProvider(BookmarkUndoProvider* undo_provider) {
  323. undo_provider_ = undo_provider;
  324. }
  325. void BookmarkUndoService::OnBookmarkNodeRemoved(
  326. BookmarkModel* model,
  327. const BookmarkNode* parent,
  328. size_t index,
  329. std::unique_ptr<BookmarkNode> node) {
  330. DCHECK(undo_provider_);
  331. std::unique_ptr<UndoOperation> op(new BookmarkRemoveOperation(
  332. model, undo_provider_, parent, index, std::move(node)));
  333. undo_manager()->AddUndoOperation(std::move(op));
  334. }