// 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; }
}
}