// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk) // // This file is part of SharpMap. // SharpMap is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // SharpMap is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License // along with SharpMap; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Globalization; using System.IO; using System.Runtime.Serialization; using System.Xml; using System.Xml.Schema; using Core.GIS.GeoAPI.Extensions.Feature; using Core.GIS.GeoAPI.Geometries; namespace Core.GIS.SharpMap.Data { /// /// Represents an in-memory cache of spatial data. The FeatureDataSet is an extension of System.Data.DataSet /// [Serializable()] public class FeatureDataSet : DataSet { /// /// Initializes a new instance of the FeatureDataSet class. /// public FeatureDataSet() { InitClass(); CollectionChangeEventHandler schemaChangedHandler = new CollectionChangeEventHandler(SchemaChanged); //this.Tables.CollectionChanged += schemaChangedHandler; Relations.CollectionChanged += schemaChangedHandler; InitClass(); } /// /// nitializes a new instance of the FeatureDataSet class. /// /// serialization info /// streaming context protected FeatureDataSet(SerializationInfo info, StreamingContext context) { string strSchema = ((string) (info.GetValue("XmlSchema", typeof(string)))); if ((strSchema != null)) { DataSet ds = new DataSet(); ds.ReadXmlSchema(new XmlTextReader(new StringReader(strSchema))); if ((ds.Tables["FeatureTable"] != null)) { Tables.Add(new FeatureDataTable(ds.Tables["FeatureTable"])); } DataSetName = ds.DataSetName; Prefix = ds.Prefix; Namespace = ds.Namespace; Locale = ds.Locale; CaseSensitive = ds.CaseSensitive; EnforceConstraints = ds.EnforceConstraints; Merge(ds, false, MissingSchemaAction.Add); } else { InitClass(); } GetSerializationData(info, context); CollectionChangeEventHandler schemaChangedHandler = new CollectionChangeEventHandler(SchemaChanged); //this.Tables.CollectionChanged += schemaChangedHandler; Relations.CollectionChanged += schemaChangedHandler; } /// /// Gets the collection of tables contained in the FeatureDataSet /// public new FeatureTableCollection Tables { get; private set; } /// /// Copies the structure of the FeatureDataSet, including all FeatureDataTable schemas, relations, and constraints. Does not copy any data. /// /// public new FeatureDataSet Clone() { FeatureDataSet cln = ((FeatureDataSet) (base.Clone())); return cln; } /// /// Gets a value indicating whether Tables property should be persisted. /// /// protected override bool ShouldSerializeTables() { return false; } /// /// Gets a value indicating whether Relations property should be persisted. /// /// protected override bool ShouldSerializeRelations() { return false; } /// /// /// /// protected override void ReadXmlSerializable(XmlReader reader) { Reset(); DataSet ds = new DataSet(); ds.ReadXml(reader); //if ((ds.Tables["FeatureTable"] != null)) //{ // this.Tables.Add(new FeatureDataTable(ds.Tables["FeatureTable"])); //} DataSetName = ds.DataSetName; Prefix = ds.Prefix; Namespace = ds.Namespace; Locale = ds.Locale; CaseSensitive = ds.CaseSensitive; EnforceConstraints = ds.EnforceConstraints; Merge(ds, false, MissingSchemaAction.Add); } /// /// /// /// protected override XmlSchema GetSchemaSerializable() { MemoryStream stream = new MemoryStream(); WriteXmlSchema(new XmlTextWriter(stream, null)); stream.Position = 0; return XmlSchema.Read(new XmlTextReader(stream), null); } private void InitClass() { Tables = new FeatureTableCollection(); //this.DataSetName = "FeatureDataSet"; Prefix = ""; Namespace = "http://tempuri.org/FeatureDataSet.xsd"; Locale = new CultureInfo("en-US"); CaseSensitive = false; EnforceConstraints = true; } private bool ShouldSerializeFeatureTable() { return false; } private void SchemaChanged(object sender, CollectionChangeEventArgs e) { if ((e.Action == CollectionChangeAction.Remove)) { //this.InitVars(); } } } /// /// Represents the method that will handle the RowChanging, RowChanged, RowDeleting, and RowDeleted events of a FeatureDataTable. /// /// /// public delegate void FeatureDataRowChangeEventHandler(object sender, FeatureDataRowChangeEventArgs e); /// /// Represents one feature table of in-memory spatial data. /// //[System.Diagnostics.DebuggerStepThrough()] [Serializable()] public class FeatureDataTable : DataTable, IList, IEnumerable { /// /// Occurs after a FeatureDataRow has been changed successfully. /// public event FeatureDataRowChangeEventHandler FeatureDataRowChanged; /// /// Occurs when a FeatureDataRow is changing. /// public event FeatureDataRowChangeEventHandler FeatureDataRowChanging; /// /// Occurs after a row in the table has been deleted. /// public event FeatureDataRowChangeEventHandler FeatureDataRowDeleted; /// /// Occurs before a row in the table is about to be deleted. /// public event FeatureDataRowChangeEventHandler FeatureDataRowDeleting; /// /// Occurs after new geometry has been set to a feature data row. /// public event FeatureDataRowChangeEventHandler FeatureDataRowGeometryChanged; /// /// Initializes a new instance of the FeatureDataTable class with no arguments. /// public FeatureDataTable() { InitClass(); } /// /// Intitalizes a new instance of the FeatureDataTable class with the specified table name. /// /// Todo: This is misleading, since the variable supplied is a table and not a tablename. /// /// public FeatureDataTable(DataTable table) : base(table.TableName) { if (table.DataSet != null) { if ((table.CaseSensitive != table.DataSet.CaseSensitive)) { CaseSensitive = table.CaseSensitive; } if ((table.Locale.ToString() != table.DataSet.Locale.ToString())) { Locale = table.Locale; } if ((table.Namespace != table.DataSet.Namespace)) { Namespace = table.Namespace; } } Prefix = table.Prefix; MinimumCapacity = table.MinimumCapacity; DisplayExpression = table.DisplayExpression; } /// /// Gets the feature data row at the specified index /// /// row index /// FeatureDataRow public object this[int index] { get { return Rows[index]; } set { throw new NotImplementedException(); } } /// /// Gets the number of rows in the table /// [Browsable(false)] public int Count { get { return Rows.Count; } } public object SyncRoot { get { return Rows.SyncRoot; } } public bool IsSynchronized { get { return Rows.IsSynchronized; } } public bool IsReadOnly { get { return Rows.IsReadOnly; } } public bool IsFixedSize { get { return false; } } /// /// Adds a row to the FeatureDataTable /// /// public void AddRow(FeatureDataRow row) { Rows.Add(row); } /// /// Clones the structure of the FeatureDataTable, including all FeatureDataTable schemas and constraints. /// /// public new FeatureDataTable Clone() { FeatureDataTable clone = ((FeatureDataTable) (base.Clone())); clone.InitVars(); return clone; } /// /// Creates a new FeatureDataRow with the same schema as the table. /// /// public new FeatureDataRow NewRow() { var newRow = (FeatureDataRow) base.NewRow(); newRow.Attributes = new FeatureDataRowAttributeAccessor(newRow); return newRow; } ///// ///// Gets the collection of rows that belong to this table. ///// //public new DataRowCollection Rows //{ // get { throw (new NotSupportedException()); } // set { throw (new NotSupportedException()); } //} /// /// Removes the row from the table /// /// Row to remove public void RemoveRow(FeatureDataRow row) { Rows.Remove(row); } IEnumerator IEnumerable.GetEnumerator() { foreach (var feature in Rows) { yield return (IFeature) feature; } } public int Add(object item) { if (item is FeatureDataRow) { Rows.Add(item); return Count - 1; } throw new NotImplementedException(); } public bool Contains(object item) { return Rows.Contains(item); } public void CopyTo(Array array, int arrayIndex) { Rows.CopyTo(array, arrayIndex); } public void Remove(object item) { Rows.Remove((DataRow) item); } public int IndexOf(object item) { return Rows.IndexOf((DataRow) item); } public void Insert(int index, object item) { if (item is FeatureDataRow) { Rows.InsertAt((DataRow) item, index); } throw new NotSupportedException(); } public void RemoveAt(int index) { Rows.RemoveAt(index); } /// /// Returns an enumerator for enumering the rows of the FeatureDataTable /// /// public IEnumerator GetEnumerator() { return Rows.GetEnumerator(); } /// /// /// /// protected override DataTable CreateInstance() { return new FeatureDataTable(); } /// /// Creates a new FeatureDataRow with the same schema as the table, based on a datarow builder /// /// /// protected override DataRow NewRowFromBuilder(DataRowBuilder builder) { var newRow = new FeatureDataRow(builder); newRow.Attributes = new FeatureDataRowAttributeAccessor(newRow); return newRow; } /// /// /// /// protected override Type GetRowType() { return typeof(FeatureDataRow); } /// /// Raises the FeatureDataRowChanged event. /// /// protected override void OnRowChanged(DataRowChangeEventArgs e) { base.OnRowChanged(e); if ((FeatureDataRowChanged != null)) { FeatureDataRowChanged(this, new FeatureDataRowChangeEventArgs(((FeatureDataRow) (e.Row)), e.Action)); } } /// /// Raises the FeatureDataRowChanging event. /// /// protected override void OnRowChanging(DataRowChangeEventArgs e) { base.OnRowChanging(e); if ((FeatureDataRowChanging != null)) { FeatureDataRowChanging(this, new FeatureDataRowChangeEventArgs(((FeatureDataRow) (e.Row)), e.Action)); } } /// /// Raises the FeatureDataRowDeleted event /// /// protected override void OnRowDeleted(DataRowChangeEventArgs e) { base.OnRowDeleted(e); if ((FeatureDataRowDeleted != null)) { FeatureDataRowDeleted(this, new FeatureDataRowChangeEventArgs(((FeatureDataRow) (e.Row)), e.Action)); } } /// /// Raises the FeatureDataRowDeleting event. /// /// protected override void OnRowDeleting(DataRowChangeEventArgs e) { base.OnRowDeleting(e); if ((FeatureDataRowDeleting != null)) { FeatureDataRowDeleting(this, new FeatureDataRowChangeEventArgs(((FeatureDataRow) (e.Row)), e.Action)); } } internal void InitVars() { //this.columnFeatureGeometry = this.Columns["FeatureGeometry"]; } internal void OnFeatureDataRowGeometryChanged(FeatureDataRowChangeEventArgs e) { if (FeatureDataRowGeometryChanged != null) { FeatureDataRowGeometryChanged(this, e); } } private void InitClass() { //this.columnFeatureGeometry = new DataColumn("FeatureGeometry", typeof(SharpMap.Geometries.Geometry), null, System.Data.MappingType.Element); //this.Columns.Add(this.columnFeatureGeometry); } } /// /// Represents the collection of tables for the FeatureDataSet. /// [Serializable()] public class FeatureTableCollection : List {} /// /// Occurs after a FeatureDataRow has been changed successfully. /// [DebuggerStepThrough()] public class FeatureDataRowChangeEventArgs : EventArgs { /// /// Initializes a new instance of the FeatureDataRowChangeEventArgs class. /// /// /// public FeatureDataRowChangeEventArgs(FeatureDataRow row, DataRowAction action) { Row = row; Action = action; } /// /// Gets the row upon which an action has occurred. /// public FeatureDataRow Row { get; private set; } /// /// Gets the action that has occurred on a FeatureDataRow. /// public DataRowAction Action { get; private set; } // TODO: make remember all row / feature including attributes. // Maybe combine with ADO.NET RowChanged event if it uses memento for changed rows public IGeometry OldGeometry { get; set; } } }