Why don't you write a custom TreeModel? I have written one for
DataTables and am testing another one for DataViews(attached, to display
data tables pass the default view of the table: table.DefaultView).
Forget about storing data at two locations in the memory, this will only
cause trouble and performance issues :-)

A good tutorial is available at
http://www.mono-project.com/ImplementingGInterfaces. Hoewever,
GInterface implementation was introduced in Gtk# 2.12 so you might need
to update your installation.
So the question is... in your opinion what is the best way to save the values from a TreeStore in a database and retrieve them again through SQL and maintain the intended parent/child relationship.

This maybe simple and I just missed it.
Thanks for your help
Andy


_______________________________________________
Gtk-sharp-list maillist  -  Gtk-sharp-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list



// DataViewStore.cs
//
//  Copyright (C) 2008 Christian Hoff
//
// This library 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.1 of the License, or (at your option) any later version.
//
// This library 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 this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 

namespace Bestandsverwaltung.DataWidgets.DataTable
{
	public class DataViewStore : GLib.Object, Gtk.TreeModelImplementor
	{
		public DataViewStore (System.Data.DataView DataView)
		{
			if (DataView == null)
				throw (new System.ArgumentNullException ("DataView"));
			
			_dataView = DataView;
			_dataView.ListChanged += this.DataView_ListChanged;
			
			// Create a random stamp for the iters
			System.Random RandomStampGen = new System.Random ();
			this.Stamp = RandomStampGen.Next (System.Int32.MinValue, System.Int32.MaxValue);
			
			_adapter = new Gtk.TreeModelAdapter (this);
		}
		
		// Properties
		
		public readonly int Stamp;
		
		private System.Data.DataView _dataView;
		public System.Data.DataView DataView
		{
			get {
				return _dataView;
			}
		}
		
		private Gtk.TreeModelAdapter _adapter;
		public Gtk.TreeModelAdapter Adapter
		{
			get {
				return _adapter;
			}
		}
		
		public Gtk.TreeModelFlags Flags
		{
			get {
				return Gtk.TreeModelFlags.ListOnly | Gtk.TreeModelFlags.ItersPersist;
			}
		}
		
		public int NColumns
		{
			get {
				return _dataView.Table.Columns.Count;
			}
		}
		
		
		// Methods
		
#region Gtk.TreeIter handling
		private System.Collections.Generic.List<System.Runtime.InteropServices.GCHandle> _rowHandles = new System.Collections.Generic.List<System.Runtime.InteropServices.GCHandle> ();
		
		public override void Dispose ()
		{
			// Free all the GCHandles pointing to the iters since they won't be garbage collected
			foreach (System.Runtime.InteropServices.GCHandle handle in _rowHandles)
				handle.Free ();
			
			base.Dispose ();
		}
		
		public Gtk.TreeIter IterFromRow (System.Data.DataRowView row)
		{
			Gtk.TreeIter result = Gtk.TreeIter.Zero;
			IterFromRow (row, ref result);
			
			return result;
		}
		
		private void IterFromRow (System.Data.DataRowView row, ref Gtk.TreeIter iter)
		{
			System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.Alloc (row);
			
			iter.UserData = (System.IntPtr) gch;
			iter.Stamp = this.Stamp;
			
			_rowHandles.Add (gch);
		}
		
		public System.Data.DataRowView RowFromIter (Gtk.TreeIter iter)
		{
			if (iter.Stamp != this.Stamp)
				throw (new System.InvalidOperationException (System.String.Format ("iter belongs to a different model; it's stamp is not equal to the stamp of this model({0})", this.Stamp.ToString ())));
			
			if (iter.UserData == System.IntPtr.Zero)
				throw (new System.InvalidOperationException ("iter does not contain any row information"));
			
			System.Runtime.InteropServices.GCHandle gch = (System.Runtime.InteropServices.GCHandle) iter.UserData;
			return gch.Target as System.Data.DataRowView;
		}
#endregion
		
#region TreePath handling
		public Gtk.TreePath GetPath (Gtk.TreeIter iter)
		{
			return PathFromRow (RowFromIter (iter));
		}
		
		public Gtk.TreePath PathFromRow (System.Data.DataRowView row)
		{
			System.Int32 index = IndexFromRow (row);
			if (index == -1)
				return null;
			
			Gtk.TreePath path = new Gtk.TreePath ();
			path.AppendIndex (index);
			
			return path;
		}
		
		public int IndexFromRow (System.Data.DataRowView row)
		{
			// Let's see how this works, but this should return the expected results
			// If it does, I'm the first to find this solution(I have googled hours in the web and found nothing)
			return (_dataView as System.Collections.IList).IndexOf (row);
		}
		
