#ifndef UI_BASE_MODELS_TREE_NODE_MODEL_H_
#define UI_BASE_MODELS_TREE_NODE_MODEL_H_
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/check_op.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "ui/base/models/tree_model.h"
namespace ui {
template <class NodeType>
class TreeNode : public TreeModelNode {
public:
using TreeNodes = std::vector<std::unique_ptr<NodeType>>;
TreeNode() : parent_(nullptr) {}
explicit TreeNode(const std::u16string& title)
: title_(title), parent_(nullptr) {}
TreeNode(const TreeNode&) = delete;
TreeNode& operator=(const TreeNode&) = delete;
~TreeNode() override {}
NodeType* Add(std::unique_ptr<NodeType> node, size_t index) {
DCHECK(node);
DCHECK_LE(index, children_.size());
DCHECK(!node->parent_);
node->parent_ = static_cast<NodeType*>(this);
NodeType* node_ptr = node.get();
children_.insert(children_.begin() + static_cast<ptrdiff_t>(index),
std::move(node));
return node_ptr;
}
NodeType* Add(std::unique_ptr<NodeType> node) {
return Add(std::move(node), children_.size());
}
std::unique_ptr<NodeType> Remove(size_t index) {
DCHECK_LT(index, children_.size());
children_[index]->parent_ = nullptr;
std::unique_ptr<NodeType> ptr = std::move(children_[index]);
children_.erase(children_.begin() + static_cast<ptrdiff_t>(index));
return ptr;
}
void DeleteAll() { children_.clear(); }
const NodeType* parent() const { return parent_; }
NodeType* parent() { return parent_; }
bool is_root() const { return parent_ == nullptr; }
const TreeNodes& children() const { return children_; }
size_t GetTotalNodeCount() const {
size_t count = 1;
for (const auto& child : children_)
count += child->GetTotalNodeCount();
return count;
}
std::optional<size_t> GetIndexOf(const NodeType* node) const {
DCHECK(node);
const auto i =
std::ranges::find(children_, node, &std::unique_ptr<NodeType>::get);
return i != children_.end()
? std::make_optional(static_cast<size_t>(i - children_.begin()))
: std::nullopt;
}
virtual void SetTitle(const std::u16string& title) { title_ = title; }
const std::u16string& GetTitle() const override { return title_; }
const std::u16string& GetAccessibleTitle() const override {
return title_.empty() ? placeholder_accessible_title_ : title_;
}
void SetPlaceholderAccessibleTitle(
std::u16string placeholder_accessible_title) {
placeholder_accessible_title_ = placeholder_accessible_title;
}
bool HasAncestor(const NodeType* ancestor) const {
if (ancestor == this)
return true;
if (!ancestor)
return false;
return parent_ ? parent_->HasAncestor(ancestor) : false;
}
void ReorderChildren(const std::vector<size_t>& new_order) {
const size_t children_count = children_.size();
DCHECK_EQ(children_count, new_order.size());
DCHECK_EQ(children_count,
std::set(new_order.begin(), new_order.end()).size());
TreeNodes new_children(children_count);
for (size_t old_index = 0; old_index < children_count; ++old_index) {
const size_t new_index = new_order[old_index];
DCHECK_LT(new_index, children_count);
DCHECK(children_[old_index]);
DCHECK(!new_children[new_index]);
new_children[new_index] = std::move(children_[old_index]);
}
children_ = std::move(new_children);
}
template <typename Compare>
void SortChildren(Compare comp) {
std::stable_sort(children_.begin(), children_.end(), comp);
}
private:
std::u16string title_;
std::u16string placeholder_accessible_title_;
raw_ptr<NodeType> parent_;
TreeNodes children_;
};
template <class ValueType>
class TreeNodeWithValue : public TreeNode<TreeNodeWithValue<ValueType>> {
public:
TreeNodeWithValue() {}
explicit TreeNodeWithValue(const ValueType& value)
: ParentType(std::u16string()), value(value) {}
TreeNodeWithValue(const std::u16string& title, const ValueType& value)
: ParentType(title), value(value) {}
TreeNodeWithValue(const TreeNodeWithValue&) = delete;
TreeNodeWithValue& operator=(const TreeNodeWithValue&) = delete;
ValueType value;
private:
using ParentType = TreeNode<TreeNodeWithValue<ValueType>>;
};
template <class NodeType>
class TreeNodeModel : public TreeModel {
public:
explicit TreeNodeModel(std::unique_ptr<NodeType> root)
: root_(std::move(root)) {}
TreeNodeModel(const TreeNodeModel&) = delete;
TreeNodeModel& operator=(const TreeNodeModel&) = delete;
virtual ~TreeNodeModel() override {}
static NodeType* AsNode(TreeModelNode* model_node) {
return static_cast<NodeType*>(model_node);
}
static const NodeType* AsNode(const TreeModelNode* model_node) {
return static_cast<const NodeType*>(model_node);
}
NodeType* Add(NodeType* parent,
std::unique_ptr<NodeType> node,
size_t index) {
DCHECK(parent);
DCHECK(node);
NodeType* node_ptr = parent->Add(std::move(node), index);
NotifyObserverTreeNodeAdded(parent, index);
return node_ptr;
}
NodeType* Add(NodeType* parent, std::unique_ptr<NodeType> node) {
return Add(parent, std::move(node), parent->children().size());
}
std::unique_ptr<NodeType> Remove(NodeType* parent, size_t index) {
DCHECK(parent);
std::unique_ptr<NodeType> owned_node = parent->Remove(index);
NotifyObserverTreeNodeRemoved(parent, index);
return owned_node;
}
std::unique_ptr<NodeType> Remove(NodeType* parent, NodeType* node) {
DCHECK(parent);
return Remove(parent, parent->GetIndexOf(node).value());
}
void NotifyObserverTreeNodeAdded(NodeType* parent, size_t index) {
observer_list_.Notify(&TreeModelObserver::TreeNodeAdded, this, parent,
index);
}
void NotifyObserverTreeNodeRemoved(NodeType* parent, size_t index) {
observer_list_.Notify(&TreeModelObserver::TreeNodeRemoved, this, parent,
index);
}
void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
observer_list_.Notify(&TreeModelObserver::TreeNodeChanged, this, node);
}
NodeType* GetRoot() override {
return root_.get();
}
Nodes GetChildren(const TreeModelNode* parent) const override {
DCHECK(parent);
const auto& children = AsNode(parent)->children();
Nodes nodes;
nodes.reserve(children.size());
std::ranges::transform(children, std::back_inserter(nodes),
&TreeNode<NodeType>::TreeNodes::value_type::get);
return nodes;
}
std::optional<size_t> GetIndexOf(TreeModelNode* parent,
TreeModelNode* child) const override {
DCHECK(parent);
return AsNode(parent)->GetIndexOf(AsNode(child));
}
TreeModelNode* GetParent(TreeModelNode* node) const override {
DCHECK(node);
return AsNode(node)->parent();
}
void AddObserver(TreeModelObserver* observer) override {
observer_list_.AddObserver(observer);
}
void RemoveObserver(TreeModelObserver* observer) override {
observer_list_.RemoveObserver(observer);
}
void SetTitle(TreeModelNode* node, const std::u16string& title) override {
DCHECK(node);
AsNode(node)->SetTitle(title);
NotifyObserverTreeNodeChanged(node);
}
private:
base::ObserverList<TreeModelObserver>::Unchecked observer_list_;
std::unique_ptr<NodeType> root_;
};
}
#endif