Index: chrome/browser/undo/bookmark_undo_service.cc |
diff --git a/chrome/browser/undo/bookmark_undo_service.cc b/chrome/browser/undo/bookmark_undo_service.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca1b281bcdad1ac4921a026335556f8681c0949f |
--- /dev/null |
+++ b/chrome/browser/undo/bookmark_undo_service.cc |
@@ -0,0 +1,418 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/undo/bookmark_undo_service.h" |
+ |
+#include "chrome/browser/bookmarks/bookmark_model.h" |
+#include "chrome/browser/bookmarks/bookmark_model_factory.h" |
+#include "chrome/browser/bookmarks/bookmark_node_data.h" |
+#include "chrome/browser/bookmarks/bookmark_utils.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/undo/bookmark_renumber_observer.h" |
+#include "chrome/browser/undo/bookmark_undo_service_factory.h" |
+#include "chrome/browser/undo/undo_manager_utils.h" |
+#include "chrome/browser/undo/undo_operation.h" |
+ |
+namespace { |
+ |
+// BookmarkUndoOperation ------------------------------------------------------ |
+ |
+// Base class for all bookmark related UndoOperations that facilitates access to |
+// the BookmarkUndoService. |
+class BookmarkUndoOperation : public UndoOperation, |
+ public BookmarkRenumberObserver { |
+ public: |
+ explicit BookmarkUndoOperation(Profile* profile); |
+ virtual ~BookmarkUndoOperation() {} |
+ |
+ BookmarkModel* GetBookmarkModel() const; |
+ BookmarkRenumberObserver* GetUndoRenumberObserver() const; |
+ |
+ private: |
+ Profile* profile_; |
+}; |
+ |
+BookmarkUndoOperation::BookmarkUndoOperation(Profile* profile) |
+ : profile_(profile) { |
+} |
+ |
+BookmarkModel* BookmarkUndoOperation::GetBookmarkModel() const { |
+ return BookmarkModelFactory::GetForProfile(profile_); |
+} |
+ |
+BookmarkRenumberObserver* BookmarkUndoOperation::GetUndoRenumberObserver( |
+ ) const { |
Tom Cassiotis
2013/09/04 13:44:43
I spent a non-trivial amount of time to figure out
sky
2013/09/04 21:52:18
HA! For the record the style guide is here: http:/
Tom Cassiotis
2013/09/05 12:51:58
I did look at the style guide to figure out the fo
|
+ return BookmarkUndoServiceFactory::GetForProfile(profile_); |
+} |
+ |
+// BookmarkAddOperation ------------------------------------------------------- |
+ |
+// Handles the undo of the insertion of a bookmark or folder. |
+class BookmarkAddOperation : public BookmarkUndoOperation { |
+ public: |
+ BookmarkAddOperation(Profile* profile, const BookmarkNode* parent, int index); |
+ virtual ~BookmarkAddOperation() {} |
+ |
+ // UndoOperation: |
+ virtual void Undo() OVERRIDE; |
+ |
+ // BookmarkRenumberObserver: |
+ virtual void OnBookmarkRenumbered(int64 old_id, int64 new_id) OVERRIDE; |
+ |
+ private: |
+ int64 parent_id_; |
+ const int index_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation); |
+}; |
+ |
+BookmarkAddOperation::BookmarkAddOperation(Profile* profile, |
+ const BookmarkNode* parent, |
+ int index) |
+ : BookmarkUndoOperation(profile), |
+ parent_id_(parent->id()), |
+ index_(index) { |
+} |
+ |
+void BookmarkAddOperation::Undo() { |
+ BookmarkModel* model = GetBookmarkModel(); |
+ const BookmarkNode* parent = model->GetNodeByID(parent_id_); |
+ DCHECK(parent); |
+ |
+ model->Remove(parent, index_); |
+} |
+ |
+void BookmarkAddOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { |
+ if (parent_id_ == old_id) |
+ parent_id_ = new_id; |
+} |
+ |
+// BookmarkRemoveOperation ---------------------------------------------------- |
+ |
+// Handles the undo of the deletion of a bookmark node. For a bookmark folder, |
+// the information for all descendant bookmark nodes is maintained. |
+// |
+// The BookmarkModel allows only single bookmark node to be removed. |
+class BookmarkRemoveOperation : public BookmarkUndoOperation { |
+ public: |
+ BookmarkRemoveOperation(Profile* profile, |
+ const BookmarkNode* parent, |
+ int old_index, |
+ const BookmarkNode* node); |
+ virtual ~BookmarkRemoveOperation() {} |
+ |
+ // UndoOperation: |
+ virtual void Undo() OVERRIDE; |
+ |
+ // BookmarkRenumberObserver: |
+ virtual void OnBookmarkRenumbered(int64 old_id, int64 new_id) OVERRIDE; |
+ |
+ private: |
+ void UpdateBookmarkIds(const BookmarkNodeData::Element& element, |
+ const BookmarkNode* parent, |
+ int index_added_at) const; |
+ |
+ int64 parent_id_; |
+ const int old_index_; |
+ BookmarkNodeData removed_node_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation); |
+}; |
+ |
+BookmarkRemoveOperation::BookmarkRemoveOperation(Profile* profile, |
+ const BookmarkNode* parent, |
+ int old_index, |
+ const BookmarkNode* node) |
+ : BookmarkUndoOperation(profile), |
+ parent_id_(parent->id()), |
+ old_index_(old_index), |
+ removed_node_(node) { |
+} |
+ |
+void BookmarkRemoveOperation::Undo() { |
+ DCHECK(removed_node_.is_valid()); |
+ BookmarkModel* model = GetBookmarkModel(); |
+ const BookmarkNode* parent = model->GetNodeByID(parent_id_); |
+ DCHECK(parent); |
+ |
+ bookmark_utils::CloneBookmarkNode(model, removed_node_.elements, parent, |
+ old_index_, false); |
+ UpdateBookmarkIds(removed_node_.elements[0], parent, old_index_); |
+} |
+ |
+void BookmarkRemoveOperation::UpdateBookmarkIds( |
+ const BookmarkNodeData::Element& element, |
+ const BookmarkNode* parent, |
+ int index_added_at) const { |
+ BookmarkModel* model = GetBookmarkModel(); |
+ |
+ const BookmarkNode* node = parent->GetChild(index_added_at); |
+ if (element.id() != node->id()) |
+ GetUndoRenumberObserver()->OnBookmarkRenumbered(element.id(), node->id()); |
+ if (!element.is_url) { |
+ for (int i = 0; i < static_cast<int>(element.children.size()); ++i) |
+ UpdateBookmarkIds(element.children[i], node, 0); |
+ } |
+} |
+ |
+void BookmarkRemoveOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { |
+ if (parent_id_ == old_id) |
+ parent_id_ = new_id; |
+} |
+ |
+// BookmarkEditOperation ------------------------------------------------------ |
+ |
+// Handles the undo of the modification of a bookmark node. |
+class BookmarkEditOperation : public BookmarkUndoOperation { |
+ public: |
+ BookmarkEditOperation(Profile* profile, |
+ const BookmarkNode* node); |
+ virtual ~BookmarkEditOperation() {} |
+ |
+ // UndoOperation: |
+ virtual void Undo() OVERRIDE; |
+ |
+ // BookmarkRenumberObserver: |
+ virtual void OnBookmarkRenumbered(int64 old_id, int64 new_id) OVERRIDE; |
+ |
+ private: |
+ int64 node_id_; |
+ BookmarkNodeData original_bookmark_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation); |
+}; |
+ |
+BookmarkEditOperation::BookmarkEditOperation(Profile* profile, |
+ const BookmarkNode* node) |
+ : BookmarkUndoOperation(profile), |
+ node_id_(node->id()), |
+ original_bookmark_(node) { |
+} |
+ |
+void BookmarkEditOperation::Undo() { |
+ DCHECK(original_bookmark_.is_valid()); |
+ BookmarkModel* model = GetBookmarkModel(); |
+ const BookmarkNode* node = model->GetNodeByID(node_id_); |
+ DCHECK(node); |
+ |
+ model->SetTitle(node, original_bookmark_.elements[0].title); |
+ if (original_bookmark_.elements[0].is_url) |
+ model->SetURL(node, original_bookmark_.elements[0].url); |
+} |
+ |
+void BookmarkEditOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { |
+ if (node_id_ == old_id) |
+ node_id_ = new_id; |
+} |
+ |
+// BookmarkMoveOperation ------------------------------------------------------ |
+ |
+// Handles the undo of a bookmark being moved to a new location. |
+class BookmarkMoveOperation : public BookmarkUndoOperation { |
+ public: |
+ BookmarkMoveOperation(Profile* profile, |
+ const BookmarkNode* old_parent, |
+ int old_index, |
+ const BookmarkNode* new_parent, |
+ int new_index); |
+ virtual ~BookmarkMoveOperation() {} |
+ |
+ // UndoOperation: |
+ virtual void Undo() OVERRIDE; |
+ |
+ // BookmarkRenumberObserver: |
+ virtual void OnBookmarkRenumbered(int64 old_id, int64 new_id) OVERRIDE; |
+ |
+ private: |
+ int64 old_parent_id_; |
+ int64 new_parent_id_; |
+ int old_index_; |
+ int new_index_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation); |
+}; |
+ |
+BookmarkMoveOperation::BookmarkMoveOperation(Profile* profile, |
+ const BookmarkNode* old_parent, |
+ int old_index, |
+ const BookmarkNode* new_parent, |
+ int new_index) |
+ : BookmarkUndoOperation(profile), |
+ old_parent_id_(old_parent->id()), |
+ old_index_(old_index), |
+ new_parent_id_(new_parent->id()), |
+ new_index_(new_index) { |
+} |
+ |
+void BookmarkMoveOperation::Undo() { |
+ BookmarkModel* model = GetBookmarkModel(); |
+ const BookmarkNode* old_parent = model->GetNodeByID(old_parent_id_); |
+ const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id_); |
+ DCHECK(old_parent); |
+ DCHECK(new_parent); |
+ |
+ const BookmarkNode* node = new_parent->GetChild(new_index_); |
+ int destination_index = old_index_; |
+ |
+ // If the bookmark was moved up within the same parent then the destination |
+ // index needs to be incremented since the old index did not account for the |
+ // moved bookmark. |
+ if (old_parent == new_parent && new_index_ < old_index_) |
+ ++destination_index; |
+ |
+ model->Move(node, old_parent, destination_index); |
+} |
+ |
+void BookmarkMoveOperation::OnBookmarkRenumbered(int64 old_id, int64 new_id) { |
+ if (old_parent_id_ == old_id) |
+ old_parent_id_ = new_id; |
+ if (new_parent_id_ == old_id) |
+ new_parent_id_ = new_id; |
+} |
+ |
+// BookmarkReorderOperation --------------------------------------------------- |
+ |
+// Handle the undo of reordering of bookmarks that can happen as a result of |
+// sorting a bookmark folder by name or the undo of that operation. The change |
+// of order is not recursive so only the order of the immediate children of the |
+// folder need to be restored. |
+class BookmarkReorderOperation : public BookmarkUndoOperation { |
+ public: |
+ BookmarkReorderOperation(Profile* profile, |
+ const BookmarkNode* parent); |
+ virtual ~BookmarkReorderOperation(); |
+ |
+ // UndoOperation: |
+ virtual void Undo() OVERRIDE; |
+ |
+ // BookmarkRenumberObserver: |
+ virtual void OnBookmarkRenumbered(int64 old_id, int64 new_id) OVERRIDE; |
+ |
+ private: |
+ int64 parent_id_; |
+ std::vector<int64> ordered_bookmarks_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation); |
+}; |
+ |
+BookmarkReorderOperation::BookmarkReorderOperation(Profile* profile, |
+ const BookmarkNode* parent) |
+ : BookmarkUndoOperation(profile), |
+ parent_id_(parent->id()) { |
+ ordered_bookmarks_.resize(parent->child_count()); |
+ for (int i = 0; i < parent->child_count(); ++i) |
+ ordered_bookmarks_[i] = parent->GetChild(i)->id(); |
+} |
+ |
+BookmarkReorderOperation::~BookmarkReorderOperation() { |
+} |
+ |
+void BookmarkReorderOperation::Undo() { |
+ BookmarkModel* model = GetBookmarkModel(); |
+ const BookmarkNode* parent = model->GetNodeByID(parent_id_); |
+ DCHECK(parent); |
+ |
+ std::vector<const BookmarkNode*> ordered_nodes; |
+ for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) |
+ ordered_nodes.push_back(model->GetNodeByID(ordered_bookmarks_[i])); |
+ |
+ model->ReorderChildren(parent, ordered_nodes); |
+} |
+ |
+void BookmarkReorderOperation::OnBookmarkRenumbered(int64 old_id, |
+ int64 new_id) { |
+ if (parent_id_ == old_id) |
+ parent_id_ = new_id; |
+ for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) { |
+ if (ordered_bookmarks_[i] == old_id) |
+ ordered_bookmarks_[i] = new_id; |
+ } |
+} |
+ |
+} // namespace |
+ |
+// BookmarkUndoService -------------------------------------------------------- |
+ |
+BookmarkUndoService::BookmarkUndoService(Profile* profile) : profile_(profile) { |
+ BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); |
+} |
+ |
+BookmarkUndoService::~BookmarkUndoService() { |
+ BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); |
+} |
+ |
+void BookmarkUndoService::OnBookmarkRenumbered(int64 old_id, int64 new_id) { |
+ std::vector<UndoOperation*> all_operations = |
+ undo_manager()->GetAllUndoOperations(); |
+ for (std::vector<UndoOperation*>::iterator it = all_operations.begin(); |
+ it != all_operations.end(); ++it) { |
+ static_cast<BookmarkUndoOperation*>(*it)->OnBookmarkRenumbered(old_id, |
+ new_id); |
+ } |
+} |
+ |
+void BookmarkUndoService::Loaded(BookmarkModel* model, bool ids_reassigned) { |
+ undo_manager_.RemoveAllOperations(); |
+} |
+ |
+void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel* model) { |
+ undo_manager_.RemoveAllOperations(); |
+} |
+ |
+void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel* model, |
+ const BookmarkNode* old_parent, |
+ int old_index, |
+ const BookmarkNode* new_parent, |
+ int new_index) { |
+ scoped_ptr<UndoOperation> op(new BookmarkMoveOperation(profile_, |
+ old_parent, |
+ old_index, |
+ new_parent, |
+ new_index)); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+} |
+ |
+void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, |
+ const BookmarkNode* parent, |
+ int index) { |
+ scoped_ptr<UndoOperation> op(new BookmarkAddOperation(profile_, |
+ parent, |
+ index)); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+} |
+ |
+void BookmarkUndoService::OnWillRemoveBookmarks(BookmarkModel* model, |
+ const BookmarkNode* parent, |
+ int old_index, |
+ const BookmarkNode* node) { |
+ scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, |
+ parent, |
+ old_index, |
+ node)); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+} |
+ |
+void BookmarkUndoService::OnWillRemoveAllBookmarks(BookmarkModel* model) { |
+ ScopedGroupingAction merge_removes(undo_manager()); |
+ for (int i = 0; i < model->root_node()->child_count(); ++i) { |
+ const BookmarkNode* permanent_node = model->root_node()->GetChild(i); |
+ for (int j = permanent_node->child_count() - 1; j >= 0; --j) { |
+ scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, |
+ permanent_node, j, permanent_node->GetChild(j))); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+ } |
+ } |
+} |
+ |
+void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel* model, |
+ const BookmarkNode* node) { |
+ scoped_ptr<UndoOperation> op(new BookmarkEditOperation(profile_, node)); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+} |
+ |
+void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel* model, |
+ const BookmarkNode* node) { |
+ scoped_ptr<UndoOperation> op(new BookmarkReorderOperation(profile_, node)); |
+ undo_manager()->AddUndoOperation(op.Pass()); |
+} |