| // 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 "components/undo/bookmark_undo_service.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/macros.h" |
| #include "components/bookmarks/browser/bookmark_model.h" |
| #include "components/bookmarks/browser/bookmark_node_data.h" |
| #include "components/bookmarks/browser/bookmark_undo_provider.h" |
| #include "components/bookmarks/browser/bookmark_utils.h" |
| #include "components/bookmarks/browser/scoped_group_bookmark_actions.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/undo/undo_operation.h" |
| |
| using bookmarks::BookmarkModel; |
| using bookmarks::BookmarkNode; |
| using bookmarks::BookmarkNodeData; |
| using bookmarks::BookmarkUndoProvider; |
| |
| namespace { |
| |
| // BookmarkUndoOperation ------------------------------------------------------ |
| |
| // Base class for all bookmark related UndoOperations that facilitates access to |
| // the BookmarkUndoService. |
| class BookmarkUndoOperation : public UndoOperation { |
| public: |
| explicit BookmarkUndoOperation(BookmarkModel* bookmark_model) |
| : bookmark_model_(bookmark_model) {} |
| ~BookmarkUndoOperation() override {} |
| |
| BookmarkModel* bookmark_model() { return bookmark_model_; } |
| |
| private: |
| BookmarkModel* bookmark_model_; |
| }; |
| |
| // BookmarkAddOperation ------------------------------------------------------- |
| |
| // Handles the undo of the insertion of a bookmark or folder. |
| class BookmarkAddOperation : public BookmarkUndoOperation { |
| public: |
| BookmarkAddOperation(BookmarkModel* bookmark_model, |
| const BookmarkNode* parent, |
| int index); |
| ~BookmarkAddOperation() override {} |
| |
| // UndoOperation: |
| void Undo() override; |
| int GetUndoLabelId() const override; |
| int GetRedoLabelId() const override; |
| |
| private: |
| int64_t parent_id_; |
| const int index_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation); |
| }; |
| |
| BookmarkAddOperation::BookmarkAddOperation( |
| BookmarkModel* bookmark_model, |
| const BookmarkNode* parent, |
| int index) |
| : BookmarkUndoOperation(bookmark_model), |
| parent_id_(parent->id()), |
| index_(index) { |
| } |
| |
| void BookmarkAddOperation::Undo() { |
| BookmarkModel* model = bookmark_model(); |
| const BookmarkNode* parent = |
| bookmarks::GetBookmarkNodeByID(model, parent_id_); |
| DCHECK(parent); |
| |
| model->Remove(parent->GetChild(index_)); |
| } |
| |
| int BookmarkAddOperation::GetUndoLabelId() const { |
| return IDS_BOOKMARK_BAR_UNDO_ADD; |
| } |
| |
| int BookmarkAddOperation::GetRedoLabelId() const { |
| return IDS_BOOKMARK_BAR_REDO_DELETE; |
| } |
| |
| // 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(BookmarkModel* model, |
| BookmarkUndoProvider* undo_provider, |
| const BookmarkNode* parent, |
| int index, |
| std::unique_ptr<BookmarkNode> node); |
| ~BookmarkRemoveOperation() override; |
| |
| // UndoOperation: |
| void Undo() override; |
| int GetUndoLabelId() const override; |
| int GetRedoLabelId() const override; |
| |
| private: |
| BookmarkUndoProvider* undo_provider_; |
| const int64_t parent_node_id_; |
| const int index_; |
| std::unique_ptr<BookmarkNode> node_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation); |
| }; |
| |
| BookmarkRemoveOperation::BookmarkRemoveOperation( |
| BookmarkModel* model, |
| BookmarkUndoProvider* undo_provider, |
| const BookmarkNode* parent, |
| int index, |
| std::unique_ptr<BookmarkNode> node) |
| : BookmarkUndoOperation(model), |
| undo_provider_(undo_provider), |
| parent_node_id_(parent->id()), |
| index_(index), |
| node_(std::move(node)) {} |
| |
| BookmarkRemoveOperation::~BookmarkRemoveOperation() { |
| } |
| |
| void BookmarkRemoveOperation::Undo() { |
| DCHECK(node_); |
| |
| const BookmarkNode* parent = bookmarks::GetBookmarkNodeByID( |
| bookmark_model(), parent_node_id_); |
| DCHECK(parent); |
| |
| undo_provider_->RestoreRemovedNode(parent, index_, std::move(node_)); |
| } |
| |
| int BookmarkRemoveOperation::GetUndoLabelId() const { |
| return IDS_BOOKMARK_BAR_UNDO_DELETE; |
| } |
| |
| int BookmarkRemoveOperation::GetRedoLabelId() const { |
| return IDS_BOOKMARK_BAR_REDO_ADD; |
| } |
| |
| // BookmarkEditOperation ------------------------------------------------------ |
| |
| // Handles the undo of the modification of a bookmark node. |
| class BookmarkEditOperation : public BookmarkUndoOperation { |
| public: |
| BookmarkEditOperation(BookmarkModel* bookmark_model, |
| const BookmarkNode* node); |
| ~BookmarkEditOperation() override {} |
| |
| // UndoOperation: |
| void Undo() override; |
| int GetUndoLabelId() const override; |
| int GetRedoLabelId() const override; |
| |
| private: |
| int64_t node_id_; |
| BookmarkNodeData original_bookmark_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation); |
| }; |
| |
| BookmarkEditOperation::BookmarkEditOperation( |
| BookmarkModel* bookmark_model, |
| const BookmarkNode* node) |
| : BookmarkUndoOperation(bookmark_model), |
| node_id_(node->id()), |
| original_bookmark_(node) { |
| } |
| |
| void BookmarkEditOperation::Undo() { |
| DCHECK(original_bookmark_.is_valid()); |
| BookmarkModel* model = bookmark_model(); |
| const BookmarkNode* node = bookmarks::GetBookmarkNodeByID(model, 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); |
| } |
| |
| int BookmarkEditOperation::GetUndoLabelId() const { |
| return IDS_BOOKMARK_BAR_UNDO_EDIT; |
| } |
| |
| int BookmarkEditOperation::GetRedoLabelId() const { |
| return IDS_BOOKMARK_BAR_REDO_EDIT; |
| } |
| |
| // BookmarkMoveOperation ------------------------------------------------------ |
| |
| // Handles the undo of a bookmark being moved to a new location. |
| class BookmarkMoveOperation : public BookmarkUndoOperation { |
| public: |
| BookmarkMoveOperation(BookmarkModel* bookmark_model, |
| const BookmarkNode* old_parent, |
| int old_index, |
| const BookmarkNode* new_parent, |
| int new_index); |
| ~BookmarkMoveOperation() override {} |
| int GetUndoLabelId() const override; |
| int GetRedoLabelId() const override; |
| |
| // UndoOperation: |
| void Undo() override; |
| |
| private: |
| int64_t old_parent_id_; |
| int64_t new_parent_id_; |
| int old_index_; |
| int new_index_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation); |
| }; |
| |
| BookmarkMoveOperation::BookmarkMoveOperation( |
| BookmarkModel* bookmark_model, |
| const BookmarkNode* old_parent, |
| int old_index, |
| const BookmarkNode* new_parent, |
| int new_index) |
| : BookmarkUndoOperation(bookmark_model), |
| old_parent_id_(old_parent->id()), |
| new_parent_id_(new_parent->id()), |
| old_index_(old_index), |
| new_index_(new_index) { |
| } |
| |
| void BookmarkMoveOperation::Undo() { |
| BookmarkModel* model = bookmark_model(); |
| const BookmarkNode* old_parent = |
| bookmarks::GetBookmarkNodeByID(model, old_parent_id_); |
| const BookmarkNode* new_parent = |
| bookmarks::GetBookmarkNodeByID(model, 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); |
| } |
| |
| int BookmarkMoveOperation::GetUndoLabelId() const { |
| return IDS_BOOKMARK_BAR_UNDO_MOVE; |
| } |
| |
| int BookmarkMoveOperation::GetRedoLabelId() const { |
| return IDS_BOOKMARK_BAR_REDO_MOVE; |
| } |
| |
| // 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(BookmarkModel* bookmark_model, |
| const BookmarkNode* parent); |
| ~BookmarkReorderOperation() override; |
| |
| // UndoOperation: |
| void Undo() override; |
| int GetUndoLabelId() const override; |
| int GetRedoLabelId() const override; |
| |
| private: |
| int64_t parent_id_; |
| std::vector<int64_t> ordered_bookmarks_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation); |
| }; |
| |
| BookmarkReorderOperation::BookmarkReorderOperation( |
| BookmarkModel* bookmark_model, |
| const BookmarkNode* parent) |
| : BookmarkUndoOperation(bookmark_model), |
| 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 = bookmark_model(); |
| const BookmarkNode* parent = |
| bookmarks::GetBookmarkNodeByID(model, parent_id_); |
| DCHECK(parent); |
| |
| std::vector<const BookmarkNode*> ordered_nodes; |
| for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) { |
| ordered_nodes.push_back( |
| bookmarks::GetBookmarkNodeByID(model, ordered_bookmarks_[i])); |
| } |
| |
| model->ReorderChildren(parent, ordered_nodes); |
| } |
| |
| int BookmarkReorderOperation::GetUndoLabelId() const { |
| return IDS_BOOKMARK_BAR_UNDO_REORDER; |
| } |
| |
| int BookmarkReorderOperation::GetRedoLabelId() const { |
| return IDS_BOOKMARK_BAR_REDO_REORDER; |
| } |
| |
| } // namespace |
| |
| // BookmarkUndoService -------------------------------------------------------- |
| |
| BookmarkUndoService::BookmarkUndoService() |
| : model_(nullptr), scoped_observer_(this) { |
| } |
| |
| BookmarkUndoService::~BookmarkUndoService() { |
| } |
| |
| void BookmarkUndoService::Start(BookmarkModel* model) { |
| DCHECK(!model_); |
| model_ = model; |
| scoped_observer_.Add(model); |
| model->SetUndoDelegate(this); |
| } |
| |
| void BookmarkUndoService::Shutdown() { |
| DCHECK(model_); |
| scoped_observer_.RemoveAll(); |
| model_->SetUndoDelegate(nullptr); |
| } |
| |
| void BookmarkUndoService::BookmarkModelLoaded(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) { |
| std::unique_ptr<UndoOperation> op(new BookmarkMoveOperation( |
| model, old_parent, old_index, new_parent, new_index)); |
| undo_manager()->AddUndoOperation(std::move(op)); |
| } |
| |
| void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, |
| const BookmarkNode* parent, |
| int index) { |
| std::unique_ptr<UndoOperation> op( |
| new BookmarkAddOperation(model, parent, index)); |
| undo_manager()->AddUndoOperation(std::move(op)); |
| } |
| |
| void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel* model, |
| const BookmarkNode* node) { |
| std::unique_ptr<UndoOperation> op(new BookmarkEditOperation(model, node)); |
| undo_manager()->AddUndoOperation(std::move(op)); |
| } |
| |
| void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel* model, |
| const BookmarkNode* node) { |
| std::unique_ptr<UndoOperation> op(new BookmarkReorderOperation(model, node)); |
| undo_manager()->AddUndoOperation(std::move(op)); |
| } |
| |
| void BookmarkUndoService::GroupedBookmarkChangesBeginning( |
| BookmarkModel* model) { |
| undo_manager()->StartGroupingActions(); |
| } |
| |
| void BookmarkUndoService::GroupedBookmarkChangesEnded(BookmarkModel* model) { |
| undo_manager()->EndGroupingActions(); |
| } |
| |
| void BookmarkUndoService::SetUndoProvider(BookmarkUndoProvider* undo_provider) { |
| undo_provider_ = undo_provider; |
| } |
| |
| void BookmarkUndoService::OnBookmarkNodeRemoved( |
| BookmarkModel* model, |
| const BookmarkNode* parent, |
| int index, |
| std::unique_ptr<BookmarkNode> node) { |
| DCHECK(undo_provider_); |
| std::unique_ptr<UndoOperation> op(new BookmarkRemoveOperation( |
| model, undo_provider_, parent, index, std::move(node))); |
| undo_manager()->AddUndoOperation(std::move(op)); |
| } |