Chromium Code Reviews| 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/bookmarks/bookmark_model.h" | |
| 8 #include "chrome/browser/bookmarks/bookmark_model_factory.h" | |
| 9 #include "chrome/browser/bookmarks/bookmark_node_data.h" | |
| 10 #include "chrome/browser/bookmarks/bookmark_utils.h" | |
| 11 #include "chrome/browser/profiles/profile.h" | |
| 12 #include "chrome/browser/undo/bookmark_undo_service_factory.h" | |
| 13 #include "chrome/browser/undo/undo_manager_utils.h" | |
| 14 #include "chrome/browser/undo/undo_operation.h" | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // BookmarkUndoOperation ------------------------------------------------------ | |
| 19 | |
| 20 // Base class for all bookmark related UndoOperations that facilitates access to | |
| 21 // the BookmarkUndoService. | |
| 22 class BookmarkUndoOperation : public UndoOperation { | |
| 23 public: | |
| 24 explicit BookmarkUndoOperation(Profile* profile); | |
| 25 virtual ~BookmarkUndoOperation() {} | |
| 26 | |
| 27 // If a bookmark node id is renumbered due to an undo operation, the | |
| 28 // BookmarkUndoOperation should be updated with the new id in order to | |
| 29 // properly locate the bookmark node during execution of Undo. | |
| 30 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) = 0; | |
| 31 | |
| 32 BookmarkModel* GetBookmarkModel() const; | |
| 33 BookmarkUndoService* GetBookmarkUndoService() const; | |
| 34 | |
| 35 private: | |
| 36 Profile* profile_; | |
| 37 }; | |
| 38 | |
| 39 BookmarkUndoOperation::BookmarkUndoOperation(Profile* profile) | |
| 40 : profile_(profile) { | |
| 41 } | |
| 42 | |
| 43 BookmarkModel* BookmarkUndoOperation::GetBookmarkModel() const { | |
| 44 return BookmarkModelFactory::GetForProfile(profile_); | |
| 45 } | |
| 46 | |
| 47 BookmarkUndoService* BookmarkUndoOperation::GetBookmarkUndoService() const { | |
| 48 return BookmarkUndoServiceFactory::GetForProfile(profile_); | |
| 49 } | |
| 50 | |
| 51 // BookmarkAddOperation ------------------------------------------------------- | |
| 52 | |
| 53 // Handles the undo of the insertion of a bookmark or folder. | |
| 54 class BookmarkAddOperation : public BookmarkUndoOperation { | |
| 55 public: | |
| 56 BookmarkAddOperation(Profile* profile, const BookmarkNode* parent, int index); | |
| 57 virtual ~BookmarkAddOperation() {} | |
| 58 | |
| 59 // UndoOperation: | |
| 60 virtual void Undo() OVERRIDE; | |
| 61 | |
| 62 // BookmarkUndoOperation: | |
| 63 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
| 64 | |
| 65 private: | |
| 66 int64 parent_id_; | |
| 67 const int index_; | |
| 68 | |
| 69 DISALLOW_COPY_AND_ASSIGN(BookmarkAddOperation); | |
| 70 }; | |
| 71 | |
| 72 BookmarkAddOperation::BookmarkAddOperation(Profile* profile, | |
| 73 const BookmarkNode* parent, | |
| 74 int index) | |
| 75 : BookmarkUndoOperation(profile), | |
| 76 parent_id_(parent->id()), | |
| 77 index_(index) { | |
| 78 } | |
| 79 | |
| 80 void BookmarkAddOperation::Undo() { | |
| 81 BookmarkModel* model = GetBookmarkModel(); | |
| 82 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
| 83 DCHECK(parent); | |
| 84 | |
| 85 model->Remove(parent, index_); | |
| 86 } | |
| 87 | |
| 88 void BookmarkAddOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
| 89 if (parent_id_ == old_id) | |
| 90 parent_id_ = new_id; | |
| 91 } | |
| 92 | |
| 93 // BookmarkRemoveOperation ---------------------------------------------------- | |
| 94 | |
| 95 // Handles the undo of the deletion of a bookmark node. For a bookmark folder, | |
| 96 // the information for all descendant bookmark nodes is maintained. | |
| 97 // | |
| 98 // The BookmarkModel allows only single bookmark node to be removed. | |
| 99 class BookmarkRemoveOperation : public BookmarkUndoOperation { | |
| 100 public: | |
| 101 BookmarkRemoveOperation(Profile* profile, | |
| 102 const BookmarkNode* parent, | |
| 103 int old_index, | |
| 104 const BookmarkNode* node); | |
| 105 virtual ~BookmarkRemoveOperation() {} | |
| 106 | |
| 107 // UndoOperation: | |
| 108 virtual void Undo() OVERRIDE; | |
| 109 | |
| 110 // BookmarkUndoOperation: | |
| 111 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
| 112 | |
| 113 private: | |
| 114 void UpdateBookmarkIds(const BookmarkNodeData::Element& element, | |
| 115 const BookmarkNode* parent, | |
| 116 int index_added_at) const; | |
| 117 | |
| 118 int64 parent_id_; | |
| 119 const int old_index_; | |
| 120 BookmarkNodeData removed_node_; | |
| 121 | |
| 122 DISALLOW_COPY_AND_ASSIGN(BookmarkRemoveOperation); | |
| 123 }; | |
| 124 | |
| 125 BookmarkRemoveOperation::BookmarkRemoveOperation(Profile* profile, | |
| 126 const BookmarkNode* parent, | |
| 127 int old_index, | |
| 128 const BookmarkNode* node) | |
| 129 : BookmarkUndoOperation(profile), | |
| 130 parent_id_(parent->id()), | |
| 131 old_index_(old_index), | |
| 132 removed_node_(node) { | |
| 133 } | |
| 134 | |
| 135 void BookmarkRemoveOperation::Undo() { | |
| 136 DCHECK(removed_node_.is_valid()); | |
| 137 BookmarkModel* model = GetBookmarkModel(); | |
| 138 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
| 139 DCHECK(parent); | |
| 140 | |
| 141 bookmark_utils::CloneBookmarkNode(model, removed_node_.elements, parent, | |
| 142 old_index_, false); | |
| 143 UpdateBookmarkIds(removed_node_.elements[0], parent, old_index_); | |
| 144 } | |
| 145 | |
| 146 void BookmarkRemoveOperation::UpdateBookmarkIds( | |
| 147 const BookmarkNodeData::Element& element, | |
| 148 const BookmarkNode* parent, | |
| 149 int index_added_at) const { | |
| 150 BookmarkModel* model = GetBookmarkModel(); | |
| 151 BookmarkUndoService* undo_service = GetBookmarkUndoService(); | |
| 152 | |
| 153 const BookmarkNode* node = parent->GetChild(index_added_at); | |
| 154 if (element.id() != node->id()) | |
| 155 undo_service->OnBookmarkRenumbered(element.id(), node->id()); | |
| 156 | |
| 157 if (!element.is_url) { | |
| 158 for (int i = 0; i < static_cast<int>(element.children.size()); ++i) | |
| 159 UpdateBookmarkIds(element.children[i], node, 0); | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 void BookmarkRemoveOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
| 164 if (parent_id_ == old_id) | |
| 165 parent_id_ = new_id; | |
| 166 } | |
| 167 | |
| 168 // BookmarkEditOperation ------------------------------------------------------ | |
| 169 | |
| 170 // Handles the undo of the modification of a bookmark node. | |
| 171 class BookmarkEditOperation : public BookmarkUndoOperation { | |
| 172 public: | |
| 173 BookmarkEditOperation(Profile* profile, | |
| 174 const BookmarkNode* node); | |
| 175 virtual ~BookmarkEditOperation() {} | |
| 176 | |
| 177 // UndoOperation: | |
| 178 virtual void Undo() OVERRIDE; | |
| 179 | |
| 180 // BookmarkUndoOperation: | |
| 181 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
| 182 | |
| 183 private: | |
| 184 int64 node_id_; | |
| 185 BookmarkNodeData original_bookmark_; | |
| 186 | |
| 187 DISALLOW_COPY_AND_ASSIGN(BookmarkEditOperation); | |
| 188 }; | |
| 189 | |
| 190 BookmarkEditOperation::BookmarkEditOperation(Profile* profile, | |
| 191 const BookmarkNode* node) | |
| 192 : BookmarkUndoOperation(profile), | |
| 193 node_id_(node->id()), | |
| 194 original_bookmark_(node) { | |
| 195 } | |
| 196 | |
| 197 void BookmarkEditOperation::Undo() { | |
| 198 DCHECK(original_bookmark_.is_valid()); | |
| 199 BookmarkModel* model = GetBookmarkModel(); | |
| 200 const BookmarkNode* node = model->GetNodeByID(node_id_); | |
| 201 DCHECK(node); | |
| 202 | |
| 203 model->SetTitle(node, original_bookmark_.elements[0].title); | |
| 204 if (original_bookmark_.elements[0].is_url) | |
| 205 model->SetURL(node, original_bookmark_.elements[0].url); | |
|
sky
2013/08/27 22:24:18
nit: spacing is off.
Tom Cassiotis
2013/09/04 13:44:43
Done.
| |
| 206 } | |
| 207 | |
| 208 void BookmarkEditOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
| 209 if (node_id_ == old_id) | |
| 210 node_id_ = new_id; | |
| 211 } | |
| 212 | |
| 213 // BookmarkMoveOperation ------------------------------------------------------ | |
| 214 | |
| 215 // Handles the undo of a bookmark being moved to a new location. | |
| 216 class BookmarkMoveOperation : public BookmarkUndoOperation { | |
| 217 public: | |
| 218 BookmarkMoveOperation(Profile* profile, | |
| 219 const BookmarkNode* old_parent, | |
| 220 int old_index, | |
| 221 const BookmarkNode* new_parent, | |
| 222 int new_index); | |
| 223 virtual ~BookmarkMoveOperation() {} | |
| 224 | |
| 225 // UndoOperation: | |
| 226 virtual void Undo() OVERRIDE; | |
| 227 | |
| 228 // BookmarkUndoOperation: | |
| 229 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
| 230 | |
| 231 private: | |
| 232 int64 old_parent_id_; | |
| 233 int64 new_parent_id_; | |
| 234 int old_index_; | |
| 235 int new_index_; | |
| 236 | |
| 237 DISALLOW_COPY_AND_ASSIGN(BookmarkMoveOperation); | |
| 238 }; | |
| 239 | |
| 240 BookmarkMoveOperation::BookmarkMoveOperation(Profile* profile, | |
| 241 const BookmarkNode* old_parent, | |
| 242 int old_index, | |
| 243 const BookmarkNode* new_parent, | |
| 244 int new_index) | |
| 245 : BookmarkUndoOperation(profile), | |
| 246 old_parent_id_(old_parent->id()), | |
| 247 old_index_(old_index), | |
| 248 new_parent_id_(new_parent->id()), | |
| 249 new_index_(new_index) { | |
| 250 } | |
| 251 | |
| 252 void BookmarkMoveOperation::Undo() { | |
| 253 BookmarkModel* model = GetBookmarkModel(); | |
| 254 const BookmarkNode* old_parent = model->GetNodeByID(old_parent_id_); | |
| 255 const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id_); | |
| 256 DCHECK(old_parent); | |
| 257 DCHECK(new_parent); | |
| 258 | |
| 259 const BookmarkNode* node = new_parent->GetChild(new_index_); | |
| 260 int destination_index = old_index_; | |
| 261 | |
| 262 // If the bookmark was moved up within the same parent then the destination | |
| 263 // index needs to be incremented since the old index did not account for the | |
| 264 // moved bookmark. | |
| 265 if (old_parent == new_parent && new_index_ < old_index_) | |
| 266 ++destination_index; | |
| 267 | |
| 268 model->Move(node, old_parent, destination_index); | |
| 269 } | |
| 270 | |
| 271 void BookmarkMoveOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
| 272 if (old_parent_id_ == old_id) | |
| 273 old_parent_id_ = new_id; | |
| 274 if (new_parent_id_ == old_id) | |
| 275 new_parent_id_ = new_id; | |
| 276 } | |
| 277 | |
| 278 // BookmarkReorderOperation --------------------------------------------------- | |
| 279 | |
| 280 // Handle the undo of reordering of bookmarks that can happen as a result of | |
| 281 // sorting a bookmark folder by name or the undo of that operation. The change | |
| 282 // of order is not recursive so only the order of the immediate children of the | |
| 283 // folder need to be restored. | |
| 284 class BookmarkReorderOperation : public BookmarkUndoOperation { | |
| 285 public: | |
| 286 BookmarkReorderOperation(Profile* profile, | |
| 287 const BookmarkNode* parent); | |
| 288 virtual ~BookmarkReorderOperation(); | |
| 289 | |
| 290 // UndoOperation: | |
| 291 virtual void Undo() OVERRIDE; | |
| 292 | |
| 293 // BookmarkUndoOperation: | |
| 294 virtual void RenumberBookmarkId(int64 old_id, int64 new_id) OVERRIDE; | |
| 295 | |
| 296 private: | |
| 297 int64 parent_id_; | |
| 298 std::vector<int64> ordered_bookmarks_; | |
| 299 | |
| 300 DISALLOW_COPY_AND_ASSIGN(BookmarkReorderOperation); | |
| 301 }; | |
| 302 | |
| 303 BookmarkReorderOperation::BookmarkReorderOperation(Profile* profile, | |
| 304 const BookmarkNode* parent) | |
| 305 : BookmarkUndoOperation(profile), | |
| 306 parent_id_(parent->id()) { | |
| 307 ordered_bookmarks_.resize(parent->child_count()); | |
| 308 for (int i = 0; i < parent->child_count(); ++i) | |
| 309 ordered_bookmarks_[i] = parent->GetChild(i)->id(); | |
| 310 } | |
| 311 | |
| 312 BookmarkReorderOperation::~BookmarkReorderOperation() { | |
| 313 } | |
| 314 | |
| 315 void BookmarkReorderOperation::Undo() { | |
| 316 BookmarkModel* model = GetBookmarkModel(); | |
| 317 const BookmarkNode* parent = model->GetNodeByID(parent_id_); | |
| 318 DCHECK(parent); | |
| 319 | |
| 320 std::vector<const BookmarkNode*> ordered_nodes; | |
| 321 for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) | |
| 322 ordered_nodes.push_back(model->GetNodeByID(ordered_bookmarks_[i])); | |
| 323 | |
| 324 model->ReorderChildren(parent, ordered_nodes); | |
| 325 } | |
| 326 | |
| 327 void BookmarkReorderOperation::RenumberBookmarkId(int64 old_id, int64 new_id) { | |
| 328 if (parent_id_ == old_id) | |
| 329 parent_id_ = new_id; | |
| 330 for (size_t i = 0; i < ordered_bookmarks_.size(); ++i) { | |
| 331 if (ordered_bookmarks_[i] == old_id) | |
| 332 ordered_bookmarks_[i] = new_id; | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 } // namespace | |
| 337 | |
| 338 // BookmarkUndoService -------------------------------------------------------- | |
| 339 | |
| 340 BookmarkUndoService::BookmarkUndoService(Profile* profile) : profile_(profile) { | |
| 341 BookmarkModelFactory::GetForProfile(profile_)->AddObserver(this); | |
| 342 } | |
| 343 | |
| 344 BookmarkUndoService::~BookmarkUndoService() { | |
| 345 BookmarkModelFactory::GetForProfile(profile_)->RemoveObserver(this); | |
| 346 } | |
| 347 | |
| 348 void BookmarkUndoService::OnBookmarkRenumbered(int64 old_id, int64 new_id) { | |
| 349 std::vector<UndoOperation*> all_operations = | |
| 350 undo_manager()->GetAllUndoOperations(); | |
| 351 for (std::vector<UndoOperation*>::iterator it = all_operations.begin(); | |
| 352 it != all_operations.end(); ++it) { | |
| 353 static_cast<BookmarkUndoOperation*>(*it)->RenumberBookmarkId(old_id, | |
| 354 new_id); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 void BookmarkUndoService::Loaded(BookmarkModel* model, bool ids_reassigned) { | |
| 359 undo_manager_.RemoveAllOperations(); | |
| 360 } | |
| 361 | |
| 362 void BookmarkUndoService::BookmarkModelBeingDeleted(BookmarkModel* model) { | |
| 363 undo_manager_.RemoveAllOperations(); | |
| 364 } | |
| 365 | |
| 366 void BookmarkUndoService::BookmarkNodeMoved(BookmarkModel* model, | |
| 367 const BookmarkNode* old_parent, | |
| 368 int old_index, | |
| 369 const BookmarkNode* new_parent, | |
| 370 int new_index) { | |
| 371 scoped_ptr<UndoOperation> op(new BookmarkMoveOperation(profile_, | |
| 372 old_parent, | |
| 373 old_index, | |
| 374 new_parent, | |
| 375 new_index)); | |
| 376 undo_manager()->AddUndoOperation(op.Pass()); | |
| 377 } | |
| 378 | |
| 379 void BookmarkUndoService::BookmarkNodeAdded(BookmarkModel* model, | |
| 380 const BookmarkNode* parent, | |
| 381 int index) { | |
| 382 scoped_ptr<UndoOperation> op(new BookmarkAddOperation(profile_, | |
| 383 parent, | |
| 384 index)); | |
| 385 undo_manager()->AddUndoOperation(op.Pass()); | |
| 386 } | |
| 387 | |
| 388 void BookmarkUndoService::OnWillRemoveBookmarks(BookmarkModel* model, | |
| 389 const BookmarkNode* parent, | |
| 390 int old_index, | |
| 391 const BookmarkNode* node) { | |
| 392 scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, | |
| 393 parent, | |
| 394 old_index, | |
| 395 node)); | |
| 396 undo_manager()->AddUndoOperation(op.Pass()); | |
| 397 } | |
| 398 | |
| 399 void BookmarkUndoService::OnWillRemoveAllBookmarks(BookmarkModel* model) { | |
| 400 ScopedGroupingAction merge_removes(undo_manager()); | |
| 401 for (int i = 0; i < model->root_node()->child_count(); ++i) { | |
| 402 const BookmarkNode* permanent_node = model->root_node()->GetChild(i); | |
| 403 for (int j = permanent_node->child_count() - 1; j >= 0; --j) { | |
| 404 scoped_ptr<UndoOperation> op(new BookmarkRemoveOperation(profile_, | |
| 405 permanent_node, j, permanent_node->GetChild(j))); | |
| 406 undo_manager()->AddUndoOperation(op.Pass()); | |
| 407 } | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 void BookmarkUndoService::OnWillChangeBookmarkNode(BookmarkModel* model, | |
| 412 const BookmarkNode* node) { | |
| 413 scoped_ptr<UndoOperation> op(new BookmarkEditOperation(profile_, node)); | |
| 414 undo_manager()->AddUndoOperation(op.Pass()); | |
| 415 } | |
| 416 | |
| 417 void BookmarkUndoService::OnWillReorderBookmarkNode(BookmarkModel* model, | |
| 418 const BookmarkNode* node) { | |
| 419 scoped_ptr<UndoOperation> op(new BookmarkReorderOperation(profile_, node)); | |
| 420 undo_manager()->AddUndoOperation(op.Pass()); | |
| 421 } | |
| OLD | NEW |