blob: 9720b8a24145faa1eaf35af8c85e7db9cab3c04c [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)
84 parent->Remove(parent->GetIndexOf(node));
85 node->parent_ = static_cast<NodeType*>(this);
86 children_->insert(children_->begin() + index, node);
initial.commit09911bf2008-07-26 23:55:2987 }
88
89 // Removes the node by index. This does NOT delete the specified node, it is
90 // up to the caller to delete it when done.
91 virtual NodeType* Remove(int index) {
[email protected]9c1a75a2011-03-10 02:38:1292 DCHECK(index >= 0 && index < child_count());
initial.commit09911bf2008-07-26 23:55:2993 NodeType* node = GetChild(index);
94 node->parent_ = NULL;
95 children_->erase(index + children_->begin());
96 return node;
97 }
98
[email protected]58b359d2009-02-27 22:05:0899 // Removes all the children from this node. This does NOT delete the nodes.
100 void RemoveAll() {
101 for (size_t i = 0; i < children_->size(); ++i)
102 children_[i]->parent_ = NULL;
103 children_->clear();
104 }
105
initial.commit09911bf2008-07-26 23:55:29106 // Returns the number of children.
[email protected]9c1a75a2011-03-10 02:38:12107 int child_count() const { return static_cast<int>(children_->size()); }
initial.commit09911bf2008-07-26 23:55:29108
[email protected]9ff22ee42009-10-25 06:03:03109 // Returns the number of all nodes in teh subtree rooted at this node,
110 // including this node.
111 int GetTotalNodeCount() const {
112 int count = 1; // Start with one to include the node itself.
113 for (size_t i = 0; i < children_->size(); ++i) {
[email protected]dce51622009-11-06 04:58:48114 const TreeNode<NodeType>* child = children_[i];
[email protected]9ff22ee42009-10-25 06:03:03115 count += child->GetTotalNodeCount();
116 }
117 return count;
118 }
119
[email protected]9c1a75a2011-03-10 02:38:12120 // Returns the node at |index|.
initial.commit09911bf2008-07-26 23:55:29121 NodeType* GetChild(int index) {
[email protected]9c1a75a2011-03-10 02:38:12122 DCHECK(index >= 0 && index < child_count());
initial.commit09911bf2008-07-26 23:55:29123 return children_[index];
124 }
[email protected]b3c33d462009-06-26 22:29:20125 const NodeType* GetChild(int index) const {
[email protected]f07d7bf2010-04-06 08:02:42126 DCHECK_LE(0, index);
[email protected]9c1a75a2011-03-10 02:38:12127 DCHECK_GT(child_count(), index);
[email protected]b3c33d462009-06-26 22:29:20128 return children_[index];
129 }
initial.commit09911bf2008-07-26 23:55:29130
[email protected]2d48ee842011-03-08 23:27:29131 // Returns the parent of this object, or NULL if it's the root.
132 const NodeType* parent() const { return parent_; }
133 NodeType* parent() { return parent_; }
initial.commit09911bf2008-07-26 23:55:29134
[email protected]368f3a72011-03-08 17:17:48135 // Returns the index of |node|, or -1 if |node| is not a child of this.
136 int GetIndexOf(const NodeType* node) const {
initial.commit09911bf2008-07-26 23:55:29137 DCHECK(node);
[email protected]b3c33d462009-06-26 22:29:20138 typename std::vector<NodeType*>::const_iterator i =
[email protected]775cfd762008-12-09 17:12:12139 std::find(children_->begin(), children_->end(), node);
initial.commit09911bf2008-07-26 23:55:29140 if (i != children_->end())
141 return static_cast<int>(i - children_->begin());
142 return -1;
143 }
144
145 // Sets the title of the node.
[email protected]23db9f72011-03-11 19:43:24146 void set_title(const string16& title) { title_ = title; }
initial.commit09911bf2008-07-26 23:55:29147
[email protected]23db9f72011-03-11 19:43:24148 // TreeModelNode:
149 virtual const string16& GetTitle() const OVERRIDE { return title_; }
initial.commit09911bf2008-07-26 23:55:29150
151 // Returns true if this is the root.
[email protected]23db9f72011-03-11 19:43:24152 bool IsRoot() const { return parent_ == NULL; }
initial.commit09911bf2008-07-26 23:55:29153
154 // Returns true if this == ancestor, or one of this nodes parents is
155 // ancestor.
[email protected]b3c33d462009-06-26 22:29:20156 bool HasAncestor(const NodeType* ancestor) const {
initial.commit09911bf2008-07-26 23:55:29157 if (ancestor == this)
158 return true;
159 if (!ancestor)
160 return false;
161 return parent_ ? parent_->HasAncestor(ancestor) : false;
162 }
163
[email protected]e2f86d92009-02-25 00:22:01164 protected:
165 std::vector<NodeType*>& children() { return children_.get(); }
166
initial.commit09911bf2008-07-26 23:55:29167 private:
168 // Title displayed in the tree.
[email protected]e64e9012010-01-11 23:10:55169 string16 title_;
initial.commit09911bf2008-07-26 23:55:29170
[email protected]9c1a75a2011-03-10 02:38:12171 // This node's parent.
initial.commit09911bf2008-07-26 23:55:29172 NodeType* parent_;
173
[email protected]9c1a75a2011-03-10 02:38:12174 // This node's children.
initial.commit09911bf2008-07-26 23:55:29175 ScopedVector<NodeType> children_;
176
[email protected]405ed122008-11-14 17:48:40177 DISALLOW_COPY_AND_ASSIGN(TreeNode);
initial.commit09911bf2008-07-26 23:55:29178};
179
180// TreeNodeWithValue ----------------------------------------------------------
181
182template <class ValueType>
[email protected]405ed122008-11-14 17:48:40183class TreeNodeWithValue : public TreeNode< TreeNodeWithValue<ValueType> > {
initial.commit09911bf2008-07-26 23:55:29184 public:
[email protected]23db9f72011-03-11 19:43:24185 TreeNodeWithValue() {}
initial.commit09911bf2008-07-26 23:55:29186
[email protected]a5b58f52009-11-17 22:15:44187 explicit TreeNodeWithValue(const ValueType& value)
[email protected]23db9f72011-03-11 19:43:24188 : ParentType(string16()), value(value) {}
initial.commit09911bf2008-07-26 23:55:29189
[email protected]964b6772010-08-25 16:50:48190 TreeNodeWithValue(const string16& title, const ValueType& value)
[email protected]23db9f72011-03-11 19:43:24191 : ParentType(title), value(value) {}
initial.commit09911bf2008-07-26 23:55:29192
193 ValueType value;
194
195 private:
[email protected]23db9f72011-03-11 19:43:24196 typedef TreeNode< TreeNodeWithValue<ValueType> > ParentType;
197
[email protected]405ed122008-11-14 17:48:40198 DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue);
initial.commit09911bf2008-07-26 23:55:29199};
200
201// TreeNodeModel --------------------------------------------------------------
202
203// TreeModel implementation intended to be used with TreeNodes.
204template <class NodeType>
205class TreeNodeModel : public TreeModel {
206 public:
207 // Creates a TreeNodeModel with the specified root node. The root is owned
208 // by the TreeNodeModel.
[email protected]23db9f72011-03-11 19:43:24209 explicit TreeNodeModel(NodeType* root) : root_(root) {}
initial.commit09911bf2008-07-26 23:55:29210 virtual ~TreeNodeModel() {}
211
initial.commit09911bf2008-07-26 23:55:29212 NodeType* AsNode(TreeModelNode* model_node) {
[email protected]dce51622009-11-06 04:58:48213 return static_cast<NodeType*>(model_node);
initial.commit09911bf2008-07-26 23:55:29214 }
215
[email protected]a0dd6a32011-03-18 17:31:37216 void Add(NodeType* parent, NodeType* child, int index) {
initial.commit09911bf2008-07-26 23:55:29217 DCHECK(parent && child);
[email protected]a0dd6a32011-03-18 17:31:37218 parent->Add(child, index);
initial.commit09911bf2008-07-26 23:55:29219 NotifyObserverTreeNodesAdded(parent, index, 1);
220 }
221
222 NodeType* Remove(NodeType* parent, int index) {
223 DCHECK(parent);
[email protected]776e7492008-10-23 16:47:41224 NodeType* child = parent->Remove(index);
initial.commit09911bf2008-07-26 23:55:29225 NotifyObserverTreeNodesRemoved(parent, index, 1);
[email protected]776e7492008-10-23 16:47:41226 return child;
initial.commit09911bf2008-07-26 23:55:29227 }
228
229 void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48230 FOR_EACH_OBSERVER(TreeModelObserver,
231 observer_list_,
232 TreeNodesAdded(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29233 }
234
235 void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) {
[email protected]0457c6b2010-02-10 18:44:48236 FOR_EACH_OBSERVER(TreeModelObserver,
237 observer_list_,
238 TreeNodesRemoved(this, parent, start, count));
initial.commit09911bf2008-07-26 23:55:29239 }
240
[email protected]23db9f72011-03-11 19:43:24241 void NotifyObserverTreeNodeChanged(TreeModelNode* node) {
[email protected]0457c6b2010-02-10 18:44:48242 FOR_EACH_OBSERVER(TreeModelObserver,
243 observer_list_,
244 TreeNodeChanged(this, node));
initial.commit09911bf2008-07-26 23:55:29245 }
246
[email protected]23db9f72011-03-11 19:43:24247 // TreeModel:
248 virtual NodeType* GetRoot() OVERRIDE {
249 return root_.get();
250 }
251
252 virtual int GetChildCount(TreeModelNode* parent) OVERRIDE {
253 DCHECK(parent);
254 return AsNode(parent)->child_count();
255 }
256
257 virtual NodeType* GetChild(TreeModelNode* parent, int index) OVERRIDE {
258 DCHECK(parent);
259 return AsNode(parent)->GetChild(index);
260 }
261
262 virtual int GetIndexOf(TreeModelNode* parent, TreeModelNode* child) OVERRIDE {
263 DCHECK(parent);
264 return AsNode(parent)->GetIndexOf(AsNode(child));
265 }
266
267 virtual TreeModelNode* GetParent(TreeModelNode* node) OVERRIDE {
268 DCHECK(node);
269 return AsNode(node)->parent();
270 }
271
272 virtual void AddObserver(TreeModelObserver* observer) OVERRIDE {
273 observer_list_.AddObserver(observer);
274 }
275
276 virtual void RemoveObserver(TreeModelObserver* observer) OVERRIDE {
277 observer_list_.RemoveObserver(observer);
278 }
279
280 virtual void SetTitle(TreeModelNode* node, const string16& title) OVERRIDE {
281 DCHECK(node);
282 AsNode(node)->set_title(title);
283 NotifyObserverTreeNodeChanged(node);
284 }
[email protected]0457c6b2010-02-10 18:44:48285
initial.commit09911bf2008-07-26 23:55:29286 private:
[email protected]0457c6b2010-02-10 18:44:48287 // The observers.
288 ObserverList<TreeModelObserver> observer_list_;
[email protected]23db9f72011-03-11 19:43:24289
initial.commit09911bf2008-07-26 23:55:29290 // The root.
291 scoped_ptr<NodeType> root_;
292
[email protected]405ed122008-11-14 17:48:40293 DISALLOW_COPY_AND_ASSIGN(TreeNodeModel);
initial.commit09911bf2008-07-26 23:55:29294};
295
[email protected]44cbd9e2011-01-14 15:49:40296} // namespace ui
297
298#endif // UI_BASE_MODELS_TREE_NODE_MODEL_H_