blob: 7b13341f15ff2b4474e9a8793529bd347762f074 [file] [log] [blame]
// 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 CHROME_BROWSER_BOOKMARKS_PERMANENT_FOLDER_ORDERING_TRACKER_H_
#define CHROME_BROWSER_BOOKMARKS_PERMANENT_FOLDER_ORDERING_TRACKER_H_
#include "base/scoped_observation.h"
#include "components/bookmarks/browser/bookmark_model_observer.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/browser/bookmark_node_data.h"
namespace bookmarks {
class BookmarkModel;
class BookmarkNode;
} // namespace bookmarks
// Tracks any custom order across child nodes of a particular local and account
// permanent bookmark node of a certain type `bookmarks::BookmarkNode::Type`
// (bookmark bar, other, mobile). Manages operations across children of local
// and account equivalent permanent node e.g. add, move, remove bookmark node.
// It also allows querying their direct children while respecting the custom
// order between the children of the two permanent nodes.
// If only local or syncable node exists, this class just forwards operations to
// the `BookmarkModel`.
class PermanentFolderOrderingTracker : public bookmarks::BookmarkModelObserver {
public:
class Delegate {
public:
// Called every time the ordering of the nodes in
// `PermanentFolderOrderingTracker` changes.
virtual void TrackedOrderingChanged() = 0;
virtual ~Delegate() = default;
};
// `tracked_type` must reflect the type of the permanent node, it must be
// one of the following: BOOKMARK_BAR, OTHER_NODE, MOBILE. Other node types
// are invalid.
// `delegate` must not be null and must outlive this class.
PermanentFolderOrderingTracker(bookmarks::BookmarkModel* model,
bookmarks::BookmarkNode::Type tracked_type,
Delegate* delegate);
~PermanentFolderOrderingTracker() override;
PermanentFolderOrderingTracker(const PermanentFolderOrderingTracker&) =
delete;
PermanentFolderOrderingTracker& operator=(
const PermanentFolderOrderingTracker&) = delete;
// This function must be invoked, and ordering will only be tracked
// afterwards.
void Init(std::vector<int64_t> in_order_node_ids);
// Returns underlying permanent nodes.
// If the bookmark model is not loaded, it returns empty.
std::vector<const bookmarks::BookmarkNode*> GetUnderlyingPermanentNodes()
const;
// Returns default parent node for new nodes created as a child of
// `tracked_type_`.
// This will return the account node if one exists, otherwise it returns the
// local/syncable node.
// `BookmarkModel` must be loaded.
const bookmarks::BookmarkNode* GetDefaultParentForNewNodes() const;
// Returns index of `node`.
// `node` must be a direct child of one of the tracked permanent
// nodes in `this`.
size_t GetIndexOf(const bookmarks::BookmarkNode* node) const;
// Returns node at `index`.
const bookmarks::BookmarkNode* GetNodeAtIndex(size_t index) const;
// Returns children count for nodes tracked in this tracker.
size_t GetChildrenCount() const;
// Moves node from an arbitrary parent to become a child of the permanent
// folder tracked by this at `index`.
// If `node` is local or account bookmark, it will remain local/account after
// the move.
// Note that if node is already being tracked by this, there are two possible
// target indices (index) that result in a no-op. This is similar to what
// `BookmarkModel::Move()` does
// Returns the new index or `std::nullopt` if `MoveToIndex` is no-op.
std::optional<size_t> MoveToIndex(const bookmarks::BookmarkNode* node,
size_t index);
// Copies nodes in `elements` to be new child nodes of the permanent
// folder tracked by this starting at `index`.
// The new nodes will be child nodes of `GetDefaultParentForNewNodes()`.
void AddNodesAsCopiesOfNodeData(
const std::vector<bookmarks::BookmarkNodeData::Element>& elements,
size_t index);
// Helper function for optimization purposes, it returns the same value as
// `GetIndexOf()`.
// Returns `in_storage_index` if ordering is not tracked
// `ShouldTrackOrdering()` is false. Otherwise, returns `GetIndexOf()`
size_t GetIndexAcrossStorage(const bookmarks::BookmarkNode* node,
size_t in_storage_index) const;
// Returns true if `ordering` is not empty and has non-default order.
// Default order is all account child nodes then local child nodes.
bool IsNonDefaultOrderingTracked() const;
// bookmarks::BookmarkModelObserver:
void BookmarkModelLoaded(bool ids_reassigned) override;
void BookmarkNodeMoved(const bookmarks::BookmarkNode* old_parent,
size_t old_index,
const bookmarks::BookmarkNode* new_parent,
size_t new_index) override;
void BookmarkNodeAdded(const bookmarks::BookmarkNode* parent,
size_t index,
bool added_by_user) override;
void BookmarkNodeRemoved(const bookmarks::BookmarkNode* parent,
size_t old_index,
const bookmarks::BookmarkNode* node,
const std::set<GURL>& removed_urls,
const base::Location& location) override;
void OnWillRemoveAllUserBookmarks(const base::Location& location) override;
void BookmarkAllUserNodesRemoved(const std::set<GURL>& removed_urls,
const base::Location& location) override;
void BookmarkNodeChanged(const bookmarks::BookmarkNode* node) override {}
void BookmarkNodeFaviconChanged(
const bookmarks::BookmarkNode* node) override {}
void BookmarkNodeChildrenReordered(
const bookmarks::BookmarkNode* node) override;
private:
void NotifyTrackedOrderingChanged();
void SetTrackedPermanentNodes();
bool IsTrackedPermanentNode(const bookmarks::BookmarkNode* node) const;
void ResetOrderingToDefault();
bool ShouldTrackOrdering() const;
size_t GetExpectedOrderingSize() const;
std::vector<raw_ptr<const bookmarks::BookmarkNode>> GetDefaultOrderIfTracked()
const;
void RemoveBookmarkNodeIfTracked(const bookmarks::BookmarkNode* parent,
size_t old_index,
const bookmarks::BookmarkNode* node);
void AddBookmarkNodeIfTracked(const bookmarks::BookmarkNode* parent,
size_t index);
// This function counts bookmarks within the permanent bookmarks folder
// tracked by this. If account_storage is true, it counts bookmarks whose
// parent is account_node_. Otherwise, it counts bookmarks with a parent of
// local_or_syncable_node_, considering only children indexed from 0 to index
// - 1.
size_t GetInStorageBookmarkCountBeforeIndex(bool account_storage,
size_t index) const;
void ReconcileLoadedNodeIds();
const raw_ptr<bookmarks::BookmarkModel> model_;
const bookmarks::BookmarkNode::Type tracked_type_;
const raw_ptr<Delegate> delegate_;
bool initialized_ = false;
raw_ptr<const bookmarks::BookmarkNode> local_or_syncable_node_ = nullptr;
raw_ptr<const bookmarks::BookmarkNode> account_node_ = nullptr;
// Loaded node Ids from disk.
// Only needed while the bookmark model is being loaded.
std::vector<int64_t> loaded_node_ids_during_model_load_;
// Non-empty if both `local_or_syncable_node_` and
// `account_node_` have children (`ShouldTrackOrdering()` returns true).
// If ordering is tracked, the size of the vector is the sum of direct
// children of the `local_or_syncable_node_` and `account_node_` (as returned
// by `GetExpectedOrderingSize()`).
std::vector<raw_ptr<const bookmarks::BookmarkNode>> ordering_;
bool all_user_bookmarks_remove_in_progress_ = false;
base::ScopedObservation<bookmarks::BookmarkModel,
bookmarks::BookmarkModelObserver>
model_observation_{this};
};
#endif // CHROME_BROWSER_BOOKMARKS_PERMANENT_FOLDER_ORDERING_TRACKER_H_