[email protected] | 3cb676a1 | 2012-06-30 15:46:03 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
license.bot | bf09a50 | 2008-08-24 00:55:55 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 4 | |
[email protected] | 44cbd9e | 2011-01-14 15:49:40 | [diff] [blame] | 5 | #ifndef UI_BASE_MODELS_TREE_NODE_MODEL_H_ |
| 6 | #define UI_BASE_MODELS_TREE_NODE_MODEL_H_ |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 7 | |
avi | 20f6a6d53 | 2015-12-23 08:05:24 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | |
[email protected] | 775cfd76 | 2008-12-09 17:12:12 | [diff] [blame] | 10 | #include <algorithm> |
danakj | 25c52c3 | 2016-04-12 21:51:08 | [diff] [blame] | 11 | #include <memory> |
Mikel Astiz | e83917a | 2022-01-27 20:21:03 | [diff] [blame] | 12 | #include <set> |
Jan Wilken Dörrie | ad587c3 | 2021-03-11 14:09:27 | [diff] [blame] | 13 | #include <string> |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 14 | #include <vector> |
| 15 | |
Hans Wennborg | 4b46b3b | 2020-06-23 08:29:08 | [diff] [blame] | 16 | #include "base/check_op.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 17 | #include "base/memory/raw_ptr.h" |
[email protected] | 0457c6b | 2010-02-10 18:44:48 | [diff] [blame] | 18 | #include "base/observer_list.h" |
[email protected] | 44cbd9e | 2011-01-14 15:49:40 | [diff] [blame] | 19 | #include "ui/base/models/tree_model.h" |
| 20 | |
| 21 | namespace ui { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 22 | |
| 23 | // TreeNodeModel and TreeNodes provide an implementation of TreeModel around |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 24 | // TreeNodes. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 25 | // |
| 26 | // TreeNodes own their children, so that deleting a node deletes all |
| 27 | // descendants. |
| 28 | // |
| 29 | // TreeNodes do NOT maintain a pointer back to the model. As such, if you |
| 30 | // are using TreeNodes with a TreeNodeModel you will need to notify the observer |
| 31 | // yourself any time you make any change directly to the TreeNodes. For example, |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 32 | // if you directly invoke set_title on a node it does not notify the observer, |
| 33 | // you will need to do it yourself. This includes the following methods: Add, |
| 34 | // Remove and set_title. TreeNodeModel provides cover methods that mutate the |
| 35 | // TreeNodes and notify the observer. If you are using TreeNodes with a |
| 36 | // TreeNodeModel use the cover methods to save yourself the headache. |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 37 | // |
| 38 | // The following example creates a TreeNode with two children and then |
| 39 | // creates a TreeNodeModel from it: |
| 40 | // |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 41 | // std::unique_ptr<TreeNodeWithValue<int>> root = |
Jeremy Roman | b460057 | 2017-10-17 01:31:50 | [diff] [blame] | 42 | // std::make_unique<TreeNodeWithValue<int>>(); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 43 | // root->Add( |
Jan Wilken Dörrie | 8aeb574 | 2021-03-23 19:27:02 | [diff] [blame] | 44 | // std::make_unique<TreeNodeWithValue<int>>(u"child 1", 0)); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 45 | // root->Add( |
Jan Wilken Dörrie | 8aeb574 | 2021-03-23 19:27:02 | [diff] [blame] | 46 | // std::make_unique<TreeNodeWithValue<int>>(u"child 2", 1)); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 47 | // TreeNodeModel<TreeNodeWithValue<int>> model(std::move(root)); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 48 | // |
| 49 | // Two variants of TreeNode are provided here: |
| 50 | // |
| 51 | // . TreeNode itself is intended for subclassing. It has one type parameter |
| 52 | // that corresponds to the type of the node. When subclassing use your class |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 53 | // name as the type parameter, e.g.: |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 54 | // class MyTreeNode : public TreeNode<MyTreeNode> . |
| 55 | // . TreeNodeWithValue is a trivial subclass of TreeNode that has one type |
| 56 | // type parameter: a value type that is associated with the node. |
| 57 | // |
| 58 | // Which you use depends upon the situation. If you want to subclass and add |
| 59 | // methods, then use TreeNode. If you don't need any extra methods and just |
| 60 | // want to associate a value with each node, then use TreeNodeWithValue. |
| 61 | // |
| 62 | // Regardless of which TreeNode you use, if you are using the nodes with a |
| 63 | // TreeView take care to notify the observer when mutating the nodes. |
| 64 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 65 | // TreeNode ------------------------------------------------------------------- |
| 66 | |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 67 | // See above for documentation. Example: |
| 68 | // |
| 69 | // class MyNode : public ui::TreeNode<MyNode> { |
| 70 | // ...<custom class logic>... |
| 71 | // }; |
| 72 | // using MyModel = ui::TreeNodeModel<MyNode>; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 73 | template <class NodeType> |
| 74 | class TreeNode : public TreeModelNode { |
| 75 | public: |
Peter Kasting | fc86fec6 | 2019-05-21 20:43:47 | [diff] [blame] | 76 | using TreeNodes = std::vector<std::unique_ptr<NodeType>>; |
| 77 | |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 78 | TreeNode() : parent_(nullptr) {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 79 | |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 80 | explicit TreeNode(const std::u16string& title) |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 81 | : title_(title), parent_(nullptr) {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 82 | |
Peter Boström | c8c1235 | 2021-09-21 23:37:15 | [diff] [blame] | 83 | TreeNode(const TreeNode&) = delete; |
| 84 | TreeNode& operator=(const TreeNode&) = delete; |
| 85 | |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 86 | ~TreeNode() override {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 87 | |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 88 | // Adds |node| as a child of this node, at |index|. Returns a raw pointer to |
| 89 | // the node. |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 90 | NodeType* Add(std::unique_ptr<NodeType> node, size_t index) { |
[email protected] | a0dd6a3 | 2011-03-18 17:31:37 | [diff] [blame] | 91 | DCHECK(node); |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 92 | DCHECK_LE(index, children_.size()); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 93 | DCHECK(!node->parent_); |
[email protected] | a0dd6a3 | 2011-03-18 17:31:37 | [diff] [blame] | 94 | node->parent_ = static_cast<NodeType*>(this); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 95 | NodeType* node_ptr = node.get(); |
Peter Kasting | d2a681f | 2022-06-24 23:08:05 | [diff] [blame] | 96 | children_.insert(children_.begin() + static_cast<ptrdiff_t>(index), |
| 97 | std::move(node)); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 98 | return node_ptr; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 99 | } |
| 100 | |
Peter Kasting | 4ea13a5 | 2019-06-04 01:17:06 | [diff] [blame] | 101 | // Shorthand for "add at end". |
| 102 | NodeType* Add(std::unique_ptr<NodeType> node) { |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 103 | return Add(std::move(node), children_.size()); |
Peter Kasting | 4ea13a5 | 2019-06-04 01:17:06 | [diff] [blame] | 104 | } |
| 105 | |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 106 | // Removes the node at the given index. Returns the removed node. |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 107 | std::unique_ptr<NodeType> Remove(size_t index) { |
| 108 | DCHECK_LT(index, children_.size()); |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 109 | children_[index]->parent_ = nullptr; |
| 110 | std::unique_ptr<NodeType> ptr = std::move(children_[index]); |
Peter Kasting | d2a681f | 2022-06-24 23:08:05 | [diff] [blame] | 111 | children_.erase(children_.begin() + static_cast<ptrdiff_t>(index)); |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 112 | return ptr; |
| 113 | } |
| 114 | |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 115 | // Removes all the children from this node. |
| 116 | void DeleteAll() { children_.clear(); } |
[email protected] | 58b359d | 2009-02-27 22:05:08 | [diff] [blame] | 117 | |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 118 | // Returns the parent node, or nullptr if this is the root node. |
[email protected] | 26b2cb72 | 2011-06-07 16:35:09 | [diff] [blame] | 119 | const NodeType* parent() const { return parent_; } |
| 120 | NodeType* parent() { return parent_; } |
| 121 | |
| 122 | // Returns true if this is the root node. |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 123 | bool is_root() const { return parent_ == nullptr; } |
[email protected] | 26b2cb72 | 2011-06-07 16:35:09 | [diff] [blame] | 124 | |
Peter Kasting | fc86fec6 | 2019-05-21 20:43:47 | [diff] [blame] | 125 | const TreeNodes& children() const { return children_; } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 126 | |
[email protected] | 18c917e | 2011-06-01 16:05:56 | [diff] [blame] | 127 | // Returns the number of all nodes in the subtree rooted at this node, |
[email protected] | 9ff22ee4 | 2009-10-25 06:03:03 | [diff] [blame] | 128 | // including this node. |
Peter Kasting | 070111cf | 2022-07-27 00:19:02 | [diff] [blame] | 129 | size_t GetTotalNodeCount() const { |
| 130 | size_t count = 1; // Start with one to include the node itself. |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 131 | for (const auto& child : children_) |
| 132 | count += child->GetTotalNodeCount(); |
[email protected] | 9ff22ee4 | 2009-10-25 06:03:03 | [diff] [blame] | 133 | return count; |
| 134 | } |
| 135 | |
Peter Kasting | 070111cf | 2022-07-27 00:19:02 | [diff] [blame] | 136 | // Returns the index of |node|, or nullopt if |node| is not a child of this. |
| 137 | absl::optional<size_t> GetIndexOf(const NodeType* node) const { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 138 | DCHECK(node); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 139 | auto i = std::find_if(children_.begin(), children_.end(), |
| 140 | [node](const std::unique_ptr<NodeType>& ptr) { |
| 141 | return ptr.get() == node; |
| 142 | }); |
Peter Kasting | 070111cf | 2022-07-27 00:19:02 | [diff] [blame] | 143 | return i != children_.end() |
| 144 | ? absl::make_optional(static_cast<size_t>(i - children_.begin())) |
| 145 | : absl::nullopt; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | // Sets the title of the node. |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 149 | virtual void SetTitle(const std::u16string& title) { title_ = title; } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 150 | |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 151 | // TreeModelNode: |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 152 | const std::u16string& GetTitle() const override { return title_; } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 153 | |
Elaine Chien | ec39da1 | 2022-07-20 16:59:06 | [diff] [blame] | 154 | const std::u16string& GetAccessibleTitle() const override { |
| 155 | return title_.empty() ? placeholder_accessible_title_ : title_; |
| 156 | } |
| 157 | |
| 158 | void SetPlaceholderAccessibleTitle( |
| 159 | std::u16string placeholder_accessible_title) { |
| 160 | placeholder_accessible_title_ = placeholder_accessible_title; |
| 161 | } |
| 162 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 163 | // Returns true if this == ancestor, or one of this nodes parents is |
| 164 | // ancestor. |
[email protected] | b3c33d46 | 2009-06-26 22:29:20 | [diff] [blame] | 165 | bool HasAncestor(const NodeType* ancestor) const { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 166 | if (ancestor == this) |
| 167 | return true; |
| 168 | if (!ancestor) |
| 169 | return false; |
| 170 | return parent_ ? parent_->HasAncestor(ancestor) : false; |
| 171 | } |
| 172 | |
Mikel Astiz | e83917a | 2022-01-27 20:21:03 | [diff] [blame] | 173 | // Reorders children according to a new arbitrary order. |new_order| must |
| 174 | // contain one entry per child node, and the value of the entry at position |
| 175 | // |i| represents the new position, which must be unique and in the range |
| 176 | // between 0 (inclusive) and the number of children (exclusive). |
| 177 | void ReorderChildren(const std::vector<size_t>& new_order) { |
| 178 | const size_t children_count = children_.size(); |
| 179 | DCHECK_EQ(children_count, new_order.size()); |
| 180 | DCHECK_EQ(children_count, |
| 181 | std::set(new_order.begin(), new_order.end()).size()); |
| 182 | TreeNodes new_children(children_count); |
| 183 | for (size_t old_index = 0; old_index < children_count; ++old_index) { |
| 184 | const size_t new_index = new_order[old_index]; |
| 185 | DCHECK_LT(new_index, children_count); |
| 186 | DCHECK(children_[old_index]); |
| 187 | DCHECK(!new_children[new_index]); |
| 188 | new_children[new_index] = std::move(children_[old_index]); |
| 189 | } |
| 190 | children_ = std::move(new_children); |
| 191 | } |
Peter Kasting | fc86fec6 | 2019-05-21 20:43:47 | [diff] [blame] | 192 | |
Mikel Astiz | e83917a | 2022-01-27 20:21:03 | [diff] [blame] | 193 | // Sorts children according to a comparator. |
| 194 | template <typename Compare> |
| 195 | void SortChildren(Compare comp) { |
| 196 | std::stable_sort(children_.begin(), children_.end(), comp); |
| 197 | } |
| 198 | |
| 199 | private: |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 200 | // Title displayed in the tree. |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 201 | std::u16string title_; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 202 | |
Elaine Chien | ec39da1 | 2022-07-20 16:59:06 | [diff] [blame] | 203 | // If set, a placeholder accessible title to fall back to if there is no |
| 204 | // title. |
| 205 | std::u16string placeholder_accessible_title_; |
| 206 | |
[email protected] | 9c1a75a | 2011-03-10 02:38:12 | [diff] [blame] | 207 | // This node's parent. |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 208 | raw_ptr<NodeType> parent_; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 209 | |
[email protected] | 9c1a75a | 2011-03-10 02:38:12 | [diff] [blame] | 210 | // This node's children. |
Peter Kasting | fc86fec6 | 2019-05-21 20:43:47 | [diff] [blame] | 211 | TreeNodes children_; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 212 | }; |
| 213 | |
| 214 | // TreeNodeWithValue ---------------------------------------------------------- |
| 215 | |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 216 | // See top of file for documentation. Example: |
| 217 | // |
| 218 | // using MyNode = ui::TreeNodeWithValue<MyData>; |
| 219 | // using MyModel = ui::TreeNodeModel<MyNode>; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 220 | template <class ValueType> |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 221 | class TreeNodeWithValue : public TreeNode<TreeNodeWithValue<ValueType>> { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 222 | public: |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 223 | TreeNodeWithValue() {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 224 | |
[email protected] | a5b58f5 | 2009-11-17 22:15:44 | [diff] [blame] | 225 | explicit TreeNodeWithValue(const ValueType& value) |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 226 | : ParentType(std::u16string()), value(value) {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 227 | |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 228 | TreeNodeWithValue(const std::u16string& title, const ValueType& value) |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 229 | : ParentType(title), value(value) {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 230 | |
Peter Boström | 03d2702 | 2021-09-27 19:45:39 | [diff] [blame] | 231 | TreeNodeWithValue(const TreeNodeWithValue&) = delete; |
| 232 | TreeNodeWithValue& operator=(const TreeNodeWithValue&) = delete; |
| 233 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 234 | ValueType value; |
| 235 | |
| 236 | private: |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 237 | using ParentType = TreeNode<TreeNodeWithValue<ValueType>>; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 238 | }; |
| 239 | |
| 240 | // TreeNodeModel -------------------------------------------------------------- |
| 241 | |
| 242 | // TreeModel implementation intended to be used with TreeNodes. |
| 243 | template <class NodeType> |
| 244 | class TreeNodeModel : public TreeModel { |
| 245 | public: |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 246 | // Creates a TreeNodeModel with the specified root node. |
| 247 | explicit TreeNodeModel(std::unique_ptr<NodeType> root) |
| 248 | : root_(std::move(root)) {} |
Peter Boström | c8c1235 | 2021-09-21 23:37:15 | [diff] [blame] | 249 | |
| 250 | TreeNodeModel(const TreeNodeModel&) = delete; |
| 251 | TreeNodeModel& operator=(const TreeNodeModel&) = delete; |
| 252 | |
nick | 9530326e8 | 2015-04-23 17:38:09 | [diff] [blame] | 253 | virtual ~TreeNodeModel() override {} |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 254 | |
Peter Kasting | f094ef9 | 2019-05-25 01:55:57 | [diff] [blame] | 255 | static NodeType* AsNode(TreeModelNode* model_node) { |
[email protected] | dce5162 | 2009-11-06 04:58:48 | [diff] [blame] | 256 | return static_cast<NodeType*>(model_node); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 257 | } |
Peter Kasting | f094ef9 | 2019-05-25 01:55:57 | [diff] [blame] | 258 | static const NodeType* AsNode(const TreeModelNode* model_node) { |
| 259 | return static_cast<const NodeType*>(model_node); |
| 260 | } |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 261 | |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 262 | NodeType* Add(NodeType* parent, |
| 263 | std::unique_ptr<NodeType> node, |
| 264 | size_t index) { |
Peter Kasting | 4d4ded1 | 2019-06-05 22:53:00 | [diff] [blame] | 265 | DCHECK(parent); |
| 266 | DCHECK(node); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 267 | NodeType* node_ptr = parent->Add(std::move(node), index); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 268 | NotifyObserverTreeNodesAdded(parent, index, 1); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 269 | return node_ptr; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 270 | } |
| 271 | |
Peter Kasting | 4ea13a5 | 2019-06-04 01:17:06 | [diff] [blame] | 272 | // Shorthand for "add at end". |
| 273 | NodeType* Add(NodeType* parent, std::unique_ptr<NodeType> node) { |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 274 | return Add(parent, std::move(node), parent->children().size()); |
Peter Kasting | 4ea13a5 | 2019-06-04 01:17:06 | [diff] [blame] | 275 | } |
| 276 | |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 277 | std::unique_ptr<NodeType> Remove(NodeType* parent, size_t index) { |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 278 | DCHECK(parent); |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 279 | std::unique_ptr<NodeType> owned_node = parent->Remove(index); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 280 | NotifyObserverTreeNodesRemoved(parent, index, 1); |
avi | cee78e4e | 2016-09-30 17:08:14 | [diff] [blame] | 281 | return owned_node; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 282 | } |
| 283 | |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 284 | std::unique_ptr<NodeType> Remove(NodeType* parent, NodeType* node) { |
| 285 | DCHECK(parent); |
Peter Kasting | 070111cf | 2022-07-27 00:19:02 | [diff] [blame] | 286 | return Remove(parent, parent->GetIndexOf(node).value()); |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 287 | } |
| 288 | |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 289 | void NotifyObserverTreeNodesAdded(NodeType* parent, |
| 290 | size_t start, |
| 291 | size_t count) { |
tfarina | b5319f19 | 2016-10-14 00:35:09 | [diff] [blame] | 292 | for (TreeModelObserver& observer : observer_list_) |
| 293 | observer.TreeNodesAdded(this, parent, start, count); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 294 | } |
| 295 | |
Peter Kasting | 8cf4c23e | 2019-06-06 00:38:30 | [diff] [blame] | 296 | void NotifyObserverTreeNodesRemoved(NodeType* parent, |
| 297 | size_t start, |
| 298 | size_t count) { |
tfarina | b5319f19 | 2016-10-14 00:35:09 | [diff] [blame] | 299 | for (TreeModelObserver& observer : observer_list_) |
| 300 | observer.TreeNodesRemoved(this, parent, start, count); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 301 | } |
| 302 | |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 303 | void NotifyObserverTreeNodeChanged(TreeModelNode* node) { |
tfarina | b5319f19 | 2016-10-14 00:35:09 | [diff] [blame] | 304 | for (TreeModelObserver& observer : observer_list_) |
| 305 | observer.TreeNodeChanged(this, node); |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 306 | } |
| 307 | |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 308 | // TreeModel: |
Brett Wilson | 05c9388 | 2017-12-12 23:06:10 | [diff] [blame] | 309 | |
| 310 | // C++ allows one to override a base class' virtual function with one that |
| 311 | // returns a different type, as long as that type implements the base class' |
| 312 | // return type. This is convenient because it allows callers with references |
| 313 | // to the specific TreeNodeModel to get the proper return type without |
| 314 | // casting. |
| 315 | // |
| 316 | // However, this does require that the NodeType be defined when this is |
| 317 | // parsed (normally one could forward define this). |
nick | 9530326e8 | 2015-04-23 17:38:09 | [diff] [blame] | 318 | NodeType* GetRoot() override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 319 | return root_.get(); |
| 320 | } |
| 321 | |
Peter Kasting | f094ef9 | 2019-05-25 01:55:57 | [diff] [blame] | 322 | Nodes GetChildren(const TreeModelNode* parent) const override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 323 | DCHECK(parent); |
Peter Kasting | f094ef9 | 2019-05-25 01:55:57 | [diff] [blame] | 324 | const auto& children = AsNode(parent)->children(); |
| 325 | Nodes nodes; |
| 326 | nodes.reserve(children.size()); |
| 327 | std::transform(children.cbegin(), children.cend(), |
| 328 | std::back_inserter(nodes), |
| 329 | [](const auto& child) { return child.get(); }); |
| 330 | return nodes; |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 331 | } |
| 332 | |
Peter Kasting | 070111cf | 2022-07-27 00:19:02 | [diff] [blame] | 333 | absl::optional<size_t> GetIndexOf(TreeModelNode* parent, |
| 334 | TreeModelNode* child) const override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 335 | DCHECK(parent); |
| 336 | return AsNode(parent)->GetIndexOf(AsNode(child)); |
| 337 | } |
| 338 | |
Peter Kasting | f094ef9 | 2019-05-25 01:55:57 | [diff] [blame] | 339 | TreeModelNode* GetParent(TreeModelNode* node) const override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 340 | DCHECK(node); |
| 341 | return AsNode(node)->parent(); |
| 342 | } |
| 343 | |
nick | 9530326e8 | 2015-04-23 17:38:09 | [diff] [blame] | 344 | void AddObserver(TreeModelObserver* observer) override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 345 | observer_list_.AddObserver(observer); |
| 346 | } |
| 347 | |
nick | 9530326e8 | 2015-04-23 17:38:09 | [diff] [blame] | 348 | void RemoveObserver(TreeModelObserver* observer) override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 349 | observer_list_.RemoveObserver(observer); |
| 350 | } |
| 351 | |
Jan Wilken Dörrie | 5263957 | 2021-03-11 16:49:54 | [diff] [blame] | 352 | void SetTitle(TreeModelNode* node, const std::u16string& title) override { |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 353 | DCHECK(node); |
[email protected] | 0491ff7 | 2011-12-30 00:45:59 | [diff] [blame] | 354 | AsNode(node)->SetTitle(title); |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 355 | NotifyObserverTreeNodeChanged(node); |
| 356 | } |
[email protected] | 0457c6b | 2010-02-10 18:44:48 | [diff] [blame] | 357 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 358 | private: |
[email protected] | 0457c6b | 2010-02-10 18:44:48 | [diff] [blame] | 359 | // The observers. |
Trent Apted | a250ec3ab | 2018-08-19 08:52:19 | [diff] [blame] | 360 | base::ObserverList<TreeModelObserver>::Unchecked observer_list_; |
[email protected] | 23db9f7 | 2011-03-11 19:43:24 | [diff] [blame] | 361 | |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 362 | // The root. |
danakj | 25c52c3 | 2016-04-12 21:51:08 | [diff] [blame] | 363 | std::unique_ptr<NodeType> root_; |
initial.commit | 09911bf | 2008-07-26 23:55:29 | [diff] [blame] | 364 | }; |
| 365 | |
[email protected] | 44cbd9e | 2011-01-14 15:49:40 | [diff] [blame] | 366 | } // namespace ui |
| 367 | |
| 368 | #endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_ |