I have written a custom TreeModel to display DataTables. With this one it should be easy to display a DataTable in a Gtk.TreeView or any other widget you want. Maybe it's even compatible with the Medsphere widget. However, I had to make use of GInterface implementation which is only supported in Gtk# 2.12 (see http://www.mono-project.com/ImplementingGInterfaces)

Mike, how about adding a custom tree model to display DataTables to Gtk.DotNet? I think this could really be a useful feature since Gtk# completly lacks support for DataTables. I would volunteer to start working on it if you want.

Christian
On Mon, 2008-07-21 at 04:11 -0700, Brett Senior wrote:
I have an application that I am converting from MS/VS/VB to
MonoDevelop/C#.  This application makes use of the data grid control
and I have not found a similar concept in GTK#.  Is there such a
widget ?  At the moment the version of MD I am running uses GTK# 2.10
- I have 2.12 on my machine but am not sure if this supports a
datagrid - as if this is the case then I can simply wait for a later
release of MD.  If such a widget does not exist then do you know of
any that can be downloaded and used ?


<http://www.medsphere.org/projects/widgets/wiki/GridView>

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


// DataTableStore.cs
// 
// Copyright (C) 2008 Christian Hoff
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

namespace Bestandsverwaltung.DataWidgets.DataTable
{
        public class DataTableStore : GLib.Object, Gtk.TreeModelImplementor
        {
                // A custom TreeModel to display DataTables
                
                private Gtk.TreeModelAdapter pAdapter;
                protected System.Data.DataTable table;
                public readonly System.Int32 Stamp;
                
                public DataTableStore (System.Data.DataTable tbl) : base() {
                        if(tbl == null)
                                throw (new System.ArgumentNullException 
("tbl"));
                        
                        table = tbl;
                        table.RowChanged += this.Row_Changed;
                        table.RowDeleted += this.Row_Changed;
                        table.RowDeleting += this.Row_Changing;
                        table.TableCleared += new 
System.Data.DataTableClearEventHandler (this.Table_Cleared);
                        
                        
                        // Create a random stamp for the iters
                        System.Random RandomStampGen = new System.Random ();
                        Stamp = RandomStampGen.Next (System.Int32.MinValue, 
System.Int32.MaxValue);
                        pAdapter = new Gtk.TreeModelAdapter (this);
                }
                
                public Gtk.TreeModelAdapter Adapter {
                        get {
                                return pAdapter;
                        }
                }
                
                public System.Data.DataRow GetRowAtPath (Gtk.TreePath path) {
                        switch (path.Indices.Length) {
                        case 0:
                                return null;
                        case 1:
                                return table.Rows [path.Indices [0]];
                        default:
                                // Model is list-only; there are no child iters
                                throw (new System.ArgumentOutOfRangeException 
("path"));
                        }
                }

                public Gtk.TreeModelFlags Flags {
                        get {
                                return Gtk.TreeModelFlags.ListOnly;
                                // return Gtk.TreeModelFlags.ItersPersist;
                        }
                }
                
                public System.Int32 NColumns {
                        get {
                                return table.Columns.Count;
                        }
                }
                
                // Problem: the conversion to a GType will fail with any 
non-value types derived from System.Object(except string)
                // Therefore, I added another function which returns a 
System.Type
                // TODO: Maybe file a bug report and provide a patch
                public GLib.GType GetColumnType (System.Int32 col) {
                        // System.Console.WriteLine("Column index: {0}, type: 
{1}", col.ToString(), type.ToString());
                        return (GLib.GType) table.Columns[col].DataType;
                }
                
                public System.Type GetColumnSystemType (System.Int32 col) {
                        return table.Columns[col].DataType;
                }
                
                public System.String GetColumnTitle(System.Int32 col) {
                        if(col < table.Columns.Count) {
                                return table.Columns[col].Caption;
                        } else {
                                throw(new 
System.ArgumentOutOfRangeException("col"));
                        }
                }
                
                public Gtk.TreeIter IterFromRow (System.Data.DataRow row) {
                        System.Runtime.InteropServices.GCHandle gch;

                        gch = System.Runtime.InteropServices.GCHandle.Alloc 
(row);
                        Gtk.TreeIter result = Gtk.TreeIter.Zero;
                        result.UserData = (System.IntPtr) gch;
                        result.Stamp = this.Stamp;
                        
                        return result;
                }
                
