blob: 4ca22b074472ec26b34815c3616e3834625f8641 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// 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
5#ifndef CHROME_VIEWS_TREE_NODE_MODEL_H__
6#define CHROME_VIEWS_TREE_NODE_MODEL_H__
7
[email protected]775cfd762008-12-09 17:12:128#include <algorithm>
initial.commit09911bf2008-07-26 23:55:299#include <vector>
10
11#include "base/basictypes.h"
[email protected]1fec8402009-03-13 19:11:5912#include "base/scoped_ptr.h"
initial.commit09911bf2008-07-26 23:55:2913#include "chrome/common/scoped_vector.h"
[email protected]405ed122008-11-14 17:48:4014#include "chrome/views/tree_model.h"
initial.commit09911bf2008-07-26 23:55:2915
[email protected]c2dacc92008-10-16 23:51:3816namespace views {
initial.commit09911bf2008-07-26 23:55:2917
18// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
19// TreeNodes. TreeNodes form a directed acyclic graph.
20//
21// TreeNodes own their children, so that deleting a node deletes all
22// descendants.
23//
24// TreeNodes do NOT maintain a pointer back to the model. As such, if you
25// are using TreeNodes with a TreeNodeModel you will need to notify the observer
26// yourself any time you make any change directly to the TreeNodes. For example,
27// if you directly invoke SetTitle on a node it does not notify the
28// observer, you will need to do it yourself. This includes the following
29// methods: SetTitle, Remove and Add. TreeNodeModel provides cover
30// methods that mutate the TreeNodes and notify the observer. If you are using
31// TreeNodes with a TreeNodeModel use the cover methods to save yourself the
32// headache.
33//
34// The following example creates a TreeNode with two children and then
35// creates a TreeNodeModel from it:
36//
37// TreeNodeWithValue<int> root = new TreeNodeWithValue<int>(0, L"root");
38// root.add(new TreeNodeWithValue<int>(1, L"child 1"));
39// root.add(new TreeNodeWithValue<int>(1, L"child 2"));
40// TreeNodeModel<TreeNodeWithValue<int>>* model =
41// new TreeNodeModel<TreeNodeWithValue<int>>(root);
42//
43// Two variants of TreeNode are provided here:
44//
45// . TreeNode itself is intended for subclassing. It has one type parameter
46// that corresponds to the type of the node. When subclassing use your class
47// name as the type parameter, eg:
48// class MyTreeNode : public TreeNode<MyTreeNode> .
49// . TreeNodeWithValue is a trivial subclass of TreeNode that has one type
50// type parameter: a value type that is associated with the node.
51//
52// Which you use depends upon the situation. If you want to subclass and add
53// methods, then use TreeNode. If you don't need any extra methods and just
54// want to associate a value with each node, then use TreeNodeWithValue.
55//
56// Regardless of which TreeNode you use, if you are using the nodes with a
57// TreeView take care to notify the observer when mutating the nodes.
58
59template <class NodeType>
60class TreeNodeModel;
61
62// TreeNode -------------------------------------------------------------------
63
64template <class NodeType>
65class TreeNode : public TreeModelNode {
66 public:
67 TreeNode() : parent_(NULL) { }
68
69 explicit TreeNode(const std::wstring& title)
70 : title_(title), parent_(NULL) {}
71
72 virtual ~TreeNode() {
73 }
74
75 // Adds the specified child node.
76 virtual void Add(int index, NodeType* child) {
77 DCHECK(child && index >= 0 && index <= GetChildCount());
78 // If the node has a parent, remove it from its parent.
79 NodeType* node_parent = child->GetParent();
80 if (node_parent)
81 node_parent->Remove(node_parent->IndexOfChild(child));
82 child->parent_ = static_cast<NodeType*>(this);
83 children_->insert(children_->begin() + index, child);
84 }
85
86 // Removes the node by index. This does NOT delete the specified node, it is
87 // up to the caller to delete it when done.
88 virtual NodeType* Remove(int index) {
89 DCHECK(index >= 0 && index < GetChildCount());
90 NodeType* node = GetChild(index);
91 node->parent_ = NULL;
92 children_->erase(index + children_->begin());
93 return node;
94 }
95
[email protected]58b359d2009-02-27 22:05:0896 // Removes all the children from this node. This does NOT delete the nodes.
97 void RemoveAll() {
98 for (size_t i = 0; i < children_->size(); ++i)
99 children_[i]->parent_ = NULL;
100 children_->clear();
101 }
102
initial.commit09911bf2008-07-26 23:55:29103 // Returns the number of children.
104 int GetChildCount() {
105 return static_cast<int>(children_->size());
106 }
107
108 // Returns a child by index.
109 NodeType* GetChild(int index) {
110 DCHECK(index >= 0 && index < GetChildCount());
111 return children_[index];
112 }
113
114 // Returns the parent.
115 NodeType* GetParent() {
116 return parent_;
117 }
118
119 // Returns the index of the specified child, or -1 if node is a not a child.
120 int IndexOfChild(const NodeType* node) {
121 DCHECK(node);
[email protected]405ed122008-11-14 17:48:40122 typename std::vector<NodeType*>::iterator i =
[email protected]775cfd762008-12-09 17:12:12123 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29124 if (i != children_->end())
125 return static_cast<int>(i - children_->begin());
126 return -1;
127 }
128
129 // Sets the title of the node.
130 void SetTitle(const std::wstring& string) {
131 title_ = string;
132 }
133
134 // Returns the title of the node.
135 std::wstring GetTitle() {
136 return title_;
137 }
138
139 // Returns true if this is the root.
140 bool IsRoot() { return (parent_ == NULL); }
141
142 // Returns true if this == ancestor, or one of this nodes parents is
143 // ancestor.
144 bool HasAncestor(NodeType* ancestor) const {
145 if (ancestor == this)
146 return true;
147 if (!ancestor)
148 return false;
149 return parent_ ? parent_->HasAncestor(ancestor) : false;
150 }
151
[email protected]e2f86d92009-02-25 00:22:01152 protected:
153 std::vector<NodeType*>& children() { return children_.get(); }
154
initial.commit09911bf2008-07-26 23:55:29155 private:
156 // Title displayed in the tree.
157 std::wstring title_;
158
159 NodeType* parent_;
160
161 // Children.
162 ScopedVector<NodeType> children_;
163
[email protected]405ed122008-11-14 17:48:40164 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29165};
166
167// TreeNodeWithValue ----------------------------------------------------------
168
169template <class ValueType>
[email protected]405ed122008-11-14 17:48:40170class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
171 private:
172 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
173
initial.commit09911bf2008-07-26 23:55:29174 public:
175 TreeNodeWithValue() { }
176
177 TreeNodeWithValue(const ValueType& value)
[email protected]405ed122008-11-14 17:48:40178 : ParentType(std::wstring()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29179
180 TreeNodeWithValue(const std::wstring& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40181 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29182
183 ValueType value;
184
185 private:
[email protected]405ed122008-11-14 17:48:40186 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29187};
188
189// TreeNodeModel --------------------------------------------------------------
190
191// TreeModel implementation intended to be used with TreeNodes.
192template <class NodeType>
193class TreeNodeModel : public TreeModel {
194 public:
195 // Creates a TreeNodeModel with the specified root node. The root is owned
196 // by the TreeNodeModel.
197 explicit TreeNodeModel(NodeType* root)
[email protected]1baa4f02009-01-26 09:29:08198 : root_(root),
199 observer_(NULL) {
initial.commit09911bf2008-07-26 23:55:29200 }
201
202 virtual ~TreeNodeModel() {}
203
204 virtual void SetObserver(TreeModelObserver* observer) {
205 observer_ = observer;
206 }
207
208 TreeModelObserver* GetObserver() {
209 return observer_;
210 }
211
212 // TreeModel methods, all forward to the nodes.
213 virtual NodeType* GetRoot() { return root_.get(); }
214
215 virtual int GetChildCount(TreeModelNode* parent) {
216 DCHECK(parent);
217 return AsNode(parent)->GetChildCount();
218 }
219
220 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
221 DCHECK(parent);
222 return AsNode(parent)->GetChild(index);
223 }
224
225 virtual TreeModelNode* GetParent(TreeModelNode* node) {
226 DCHECK(node);
227 return AsNode(node)->GetParent();
228 }
229
230 NodeType* AsNode(TreeModelNode* model_node) {
231 return reinterpret_cast<NodeType*>(model_node);
232 }
233
234 // Sets the title of the specified node.
235 virtual void SetTitle(TreeModelNode* node,
236 const std::wstring& title) {
237 DCHECK(node);
238 AsNode(node)->SetTitle(title);
239 NotifyObserverTreeNodeChanged(node);
240 }
241
242 void Add(NodeType* parent, int index, NodeType* child) {
243 DCHECK(parent && child);
244 parent->Add(index, child);
245 NotifyObserverTreeNodesAdded(parent, index, 1);
246 }
247
248 NodeType* Remove(NodeType* parent, int index) {
249 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41250 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29251 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41252 return child;
initial.commit09911bf2008-07-26 23:55:29253 }
254
255 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
256 if (observer_)
257 observer_->TreeNodesAdded(this, parent, start, count);
258 }
259
260 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
261 if (observer_)
262 observer_->TreeNodesRemoved(this, parent, start, count);
263 }
264
265 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
266 if (observer_)
267 observer_->TreeNodeChanged(this, node);
268 }
269
270 private:
271 // The root.
272 scoped_ptr<NodeType> root_;
273
274 // The observer.
275 TreeModelObserver* observer_;
276
[email protected]405ed122008-11-14 17:48:40277 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29278};
279
[email protected]c2dacc92008-10-16 23:51:38280} // namespace views
initial.commit09911bf2008-07-26 23:55:29281
282#endif // CHROME_VIEWS_TREE_NODE_MODEL_H__