		public bool GetIter (out Gtk.TreeIter iter, Gtk.TreePath path)
		{
			iter = Gtk.TreeIter.Zero;
			
			if (path.Indices.Length != 1)
				return false;
			
			int index = path.Indices [0];
			if (index >= _dataView.Count)
				return false;
			
			IterFromRow (_dataView [index], ref iter);
			return true;
		}
#endregion
		
#region get/set model data
		/* NOTE: Do not use this method from managed code. The reconversion into a System.type will fail for any non-primitive data types
		*  Use GetColumnSystemType instead
		*/
		public GLib.GType GetColumnType (int column)
		{
			return (GLib.GType) GetColumnSystemType (column);
		}
		
		public System.Type GetColumnSystemType (int column)
		{
			return _dataView.Table.Columns [column].DataType;
		}
		
		public void GetValue (Gtk.TreeIter iter, int column, ref GLib.Value val)
		{
			val.Init (GetColumnType (column));
			val.Val = GetValue (iter, column);
		}
		
		public System.Object GetValue (Gtk.TreeIter iter, int column)
		{
			return RowFromIter (iter) [column];
		}
		
		public void SetValue (Gtk.TreeIter iter, int column, object val)
		{
			RowFromIter (iter) [column] = val;
		}
#endregion
		
		public System.Boolean GetIterFirst (out Gtk.TreeIter iter)
		{
			if (_dataView.Count == 0) {
				iter = Gtk.TreeIter.Zero;
				return false;
			} else {
				iter = IterFromRow (_dataView [0]);
				return true;
			}
		}
		
		public bool IterNext (ref Gtk.TreeIter iter)
		{
			int NewIndex = IndexFromRow (RowFromIter (iter)) + 1;
			if (NewIndex >= _dataView.Count)
				return false;
			
			IterFromRow (_dataView [NewIndex], ref iter);
			return true;
		}
		
		public int IterNChildren (Gtk.TreeIter iter)
		{
			// List-only model
			if (iter.UserData == System.IntPtr.Zero)
				return _dataView.Count;
			else
				return 0;
		}
		
		public bool IterHasChild (Gtk.TreeIter iter)
		{
			return IterNChildren (iter) != 0;
		}
		
		public bool IterNthChild (out Gtk.TreeIter child, Gtk.TreeIter parent, int index)
		{
			if (parent.UserData == System.IntPtr.Zero) {
				child = IterFromRow (_dataView [index]);
				return true;
			} else {
				// List-only model
				child = Gtk.TreeIter.Zero;
				return false;
			}
		}
		
		// child: first child iter of parent
		public System.Boolean IterChildren (out Gtk.TreeIter child, Gtk.TreeIter parent)
		{
			if (parent.UserData == System.IntPtr.Zero)
				return GetIterFirst (out child);
			
			child = Gtk.TreeIter.Zero;
			return false;
		}
		
		public System.Boolean IterParent (out Gtk.TreeIter parent, Gtk.TreeIter child)
		{
			// List-only model
			parent = Gtk.TreeIter.Zero;
			return false;
		}
		
		public void RefNode (Gtk.TreeIter iter)
		{
		}
		
		public void UnrefNode (Gtk.TreeIter iter)
		{
		}
		
		// Event handling
		
		private void DataView_ListChanged (System.Object o, System.ComponentModel.ListChangedEventArgs e)
		{
			switch (e.ListChangedType) {
			case System.ComponentModel.ListChangedType.ItemAdded:
				_adapter.EmitRowInserted (new Gtk.TreePath (new int[1] {e.NewIndex}), IterFromRow (_dataView [e.NewIndex]));
				break;
			case System.ComponentModel.ListChangedType.ItemDeleted:
				_adapter.EmitRowDeleted (new Gtk.TreePath (new int[1] {e.OldIndex}));
				break;
			case System.ComponentModel.ListChangedType.ItemChanged:
				_adapter.EmitRowChanged (new Gtk.TreePath (new int[1] {e.NewIndex}), IterFromRow (_dataView [e.NewIndex]));
				break;
			case System.ComponentModel.ListChangedType.ItemMoved:
				// TODO: File a Gtk# bug report (why is the integer array an out param????)
				_adapter.EmitRowsReordered (null, Gtk.TreeIter.Zero);
				break;
			case System.ComponentModel.ListChangedType.Reset:
				throw (new System.NotImplementedException ());
			}
		}
	}
}

_______________________________________________
Gtk-sharp-list maillist  -  Gtk-sharp-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list

Reply via email to