blob: 482221de5a348becd24bccd348de4f368ac1bb8d [file] [log] [blame]
[email protected]44cbd9e2011-01-14 15:49:401// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]44cbd9e2011-01-14 15:49:405#ifndef UI_BASE_MODELS_TREE_NODE_MODEL_H_
6#define UI_BASE_MODELS_TREE_NODE_MODEL_H_
[email protected]32b76ef2010-07-26 23:08:247#pragma once
initial.commit09911bf2008-07-26 23:55:298
[email protected]775cfd762008-12-09 17:12:129#include <algorithm>
initial.commit09911bf2008-07-26 23:55:2910#include <vector>
11
12#include "base/basictypes.h"
[email protected]dec76e802010-09-23 22:43:5313#include "base/logging.h"
[email protected]0457c6b2010-02-10 18:44:4814#include "base/observer_list.h"
[email protected]1fec8402009-03-13 19:11:5915#include "base/scoped_ptr.h"
[email protected]807204142009-05-05 03:31:4416#include "base/scoped_vector.h"
17#include "base/stl_util-inl.h"
[email protected]e64e9012010-01-11 23:10:5518#include "base/string16.h"
[email protected]44cbd9e2011-01-14 15:49:4019#include "ui/base/models/tree_model.h"
20
21namespace ui {
initial.commit09911bf2008-07-26 23:55:2922
23// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
24// TreeNodes. TreeNodes form a directed acyclic graph.
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,
32// if you directly invoke SetTitle on a node it does not notify the
33// observer, you will need to do it yourself. This includes the following
34// methods: SetTitle, Remove and Add. TreeNodeModel provides cover
35// methods that mutate the TreeNodes and notify the observer. If you are using
36// TreeNodes with a TreeNodeModel use the cover methods to save yourself the
37// headache.
38//
39// The following example creates a TreeNode with two children and then
40// creates a TreeNodeModel from it:
41//
[email protected]964b6772010-08-25 16:50:4842// TreeNodeWithValue<int> root =
43// new TreeNodeWithValue<int>(ASCIIToUTF16("root"), 0);
44// root.add(new TreeNodeWithValue<int>(ASCIIToUTF16("child 1"), 1));
45// root.add(new TreeNodeWithValue<int>(ASCIIToUTF16("child 2"), 1));
initial.commit09911bf2008-07-26 23:55:2946// TreeNodeModel<TreeNodeWithValue<int>>* model =
47// new TreeNodeModel<TreeNodeWithValue<int>>(root);
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
53// name as the type parameter, eg:
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
65template <class NodeType>
66class TreeNodeModel;
67
68// TreeNode -------------------------------------------------------------------
69
70template <class NodeType>
71class TreeNode : public TreeModelNode {
72 public:
73 TreeNode() : parent_(NULL) { }
74
[email protected]e64e9012010-01-11 23:10:5575 explicit TreeNode(const string16& title)
initial.commit09911bf2008-07-26 23:55:2976 : title_(title), parent_(NULL) {}
77
78 virtual ~TreeNode() {
79 }
80
81 // Adds the specified child node.
82 virtual void Add(int index, NodeType* child) {
[email protected]f07d7bf2010-04-06 08:02:4283 DCHECK(child);
84 DCHECK_LE(0, index);
85 DCHECK_GE(GetChildCount(), index);
initial.commit09911bf2008-07-26 23:55:2986 // If the node has a parent, remove it from its parent.
[email protected]2d48ee842011-03-08 23:27:2987 NodeType* node_parent = child->parent();
initial.commit09911bf2008-07-26 23:55:2988 if (node_parent)
[email protected]368f3a72011-03-08 17:17:4889 node_parent->Remove(node_parent->GetIndexOf(child));
initial.commit09911bf2008-07-26 23:55:2990 child->parent_ = static_cast<NodeType*>(this);
91 children_->insert(children_->begin() + index, child);
92 }
93
94 // Removes the node by index. This does NOT delete the specified node, it is
95 // up to the caller to delete it when done.
96 virtual NodeType* Remove(int index) {
97 DCHECK(index >= 0 && index < GetChildCount());
98 NodeType* node = GetChild(index);
99 node->parent_ = NULL;
100 children_->erase(index + children_->begin());
101 return node;
102 }
103
[email protected]58b359d2009-02-27 22:05:08104 // Removes all the children from this node. This does NOT delete the nodes.
105 void RemoveAll() {
106 for (size_t i = 0; i < children_->size(); ++i)
107 children_[i]->parent_ = NULL;
108 children_->clear();
109 }
110
initial.commit09911bf2008-07-26 23:55:29111 // Returns the number of children.
[email protected]b3c33d462009-06-26 22:29:20112 int GetChildCount() const {
initial.commit09911bf2008-07-26 23:55:29113 return static_cast<int>(children_->size());
114 }
115
[email protected]9ff22ee42009-10-25 06:03:03116 // Returns the number of all nodes in teh subtree rooted at this node,
117 // including this node.
118 int GetTotalNodeCount() const {
119 int count = 1; // Start with one to include the node itself.
120 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48121 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03122 count += child->GetTotalNodeCount();
123 }
124 return count;
125 }
126
initial.commit09911bf2008-07-26 23:55:29127 // Returns a child by index.
128 NodeType* GetChild(int index) {
129 DCHECK(index >= 0 && index < GetChildCount());
130 return children_[index];
131 }
[email protected]b3c33d462009-06-26 22:29:20132 const NodeType* GetChild(int index) const {
[email protected]f07d7bf2010-04-06 08:02:42133 DCHECK_LE(0, index);
134 DCHECK_GT(GetChildCount(), index);
[email protected]b3c33d462009-06-26 22:29:20135 return children_[index];
136 }
initial.commit09911bf2008-07-26 23:55:29137
[email protected]2d48ee842011-03-08 23:27:29138 // Returns the parent of this object, or NULL if it's the root.
139 const NodeType* parent() const { return parent_; }
140 NodeType* parent() { return parent_; }
initial.commit09911bf2008-07-26 23:55:29141
[email protected]368f3a72011-03-08 17:17:48142 // Returns the index of |node|, or -1 if |node| is not a child of this.
143 int GetIndexOf(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29144 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20145 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12146 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29147 if (i != children_->end())
148 return static_cast<int>(i - children_->begin());
149 return -1;
150 }
151
152 // Sets the title of the node.
[email protected]e64e9012010-01-11 23:10:55153 void SetTitle(const string16& string) {
initial.commit09911bf2008-07-26 23:55:29154 title_ = string;
155 }
156
157 // Returns the title of the node.
[email protected]440b37b22010-08-30 05:31:40158 virtual const string16& GetTitle() const {
initial.commit09911bf2008-07-26 23:55:29159 return title_;
160 }
161
162 // Returns true if this is the root.
[email protected]b3c33d462009-06-26 22:29:20163 bool IsRoot() const { return (parent_ == NULL); }
initial.commit09911bf2008-07-26 23:55:29164
165 // Returns true if this == ancestor, or one of this nodes parents is
166 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20167 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29168 if (ancestor == this)
169 return true;
170 if (!ancestor)
171 return false;
172 return parent_ ? parent_->HasAncestor(ancestor) : false;
173 }
174
[email protected]e2f86d92009-02-25 00:22:01175 protected:
176 std::vector<NodeType*>& children() { return children_.get(); }
177
initial.commit09911bf2008-07-26 23:55:29178 private:
179 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55180 string16 title_;
initial.commit09911bf2008-07-26 23:55:29181
182 NodeType* parent_;
183
184 // Children.
185 ScopedVector<NodeType> children_;
186
[email protected]405ed122008-11-14 17:48:40187 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29188};
189
190// TreeNodeWithValue ----------------------------------------------------------
191
192template <class ValueType>
[email protected]405ed122008-11-14 17:48:40193class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
194 private:
195 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
196
initial.commit09911bf2008-07-26 23:55:29197 public:
198 TreeNodeWithValue() { }
199
[email protected]a5b58f52009-11-17 22:15:44200 explicit TreeNodeWithValue(const ValueType& value)
[email protected]964b6772010-08-25 16:50:48201 : ParentType(string16()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29202
[email protected]964b6772010-08-25 16:50:48203 TreeNodeWithValue(const string16& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40204 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29205
206 ValueType value;
207
208 private:
[email protected]405ed122008-11-14 17:48:40209 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29210};
211
212// TreeNodeModel --------------------------------------------------------------
213
214// TreeModel implementation intended to be used with TreeNodes.
215template <class NodeType>
216class TreeNodeModel : public TreeModel {
217 public:
218 // Creates a TreeNodeModel with the specified root node. The root is owned
219 // by the TreeNodeModel.
220 explicit TreeNodeModel(NodeType* root)
[email protected]0457c6b2010-02-10 18:44:48221 : root_(root) {
initial.commit09911bf2008-07-26 23:55:29222 }
223
224 virtual ~TreeNodeModel() {}
225
[email protected]0457c6b2010-02-10 18:44:48226 // Observer methods, calls into ObserverList.
227 virtual void AddObserver(TreeModelObserver* observer) {
228 observer_list_.AddObserver(observer);
initial.commit09911bf2008-07-26 23:55:29229 }
230
[email protected]0457c6b2010-02-10 18:44:48231 virtual void RemoveObserver(TreeModelObserver* observer) {
232 observer_list_.RemoveObserver(observer);
initial.commit09911bf2008-07-26 23:55:29233 }
234
235 // TreeModel methods, all forward to the nodes.
236 virtual NodeType* GetRoot() { return root_.get(); }
237
238 virtual int GetChildCount(TreeModelNode* parent) {
239 DCHECK(parent);
240 return AsNode(parent)->GetChildCount();
241 }
242
243 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
244 DCHECK(parent);
245 return AsNode(parent)->GetChild(index);
246 }
247
[email protected]368f3a72011-03-08 17:17:48248 virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) {
[email protected]42062e72009-11-11 23:07:58249 DCHECK(parent);
[email protected]368f3a72011-03-08 17:17:48250 return AsNode(parent)->GetIndexOf(AsNode(child));
[email protected]42062e72009-11-11 23:07:58251 }
252
initial.commit09911bf2008-07-26 23:55:29253 virtual TreeModelNode* GetParent(TreeModelNode* node) {
254 DCHECK(node);
[email protected]2d48ee842011-03-08 23:27:29255 return AsNode(node)->parent();
initial.commit09911bf2008-07-26 23:55:29256 }
257
258 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48259 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29260 }
261
262 // Sets the title of the specified node.
263 virtual void SetTitle(TreeModelNode* node,
[email protected]01d552552010-08-22 00:17:18264 const string16& title) {
initial.commit09911bf2008-07-26 23:55:29265 DCHECK(node);
[email protected]01d552552010-08-22 00:17:18266 AsNode(node)->SetTitle(title);
initial.commit09911bf2008-07-26 23:55:29267 NotifyObserverTreeNodeChanged(node);
268 }
269
270 void Add(NodeType* parent, int index, NodeType* child) {
271 DCHECK(parent && child);
272 parent->Add(index, child);
273 NotifyObserverTreeNodesAdded(parent, index, 1);
274 }
275
276 NodeType* Remove(NodeType* parent, int index) {
277 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41278 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29279 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41280 return child;
initial.commit09911bf2008-07-26 23:55:29281 }
282
283 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48284 FOR_EACH_OBSERVER(TreeModelObserver,
285 observer_list_,
286 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29287 }
288
289 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48290 FOR_EACH_OBSERVER(TreeModelObserver,
291 observer_list_,
292 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29293 }
294
295 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48296 FOR_EACH_OBSERVER(TreeModelObserver,
297 observer_list_,
298 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29299 }
300
[email protected]0457c6b2010-02-10 18:44:48301 protected:
302 ObserverList<TreeModelObserver>& observer_list() { return observer_list_; }
303
initial.commit09911bf2008-07-26 23:55:29304 private:
[email protected]0457c6b2010-02-10 18:44:48305 // The observers.
306 ObserverList<TreeModelObserver> observer_list_;
initial.commit09911bf2008-07-26 23:55:29307 // The root.
308 scoped_ptr<NodeType> root_;
309
[email protected]405ed122008-11-14 17:48:40310 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29311};
312
[email protected]44cbd9e2011-01-14 15:49:40313} // namespace ui
314
315#endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_