| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/glue/bookmark_change_processor.h" | 5 #include "chrome/browser/sync/glue/bookmark_change_processor.h" |
| 6 | 6 |
| 7 #include <stack> | 7 #include <stack> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/string16.h" | 10 #include "base/string16.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/tracked.h" | 12 #include "base/tracked.h" |
| 13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
| 14 #include "chrome/browser/bookmarks/bookmark_model.h" | 14 #include "chrome/browser/bookmarks/bookmark_model.h" |
| 15 #include "chrome/browser/bookmarks/bookmark_utils.h" | 15 #include "chrome/browser/bookmarks/bookmark_utils.h" |
| 16 #include "chrome/browser/favicon/favicon_service.h" | 16 #include "chrome/browser/favicon/favicon_service.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/browser/sync/internal_api/change_record.h" |
| 18 #include "chrome/browser/sync/internal_api/read_node.h" | 19 #include "chrome/browser/sync/internal_api/read_node.h" |
| 19 #include "chrome/browser/sync/internal_api/write_node.h" | 20 #include "chrome/browser/sync/internal_api/write_node.h" |
| 20 #include "chrome/browser/sync/internal_api/write_transaction.h" | 21 #include "chrome/browser/sync/internal_api/write_transaction.h" |
| 21 #include "chrome/browser/sync/profile_sync_service.h" | 22 #include "chrome/browser/sync/profile_sync_service.h" |
| 22 #include "content/browser/browser_thread.h" | 23 #include "content/browser/browser_thread.h" |
| 23 #include "third_party/skia/include/core/SkBitmap.h" | 24 #include "third_party/skia/include/core/SkBitmap.h" |
| 24 #include "ui/gfx/codec/png_codec.h" | 25 #include "ui/gfx/codec/png_codec.h" |
| 25 | 26 |
| 26 namespace browser_sync { | 27 namespace browser_sync { |
| 27 | 28 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 DCHECK(predecessor); | 349 DCHECK(predecessor); |
| 349 DCHECK_EQ(predecessor->parent(), parent); | 350 DCHECK_EQ(predecessor->parent(), parent); |
| 350 return parent->GetIndexOf(predecessor) + 1; | 351 return parent->GetIndexOf(predecessor) + 1; |
| 351 } | 352 } |
| 352 | 353 |
| 353 // ApplyModelChanges is called by the sync backend after changes have been made | 354 // ApplyModelChanges is called by the sync backend after changes have been made |
| 354 // to the sync engine's model. Apply these changes to the browser bookmark | 355 // to the sync engine's model. Apply these changes to the browser bookmark |
| 355 // model. | 356 // model. |
| 356 void BookmarkChangeProcessor::ApplyChangesFromSyncModel( | 357 void BookmarkChangeProcessor::ApplyChangesFromSyncModel( |
| 357 const sync_api::BaseTransaction* trans, | 358 const sync_api::BaseTransaction* trans, |
| 358 const sync_api::SyncManager::ChangeRecord* changes, | 359 const sync_api::ImmutableChangeRecordList& changes) { |
| 359 int change_count) { | |
| 360 if (!running()) | 360 if (!running()) |
| 361 return; | 361 return; |
| 362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 363 // A note about ordering. Sync backend is responsible for ordering the change | 363 // A note about ordering. Sync backend is responsible for ordering the change |
| 364 // records in the following order: | 364 // records in the following order: |
| 365 // | 365 // |
| 366 // 1. Deletions, from leaves up to parents. | 366 // 1. Deletions, from leaves up to parents. |
| 367 // 2. Existing items with synced parents & predecessors. | 367 // 2. Existing items with synced parents & predecessors. |
| 368 // 3. New items with synced parents & predecessors. | 368 // 3. New items with synced parents & predecessors. |
| 369 // 4. Items with parents & predecessors in the list. | 369 // 4. Items with parents & predecessors in the list. |
| 370 // 5. Repeat #4 until all items are in the list. | 370 // 5. Repeat #4 until all items are in the list. |
| 371 // | 371 // |
| 372 // "Predecessor" here means the previous item within a given folder; an item | 372 // "Predecessor" here means the previous item within a given folder; an item |
| 373 // in the first position is always said to have a synced predecessor. | 373 // in the first position is always said to have a synced predecessor. |
| 374 // For the most part, applying these changes in the order given will yield | 374 // For the most part, applying these changes in the order given will yield |
| 375 // the correct result. There is one exception, however: for items that are | 375 // the correct result. There is one exception, however: for items that are |
| 376 // moved away from a folder that is being deleted, we will process the delete | 376 // moved away from a folder that is being deleted, we will process the delete |
| 377 // before the move. Since deletions in the bookmark model propagate from | 377 // before the move. Since deletions in the bookmark model propagate from |
| 378 // parent to child, we must move them to a temporary location. | 378 // parent to child, we must move them to a temporary location. |
| 379 BookmarkModel* model = bookmark_model_; | 379 BookmarkModel* model = bookmark_model_; |
| 380 | 380 |
| 381 // We are going to make changes to the bookmarks model, but don't want to end | 381 // We are going to make changes to the bookmarks model, but don't want to end |
| 382 // up in a feedback loop, so remove ourselves as an observer while applying | 382 // up in a feedback loop, so remove ourselves as an observer while applying |
| 383 // changes. | 383 // changes. |
| 384 model->RemoveObserver(this); | 384 model->RemoveObserver(this); |
| 385 | 385 |
| 386 // A parent to hold nodes temporarily orphaned by parent deletion. It is | 386 // A parent to hold nodes temporarily orphaned by parent deletion. It is |
| 387 // lazily created inside the loop. | 387 // lazily created inside the loop. |
| 388 const BookmarkNode* foster_parent = NULL; | 388 const BookmarkNode* foster_parent = NULL; |
| 389 for (int i = 0; i < change_count; ++i) { | 389 |
| 390 // Whether we have passed all the deletes (which should be at the |
| 391 // front of the list). |
| 392 bool passed_deletes = false; |
| 393 for (sync_api::ChangeRecordList::const_iterator it = |
| 394 changes.Get().begin(); it != changes.Get().end(); ++it) { |
| 390 const BookmarkNode* dst = | 395 const BookmarkNode* dst = |
| 391 model_associator_->GetChromeNodeFromSyncId(changes[i].id); | 396 model_associator_->GetChromeNodeFromSyncId(it->id); |
| 392 // Ignore changes to the permanent top-level nodes. We only care about | 397 // Ignore changes to the permanent top-level nodes. We only care about |
| 393 // their children. | 398 // their children. |
| 394 if (model->is_permanent_node(dst)) | 399 if (model->is_permanent_node(dst)) |
| 395 continue; | 400 continue; |
| 396 if (changes[i].action == | 401 if (it->action == |
| 397 sync_api::SyncManager::ChangeRecord::ACTION_DELETE) { | 402 sync_api::ChangeRecord::ACTION_DELETE) { |
| 398 // Deletions should always be at the front of the list. | 403 // Deletions should always be at the front of the list. |
| 399 DCHECK(i == 0 || changes[i-1].action == changes[i].action); | 404 DCHECK(!passed_deletes); |
| 400 // Children of a deleted node should not be deleted; they may be | 405 // Children of a deleted node should not be deleted; they may be |
| 401 // reparented by a later change record. Move them to a temporary place. | 406 // reparented by a later change record. Move them to a temporary place. |
| 402 if (!dst) // Can't do anything if we can't find the chrome node. | 407 if (!dst) // Can't do anything if we can't find the chrome node. |
| 403 continue; | 408 continue; |
| 404 const BookmarkNode* parent = dst->parent(); | 409 const BookmarkNode* parent = dst->parent(); |
| 405 if (!dst->empty()) { | 410 if (!dst->empty()) { |
| 406 if (!foster_parent) { | 411 if (!foster_parent) { |
| 407 foster_parent = model->AddFolder(model->other_node(), | 412 foster_parent = model->AddFolder(model->other_node(), |
| 408 model->other_node()->child_count(), | 413 model->other_node()->child_count(), |
| 409 string16()); | 414 string16()); |
| 410 } | 415 } |
| 411 for (int i = dst->child_count() - 1; i >= 0; --i) { | 416 for (int i = dst->child_count() - 1; i >= 0; --i) { |
| 412 model->Move(dst->GetChild(i), foster_parent, | 417 model->Move(dst->GetChild(i), foster_parent, |
| 413 foster_parent->child_count()); | 418 foster_parent->child_count()); |
| 414 } | 419 } |
| 415 } | 420 } |
| 416 DCHECK_EQ(dst->child_count(), 0) << "Node being deleted has children"; | 421 DCHECK_EQ(dst->child_count(), 0) << "Node being deleted has children"; |
| 417 model_associator_->Disassociate(changes[i].id); | 422 model_associator_->Disassociate(it->id); |
| 418 int index = parent->GetIndexOf(dst); | 423 int index = parent->GetIndexOf(dst); |
| 419 if (index > -1) | 424 if (index > -1) |
| 420 model->Remove(parent, index); | 425 model->Remove(parent, index); |
| 421 dst = NULL; | 426 dst = NULL; |
| 422 } else { | 427 } else { |
| 423 DCHECK_EQ((changes[i].action == | 428 DCHECK_EQ((it->action == |
| 424 sync_api::SyncManager::ChangeRecord::ACTION_ADD), (dst == NULL)) | 429 sync_api::ChangeRecord::ACTION_ADD), (dst == NULL)) |
| 425 << "ACTION_ADD should be seen if and only if the node is unknown."; | 430 << "ACTION_ADD should be seen if and only if the node is unknown."; |
| 431 passed_deletes = true; |
| 426 | 432 |
| 427 sync_api::ReadNode src(trans); | 433 sync_api::ReadNode src(trans); |
| 428 if (!src.InitByIdLookup(changes[i].id)) { | 434 if (!src.InitByIdLookup(it->id)) { |
| 429 error_handler()->OnUnrecoverableError(FROM_HERE, | 435 error_handler()->OnUnrecoverableError(FROM_HERE, |
| 430 "ApplyModelChanges was passed a bad ID"); | 436 "ApplyModelChanges was passed a bad ID"); |
| 431 return; | 437 return; |
| 432 } | 438 } |
| 433 | 439 |
| 434 CreateOrUpdateBookmarkNode(&src, model); | 440 CreateOrUpdateBookmarkNode(&src, model); |
| 435 } | 441 } |
| 436 } | 442 } |
| 437 // Clean up the temporary node. | 443 // Clean up the temporary node. |
| 438 if (foster_parent) { | 444 if (foster_parent) { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 const BookmarkNode* bookmark_node, | 562 const BookmarkNode* bookmark_node, |
| 557 BookmarkModel* model, | 563 BookmarkModel* model, |
| 558 sync_api::WriteNode* sync_node) { | 564 sync_api::WriteNode* sync_node) { |
| 559 std::vector<unsigned char> favicon_bytes; | 565 std::vector<unsigned char> favicon_bytes; |
| 560 EncodeFavicon(bookmark_node, model, &favicon_bytes); | 566 EncodeFavicon(bookmark_node, model, &favicon_bytes); |
| 561 if (!favicon_bytes.empty()) | 567 if (!favicon_bytes.empty()) |
| 562 sync_node->SetFaviconBytes(favicon_bytes); | 568 sync_node->SetFaviconBytes(favicon_bytes); |
| 563 } | 569 } |
| 564 | 570 |
| 565 } // namespace browser_sync | 571 } // namespace browser_sync |
| OLD | NEW |