Expand my Community achievements bar.

Multiuser Google Map

Avatar

Former Community Member

Hi,

I am currenly developing application implementing Google Map sharing with Adobe LCCS and Flex for Android. I have a problem building the shared model of the google map, is there anyone who could show me any example regarding this as I could'nt found any. Any help is appreciated. Thx.

Regards

Tan

4 Replies

Avatar

Former Community Member

Hi There,

Have you checked out the YahooMaps sample? It has a SharedYahooMaps model.

nigel

Avatar

Former Community Member

Hi,

I had went through the Yahoo Map example and I am trying to build the it using the Google Map, I utilized just the AfcsCollection.as(without changing) and SharedYahooMapsModel(changed according to Google Map). Then I build a simple main application for the Google Map just changing the position and zoom level. But everytime i try to launch, this error came out which I don't really understand. Below is the error:

Error: MessageManager.getRootUserRole - This user doesn't exist.

at com.adobe.rtc.messaging.manager::MessageManager/http://www.adobe.com/2006/connect/cocomo/messaging/internal::getRootUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:454]

at com.adobe.rtc.sharedModel::CollectionNode/getRootUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:883]

at com.adobe.rtc.sharedModel::CollectionNode/getUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:471]

at com.adobe.rtc.sharedModel::CollectionNode/canUserConfigure()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:593]

at SharedMapModel/onSyncChange()[C:\Users\Compaq\Adobe Flash Builder 4\GoogleMap\src\SharedMapModel.as:182]

at flash.events::EventDispatcher/dispatchEventFunction()

at flash.events::EventDispatcher/dispatchEvent()

at com.adobe.rtc.sharedModel::CollectionNode/http://www.adobe.com/2006/connect/cocomo/messaging/internal::setIsSynchronized()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:700]

at com.adobe.rtc.messaging.manager::MessageManager/receiveAllSynchData()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:851]

at com.adobe.rtc.messaging.manager::MessageManager/http://www.adobe.com/2006/connect/cocomo/messaging/internal::receiveItems()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:596]

at com.adobe.rtc.session.managers::SessionManagerBase/receiveItems()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/session/managers/SessionManagerBase.as:456]

Any help would be appreciated.Thx.
Regards,
Tan

Avatar

Employee

Did you try the original example before chaning it ? Are you setting room and credentials correctly ? The error is related to a user so maybe your application didn't authenticate correctly (or you started the room as a guest without first entering as the owner so that all the nodes would get setup correctly).

It would be helpful if you send the full list of log messages you get when running in debug mode in FlashBuilder.

Avatar

Former Community Member

I didn't manage to get the Yahoo Map example running, so I went through it to get the important script to build the google map sharing. My source folder has only 3 files which i think suppose to be able to generate the Google Map.I login straight using my developer account.Below is the full list of log messages and I attached along the three scripts I've written...

Log messages:

[SWF] GoogleMap.swf - 2,651,420 bytes after decompression

Tue Mar 8 04:56:58 GMT+0800 2011    LCCS SDK Version : 1.3.7.1    Player Version : WIN 10,1,85,3

04:56:58 GMT+0800    requestInfo https://collaboration.adobelivecycle.com/yytan1987/myfirstroom?mode=xml&glt=g:&x=0.5164360296912491

[SWF] /mapsapi/publicapi - 4,125 bytes after decompression

[SWF] /mapfiles/lib/map_1_20.swf - 317,303 bytes after decompression

[SWF] /mapsapi/publicapi - 790 bytes after decompression

04:57:08 GMT+0800    authentication status: 200

04:57:08 GMT+0800    authentication request complete

04:57:08 GMT+0800    requestInfo https://collaboration.adobelivecycle.com/yytan1987/myfirstroom?gak=cmVuZ2EqbmExcioxMmU5MjFiZjY0MSpKR...

04:57:11 GMT+0800    #TicketService# ticket received: 26tkbnwc3t7z

04:57:11 GMT+0800    Getting FMS at https://na2.collaboration.adobelivecycle.com/fms?ticket=26tkbnwc3t7z&proto=rtmfp, attempt #1/3

