OLD | NEW |
| (Empty) |
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 | |
5 #include "chrome/browser/undo/bookmark_undo_service.h" | |
6 | |
7 #include "chrome/browser/undo/bookmark_renumber_observer.h" | |
8 #include "chrome/browser/undo/undo_operation.h" | |
9 #include "components/bookmarks/browser/bookmark_model.h" | |
10 #include "components/bookmarks/browser/bookmark_node_data.h" | |
11 #include "components/bookmarks/browser/bookmark_utils.h" | |
12 #include "components/bookmarks/browser/scoped_group_bookmark_actions.h" | |
13 #include "grit/components_strings.h" | |
14 | |
15 using bookmarks::BookmarkModel; | |
16 using bookmarks::BookmarkNode; | |
17 using bookmarks::BookmarkNodeData; | |
18 | |
19 namespace { | |
20 | |
21 // BookmarkUndoOperation ------------------------------------------------------ | |
22 | |
23 // Base class for all bookmark related UndoOperations that facilitates access to | |
24 // the BookmarkUndoService. | |
25 class BookmarkUndoOperation : public UndoOperation, | |
26 public BookmarkRenumberObserver { | |
27 public: | |
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 {} | |
33 | |
34 BookmarkModel* bookmark_model() { return bookmark_model_; } | |
35 | |
36 BookmarkRenumberObserver* undo_renumber_observer() { | |
37 return undo_renumber_observer_; | |
38 } | |
39 | |
40 private: | |
41 BookmarkModel* bookmark_model_; | |
42 BookmarkRenumberObserver* undo_renumber_observer_; | |
43 }; | |
44 | |
45 // BookmarkAddOperation ------------------------------------------------------- | |
46 | |
47 // Handles the undo of the insertion of a bookmark or folder. | |
48 class BookmarkAddOperation : public BookmarkUndoOperation { | |
49 public: | |
50 BookmarkAddOperation(BookmarkModel* bookmark_model, | |
51 BookmarkRenumberObserver* undo_renumber_observer, | |
52 const BookmarkNode* parent, | |
53 int index); | |
54 ~BookmarkAddOperation() override {} | |
55 | |
56 // UndoOperation: | |
57 void Undo() override; | |
58 int GetUndoLabelId() const override; | |
59 int GetRedoLabelId() const override; | |
60 | |
61 // BookmarkRenumberObserver: | |
62 void OnBookmarkRenumbered(int64 old_id, int64 new_id) override; | |
63 | |
64 private: | |
65 int64 parent_id_; | |
66 const int index_; | |
67 | |
68 DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation); | |
69 }; | |
70 | |
71 BookmarkAddOperation::BookmarkAddOperation( | |
72 BookmarkModel* bookmark_model, | |
73 BookmarkRenumberObserver* undo_renumber_observer, | |
74 const BookmarkNode* parent, | |
75 int index) | |
76 : BookmarkUndoOperation(bookmark_model, undo_renumber_observer), | |
77 parent_id_(parent->id()), | |
78 index_(index) { | |
79 } | |
80 | |
81 void BookmarkAddOperation::Undo() { | |
82 BookmarkModel* model = bookmark_model(); | |
83 const BookmarkNode* parent = | |
84 bookmarks::GetBookmarkNodeByID(model, parent_id_); | |
85 DCHECK(parent); | |
86 | |
87 model->Remove(parent, index_); | |
88 } | |
89 | |
90 int BookmarkAddOperation::GetUndoLabelId() const { | |
91 return IDS_BOOKMARK_BAR_UNDO_ADD; | |
92 } | |
93 | |
94 int BookmarkAddOperation::GetRedoLabelId() const { | |
95 return IDS_BOOKMARK_BAR_REDO_DELETE; | |
96 } | |
97 | |
98 void BookmarkAddOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { | |
99 if (parent_id_ == old_id) | |
100 parent_id_ = new_id; | |
101 } | |
102 | |
103 // BookmarkRemoveOperation ---------------------------------------------------- | |
104 | |
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. | |
107 // | |
108 // The BookmarkModel allows only single bookmark node to be removed. | |
109 class BookmarkRemoveOperation : public BookmarkUndoOperation { | |
110 public: | |
111 BookmarkRemoveOperation(BookmarkModel* bookmark_model, | |
112 BookmarkRenumberObserver* undo_renumber_observer, | |
113 const BookmarkNode* parent, | |
114 int old_index, | |
115 const BookmarkNode* node); | |
116 ~BookmarkRemoveOperation() override {} | |
117 | |
118 // UndoOperation: | |
119 void Undo() override; | |
120 int GetUndoLabelId() const override; | |
121 int GetRedoLabelId() const override; | |
122 | |
123 // BookmarkRenumberObserver: | |
124 void OnBookmarkRenumbered(int64 old_id, int64 new_id) override; | |
125 | |
126 private: | |
127 void UpdateBookmarkIds(const BookmarkNodeData::Element& element, | |
128 const BookmarkNode* parent, | |
129 int index_added_at); | |
130 | |
131 int64 parent_id_; | |
132 const int old_index_; | |
133 BookmarkNodeData removed_node_; | |
134 | |
135 DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation); | |
136 }; | |
137 | |
138 BookmarkRemoveOperation::BookmarkRemoveOperation( | |
139 BookmarkModel* bookmark_model, | |
140 BookmarkRenumberObserver* undo_renumber_observer, | |
141 const BookmarkNode* parent, | |
142 int old_index, | |
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) { | |
148 } | |
149 | |
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_); | |
155 DCHECK(parent); | |
156 | |
157 bookmarks::CloneBookmarkNode( | |
158 model, removed_node_.elements, parent, old_index_, false); | |
159 UpdateBookmarkIds(removed_node_.elements[0], parent, old_index_); | |
160 } | |
161 | |
162 int BookmarkRemoveOperation::GetUndoLabelId() const { | |
163 return IDS_BOOKMARK_BAR_UNDO_DELETE; | |
164 } | |
165 | |
166 int BookmarkRemoveOperation::GetRedoLabelId() const { | |
167 return IDS_BOOKMARK_BAR_REDO_ADD; | |
168 } | |
169 | |
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, 0); | |
180 } | |
181 } | |
182 | |
183 void BookmarkRemoveOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { | |
184 if (parent_id_ == old_id) | |
185 parent_id_ = new_id; | |
186 } | |
187 | |
188 // BookmarkEditOperation ------------------------------------------------------ | |
189 | |
190 // Handles the undo of the modification of a bookmark node. | |
191 class BookmarkEditOperation : public BookmarkUndoOperation { | |
192 public: | |
193 BookmarkEditOperation(BookmarkModel* bookmark_model, | |
194 BookmarkRenumberObserver* undo_renumber_observer, | |
195 const BookmarkNode* node); | |
196 ~BookmarkEditOperation() override {} | |
197 | |
198 // UndoOperation: | |
199 void Undo() override; | |
200 int GetUndoLabelId() const override; | |
201 int GetRedoLabelId() const override; | |
202 | |
203 // BookmarkRenumberObserver: | |
204 void OnBookmarkRenumbered(int64 old_id, int64 new_id) override; | |
205 | |
206 private: | |
207 int64 node_id_; | |
208 BookmarkNodeData original_bookmark_; | |
209 | |
210 DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation); | |
211 }; | |
212 | |
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) { | |
220 } | |
221 | |
222 void BookmarkEditOperation::Undo() { | |
223 DCHECK(original_bookmark_.is_valid()); | |
224 BookmarkModel* model = bookmark_model(); | |
225 const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, node_id_); | |
226 DCHECK(node); | |
227 | |
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); | |
231 } | |
232 | |
233 int BookmarkEditOperation::GetUndoLabelId() const { | |
234 return IDS_BOOKMARK_BAR_UNDO_EDIT; | |
235 } | |
236 | |
237 int BookmarkEditOperation::GetRedoLabelId() const { | |
238 return IDS_BOOKMARK_BAR_REDO_EDIT; | |
239 } | |
240 | |
241 void BookmarkEditOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { | |
242 if (node_id_ == old_id) | |
243 node_id_ = new_id; | |
244 } | |
245 | |
246 // BookmarkMoveOperation ------------------------------------------------------ | |
247 | |
248 // Handles the undo of a bookmark being moved to a new location. | |
249 class BookmarkMoveOperation : public BookmarkUndoOperation { | |
250 public: | |
251 BookmarkMoveOperation(BookmarkModel* bookmark_model, | |
252 BookmarkRenumberObserver* undo_renumber_observer, | |
253 const BookmarkNode* old_parent, | |
254 int old_index, | |
255 const BookmarkNode* new_parent, | |
256 int new_index); | |
257 ~BookmarkMoveOperation() override {} | |
258 int GetUndoLabelId() const override; | |
259 int GetRedoLabelId() const override; | |
260 | |
261 // UndoOperation: | |
262 void Undo() override; | |
263 | |
264 // BookmarkRenumberObserver: | |
265 void OnBookmarkRenumbered(int64 old_id, int64 new_id) override; | |
266 | |
267 private: | |
268 int64 old_parent_id_; | |
269 int64 new_parent_id_; | |
270 int old_index_; | |
271 int new_index_; | |
272 | |
273 DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation); | |
274 }; | |
275 | |
276 BookmarkMoveOperation::BookmarkMoveOperation( | |
277 BookmarkModel* bookmark_model, | |
278 BookmarkRenumberObserver* undo_renumber_observer, | |
279 const BookmarkNode* old_parent, | |
280 int old_index, | |
281 const BookmarkNode* new_parent, | |
282 int new_index) | |
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) { | |
288 } | |
289 | |
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_); | |
296 DCHECK(old_parent); | |
297 DCHECK(new_parent); | |
298 | |
299 const BookmarkNode* node = new_parent->GetChild(new_index_); | |
300 int destination_index = old_index_; | |
301 | |
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 | |
304 // moved bookmark. | |
305 if (old_parent == new_parent && new_index_ < old_index_) | |
306 ++destination_index; | |
307 | |
308 model->Move(node, old_parent, destination_index); | |
309 } | |
310 | |
311 int BookmarkMoveOperation::GetUndoLabelId() const { | |
312 return IDS_BOOKMARK_BAR_UNDO_MOVE; | |
313 } | |
314 | |
315 int BookmarkMoveOperation::GetRedoLabelId() const { | |
316 return IDS_BOOKMARK_BAR_REDO_MOVE; | |
317 } | |
318 | |
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; | |
324 } | |
325 | |
326 // BookmarkReorderOperation --------------------------------------------------- | |
327 | |
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 { | |
333 public: | |
334 BookmarkReorderOperation(BookmarkModel* bookmark_model, | |
335 BookmarkRenumberObserver* undo_renumber_observer, | |
336 const BookmarkNode* parent); | |
337 ~BookmarkReorderOperation() override; | |
338 | |
339 // UndoOperation: | |
340 void Undo() override; | |
341 int GetUndoLabelId() const override; | |
342 int GetRedoLabelId() const override; | |
343 | |
344 // BookmarkRenumberObserver: | |
345 void OnBookmarkRenumbered(int64 old_id, int64 new_id) override; | |
346 | |
347 private: | |
348 int64 parent_id_; | |
349 std::vector<int64> ordered_bookmarks_; | |
350 | |
351 DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation); | |
352 }; | |
353 | |
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(); | |
363 } | |
364 | |
365 BookmarkReorderOperation::~BookmarkReorderOperation() { | |
366 } | |
367 | |
368 void BookmarkReorderOperation::Undo() { | |
369 BookmarkModel* model = bookmark_model(); | |
370 const BookmarkNode* parent = | |
371 bookmarks::GetBookmarkNodeByID(model, parent_id_); | |
372 DCHECK(parent); | |
373 | |
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])); | |
378 } | |
379 | |
380 model->ReorderChildren(parent, ordered_nodes); | |
381 } | |
382 | |
383 int BookmarkReorderOperation::GetUndoLabelId() const { | |
384 return IDS_BOOKMARK_BAR_UNDO_REORDER; | |
385 } | |
386 | |
387 int BookmarkReorderOperation::GetRedoLabelId() const { | |
388 return IDS_BOOKMARK_BAR_REDO_REORDER; | |
389 } | |
390 | |
391 void BookmarkReorderOperation::OnBookmarkRenumbered(int64 old_id, | |
392 int64 new_id) { | |
393 if (parent_id_ == old_id) | |
394 parent_id_ = new_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; | |
398 } | |
399 } | |
400 | |
401 } // namespace | |
402 | |
403 // BookmarkUndoService -------------------------------------------------------- | |
404 | |
405 BookmarkUndoService::BookmarkUndoService() : scoped_observer_(this) { | |
406 } | |
407 | |
408 BookmarkUndoService::~BookmarkUndoService() { | |
409 } | |
410 | |
411 void BookmarkUndoService::Start(BookmarkModel* model) { | |
412 scoped_observer_.Add(model); | |
413 } | |
414 | |
415 void BookmarkUndoService::Shutdown() { | |
416 scoped_observer_.RemoveAll(); | |
417 } | |
418 | |
419 void BookmarkUndoService::BookmarkModelLoaded(BookmarkModel* model, | |
420 bool ids_reassigned) { | |
421 undo_manager_.RemoveAllOperations(); | |
422 } | |
423 | |
424 void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel* model) { | |
425 undo_manager_.RemoveAllOperations(); | |
426 } | |
427 | |
428 void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel* model, | |
429 const BookmarkNode* old_parent, | |
430 int old_index, | |
431 const BookmarkNode* new_parent, | |
432 int new_index) { | |
433 scoped_ptr<UndoOperation> op(new BookmarkMoveOperation( | |
434 model, this, old_parent, old_index, new_parent, new_index)); | |
435 undo_manager()->AddUndoOperation(op.Pass()); | |
436 } | |
437 | |
438 void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, | |
439 const BookmarkNode* parent, | |
440 int index) { | |
441 scoped_ptr<UndoOperation> op( | |
442 new BookmarkAddOperation(model, this, parent, index)); | |
443 undo_manager()->AddUndoOperation(op.Pass()); | |
444 } | |
445 | |
446 void BookmarkUndoService::OnWillRemoveBookmarks(BookmarkModel* model, | |
447 const BookmarkNode* parent, | |
448 int old_index, | |
449 const BookmarkNode* node) { | |
450 scoped_ptr<UndoOperation> op( | |
451 new BookmarkRemoveOperation(model, this, parent, old_index, node)); | |
452 undo_manager()->AddUndoOperation(op.Pass()); | |
453 } | |
454 | |
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()); | |
463 } | |
464 } | |
465 } | |
466 | |
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()); | |
471 } | |
472 | |
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()); | |
477 } | |
478 | |
479 void BookmarkUndoService::GroupedBookmarkChangesBeginning( | |
480 BookmarkModel* model) { | |
481 undo_manager()->StartGroupingActions(); | |
482 } | |
483 | |
484 void BookmarkUndoService::GroupedBookmarkChangesEnded(BookmarkModel* model) { | |
485 undo_manager()->EndGroupingActions(); | |
486 } | |
487 | |
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); | |
494 } | |
495 } | |
OLD | NEW |