using System; using System.Collections.Generic; using System.Text; using OSGeo.MapGuide.MaestroAPI.Serialization; using System.Xml; using OSGeo.MapGuide.MaestroAPI.Feature; namespace OSGeo.MapGuide.MaestroAPI.Mapping { /// /// Represents a map selection /// /// /// This sample shows how to list selected features in ASP.net. The sample expects 3 parameters: /// /// The session ID (SESSION) /// The runtime map name (MAPNAME) /// The selection XML (SELECTION) /// /// /// 0) /// { /// StringBuilder sb = new StringBuilder(); /// for (int i = 0; i < selection.Count; i++) /// { /// MapSelection.LayerSelection layerSel = selection[i]; /// sb.Append("

Layer: " + layerSel.Layer.Name + " (" + layerSel.Count + " selected item)"); /// sb.Append(""); /// for (int j = 0; j < layerSel.Count; j++) /// { /// sb.Append(""); /// object[] values = layerSel[j]; /// for (int k = 0; k < values.Length; k++) /// { /// sb.Append(""); /// } /// sb.AppendFormat("", /// rtMap.Name, /// conn.SessionID, /// layerSel.Layer.ObjectId, /// System.Web.HttpUtility.UrlEncode(layerSel.EncodeIDString(values))); /// sb.Append(""); /// } /// sb.Append("
"); /// sb.Append(values[k].ToString()); /// sb.Append("More Info
"); /// Response.WriteLine("

Showing IDs of selected features

"); /// Response.WriteLine(sb.ToString()); /// } /// } /// else /// { /// Response.WriteLine("Nothing selected. Select some features first then run this sample again."); /// } /// ]]> ///
///
public class MapSelection : IBinarySerializable, IList { private RuntimeMap _map; private List _layers; /// /// Constructor /// /// public MapSelection(RuntimeMap map) { _map = map; _layers = new List(); } /// /// Constructor /// /// /// public MapSelection(RuntimeMap map, string xml) : this(map) { LoadXml(xml); } /// /// Initialize this selection from the specified xml string /// /// public void LoadXml(string xml) { _layers.Clear(); System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); if (!string.IsNullOrEmpty(xml)) doc.LoadXml(xml); //There are two variations System.Xml.XmlNodeList lst = doc.SelectNodes("FeatureSet/Layer"); //NOXLATE if (lst.Count == 0) lst = doc.SelectNodes("FeatureInformation/FeatureSet/Layer"); //NOXLATE foreach (System.Xml.XmlNode n in lst) { if (n.Attributes["id"] != null) //NOXLATE { string guid = n.Attributes["id"].Value; //NOXLATE var l = _map.Layers.GetByObjectId(guid); if (l != null) { foreach (System.Xml.XmlNode c in n.SelectNodes("Class")) //NOXLATE { if (c.Attributes["id"] != null) //NOXLATE if (c.Attributes["id"].Value == l.QualifiedClassName) //NOXLATE _layers.Add(new LayerSelection(l, c.SelectNodes("ID"))); //NOXLATE } } } } } /// /// Returns an xml document that represents the current map selection /// /// An xml document that represents the current map selection public string ToXml() { System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); System.Xml.XmlNode root = doc.AppendChild(doc.CreateElement("FeatureSet")); //NOXLATE foreach (LayerSelection layer in _layers) { System.Xml.XmlNode ln = root.AppendChild(doc.CreateElement("Layer")); //NOXLATE ln.Attributes.Append(doc.CreateAttribute("id")).Value = layer.Layer.ObjectId; //NOXLATE System.Xml.XmlNode cn = ln.AppendChild(doc.CreateElement("Class")); //NOXLATE cn.Attributes.Append(doc.CreateAttribute("id")).Value = layer.Layer.QualifiedClassName; //NOXLATE for (int i = 0; i < layer.Count; i++) cn.AppendChild(doc.CreateElement("ID")).InnerText = layer.EncodeIDString(layer[i]); //NOXLATE } return doc.OuterXml; } /// /// Represents a layer selection /// public class LayerSelection : IList { private RuntimeMapLayer m_layer; private List m_list = new List(); /// /// Gets the layer that contains the selected objects /// public RuntimeMapLayer Layer { get { return m_layer; } } /// /// Internal helper to construct a LayerSelection /// /// The layer that the selection belongs to /// A list of xml <ID> nodes internal LayerSelection(RuntimeMapLayer layer, System.Xml.XmlNodeList ids) : this(layer) { foreach (System.Xml.XmlNode n in ids) Add(ParseIDString(n.InnerXml)); } /// /// Adds records from the specified reader into this selection /// /// The reader /// The maximum number of records to add. Specify -1 for all /// Number of records added public int AddFeatures(IReader reader, int limit) { int added = 0; if (limit < 0) { while (reader.ReadNext()) { AddFeature(reader); added++; } } else { while (reader.ReadNext() && added < limit) { AddFeature(reader); added++; } } reader.Close(); return added; } /// /// Adds the specified record to the selection /// /// public void AddFeature(IRecord record) { var idProps = m_layer.IdentityProperties; object[] values = new object[idProps.Length]; for (int i = 0; i < idProps.Length; i++) { var prop = idProps[i]; //Don't null check because identity property values cannot be null values[i] = record[prop.Name]; } Add(values); } /// /// Encodes the given combined keyset into an ID string for use in the Xml /// /// The combined key /// A base64 encoded ID string public string EncodeIDString(object[] values) { object[] tmp = NormalizeAndValidate(values); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { for (int i = 0; i < m_layer.IdentityProperties.Length; i++) { Type type = m_layer.IdentityProperties[i].Type; if (type == typeof(short)) { byte[] x = BitConverter.GetBytes((short)tmp[i]); ms.Write(x, 0, x.Length); } else if (type == typeof(int)) { byte[] x = BitConverter.GetBytes((int)tmp[i]); ms.Write(x, 0, x.Length); } else if (type == typeof(long)) { byte[] x = BitConverter.GetBytes((long)tmp[i]); ms.Write(x, 0, x.Length); } else if (type == typeof(double)) { byte[] x = BitConverter.GetBytes((double)tmp[i]); ms.Write(x, 0, x.Length); } else if (type == typeof(string)) { byte[] x = System.Text.Encoding.UTF8.GetBytes((string)tmp[i]); ms.Write(x, 0, x.Length); ms.WriteByte(0); } else throw new Exception(string.Format(Strings.ErrorUnsupportedPkType, type.ToString())); } return Convert.ToBase64String(ms.ToArray()); } } /// /// Parses a base64 encoded string with key values /// /// The base64 encoded ID string /// The composite value key public object[] ParseIDString(string id) { return m_layer.ParseSelectionValues(id); } /// /// Constructs a new LayerSelection with a number of selected featured /// /// The layer to represent /// The list of composite IDs that the layer supports public LayerSelection(RuntimeMapLayer layer, IEnumerable ids) : this(layer) { AddRange(ids); } /// /// Constructs a new LayerSelection with a number of selected featured /// /// The layer to represent public LayerSelection(RuntimeMapLayer layer) { if (layer == null) throw new ArgumentNullException("layer"); //NOXLATE if (layer.IdentityProperties.Length == 0 && layer.Parent.StrictSelection) throw new Exception(Strings.ErrorLayerHasNoPk); m_layer = layer; } /// /// Adds a composite key to the selection /// /// The composite key public void Add(object[] values) { object[] tmp = NormalizeAndValidate(values); if (!this.Contains(tmp)) m_list.Add(tmp); } /// /// Ensures that the composite key types match the layers ID column types. /// The returned array is a copy of the one passed in /// /// The composite key /// A copy of the composite key private object[] NormalizeAndValidate(object[] values) { if (values == null) throw new ArgumentNullException("values"); //NOXLATE if (values.Length != m_layer.IdentityProperties.Length) throw new Exception(string.Format(Strings.ErrorLayerKeyMismatch, m_layer.IdentityProperties.Length, values.Length)); object[] tmp = new object[values.Length]; for (int i = 0; i < values.Length; i++) { if (values[i] == null) throw new Exception(string.Format(Strings.ErrorNullKeyValue, m_layer.IdentityProperties[i].Name)); if (values[i].GetType() != m_layer.IdentityProperties[i].Type) try { tmp[i] = Convert.ChangeType(values[i], m_layer.IdentityProperties[i].Type); } catch (Exception ex) { throw new Exception(string.Format(Strings.ErrorFailedValueConversion, m_layer.IdentityProperties[i].Name, values[i].GetType(), m_layer.IdentityProperties[i].Type), ex); } else tmp[i] = values[i]; } return tmp; } /// /// Adds a number of composite keys /// /// A list of composite keys public void AddRange(IEnumerable lst) { foreach (object[] x in lst) Add(x); } #region IList Members /// /// Returns the index of the given composite key /// /// The composite key to look for /// The index of the composite key or -1 if the key is not found public int IndexOf(object[] item) { object[] tmp = NormalizeAndValidate(item); for (int i = 0; i < m_list.Count; i++) { object[] tmpx = m_list[i]; bool matches = true; for (int j = 0; j < tmpx.Length; j++) if (tmpx[j] != item[j]) { matches = false; break; } if (matches) return i; } return -1; } /// /// Inserts a key at the specified location /// /// The index to insert the key at /// The key to insert public void Insert(int index, object[] item) { object[] tmp = NormalizeAndValidate(item); int ix = IndexOf(tmp); if (ix >= 0) RemoveAt(ix); Insert(index, item); } /// /// Removes the element at the specified location /// /// The index of the item to remove public void RemoveAt(int index) { m_list.RemoveAt(index); } /// /// Gets or sets the composite key for the specified index /// /// The index for the composite key /// The composite key public object[] this[int index] { get { object[] tmp = new object[m_layer.IdentityProperties.Length]; Array.Copy(m_list[index], tmp, tmp.Length); return tmp; } set { m_list[index] = NormalizeAndValidate(value); } } #endregion #region ICollection Members /// /// Removes all composite keys from the collection /// public void Clear() { m_list.Clear(); } /// /// Returns a value indicating if the composite key is contained in the collection /// /// The composite key to look for /// True if the collection contains the composite key, false otherwise public bool Contains(object[] item) { return IndexOf(item) >= 0; } /// /// Not implemented /// /// /// public void CopyTo(object[][] array, int arrayIndex) { throw new NotImplementedException(); } /// /// Returns the number of composite keys (and thus selected objects) /// public int Count { get { return m_list.Count; } } /// /// Gets a value indicating if the collection is read-only /// public bool IsReadOnly { get { return false; } } /// /// Removes the given composite key from the collection /// /// The composite key to remove /// True if the composite key was found and removed, false otherwise public bool Remove(object[] item) { int ix = IndexOf(item); if (ix < 0) return false; m_list.RemoveAt(ix); return true; } #endregion #region IEnumerable Members /// /// Returns an enumerator for the collection /// /// An enumerator for the collection public IEnumerator GetEnumerator() { return m_list.GetEnumerator(); } #endregion #region IEnumerable Members /// /// Returns an enumerator for the collection /// /// An enumerator for the collection System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)m_list).GetEnumerator(); } #endregion } /// /// Serializes this instance using the specified serializer. /// /// The serializer. public void Serialize(MgBinarySerializer s) { var m_selection = new XmlDocument(); m_selection.LoadXml(ToXml()); if (m_selection["FeatureSet"] == null) //NOXLATE { s.Write((int)0); return; } XmlNodeList lst = m_selection["FeatureSet"].SelectNodes("Layer"); //NOXLATE s.Write(lst.Count); foreach (XmlNode n in lst) { if (n.Attributes["id"] == null) //NOXLATE throw new Exception(Strings.ErrorSelectedLayerHasNoId); s.Write(n.Attributes["id"].Value); //NOXLATE XmlNodeList cls = n.SelectNodes("Class"); //NOXLATE s.Write(cls.Count); foreach (XmlNode c in cls) { s.Write(c.Attributes["id"].Value); //NOXLATE XmlNodeList ids = c.SelectNodes("ID"); //NOXLATE s.Write(ids.Count); foreach (XmlNode id in ids) s.Write(id.InnerText); } } } /// /// Deserializes this object using the specified deserializer. /// /// The deserializer. public void Deserialize(MgBinaryDeserializer d) { XmlDocument doc = new XmlDocument(); XmlNode root = doc.AppendChild(doc.CreateElement("FeatureSet")); //NOXLATE int layerCount = d.ReadInt32(); for (int i = 0; i < layerCount; i++) { XmlNode layer = root.AppendChild(doc.CreateElement("Layer")); //NOXLATE layer.Attributes.Append(doc.CreateAttribute("id")).Value = d.ReadString(); //NOXLATE int classCount = d.ReadInt32(); for (int j = 0; j < classCount; j++) { XmlNode @class = layer.AppendChild(doc.CreateElement("Class")); //NOXLATE @class.Attributes.Append(doc.CreateAttribute("id")).Value = d.ReadString(); //NOXLATE int idCount = d.ReadInt32(); for (int k = 0; k < idCount; k++) @class.AppendChild(doc.CreateElement("ID")).InnerText = d.ReadString(); //NOXLATE } } LoadXml(doc.OuterXml); } #region IList Members /// /// Returns the index of the given layer /// /// The layer to look for /// The index of the layer, or -1 if the layer is not in the collection public int IndexOf(MapSelection.LayerSelection item) { return IndexOf(item.Layer); } /// /// Returns the index of the given layer /// /// The layer. /// /// The index of the layer, or -1 if the layer is not in the collection /// public int IndexOf(RuntimeMapLayer layer) { for (int i = 0; i < _layers.Count; i++) if (_layers[i].Layer.ObjectId == layer.ObjectId) return i; return -1; } /// /// Inserts a selection layer into the collection /// /// The index to place the item at /// The item to insert public void Insert(int index, MapSelection.LayerSelection item) { _layers.Insert(index, item); } /// /// Inserts a selection layer into the collection /// /// The index to place the item at /// The layer. public void Insert(int index, RuntimeMapLayer layer) { _layers.Insert(index, new LayerSelection(layer)); } /// /// Removes the item at the given index /// /// The index to remove the item at public void RemoveAt(int index) { _layers.RemoveAt(index); } /// /// Gets or sets the selection layer at a given index /// /// The index to get or set the item for /// The item at the given index public MapSelection.LayerSelection this[int index] { get { return _layers[index]; } set { if (value == null) throw new ArgumentNullException(); _layers[index] = value; } } /// /// Gets the selection layer at a given index /// /// The index to get or set the item for /// The item at the given index public MapSelection.LayerSelection this[RuntimeMapLayer index] { get { return _layers[IndexOf(index)]; } } #endregion #region ICollection Members /// /// Adds the specified layer selection /// /// public void Add(MapSelection.LayerSelection item) { if (item == null) throw new ArgumentNullException(); _layers.Add(item); } /// /// Adds the specified layer /// /// public void Add(RuntimeMapLayer layer) { if (!Contains(layer)) { var sel = new LayerSelection(layer); Add(sel); } } /// /// Clears this selction /// public void Clear() { _layers.Clear(); } /// /// Gets whether this selection contains the specified layer /// /// /// public bool Contains(RuntimeMapLayer item) { return IndexOf(item) >= 0; } /// /// Gets whether this selection contains the specified layer selection /// /// /// public bool Contains(MapSelection.LayerSelection item) { return IndexOf(item) >= 0; } /// /// Copies the elements of the to an , starting at a particular index. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// /// is null. /// /// /// /// is less than 0. /// /// /// /// is multidimensional. /// -or- /// is equal to or greater than the length of . /// -or- /// The number of elements in the source is greater than the available space from to the end of the destination . /// public void CopyTo(MapSelection.LayerSelection[] array, int arrayIndex) { throw new NotImplementedException(); } /// /// Gets the number of layers in this selection /// public int Count { get { return _layers.Count; } } /// /// Gets whether this is read only /// public bool IsReadOnly { get { return false; } } /// /// Removes the specified layer selection /// /// /// public bool Remove(MapSelection.LayerSelection item) { int ix = IndexOf(item); if (ix < 0) return false; _layers.RemoveAt(ix); return true; } #endregion #region IEnumerable Members /// /// Gets the layer selection enumerator /// /// public IEnumerator GetEnumerator() { return _layers.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return ((System.Collections.IEnumerable)_layers).GetEnumerator(); } #endregion } }