04:57:12 GMT+0800    result: <fms>

  <origin>fms2.acrobat.com</origin>

  <proto_ports>rtmfp:1935,rtmps:443</proto_ports>

  <retry_attempts>2</retry_attempts>

</fms>

04:57:12 GMT+0800    protocols: [object ProtocolPortPair],[object ProtocolPortPair]

04:57:12 GMT+0800    [attempt 1 of 2] Connecting to 0/1: rtmfp://fms2.acrobat.com/cocomo/na2-sdk-de21bd7d-e997-46a3-b4a2-33bf56efa416/myfirstroom #startProtosConnect#

04:57:14 GMT+0800    tempNetStatusHandler 0/2,NetConnection.Connect.Success

04:57:14 GMT+0800    isTunneling? false

04:57:14 GMT+0800    is using RTMPS? false

04:57:14 GMT+0800    RECEIVED LOGIN AT SESSION

04:57:14 GMT+0800      .user descriptor from server [object]

04:57:14 GMT+0800        \\

04:57:14 GMT+0800        .role [number]= 100

04:57:14 GMT+0800        .affiliation [number]= 100

04:57:14 GMT+0800        .userID [string]= WCD-2A9F0D364CAC939C0A746C1B/6

04:57:14 GMT+0800        .displayName [string]= YY Tan 6

04:57:15 GMT+0800    RECEIVENODES UserManager

04:57:15 GMT+0800    receiveAllSynchData UserManager

04:57:15 GMT+0800    RECEIVENODES FileManager

04:57:15 GMT+0800    receiveAllSynchData FileManager

04:57:15 GMT+0800    checkManagerSync:[object FileManager]

04:57:16 GMT+0800    RECEIVENODES AVManager

04:57:16 GMT+0800    receiveAllSynchData AVManager

04:57:16 GMT+0800    checkManagerSync:[object StreamManager]

04:57:16 GMT+0800    RECEIVENODES RoomManager

04:57:16 GMT+0800    receiveAllSynchData RoomManager

04:57:16 GMT+0800    checkManagerSync:[object RoomManager]

04:57:16 GMT+0800    checkManagerSync:[object UserManager]

04:57:17 GMT+0800    RECEIVENODES sharedMap

04:57:17 GMT+0800    receiveAllSynchData sharedMap

Error: MessageManager.getRootUserRole - This user doesn't exist.

at com.adobe.rtc.messaging.manager::MessageManager/http://www.adobe.com/2006/connect/cocomo/messaging/internal::getRootUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:454]

at com.adobe.rtc.sharedModel::CollectionNode/getRootUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:883]

at com.adobe.rtc.sharedModel::CollectionNode/getUserRole()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:471]

at com.adobe.rtc.sharedModel::CollectionNode/canUserConfigure()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:593]

at SharedMapModel/onSyncChange()[C:\Users\Compaq\Adobe Flash Builder 4\GoogleMap\src\SharedMapModel.as:185]

at flash.events::EventDispatcher/dispatchEventFunction()

at flash.events::EventDispatcher/dispatchEvent()

at com.adobe.rtc.sharedModel::CollectionNode/http://www.adobe.com/2006/connect/cocomo/messaging/internal::setIsSynchronized()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/sharedModel/CollectionNode.as:700]

at com.adobe.rtc.messaging.manager::MessageManager/receiveAllSynchData()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:851]

at com.adobe.rtc.messaging.manager::MessageManager/http://www.adobe.com/2006/connect/cocomo/messaging/internal::receiveItems()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/messaging/manager/MessageManager.as:596]

at com.adobe.rtc.session.managers::SessionManagerBase/receiveItems()[/Users/arun/Work/aponnusa_theoden.corp.adobe.com_1666/depot/branches/connect/1010/cocomoPlayer10/src/com/adobe/rtc/session/managers/SessionManagerBase.as:456]

GoogleMap.mxml(main):
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx"
   xmlns:rtc="http://ns.adobe.com/rtc"
   xmlns:maps="com.google.maps.*"
   xmlns:ns2="*">
