1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2003-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.containers
13{
14
15import flash.display.DisplayObject;
16import flash.events.Event;
17import flash.events.FocusEvent;
18import flash.events.KeyboardEvent;
19import mx.controls.Button;
20import mx.controls.TabBar;
21import mx.core.Container;
22import mx.core.EdgeMetrics;
23import mx.core.FlexVersion;
24import mx.core.IFlexDisplayObject;
25import mx.core.IInvalidating;
26import mx.core.IProgrammaticSkin;
27import mx.core.IUIComponent;
28import mx.core.mx_internal;
29import mx.events.ItemClickEvent;
30import mx.managers.IFocusManagerComponent;
31import mx.styles.StyleProxy;
32
33use namespace mx_internal;
34
35//--------------------------------------
36//  Styles
37//--------------------------------------
38
39// The fill related styles are applied to the children
40// of the TabNavigator, ie: the TabBar
41include "../styles/metadata/FillStyles.as"
42
43// The focus styles are applied to the TabNavigator itself.
44include "../styles/metadata/FocusStyles.as"
45
46/**
47 *  Name of CSS style declaration that specifies styles for the first tab.
48 *  If this is unspecified, the default value
49 *  of the <code>tabStyleName</code> style property is used.
50 */
51[Style(name="firstTabStyleName", type="String", inherit="no")]
52
53/**
54 *  Horizontal positioning of tabs at the top of this TabNavigator container.
55 *  The possible values are <code>"left"</code>, <code>"center"</code>,
56 *  and <code>"right"</code>.
57 *  The default value is <code>"left"</code>.
58 *
59 *  <p>If the value is <code>"left"</code>, the left edge of the first tab
60 *  is aligned with the left edge of the TabNavigator container.
61 *  If the value is <code>"right"</code>, the right edge of the last tab
62 *  is aligned with the right edge of the TabNavigator container.
63 *  If the value is <code>"center"</code>, the tabs are centered on the top
64 *  of the TabNavigator container.</p>
65 *
66 *  <p>To see a difference between the alignments,
67 *  the total width of all the tabs must be less than
68 *  the width of the TabNavigator container.</p>
69 */
70[Style(name="horizontalAlign", type="String", enumeration="left,center,right", inherit="no")]
71
72/**
73 *  Separation between tabs, in pixels.
74 *  The default value is -1, so that the borders of adjacent tabs overlap.
75 */
76[Style(name="horizontalGap", type="Number", format="Length", inherit="no")]
77
78/**
79 *  Name of CSS style declaration that specifies styles for the last tab.
80 *  If this is unspecified, the default value
81 *  of the <code>tabStyleName</code> style property is used.
82 */
83[Style(name="lastTabStyleName", type="String", inherit="no")]
84
85/**
86 *  Name of CSS style declaration that specifies styles for the text
87 *  of the selected tab.
88 */
89[Style(name="selectedTabTextStyleName", type="String", inherit="no")]
90
91/**
92 *  Height of each tab, in pixels.
93 *  The default value is <code>undefined</code>.
94 *  When this property is <code>undefined</code>, the height of each tab is
95 *  determined by the font styles applied to this TabNavigator container.
96 *  If you set this property, the specified value overrides this calculation.
97 */
98[Style(name="tabHeight", type="Number", format="Length", inherit="no")]
99
100/**
101 *  Name of CSS style declaration that specifies styles for the tabs.
102 *
103 *  @default undefined
104 */
105[Style(name="tabStyleName", type="String", inherit="no")]
106
107/**
108 *  Width of each tab, in pixels.
109 *  The default value is <code>undefined</code>.
110 *  When this property is <code>undefined</code>, the width of each tab is
111 *  determined by the width of its label text, using the font styles applied
112 *  to this TabNavigator container.
113 *  If the total width of the tabs would be greater than the width of the
114 *  TabNavigator container, the calculated tab width is decreased, but
115 *  only to a minimum of 30 pixels.
116 *  If you set this property, the specified value overrides this calculation.
117 *
118 *  <p>The label text on a tab is truncated if it does not fit in the tab.
119 *  If a tab label is truncated, a tooltip with the full label text is
120 *  displayed when a user rolls the mouse over the tab.</p>
121 */
122[Style(name="tabWidth", type="Number", format="Length", inherit="no")]
123
124/**
125 *  The horizontal offset, in pixels, of the tab bar from the left edge
126 *  of the TabNavigator container.
127 *  A positive value moves the tab bar to the right. A negative
128 *  value move the tab bar to the left.
129 *
130 *  @default 0
131 */
132[Style(name="tabOffset", type="Number", format="Length", inherit="no")]
133
134//--------------------------------------
135//  Excluded APIs
136//--------------------------------------
137
138[Exclude(name="defaultButton", kind="property")]
139[Exclude(name="horizontalLineScrollSize", kind="property")]
140[Exclude(name="horizontalPageScrollSize", kind="property")]
141[Exclude(name="horizontalScrollBar", kind="property")]
142[Exclude(name="horizontalScrollPolicy", kind="property")]
143[Exclude(name="horizontalScrollPosition", kind="property")]
144[Exclude(name="maxHorizontalScrollPosition", kind="property")]
145[Exclude(name="maxVerticalScrollPosition", kind="property")]
146[Exclude(name="verticalLineScrollSize", kind="property")]
147[Exclude(name="verticalPageScrollSize", kind="property")]
148[Exclude(name="verticalScrollBar", kind="property")]
149[Exclude(name="verticalScrollPolicy", kind="property")]
150[Exclude(name="verticalScrollPosition", kind="property")]
151
152[Exclude(name="scroll", kind="event")]
153
154[Exclude(name="fillAlphas", kind="style")]
155[Exclude(name="fillColors", kind="style")]
156[Exclude(name="horizontalScrollBarStyleName", kind="style")]
157[Exclude(name="verticalScrollBarStyleName", kind="style")]
158
159//--------------------------------------
160//  Other metadata
161//--------------------------------------
162
163[IconFile("TabNavigator.png")]
164
165/**
166 *  The TabNavigator container extends the ViewStack container by including
167 *  a TabBar container for navigating between its child containers.
168 *
169 *  <p>Like a ViewStack container, a TabNavigator container has a collection
170 *  of child containers, in which only one child at a time is visible.
171 *  Flex automatically creates a TabBar container at the top of the
172 *  TabNavigator container, with a tab corresponding to each child container.
173 *  Each tab can have its own label and icon.
174 *  When the user clicks a tab, the corresponding child container becomes
175 *  visible as the selected child of the TabNavigator container.</p>
176 *
177 *  <p>When you change the currently visible child container,
178 *  you can use the <code>hideEffect</code> property of the container being
179 *  hidden and the <code>showEffect</code> property of the newly visible child
180 *  container to apply an effect to the child containers.
181 *  The TabNavigator container waits for the <code>hideEffect</code> of the
182 *  child container being hidden to complete before it reveals the new child
183 *  container.
184 *  You can interrupt a currently playing effect if you change the
185 *  <code>selectedIndex</code> property of the TabNavigator container
186 *  while an effect is playing. </p>
187 *
188 *  <p>To define the appearance of tabs in a TabNavigator, you can define style properties in a
189 *  Tab type selector, as the following example shows:</p>
190 *  <pre>
191 *  &lt;mx:Style&gt;
192 *    Tab {
193 *       fillColors: #006699, #cccc66;
194 *       upSkin: ClassReference("CustomSkinClass");
195 *       overSkin: ClassReference("CustomSkinClass");
196 *       downSkin: ClassReference("CustomSkinClass");
197 *    }
198 *  &lt;/mx:Style&gt;
199 *  </pre>
200 *
201 *  <p>The Tab type selector defines values on the hidden mx.controls.tabBarClasses.Tab
202 *  class. The default values for the Tab type selector are defined in the
203 *  defaults.css file.</p>
204 *
205 *  <p>You can also define the styles in a class selector that you specify using
206 *  the <code>tabStyleName</code> style property; for example:</p>
207 *  <pre>
208 *  &lt;mx:Style&gt;
209 *    TabNavigator {
210 *       tabStyleName:myTabStyle;
211 *    }
212 *
213 *    .myTabStyle {
214 *       fillColors: #006699, #cccc66;
215 *       upSkin: ClassReference("CustomSkinClass");
216 *       overSkin: ClassReference("CustomSkinClass");
217 *       downSkin: ClassReference("CustomSkinClass");
218 *    }
219 *  &lt;/mx:Style&gt;
220 *  </pre>
221 *
222 *  <p>A TabNavigator container has the following default sizing characteristics:</p>
223 *     <table class="innertable">
224 *        <tr>
225 *           <th>Characteristic</th>
226 *           <th>Description</th>
227 *        </tr>
228 *        <tr>
229 *           <td>Default size</td>
230 *           <td>The default or explicit width and height of the first active child
231 *               plus the tabs, at their default or explicit heights and widths.
232 *               Default tab height is determined by the font, style, and skin applied
233 *               to the TabNavigator container.</td>
234 *        </tr>
235 *        <tr>
236 *           <td>Container resizing rules</td>
237 *           <td>By default, TabNavigator containers are only sized once to fit the size
238 *               of the first child container. They do not resize when you navigate to
239 *               other child containers. To force TabNavigator containers to resize when
240 *               you navigate to a different child container, set the resizeToContent
241 *               property to true.</td>
242 *        </tr>
243 *        <tr>
244 *           <td>Child layout rules</td>
245 *           <td>If the child is larger than the TabNavigator container, it is clipped. If
246 *               the child is smaller than the TabNavigator container, it is aligned to
247 *               the upper-left corner of the TabNavigator container.</td>
248 *        </tr>
249 *        <tr>
250 *           <td>Default padding</td>
251 *           <td>0 pixels for the top, bottom, left, and right values.</td>
252 *        </tr>
253 *     </table>
254 *
255 *  @mxml
256 *
257 *  <p>The <code>&lt;mx:TabNavigator&gt;</code> tag inherits all of the
258 *  tag attributes of its superclass,
259 *  and adds the following tag attributes:</p>
260 *
261 *  <pre>
262 *  &lt;mx:TabNavigator
263 *    <b>Styles</b>
264 *    fillAlphas="[0.60, 0.40, 0.75, 0.65]"
265 *    fillColors="[0xFFFFFF, 0xCCCCCC, 0xFFFFFF, 0xEEEEEE]"
266 *    firstTabStyleName="<i>Value of the</i> <code>tabStyleName</code> <i>property</i>"
267 *    focusAlpha="0.4"
268 *    focusRoundedCorners="tl tr bl br"
269 *    horizontalAlign="left|center|right"
270 *    horizontalGap="-1"
271 *    lastTabStyleName="<i>Value of the</i> <code>tabStyleName</code> <i>property</i>"
272 *    selectedTabTextStyleName="undefined"
273 *    tabHeight="undefined"
274 *    tabOffset="0"
275 *    tabStyleName="<i>Name of CSS style declaration that specifies styles for the tabs</i>"
276 *    tabWidth="undefined"
277 *    &gt;
278 *      ...
279 *      <i>child tags</i>
280 *      ...
281 *  &lt;/mx:TabNavigator&gt;
282 *  </pre>
283 *
284 *  @includeExample examples/TabNavigatorExample.mxml
285 *
286 *  @see mx.containers.ViewStack
287 *  @see mx.controls.TabBar
288 */
289public class TabNavigator extends ViewStack implements IFocusManagerComponent
290{
291    include "../core/Version.as";
292
293    //--------------------------------------------------------------------------
294    //
295    //  Class constants
296    //
297    //--------------------------------------------------------------------------
298
299    /**
300     *  @private
301     */
302    private static const MIN_TAB_WIDTH:Number = 30;
303
304    //--------------------------------------------------------------------------
305    //
306    //  Constructor
307    //
308    //--------------------------------------------------------------------------
309
310    /**
311     *  Constructor.
312     */
313    public function TabNavigator()
314    {
315        super();
316
317        // Most views can't take focus, but a TabNavigator can.
318        // Container.init() has set tabEnabled false, so we
319        // have to set it back to true.
320        tabEnabled = true;
321
322        historyManagementEnabled = true;
323    }
324
325    //--------------------------------------------------------------------------
326    //
327    //  Overridden properties
328    //
329    //--------------------------------------------------------------------------
330
331    //----------------------------------
332    //  baselinePosition
333    //----------------------------------
334
335    /**
336     *  @private
337     *  The baselinePosition of a TabNavigator is calculated
338	 *  for the label of the first tab.
339  	 *  If there are no children, a child is temporarily added
340  	 *  to do the computation.
341     */
342    override public function get baselinePosition():Number
343    {
344    	if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0)
345    		return super.baselinePosition;
346
347		if (!validateBaselinePosition())
348			return NaN;
349
350	    var isEmpty:Boolean = numChildren == 0;
351	    if (isEmpty)
352	    {
353	    	var child0:Container = new Container();
354	    	addChild(child0);
355	    	validateNow();
356	    }
357
358	    var tab0:Button = getTabAt(0);
359	    var result:Number = tabBar.y + tab0.y + tab0.baselinePosition;
360
361	    if (isEmpty)
362	    {
363	   		removeChildAt(0);
364	   		validateNow();
365	    }
366
367	    return result;
368    }
369
370    //----------------------------------
371    //  contentHeight
372    //----------------------------------
373
374    /**
375     *  @private
376     */
377    override protected function get contentHeight():Number
378    {
379        var vm:EdgeMetrics = viewMetricsAndPadding;
380
381        var vmTop:Number = vm.top;
382        var vmBottom:Number = vm.bottom;
383
384        if (isNaN(vmTop))
385            vmTop = 0;
386        if (isNaN(vmBottom))
387            vmBottom = 0;
388
389        return unscaledHeight - tabBarHeight - vmTop - vmBottom;
390    }
391
392    //----------------------------------
393    //  contentY
394    //----------------------------------
395
396    /**
397     *  @private
398     */
399    override protected function get contentY():Number
400    {
401        var paddingTop:Number = getStyle("paddingTop");
402
403        if (isNaN(paddingTop))
404            paddingTop = 0;
405
406        return tabBarHeight + paddingTop;
407    }
408
409    //--------------------------------------------------------------------------
410    //
411    //  Properties
412    //
413    //--------------------------------------------------------------------------
414
415    //----------------------------------
416    //  tabBarHeight
417    //----------------------------------
418
419    /**
420     *  A reference to the TabBar inside this TabNavigator.
421     */
422    protected var tabBar:TabBar;
423
424    //----------------------------------
425    //  tabBarHeight
426    //----------------------------------
427
428    /**
429     *  @private
430     *  Height of the tab.
431     */
432    private function get tabBarHeight():Number
433    {
434        var tabHeight:Number = getStyle("tabHeight");
435
436        if (isNaN(tabHeight))
437            tabHeight = tabBar.getExplicitOrMeasuredHeight();
438
439        return tabHeight - borderMetrics.top;
440    }
441
442	//----------------------------------
443    //  tabBarStyleFilters
444    //----------------------------------
445
446    /**
447     *  The set of styles to pass from the TabNavigator to the tabBar.
448     *  @see mx.styles.StyleProxy
449     *  @review
450     */
451    protected function get tabBarStyleFilters():Object
452    {
453    	return _tabBarStyleFilters;
454    }
455
456    private static var _tabBarStyleFilters:Object =
457    {
458    	"firstTabStyleName" : "firstTabStyleName",
459    	"horizontalAlign" : "horizontalAlign",
460    	"horizontalGap" : "horizontalGap",
461    	"lastTabStyleName" : "lastTabStyleName",
462    	"selectedTabTextStyleName" : "selectedTabTextStyleName",
463    	"tabStyleName" : "tabStyleName",
464    	"tabWidth" : "tabWidth",
465    	"verticalAlign" : "verticalAlign",
466    	"verticalGap" : "verticalGap"
467    };
468
469    //--------------------------------------------------------------------------
470    //
471    //  Overridden methods: UIComponent
472    //
473    //--------------------------------------------------------------------------
474
475    /**
476     *  @private
477     */
478    override protected function createChildren():void
479    {
480        super.createChildren();
481
482        if (!tabBar)
483        {
484            tabBar = new TabBar();
485            tabBar.name = "tabBar";
486            tabBar.focusEnabled = false;
487            tabBar.styleName = new StyleProxy(this, tabBarStyleFilters);
488            rawChildren.addChild(tabBar);
489
490            if (FlexVersion.compatibilityVersion < FlexVersion.VERSION_3_0)
491            {
492            	tabBar.setStyle("paddingTop", 0);
493            	tabBar.setStyle("paddingBottom", 0);
494				tabBar.setStyle("borderStyle", "none");
495            }
496        }
497    }
498
499    /**
500     *  @private
501     */
502    override protected function commitProperties():void
503    {
504        super.commitProperties();
505
506        // Things get a bit tricky here... we need to
507        // wait until our children have been instantiated
508        // before we can attach the tab bar to us.
509        if (tabBar && tabBar.dataProvider != this &&
510            numChildren > 0 && getChildAt(0))
511        {
512            tabBar.dataProvider = this;
513        }
514    }
515
516    /**
517     *  Calculates the default sizes and mininum and maximum values of this
518     *  TabNavigator container.
519     *  See the <code>UIComponent.measure()</code> method for more information
520     *  about the <code>measure()</code> method.
521     *
522     *  <p>The TabNavigator container uses the same measurement logic as the
523     *  <code>ViewStack</code> container, with two modifications:
524     *  First, it increases the value of the
525     *  <code>measuredHeight</code> and
526     *  <code>measuredMinHeight</code> properties to accomodate the tabs.
527     *  Second, it increases the value of the
528     *  <code>measuredWidth</code> property if necessary
529     *  to ensure that each tab can be at least 30 pixels wide.</p>
530     *
531     *  @see mx.core.UIComponent#measure()
532     *  @see mx.containers.ViewStack#measure()
533     */
534    override protected function measure():void
535    {
536        // Only measure once. Thereafter, we'll just use cached values.
537        // We need to copy the cached values into the measured fields
538        // again to handle the case where scaleX or scaleY is not 1.0.
539        // When the TabNavigator is zoomed, code in UIComponent.measureSizes
540        // scales the measuredWidth/Height values every time that
541        // measureSizes is called.  (bug 100749)
542
543        // This must be done before the call to super.measure(), otherwise
544        // we don't get the first measurement correct.
545        if (vsPreferredWidth && !resizeToContent)
546        {
547            measuredMinWidth = vsMinWidth;
548            measuredMinHeight = vsMinHeight;
549            measuredWidth = vsPreferredWidth;
550            measuredHeight = vsPreferredHeight;
551            return;
552        }
553
554        super.measure();
555
556        var addedHeight:Number = tabBarHeight;
557        measuredMinHeight += addedHeight;
558        measuredHeight += addedHeight;
559
560        // Make sure there is at least enough room
561        // to draw all tabs at their minimum size.
562        var tabWidth:Number = getStyle("tabWidth");
563        if (isNaN(tabWidth))
564            tabWidth = 0;
565
566        var minTabBarWidth:Number =
567            numChildren * Math.max(tabWidth, MIN_TAB_WIDTH);
568
569        // Add view metrics.
570        var vm:EdgeMetrics = viewMetrics;
571        minTabBarWidth += (vm.left + vm.right);
572
573        // Add horizontal gaps.
574        if (numChildren > 1)
575            minTabBarWidth += (getStyle("horizontalGap") * (numChildren - 1));
576
577        if (measuredWidth < minTabBarWidth)
578            measuredWidth = minTabBarWidth;
579
580        // If we're called before instantiateSelectedChild, then bail.
581        // We'll be called again later (instantiateSelectedChild calls
582        // invalidateSize), and we don't want to load values into the
583        // cache until we're fully initialized.  (bug 102639)
584        if (selectedChild && Container(selectedChild).numChildrenCreated == -1)
585            return;
586
587        // Don't remember sizes if we don't have any children
588        if (numChildren == 0)
589            return;
590
591        vsMinWidth = measuredMinWidth;
592        vsMinHeight = measuredMinHeight;
593        vsPreferredWidth = measuredWidth;
594        vsPreferredHeight = measuredHeight;
595    }
596
597    /**
598     *  Responds to size changes by setting the positions and sizes
599     *  of this container's tabs and children.
600     *
601     *  For more information about the <code>updateDisplayList()</code> method,
602     *  see the <code>UIComponent.updateDisplayList()</code> method.
603     *
604     *  <p>A TabNavigator container positions its TabBar container at the top.
605     *  The width of the TabBar is set to the width of the
606     *  TabNavigator, and the height of the TabBar is set
607     *  based on the <code>tabHeight</code> property.</p>
608     *
609     *  <p>A TabNavigator container positions and sizes its child containers
610     *  underneath the TabBar, using the same logic as in
611     *  ViewStack container.</p>
612     *
613     *  @param unscaledWidth Specifies the width of the component, in pixels,
614     *  in the component's coordinates, regardless of the value of the
615     *  <code>scaleX</code> property of the component.
616     *
617     *  @param unscaledHeight Specifies the height of the component, in pixels,
618     *  in the component's coordinates, regardless of the value of the
619     *  <code>scaleY</code> property of the component.
620     *
621     *  @see mx.core.UIComponent#updateDisplayList()
622     */
623    override protected function updateDisplayList(unscaledWidth:Number,
624                                                  unscaledHeight:Number):void
625    {
626        super.updateDisplayList(unscaledWidth, unscaledHeight);
627
628        var bm:EdgeMetrics = borderMetrics;
629        var vm:EdgeMetrics = viewMetrics;
630        var w:Number = unscaledWidth - vm.left - vm.right;
631
632        var th:Number = tabBarHeight + bm.top;
633        var pw:Number = tabBar.getExplicitOrMeasuredWidth();
634        tabBar.setActualSize(Math.min(w, pw), th);
635        var leftOffset:Number = getStyle("tabOffset");
636
637        switch (getStyle("horizontalAlign"))
638        {
639        case "left":
640            tabBar.move(0 + leftOffset, tabBar.y);
641            break;
642        case "right":
643            tabBar.move(unscaledWidth - tabBar.width + leftOffset, tabBar.y);
644            break;
645        case "center":
646            tabBar.move((unscaledWidth - tabBar.width) / 2 + leftOffset, tabBar.y);
647        }
648    }
649
650    /**
651     *  @private
652     */
653    override public function drawFocus(isFocused:Boolean):void
654    {
655        // Superclass sets up standard focus glow.
656        super.drawFocus(isFocused);
657
658        if (!parent)
659            return;
660
661        // Clip the glow so it doesn't include the tabs
662        var focusObj:DisplayObject = IUIComponent(parent).focusPane;
663        if (isFocused && !isEffectStarted)
664        {
665            // Normally the focus skin is in front of the object. For TabNavigator
666            // we want it behind.
667            if (focusObj)
668            {
669                if (parent is Container)
670                {
671                    var n:int = Container(parent).rawChildren.numChildren;
672                    var fci:int = Container(parent).firstChildIndex;
673                    // make sure we don't set it past the last index.  This happens
674                    // if all content children are in a contentpane
675                    Container(parent).rawChildren.setChildIndex(
676                        focusObj, Math.max(0, (fci == n) ? n - 1 : fci));
677                }
678                else
679                {
680                    parent.setChildIndex(focusObj, 0);
681                }
682            }
683        }
684        else
685        {
686            if (focusObj)
687            {
688                // Move the focus skin back in front of the children, where it
689                // was before we drew focus.
690                if (parent is Container)
691                {
692                    Container(parent).rawChildren.setChildIndex(
693                            focusObj, Container(parent).rawChildren.numChildren - 1);
694                }
695                else
696                {
697                    parent.setChildIndex(focusObj, parent.numChildren - 1);
698                }
699            }
700        }
701
702        tabBar.drawFocus(isFocused);
703    }
704
705    /**
706     *  @private
707     */
708    override protected function adjustFocusRect(
709                                    object:DisplayObject = null):void
710    {
711        // Superclass does most of the work
712        super.adjustFocusRect(object);
713
714        // Adjust the focus rect so it is below the tabs
715        var focusObj:IFlexDisplayObject = IFlexDisplayObject(getFocusObject());
716
717        if (focusObj)
718        {
719            focusObj.setActualSize(focusObj.width, focusObj.height - tabBarHeight);
720            focusObj.move(focusObj.x, focusObj.y + tabBarHeight);
721
722            if (focusObj is IInvalidating)
723                IInvalidating(focusObj).validateNow();
724
725            else if (focusObj is IProgrammaticSkin)
726                IProgrammaticSkin(focusObj).validateNow();
727        }
728    }
729
730    //--------------------------------------------------------------------------
731    //
732    //  Overridden methods: Container
733    //
734    //--------------------------------------------------------------------------
735
736    /**
737     *  @private
738     */
739    override protected function layoutChrome(unscaledWidth:Number,
740                                             unscaledHeight:Number):void
741    {
742        super.layoutChrome(unscaledWidth, unscaledHeight);
743
744        // Move our border so it leaves room for the tabs
745        if (border)
746        {
747            var borderOffset:Number = tabBarHeight;
748            border.setActualSize(unscaledWidth, unscaledHeight - borderOffset);
749            border.move(0, borderOffset);
750        }
751    }
752
753    //--------------------------------------------------------------------------
754    //
755    //  Methods
756    //
757    //--------------------------------------------------------------------------
758
759    /**
760     *  Returns the tab of the navigator's TabBar control at the specified
761     *  index.
762     *
763     *  @param index Index in the navigator's TabBar control.
764     *
765     *  @return The tab at the specified index.
766     */
767    public function getTabAt(index:int):Button
768    {
769        return Button(tabBar.getChildAt(index));
770    }
771
772    //--------------------------------------------------------------------------
773    //
774    //  Overridden event handlers: UIComponent
775    //
776    //--------------------------------------------------------------------------
777
778    /**
779     *  @private
780     */
781    override protected function focusInHandler(event:FocusEvent):void
782    {
783        super.focusInHandler(event);
784
785        // When the TabNavigator has focus, the Focus Manager
786        // should not treat the Enter key as a click on
787        // the default pushbutton.
788        if (event.target == this)
789            focusManager.defaultButtonEnabled = false;
790    }
791
792    /**
793     *  @private
794     */
795    override protected function focusOutHandler(event:FocusEvent):void
796    {
797        super.focusOutHandler(event);
798
799        if (focusManager && event.target == this)
800            focusManager.defaultButtonEnabled = true;
801    }
802
803    import flash.ui.Keyboard;
804
805    /**
806     *  @private
807     */
808    override protected function keyDownHandler(event:KeyboardEvent):void
809    {
810        if (focusManager.getFocus() == this)
811        {
812            // Redispatch the event from the TabBar so that it can handle it.
813            tabBar.dispatchEvent(event);
814        }
815    }
816
817    /**
818     *  @private
819     */
820    mx_internal function getTabBar():TabBar
821    {
822        return tabBar;
823    }
824
825}
826
827}
828