blob: b47fe03cbbb684694fb4b51b58846a482be99db6 [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
[email protected]992c6252009-05-13 18:54:205#ifndef APP_TREE_NODE_MODEL_H_
6#define APP_TREE_NODE_MODEL_H_
initial.commit09911bf2008-07-26 23:55:297
[email protected]775cfd762008-12-09 17:12:128#include <algorithm>
[email protected]e64e9012010-01-11 23:10:559#include <string>
initial.commit09911bf2008-07-26 23:55:2910#include <vector>
11
[email protected]992c6252009-05-13 18:54:2012#include "app/tree_model.h"
initial.commit09911bf2008-07-26 23:55:2913#include "base/basictypes.h"
[email protected]1fec8402009-03-13 19:11:5914#include "base/scoped_ptr.h"
[email protected]807204142009-05-05 03:31:4415#include "base/scoped_vector.h"
16#include "base/stl_util-inl.h"
[email protected]e64e9012010-01-11 23:10:5517#include "base/string16.h"
18#include "base/utf_string_conversions.h"
initial.commit09911bf2008-07-26 23:55:2919
20// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
21// TreeNodes. TreeNodes form a directed acyclic graph.
22//
23// TreeNodes own their children, so that deleting a node deletes all
24// descendants.
25//
26// TreeNodes do NOT maintain a pointer back to the model. As such, if you
27// are using TreeNodes with a TreeNodeModel you will need to notify the observer
28// yourself any time you make any change directly to the TreeNodes. For example,
29// if you directly invoke SetTitle on a node it does not notify the
30// observer, you will need to do it yourself. This includes the following
31// methods: SetTitle, Remove and Add. TreeNodeModel provides cover
32// methods that mutate the TreeNodes and notify the observer. If you are using
33// TreeNodes with a TreeNodeModel use the cover methods to save yourself the
34// headache.
35//
36// The following example creates a TreeNode with two children and then
37// creates a TreeNodeModel from it:
38//
39// TreeNodeWithValue<int> root = new TreeNodeWithValue<int>(0, L"root");
40// root.add(new TreeNodeWithValue<int>(1, L"child 1"));
41// root.add(new TreeNodeWithValue<int>(1, L"child 2"));
42// TreeNodeModel<TreeNodeWithValue<int>>* model =
43// new TreeNodeModel<TreeNodeWithValue<int>>(root);
44//
45// Two variants of TreeNode are provided here:
46//
47// . TreeNode itself is intended for subclassing. It has one type parameter
48// that corresponds to the type of the node. When subclassing use your class
49// name as the type parameter, eg:
50// class MyTreeNode : public TreeNode<MyTreeNode> .
51// . TreeNodeWithValue is a trivial subclass of TreeNode that has one type
52// type parameter: a value type that is associated with the node.
53//
54// Which you use depends upon the situation. If you want to subclass and add
55// methods, then use TreeNode. If you don't need any extra methods and just
56// want to associate a value with each node, then use TreeNodeWithValue.
57//
58// Regardless of which TreeNode you use, if you are using the nodes with a
59// TreeView take care to notify the observer when mutating the nodes.
60
61template <class NodeType>
62class TreeNodeModel;
63
64// TreeNode -------------------------------------------------------------------
65
66template <class NodeType>
67class TreeNode : public TreeModelNode {
68 public:
69 TreeNode() : parent_(NULL) { }
70
[email protected]e64e9012010-01-11 23:10:5571 // TODO(munjal): Remove wstring overload once all code is moved to string16.
72#if !defined(WCHAR_T_IS_UTF16)
initial.commit09911bf2008-07-26 23:55:2973 explicit TreeNode(const std::wstring& title)
[email protected]e64e9012010-01-11 23:10:5574 : title_(WideToUTF16(title)), parent_(NULL) {}
75#endif
76 explicit TreeNode(const string16& title)
initial.commit09911bf2008-07-26 23:55:2977 : title_(title), parent_(NULL) {}
78
79 virtual ~TreeNode() {
80 }
81
82 // Adds the specified child node.
83 virtual void Add(int index, NodeType* child) {
84 DCHECK(child && index >= 0 && index <= GetChildCount());
85 // If the node has a parent, remove it from its parent.
86 NodeType* node_parent = child->GetParent();
87 if (node_parent)
88 node_parent->Remove(node_parent->IndexOfChild(child));
89 child->parent_ = static_cast<NodeType*>(this);
90 children_->insert(children_->begin() + index, child);
91 }
92
93 // Removes the node by index. This does NOT delete the specified node, it is
94 // up to the caller to delete it when done.
95 virtual NodeType* Remove(int index) {
96 DCHECK(index >= 0 && index < GetChildCount());
97 NodeType* node = GetChild(index);
98 node->parent_ = NULL;
99 children_->erase(index + children_->begin());
100 return node;
101 }
102
[email protected]58b359d2009-02-27 22:05:08103 // Removes all the children from this node. This does NOT delete the nodes.
104 void RemoveAll() {
105 for (size_t i = 0; i < children_->size(); ++i)
106 children_[i]->parent_ = NULL;
107 children_->clear();
108 }
109
initial.commit09911bf2008-07-26 23:55:29110 // Returns the number of children.
[email protected]b3c33d462009-06-26 22:29:20111 int GetChildCount() const {
initial.commit09911bf2008-07-26 23:55:29112 return static_cast<int>(children_->size());
113 }
114
[email protected]9ff22ee42009-10-25 06:03:03115 // Returns the number of all nodes in teh subtree rooted at this node,
116 // including this node.
117 int GetTotalNodeCount() const {
118 int count = 1; // Start with one to include the node itself.
119 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48120 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03121 count += child->GetTotalNodeCount();
122 }
123 return count;
124 }
125
initial.commit09911bf2008-07-26 23:55:29126 // Returns a child by index.
127 NodeType* GetChild(int index) {
128 DCHECK(index >= 0 && index < GetChildCount());
129 return children_[index];
130 }
[email protected]b3c33d462009-06-26 22:29:20131 const NodeType* GetChild(int index) const {
132 DCHECK(index >= 0 && index < GetChildCount());
133 return children_[index];
134 }
initial.commit09911bf2008-07-26 23:55:29135
136 // Returns the parent.
137 NodeType* GetParent() {
138 return parent_;
139 }
[email protected]b3c33d462009-06-26 22:29:20140 const NodeType* GetParent() const {
141 return parent_;
142 }
initial.commit09911bf2008-07-26 23:55:29143
144 // Returns the index of the specified child, or -1 if node is a not a child.
[email protected]b3c33d462009-06-26 22:29:20145 int IndexOfChild(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29146 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20147 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12148 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29149 if (i != children_->end())
150 return static_cast<int>(i - children_->begin());
151 return -1;
152 }
153
154 // Sets the title of the node.
[email protected]e64e9012010-01-11 23:10:55155 // TODO(munjal): Remove wstring overload once all code is moved to string16.
156#if !defined(WCHAR_T_IS_UTF16)
initial.commit09911bf2008-07-26 23:55:29157 void SetTitle(const std::wstring& string) {
[email protected]e64e9012010-01-11 23:10:55158 title_ = WideToUTF16(string);
159 }
160#endif
161 void SetTitle(const string16& string) {
initial.commit09911bf2008-07-26 23:55:29162 title_ = string;
163 }
164
[email protected]e64e9012010-01-11 23:10:55165 // TODO(munjal): Remove wstring version and rename GetTitleAsString16 to
166 // GetTitle once all code is moved to string16.
initial.commit09911bf2008-07-26 23:55:29167 // Returns the title of the node.
[email protected]e64e9012010-01-11 23:10:55168 virtual std::wstring GetTitle() const {
169 return UTF16ToWide(title_);
170 }
171 virtual const string16& GetTitleAsString16() const {
initial.commit09911bf2008-07-26 23:55:29172 return title_;
173 }
174
175 // Returns true if this is the root.
[email protected]b3c33d462009-06-26 22:29:20176 bool IsRoot() const { return (parent_ == NULL); }
initial.commit09911bf2008-07-26 23:55:29177
178 // Returns true if this == ancestor, or one of this nodes parents is
179 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20180 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29181 if (ancestor == this)
182 return true;
183 if (!ancestor)
184 return false;
185 return parent_ ? parent_->HasAncestor(ancestor) : false;
186 }
187
[email protected]e2f86d92009-02-25 00:22:01188 protected:
189 std::vector<NodeType*>& children() { return children_.get(); }
190
initial.commit09911bf2008-07-26 23:55:29191 private:
192 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55193 string16 title_;
initial.commit09911bf2008-07-26 23:55:29194
195 NodeType* parent_;
196
197 // Children.
198 ScopedVector<NodeType> children_;
199
[email protected]405ed122008-11-14 17:48:40200 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29201};
202
203// TreeNodeWithValue ----------------------------------------------------------
204
205template <class ValueType>
[email protected]405ed122008-11-14 17:48:40206class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
207 private:
208 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
209
initial.commit09911bf2008-07-26 23:55:29210 public:
211 TreeNodeWithValue() { }
212
[email protected]a5b58f52009-11-17 22:15:44213 explicit TreeNodeWithValue(const ValueType& value)
[email protected]405ed122008-11-14 17:48:40214 : ParentType(std::wstring()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29215
216 TreeNodeWithValue(const std::wstring& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40217 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29218
219 ValueType value;
220
221 private:
[email protected]405ed122008-11-14 17:48:40222 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29223};
224
225// TreeNodeModel --------------------------------------------------------------
226
227// TreeModel implementation intended to be used with TreeNodes.
228template <class NodeType>
229class TreeNodeModel : public TreeModel {
230 public:
231 // Creates a TreeNodeModel with the specified root node. The root is owned
232 // by the TreeNodeModel.
233 explicit TreeNodeModel(NodeType* root)
[email protected]1baa4f02009-01-26 09:29:08234 : root_(root),
235 observer_(NULL) {
initial.commit09911bf2008-07-26 23:55:29236 }
237
238 virtual ~TreeNodeModel() {}
239
240 virtual void SetObserver(TreeModelObserver* observer) {
241 observer_ = observer;
242 }
243
244 TreeModelObserver* GetObserver() {
245 return observer_;
246 }
247
248 // TreeModel methods, all forward to the nodes.
249 virtual NodeType* GetRoot() { return root_.get(); }
250
251 virtual int GetChildCount(TreeModelNode* parent) {
252 DCHECK(parent);
253 return AsNode(parent)->GetChildCount();
254 }
255
256 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
257 DCHECK(parent);
258 return AsNode(parent)->GetChild(index);
259 }
260
[email protected]42062e72009-11-11 23:07:58261 virtual int IndexOfChild(TreeModelNode* parent, TreeModelNode* child) {
262 DCHECK(parent);
263 return AsNode(parent)->IndexOfChild(AsNode(child));
264 }
265
initial.commit09911bf2008-07-26 23:55:29266 virtual TreeModelNode* GetParent(TreeModelNode* node) {
267 DCHECK(node);
268 return AsNode(node)->GetParent();
269 }
270
271 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48272 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29273 }
274
275 // Sets the title of the specified node.
276 virtual void SetTitle(TreeModelNode* node,
277 const std::wstring& title) {
278 DCHECK(node);
279 AsNode(node)->SetTitle(title);
280 NotifyObserverTreeNodeChanged(node);
281 }
282
283 void Add(NodeType* parent, int index, NodeType* child) {
284 DCHECK(parent && child);
285 parent->Add(index, child);
286 NotifyObserverTreeNodesAdded(parent, index, 1);
287 }
288
289 NodeType* Remove(NodeType* parent, int index) {
290 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41291 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29292 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41293 return child;
initial.commit09911bf2008-07-26 23:55:29294 }
295
296 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
297 if (observer_)
298 observer_->TreeNodesAdded(this, parent, start, count);
299 }
300
301 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
302 if (observer_)
303 observer_->TreeNodesRemoved(this, parent, start, count);
304 }
305
306 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
307 if (observer_)
308 observer_->TreeNodeChanged(this, node);
309 }
310
311 private:
312 // The root.
313 scoped_ptr<NodeType> root_;
314
315 // The observer.
316 TreeModelObserver* observer_;
317
[email protected]405ed122008-11-14 17:48:40318 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29319};
320
[email protected]992c6252009-05-13 18:54:20321#endif // APP_TREE_NODE_MODEL_H_