You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by la...@apache.org on 2012/04/05 19:46:36 UTC
svn commit: r1309973 - in /incubator/flex/whiteboard/labriola: ./
frameworks/ frameworks/projects/ frameworks/projects/framework/
frameworks/projects/framework/src/ frameworks/projects/framework/src/mx/
frameworks/projects/framework/src/mx/collections/
Author: labriola
Date: Thu Apr 5 17:46:36 2012
New Revision: 1309973
URL: http://svn.apache.org/viewvc?rev=1309973&view=rev
Log:
FLEX-36 Addition of VectorCollection and VectorList to the repository
Added:
incubator/flex/whiteboard/labriola/
incubator/flex/whiteboard/labriola/frameworks/
incubator/flex/whiteboard/labriola/frameworks/projects/
incubator/flex/whiteboard/labriola/frameworks/projects/framework/
incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/
incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/
incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/
incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorCollection.as
incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorList.as
Added: incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorCollection.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorCollection.as?rev=1309973&view=auto
==============================================================================
--- incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorCollection.as (added)
+++ incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorCollection.as Thu Apr 5 17:46:36 2012
@@ -0,0 +1,138 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import flash.utils.IExternalizable;
+
+import mx.collections.ICollectionView;
+import mx.collections.ListCollectionView;
+import mx.collections.VectorList;
+import mx.core.mx_internal;
+
+use namespace mx_internal;
+
+[DefaultProperty("source")]
+
+public class VectorCollection extends ListCollectionView implements ICollectionView, IExternalizable
+{
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * <p>Creates a new VectorCollection using the specified source vector.
+ * If no Vector is specified an empty vector of type<*> will be used.</p>
+ *
+ * Due to the way the compiler (not the runtime) checks Vectors, we need to leave the source as an <*> until a compiler change can be implemented
+ */
+ public function VectorCollection(source:* = null)
+ {
+ super();
+
+ this.source = source;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // source
+ //----------------------------------
+
+ [Inspectable(category="General", arrayType="Object")]
+ [Bindable("listChanged")] //superclass will fire this
+
+ /**
+ * The source of data in the VectorCollection.
+ * The VectorCollection object does not represent any changes that you make
+ * directly to the source Vector. Always use
+ * the ICollectionView or IList methods to modify the collection.
+ */
+ public function get source():*
+ {
+ if (list && (list is VectorList))
+ {
+ return VectorList(list).source;
+ }
+
+ return null;
+ }
+
+ /**
+ * @private
+ */
+ public function set source(s:*):void
+ {
+ if ( s is Vector.<*> ) {
+ //Wraps provided Vectors in a VectorList implementation
+ list = new VectorList(s);
+ } else if ( !s ) {
+ //Provides a default VectorList
+ list = new VectorList();
+ } else {
+ //Need this because of our unfortunate requirement to take an * as the type to get around the compiler
+ throw new Error("The source of a VectorCollection must be a Vector" );
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * Ensures that only the source property is serialized.
+ */
+ public function readExternal(input:IDataInput):void
+ {
+ if (list is IExternalizable)
+ IExternalizable(list).readExternal(input);
+ else
+ source = input.readObject();
+ }
+
+ /**
+ * @private
+ * Ensures that only the source property is serialized.
+ */
+ public function writeExternal(output:IDataOutput):void
+ {
+ if (list is IExternalizable)
+ IExternalizable(list).writeExternal(output);
+ else
+ output.writeObject(source);
+ }
+
+}
+
+}
Added: incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorList.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorList.as?rev=1309973&view=auto
==============================================================================
--- incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorList.as (added)
+++ incubator/flex/whiteboard/labriola/frameworks/projects/framework/src/mx/collections/VectorList.as Thu Apr 5 17:46:36 2012
@@ -0,0 +1,598 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections {
+
+import flash.events.EventDispatcher;
+import flash.events.IEventDispatcher;
+import flash.utils.IExternalizable;
+
+import mx.core.IPropertyChangeNotifier;
+import mx.events.CollectionEvent;
+import mx.utils.UIDUtil;
+
+//--------------------------------------
+// Events
+//--------------------------------------
+
+/**
+ * Dispatched when the IList has been updated in some way.
+ *
+ * @eventType mx.events.CollectionEvent.COLLECTION_CHANGE
+ */
+[Event(name="collectionChange", type="mx.events.CollectionEvent")]
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("collections")]
+
+/**
+ * @private
+ * A simple implementation of IList that uses a backing Vector.
+ * This base class will not throw ItemPendingErrors but it
+ * is possible that a subclass might.
+ */
+public class VectorList extends EventDispatcher
+ implements IList, IExternalizable, IPropertyChangeNotifier {
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Construct a new VectorList using the specified Vector as its source.
+ * If no source is specified an empty Vector of type * will be used.
+ */
+ public function VectorList(source:Vector.<*> = null)
+ {
+ super();
+
+ disableEvents();
+ this.source = source;
+ enableEvents();
+ _uid = UIDUtil.createUID();
+ }
+import flash.utils.IDataInput;
+import flash.utils.IDataOutput;
+import flash.utils.getQualifiedClassName;
+
+import mx.events.CollectionEventKind;
+import mx.events.PropertyChangeEvent;
+import mx.events.PropertyChangeEventKind;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // length
+ //----------------------------------
+
+ /**
+ * Get the number of items in the list. An VectorList should always
+ * know its length so it shouldn't return -1, though a subclass may
+ * override that behavior.
+ *
+ * @return int representing the length of the source.
+ */
+ public function get length():int
+ {
+ if (source)
+ return source.length;
+ else
+ return 0;
+ }
+
+ //----------------------------------
+ // source
+ //----------------------------------
+
+ /**
+ * The source vector for this VectorList.
+ * Any changes done through the IList interface will be reflected in the
+ * source Vector.
+ * If no source Vector was supplied the VectorList will create one internally.
+ * Changes made directly to the underlying Vector (e.g., calling
+ * <code>theList.source.pop()</code> will not cause <code>CollectionEvents</code>
+ * to be dispatched.
+ *
+ * @return An Vector that represents the underlying source.
+ */
+ public function get source():Vector.<*>
+ {
+ return _source;
+ }
+
+ public function set source(s:Vector.<*>):void
+ {
+ var i:int;
+ var len:int;
+ if (_source && _source.length)
+ {
+ len = _source.length;
+ for (i = 0; i < len; i++)
+ {
+ stopTrackUpdates(_source[i]);
+ }
+ }
+ _source = s ? s : new Vector.<*>();
+ len = _source.length;
+ for (i = 0; i < len; i++)
+ {
+ startTrackUpdates(_source[i]);
+ }
+
+ if (_dispatchEvents == 0)
+ {
+ var event:CollectionEvent =
+ new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+ event.kind = CollectionEventKind.RESET;
+ dispatchEvent(event);
+ }
+ }
+
+ //----------------------------------
+ // uid -- mx.core.IPropertyChangeNotifier
+ //----------------------------------
+
+ /**
+ * Provides access to the unique id for this list.
+ *
+ * @return String representing the internal uid.
+ */
+ public function get uid():String
+ {
+ return _uid;
+ }
+
+ public function set uid(value:String):void
+ {
+ _uid = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get the item at the specified index.
+ *
+ * @param index the index in the list from which to retrieve the item
+ * @param prefetch int indicating both the direction and amount of items
+ * to fetch during the request should the item not be local.
+ * @return the item at that index, null if there is none
+ * @throws ItemPendingError if the data for that index needs to be
+ * loaded from a remote location
+ * @throws RangeError if the index < 0 or index >= length
+ */
+ public function getItemAt(index:int, prefetch:int = 0):Object
+ {
+ if (index < 0 || index >= length)
+ {
+ var message:String = resourceManager.getString(
+ "collections", "outOfBounds", [ index ]);
+ throw new RangeError(message);
+ }
+
+ return source[index];
+ }
+
+ /**
+ * Place the item at the specified index.
+ * If an item was already at that index the new item will replace it and it
+ * will be returned.
+ *
+ * @param item the new value for the index
+ * @param index the index at which to place the item
+ * @return the item that was replaced, null if none
+ * @throws RangeError if index is less than 0 or greater than or equal to length
+ */
+ public function setItemAt(item:Object, index:int):Object
+ {
+ if (index < 0 || index >= length)
+ {
+ var message:String = resourceManager.getString(
+ "collections", "outOfBounds", [ index ]);
+ throw new RangeError(message);
+ }
+
+ var oldItem:Object = source[index];
+ source[index] = item;
+ stopTrackUpdates(oldItem);
+ startTrackUpdates(item);
+
+ //dispatch the appropriate events
+ if (_dispatchEvents == 0)
+ {
+ var hasCollectionListener:Boolean =
+ hasEventListener(CollectionEvent.COLLECTION_CHANGE);
+ var hasPropertyListener:Boolean =
+ hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE);
+ var updateInfo:PropertyChangeEvent;
+
+ if (hasCollectionListener || hasPropertyListener)
+ {
+ updateInfo = new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+ updateInfo.kind = PropertyChangeEventKind.UPDATE;
+ updateInfo.oldValue = oldItem;
+ updateInfo.newValue = item;
+ updateInfo.property = index;
+ }
+
+ if (hasCollectionListener)
+ {
+ var event:CollectionEvent =
+ new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+ event.kind = CollectionEventKind.REPLACE;
+ event.location = index;
+ event.items.push(updateInfo);
+ dispatchEvent(event);
+ }
+
+ if (hasPropertyListener)
+ {
+ dispatchEvent(updateInfo);
+ }
+ }
+ return oldItem;
+ }
+
+ /**
+ * Add the specified item to the end of the list.
+ * Equivalent to addItemAt(item, length);
+ *
+ * @param item the item to add
+ */
+ public function addItem(item:Object):void
+ {
+ addItemAt(item, length);
+ }
+
+ /**
+ * Add the item at the specified index.
+ * Any item that was after this index is moved out by one.
+ *
+ * @param item the item to place at the index
+ * @param index the index at which to place the item
+ * @throws RangeError if index is less than 0 or greater than the length
+ */
+ public function addItemAt(item:Object, index:int):void
+ {
+ if (index < 0 || index > length)
+ {
+ var message:String = resourceManager.getString(
+ "collections", "outOfBounds", [ index ]);
+ throw new RangeError(message);
+ }
+
+ source.splice(index, 0, item);
+
+ startTrackUpdates(item);
+ internalDispatchEvent(CollectionEventKind.ADD, item, index);
+ }
+
+ /**
+ * Return the index of the item if it is in the list such that
+ * getItemAt(index) == item.
+ * Note that in this implementation the search is linear and is therefore
+ * O(n).
+ *
+ * @param item the item to find
+ * @return the index of the item, -1 if the item is not in the list.
+ */
+ public function getItemIndex(item:Object):int
+ {
+ var n:int = source.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ if (source[i] === item)
+ return i;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Removes the specified item from this list, should it exist.
+ *
+ * @param item Object reference to the item that should be removed.
+ * @return Boolean indicating if the item was removed.
+ */
+ public function removeItem(item:Object):Boolean
+ {
+ var index:int = getItemIndex(item);
+ var result:Boolean = index >= 0;
+ if (result)
+ removeItemAt(index);
+
+ return result;
+ }
+
+ /**
+ * Remove the item at the specified index and return it.
+ * Any items that were after this index are now one index earlier.
+ *
+ * @param index the index from which to remove the item
+ * @return the item that was removed
+ * @throws RangeError is index < 0 or index >= length
+ */
+ public function removeItemAt(index:int):Object
+ {
+ if (index < 0 || index >= length)
+ {
+ var message:String = resourceManager.getString(
+ "collections", "outOfBounds", [ index ]);
+ throw new RangeError(message);
+ }
+
+ var removed:Object = source.splice(index, 1)[0];
+ stopTrackUpdates(removed);
+ internalDispatchEvent(CollectionEventKind.REMOVE, removed, index);
+ return removed;
+ }
+
+ /**
+ * Remove all items from the list.
+ */
+ public function removeAll():void
+ {
+ if (length > 0)
+ {
+ var len:int = length;
+ for (var i:int = 0; i < len; i++)
+ {
+ stopTrackUpdates(source[i]);
+ }
+
+ source.splice(0, length);
+ internalDispatchEvent(CollectionEventKind.RESET);
+ }
+ }
+
+ /**
+ * Notify the view that an item has been updated.
+ * This is useful if the contents of the view do not implement
+ * <code>IEventDispatcher</code>.
+ * If a property is specified the view may be able to optimize its
+ * notification mechanism.
+ * Otherwise it may choose to simply refresh the whole view.
+ *
+ * @param item The item within the view that was updated.
+ *
+ * @param property A String, QName, or int
+ * specifying the property that was updated.
+ *
+ * @param oldValue The old value of that property.
+ * (If property was null, this can be the old value of the item.)
+ *
+ * @param newValue The new value of that property.
+ * (If property was null, there's no need to specify this
+ * as the item is assumed to be the new value.)
+ *
+ * @see mx.events.CollectionEvent
+ * @see mx.core.IPropertyChangeNotifier
+ * @see mx.events.PropertyChangeEvent
+ */
+ public function itemUpdated(item:Object, property:Object = null,
+ oldValue:Object = null,
+ newValue:Object = null):void
+ {
+ var event:PropertyChangeEvent =
+ new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+
+ event.kind = PropertyChangeEventKind.UPDATE;
+ event.source = item;
+ event.property = property;
+ event.oldValue = oldValue;
+ event.newValue = newValue;
+
+ itemUpdateHandler(event);
+ }
+
+ /**
+ * Return an Vector that is populated in the same order as the IList
+ * implementation.
+ *
+ * @throws ItemPendingError if the data is not yet completely loaded
+ * from a remote location
+ */
+ public function toArray():Array
+ {
+ var ar:Array = new Array( source.length );
+
+ for ( var i:int=0;i<source.length; i++ ) {
+ ar[ i ] = source[ i ];
+ }
+
+ return ar;
+ }
+
+ /**
+ * Ensures that only the source property is seralized.
+ * @private
+ */
+ public function readExternal(input:IDataInput):void
+ {
+ source = input.readObject();
+ }
+
+ /**
+ * Ensures that only the source property is serialized.
+ * @private
+ */
+ public function writeExternal(output:IDataOutput):void
+ {
+ output.writeObject(_source);
+ }
+
+ /**
+ * Pretty prints the contents of this VectorList to a string and returns it.
+ */
+ override public function toString():String
+ {
+ if (source)
+ return source.toString();
+ else
+ return getQualifiedClassName(this);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Internal Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Enables event dispatch for this list.
+ */
+ private function enableEvents():void
+ {
+ _dispatchEvents++;
+ if (_dispatchEvents > 0)
+ _dispatchEvents = 0;
+ }
+
+ /**
+ * Disables event dispatch for this list.
+ * To re-enable events call enableEvents(), enableEvents() must be called
+ * a matching number of times as disableEvents().
+ */
+ private function disableEvents():void
+ {
+ _dispatchEvents--;
+ }
+
+ /**
+ * Dispatches a collection event with the specified information.
+ *
+ * @param kind String indicates what the kind property of the event should be
+ * @param item Object reference to the item that was added or removed
+ * @param location int indicating where in the source the item was added.
+ */
+ private function internalDispatchEvent(kind:String, item:Object = null, location:int = -1):void
+ {
+ if (_dispatchEvents == 0)
+ {
+ if (hasEventListener(CollectionEvent.COLLECTION_CHANGE))
+ {
+ var event:CollectionEvent =
+ new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+ event.kind = kind;
+ event.items.push(item);
+ event.location = location;
+ dispatchEvent(event);
+ }
+
+ // now dispatch a complementary PropertyChangeEvent
+ if (hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE) &&
+ (kind == CollectionEventKind.ADD || kind == CollectionEventKind.REMOVE))
+ {
+ var objEvent:PropertyChangeEvent =
+ new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE);
+ objEvent.property = location;
+ if (kind == CollectionEventKind.ADD)
+ objEvent.newValue = item;
+ else
+ objEvent.oldValue = item;
+ dispatchEvent(objEvent);
+ }
+ }
+ }
+
+ /**
+ * Called whenever any of the contained items in the list fire an
+ * ObjectChange event.
+ * Wraps it in a CollectionEventKind.UPDATE.
+ */
+ protected function itemUpdateHandler(event:PropertyChangeEvent):void
+ {
+ internalDispatchEvent(CollectionEventKind.UPDATE, event);
+ // need to dispatch object event now
+ if (_dispatchEvents == 0 && hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE))
+ {
+ var objEvent:PropertyChangeEvent = PropertyChangeEvent(event.clone());
+ var index:uint = getItemIndex(event.target);
+ objEvent.property = index.toString() + "." + event.property;
+ dispatchEvent(objEvent);
+ }
+ }
+
+ /**
+ * If the item is an IEventDispatcher watch it for updates.
+ * This is called by addItemAt and when the source is initially
+ * assigned.
+ */
+ protected function startTrackUpdates(item:Object):void
+ {
+ if (item && (item is IEventDispatcher))
+ {
+ IEventDispatcher(item).addEventListener(
+ PropertyChangeEvent.PROPERTY_CHANGE,
+ itemUpdateHandler, false, 0, true);
+ }
+ }
+
+ /**
+ * If the item is an IEventDispatcher stop watching it for updates.
+ * This is called by removeItemAt, removeAll, and before a new
+ * source is assigned.
+ */
+ protected function stopTrackUpdates(item:Object):void
+ {
+ if (item && item is IEventDispatcher)
+ {
+ IEventDispatcher(item).removeEventListener(
+ PropertyChangeEvent.PROPERTY_CHANGE,
+ itemUpdateHandler);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * indicates if events should be dispatched.
+ * calls to enableEvents() and disableEvents() effect the value when == 0
+ * events should be dispatched.
+ */
+ private var _dispatchEvents:int = 0;
+ private var _source:Vector.<*>;
+ private var _uid:String;
+}
+
+}