blob: 0064172d3cfb84452563b331fe826d97bc8cd970 [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);
[email protected]9c1a75a2011-03-10 02:38:1285 DCHECK_GE(child_count(), 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) {
[email protected]9c1a75a2011-03-10 02:38:1297 DCHECK(index >= 0 && index < child_count());
initial.commit09911bf2008-07-26 23:55:2998 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]9c1a75a2011-03-10 02:38:12112 int child_count() const { return static_cast<int>(children_->size()); }
initial.commit09911bf2008-07-26 23:55:29113
[email protected]9ff22ee42009-10-25 06:03:03114 // Returns the number of all nodes in teh subtree rooted at this node,
115 // including this node.
116 int GetTotalNodeCount() const {
117 int count = 1; // Start with one to include the node itself.
118 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48119 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03120 count += child->GetTotalNodeCount();
121 }
122 return count;
123 }
124
[email protected]9c1a75a2011-03-10 02:38:12125 // Returns the node at |index|.
initial.commit09911bf2008-07-26 23:55:29126 NodeType* GetChild(int index) {
[email protected]9c1a75a2011-03-10 02:38:12127 DCHECK(index >= 0 && index < child_count());
initial.commit09911bf2008-07-26 23:55:29128 return children_[index];
129 }
[email protected]b3c33d462009-06-26 22:29:20130 const NodeType* GetChild(int index) const {
[email protected]f07d7bf2010-04-06 08:02:42131 DCHECK_LE(0, index);
[email protected]9c1a75a2011-03-10 02:38:12132 DCHECK_GT(child_count(), index);
[email protected]b3c33d462009-06-26 22:29:20133 return children_[index];
134 }
initial.commit09911bf2008-07-26 23:55:29135
[email protected]2d48ee842011-03-08 23:27:29136 // Returns the parent of this object, or NULL if it's the root.
137 const NodeType* parent() const { return parent_; }
138 NodeType* parent() { return parent_; }
initial.commit09911bf2008-07-26 23:55:29139
[email protected]368f3a72011-03-08 17:17:48140 // Returns the index of |node|, or -1 if |node| is not a child of this.
141 int GetIndexOf(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29142 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20143 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12144 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29145 if (i != children_->end())
146 return static_cast<int>(i - children_->begin());
147 return -1;
148 }
149
150 // Sets the title of the node.
[email protected]e64e9012010-01-11 23:10:55151 void SetTitle(const string16& string) {
initial.commit09911bf2008-07-26 23:55:29152 title_ = string;
153 }
154
155 // Returns the title of the node.
[email protected]440b37b22010-08-30 05:31:40156 virtual const string16& GetTitle() const {
initial.commit09911bf2008-07-26 23:55:29157 return title_;
158 }
159
160 // Returns true if this is the root.
[email protected]b3c33d462009-06-26 22:29:20161 bool IsRoot() const { return (parent_ == NULL); }
initial.commit09911bf2008-07-26 23:55:29162
163 // Returns true if this == ancestor, or one of this nodes parents is
164 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20165 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29166 if (ancestor == this)
167 return true;
168 if (!ancestor)
169 return false;
170 return parent_ ? parent_->HasAncestor(ancestor) : false;
171 }
172
[email protected]e2f86d92009-02-25 00:22:01173 protected:
174 std::vector<NodeType*>& children() { return children_.get(); }
175
initial.commit09911bf2008-07-26 23:55:29176 private:
177 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55178 string16 title_;
initial.commit09911bf2008-07-26 23:55:29179
[email protected]9c1a75a2011-03-10 02:38:12180 // This node's parent.
initial.commit09911bf2008-07-26 23:55:29181 NodeType* parent_;
182
[email protected]9c1a75a2011-03-10 02:38:12183 // This node's children.
initial.commit09911bf2008-07-26 23:55:29184 ScopedVector<NodeType> children_;
185
[email protected]405ed122008-11-14 17:48:40186 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29187};
188
189// TreeNodeWithValue ----------------------------------------------------------
190
191template <class ValueType>
[email protected]405ed122008-11-14 17:48:40192class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
193 private:
194 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
195
initial.commit09911bf2008-07-26 23:55:29196 public:
197 TreeNodeWithValue() { }
198
[email protected]a5b58f52009-11-17 22:15:44199 explicit TreeNodeWithValue(const ValueType& value)
[email protected]964b6772010-08-25 16:50:48200 : ParentType(string16()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29201
[email protected]964b6772010-08-25 16:50:48202 TreeNodeWithValue(const string16& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40203 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29204
205 ValueType value;
206
207 private:
[email protected]405ed122008-11-14 17:48:40208 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29209};
210
211// TreeNodeModel --------------------------------------------------------------
212
213// TreeModel implementation intended to be used with TreeNodes.
214template <class NodeType>
215class TreeNodeModel : public TreeModel {
216 public:
217 // Creates a TreeNodeModel with the specified root node. The root is owned
218 // by the TreeNodeModel.
219 explicit TreeNodeModel(NodeType* root)
[email protected]0457c6b2010-02-10 18:44:48220 : root_(root) {
initial.commit09911bf2008-07-26 23:55:29221 }
222
223 virtual ~TreeNodeModel() {}
224
[email protected]0457c6b2010-02-10 18:44:48225 // Observer methods, calls into ObserverList.
226 virtual void AddObserver(TreeModelObserver* observer) {
227 observer_list_.AddObserver(observer);
initial.commit09911bf2008-07-26 23:55:29228 }
229
[email protected]0457c6b2010-02-10 18:44:48230 virtual void RemoveObserver(TreeModelObserver* observer) {
231 observer_list_.RemoveObserver(observer);
initial.commit09911bf2008-07-26 23:55:29232 }
233
234 // TreeModel methods, all forward to the nodes.
235 virtual NodeType* GetRoot() { return root_.get(); }
236
237 virtual int GetChildCount(TreeModelNode* parent) {
238 DCHECK(parent);
[email protected]9c1a75a2011-03-10 02:38:12239 return AsNode(parent)->child_count();
initial.commit09911bf2008-07-26 23:55:29240 }
241
242 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
243 DCHECK(parent);
244 return AsNode(parent)->GetChild(index);
245 }
246
[email protected]368f3a72011-03-08 17:17:48247 virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) {
[email protected]42062e72009-11-11 23:07:58248 DCHECK(parent);
[email protected]368f3a72011-03-08 17:17:48249 return AsNode(parent)->GetIndexOf(AsNode(child));
[email protected]42062e72009-11-11 23:07:58250 }
251
initial.commit09911bf2008-07-26 23:55:29252 virtual TreeModelNode* GetParent(TreeModelNode* node) {
253 DCHECK(node);
[email protected]2d48ee842011-03-08 23:27:29254 return AsNode(node)->parent();
initial.commit09911bf2008-07-26 23:55:29255 }
256
257 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48258 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29259 }
260
261 // Sets the title of the specified node.
262 virtual void SetTitle(TreeModelNode* node,
[email protected]01d552552010-08-22 00:17:18263 const string16& title) {
initial.commit09911bf2008-07-26 23:55:29264 DCHECK(node);
[email protected]01d552552010-08-22 00:17:18265 AsNode(node)->SetTitle(title);
initial.commit09911bf2008-07-26 23:55:29266 NotifyObserverTreeNodeChanged(node);
267 }
268
269 void Add(NodeType* parent, int index, NodeType* child) {
270 DCHECK(parent && child);
271 parent->Add(index, child);
272 NotifyObserverTreeNodesAdded(parent, index, 1);
273 }
274
275 NodeType* Remove(NodeType* parent, int index) {
276 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41277 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29278 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41279 return child;
initial.commit09911bf2008-07-26 23:55:29280 }
281
282 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48283 FOR_EACH_OBSERVER(TreeModelObserver,
284 observer_list_,
285 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29286 }
287
288 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48289 FOR_EACH_OBSERVER(TreeModelObserver,
290 observer_list_,
291 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29292 }
293
294 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48295 FOR_EACH_OBSERVER(TreeModelObserver,
296 observer_list_,
297 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29298 }
299
[email protected]0457c6b2010-02-10 18:44:48300 protected:
301 ObserverList<TreeModelObserver>& observer_list() { return observer_list_; }
302
initial.commit09911bf2008-07-26 23:55:29303 private:
[email protected]0457c6b2010-02-10 18:44:48304 // The observers.
305 ObserverList<TreeModelObserver> observer_list_;
initial.commit09911bf2008-07-26 23:55:29306 // The root.
307 scoped_ptr<NodeType> root_;
308
[email protected]405ed122008-11-14 17:48:40309 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29310};
311
[email protected]44cbd9e2011-01-14 15:49:40312} // namespace ui
313
314#endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_