blob: 34f6ee88fd4e5815038a0427a11981aa56ade0ea [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.
87 NodeType* node_parent = child->GetParent();
88 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
138 // Returns the parent.
139 NodeType* GetParent() {
140 return parent_;
141 }
[email protected]b3c33d462009-06-26 22:29:20142 const NodeType* GetParent() const {
143 return parent_;
144 }
initial.commit09911bf2008-07-26 23:55:29145
[email protected]368f3a72011-03-08 17:17:48146 // Returns the index of |node|, or -1 if |node| is not a child of this.
147 int GetIndexOf(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29148 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20149 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12150 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29151 if (i != children_->end())
152 return static_cast<int>(i - children_->begin());
153 return -1;
154 }
155
156 // Sets the title of the node.
[email protected]e64e9012010-01-11 23:10:55157 void SetTitle(const string16& string) {
initial.commit09911bf2008-07-26 23:55:29158 title_ = string;
159 }
160
161 // Returns the title of the node.
[email protected]440b37b22010-08-30 05:31:40162 virtual const string16& GetTitle() const {
initial.commit09911bf2008-07-26 23:55:29163 return title_;
164 }
165
166 // Returns true if this is the root.
[email protected]b3c33d462009-06-26 22:29:20167 bool IsRoot() const { return (parent_ == NULL); }
initial.commit09911bf2008-07-26 23:55:29168
169 // Returns true if this == ancestor, or one of this nodes parents is
170 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20171 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29172 if (ancestor == this)
173 return true;
174 if (!ancestor)
175 return false;
176 return parent_ ? parent_->HasAncestor(ancestor) : false;
177 }
178
[email protected]e2f86d92009-02-25 00:22:01179 protected:
180 std::vector<NodeType*>& children() { return children_.get(); }
181
initial.commit09911bf2008-07-26 23:55:29182 private:
183 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55184 string16 title_;
initial.commit09911bf2008-07-26 23:55:29185
186 NodeType* parent_;
187
188 // Children.
189 ScopedVector<NodeType> children_;
190
[email protected]405ed122008-11-14 17:48:40191 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29192};
193
194// TreeNodeWithValue ----------------------------------------------------------
195
196template <class ValueType>
[email protected]405ed122008-11-14 17:48:40197class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
198 private:
199 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
200
initial.commit09911bf2008-07-26 23:55:29201 public:
202 TreeNodeWithValue() { }
203
[email protected]a5b58f52009-11-17 22:15:44204 explicit TreeNodeWithValue(const ValueType& value)
[email protected]964b6772010-08-25 16:50:48205 : ParentType(string16()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29206
[email protected]964b6772010-08-25 16:50:48207 TreeNodeWithValue(const string16& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40208 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29209
210 ValueType value;
211
212 private:
[email protected]405ed122008-11-14 17:48:40213 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29214};
215
216// TreeNodeModel --------------------------------------------------------------
217
218// TreeModel implementation intended to be used with TreeNodes.
219template <class NodeType>
220class TreeNodeModel : public TreeModel {
221 public:
222 // Creates a TreeNodeModel with the specified root node. The root is owned
223 // by the TreeNodeModel.
224 explicit TreeNodeModel(NodeType* root)
[email protected]0457c6b2010-02-10 18:44:48225 : root_(root) {
initial.commit09911bf2008-07-26 23:55:29226 }
227
228 virtual ~TreeNodeModel() {}
229
[email protected]0457c6b2010-02-10 18:44:48230 // Observer methods, calls into ObserverList.
231 virtual void AddObserver(TreeModelObserver* observer) {
232 observer_list_.AddObserver(observer);
initial.commit09911bf2008-07-26 23:55:29233 }
234
[email protected]0457c6b2010-02-10 18:44:48235 virtual void RemoveObserver(TreeModelObserver* observer) {
236 observer_list_.RemoveObserver(observer);
initial.commit09911bf2008-07-26 23:55:29237 }
238
239 // TreeModel methods, all forward to the nodes.
240 virtual NodeType* GetRoot() { return root_.get(); }
241
242 virtual int GetChildCount(TreeModelNode* parent) {
243 DCHECK(parent);
244 return AsNode(parent)->GetChildCount();
245 }
246
247 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
248 DCHECK(parent);
249 return AsNode(parent)->GetChild(index);
250 }
251
[email protected]368f3a72011-03-08 17:17:48252 virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) {
[email protected]42062e72009-11-11 23:07:58253 DCHECK(parent);
[email protected]368f3a72011-03-08 17:17:48254 return AsNode(parent)->GetIndexOf(AsNode(child));
[email protected]42062e72009-11-11 23:07:58255 }
256
initial.commit09911bf2008-07-26 23:55:29257 virtual TreeModelNode* GetParent(TreeModelNode* node) {
258 DCHECK(node);
259 return AsNode(node)->GetParent();
260 }
261
262 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48263 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29264 }
265
266 // Sets the title of the specified node.
267 virtual void SetTitle(TreeModelNode* node,
[email protected]01d552552010-08-22 00:17:18268 const string16& title) {
initial.commit09911bf2008-07-26 23:55:29269 DCHECK(node);
[email protected]01d552552010-08-22 00:17:18270 AsNode(node)->SetTitle(title);
initial.commit09911bf2008-07-26 23:55:29271 NotifyObserverTreeNodeChanged(node);
272 }
273
274 void Add(NodeType* parent, int index, NodeType* child) {
275 DCHECK(parent && child);
276 parent->Add(index, child);
277 NotifyObserverTreeNodesAdded(parent, index, 1);
278 }
279
280 NodeType* Remove(NodeType* parent, int index) {
281 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41282 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29283 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41284 return child;
initial.commit09911bf2008-07-26 23:55:29285 }
286
287 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48288 FOR_EACH_OBSERVER(TreeModelObserver,
289 observer_list_,
290 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29291 }
292
293 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48294 FOR_EACH_OBSERVER(TreeModelObserver,
295 observer_list_,
296 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29297 }
298
299 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48300 FOR_EACH_OBSERVER(TreeModelObserver,
301 observer_list_,
302 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29303 }
304
[email protected]0457c6b2010-02-10 18:44:48305 protected:
306 ObserverList<TreeModelObserver>& observer_list() { return observer_list_; }
307
initial.commit09911bf2008-07-26 23:55:29308 private:
[email protected]0457c6b2010-02-10 18:44:48309 // The observers.
310 ObserverList<TreeModelObserver> observer_list_;
initial.commit09911bf2008-07-26 23:55:29311 // The root.
312 scoped_ptr<NodeType> root_;
313
[email protected]405ed122008-11-14 17:48:40314 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29315};
316
[email protected]44cbd9e2011-01-14 15:49:40317} // namespace ui
318
319#endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_