Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / container / AbstractContainer.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.container.AbstractContainer
17  * @extends Ext.Component
18  * <p>An abstract base class which provides shared methods for Containers across the Sencha product line.</p>
19  * Please refer to sub class's documentation
20  */
21 Ext.define('Ext.container.AbstractContainer', {
22
23     /* Begin Definitions */
24
25     extend: 'Ext.Component',
26
27     requires: [
28         'Ext.util.MixedCollection',
29         'Ext.layout.container.Auto',
30         'Ext.ZIndexManager'
31     ],
32
33     /* End Definitions */
34     /**
35      * @cfg {String/Object} layout
36      * <p><b>*Important</b>: In order for child items to be correctly sized and
37      * positioned, typically a layout manager <b>must</b> be specified through
38      * the <code>layout</code> configuration option.</p>
39      * <br><p>The sizing and positioning of child {@link #items} is the responsibility of
40      * the Container's layout manager which creates and manages the type of layout
41      * you have in mind.  For example:</p>
42      * <p>If the {@link #layout} configuration is not explicitly specified for
43      * a general purpose container (e.g. Container or Panel) the
44      * {@link Ext.layout.container.Auto default layout manager} will be used
45      * which does nothing but render child components sequentially into the
46      * Container (no sizing or positioning will be performed in this situation).</p>
47      * <br><p><b><code>layout</code></b> may be specified as either as an Object or
48      * as a String:</p><div><ul class="mdetail-params">
49      *
50      * <li><u>Specify as an Object</u></li>
51      * <div><ul class="mdetail-params">
52      * <li>Example usage:</li>
53      * <pre><code>
54 layout: {
55     type: 'vbox',
56     align: 'left'
57 }
58        </code></pre>
59      *
60      * <li><code><b>type</b></code></li>
61      * <br/><p>The layout type to be used for this container.  If not specified,
62      * a default {@link Ext.layout.container.Auto} will be created and used.</p>
63      * <br/><p>Valid layout <code>type</code> values are:</p>
64      * <div class="sub-desc"><ul class="mdetail-params">
65      * <li><code><b>{@link Ext.layout.container.Auto Auto}</b></code> &nbsp;&nbsp;&nbsp; <b>Default</b></li>
66      * <li><code><b>{@link Ext.layout.container.Card card}</b></code></li>
67      * <li><code><b>{@link Ext.layout.container.Fit fit}</b></code></li>
68      * <li><code><b>{@link Ext.layout.container.HBox hbox}</b></code></li>
69      * <li><code><b>{@link Ext.layout.container.VBox vbox}</b></code></li>
70      * <li><code><b>{@link Ext.layout.container.Anchor anchor}</b></code></li>
71      * <li><code><b>{@link Ext.layout.container.Table table}</b></code></li>
72      * </ul></div>
73      *
74      * <li>Layout specific configuration properties</li>
75      * <br/><p>Additional layout specific configuration properties may also be
76      * specified. For complete details regarding the valid config options for
77      * each layout type, see the layout class corresponding to the <code>type</code>
78      * specified.</p>
79      *
80      * </ul></div>
81      *
82      * <li><u>Specify as a String</u></li>
83      * <div><ul class="mdetail-params">
84      * <li>Example usage:</li>
85      * <pre><code>
86 layout: {
87     type: 'vbox',
88     padding: '5',
89     align: 'left'
90 }
91        </code></pre>
92      * <li><code><b>layout</b></code></li>
93      * <br/><p>The layout <code>type</code> to be used for this container (see list
94      * of valid layout type values above).</p><br/>
95      * <br/><p>Additional layout specific configuration properties. For complete
96      * details regarding the valid config options for each layout type, see the
97      * layout class corresponding to the <code>layout</code> specified.</p>
98      * </ul></div></ul></div>
99      */
100
101     /**
102      * @cfg {String/Number} activeItem
103      * A string component id or the numeric index of the component that should be initially activated within the
104      * container's layout on render.  For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
105      * item in the container's collection).  activeItem only applies to layout styles that can display
106      * items one at a time (like {@link Ext.layout.container.Card} and {@link Ext.layout.container.Fit}).
107      */
108     /**
109      * @cfg {Object/Array} items
110      * <p>A single item, or an array of child Components to be added to this container</p>
111      * <p><b>Unless configured with a {@link #layout}, a Container simply renders child Components serially into
112      * its encapsulating element and performs no sizing or positioning upon them.</b><p>
113      * <p>Example:</p>
114      * <pre><code>
115 // specifying a single item
116 items: {...},
117 layout: 'fit',    // The single items is sized to fit
118
119 // specifying multiple items
120 items: [{...}, {...}],
121 layout: 'hbox', // The items are arranged horizontally
122        </code></pre>
123      * <p>Each item may be:</p>
124      * <ul>
125      * <li>A {@link Ext.Component Component}</li>
126      * <li>A Component configuration object</li>
127      * </ul>
128      * <p>If a configuration object is specified, the actual type of Component to be
129      * instantiated my be indicated by using the {@link Ext.Component#xtype xtype} option.</p>
130      * <p>Every Component class has its own {@link Ext.Component#xtype xtype}.</p>
131      * <p>If an {@link Ext.Component#xtype xtype} is not explicitly
132      * specified, the {@link #defaultType} for the Container is used, which by default is usually <code>panel</code>.</p>
133      * <p><b>Notes</b>:</p>
134      * <p>Ext uses lazy rendering. Child Components will only be rendered
135      * should it become necessary. Items are automatically laid out when they are first
136      * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.</p>
137      * <p>Do not specify <code>{@link Ext.panel.Panel#contentEl contentEl}</code> or 
138      * <code>{@link Ext.panel.Panel#html html}</code> with <code>items</code>.</p>
139      */
140     /**
141      * @cfg {Object|Function} defaults
142      * <p>This option is a means of applying default settings to all added items whether added through the {@link #items}
143      * config or via the {@link #add} or {@link #insert} methods.</p>
144      * <p>If an added item is a config object, and <b>not</b> an instantiated Component, then the default properties are
145      * unconditionally applied. If the added item <b>is</b> an instantiated Component, then the default properties are
146      * applied conditionally so as not to override existing properties in the item.</p>
147      * <p>If the defaults option is specified as a function, then the function will be called using this Container as the
148      * scope (<code>this</code> reference) and passing the added item as the first parameter. Any resulting object
149      * from that call is then applied to the item as default properties.</p>
150      * <p>For example, to automatically apply padding to the body of each of a set of
151      * contained {@link Ext.panel.Panel} items, you could pass: <code>defaults: {bodyStyle:'padding:15px'}</code>.</p>
152      * <p>Usage:</p><pre><code>
153 defaults: {               // defaults are applied to items, not the container
154     autoScroll:true
155 },
156 items: [
157     {
158         xtype: 'panel',   // defaults <b>do not</b> have precedence over
159         id: 'panel1',     // options in config objects, so the defaults
160         autoScroll: false // will not be applied here, panel1 will be autoScroll:false
161     },
162     new Ext.panel.Panel({       // defaults <b>do</b> have precedence over options
163         id: 'panel2',     // options in components, so the defaults
164         autoScroll: false // will be applied here, panel2 will be autoScroll:true.
165     })
166 ]</code></pre>
167      */
168
169     /** @cfg {Boolean} suspendLayout
170      * If true, suspend calls to doLayout.  Useful when batching multiple adds to a container and not passing them
171      * as multiple arguments or an array.
172      */
173     suspendLayout : false,
174
175     /** @cfg {Boolean} autoDestroy
176      * If true the container will automatically destroy any contained component that is removed from it, else
177      * destruction must be handled manually.
178      * Defaults to true.
179      */
180     autoDestroy : true,
181
182      /** @cfg {String} defaultType
183       * <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
184       * a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
185       * <p>Defaults to <code>'panel'</code>.</p>
186       */
187     defaultType: 'panel',
188
189     isContainer : true,
190
191     baseCls: Ext.baseCSSPrefix + 'container',
192
193     /**
194      * @cfg {Array} bubbleEvents
195      * <p>An array of events that, when fired, should be bubbled to any parent container.
196      * See {@link Ext.util.Observable#enableBubble}.
197      * Defaults to <code>['add', 'remove']</code>.
198      */
199     bubbleEvents: ['add', 'remove'],
200     
201     // @private
202     initComponent : function(){
203         var me = this;
204         me.addEvents(
205             /**
206              * @event afterlayout
207              * Fires when the components in this container are arranged by the associated layout manager.
208              * @param {Ext.container.Container} this
209              * @param {ContainerLayout} layout The ContainerLayout implementation for this container
210              */
211             'afterlayout',
212             /**
213              * @event beforeadd
214              * Fires before any {@link Ext.Component} is added or inserted into the container.
215              * A handler can return false to cancel the add.
216              * @param {Ext.container.Container} this
217              * @param {Ext.Component} component The component being added
218              * @param {Number} index The index at which the component will be added to the container's items collection
219              */
220             'beforeadd',
221             /**
222              * @event beforeremove
223              * Fires before any {@link Ext.Component} is removed from the container.  A handler can return
224              * false to cancel the remove.
225              * @param {Ext.container.Container} this
226              * @param {Ext.Component} component The component being removed
227              */
228             'beforeremove',
229             /**
230              * @event add
231              * @bubbles
232              * Fires after any {@link Ext.Component} is added or inserted into the container.
233              * @param {Ext.container.Container} this
234              * @param {Ext.Component} component The component that was added
235              * @param {Number} index The index at which the component was added to the container's items collection
236              */
237             'add',
238             /**
239              * @event remove
240              * @bubbles
241              * Fires after any {@link Ext.Component} is removed from the container.
242              * @param {Ext.container.Container} this
243              * @param {Ext.Component} component The component that was removed
244              */
245             'remove',
246             /**
247              * @event beforecardswitch
248              * Fires before this container switches the active card. This event
249              * is only available if this container uses a CardLayout. Note that
250              * TabPanel and Carousel both get a CardLayout by default, so both
251              * will have this event.
252              * A handler can return false to cancel the card switch.
253              * @param {Ext.container.Container} this
254              * @param {Ext.Component} newCard The card that will be switched to
255              * @param {Ext.Component} oldCard The card that will be switched from
256              * @param {Number} index The index of the card that will be switched to
257              * @param {Boolean} animated True if this cardswitch will be animated
258              */
259             'beforecardswitch',
260             /**
261              * @event cardswitch
262              * Fires after this container switches the active card. If the card
263              * is switched using an animation, this event will fire after the
264              * animation has finished. This event is only available if this container
265              * uses a CardLayout. Note that TabPanel and Carousel both get a CardLayout
266              * by default, so both will have this event.
267              * @param {Ext.container.Container} this
268              * @param {Ext.Component} newCard The card that has been switched to
269              * @param {Ext.Component} oldCard The card that has been switched from
270              * @param {Number} index The index of the card that has been switched to
271              * @param {Boolean} animated True if this cardswitch was animated
272              */
273             'cardswitch'
274         );
275
276         // layoutOnShow stack
277         me.layoutOnShow = Ext.create('Ext.util.MixedCollection');
278         me.callParent();
279         me.initItems();
280     },
281
282     // @private
283     initItems : function() {
284         var me = this,
285             items = me.items;
286
287         /**
288          * The MixedCollection containing all the child items of this container.
289          * @property items
290          * @type Ext.util.MixedCollection
291          */
292         me.items = Ext.create('Ext.util.MixedCollection', false, me.getComponentId);
293
294         if (items) {
295             if (!Ext.isArray(items)) {
296                 items = [items];
297             }
298
299             me.add(items);
300         }
301     },
302
303     // @private
304     afterRender : function() {
305         this.getLayout();
306         this.callParent();
307     },
308
309     // @private
310     setLayout : function(layout) {
311         var currentLayout = this.layout;
312
313         if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
314             currentLayout.setOwner(null);
315         }
316
317         this.layout = layout;
318         layout.setOwner(this);
319     },
320
321     /**
322      * Returns the {@link Ext.layout.container.AbstractContainer layout} instance currently associated with this Container.
323      * If a layout has not been instantiated yet, that is done first
324      * @return {Ext.layout.container.AbstractContainer} The layout
325      */
326     getLayout : function() {
327         var me = this;
328         if (!me.layout || !me.layout.isLayout) {
329             me.setLayout(Ext.layout.Layout.create(me.layout, 'autocontainer'));
330         }
331
332         return me.layout;
333     },
334
335     /**
336      * Manually force this container's layout to be recalculated.  The framwork uses this internally to refresh layouts
337      * form most cases.
338      * @return {Ext.container.Container} this
339      */
340     doLayout : function() {
341         var me = this,
342             layout = me.getLayout();
343
344         if (me.rendered && layout && !me.suspendLayout) {
345             // If either dimension is being auto-set, then it requires a ComponentLayout to be run.
346             if (!me.isFixedWidth() || !me.isFixedHeight()) {
347                 // Only run the ComponentLayout if it is not already in progress
348                 if (me.componentLayout.layoutBusy !== true) {
349                     me.doComponentLayout();
350                     if (me.componentLayout.layoutCancelled === true) {
351                         layout.layout();
352                     }
353                 }
354             }
355             // Both dimensions set, either by configuration, or by an owning layout, run a ContainerLayout
356             else {
357                 // Only run the ContainerLayout if it is not already in progress
358                 if (layout.layoutBusy !== true) {
359                     layout.layout();
360                 }
361             }
362         }
363
364         return me;
365     },
366
367     // @private
368     afterLayout : function(layout) {
369         this.fireEvent('afterlayout', this, layout);
370     },
371
372     // @private
373     prepareItems : function(items, applyDefaults) {
374         if (!Ext.isArray(items)) {
375             items = [items];
376         }
377
378         // Make sure defaults are applied and item is initialized
379         var i = 0,
380             len = items.length,
381             item;
382
383         for (; i < len; i++) {
384             item = items[i];
385             if (applyDefaults) {
386                 item = this.applyDefaults(item);
387             }
388             items[i] = this.lookupComponent(item);
389         }
390         return items;
391     },
392
393     // @private
394     applyDefaults : function(config) {
395         var defaults = this.defaults;
396
397         if (defaults) {
398             if (Ext.isFunction(defaults)) {
399                 defaults = defaults.call(this, config);
400             }
401
402             if (Ext.isString(config)) {
403                 config = Ext.ComponentManager.get(config);
404                 Ext.applyIf(config, defaults);
405             } else if (!config.isComponent) {
406                 Ext.applyIf(config, defaults);
407             } else {
408                 Ext.applyIf(config, defaults);
409             }
410         }
411
412         return config;
413     },
414
415     // @private
416     lookupComponent : function(comp) {
417         return Ext.isString(comp) ? Ext.ComponentManager.get(comp) : this.createComponent(comp);
418     },
419
420     // @private
421     createComponent : function(config, defaultType) {
422         // // add in ownerCt at creation time but then immediately
423         // // remove so that onBeforeAdd can handle it
424         // var component = Ext.create(Ext.apply({ownerCt: this}, config), defaultType || this.defaultType);
425         //
426         // delete component.initialConfig.ownerCt;
427         // delete component.ownerCt;
428
429         return Ext.ComponentManager.create(config, defaultType || this.defaultType);
430     },
431
432     // @private - used as the key lookup function for the items collection
433     getComponentId : function(comp) {
434         return comp.getItemId();
435     },
436
437     /**
438
439 Adds {@link Ext.Component Component}(s) to this Container.
440
441 ##Description:##
442
443 - Fires the {@link #beforeadd} event before adding.
444 - The Container's {@link #defaults default config values} will be applied
445   accordingly (see `{@link #defaults}` for details).
446 - Fires the `{@link #add}` event after the component has been added.
447
448 ##Notes:##
449
450 If the Container is __already rendered__ when `add`
451 is called, it will render the newly added Component into its content area.
452
453 __**If**__ the Container was configured with a size-managing {@link #layout} manager, the Container
454 will recalculate its internal layout at this time too.
455
456 Note that the default layout manager simply renders child Components sequentially into the content area and thereafter performs no sizing.
457
458 If adding multiple new child Components, pass them as an array to the `add` method, so that only one layout recalculation is performed.
459
460     tb = new {@link Ext.toolbar.Toolbar}({
461         renderTo: document.body
462     });  // toolbar is rendered
463     tb.add([{text:'Button 1'}, {text:'Button 2'}]); // add multiple items. ({@link #defaultType} for {@link Ext.toolbar.Toolbar Toolbar} is 'button')
464
465 ##Warning:## 
466
467 Components directly managed by the BorderLayout layout manager
468 may not be removed or added.  See the Notes for {@link Ext.layout.container.Border BorderLayout}
469 for more details.
470
471      * @param {...Object/Array} Component
472      * Either one or more Components to add or an Array of Components to add.
473      * See `{@link #items}` for additional information.
474      *
475      * @return {Ext.Component/Array} The Components that were added.
476      * @markdown
477      */
478     add : function() {
479         var me = this,
480             args = Array.prototype.slice.call(arguments),
481             hasMultipleArgs,
482             items,
483             results = [],
484             i,
485             ln,
486             item,
487             index = -1,
488             cmp;
489
490         if (typeof args[0] == 'number') {
491             index = args.shift();
492         }
493
494         hasMultipleArgs = args.length > 1;
495         if (hasMultipleArgs || Ext.isArray(args[0])) {
496
497             items = hasMultipleArgs ? args : args[0];
498             // Suspend Layouts while we add multiple items to the container
499             me.suspendLayout = true;
500             for (i = 0, ln = items.length; i < ln; i++) {
501                 item = items[i];
502                 
503                 //<debug>
504                 if (!item) {
505                     Ext.Error.raise("Trying to add a null item as a child of Container with itemId/id: " + me.getItemId());
506                 }
507                 //</debug>
508                 
509                 if (index != -1) {
510                     item = me.add(index + i, item);
511                 } else {
512                     item = me.add(item);
513                 }
514                 results.push(item);
515             }
516             // Resume Layouts now that all items have been added and do a single layout for all the items just added
517             me.suspendLayout = false;
518             me.doLayout();
519             return results;
520         }
521
522         cmp = me.prepareItems(args[0], true)[0];
523
524         // Floating Components are not added into the items collection
525         // But they do get an upward ownerCt link so that they can traverse
526         // up to their z-index parent.
527         if (cmp.floating) {
528             cmp.onAdded(me, index);
529         } else {
530             index = (index !== -1) ? index : me.items.length;
531             if (me.fireEvent('beforeadd', me, cmp, index) !== false && me.onBeforeAdd(cmp) !== false) {
532                 me.items.insert(index, cmp);
533                 cmp.onAdded(me, index);
534                 me.onAdd(cmp, index);
535                 me.fireEvent('add', me, cmp, index);
536             }
537             me.doLayout();
538         }
539         return cmp;
540     },
541
542     /**
543      * @private
544      * <p>Called by Component#doAutoRender</p>
545      * <p>Register a Container configured <code>floating: true</code> with this Container's {@link Ext.ZIndexManager ZIndexManager}.</p>
546      * <p>Components added in ths way will not participate in the layout, but will be rendered
547      * upon first show in the way that {@link Ext.window.Window Window}s are.</p>
548      * <p></p>
549      */
550     registerFloatingItem: function(cmp) {
551         var me = this;
552         if (!me.floatingItems) {
553             me.floatingItems = Ext.create('Ext.ZIndexManager', me);
554         }
555         me.floatingItems.register(cmp);
556     },
557
558     onAdd : Ext.emptyFn,
559     onRemove : Ext.emptyFn,
560
561     /**
562      * Inserts a Component into this Container at a specified index. Fires the
563      * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
564      * Component has been inserted.
565      * @param {Number} index The index at which the Component will be inserted
566      * into the Container's items collection
567      * @param {Ext.Component} component The child Component to insert.<br><br>
568      * Ext uses lazy rendering, and will only render the inserted Component should
569      * it become necessary.<br><br>
570      * A Component config object may be passed in order to avoid the overhead of
571      * constructing a real Component object if lazy rendering might mean that the
572      * inserted Component will not be rendered immediately. To take advantage of
573      * this 'lazy instantiation', set the {@link Ext.Component#xtype} config
574      * property to the registered type of the Component wanted.<br><br>
575      * For a list of all available xtypes, see {@link Ext.Component}.
576      * @return {Ext.Component} component The Component (or config object) that was
577      * inserted with the Container's default config values applied.
578      */
579     insert : function(index, comp) {
580         return this.add(index, comp);
581     },
582
583     /**
584      * Moves a Component within the Container
585      * @param {Number} fromIdx The index the Component you wish to move is currently at.
586      * @param {Number} toIdx The new index for the Component.
587      * @return {Ext.Component} component The Component (or config object) that was moved.
588      */
589     move : function(fromIdx, toIdx) {
590         var items = this.items,
591             item;
592         item = items.removeAt(fromIdx);
593         if (item === false) {
594             return false;
595         }
596         items.insert(toIdx, item);
597         this.doLayout();
598         return item;
599     },
600
601     // @private
602     onBeforeAdd : function(item) {
603         var me = this;
604         
605         if (item.ownerCt) {
606             item.ownerCt.remove(item, false);
607         }
608
609         if (me.border === false || me.border === 0) {
610             item.border = (item.border === true);
611         }
612     },
613
614     /**
615      * Removes a component from this container.  Fires the {@link #beforeremove} event before removing, then fires
616      * the {@link #remove} event after the component has been removed.
617      * @param {Component/String} component The component reference or id to remove.
618      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
619      * Defaults to the value of this Container's {@link #autoDestroy} config.
620      * @return {Ext.Component} component The Component that was removed.
621      */
622     remove : function(comp, autoDestroy) {
623         var me = this,
624             c = me.getComponent(comp);
625         //<debug>
626             if (Ext.isDefined(Ext.global.console) && !c) {
627                 console.warn("Attempted to remove a component that does not exist. Ext.container.Container: remove takes an argument of the component to remove. cmp.remove() is incorrect usage.");
628             }
629         //</debug>
630
631         if (c && me.fireEvent('beforeremove', me, c) !== false) {
632             me.doRemove(c, autoDestroy);
633             me.fireEvent('remove', me, c);
634         }
635
636         return c;
637     },
638
639     // @private
640     doRemove : function(component, autoDestroy) {
641         var me = this,
642             layout = me.layout,
643             hasLayout = layout && me.rendered;
644
645         me.items.remove(component);
646         component.onRemoved();
647
648         if (hasLayout) {
649             layout.onRemove(component);
650         }
651
652         me.onRemove(component, autoDestroy);
653
654         if (autoDestroy === true || (autoDestroy !== false && me.autoDestroy)) {
655             component.destroy();
656         }
657
658         if (hasLayout && !autoDestroy) {
659             layout.afterRemove(component);
660         }
661
662         if (!me.destroying) {
663             me.doLayout();
664         }
665     },
666
667     /**
668      * Removes all components from this container.
669      * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
670      * Defaults to the value of this Container's {@link #autoDestroy} config.
671      * @return {Array} Array of the destroyed components
672      */
673     removeAll : function(autoDestroy) {
674         var me = this,
675             removeItems = me.items.items.slice(),
676             items = [],
677             i = 0,
678             len = removeItems.length,
679             item;
680
681         // Suspend Layouts while we remove multiple items from the container
682         me.suspendLayout = true;
683         for (; i < len; i++) {
684             item = removeItems[i];
685             me.remove(item, autoDestroy);
686
687             if (item.ownerCt !== me) {
688                 items.push(item);
689             }
690         }
691
692         // Resume Layouts now that all items have been removed and do a single layout (if we removed anything!)
693         me.suspendLayout = false;
694         if (len) {
695             me.doLayout();
696         }
697         return items;
698     },
699
700     // Used by ComponentQuery to retrieve all of the items
701     // which can potentially be considered a child of this Container.
702     // This should be overriden by components which have child items
703     // that are not contained in items. For example dockedItems, menu, etc
704     // IMPORTANT note for maintainers:
705     //  Items are returned in tree traversal order. Each item is appended to the result array
706     //  followed by the results of that child's getRefItems call.
707     //  Floating child items are appended after internal child items.
708     getRefItems : function(deep) {
709         var me = this,
710             items = me.items.items,
711             len = items.length,
712             i = 0,
713             item,
714             result = [];
715
716         for (; i < len; i++) {
717             item = items[i];
718             result.push(item);
719             if (deep && item.getRefItems) {
720                 result.push.apply(result, item.getRefItems(true));
721             }
722         }
723
724         // Append floating items to the list.
725         // These will only be present after they are rendered.
726         if (me.floatingItems && me.floatingItems.accessList) {
727             result.push.apply(result, me.floatingItems.accessList);
728         }
729
730         return result;
731     },
732
733     /**
734      * Cascades down the component/container heirarchy from this component (passed in the first call), calling the specified function with
735      * each component. The scope (<code>this</code> reference) of the
736      * function call will be the scope provided or the current component. The arguments to the function
737      * will be the args provided or the current component. If the function returns false at any point,
738      * the cascade is stopped on that branch.
739      * @param {Function} fn The function to call
740      * @param {Object} scope (optional) The scope of the function (defaults to current component)
741      * @param {Array} args (optional) The args to call the function with. The current component always passed as the last argument.
742      * @return {Ext.Container} this
743      */
744     cascade : function(fn, scope, origArgs){
745         var me = this,
746             cs = me.items ? me.items.items : [],
747             len = cs.length,
748             i = 0,
749             c,
750             args = origArgs ? origArgs.concat(me) : [me],
751             componentIndex = args.length - 1;
752
753         if (fn.apply(scope || me, args) !== false) {
754             for(; i < len; i++){
755                 c = cs[i];
756                 if (c.cascade) {
757                     c.cascade(fn, scope, origArgs);
758                 } else {
759                     args[componentIndex] = c;
760                     fn.apply(scope || cs, args);
761                 }
762             }
763         }
764         return this;
765     },
766
767     /**
768      * Examines this container's <code>{@link #items}</code> <b>property</b>
769      * and gets a direct child component of this container.
770      * @param {String/Number} comp This parameter may be any of the following:
771      * <div><ul class="mdetail-params">
772      * <li>a <b><code>String</code></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
773      * or <code>{@link Ext.Component#id id}</code> of the child component </li>
774      * <li>a <b><code>Number</code></b> : representing the position of the child component
775      * within the <code>{@link #items}</code> <b>property</b></li>
776      * </ul></div>
777      * <p>For additional information see {@link Ext.util.MixedCollection#get}.
778      * @return Ext.Component The component (if found).
779      */
780     getComponent : function(comp) {
781         if (Ext.isObject(comp)) {
782             comp = comp.getItemId();
783         }
784
785         return this.items.get(comp);
786     },
787
788     /**
789      * Retrieves all descendant components which match the passed selector.
790      * Executes an Ext.ComponentQuery.query using this container as its root.
791      * @param {String} selector Selector complying to an Ext.ComponentQuery selector
792      * @return {Array} Ext.Component's which matched the selector
793      */
794     query : function(selector) {
795         return Ext.ComponentQuery.query(selector, this);
796     },
797
798     /**
799      * Retrieves the first direct child of this container which matches the passed selector.
800      * The passed in selector must comply with an Ext.ComponentQuery selector.
801      * @param {String} selector An Ext.ComponentQuery selector
802      * @return Ext.Component
803      */
804     child : function(selector) {
805         return this.query('> ' + selector)[0] || null;
806     },
807
808     /**
809      * Retrieves the first descendant of this container which matches the passed selector.
810      * The passed in selector must comply with an Ext.ComponentQuery selector.
811      * @param {String} selector An Ext.ComponentQuery selector
812      * @return Ext.Component
813      */
814     down : function(selector) {
815         return this.query(selector)[0] || null;
816     },
817
818     // inherit docs
819     show : function() {
820         this.callParent(arguments);
821         this.performDeferredLayouts();
822         return this;
823     },
824
825     // Lay out any descendant containers who queued a layout operation during the time this was hidden
826     // This is also called by Panel after it expands because descendants of a collapsed Panel allso queue any layout ops.
827     performDeferredLayouts: function() {
828         var layoutCollection = this.layoutOnShow,
829             ln = layoutCollection.getCount(),
830             i = 0,
831             needsLayout,
832             item;
833
834         for (; i < ln; i++) {
835             item = layoutCollection.get(i);
836             needsLayout = item.needsLayout;
837
838             if (Ext.isObject(needsLayout)) {
839                 item.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt);
840             }
841         }
842         layoutCollection.clear();
843     },    
844     
845     //@private
846     // Enable all immediate children that was previously disabled
847     onEnable: function() {
848         Ext.Array.each(this.query('[isFormField]'), function(item) {
849             if (item.resetDisable) {
850                 item.enable();
851                 delete item.resetDisable;             
852             }
853         });
854         this.callParent();
855     },
856     
857     // @private
858     // Disable all immediate children that was previously disabled
859     onDisable: function() {
860         Ext.Array.each(this.query('[isFormField]'), function(item) {
861             if (item.resetDisable !== false && !item.disabled) {
862                 item.disable();
863                 item.resetDisable = true;
864             }
865         });
866         this.callParent();
867     },
868
869     /**
870      * Occurs before componentLayout is run. Returning false from this method will prevent the containerLayout
871      * from being executed.
872      */
873     beforeLayout: function() {
874         return true;
875     },
876
877     // @private
878     beforeDestroy : function() {
879         var me = this,
880             items = me.items,
881             c;
882
883         if (items) {
884             while ((c = items.first())) {
885                 me.doRemove(c, true);
886             }
887         }
888
889         Ext.destroy(
890             me.layout,
891             me.floatingItems
892         );
893         me.callParent();
894     }
895 });