                public System.Data.DataRow 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.Exception ("iter is 
Gtk.TreeIter.Zero"));
                        
                        System.Runtime.InteropServices.GCHandle gch = 
(System.Runtime.InteropServices.GCHandle) iter.UserData;
                        return gch.Target as System.Data.DataRow;
                }
                
                private Gtk.TreePath PathFromRow (System.Data.DataRow row) {
                        if (row == null) {
                                return null;
                        } else {
                                Gtk.TreePath path = new Gtk.TreePath ();
                                path.AppendIndex (table.Rows.IndexOf (row));
                                return path;
                        }
                }
                
                public System.Boolean GetIter (out Gtk.TreeIter iter, 
Gtk.TreePath path) {
                        if (path == null)
                                throw new System.ArgumentNullException ("path");

                        iter = Gtk.TreeIter.Zero;
                        System.Data.DataRow row;
                        try {
                                row = GetRowAtPath (path);
                        } catch {
                                return false;
                        }
                        if (row == null)
                                return false;
                        
                        iter = IterFromRow (row);
                        return true;
                }

                public Gtk.TreePath GetPath (Gtk.TreeIter iter) {
                        System.Data.DataRow row = RowFromIter (iter);
                        
                        return PathFromRow (row);
                }
                
                public System.Data.DataColumn GetColumn(System.Int32 
ColumnIndex) {
                        return table.Columns [ColumnIndex];
                }
                
                // col: zero-based index of the column
                public void GetValue (Gtk.TreeIter iter, System.Int32 col, ref 
GLib.Value val) {
                        val = new GLib.Value (GetValue (iter, col));
                }
                
