1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SYNC_BOOKMARKS_LOCAL_BOOKMARK_TO_ACCOUNT_MERGER_H_
#define COMPONENTS_SYNC_BOOKMARKS_LOCAL_BOOKMARK_TO_ACCOUNT_MERGER_H_
#include <optional>
#include <set>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
namespace base {
class Location;
} // namespace base
namespace bookmarks {
class BookmarkModel;
class BookmarkNode;
} // namespace bookmarks
namespace sync_bookmarks {
// Class responsible for implementing the merge algorithm that allows moving all
// or some local bookmarks to become account bookmarks, with the ability to
// dedup data.
class LocalBookmarkToAccountMerger {
public:
// `model` must not be null and must outlive this object. It must also be
// loaded and with existing permanent folders for account bookmarks.
explicit LocalBookmarkToAccountMerger(bookmarks::BookmarkModel* model);
LocalBookmarkToAccountMerger(const LocalBookmarkToAccountMerger&) = delete;
LocalBookmarkToAccountMerger& operator=(const LocalBookmarkToAccountMerger&) =
delete;
~LocalBookmarkToAccountMerger();
// Merges all local bookmarks into account bookmarks.
void MoveAndMergeAllNodes();
// Merges a specified subset of local bookmarks into account bookmarks.
//
// `child_ids_to_merge` contains a list of `BookmarkNode::id()` values. Only
// the immediate children of the permanent local folders with these IDs (and
// their descendents) will be merged.
//
// Any IDs that aren't immediate children of the permanent local folders will
// simply be ignored (i.e. the caller does not need to prune them).
void MoveAndMergeSpecificSubtrees(
std::set<int64_t> permanent_folder_child_ids_to_merge);
// Exposed publicly for testing only.
void RemoveChildrenAtForTesting(const bookmarks::BookmarkNode* parent,
const std::vector<size_t>& indices_to_remove,
const base::Location& location);
private:
// Removes an arbitrary set of nodes among siblings under `parent`, as
// selected by `indices_to_remove`. `location` is used for logging purposes
// and investigations.
void RemoveChildrenAt(const bookmarks::BookmarkNode* parent,
const base::flat_set<size_t>& indices_to_remove,
const base::Location& location);
// Internal implementation containing shared logic for `MoveAndMergeAllNodes`
// and `MoveAndMergeSpecificSubtrees`. `child_ids_to_merge` is nullopt for
// `MoveAndMergeAllNodes` and contains the list of IDs for
// `MoveAndMergeSpecificSubtrees`.
void MoveAndMergeInternal(
std::optional<std::set<int64_t>> child_ids_to_merge);
// Moves descendants under `local_subtree_root`, excluding the root itself, to
// append them under `account_subtree_root`. This method tries to remove
// duplicates by UUID or similarity, which results in merging nodes. Both
// `local_subtree_root` and `account_subtree_root` must not be null.
//
// An optional `local_child_ids_to_merge` can be provided, containing a list
// of `BookmarkNode::id()` values. If provided, only the immediate children of
// `local_subtree_root` with these IDs (and their descendents) will be merged.
// If not provided, all descendants of `local_subtree_root` will be merged.
//
// If this is a recursive call (i.e. the parent of `local_subtree_root` is
// being moved), `local_child_ids_to_merge` must be nullopt.
void MoveOrMergeDescendants(
const bookmarks::BookmarkNode* local_subtree_root,
const bookmarks::BookmarkNode* account_subtree_root,
std::optional<std::set<int64_t>> local_child_ids_to_merge);
// Moves descendants under `local_subtree_root` if they match an account node
// by UUID. The remaining local nodes are left unmodified, i.e. those that
// didn't match by UUID and their ancestors didn't either. This is useful when
// a local subtree is about to be moved to account storage because its root
// node didn't match any account node: descendants should move as part of this
// subtree move, *except* those which have a UUID-based match, which should
// take precedence.
void MergeAndDeleteDescendantsThatMatchByUuid(
const bookmarks::BookmarkNode* local_subtree_root);
// Updates `account_node` to hold the same semantics as `local_node`, which
// excludes the UUID (remains unchanged). `account_node` must not be a
// BookmarkPermanentNode.
void UpdateAccountNodeFromMatchingLocalNode(
const bookmarks::BookmarkNode* local_node,
const bookmarks::BookmarkNode* account_node);
// If `account_node` has a local counterpart of the same UUID, returns the
// corresponding local node, otherwise returns a nullptr. `account_node` must
// not be null.
const bookmarks::BookmarkNode* FindMatchingLocalNodeByUuid(
const bookmarks::BookmarkNode* account_node) const;
// If `local_node` has an account counterpart of the same UUID, returns the
// corresponding account node, otherwise returns a nullptr.
const bookmarks::BookmarkNode* FindMatchingAccountNodeByUuid(
const bookmarks::BookmarkNode* local_node) const;
const raw_ptr<bookmarks::BookmarkModel> model_;
};
} // namespace sync_bookmarks
#endif // COMPONENTS_SYNC_BOOKMARKS_LOCAL_BOOKMARK_TO_ACCOUNT_MERGER_H_
|