<maps:Map mapevent_mapready="onReady(event)" url="http://code.google.com/apis/maps/" id="map" width="100%" height="100%" key="ABQIAAAAa1d-LRFOUL0Fhv8VJsT-JhROcIOxpjBZUVD7XRlGFELYl3GNYxQIzt1g1Bnuf1QsKZfb47Zk7_c6Bw" sensor="true" x="0" y="0"/>
<fx:Script>
<![CDATA[
import com.google.maps.LatLng;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.MapMoveEvent;
import com.google.maps.MapOptions;
import com.google.maps.MapType;
import com.google.maps.MapZoomEvent;
import com.google.maps.controls.ZoomControl;
import com.google.maps.overlays.Marker;
import com.google.maps.overlays.MarkerOptions;
import com.google.maps.styles.FillStyle;
import com.google.maps.styles.StrokeStyle;
import flash.events.GeolocationEvent;
import flash.sensors.Geolocation;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import mx.events.FlexEvent;
protected var _sharedMapModel:SharedMapModel;
private var zoomControl:ZoomControl = new ZoomControl();
private function onReady(e:MapEvent):void{
this.map.visible = false;
this.map.setCenter(new LatLng(45.468799,9.188004),14, MapType.NORMAL_MAP_TYPE);
addMapControls();
setupSharedMap();
}
private function addMapControls():void {
map.addControl(zoomControl);
}
private function removeMapControls():void {
map.removeControl(zoomControl);
}
private function setupMapListeners():void {
map.addEventListener(MapMoveEvent.MOVE_END, onMapMoveEnd);
map.addEventListener(MapZoomEvent.ZOOM_CHANGED, onMapZoom);
}
private function setupSharedMap():void {
_sharedMapModel = new SharedMapModel();
_sharedMapModel.subscribe("sharedMap");
_sharedMapModel.addEventListener("subscribe",onSubscribed);
_sharedMapModel.addEventListener("latLngChange",onPositionChange);
_sharedMapModel.addEventListener("zoomChange",onZoomChange);
}
private function onSubscribed(p_evt:Event=null):void {
_sharedMapModel.removeEventListener("subscribe",onSubscribed);
setupMapListeners();
this.map.visible = true;
}
private function onMapMoveEnd(event:MapMoveEvent):void {
_sharedMapModel.latLng = this.map.getCenter();
}
protected function onPositionChange(p_evt:Event=null):void {
this.map.removeEventListener(MapMoveEvent.MOVE_END, onMapMoveEnd);
this.map.setCenter(_sharedMapModel.latLng);
this.map.addEventListener(MapMoveEvent.MOVE_END, onMapMoveEnd);
}
private function onMapZoom(event:MapZoomEvent):void {
_sharedMapModel.zoom = this.map.getZoom();
}
protected function onZoomChange(p_evt:Event=null):void {
this.map.removeEventListener(MapZoomEvent.ZOOM_CHANGED, onMapZoom);
this.map.setZoom(_sharedMapModel.zoom);
this.map.addEventListener(MapZoomEvent.ZOOM_CHANGED, onMapZoom);
}
]]>
</fx:Script>
<fx:Declarations>
<rtc:AdobeHSAuthenticator id="auth"
  userName="camely3k@hotmail.com"
  password="password"
  />