                public System.Object GetValue(Gtk.TreeIter iter, System.Int32 
col) {
                        System.Data.DataRow row = RowFromIter (iter);
                        if (row == null) {
                                throw(new System.ArgumentException ("The iter 
is pointing to a row that is NULL"));
                        } else {
                                return row [col];
                        }
                }
                
                public void SetValue (Gtk.TreeIter iter, System.Int32 column, 
System.Object val) {
                        RowFromIter (iter) [column] = val;
                }
                
                public System.Boolean GetIterFirst (out Gtk.TreeIter iter) {
                        if(table.Rows.Count == 0) {
                                iter = Gtk.TreeIter.Zero;
                                return false;
                        } else {
                                iter = IterFromRow (table.Rows[0]);
                                return true;
                        }
                }

                public System.Boolean IterNext (ref Gtk.TreeIter iter) {
                        System.Data.DataRow row = RowFromIter (iter);
                        
                        if (row == null) {
                                return false;
                        } else {
                                System.Int32 index = table.Rows.IndexOf (row);
                                
                                if(index + 1 < table.Rows.Count - 1) {
                                        // Return next row
                                        iter = IterFromRow (table.Rows [index + 
1]);
                                        return true;
                                } else {
                                        // No rows remaining
                                        return false;
                                }
                        }
                }
                
                // DataTableStore is list-only
                public System.Int32 ChildCount (System.Data.DataRow row) {
                        return 0;
                }
                
                // Child: first child iter of parent
                // @return: failure: false, otherwise; true
                public System.Boolean IterChildren (out Gtk.TreeIter child, 
Gtk.TreeIter parent)
                {
                        child = Gtk.TreeIter.Zero;
                        
                        if (parent.UserData == System.IntPtr.Zero) {
                                if(table.Rows.Count == 0) {
                                        return false;
                                } else {
                                        child = IterFromRow (table.Rows[0]);
                                        return true;
                                }
                        } else {
                                // List-only model
                                return false;
                        }
                }

                public System.Boolean IterHasChild (Gtk.TreeIter iter)
                {
                        // List-only model
                        if (IterNChildren(iter) == 0) {
                                return false;
                        } else {
                                return true;
                        }
                }

                public System.Int32 IterNChildren (Gtk.TreeIter iter)
                {
                        // List-only model
                        if (iter.UserData == System.IntPtr.Zero) {
                                return table.Rows.Count;
                        } else {
                                return 0;
                        }
                }
                
                // According to the Mono docs, index should be zero-based
                public System.Boolean IterNthChild (out Gtk.TreeIter child, 
Gtk.TreeIter parent, System.Int32 index)
                {
                        if (parent.UserData == System.IntPtr.Zero) {
                                child = IterFromRow (table.Rows [index]);
                                return true;
                        } else {
                                // List-only model
                                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) {
                }
                
                public System.Data.DataTable Table {
                        get {
                                return table;
                        }
                }
                
                public System.Data.DataColumn[] 
GetRelatedColumns(System.Int32[] ColIndices) {
                        System.Data.DataColumn[] SrcCols = new 
System.Data.DataColumn[ColIndices.GetLength(0)];
                        for(System.Int32 ColumnIndex = 0; ColumnIndex <= 
ColIndices.GetUpperBound(0); ColumnIndex++) {
                                SrcCols[ColumnIndex] = 
table.Columns[ColIndices[ColumnIndex]];
                        }
                        return GetRelatedColumns(SrcCols);
                }
                
                public System.Data.DataColumn[] 
GetRelatedColumns(System.Data.DataColumn[] SrcCols) {
                        System.Data.DataSet ds = table.DataSet;
                        System.Collections.Generic.List<System.Data.DataColumn> 
DestColumns = new System.Collections.Generic.List<System.Data.DataColumn>();
                        
                        foreach(System.Data.DataRelation rel in ds.Relations) {
                                foreach(System.Data.DataColumn col1 in 
rel.ChildColumns) {
                                        foreach(System.Data.DataColumn col2 in 
SrcCols) {
                                                if(col1 == col2) {
                                                        
foreach(System.Data.DataColumn col in rel.ParentColumns) {
                                                                
DestColumns.Add(col);
                                                        }
                                                }
                                        }
                                }
                                
                                foreach(System.Data.DataColumn col1 in 
rel.ParentColumns) {
                                        foreach(System.Data.DataColumn col2 in 
SrcCols) {
                                                if(col1 == col2) {
                                                        
foreach(System.Data.DataColumn col in rel.ChildColumns) {
                                                                
DestColumns.Add(col);
                                                        }
                                                }
                                        }
                                }
                        }
                        return DestColumns.ToArray();
                }
                
                // Event handlers
                private 
System.Collections.Generic.Dictionary<System.Data.DataRow, Gtk.TreePath> 
RowsToBeDeleted = new 
System.Collections.Generic.Dictionary<System.Data.DataRow, Gtk.TreePath> ();
                
                private void Row_Changing (System.Object o, 
System.Data.DataRowChangeEventArgs e) {
                        if ((e.Action & System.Data.DataRowAction.Delete) == 
System.Data.DataRowAction.Delete)
                                RowsToBeDeleted.Add (e.Row, PathFromRow 
(e.Row));
                        System.Console.WriteLine ("Note: Action {0} is 
performed in DataTable", e.Action.ToString ());
                }
                
                private void Row_Changed(System.Object obj, 
System.Data.DataRowChangeEventArgs e) {
                        if ((e.Action & System.Data.DataRowAction.Add) == 
System.Data.DataRowAction.Add)
                                pAdapter.EmitRowInserted (PathFromRow (e.Row), 
IterFromRow (e.Row));
                        else if ((e.Action & System.Data.DataRowAction.Change) 
== System.Data.DataRowAction.Change)
                                pAdapter.EmitRowChanged (PathFromRow (e.Row), 
IterFromRow (e.Row));
                        else if ((e.Action & System.Data.DataRowAction.Delete) 
== System.Data.DataRowAction.Delete) {
                                Gtk.TreePath delPath = RowsToBeDeleted [e.Row];
                                System.Console.WriteLine ("Removed row, path: 
{0}", delPath.Indices [0]);
                                RowsToBeDeleted.Remove (e.Row);
                                pAdapter.EmitRowDeleted (delPath);
                                
                                foreach (Gtk.TreePath currPath in 
RowsToBeDeleted.Values) {
                                        System.Console.WriteLine ("Looking for 
a TreePath to be changed");
                                        if (currPath.Indices [0] > 
delPath.Indices [0]) {
                                                if (!currPath.Prev ())
                                                        throw (new 
System.ApplicationException ("Moving TreePath to previous element failed"));
                                                
                                        }
                                }
                                delPath.Dispose ();
                        } else
                                System.Console.WriteLine ("Note: Unhandled 
action {0} performed in DataTable", e.Action.ToString ());
                }
                
                private void Table_Cleared(System.Object sender, 
System.Data.DataTableClearEventArgs e) {
                        pAdapter.EmitRowDeleted (new Gtk.TreePath ());
                }
        }
}
_______________________________________________
Gtk-sharp-list maillist  -  Gtk-sharp-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list

Reply via email to