1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2009 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.charts.chartClasses
13{
14
15import flash.text.TextFormat;
16
17import mx.core.ClassFactory;
18import mx.core.ContextualClassFactory;
19import mx.core.IFactory;
20import mx.core.IFlexModuleFactory;
21import mx.core.IUITextField;
22
23/**
24 *  InstanceCache is a utility that governs the task of creating and managing
25 *  a set of <i>n</i> object instances, where <i>n</i> changes frequently.
26 *
27 *  @langversion 3.0
28 *  @playerversion Flash 9
29 *  @playerversion AIR 1.1
30 *  @productversion Flex 3
31 */
32public class InstanceCache
33{
34    include "../../core/Version.as";
35
36    //--------------------------------------------------------------------------
37    //
38    //  Constructor
39    //
40    //--------------------------------------------------------------------------
41
42    /**
43     *  Constructor.
44     *
45     *  @param type The type of object to construct.
46     *  This can be either a Class or an IFactory.
47     *
48     *  @param parent An optional DisplayObject to add new instances to.
49     *
50     *  @param insertPosition Where in the parent's child list
51     *  to insert instances. Set to -1 to add the children to the end of the child list.
52     *
53     *  @param moduleFactory The context for using embedded fonts and for
54     *  finding the style manager that controls the styles for this component.
55     *
56     *  @langversion 3.0
57     *  @playerversion Flash 9
58     *  @playerversion AIR 1.1
59     *  @productversion Flex 3
60     */
61    public function InstanceCache(type:Object, parent:Object = null,
62                                  insertPosition:int = -1, moduleFactory:IFlexModuleFactory = null)
63    {
64        super();
65
66        _parent = parent;
67
68        if (type is IFactory)
69        {
70            _factory = IFactory(type);
71        }
72        else if (type is Class)
73        {
74            _class = Class(type);
75            _factory = new ContextualClassFactory(Class(type), moduleFactory);
76        }
77
78        _insertPosition = insertPosition;
79    }
80
81    //--------------------------------------------------------------------------
82    //
83    //  Variables
84    //
85    //--------------------------------------------------------------------------
86
87    /**
88     *  @private
89     */
90    private var _parent:Object;
91
92    /**
93     *  @private
94     */
95    private var _class:Class = null;
96
97    /**
98     *  @private
99     */
100    private var _insertPosition:int;
101
102    /**
103     *  @private
104     */
105    private var _count:int = 0;
106
107    //--------------------------------------------------------------------------
108    //
109    //  Properties
110    //
111    //--------------------------------------------------------------------------
112
113    //----------------------------------
114    //  count
115    //----------------------------------
116
117    [Inspectable(environment="none")]
118
119    /**
120     *  The number of items currently required in the cache.
121     *
122     *  @langversion 3.0
123     *  @playerversion Flash 9
124     *  @playerversion AIR 1.1
125     *  @productversion Flex 3
126     */
127    public function get count():int
128    {
129        return _count;
130    }
131
132    /**
133     *  @private
134     */
135    public function set count(value:int):void
136    {
137        if (value == _count)
138            return;
139
140        var newInstanceCount:int = value;
141        var oldInstanceCount:int = _count;
142        var availableInstanceCount:int = _instances.length;
143        var insertBase:int;
144        if (_parent != null)
145        {
146              insertBase = Math.min(_insertPosition,
147                _parent.numChildren - availableInstanceCount);
148        }
149
150        if (newInstanceCount> oldInstanceCount)
151        {
152            if (!_factory)
153            {
154                value = 0;
155            }
156            else
157            {
158                for (var i:int = oldInstanceCount;
159                     i < newInstanceCount && i < availableInstanceCount;
160                     i++)
161                {
162                    if (hide)
163                        _instances[i].visible = true;
164
165                    if (_parent && remove)
166                    {
167                        if (insertBase >= 0)
168                            _parent.addChildAt(_instances[i],insertBase + i);
169                        else
170                            _parent.addChild(_instances[i]);
171                    }
172                }
173
174                for (; i < newInstanceCount; i++)
175                {
176                    var newInst:Object = _factory.newInstance();
177
178                    if (_parent)
179                    {
180                        if (insertBase > 0)
181                            _parent.addChildAt(newInst, insertBase + i);
182                        else
183                            _parent.addChild(newInst);
184                    }
185
186                    if (creationCallback != null)
187                        creationCallback(newInst,this);
188
189                    _instances.push(newInst);
190                }
191
192                applyProperties(availableInstanceCount, newInstanceCount);
193
194                if (_format)
195                    applyFormat(availableInstanceCount, newInstanceCount);
196            }
197        }
198
199        else if (newInstanceCount < oldInstanceCount)
200        {
201            if (remove)
202            {
203                for (i = newInstanceCount; i < oldInstanceCount; i++)
204                {
205                    _parent.removeChild(_instances[i]);
206                }
207            }
208
209            if (hide)
210            {
211                for (i = newInstanceCount; i < oldInstanceCount; i++)
212                {
213                    _instances[i].visible = false;
214                }
215            }
216
217            if (discard)
218                _instances = _instances.slice(0, newInstanceCount);
219        }
220
221        _count = value;
222    }
223
224    //----------------------------------
225    //  creationCallback
226    //----------------------------------
227
228    [Inspectable(environment="none")]
229
230    /**
231     *  A callback invoked when new instances are created.
232     *  This callback has the following signature:
233     *  <pre>
234     *  function creationCallback(<i>newInstance</i>:Object, <i>cache</i>:InstanceCache):void;
235     *  </pre>
236     *
237     *  @langversion 3.0
238     *  @playerversion Flash 9
239     *  @playerversion AIR 1.1
240     *  @productversion Flex 3
241     */
242    public var creationCallback:Function;
243
244    //----------------------------------
245    //  discard
246    //----------------------------------
247
248    [Inspectable(environment="none")]
249
250    /**
251     *  Determines if unneeded instances are discarded.
252     *  If set to <code>true</code>, extra elements are discarded
253     *  when the cache count is reduced.
254     *  Otherwise, extra elements are kept in a separate cache
255     *  and reused when the count is increased.
256     *
257     *  @langversion 3.0
258     *  @playerversion Flash 9
259     *  @playerversion AIR 1.1
260     *  @productversion Flex 3
261     */
262    public var discard:Boolean = false;
263
264    //----------------------------------
265    //  factory
266    //----------------------------------
267
268    /**
269     *  @private
270     */
271    private var _factory:IFactory;
272
273    [Inspectable(environment="none")]
274
275    /**
276     *  A factory that generates the type of object to cache.
277     *  Assigning to this discards all current instances
278     *  and recreate new instances of the correct type.
279     *
280     *  @langversion 3.0
281     *  @playerversion Flash 9
282     *  @playerversion AIR 1.1
283     *  @productversion Flex 3
284     */
285    public function get factory():IFactory
286    {
287        return _factory;
288    }
289
290    /**
291     *  @private
292     */
293    public function set factory(value:IFactory):void
294    {
295        if (value == _factory ||
296            ((value is ClassFactory) &&
297            (_factory is ClassFactory) &&
298            (ClassFactory(_factory).generator == ClassFactory(value).generator) &&
299            (!(value is ContextualClassFactory))))
300            return;
301
302        _factory = value;
303        _class = null;
304
305        var instanceCount:Number = _count;
306        count = 0;
307        count = instanceCount;
308    }
309
310    //----------------------------------
311    //  format
312    //----------------------------------
313
314    /**
315     *  @private
316     */
317    private var _format:TextFormat;
318
319    [Inspectable(environment="none")]
320
321    /**
322     *  A TextFormat to apply to any instances created.
323     *  If set, this format is applied as the current and default format
324     *  for the contents of any instances created.
325     *  This property is only relevant if the factory
326     *  generates TextField instances.
327     *
328     *  @langversion 3.0
329     *  @playerversion Flash 9
330     *  @playerversion AIR 1.1
331     *  @productversion Flex 3
332     */
333    public function get format():TextFormat
334    {
335        return _format;
336    }
337
338    /**
339     *  @private
340     */
341    public function set format(value:TextFormat):void
342    {
343        _format = value;
344
345        if (_format)
346            applyFormat(0, _instances.length);
347    }
348
349    //----------------------------------
350    //  hide
351    //----------------------------------
352
353    [Inspectable(environment="none")]
354
355    /**
356     *  Determines if unneeded instances should be hidden.
357     *  If <code>true</code>, the <code>visible</code> property
358     *  is set to <code>false</code> on each extra element
359     *  when the cache count is reduced, and set to <code>true</code>
360     *  when the count is increased.
361     *
362     *  <p>This property is only relevant when the factory
363     *  generates DisplayObjects.
364     *  Setting this property to <code>true</code> for other factory types
365     *  generates a run-time error.</p>
366     *
367     *  @langversion 3.0
368     *  @playerversion Flash 9
369     *  @playerversion AIR 1.1
370     *  @productversion Flex 3
371     */
372    public var hide:Boolean = true;
373
374    //----------------------------------
375    //  insertPosition
376    //----------------------------------
377
378    [Inspectable(environment="none")]
379
380    /**
381     *  The position of the instance in the parent's child list.
382     *
383     *  @langversion 3.0
384     *  @playerversion Flash 9
385     *  @playerversion AIR 1.1
386     *  @productversion Flex 3
387     */
388    public function set insertPosition(value:int):void
389    {
390        if (value != _insertPosition)
391        {
392            _insertPosition = value;
393
394            if (_parent)
395            {
396                var n:int = _instances.length;
397                for (var i:int = 0; i < n; i++)
398                {
399                    _parent.setChildIndex(_instances[i], i + _insertPosition);
400                }
401            }
402        }
403    }
404
405    //----------------------------------
406    //  instances
407    //----------------------------------
408
409    /**
410     *  @private
411     */
412    private var _instances:Array /* of Object */= [];
413
414    [Inspectable(environment="none")]
415
416    /**
417     *  The Array of cached instances.
418     *  There may be more instances in this Array than currently requested.
419     *  You should rely on the <code>count</code> property
420     *  of the instance cache rather than the length of this Array.
421     *
422     *  @langversion 3.0
423     *  @playerversion Flash 9
424     *  @playerversion AIR 1.1
425     *  @productversion Flex 3
426     */
427    public function get instances():Array /* of Object */
428    {
429        return _instances;
430    }
431
432    //----------------------------------
433    //  properties
434    //----------------------------------
435
436    /**
437     *  @private
438     */
439    private var _properties:Object = {};
440
441    [Inspectable(environment="none")]
442
443    /**
444     *  A hashmap of properties to assign to new instances.
445     *  Each key/value pair in this hashmap is assigned
446     *  to each new instance created.
447     *  The property hashmap is assigned to any existing instances when set.
448     *
449     *  <p>The values in the hashmap are not cloned;
450     *  object values are shared by all instances.</p>
451     *
452     *  @langversion 3.0
453     *  @playerversion Flash 9
454     *  @playerversion AIR 1.1
455     *  @productversion Flex 3
456     */
457    public function get properties():Object
458    {
459        return _properties;
460    }
461
462    /**
463     *  @private
464     */
465    public function set properties(value:Object):void
466    {
467        _properties = value;
468
469        applyProperties(0, _instances.length);
470    }
471
472    //----------------------------------
473    //  remove
474    //----------------------------------
475
476    [Inspectable(environment="none")]
477
478    /**
479     *  Determines if unneeded instances should be removed from their parent.
480     *  If <code>true</code>, the <code>removeChild()</code> method
481     *  is called on the parent for each extra element
482     *  when the cache count is reduced.
483     *
484     *  <p>This property is only relevant when the factory
485     *  generates DisplayObjects.
486     *  Setting this property to <code>true</code> for other factory types
487     *  generates a run-time error.</p>
488     *
489     *  @langversion 3.0
490     *  @playerversion Flash 9
491     *  @playerversion AIR 1.1
492     *  @productversion Flex 3
493     */
494    public var remove:Boolean = false;
495
496    //--------------------------------------------------------------------------
497    //
498    //  Methods
499    //
500    //--------------------------------------------------------------------------
501
502    /**
503     *  @private
504     */
505    private function applyProperties(start:int, end:int):void
506    {
507        for (var i:int = start; i < end; i++)
508        {
509            var newInst:Object = _instances[i];
510
511            for (var p:String in _properties)
512            {
513                newInst[p] = _properties[p];
514            }
515        }
516    }
517
518    /**
519     *  @private
520     */
521    private function applyFormat(start:int, end:int):void
522    {
523        for (var i:int = start; i < end; i++)
524        {
525            var newField:IUITextField = _instances[i];
526            newField.setTextFormat(_format);
527            newField.defaultTextFormat = _format;
528
529        }
530    }
531}
532
533}