</fx:Declarations>
<rtc:ConnectSessionContainer width="100%" height="100%"
roomURL="https://collaboration.adobelivecycle.com/yytan1987/myfirstroom"
id="cSession"
authenticator="{auth}">
</rtc:ConnectSessionContainer>
</s:WindowedApplication>
SharedMapModel.as:
package
{
import com.adobe.rtc.events.CollectionNodeEvent;
import com.adobe.rtc.events.SharedModelEvent;
import com.adobe.rtc.messaging.MessageItem;
import com.adobe.rtc.session.ConnectSession;
import com.adobe.rtc.sharedModel.Baton;
import com.adobe.rtc.sharedModel.CollectionNode;
import com.adobe.rtc.sharedModel.SharedCollection;
import com.google.maps.LatLng;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class SharedMapModel extends EventDispatcher
{
// fired when the position of the map has been changed
[Event(name="latLngChange", type="flash.events.Event")]
// fired when the zoom level of the map has been changed
[Event(name="zoomChange", type="flash.events.Event")]
// fired when the mode of the map (annotation or navigation) has been changed
[Event(name="modeChange", type="flash.events.Event")]
// fired when the contolling user of the map has been changed
[Event(name="batonChange", type="flash.events.Event")]
[Event(name="subscribe", type="flash.events.Event")]
protected var _latLng:LatLng;
protected var _zoom:int;
protected var _mode:String;
protected var _collectionNode:CollectionNode;
protected var _myUserID:String;
protected var _controllingUser:String;
protected var _baton:Baton;
public var markerCollection:SharedCollection = new SharedCollection();
protected static const LAT_LNG_NODE:String = "latLngNode";
protected static const ZOOM_NODE:String = "zoomNode";
protected static const MODE_NODE:String = "modeNode";
public function SharedMapModel(target:IEventDispatcher=null)
{
super(target);
}
[Bindable("subscribe")]
public function subscribe(p_uniqueID:String):void
{
_myUserID = ConnectSession.primarySession.userManager.myUserID;
// set up the collectionNode
_collectionNode = new CollectionNode();
_collectionNode.sharedID = p_uniqueID ;
_collectionNode.subscribe();
_collectionNode.addEventListener(CollectionNodeEvent.SYNCHRONIZATION_CHANGE, onSyncChange);
_collectionNode.addEventListener(CollectionNodeEvent.ITEM_RECEIVE, onItemReceive);
// set up the marker collection - CocomoCollection allows you to specify an existing
// collectionNode to use for messaging, so we'll have it piggy-back on the same
// collectionNode as the one our model uses (to reduce the number of destinations on server)
markerCollection.collectionNode = _collectionNode;
// use the userID field as the unique ID for each item in the collection
markerCollection.idField = "userID";
// use one node on our collectionNode for marker details
markerCollection.subscribe();
// set up the baton. we'll also have it piggy-back on our existing collectionNode.
_baton = new Baton();
_baton.sharedID = "mapControl" ;
_baton.timeOut = 5 ;
_baton.collectionNode = _collectionNode ;
_baton.subscribe();
_baton.addEventListener(SharedModelEvent.BATON_HOLDER_CHANGE, onBatonChange);
}
/**
* Sets the position of the SharedMap model. Note that the value isn't updated until the resulting
* message returns from the service.
* @param p_val - the LatLon object corresponding to the map's position
*/
public function set latLng(p_val:LatLng):void
{
// baton management - if I've got the baton already, then keep it for a while longer,
// if I don't but can grab it, do so. Otherwise, I'm not allowed to update this value.
if (_baton.amIHolding) {
_baton.extendTimer();
} else if (_baton.canIGrab) {
_baton.grab();
} else {
return;
}
// send a message (through our collectionNode) to the service to update the position.
// note that LAT_LON_NODE is configured to only store a single item (see onSyncChange),
// so only the last item published here gets stored
var msg:MessageItem = new MessageItem(LAT_LNG_NODE, {lat:p_val.lat, lng:p_val.lng});
_collectionNode.publishItem(msg);
}
[Bindable("latLngChange")]
public function get latLng():LatLng
{
return _latLng;
}
/**
* Sets the zoom level of the SharedMap model. Note that the value isn't updated until the resulting
* message returns from the service.
* @param p_val - the LatLon object corresponding to the map's position
*/
public function set zoom(p_val:int):void
{
// baton management - if I've got the baton already, then keep it for a while longer,
// if I don't but can grab it, do so. Otherwise, I'm not allowed to update this value.
if (_baton.amIHolding) {
_baton.extendTimer();
} else if (_baton.canIGrab) {
_baton.grab();
} else {
return;
}
// send a message (through our collectionNode) to the service to update the zoom level.
// note that ZOOM_NODE is configured to only store a single item (see onSyncChange),
// so only the last item published here gets stored
var msg:MessageItem = new MessageItem(ZOOM_NODE, p_val);
_collectionNode.publishItem(msg);
}
[Bindable("zoomChange")]
public function get zoom():int
{
return _zoom;
}
/**
* Sets the mode (annotation or navigation) of the SharedMap model.
* Note that the value isn't updated until the resulting
* message returns from the service.
* @param p_val
*
*/
public function set mode(p_val:String):void
{
// baton management - if I've got the baton already, then keep it for a while longer,
// if I don't but can grab it, do so. Otherwise, I'm not allowed to update this value.
if (_baton.amIHolding) {
_baton.extendTimer();
} else if (_baton.canIGrab) {
_baton.grab();
} else {
return;
}
// send a message (through our collectionNode) to the service to update the mode.
// note that MODE_NODE is configured to only store a single item (see onSyncChange),
// so only the last item published here gets stored
var msg:MessageItem = new MessageItem(MODE_NODE, p_val);
_collectionNode.publishItem(msg);
}
[Bindable("modeChange")]
public function get mode():String
{
return _mode;
}
/**
* returns the userID of the user currently controlling the map
*/
[Bindable("batonChange")]
public function get controllingUser():String
{
return _controllingUser;
}
/**
* Fired when the collectionNode has fully connected to the service and retrieved all information
* about its nodes and stored message items. Note that this is typically the time when an OWNER sets up
* the node structure of any CollectionNodes, after the CollectionNode has synched and the OWNER notices
* it hasn't got the requisite nodes.
*/
protected function onSyncChange(p_evt:CollectionNodeEvent):void
{
// if I'm the OWNER and there's no node defined for LAT_LON, create one.
// note we're using the default NodeConfiguration, which only stores one item and has default
// publish/subscribe permissions.
if (!_collectionNode.isNodeDefined(LAT_LNG_NODE) && _collectionNode.canUserConfigure(_myUserID)) {
_collectionNode.createNode(LAT_LNG_NODE);
}
// if I'm the OWNER and there's no node defined for ZOOM, create one.
if (!_collectionNode.isNodeDefined(ZOOM_NODE) && _collectionNode.canUserConfigure(_myUserID)) {
_collectionNode.createNode(ZOOM_NODE);
}
// if I'm the OWNER and there's no node defined for MODE, create one.
if (!_collectionNode.isNodeDefined(MODE_NODE) && _collectionNode.canUserConfigure(_myUserID)) {
_collectionNode.createNode(MODE_NODE);
}
}
/**
* Fired when an item is received from the service (whether from the current user's updates
* or a remote one).
*/
protected function onItemReceive(p_evt:CollectionNodeEvent):void
{
if (p_evt.nodeName==LAT_LNG_NODE) {
// the latlon has been updated. Update our model value, and fire an event to notify of the change
_latLng = new LatLng(p_evt.item.body.lat, p_evt.item.body.lng);
if (p_evt.item.publisherID!=_myUserID) {
dispatchEvent(new Event("latLngChange"));
}
} else if (p_evt.nodeName==ZOOM_NODE) {
// the zoom has been updated. Update our model value, and fire an event to notify of the change
_zoom = p_evt.item.body;
dispatchEvent(new Event("zoomChange"));
} else if (p_evt.nodeName==MODE_NODE) {
// the mode has been updated. Update our model value, and fire an event to notify of the change
_mode = p_evt.item.body;
dispatchEvent(new Event("modeChange"));
}
}
/**
* Fired when the holderID of the baton changes. We update our model value and fire an event to notify of the change
*/
protected function onBatonChange(p_evt:Event):void
{
_controllingUser = _baton.holderID;
dispatchEvent(new Event("batonChange"));
}
}
}
AfcsCollection.as:
package
{
import mx.collections.ArrayCollection;
import com.adobe.rtc.sharedModel.CollectionNode;
import com.adobe.rtc.messaging.NodeConfiguration;
import com.adobe.rtc.events.CollectionNodeEvent;
import com.adobe.rtc.messaging.MessageItem;
import mx.core.IUID;
import com.adobe.rtc.session.ConnectSession;
[Event(name="synchronizationChange", type="com.adobe.rtc.events.CollectionNodeEvent")]
public class AfcsCollection extends ArrayCollection
{
public function AfcsCollection(source:Array=null)
{
super(source);
}
public var collectionNode:CollectionNode;
protected static const ITEM_NODE:String = "itemNode";
protected var _nodeConfig:NodeConfiguration;
protected var _nodeName:String = ITEM_NODE;
protected var _myUserID:String;
/**
* what field in each item can be used as a unique identifier?
*/
public var idField:String;
/**
* what class is each item?
*/
public var itemClass:Class;
[Bindable("synchronizationChange")]
public function get isSynchronized():Boolean
{
if (collectionNode) {
return collectionNode.isSynchronized;
} else {
return false;
}
}
public function subscribe(p_uniqueID:String, p_nodeConfig:NodeConfiguration=null):void
{
_nodeConfig = (p_nodeConfig) ? p_nodeConfig : new NodeConfiguration();
_nodeConfig.itemStorageScheme = NodeConfiguration.STORAGE_SCHEME_MANUAL;
_myUserID = ConnectSession.primarySession.userManager.myUserID;
if (collectionNode==null) {
collectionNode = new CollectionNode();
collectionNode.sharedID = p_uniqueID ;
collectionNode.subscribe();
} else {
_nodeName = p_uniqueID;
}
collectionNode.addEventListener(CollectionNodeEvent.SYNCHRONIZATION_CHANGE, onSyncChange);
collectionNode.addEventListener(CollectionNodeEvent.ITEM_RECEIVE, onItemReceive);
collectionNode.addEventListener(CollectionNodeEvent.ITEM_RETRACT, onItemRetract);
}
override public function setItemAt(p_item:Object, p_index:int):Object
{
var oldItem:Object = getItemAt(p_index);
var msg:MessageItem = new MessageItem(_nodeName, p_item, getItemID(oldItem));
collectionNode.publishItem(msg, true);
return oldItem;
}
override public function addItem(p_item:Object):void
{
var msg:MessageItem = new MessageItem(_nodeName, p_item, getItemID(p_item));
collectionNode.publishItem(msg);
}
override public function removeItemAt(p_index:int):Object
{
var oldItem:Object = getItemAt(p_index);
collectionNode.retractItem(_nodeName, getItemID(oldItem));
return oldItem;
}
override public function removeAll():void
{
var l:int = length;
for (var i:int=l-1; i>=0; i--) {
removeItemAt(i);
}
}
protected function onSyncChange(p_evt:CollectionNodeEvent):void
{
if (!collectionNode.isNodeDefined(_nodeName) && collectionNode.canUserConfigure(_myUserID, _nodeName)) {
// this collectionNode has never been built, and I can add it...
collectionNode.createNode(_nodeName, _nodeConfig);
}
dispatchEvent(p_evt);
}
protected function onItemReceive(p_evt:CollectionNodeEvent):void
{
if (p_evt.nodeName!=_nodeName) {
return;
}
var newItem:Object = p_evt.item.body;
var itemID:String = (idField) ? newItem[idField] : newItem.uid;
var oldItem:Object;
var i:String;
// yes, this is ugly. Improve later
var l:int = length;
for (var idx:int=0; idx<l; idx++) {
if (itemID==getItemID(getItemAt(idx))) {
oldItem = getItemAt(idx);
break;
}
}
if (oldItem) {
// it's an item update
for (i in newItem) {
if (newItem[i]!=oldItem[i]) {
var tmpOldValue:Object = oldItem[i];
oldItem[i] = newItem[i];
itemUpdated(oldItem, i, tmpOldValue, oldItem[i]);
}
}
super.setItemAt(oldItem, idx);
} else {
// it's a brand new item
if (itemClass) {
// yeah, this wouldn't work if there are constructor args
var newItemTyped:Object = new itemClass();
for (i in newItem) {
newItemTyped[i] = newItem[i];
}
super.addItem(newItemTyped);
} else {
super.addItem(newItem);
}
}
}
protected function onItemRetract(p_evt:CollectionNodeEvent):void
{
if (p_evt.nodeName!=_nodeName) {
return;
}
var newItem:Object = p_evt.item.body;
var itemID:String = (idField) ? newItem[idField] : newItem.uid;
var oldItem:Object;
// yes, this is ugly. Improve later
var l:int = length;
for (var idx:int=0; idx<l; idx++) {
if (itemID==getItemID(getItemAt(idx))) {
oldItem = getItemAt(idx);
break;
}
}
if (oldItem) {
super.removeItemAt(idx);
}
}
protected function getItemID(p_item:Object):String
{
return (p_item is IUID) ? IUID(p_item).uid : p_item[idField] as String;
}
}
}