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.
5 #include "components/undo/bookmark_undo_service.h"
7 #include "components/bookmarks/browser/bookmark_model.h"
8 #include "components/bookmarks/browser/bookmark_node_data.h"
9 #include "components/bookmarks/browser/bookmark_utils.h"
10 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h"
11 #include "components/undo/bookmark_renumber_observer.h"
12 #include "components/undo/undo_operation.h"
13 #include "grit/components_strings.h"
15 using bookmarks::BookmarkModel
;
16 using bookmarks::BookmarkNode
;
17 using bookmarks::BookmarkNodeData
;
21 // BookmarkUndoOperation ------------------------------------------------------
23 // Base class for all bookmark related UndoOperations that facilitates access to
24 // the BookmarkUndoService.
25 class BookmarkUndoOperation
: public UndoOperation
,
26 public BookmarkRenumberObserver
{
28 BookmarkUndoOperation(BookmarkModel
* bookmark_model
,
29 BookmarkRenumberObserver
* undo_renumber_observer
)
30 : bookmark_model_(bookmark_model
),
31 undo_renumber_observer_(undo_renumber_observer
) {}
32 ~BookmarkUndoOperation() override
{}
34 BookmarkModel
* bookmark_model() { return bookmark_model_
; }
36 BookmarkRenumberObserver
* undo_renumber_observer() {
37 return undo_renumber_observer_
;
41 BookmarkModel
* bookmark_model_
;
42 BookmarkRenumberObserver
* undo_renumber_observer_
;
45 // BookmarkAddOperation -------------------------------------------------------
47 // Handles the undo of the insertion of a bookmark or folder.
48 class BookmarkAddOperation
: public BookmarkUndoOperation
{
50 BookmarkAddOperation(BookmarkModel
* bookmark_model
,
51 BookmarkRenumberObserver
* undo_renumber_observer
,
52 const BookmarkNode
* parent
,
54 ~BookmarkAddOperation() override
{}
58 int GetUndoLabelId() const override
;
59 int GetRedoLabelId() const override
;
61 // BookmarkRenumberObserver:
62 void OnBookmarkRenumbered(int64 old_id
, int64 new_id
) override
;
68 DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation
);
71 BookmarkAddOperation::BookmarkAddOperation(
72 BookmarkModel
* bookmark_model
,
73 BookmarkRenumberObserver
* undo_renumber_observer
,
74 const BookmarkNode
* parent
,
76 : BookmarkUndoOperation(bookmark_model
, undo_renumber_observer
),
77 parent_id_(parent
->id()),
81 void BookmarkAddOperation::Undo() {
82 BookmarkModel
* model
= bookmark_model();
83 const BookmarkNode
* parent
=
84 bookmarks::GetBookmarkNodeByID(model
, parent_id_
);
87 model
->Remove(parent
->GetChild(index_
));
90 int BookmarkAddOperation::GetUndoLabelId() const {
91 return IDS_BOOKMARK_BAR_UNDO_ADD
;
94 int BookmarkAddOperation::GetRedoLabelId() const {
95 return IDS_BOOKMARK_BAR_REDO_DELETE
;
98 void BookmarkAddOperation::OnBookmarkRenumbered(int64 old_id
, int64 new_id
) {
99 if (parent_id_
== old_id
)
103 // BookmarkRemoveOperation ----------------------------------------------------
105 // Handles the undo of the deletion of a bookmark node. For a bookmark folder,
106 // the information for all descendant bookmark nodes is maintained.
108 // The BookmarkModel allows only single bookmark node to be removed.
109 class BookmarkRemoveOperation
: public BookmarkUndoOperation
{
111 BookmarkRemoveOperation(BookmarkModel
* bookmark_model
,
112 BookmarkRenumberObserver
* undo_renumber_observer
,
113 const BookmarkNode
* parent
,
115 const BookmarkNode
* node
);
116 ~BookmarkRemoveOperation() override
{}
119 void Undo() override
;
120 int GetUndoLabelId() const override
;
121 int GetRedoLabelId() const override
;
123 // BookmarkRenumberObserver:
124 void OnBookmarkRenumbered(int64 old_id
, int64 new_id
) override
;
127 void UpdateBookmarkIds(const BookmarkNodeData::Element
& element
,
128 const BookmarkNode
* parent
,
132 const int old_index_
;
133 BookmarkNodeData removed_node_
;
135 DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation
);
138 BookmarkRemoveOperation::BookmarkRemoveOperation(
139 BookmarkModel
* bookmark_model
,
140 BookmarkRenumberObserver
* undo_renumber_observer
,
141 const BookmarkNode
* parent
,
143 const BookmarkNode
* node
)
144 : BookmarkUndoOperation(bookmark_model
, undo_renumber_observer
),
145 parent_id_(parent
->id()),
146 old_index_(old_index
),
147 removed_node_(node
) {
150 void BookmarkRemoveOperation::Undo() {
151 DCHECK(removed_node_
.is_valid());
152 BookmarkModel
* model
= bookmark_model();
153 const BookmarkNode
* parent
=
154 bookmarks::GetBookmarkNodeByID(model
, parent_id_
);
157 bookmarks::CloneBookmarkNode(
158 model
, removed_node_
.elements
, parent
, old_index_
, false);
159 UpdateBookmarkIds(removed_node_
.elements
[0], parent
, old_index_
);
162 int BookmarkRemoveOperation::GetUndoLabelId() const {
163 return IDS_BOOKMARK_BAR_UNDO_DELETE
;
166 int BookmarkRemoveOperation::GetRedoLabelId() const {
167 return IDS_BOOKMARK_BAR_REDO_ADD
;
170 void BookmarkRemoveOperation::UpdateBookmarkIds(
171 const BookmarkNodeData::Element
& element
,
172 const BookmarkNode
* parent
,
173 int index_added_at
) {
174 const BookmarkNode
* node
= parent
->GetChild(index_added_at
);
175 if (element
.id() != node
->id())
176 undo_renumber_observer()->OnBookmarkRenumbered(element
.id(), node
->id());
177 if (!element
.is_url
) {
178 for (int i
= 0; i
< static_cast<int>(element
.children
.size()); ++i
)
179 UpdateBookmarkIds(element
.children
[i
], node
, i
);
183 void BookmarkRemoveOperation::OnBookmarkRenumbered(int64 old_id
, int64 new_id
) {
184 if (parent_id_
== old_id
)
188 // BookmarkEditOperation ------------------------------------------------------
190 // Handles the undo of the modification of a bookmark node.
191 class BookmarkEditOperation
: public BookmarkUndoOperation
{
193 BookmarkEditOperation(BookmarkModel
* bookmark_model
,
194 BookmarkRenumberObserver
* undo_renumber_observer
,
195 const BookmarkNode
* node
);
196 ~BookmarkEditOperation() override
{}
199 void Undo() override
;
200 int GetUndoLabelId() const override
;
201 int GetRedoLabelId() const override
;
203 // BookmarkRenumberObserver:
204 void OnBookmarkRenumbered(int64 old_id
, int64 new_id
) override
;
208 BookmarkNodeData original_bookmark_
;
210 DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation
);
213 BookmarkEditOperation::BookmarkEditOperation(
214 BookmarkModel
* bookmark_model
,
215 BookmarkRenumberObserver
* undo_renumber_observer
,
216 const BookmarkNode
* node
)
217 : BookmarkUndoOperation(bookmark_model
, undo_renumber_observer
),
218 node_id_(node
->id()),
219 original_bookmark_(node
) {
222 void BookmarkEditOperation::Undo() {
223 DCHECK(original_bookmark_
.is_valid());
224 BookmarkModel
* model
= bookmark_model();
225 const BookmarkNode
* node
= bookmarks::GetBookmarkNodeByID(model
, node_id_
);
228 model
->SetTitle(node
, original_bookmark_
.elements
[0].title
);
229 if (original_bookmark_
.elements
[0].is_url
)
230 model
->SetURL(node
, original_bookmark_
.elements
[0].url
);
233 int BookmarkEditOperation::GetUndoLabelId() const {
234 return IDS_BOOKMARK_BAR_UNDO_EDIT
;
237 int BookmarkEditOperation::GetRedoLabelId() const {
238 return IDS_BOOKMARK_BAR_REDO_EDIT
;
241 void BookmarkEditOperation::OnBookmarkRenumbered(int64 old_id
, int64 new_id
) {
242 if (node_id_
== old_id
)
246 // BookmarkMoveOperation ------------------------------------------------------
248 // Handles the undo of a bookmark being moved to a new location.
249 class BookmarkMoveOperation
: public BookmarkUndoOperation
{
251 BookmarkMoveOperation(BookmarkModel
* bookmark_model
,
252 BookmarkRenumberObserver
* undo_renumber_observer
,
253 const BookmarkNode
* old_parent
,
255 const BookmarkNode
* new_parent
,
257 ~BookmarkMoveOperation() override
{}
258 int GetUndoLabelId() const override
;
259 int GetRedoLabelId() const override
;
262 void Undo() override
;
264 // BookmarkRenumberObserver:
265 void OnBookmarkRenumbered(int64 old_id
, int64 new_id
) override
;
268 int64 old_parent_id_
;
269 int64 new_parent_id_
;
273 DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation
);
276 BookmarkMoveOperation::BookmarkMoveOperation(
277 BookmarkModel
* bookmark_model
,
278 BookmarkRenumberObserver
* undo_renumber_observer
,
279 const BookmarkNode
* old_parent
,
281 const BookmarkNode
* new_parent
,
283 : BookmarkUndoOperation(bookmark_model
, undo_renumber_observer
),
284 old_parent_id_(old_parent
->id()),
285 new_parent_id_(new_parent
->id()),
286 old_index_(old_index
),
287 new_index_(new_index
) {
290 void BookmarkMoveOperation::Undo() {
291 BookmarkModel
* model
= bookmark_model();
292 const BookmarkNode
* old_parent
=
293 bookmarks::GetBookmarkNodeByID(model
, old_parent_id_
);
294 const BookmarkNode
* new_parent
=
295 bookmarks::GetBookmarkNodeByID(model
, new_parent_id_
);
299 const BookmarkNode
* node
= new_parent
->GetChild(new_index_
);
300 int destination_index
= old_index_
;
302 // If the bookmark was moved up within the same parent then the destination
303 // index needs to be incremented since the old index did not account for the
305 if (old_parent
== new_parent
&& new_index_
< old_index_
)
308 model
->Move(node
, old_parent
, destination_index
);
311 int BookmarkMoveOperation::GetUndoLabelId() const {
312 return IDS_BOOKMARK_BAR_UNDO_MOVE
;
315 int BookmarkMoveOperation::GetRedoLabelId() const {
316 return IDS_BOOKMARK_BAR_REDO_MOVE
;
319 void BookmarkMoveOperation::OnBookmarkRenumbered(int64 old_id
, int64 new_id
) {
320 if (old_parent_id_
== old_id
)
321 old_parent_id_
= new_id
;
322 if (new_parent_id_
== old_id
)
323 new_parent_id_
= new_id
;
326 // BookmarkReorderOperation ---------------------------------------------------
328 // Handle the undo of reordering of bookmarks that can happen as a result of
329 // sorting a bookmark folder by name or the undo of that operation. The change
330 // of order is not recursive so only the order of the immediate children of the
331 // folder need to be restored.
332 class BookmarkReorderOperation
: public BookmarkUndoOperation
{
334 BookmarkReorderOperation(BookmarkModel
* bookmark_model
,
335 BookmarkRenumberObserver
* undo_renumber_observer
,
336 const BookmarkNode
* parent
);
337 ~BookmarkReorderOperation() override
;
340 void Undo() override
;
341 int GetUndoLabelId() const override
;
342 int GetRedoLabelId() const override
;
344 // BookmarkRenumberObserver:
345 void OnBookmarkRenumbered(int64 old_id
, int64 new_id
) override
;
349 std::vector
<int64
> ordered_bookmarks_
;
351 DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation
);
354 BookmarkReorderOperation::BookmarkReorderOperation(
355 BookmarkModel
* bookmark_model
,
356 BookmarkRenumberObserver
* undo_renumber_observer
,
357 const BookmarkNode
* parent
)
358 : BookmarkUndoOperation(bookmark_model
, undo_renumber_observer
),
359 parent_id_(parent
->id()) {
360 ordered_bookmarks_
.resize(parent
->child_count());
361 for (int i
= 0; i
< parent
->child_count(); ++i
)
362 ordered_bookmarks_
[i
] = parent
->GetChild(i
)->id();
365 BookmarkReorderOperation::~BookmarkReorderOperation() {
368 void BookmarkReorderOperation::Undo() {
369 BookmarkModel
* model
= bookmark_model();
370 const BookmarkNode
* parent
=
371 bookmarks::GetBookmarkNodeByID(model
, parent_id_
);
374 std::vector
<const BookmarkNode
*> ordered_nodes
;
375 for (size_t i
= 0; i
< ordered_bookmarks_
.size(); ++i
) {
376 ordered_nodes
.push_back(
377 bookmarks::GetBookmarkNodeByID(model
, ordered_bookmarks_
[i
]));
380 model
->ReorderChildren(parent
, ordered_nodes
);
383 int BookmarkReorderOperation::GetUndoLabelId() const {
384 return IDS_BOOKMARK_BAR_UNDO_REORDER
;
387 int BookmarkReorderOperation::GetRedoLabelId() const {
388 return IDS_BOOKMARK_BAR_REDO_REORDER
;
391 void BookmarkReorderOperation::OnBookmarkRenumbered(int64 old_id
,
393 if (parent_id_
== old_id
)
395 for (size_t i
= 0; i
< ordered_bookmarks_
.size(); ++i
) {
396 if (ordered_bookmarks_
[i
] == old_id
)
397 ordered_bookmarks_
[i
] = new_id
;
403 // BookmarkUndoService --------------------------------------------------------
405 BookmarkUndoService::BookmarkUndoService() : scoped_observer_(this) {
408 BookmarkUndoService::~BookmarkUndoService() {
411 void BookmarkUndoService::Start(BookmarkModel
* model
) {
412 scoped_observer_
.Add(model
);
415 void BookmarkUndoService::Shutdown() {
416 scoped_observer_
.RemoveAll();
419 void BookmarkUndoService::BookmarkModelLoaded(BookmarkModel
* model
,
420 bool ids_reassigned
) {
421 undo_manager_
.RemoveAllOperations();
424 void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel
* model
) {
425 undo_manager_
.RemoveAllOperations();
428 void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel
* model
,
429 const BookmarkNode
* old_parent
,
431 const BookmarkNode
* new_parent
,
433 scoped_ptr
<UndoOperation
> op(new BookmarkMoveOperation(
434 model
, this, old_parent
, old_index
, new_parent
, new_index
));
435 undo_manager()->AddUndoOperation(op
.Pass());
438 void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel
* model
,
439 const BookmarkNode
* parent
,
441 scoped_ptr
<UndoOperation
> op(
442 new BookmarkAddOperation(model
, this, parent
, index
));
443 undo_manager()->AddUndoOperation(op
.Pass());
446 void BookmarkUndoService::OnWillRemoveBookmarks(BookmarkModel
* model
,
447 const BookmarkNode
* parent
,
449 const BookmarkNode
* node
) {
450 scoped_ptr
<UndoOperation
> op(
451 new BookmarkRemoveOperation(model
, this, parent
, old_index
, node
));
452 undo_manager()->AddUndoOperation(op
.Pass());
455 void BookmarkUndoService::OnWillRemoveAllUserBookmarks(BookmarkModel
* model
) {
456 bookmarks::ScopedGroupBookmarkActions
merge_removes(model
);
457 for (int i
= 0; i
< model
->root_node()->child_count(); ++i
) {
458 const BookmarkNode
* permanent_node
= model
->root_node()->GetChild(i
);
459 for (int j
= permanent_node
->child_count() - 1; j
>= 0; --j
) {
460 scoped_ptr
<UndoOperation
> op(new BookmarkRemoveOperation(
461 model
, this, permanent_node
, j
, permanent_node
->GetChild(j
)));
462 undo_manager()->AddUndoOperation(op
.Pass());
467 void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel
* model
,
468 const BookmarkNode
* node
) {
469 scoped_ptr
<UndoOperation
> op(new BookmarkEditOperation(model
, this, node
));
470 undo_manager()->AddUndoOperation(op
.Pass());
473 void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel
* model
,
474 const BookmarkNode
* node
) {
475 scoped_ptr
<UndoOperation
> op(new BookmarkReorderOperation(model
, this, node
));
476 undo_manager()->AddUndoOperation(op
.Pass());
479 void BookmarkUndoService::GroupedBookmarkChangesBeginning(
480 BookmarkModel
* model
) {
481 undo_manager()->StartGroupingActions();
484 void BookmarkUndoService::GroupedBookmarkChangesEnded(BookmarkModel
* model
) {
485 undo_manager()->EndGroupingActions();
488 void BookmarkUndoService::OnBookmarkRenumbered(int64 old_id
, int64 new_id
) {
489 std::vector
<UndoOperation
*> all_operations
=
490 undo_manager()->GetAllUndoOperations();
491 for (UndoOperation
* op
: all_operations
) {
492 static_cast<BookmarkUndoOperation
*>(op
)
493 ->OnBookmarkRenumbered(old_id
, new_id
);