AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
SyncArray.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using System.Collections;
6 using System.Collections.Generic;
7 using UnityEngine;
8 
9 namespace HoloToolkit.Sharing.SyncModel
10 {
17  public class SyncArray<T> : SyncObject, IEnumerable<T> where T : SyncObject, new()
18  {
22  public event Action<T> ObjectAdded;
23 
27  public event Action<T> ObjectRemoved;
28 
32  private readonly Dictionary<string, T> dataArray;
33 
38  protected readonly Type arrayType;
39 
40  public SyncArray(string field)
41  : base(field)
42  {
43  dataArray = new Dictionary<string, T>();
44  arrayType = typeof(T);
45  }
46 
47  public SyncArray() : this(string.Empty) { }
48 
54  protected virtual T CreateObject(ObjectElement objectElement)
55  {
56  Type objectType = SyncSettings.Instance.GetDataModelType(objectElement.GetObjectType()).AsType();
57  if (!objectType.IsSubclassOf(arrayType) && objectType != arrayType)
58  {
59  throw new InvalidCastException(string.Format("Object of incorrect type added to SyncArray: Expected {0}, got {1} ", objectType, objectElement.GetObjectType().GetString()));
60  }
61 
62  object createdObject = Activator.CreateInstance(objectType);
63 
64  T spawnedDataModel = (T)createdObject;
65  spawnedDataModel.Element = objectElement;
66  spawnedDataModel.FieldName = objectElement.GetName();
67 
68  // TODO: this should not query SharingStage, but instead query the underlying session layer
69  spawnedDataModel.Owner = SharingStage.Instance.SessionUsersTracker.GetUserById(objectElement.GetOwnerID());
70 
71  return spawnedDataModel;
72  }
73 
80  public T AddObject(T newSyncObject, User owner = null)
81  {
82  // Create our object element for our target
83  string id = System.Guid.NewGuid().ToString();
84  string dataModelName = SyncSettings.Instance.GetDataModelName(newSyncObject.GetType());
85  ObjectElement existingElement = Element.CreateObjectElement(new XString(id), dataModelName, owner);
86 
87  // Create a new object and assign the element
88  newSyncObject.Element = existingElement;
89  newSyncObject.FieldName = id;
90  newSyncObject.Owner = owner;
91 
92  // Register the child with the object
93  AddChild(newSyncObject);
94 
95  // Update internal map
96  dataArray[id] = newSyncObject;
97 
98  // Initialize it so it can be used immediately.
99  newSyncObject.InitializeLocal(Element);
100 
101  // Notify listeners that an object was added.
102  if (ObjectAdded != null)
103  {
104  ObjectAdded(newSyncObject);
105  }
106 
107  return newSyncObject;
108  }
109 
115  public bool RemoveObject(T existingObject)
116  {
117  bool success = false;
118  if (existingObject != null)
119  {
120  string uniqueName = existingObject.Element.GetName();
121  if (dataArray.Remove(uniqueName))
122  {
123  RemoveChild(existingObject);
124 
125  if (ObjectRemoved != null)
126  {
127  ObjectRemoved(existingObject);
128  }
129 
130  success = true;
131  }
132  }
133 
134  return success;
135  }
136 
137  // Returns a full list of the objects
138  public T[] GetDataArray()
139  {
140  var childrenList = new List<T>(dataArray.Count);
141  foreach (KeyValuePair<string, T> pair in dataArray)
142  {
143  childrenList.Add(pair.Value);
144  }
145 
146  return childrenList.ToArray();
147  }
148 
149  IEnumerator<T> IEnumerable<T>.GetEnumerator()
150  {
151  return dataArray.Values.GetEnumerator();
152  }
153 
154  IEnumerator IEnumerable.GetEnumerator()
155  {
156  return dataArray.Values.GetEnumerator();
157  }
158 
159  public void Clear()
160  {
161  // TODO: We need a way of resetting in a consistent way across all object types and hierarchies.
162  T[] array = GetDataArray();
163  for (int i = 0; i < array.Length; i++)
164  {
165  RemoveObject(array[i]);
166  }
167  }
168 
169  protected override void OnElementAdded(Element element)
170  {
171  if (element.GetElementType() == ElementType.ObjectType)
172  {
173  // Add the new object and listen for when the initialization has fully completed since it can take time.
174  T newObject = AddObject(ObjectElement.Cast(element));
175  newObject.InitializationComplete += OnInitializationComplete;
176  }
177  else
178  {
179  Debug.LogError("Error: Adding unknown element to SyncArray<T>");
180  }
181 
182  base.OnElementAdded(element);
183  }
184 
185  protected override void OnElementDeleted(Element element)
186  {
187  base.OnElementDeleted(element);
188 
189  string uniqueName = element.GetName();
190  if (dataArray.ContainsKey(uniqueName))
191  {
192  T obj = dataArray[uniqueName];
193  RemoveObject(obj);
194  }
195  }
196 
197  private void OnInitializationComplete(SyncObject obj)
198  {
199  // Notify listeners know that an object was added
200  if (ObjectAdded != null)
201  {
202  ObjectAdded(obj as T);
203  }
204  }
205 
211  private T AddObject(ObjectElement existingElement)
212  {
213  string id = existingElement.GetName();
214 
215  // Create a new object and assign the element
216  T newObject = CreateObject(existingElement);
217 
218  // Register the child with the object
219  AddChild(newObject);
220 
221  // Update internal map
222  dataArray[id] = newObject;
223 
224  return newObject;
225  }
226  }
227 }
static ObjectElement Cast(Element element)
virtual XString GetName()
Definition: Element.cs:53
readonly Type arrayType
Type of objects in the array. This is cached so that we don&#39;t have to call typeof(T) more than once...
Definition: SyncArray.cs:38
virtual T CreateObject(ObjectElement objectElement)
Creates the object in the array, based on its underlying object element that came from the sync syste...
Definition: SyncArray.cs:54
Action< T > ObjectRemoved
Called when an existing object has been removed from the array
Definition: SyncArray.cs:27
override void OnElementDeleted(Element element)
Handler for if a child is deleted.
Definition: SyncArray.cs:185
Collection of sharing sync settings, used by the HoloToolkit Sharing sync system to figure out which ...
Definition: SyncSettings.cs:16
virtual ElementType GetElementType()
Definition: Element.cs:43
The SyncArray class provides the functionality of an array in the data model. The array holds entire ...
Definition: SyncArray.cs:17
static T Instance
Returns the Singleton instance of the classes type. If no instance is found, then we search for an in...
Definition: Singleton.cs:26
T AddObject(T newSyncObject, User owner=null)
Adds a new entry into the array.
Definition: SyncArray.cs:80
The SyncObject class is a container object that can hold multiple SyncPrimitives. ...
Definition: SyncObject.cs:21
override void OnElementAdded(Element element)
Handler for if a child is added.
Definition: SyncArray.cs:169
Action< T > ObjectAdded
Called when a new object has been added to the array.
Definition: SyncArray.cs:22
The SharingStage is in charge of managing the core networking layer for the application.
Definition: SharingStage.cs:14
bool RemoveObject(T existingObject)
Removes an entry from the array
Definition: SyncArray.cs:115