// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef APP_TREE_NODE_MODEL_H_ #define APP_TREE_NODE_MODEL_H_ #include #include #include #include "app/tree_model.h" #include "base/basictypes.h" #include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/scoped_vector.h" #include "base/stl_util-inl.h" #include "base/string16.h" #include "base/utf_string_conversions.h" // TreeNodeModel and TreeNodes provide an implementation of TreeModel around // TreeNodes. TreeNodes form a directed acyclic graph. // // TreeNodes own their children, so that deleting a node deletes all // descendants. // // TreeNodes do NOT maintain a pointer back to the model. As such, if you // are using TreeNodes with a TreeNodeModel you will need to notify the observer // yourself any time you make any change directly to the TreeNodes. For example, // if you directly invoke SetTitle on a node it does not notify the // observer, you will need to do it yourself. This includes the following // methods: SetTitle, Remove and Add. TreeNodeModel provides cover // methods that mutate the TreeNodes and notify the observer. If you are using // TreeNodes with a TreeNodeModel use the cover methods to save yourself the // headache. // // The following example creates a TreeNode with two children and then // creates a TreeNodeModel from it: // // TreeNodeWithValue root = new TreeNodeWithValue(0, L"root"); // root.add(new TreeNodeWithValue(1, L"child 1")); // root.add(new TreeNodeWithValue(1, L"child 2")); // TreeNodeModel>* model = // new TreeNodeModel>(root); // // Two variants of TreeNode are provided here: // // . TreeNode itself is intended for subclassing. It has one type parameter // that corresponds to the type of the node. When subclassing use your class // name as the type parameter, eg: // class MyTreeNode : public TreeNode . // . TreeNodeWithValue is a trivial subclass of TreeNode that has one type // type parameter: a value type that is associated with the node. // // Which you use depends upon the situation. If you want to subclass and add // methods, then use TreeNode. If you don't need any extra methods and just // want to associate a value with each node, then use TreeNodeWithValue. // // Regardless of which TreeNode you use, if you are using the nodes with a // TreeView take care to notify the observer when mutating the nodes. template class TreeNodeModel; // TreeNode ------------------------------------------------------------------- template class TreeNode : public TreeModelNode { public: TreeNode() : parent_(NULL) { } // TODO(munjal): Remove wstring overload once all code is moved to string16. #if !defined(WCHAR_T_IS_UTF16) explicit TreeNode(const std::wstring& title) : title_(WideToUTF16(title)), parent_(NULL) {} #endif explicit TreeNode(const string16& title) : title_(title), parent_(NULL) {} virtual ~TreeNode() { } // Adds the specified child node. virtual void Add(int index, NodeType* child) { DCHECK(child); DCHECK_LE(0, index); DCHECK_GE(GetChildCount(), index); // If the node has a parent, remove it from its parent. NodeType* node_parent = child->GetParent(); if (node_parent) node_parent->Remove(node_parent->IndexOfChild(child)); child->parent_ = static_cast(this); children_->insert(children_->begin() + index, child); } // Removes the node by index. This does NOT delete the specified node, it is // up to the caller to delete it when done. virtual NodeType* Remove(int index) { DCHECK(index >= 0 && index < GetChildCount()); NodeType* node = GetChild(index); node->parent_ = NULL; children_->erase(index + children_->begin()); return node; } // Removes all the children from this node. This does NOT delete the nodes. void RemoveAll() { for (size_t i = 0; i < children_->size(); ++i) children_[i]->parent_ = NULL; children_->clear(); } // Returns the number of children. int GetChildCount() const { return static_cast(children_->size()); } // Returns the number of all nodes in teh subtree rooted at this node, // including this node. int GetTotalNodeCount() const { int count = 1; // Start with one to include the node itself. for (size_t i = 0; i < children_->size(); ++i) { const TreeNode* child = children_[i]; count += child->GetTotalNodeCount(); } return count; } // Returns a child by index. NodeType* GetChild(int index) { DCHECK(index >= 0 && index < GetChildCount()); return children_[index]; } const NodeType* GetChild(int index) const { DCHECK_LE(0, index); DCHECK_GT(GetChildCount(), index); return children_[index]; } // Returns the parent. NodeType* GetParent() { return parent_; } const NodeType* GetParent() const { return parent_; } // Returns the index of the specified child, or -1 if node is a not a child. int IndexOfChild(const NodeType* node) const { DCHECK(node); typename std::vector::const_iterator i = std::find(children_->begin(), children_->end(), node); if (i != children_->end()) return static_cast(i - children_->begin()); return -1; } // Sets the title of the node. // TODO(munjal): Remove wstring overload once all code is moved to string16. #if !defined(WCHAR_T_IS_UTF16) void SetTitle(const std::wstring& string) { title_ = WideToUTF16(string); } #endif void SetTitle(const string16& string) { title_ = string; } // TODO(munjal): Remove wstring version and rename GetTitleAsString16 to // GetTitle once all code is moved to string16. // Returns the title of the node. virtual std::wstring GetTitle() const { return UTF16ToWide(title_); } virtual const string16& GetTitleAsString16() const { return title_; } // Returns true if this is the root. bool IsRoot() const { return (parent_ == NULL); } // Returns true if this == ancestor, or one of this nodes parents is // ancestor. bool HasAncestor(const NodeType* ancestor) const { if (ancestor == this) return true; if (!ancestor) return false; return parent_ ? parent_->HasAncestor(ancestor) : false; } protected: std::vector& children() { return children_.get(); } private: // Title displayed in the tree. string16 title_; NodeType* parent_; // Children. ScopedVector children_; DISALLOW_COPY_AND_ASSIGN(TreeNode); }; // TreeNodeWithValue ---------------------------------------------------------- template class TreeNodeWithValue : public TreeNode< TreeNodeWithValue > { private: typedef TreeNode< TreeNodeWithValue > ParentType; public: TreeNodeWithValue() { } explicit TreeNodeWithValue(const ValueType& value) : ParentType(std::wstring()), value(value) { } TreeNodeWithValue(const std::wstring& title, const ValueType& value) : ParentType(title), value(value) { } ValueType value; private: DISALLOW_COPY_AND_ASSIGN(TreeNodeWithValue); }; // TreeNodeModel -------------------------------------------------------------- // TreeModel implementation intended to be used with TreeNodes. template class TreeNodeModel : public TreeModel { public: // Creates a TreeNodeModel with the specified root node. The root is owned // by the TreeNodeModel. explicit TreeNodeModel(NodeType* root) : root_(root) { } virtual ~TreeNodeModel() {} // Observer methods, calls into ObserverList. virtual void AddObserver(TreeModelObserver* observer) { observer_list_.AddObserver(observer); } virtual void RemoveObserver(TreeModelObserver* observer) { observer_list_.RemoveObserver(observer); } // TreeModel methods, all forward to the nodes. virtual NodeType* GetRoot() { return root_.get(); } virtual int GetChildCount(TreeModelNode* parent) { DCHECK(parent); return AsNode(parent)->GetChildCount(); } virtual NodeType* GetChild(TreeModelNode* parent, int index) { DCHECK(parent); return AsNode(parent)->GetChild(index); } virtual int IndexOfChild(TreeModelNode* parent, TreeModelNode* child) { DCHECK(parent); return AsNode(parent)->IndexOfChild(AsNode(child)); } virtual TreeModelNode* GetParent(TreeModelNode* node) { DCHECK(node); return AsNode(node)->GetParent(); } NodeType* AsNode(TreeModelNode* model_node) { return static_cast(model_node); } // Sets the title of the specified node. virtual void SetTitle(TreeModelNode* node, const std::wstring& title) { DCHECK(node); AsNode(node)->SetTitle(title); NotifyObserverTreeNodeChanged(node); } void Add(NodeType* parent, int index, NodeType* child) { DCHECK(parent && child); parent->Add(index, child); NotifyObserverTreeNodesAdded(parent, index, 1); } NodeType* Remove(NodeType* parent, int index) { DCHECK(parent); NodeType* child = parent->Remove(index); NotifyObserverTreeNodesRemoved(parent, index, 1); return child; } void NotifyObserverTreeNodesAdded(NodeType* parent, int start, int count) { FOR_EACH_OBSERVER(TreeModelObserver, observer_list_, TreeNodesAdded(this, parent, start, count)); } void NotifyObserverTreeNodesRemoved(NodeType* parent, int start, int count) { FOR_EACH_OBSERVER(TreeModelObserver, observer_list_, TreeNodesRemoved(this, parent, start, count)); } virtual void NotifyObserverTreeNodeChanged(TreeModelNode* node) { FOR_EACH_OBSERVER(TreeModelObserver, observer_list_, TreeNodeChanged(this, node)); } protected: ObserverList& observer_list() { return observer_list_; } private: // The observers. ObserverList observer_list_; // The root. scoped_ptr root_; DISALLOW_COPY_AND_ASSIGN(TreeNodeModel); }; #endif // APP_TREE_NODE_MODEL_H_