blob: ec6e2c347850fdd5349af0320db6ebfa20562a2f [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]23db9f72011-03-11 19:43:2413#include "base/compiler_specific.h"
[email protected]dec76e802010-09-23 22:43:5314#include "base/logging.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"
[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
[email protected]23db9f72011-03-11 19:43:2424// TreeNodes.
initial.commit09911bf2008-07-26 23:55:2925//
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,
[email protected]23db9f72011-03-11 19:43:2432// if you directly invoke set_title on a node it does not notify the observer,
33// you will need to do it yourself. This includes the following methods: Add,
34// Remove and set_title. TreeNodeModel provides cover methods that mutate the
35// TreeNodes and notify the observer. If you are using TreeNodes with a
36// TreeNodeModel use the cover methods to save yourself the headache.
initial.commit09911bf2008-07-26 23:55:2937//
38// The following example creates a TreeNode with two children and then
39// creates a TreeNodeModel from it:
40//
[email protected]964b6772010-08-25 16:50:4841// TreeNodeWithValue<int> root =
42// new TreeNodeWithValue<int>(ASCIIToUTF16("root"), 0);
43// root.add(new TreeNodeWithValue<int>(ASCIIToUTF16("child 1"), 1));
44// root.add(new TreeNodeWithValue<int>(ASCIIToUTF16("child 2"), 1));
initial.commit09911bf2008-07-26 23:55:2945// TreeNodeModel<TreeNodeWithValue<int>>* model =
46// new TreeNodeModel<TreeNodeWithValue<int>>(root);
47//
48// Two variants of TreeNode are provided here:
49//
50// . TreeNode itself is intended for subclassing. It has one type parameter
51// that corresponds to the type of the node. When subclassing use your class
52// name as the type parameter, eg:
53// class MyTreeNode : public TreeNode<MyTreeNode> .
54// . TreeNodeWithValue is a trivial subclass of TreeNode that has one type
55// type parameter: a value type that is associated with the node.
56//
57// Which you use depends upon the situation. If you want to subclass and add
58// methods, then use TreeNode. If you don't need any extra methods and just
59// want to associate a value with each node, then use TreeNodeWithValue.
60//
61// Regardless of which TreeNode you use, if you are using the nodes with a
62// TreeView take care to notify the observer when mutating the nodes.
63
initial.commit09911bf2008-07-26 23:55:2964// TreeNode -------------------------------------------------------------------
65
66template <class NodeType>
67class TreeNode : public TreeModelNode {
68 public:
[email protected]23db9f72011-03-11 19:43:2469 TreeNode() : parent_(NULL) {}
initial.commit09911bf2008-07-26 23:55:2970
[email protected]e64e9012010-01-11 23:10:5571 explicit TreeNode(const string16& title)
initial.commit09911bf2008-07-26 23:55:2972 : title_(title), parent_(NULL) {}
73
[email protected]23db9f72011-03-11 19:43:2474 virtual ~TreeNode() {}
initial.commit09911bf2008-07-26 23:55:2975
[email protected]a0dd6a32011-03-18 17:31:3776 // Adds a TreeNode as a child of this one, at |index|.
77 virtual void Add(NodeType* node, int index) {
78 DCHECK(node);
[email protected]f07d7bf2010-04-06 08:02:4279 DCHECK_LE(0, index);
[email protected]9c1a75a2011-03-10 02:38:1280 DCHECK_GE(child_count(), index);
initial.commit09911bf2008-07-26 23:55:2981 // If the node has a parent, remove it from its parent.
[email protected]a0dd6a32011-03-18 17:31:3782 NodeType* parent = node->parent();
83 if (parent)
[email protected]18cc5ff2011-03-22 01:05:2384 parent->Remove(node);
[email protected]a0dd6a32011-03-18 17:31:3785 node->parent_ = static_cast<NodeType*>(this);
86 children_->insert(children_->begin() + index, node);
initial.commit09911bf2008-07-26 23:55:2987 }
88
[email protected]18cc5ff2011-03-22 01:05:2389 // Remove |node| from this Node and returns it. It's up to the caller to
90 // delete it.
91 virtual NodeType* Remove(NodeType* node) {
92 typename std::vector<NodeType*>::iterator i =
93 std::find(children_->begin(), children_->end(), node);
94 DCHECK(i != children_.end());
initial.commit09911bf2008-07-26 23:55:2995 node->parent_ = NULL;
[email protected]18cc5ff2011-03-22 01:05:2396 children_->erase(i);
initial.commit09911bf2008-07-26 23:55:2997 return node;
98 }
99
[email protected]58b359d2009-02-27 22:05:08100 // Removes all the children from this node. This does NOT delete the nodes.
101 void RemoveAll() {
102 for (size_t i = 0; i < children_->size(); ++i)
103 children_[i]->parent_ = NULL;
104 children_->clear();
105 }
106
initial.commit09911bf2008-07-26 23:55:29107 // Returns the number of children.
[email protected]9c1a75a2011-03-10 02:38:12108 int child_count() const { return static_cast<int>(children_->size()); }
initial.commit09911bf2008-07-26 23:55:29109
[email protected]9ff22ee42009-10-25 06:03:03110 // Returns the number of all nodes in teh subtree rooted at this node,
111 // including this node.
112 int GetTotalNodeCount() const {
113 int count = 1; // Start with one to include the node itself.
114 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48115 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03116 count += child->GetTotalNodeCount();
117 }
118 return count;
119 }
120
[email protected]9c1a75a2011-03-10 02:38:12121 // Returns the node at |index|.
initial.commit09911bf2008-07-26 23:55:29122 NodeType* GetChild(int index) {
[email protected]9c1a75a2011-03-10 02:38:12123 DCHECK(index >= 0 && index < child_count());
initial.commit09911bf2008-07-26 23:55:29124 return children_[index];
125 }
[email protected]b3c33d462009-06-26 22:29:20126 const NodeType* GetChild(int index) const {
[email protected]f07d7bf2010-04-06 08:02:42127 DCHECK_LE(0, index);
[email protected]9c1a75a2011-03-10 02:38:12128 DCHECK_GT(child_count(), index);
[email protected]b3c33d462009-06-26 22:29:20129 return children_[index];
130 }
initial.commit09911bf2008-07-26 23:55:29131
[email protected]2d48ee842011-03-08 23:27:29132 // Returns the parent of this object, or NULL if it's the root.
133 const NodeType* parent() const { return parent_; }
134 NodeType* parent() { return parent_; }
initial.commit09911bf2008-07-26 23:55:29135
[email protected]368f3a72011-03-08 17:17:48136 // Returns the index of |node|, or -1 if |node| is not a child of this.
137 int GetIndexOf(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29138 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20139 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12140 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29141 if (i != children_->end())
142 return static_cast<int>(i - children_->begin());
143 return -1;
144 }
145
146 // Sets the title of the node.
[email protected]23db9f72011-03-11 19:43:24147 void set_title(const string16& title) { title_ = title; }
initial.commit09911bf2008-07-26 23:55:29148
[email protected]23db9f72011-03-11 19:43:24149 // TreeModelNode:
150 virtual const string16& GetTitle() const OVERRIDE { return title_; }
initial.commit09911bf2008-07-26 23:55:29151
152 // Returns true if this is the root.
[email protected]23db9f72011-03-11 19:43:24153 bool IsRoot() const { return parent_ == NULL; }
initial.commit09911bf2008-07-26 23:55:29154
155 // Returns true if this == ancestor, or one of this nodes parents is
156 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20157 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29158 if (ancestor == this)
159 return true;
160 if (!ancestor)
161 return false;
162 return parent_ ? parent_->HasAncestor(ancestor) : false;
163 }
164
[email protected]e2f86d92009-02-25 00:22:01165 protected:
166 std::vector<NodeType*>& children() { return children_.get(); }
167
initial.commit09911bf2008-07-26 23:55:29168 private:
169 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55170 string16 title_;
initial.commit09911bf2008-07-26 23:55:29171
[email protected]9c1a75a2011-03-10 02:38:12172 // This node's parent.
initial.commit09911bf2008-07-26 23:55:29173 NodeType* parent_;
174
[email protected]9c1a75a2011-03-10 02:38:12175 // This node's children.
initial.commit09911bf2008-07-26 23:55:29176 ScopedVector<NodeType> children_;
177
[email protected]405ed122008-11-14 17:48:40178 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29179};
180
181// TreeNodeWithValue ----------------------------------------------------------
182
183template <class ValueType>
[email protected]405ed122008-11-14 17:48:40184class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
initial.commit09911bf2008-07-26 23:55:29185 public:
[email protected]23db9f72011-03-11 19:43:24186 TreeNodeWithValue() {}
initial.commit09911bf2008-07-26 23:55:29187
[email protected]a5b58f52009-11-17 22:15:44188 explicit TreeNodeWithValue(const ValueType& value)
[email protected]23db9f72011-03-11 19:43:24189 : ParentType(string16()), value(value) {}
initial.commit09911bf2008-07-26 23:55:29190
[email protected]964b6772010-08-25 16:50:48191 TreeNodeWithValue(const string16& title, const ValueType& value)
[email protected]23db9f72011-03-11 19:43:24192 : ParentType(title), value(value) {}
initial.commit09911bf2008-07-26 23:55:29193
194 ValueType value;
195
196 private:
[email protected]23db9f72011-03-11 19:43:24197 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
198
[email protected]405ed122008-11-14 17:48:40199 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29200};
201
202// TreeNodeModel --------------------------------------------------------------
203
204// TreeModel implementation intended to be used with TreeNodes.
205template <class NodeType>
206class TreeNodeModel : public TreeModel {
207 public:
208 // Creates a TreeNodeModel with the specified root node. The root is owned
209 // by the TreeNodeModel.
[email protected]23db9f72011-03-11 19:43:24210 explicit TreeNodeModel(NodeType* root) : root_(root) {}
initial.commit09911bf2008-07-26 23:55:29211 virtual ~TreeNodeModel() {}
212
initial.commit09911bf2008-07-26 23:55:29213 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48214 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29215 }
216
[email protected]18cc5ff2011-03-22 01:05:23217 void Add(NodeType* parent, NodeType* node, int index) {
218 DCHECK(parent && node);
219 parent->Add(node, index);
initial.commit09911bf2008-07-26 23:55:29220 NotifyObserverTreeNodesAdded(parent, index, 1);
221 }
222
[email protected]18cc5ff2011-03-22 01:05:23223 NodeType* Remove(NodeType* parent, NodeType* node) {
initial.commit09911bf2008-07-26 23:55:29224 DCHECK(parent);
[email protected]18cc5ff2011-03-22 01:05:23225 int index = parent->GetIndexOf(node);
226 NodeType* delete_node = parent->Remove(node);
initial.commit09911bf2008-07-26 23:55:29227 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]18cc5ff2011-03-22 01:05:23228 return delete_node;
initial.commit09911bf2008-07-26 23:55:29229 }
230
231 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48232 FOR_EACH_OBSERVER(TreeModelObserver,
233 observer_list_,
234 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29235 }
236
237 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48238 FOR_EACH_OBSERVER(TreeModelObserver,
239 observer_list_,
240 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29241 }
242
[email protected]23db9f72011-03-11 19:43:24243 void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48244 FOR_EACH_OBSERVER(TreeModelObserver,
245 observer_list_,
246 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29247 }
248
[email protected]23db9f72011-03-11 19:43:24249 // TreeModel:
250 virtual NodeType* GetRoot() OVERRIDE {
251 return root_.get();
252 }
253
254 virtual int GetChildCount(TreeModelNode* parent) OVERRIDE {
255 DCHECK(parent);
256 return AsNode(parent)->child_count();
257 }
258
259 virtual NodeType* GetChild(TreeModelNode* parent, int index) OVERRIDE {
260 DCHECK(parent);
261 return AsNode(parent)->GetChild(index);
262 }
263
264 virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) OVERRIDE {
265 DCHECK(parent);
266 return AsNode(parent)->GetIndexOf(AsNode(child));
267 }
268
269 virtual TreeModelNode* GetParent(TreeModelNode* node) OVERRIDE {
270 DCHECK(node);
271 return AsNode(node)->parent();
272 }
273
274 virtual void AddObserver(TreeModelObserver* observer) OVERRIDE {
275 observer_list_.AddObserver(observer);
276 }
277
278 virtual void RemoveObserver(TreeModelObserver* observer) OVERRIDE {
279 observer_list_.RemoveObserver(observer);
280 }
281
282 virtual void SetTitle(TreeModelNode* node, const string16& title) OVERRIDE {
283 DCHECK(node);
284 AsNode(node)->set_title(title);
285 NotifyObserverTreeNodeChanged(node);
286 }
[email protected]0457c6b2010-02-10 18:44:48287
initial.commit09911bf2008-07-26 23:55:29288 private:
[email protected]0457c6b2010-02-10 18:44:48289 // The observers.
290 ObserverList<TreeModelObserver> observer_list_;
[email protected]23db9f72011-03-11 19:43:24291
initial.commit09911bf2008-07-26 23:55:29292 // The root.
293 scoped_ptr<NodeType> root_;
294
[email protected]405ed122008-11-14 17:48:40295 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29296};
297
[email protected]44cbd9e2011-01-14 15:49:40298} // namespace ui
299
300#endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_