blob: b294911fb84fe754cbb8a291fa2abbddba5c9104 [file] [log] [blame]
[email protected]7caca8a22010-08-21 18:25:311// Copyright (c) 2010 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]992c6252009-05-13 18:54:205#ifndef APP_TREE_NODE_MODEL_H_
6#define APP_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>
[email protected]e64e9012010-01-11 23:10:5510#include <string>
initial.commit09911bf2008-07-26 23:55:2911#include <vector>
12
[email protected]992c6252009-05-13 18:54:2013#include "app/tree_model.h"
initial.commit09911bf2008-07-26 23:55:2914#include "base/basictypes.h"
[email protected]0457c6b2010-02-10 18:44:4815#include "base/observer_list.h"
[email protected]1fec8402009-03-13 19:11:5916#include "base/scoped_ptr.h"
[email protected]807204142009-05-05 03:31:4417#include "base/scoped_vector.h"
18#include "base/stl_util-inl.h"
[email protected]e64e9012010-01-11 23:10:5519#include "base/string16.h"
20#include "base/utf_string_conversions.h"
initial.commit09911bf2008-07-26 23:55:2921
22// TreeNodeModel and TreeNodes provide an implementation of TreeModel around
23// TreeNodes. TreeNodes form a directed acyclic graph.
24//
25// TreeNodes own their children, so that deleting a node deletes all
26// descendants.
27//
28// TreeNodes do NOT maintain a pointer back to the model. As such, if you
29// are using TreeNodes with a TreeNodeModel you will need to notify the observer
30// yourself any time you make any change directly to the TreeNodes. For example,
31// if you directly invoke SetTitle on a node it does not notify the
32// observer, you will need to do it yourself. This includes the following
33// methods: SetTitle, Remove and Add. TreeNodeModel provides cover
34// methods that mutate the TreeNodes and notify the observer. If you are using
35// TreeNodes with a TreeNodeModel use the cover methods to save yourself the
36// headache.
37//
38// The following example creates a TreeNode with two children and then
39// creates a TreeNodeModel from it:
40//
41// TreeNodeWithValue<int> root = new TreeNodeWithValue<int>(0, L"root");
42// root.add(new TreeNodeWithValue<int>(1, L"child 1"));
43// root.add(new TreeNodeWithValue<int>(1, L"child 2"));
44// TreeNodeModel<TreeNodeWithValue<int>>* model =
45// new TreeNodeModel<TreeNodeWithValue<int>>(root);
46//
47// Two variants of TreeNode are provided here:
48//
49// . TreeNode itself is intended for subclassing. It has one type parameter
50// that corresponds to the type of the node. When subclassing use your class
51// name as the type parameter, eg:
52// class MyTreeNode : public TreeNode<MyTreeNode> .
53// . TreeNodeWithValue is a trivial subclass of TreeNode that has one type
54// type parameter: a value type that is associated with the node.
55//
56// Which you use depends upon the situation. If you want to subclass and add
57// methods, then use TreeNode. If you don't need any extra methods and just
58// want to associate a value with each node, then use TreeNodeWithValue.
59//
60// Regardless of which TreeNode you use, if you are using the nodes with a
61// TreeView take care to notify the observer when mutating the nodes.
62
63template <class NodeType>
64class TreeNodeModel;
65
66// TreeNode -------------------------------------------------------------------
67
68template <class NodeType>
69class TreeNode : public TreeModelNode {
70 public:
71 TreeNode() : parent_(NULL) { }
72
[email protected]e64e9012010-01-11 23:10:5573 // TODO(munjal): Remove wstring overload once all code is moved to string16.
74#if !defined(WCHAR_T_IS_UTF16)
initial.commit09911bf2008-07-26 23:55:2975 explicit TreeNode(const std::wstring& title)
[email protected]e64e9012010-01-11 23:10:5576 : title_(WideToUTF16(title)), parent_(NULL) {}
77#endif
78 explicit TreeNode(const string16& title)
initial.commit09911bf2008-07-26 23:55:2979 : title_(title), parent_(NULL) {}
80
81 virtual ~TreeNode() {
82 }
83
84 // Adds the specified child node.
85 virtual void Add(int index, NodeType* child) {
[email protected]f07d7bf2010-04-06 08:02:4286 DCHECK(child);
87 DCHECK_LE(0, index);
88 DCHECK_GE(GetChildCount(), index);
initial.commit09911bf2008-07-26 23:55:2989 // If the node has a parent, remove it from its parent.
90 NodeType* node_parent = child->GetParent();
91 if (node_parent)
92 node_parent->Remove(node_parent->IndexOfChild(child));
93 child->parent_ = static_cast<NodeType*>(this);
94 children_->insert(children_->begin() + index, child);
95 }
96
97 // Removes the node by index. This does NOT delete the specified node, it is
98 // up to the caller to delete it when done.
99 virtual NodeType* Remove(int index) {
100 DCHECK(index >= 0 && index < GetChildCount());
101 NodeType* node = GetChild(index);
102 node->parent_ = NULL;
103 children_->erase(index + children_->begin());
104 return node;
105 }
106
[email protected]58b359d2009-02-27 22:05:08107 // Removes all the children from this node. This does NOT delete the nodes.
108 void RemoveAll() {
109 for (size_t i = 0; i < children_->size(); ++i)
110 children_[i]->parent_ = NULL;
111 children_->clear();
112 }
113
initial.commit09911bf2008-07-26 23:55:29114 // Returns the number of children.
[email protected]b3c33d462009-06-26 22:29:20115 int GetChildCount() const {
initial.commit09911bf2008-07-26 23:55:29116 return static_cast<int>(children_->size());
117 }
118
[email protected]9ff22ee42009-10-25 06:03:03119 // Returns the number of all nodes in teh subtree rooted at this node,
120 // including this node.
121 int GetTotalNodeCount() const {
122 int count = 1; // Start with one to include the node itself.
123 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48124 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03125 count += child->GetTotalNodeCount();
126 }
127 return count;
128 }
129
initial.commit09911bf2008-07-26 23:55:29130 // Returns a child by index.
131 NodeType* GetChild(int index) {
132 DCHECK(index >= 0 && index < GetChildCount());
133 return children_[index];
134 }
[email protected]b3c33d462009-06-26 22:29:20135 const NodeType* GetChild(int index) const {
[email protected]f07d7bf2010-04-06 08:02:42136 DCHECK_LE(0, index);
137 DCHECK_GT(GetChildCount(), index);
[email protected]b3c33d462009-06-26 22:29:20138 return children_[index];
139 }
initial.commit09911bf2008-07-26 23:55:29140
141 // Returns the parent.
142 NodeType* GetParent() {
143 return parent_;
144 }
[email protected]b3c33d462009-06-26 22:29:20145 const NodeType* GetParent() const {
146 return parent_;
147 }
initial.commit09911bf2008-07-26 23:55:29148
149 // Returns the index of the specified child, or -1 if node is a not a child.
[email protected]b3c33d462009-06-26 22:29:20150 int IndexOfChild(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29151 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20152 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12153 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29154 if (i != children_->end())
155 return static_cast<int>(i - children_->begin());
156 return -1;
157 }
158
159 // Sets the title of the node.
[email protected]e64e9012010-01-11 23:10:55160 void SetTitle(const string16& string) {
initial.commit09911bf2008-07-26 23:55:29161 title_ = string;
162 }
163
[email protected]e64e9012010-01-11 23:10:55164 // TODO(munjal): Remove wstring version and rename GetTitleAsString16 to
165 // GetTitle once all code is moved to string16.
initial.commit09911bf2008-07-26 23:55:29166 // Returns the title of the node.
[email protected]e64e9012010-01-11 23:10:55167 virtual std::wstring GetTitle() const {
168 return UTF16ToWide(title_);
169 }
170 virtual const string16& GetTitleAsString16() const {
initial.commit09911bf2008-07-26 23:55:29171 return title_;
172 }
173
174 // Returns true if this is the root.
[email protected]b3c33d462009-06-26 22:29:20175 bool IsRoot() const { return (parent_ == NULL); }
initial.commit09911bf2008-07-26 23:55:29176
177 // Returns true if this == ancestor, or one of this nodes parents is
178 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20179 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29180 if (ancestor == this)
181 return true;
182 if (!ancestor)
183 return false;
184 return parent_ ? parent_->HasAncestor(ancestor) : false;
185 }
186
[email protected]e2f86d92009-02-25 00:22:01187 protected:
188 std::vector<NodeType*>& children() { return children_.get(); }
189
initial.commit09911bf2008-07-26 23:55:29190 private:
191 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55192 string16 title_;
initial.commit09911bf2008-07-26 23:55:29193
194 NodeType* parent_;
195
196 // Children.
197 ScopedVector<NodeType> children_;
198
[email protected]405ed122008-11-14 17:48:40199 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29200};
201
202// TreeNodeWithValue ----------------------------------------------------------
203
204template <class ValueType>
[email protected]405ed122008-11-14 17:48:40205class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
206 private:
207 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
208
initial.commit09911bf2008-07-26 23:55:29209 public:
210 TreeNodeWithValue() { }
211
[email protected]a5b58f52009-11-17 22:15:44212 explicit TreeNodeWithValue(const ValueType& value)
[email protected]405ed122008-11-14 17:48:40213 : ParentType(std::wstring()), value(value) { }
initial.commit09911bf2008-07-26 23:55:29214
215 TreeNodeWithValue(const std::wstring& title, const ValueType& value)
[email protected]405ed122008-11-14 17:48:40216 : ParentType(title), value(value) { }
initial.commit09911bf2008-07-26 23:55:29217
218 ValueType value;
219
220 private:
[email protected]405ed122008-11-14 17:48:40221 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29222};
223
224// TreeNodeModel --------------------------------------------------------------
225
226// TreeModel implementation intended to be used with TreeNodes.
227template <class NodeType>
228class TreeNodeModel : public TreeModel {
229 public:
230 // Creates a TreeNodeModel with the specified root node. The root is owned
231 // by the TreeNodeModel.
232 explicit TreeNodeModel(NodeType* root)
[email protected]0457c6b2010-02-10 18:44:48233 : root_(root) {
initial.commit09911bf2008-07-26 23:55:29234 }
235
236 virtual ~TreeNodeModel() {}
237
[email protected]0457c6b2010-02-10 18:44:48238 // Observer methods, calls into ObserverList.
239 virtual void AddObserver(TreeModelObserver* observer) {
240 observer_list_.AddObserver(observer);
initial.commit09911bf2008-07-26 23:55:29241 }
242
[email protected]0457c6b2010-02-10 18:44:48243 virtual void RemoveObserver(TreeModelObserver* observer) {
244 observer_list_.RemoveObserver(observer);
initial.commit09911bf2008-07-26 23:55:29245 }
246
247 // TreeModel methods, all forward to the nodes.
248 virtual NodeType* GetRoot() { return root_.get(); }
249
250 virtual int GetChildCount(TreeModelNode* parent) {
251 DCHECK(parent);
252 return AsNode(parent)->GetChildCount();
253 }
254
255 virtual NodeType* GetChild(TreeModelNode* parent, int index) {
256 DCHECK(parent);
257 return AsNode(parent)->GetChild(index);
258 }
259
[email protected]42062e72009-11-11 23:07:58260 virtual int IndexOfChild(TreeModelNode* parent, TreeModelNode* child) {
261 DCHECK(parent);
262 return AsNode(parent)->IndexOfChild(AsNode(child));
263 }
264
initial.commit09911bf2008-07-26 23:55:29265 virtual TreeModelNode* GetParent(TreeModelNode* node) {
266 DCHECK(node);
267 return AsNode(node)->GetParent();
268 }
269
270 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48271 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29272 }
273
274 // Sets the title of the specified node.
275 virtual void SetTitle(TreeModelNode* node,
[email protected]01d552552010-08-22 00:17:18276 const string16& title) {
initial.commit09911bf2008-07-26 23:55:29277 DCHECK(node);
[email protected]01d552552010-08-22 00:17:18278 AsNode(node)->SetTitle(title);
initial.commit09911bf2008-07-26 23:55:29279 NotifyObserverTreeNodeChanged(node);
280 }
281
282 void Add(NodeType* parent, int index, NodeType* child) {
283 DCHECK(parent && child);
284 parent->Add(index, child);
285 NotifyObserverTreeNodesAdded(parent, index, 1);
286 }
287
288 NodeType* Remove(NodeType* parent, int index) {
289 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41290 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29291 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41292 return child;
initial.commit09911bf2008-07-26 23:55:29293 }
294
295 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48296 FOR_EACH_OBSERVER(TreeModelObserver,
297 observer_list_,
298 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29299 }
300
301 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48302 FOR_EACH_OBSERVER(TreeModelObserver,
303 observer_list_,
304 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29305 }
306
307 virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48308 FOR_EACH_OBSERVER(TreeModelObserver,
309 observer_list_,
310 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29311 }
312
[email protected]0457c6b2010-02-10 18:44:48313 protected:
314 ObserverList<TreeModelObserver>& observer_list() { return observer_list_; }
315
initial.commit09911bf2008-07-26 23:55:29316 private:
[email protected]0457c6b2010-02-10 18:44:48317 // The observers.
318 ObserverList<TreeModelObserver> observer_list_;
initial.commit09911bf2008-07-26 23:55:29319 // The root.
320 scoped_ptr<NodeType> root_;
321
[email protected]405ed122008-11-14 17:48:40322 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29323};
324
[email protected]992c6252009-05-13 18:54:20325#endif // APP_TREE_NODE_MODEL_H_