Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / data / Tree.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.data.Tree
17  * 
18  * This class is used as a container for a series of nodes. The nodes themselves maintain
19  * the relationship between parent/child. The tree itself acts as a manager. It gives functionality
20  * to retrieve a node by its identifier: {@link #getNodeById}. 
21  *
22  * The tree also relays events from any of it's child nodes, allowing them to be handled in a 
23  * centralized fashion. In general this class is not used directly, rather used internally 
24  * by other parts of the framework.
25  *
26  */
27 Ext.define('Ext.data.Tree', {
28     alias: 'data.tree',
29     
30     mixins: {
31         observable: "Ext.util.Observable"
32     },
33
34     /**
35      * The root node for this tree
36      * @type Node
37      */
38     root: null,
39
40     /**
41      * Creates new Tree object.
42      * @param {Node} root (optional) The root node
43      */
44     constructor: function(root) {
45         var me = this;
46         
47         me.nodeHash = {};
48
49         me.mixins.observable.constructor.call(me);
50                         
51         if (root) {
52             me.setRootNode(root);
53         }
54     },
55
56     /**
57      * Returns the root node for this tree.
58      * @return {Ext.data.NodeInterface}
59      */
60     getRootNode : function() {
61         return this.root;
62     },
63
64     /**
65      * Sets the root node for this tree.
66      * @param {Ext.data.NodeInterface} node
67      * @return {Ext.data.NodeInterface} The root node
68      */
69     setRootNode : function(node) {
70         var me = this;
71         
72         me.root = node;
73         Ext.data.NodeInterface.decorate(node);
74         
75         if (me.fireEvent('beforeappend', null, node) !== false) {
76             node.set('root', true);
77             node.updateInfo();
78             
79             me.relayEvents(node, [
80                 /**
81                  * @event append
82                  * Fires when a new child node is appended to a node in this tree.
83                  * @param {Tree} tree The owner tree
84                  * @param {Node} parent The parent node
85                  * @param {Node} node The newly appended node
86                  * @param {Number} index The index of the newly appended node
87                  */
88                 "append",
89
90                 /**
91                  * @event remove
92                  * Fires when a child node is removed from a node in this tree.
93                  * @param {Tree} tree The owner tree
94                  * @param {Node} parent The parent node
95                  * @param {Node} node The child node removed
96                  */
97                 "remove",
98
99                 /**
100                  * @event move
101                  * Fires when a node is moved to a new location in the tree
102                  * @param {Tree} tree The owner tree
103                  * @param {Node} node The node moved
104                  * @param {Node} oldParent The old parent of this node
105                  * @param {Node} newParent The new parent of this node
106                  * @param {Number} index The index it was moved to
107                  */
108                 "move",
109
110                 /**
111                  * @event insert
112                  * Fires when a new child node is inserted in a node in this tree.
113                  * @param {Tree} tree The owner tree
114                  * @param {Node} parent The parent node
115                  * @param {Node} node The child node inserted
116                  * @param {Node} refNode The child node the node was inserted before
117                  */
118                 "insert",
119
120                 /**
121                  * @event beforeappend
122                  * Fires before a new child is appended to a node in this tree, return false to cancel the append.
123                  * @param {Tree} tree The owner tree
124                  * @param {Node} parent The parent node
125                  * @param {Node} node The child node to be appended
126                  */
127                 "beforeappend",
128
129                 /**
130                  * @event beforeremove
131                  * Fires before a child is removed from a node in this tree, return false to cancel the remove.
132                  * @param {Tree} tree The owner tree
133                  * @param {Node} parent The parent node
134                  * @param {Node} node The child node to be removed
135                  */
136                 "beforeremove",
137
138                 /**
139                  * @event beforemove
140                  * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
141                  * @param {Tree} tree The owner tree
142                  * @param {Node} node The node being moved
143                  * @param {Node} oldParent The parent of the node
144                  * @param {Node} newParent The new parent the node is moving to
145                  * @param {Number} index The index it is being moved to
146                  */
147                 "beforemove",
148
149                 /**
150                  * @event beforeinsert
151                  * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
152                  * @param {Tree} tree The owner tree
153                  * @param {Node} parent The parent node
154                  * @param {Node} node The child node to be inserted
155                  * @param {Node} refNode The child node the node is being inserted before
156                  */
157                 "beforeinsert",
158
159                  /**
160                   * @event expand
161                   * Fires when this node is expanded.
162                   * @param {Node} this The expanding node
163                   */
164                  "expand",
165
166                  /**
167                   * @event collapse
168                   * Fires when this node is collapsed.
169                   * @param {Node} this The collapsing node
170                   */
171                  "collapse",
172
173                  /**
174                   * @event beforeexpand
175                   * Fires before this node is expanded.
176                   * @param {Node} this The expanding node
177                   */
178                  "beforeexpand",
179
180                  /**
181                   * @event beforecollapse
182                   * Fires before this node is collapsed.
183                   * @param {Node} this The collapsing node
184                   */
185                  "beforecollapse" ,
186
187                  /**
188                   * @event rootchange
189                   * Fires whenever the root node is changed in the tree.
190                   * @param {Ext.data.Model} root The new root
191                   */
192                  "rootchange"
193             ]);
194             
195             node.on({
196                 scope: me,
197                 insert: me.onNodeInsert,
198                 append: me.onNodeAppend,
199                 remove: me.onNodeRemove
200             });
201
202             me.registerNode(node);        
203             me.fireEvent('append', null, node);
204             me.fireEvent('rootchange', node);
205         }
206             
207         return node;
208     },
209     
210     /**
211      * Flattens all the nodes in the tree into an array.
212      * @private
213      * @return {Array} The flattened nodes.
214      */
215     flatten: function(){
216         var nodes = [],
217             hash = this.nodeHash,
218             key;
219             
220         for (key in hash) {
221             if (hash.hasOwnProperty(key)) {
222                 nodes.push(hash[key]);
223             }
224         }
225         return nodes;
226     },
227     
228     /**
229      * Fired when a node is inserted into the root or one of it's children
230      * @private
231      * @param {Ext.data.NodeInterface} parent The parent node
232      * @param {Ext.data.NodeInterface} node The inserted node
233      */
234     onNodeInsert: function(parent, node) {
235         this.registerNode(node);
236     },
237     
238     /**
239      * Fired when a node is appended into the root or one of it's children
240      * @private
241      * @param {Ext.data.NodeInterface} parent The parent node
242      * @param {Ext.data.NodeInterface} node The appended node
243      */
244     onNodeAppend: function(parent, node) {
245         this.registerNode(node);
246     },
247     
248     /**
249      * Fired when a node is removed from the root or one of it's children
250      * @private
251      * @param {Ext.data.NodeInterface} parent The parent node
252      * @param {Ext.data.NodeInterface} node The removed node
253      */
254     onNodeRemove: function(parent, node) {
255         this.unregisterNode(node);
256     },
257
258     /**
259      * Gets a node in this tree by its id.
260      * @param {String} id
261      * @return {Ext.data.NodeInterface} The match node.
262      */
263     getNodeById : function(id) {
264         return this.nodeHash[id];
265     },
266
267     /**
268      * Registers a node with the tree
269      * @private
270      * @param {Ext.data.NodeInterface} The node to register
271      */
272     registerNode : function(node) {
273         this.nodeHash[node.getId() || node.internalId] = node;
274     },
275
276     /**
277      * Unregisters a node with the tree
278      * @private
279      * @param {Ext.data.NodeInterface} The node to unregister
280      */
281     unregisterNode : function(node) {
282         delete this.nodeHash[node.getId() || node.internalId];
283     },
284     
285     /**
286      * Sorts this tree
287      * @private
288      * @param {Function} sorterFn The function to use for sorting
289      * @param {Boolean} recursive True to perform recursive sorting
290      */
291     sort: function(sorterFn, recursive) {
292         this.getRootNode().sort(sorterFn, recursive);
293     },
294     
295      /**
296      * Filters this tree
297      * @private
298      * @param {Function} sorterFn The function to use for filtering
299      * @param {Boolean} recursive True to perform recursive filtering
300      */
301     filter: function(filters, recursive) {
302         this.getRootNode().filter(filters, recursive);
303     }
304 });