diff --git a/ChangeLog b/ChangeLog index 252f5b3f5..2e748d53f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2003-11-04 Mike Kestner + + * glib/Value.cs : add set to Val prop + * glue/Makefile.am : build nodestore.c + * glue/makefile.win32 : link nodestore.o + * glue/nodestore.c : new, glue for TreeModel implementation + * gtk/NodeStore.cs : new tree store implementation + * gtk/ITreeNode.cs : new interface for nodestore node types + * gtk/TreeNode.cs : abstract class for deriving nodestore nodes + * gtk/TreeNodeAttribute.cs : tree node marking attr + * gtk/TreeNodeValueAttribute.cs : node column marking attr + * gtk/TreeView.custom : add ctor(NodeStore) + 2003-11-04 John Luke * sources/makefile: add gstreamer 0.6.4 sources diff --git a/glib/Value.cs b/glib/Value.cs index d4d09446b..814e2e64a 100755 --- a/glib/Value.cs +++ b/glib/Value.cs @@ -628,6 +628,40 @@ namespace GLib { throw new Exception ("Unknown type"); } } + set { + GLib.TypeFundamentals type = GLibSharp.TypeConverter.LookupType (value.GetType()); + switch (type) { + case TypeFundamentals.TypeNone: + g_value_set_boxed_take_ownership (_val, ManagedValue.WrapObject (value)); + break; + case TypeFundamentals.TypeString: + g_value_set_string (_val, (string) value); + break; + case TypeFundamentals.TypeBoolean: + g_value_set_boolean (_val, (bool) value); + break; + case TypeFundamentals.TypeInt: + g_value_set_int (_val, (int) value); + break; + case TypeFundamentals.TypeDouble: + g_value_set_double (_val, (double) value); + break; + case TypeFundamentals.TypeFloat: + g_value_set_float (_val, (float) value); + break; + case TypeFundamentals.TypeChar: + g_value_set_char (_val, (char) value); + break; + case TypeFundamentals.TypeUInt: + g_value_set_uint (_val, (uint) value); + break; + case TypeFundamentals.TypeObject: + g_value_set_object (_val, ((GLib.Object) value).Handle); + break; + default: + throw new Exception ("Unknown type"); + } + } } /// diff --git a/glue/Makefile.am b/glue/Makefile.am index c2fc88d36..682fd13e1 100644 --- a/glue/Makefile.am +++ b/glue/Makefile.am @@ -12,6 +12,7 @@ BASESOURCES = \ fileselection.c \ layout.c \ list.c \ + nodestore.c \ object.c \ paned.c \ selection.c \ diff --git a/glue/makefile.win32 b/glue/makefile.win32 index 5e32f7eb6..71062dc9e 100755 --- a/glue/makefile.win32 +++ b/glue/makefile.win32 @@ -15,6 +15,7 @@ GLUE_OBJS = \ fileselection.o \ layout.o \ list.o \ + nodestore.o \ object.o \ paned.o \ selection.o \ diff --git a/glue/nodestore.c b/glue/nodestore.c new file mode 100644 index 000000000..1682455a0 --- /dev/null +++ b/glue/nodestore.c @@ -0,0 +1,346 @@ +/* + * nodestore.c + * + * Copyright (C) 2003 Novell, Inc. + * + * Authors: Mike Kestner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +typedef GtkTreeModelFlags (* GtkSharpNodeStoreGetFlagsFunc) (void); +typedef gint (* GtkSharpNodeStoreGetNColumnsFunc) (void); +typedef GType (* GtkSharpNodeStoreGetColumnTypeFunc) (gint col); +typedef gboolean (* GtkSharpNodeStoreGetNodeFunc) (gint *node_idx, GtkTreePath *path); +typedef GtkTreePath* (* GtkSharpNodeStoreGetPathFunc) (gint node_idx); +typedef void (* GtkSharpNodeStoreGetValueFunc) (gint node_idx, gint col, GValue *value); +typedef gboolean (* GtkSharpNodeStoreIterNextFunc) (gint *node_idx); +typedef gboolean (* GtkSharpNodeStoreIterChildrenFunc) (gint *first_child, gint parent); +typedef gboolean (* GtkSharpNodeStoreIterHasChildFunc) (gint node_idx); +typedef gint (* GtkSharpNodeStoreIterNChildrenFunc) (gint node_idx); +typedef gboolean (* GtkSharpNodeStoreIterNthChildFunc) (gint *child, gint parent, gint n); +typedef gboolean (* GtkSharpNodeStoreIterParentFunc) (gint *parent, gint child); + +typedef struct _GtkSharpNodeStoreTreeModelIface { + GtkSharpNodeStoreGetFlagsFunc get_flags; + GtkSharpNodeStoreGetNColumnsFunc get_n_columns; + GtkSharpNodeStoreGetColumnTypeFunc get_column_type; + GtkSharpNodeStoreGetNodeFunc get_node; + GtkSharpNodeStoreGetPathFunc get_path; + GtkSharpNodeStoreGetValueFunc get_value; + GtkSharpNodeStoreIterNextFunc iter_next; + GtkSharpNodeStoreIterChildrenFunc iter_children; + GtkSharpNodeStoreIterHasChildFunc iter_has_child; + GtkSharpNodeStoreIterNChildrenFunc iter_n_children; + GtkSharpNodeStoreIterNthChildFunc iter_nth_child; + GtkSharpNodeStoreIterParentFunc iter_parent; +} GtkSharpNodeStoreTreeModelIface; + +typedef struct _GtkSharpNodeStore { + GObject parent; + + gint stamp; + GtkSharpNodeStoreTreeModelIface tree_model; +} GtkSharpNodeStore; + +typedef struct _GtkSharpNodeStoreClass { + GObjectClass parent; +} GtkSharpNodeStoreClass; + +GType gtksharp_node_store_get_type (void); +GObject * gtksharp_node_store_new (void); +void gtksharp_node_store_set_tree_model_callbacks (GtkSharpNodeStore *store, GtkSharpNodeStoreTreeModelIface *iface); +void gtksharp_node_store_emit_row_changed (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx); +void gtksharp_node_store_emit_row_inserted (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx); +void gtksharp_node_store_emit_row_deleted (GtkSharpNodeStore *store, GtkTreePath *path); +void gtksharp_node_store_emit_row_has_child_toggled (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx); + +static GtkTreeModelFlags +gns_get_flags (GtkTreeModel *model) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + return store->tree_model.get_flags (); +} + +static int +gns_get_n_columns (GtkTreeModel *model) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + return store->tree_model.get_n_columns (); +} + +static GType +gns_get_column_type (GtkTreeModel *model, int col) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + return store->tree_model.get_column_type (col); +} + +static gboolean +gns_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint node_idx; + + if (!store->tree_model.get_node (&node_idx, path)) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = GINT_TO_POINTER (node_idx); + return TRUE; +} + +static GtkTreePath * +gns_get_path (GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + return store->tree_model.get_path (GPOINTER_TO_INT (iter->user_data)); +} + +static void +gns_get_value (GtkTreeModel *model, GtkTreeIter *iter, int col, GValue *value) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + store->tree_model.get_value (GPOINTER_TO_INT (iter->user_data), col, value); +} + +static gboolean +gns_iter_next (GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint node_idx; + + if (store->stamp != iter->stamp) + return FALSE; + + node_idx = GPOINTER_TO_INT (iter->user_data); + if (!store->tree_model.iter_next (&node_idx)) { + iter->stamp = -1; + return FALSE; + } + + iter->user_data = GINT_TO_POINTER (node_idx); + return TRUE; +} + +static gboolean +gns_iter_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint child_idx, parent_idx; + + if (!parent) + parent_idx = -1; + else { + if (store->stamp != parent->stamp) + return FALSE; + parent_idx = GPOINTER_TO_INT (parent->user_data); + } + + if (!store->tree_model.iter_children (&child_idx, parent_idx)) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = GINT_TO_POINTER (child_idx); + return TRUE; +} + +static gboolean +gns_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + return store->tree_model.iter_has_child (GPOINTER_TO_INT (iter->user_data)); +} + +static int +gns_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint node_idx; + + if (!iter) + node_idx = -1; + else { + if (store->stamp != iter->stamp) + return 0; + node_idx = GPOINTER_TO_INT (iter->user_data); + } + + return store->tree_model.iter_n_children (node_idx); +} + +static gboolean +gns_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent, int n) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint child_idx, parent_idx; + + if (!parent) + parent_idx = -1; + else { + if (store->stamp != parent->stamp) + return FALSE; + parent_idx = GPOINTER_TO_INT (parent->user_data); + } + + if (!store->tree_model.iter_nth_child (&child_idx, parent_idx, n)) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = GINT_TO_POINTER (child_idx); + return TRUE; +} + +static gboolean +gns_iter_parent (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *child) +{ + GtkSharpNodeStore *store = (GtkSharpNodeStore *) model; + gint parent; + + if (store->stamp != child->stamp) + return FALSE; + + if (!store->tree_model.iter_parent (&parent, GPOINTER_TO_INT (child->user_data))) + return FALSE; + + iter->stamp = store->stamp; + iter->user_data = GINT_TO_POINTER (parent); + return TRUE; +} + +static void +gns_tree_model_init (GtkTreeModelIface *iface) +{ + iface->get_flags = gns_get_flags; + iface->get_n_columns = gns_get_n_columns; + iface->get_column_type = gns_get_column_type; + iface->get_iter = gns_get_iter; + iface->get_path = gns_get_path; + iface->get_value = gns_get_value; + iface->iter_next = gns_iter_next; + iface->iter_children = gns_iter_children; + iface->iter_has_child = gns_iter_has_child; + iface->iter_n_children = gns_iter_n_children; + iface->iter_nth_child = gns_iter_nth_child; + iface->iter_parent = gns_iter_parent; +} + +static void +gns_class_init (GObjectClass *klass) +{ +} + + +static void +gns_init (GtkSharpNodeStore *store) +{ + store->stamp = 0; + store->tree_model.get_flags = NULL; + store->tree_model.get_n_columns = NULL; + store->tree_model.get_column_type = NULL; + store->tree_model.get_node = NULL; + store->tree_model.get_path = NULL; + store->tree_model.get_value = NULL; + store->tree_model.iter_next = NULL; + store->tree_model.iter_children = NULL; + store->tree_model.iter_has_child = NULL; + store->tree_model.iter_n_children = NULL; + store->tree_model.iter_nth_child = NULL; + store->tree_model.iter_parent = NULL; +} + +GType +gtksharp_node_store_get_type (void) +{ + static GType gns_type = 0; + + if (!gns_type) { + static const GTypeInfo gns_info = { + sizeof (GtkSharpNodeStoreClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gns_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GtkSharpNodeStore), + 0, + (GInstanceInitFunc) gns_init }; + + static const GInterfaceInfo tree_model_info = { + (GInterfaceInitFunc) gns_tree_model_init, + NULL, + NULL }; + + gns_type = g_type_register_static (G_TYPE_OBJECT, "GtkSharpNodeStore", &gns_info, 0); + + g_type_add_interface_static (gns_type, GTK_TYPE_TREE_MODEL, &tree_model_info); + } + + return gns_type; +} + +GObject * +gtksharp_node_store_new (void) +{ + return g_object_new (gtksharp_node_store_get_type (), NULL); +} + +void +gtksharp_node_store_set_tree_model_callbacks (GtkSharpNodeStore *store, GtkSharpNodeStoreTreeModelIface *iface) +{ + store->tree_model = *iface; +} + +void +gtksharp_node_store_emit_row_changed (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx) +{ + GtkTreeIter iter; + + iter.stamp = store->stamp; + iter.user_data = GINT_TO_POINTER (node_idx); + + gtk_tree_model_row_changed (GTK_TREE_MODEL (store), path, &iter); +} + +void +gtksharp_node_store_emit_row_inserted (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx) +{ + GtkTreeIter iter; + + iter.stamp = store->stamp; + iter.user_data = GINT_TO_POINTER (node_idx); + + gtk_tree_model_row_inserted (GTK_TREE_MODEL (store), path, &iter); +} + +void +gtksharp_node_store_emit_row_deleted (GtkSharpNodeStore *store, GtkTreePath *path) +{ + gtk_tree_model_row_deleted (GTK_TREE_MODEL (store), path); +} + +void +gtksharp_node_store_emit_row_has_child_toggled (GtkSharpNodeStore *store, GtkTreePath *path, gint node_idx) +{ + GtkTreeIter iter; + + iter.stamp = store->stamp; + iter.user_data = GINT_TO_POINTER (node_idx); + + gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (store), path, &iter); +} + diff --git a/gtk/ITreeNode.cs b/gtk/ITreeNode.cs new file mode 100644 index 000000000..41a4e7aee --- /dev/null +++ b/gtk/ITreeNode.cs @@ -0,0 +1,33 @@ +// ITreeNode.cs - Interface and delegates for tree node navigation and updating. +// +// Author: Mike Kestner +// +// 2003 Novell, Inc. + +namespace Gtk { + + using System; + + public delegate void TreeNodeAddedHandler (object o, ITreeNode child); + + public delegate void TreeNodeRemovedHandler (object o, int old_position); + + public interface ITreeNode { + + int ID { get; } + + ITreeNode Parent { get; set; } + + int ChildCount { get; } + + ITreeNode this [int index] { get; } + + int IndexOf (object o); + + event EventHandler Changed; + + event TreeNodeAddedHandler ChildAdded; + + event TreeNodeRemovedHandler ChildRemoved; + } +} diff --git a/gtk/NodeStore.cs b/gtk/NodeStore.cs new file mode 100644 index 000000000..1fb072798 --- /dev/null +++ b/gtk/NodeStore.cs @@ -0,0 +1,414 @@ +// NodeStore.cs - Tree store implementation for TreeView. +// +// Author: Mike Kestner +// +// 2003 Novell, Inc. + +namespace Gtk { + + using System; + using System.Collections; + using System.Reflection; + using System.Runtime.InteropServices; + + public class NodeStore : GLib.Object { + + class IDHashtable : Hashtable { + class IDComparer : IComparer { + public int Compare (object x, object y) + { + if ((int) x == (int) y) + return 0; + else + return 1; + } + } + + class IDHashCodeProvider : IHashCodeProvider { + public int GetHashCode (object o) + { + return (int) o; + } + } + + public IDHashtable () : base (new IDHashCodeProvider (), new IDComparer ()) {} + } + + delegate int GetFlagsDelegate (); + delegate int GetNColumnsDelegate (); + delegate uint GetColumnTypeDelegate (int col); + delegate bool GetNodeDelegate (out int node_idx, IntPtr path); + delegate IntPtr GetPathDelegate (int node_idx); + delegate void GetValueDelegate (int node_idx, int col, IntPtr val); + delegate bool NextDelegate (ref int node_idx); + delegate bool ChildrenDelegate (out int child, int parent); + delegate bool HasChildDelegate (int node_idx); + delegate int NChildrenDelegate (int node_idx); + delegate bool NthChildDelegate (out int child, int parent, int n); + delegate bool ParentDelegate (out int parent, int child); + + [StructLayout(LayoutKind.Sequential)] + struct TreeModelIfaceDelegates { + public GetFlagsDelegate get_flags; + public GetNColumnsDelegate get_n_columns; + public GetColumnTypeDelegate get_column_type; + public GetNodeDelegate get_node; + public GetPathDelegate get_path; + public GetValueDelegate get_value; + public NextDelegate next; + public ChildrenDelegate children; + public HasChildDelegate has_child; + public NChildrenDelegate n_children; + public NthChildDelegate nth_child; + public ParentDelegate parent; + } + + int stamp; + Hashtable node_hash = new IDHashtable (); + uint[] ctypes; + PropertyInfo[] getters; + int n_cols = 1; + ArrayList nodes = new ArrayList (); + TreeModelIfaceDelegates tree_model_iface; + + int get_flags_cb () + { + return (int) TreeModelFlags.ItersPersist; + } + + int get_n_columns_cb () + { + return n_cols; + } + + uint get_column_type_cb (int col) + { + return ctypes [col]; + } + + bool get_node_cb (out int node_idx, IntPtr path) + { + if (path == IntPtr.Zero) + Console.WriteLine ("Got a null path in get_node"); + TreePath treepath = new TreePath (path); + node_idx = -1; + int[] indices = treepath.Indices; + + if (indices[0] >= Nodes.Count) + return false; + + ITreeNode node = Nodes [indices [0]] as ITreeNode; + int i; + for (i = 1; i < treepath.Depth; i++) { + if (indices [i] >= node.ChildCount) + return false; + + node = node [indices [i]]; + } + + node_idx = node.ID; + node_hash [node.ID] = node; + return true; + } + + IntPtr get_path_cb (int node_idx) + { + TreePath path = new TreePath (); + int idx; + + ITreeNode node = node_hash [node_idx] as ITreeNode; + if (node == null) throw new Exception ("Invalid Node ID"); + + while (node.Parent != null) { + idx = node.Parent.IndexOf (node); + if (idx < 0) throw new Exception ("Badly formed tree"); + path.PrependIndex (idx); + node = node.Parent; + } + idx = Nodes.IndexOf (node); + if (idx < 0) throw new Exception ("Node not found in Nodes list"); + path.PrependIndex (idx); + return path.Handle; + } + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_value_init (IntPtr handle, uint type); + + void get_value_cb (int node_idx, int col, IntPtr val) + { + GLib.Value gval = new GLib.Value (val, IntPtr.Zero); + ITreeNode node = node_hash [node_idx] as ITreeNode; + if (node == null) + return; + g_value_init (gval.Handle, ctypes [col]); + object col_val = getters[col].GetValue (node, null); + gval.Val = col_val; + } + + bool next_cb (ref int node_idx) + { + ITreeNode node = node_hash [node_idx] as ITreeNode; + if (node == null) + return false; + + int idx; + if (node.Parent == null) + idx = Nodes.IndexOf (node); + else + idx = node.Parent.IndexOf (node); + + if (idx < 0) throw new Exception ("Node not found in Nodes list"); + + if (node.Parent == null) { + if (++idx >= Nodes.Count) + return false; + node = Nodes [idx] as ITreeNode; + } else { + if (++idx >= node.Parent.ChildCount) + return false; + node = node.Parent [idx]; + } + node_hash [node.ID] = node; + node_idx = node.ID; + return true; + } + + bool children_cb (out int child_idx, int parent) + { + child_idx = -1; + ITreeNode node; + + if (parent == -1) { + if (Nodes.Count <= 0) + return false; + node = Nodes [0] as ITreeNode; + child_idx = node.ID; + node_hash [node.ID] = node; + return true; + } + + node = node_hash [parent] as ITreeNode; + if (node == null || node.ChildCount <= 0) + return false; + + ITreeNode child = node [0]; + node_hash [child.ID] = child; + child_idx = child.ID; + return true; + } + + bool has_child_cb (int node_idx) + { + ITreeNode node = node_hash [node_idx] as ITreeNode; + if (node == null || node.ChildCount <= 0) + return false; + + return true; + } + + int n_children_cb (int node_idx) + { + if (node_idx == -1) + return Nodes.Count; + + ITreeNode node = node_hash [node_idx] as ITreeNode; + if (node == null || node.ChildCount <= 0) + return 0; + + return node.ChildCount; + } + + bool nth_child_cb (out int child_idx, int parent, int n) + { + child_idx = -1; + ITreeNode node; + + if (parent == -1) { + if (Nodes.Count <= n) + return false; + node = Nodes [n] as ITreeNode; + child_idx = node.ID; + node_hash [node.ID] = node; + return true; + } + + node = node_hash [parent] as ITreeNode; + if (node == null || node.ChildCount <= n) + return false; + + ITreeNode child = node [n]; + node_hash [child.ID] = child; + child_idx = child.ID; + return true; + } + + bool parent_cb (out int parent_idx, int child) + { + parent_idx = -1; + ITreeNode node = node_hash [child] as ITreeNode; + if (node == null || node.Parent == null) + return false; + + node_hash [node.Parent.ID] = node.Parent; + parent_idx = node.Parent.ID; + return true; + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_node_store_set_tree_model_callbacks (IntPtr raw, ref TreeModelIfaceDelegates cbs); + + private void BuildTreeModelIface () + { + tree_model_iface.get_flags = new GetFlagsDelegate (get_flags_cb); + tree_model_iface.get_n_columns = new GetNColumnsDelegate (get_n_columns_cb); + tree_model_iface.get_column_type = new GetColumnTypeDelegate (get_column_type_cb); + tree_model_iface.get_node = new GetNodeDelegate (get_node_cb); + tree_model_iface.get_path = new GetPathDelegate (get_path_cb); + tree_model_iface.get_value = new GetValueDelegate (get_value_cb); + tree_model_iface.next = new NextDelegate (next_cb); + tree_model_iface.children = new ChildrenDelegate (children_cb); + tree_model_iface.has_child = new HasChildDelegate (has_child_cb); + tree_model_iface.n_children = new NChildrenDelegate (n_children_cb); + tree_model_iface.nth_child = new NthChildDelegate (nth_child_cb); + tree_model_iface.parent = new ParentDelegate (parent_cb); + + gtksharp_node_store_set_tree_model_callbacks (Handle, ref tree_model_iface); + } + + [DllImport("gtksharpglue")] + static extern IntPtr gtksharp_node_store_new (); + + public NodeStore (Type node_type) + { + Raw = gtksharp_node_store_new (); + ScanType (node_type); + BuildTreeModelIface (); + } + + void ScanType (Type type) + { + object[] attrs = type.GetCustomAttributes (false); + foreach (object attr in attrs) { + switch (attr.ToString ()) { + case "Gtk.TreeNodeAttribute": + TreeNodeAttribute tna = attr as TreeNodeAttribute; + n_cols = tna.ColumnCount; + break; + default: + Console.WriteLine ("Unknown attr: " + attr); + break; + } + } + + ctypes = new uint [n_cols]; + getters = new PropertyInfo [n_cols]; + + MemberInfo[] info = type.GetMembers (); + foreach (MemberInfo mi in info) { + PropertyInfo pi; + object[] attr_info = mi.GetCustomAttributes (false); + foreach (object attr in attr_info) { + switch (attr.ToString ()) { + case "Gtk.TreeNodeValueAttribute": + TreeNodeValueAttribute tnva = attr as TreeNodeValueAttribute; + int col = tnva.Column; + pi = mi as PropertyInfo; + getters [col] = pi; + GLib.TypeFundamentals ctype = GLibSharp.TypeConverter.LookupType (pi.PropertyType); + if (ctype == GLib.TypeFundamentals.TypeNone) { + ctypes[col] = GLibSharp.ManagedValue.GType; + } else if (ctype == GLib.TypeFundamentals.TypeInvalid) { + throw new Exception ("Unknown type"); + } else { + ctypes[col] = (uint) ctype; + } + break; + default: + Console.WriteLine ("Unknown custom attr: " + attr); + break; + } + } + } + } + + private IList Nodes { + get { + return nodes as IList; + } + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_node_store_emit_row_changed (IntPtr handle, IntPtr path, int node_idx); + + private void changed_cb (object o, EventArgs args) + { + ITreeNode node = o as ITreeNode; + node_hash [node.ID] = node; + + gtksharp_node_store_emit_row_changed (Handle, get_path_cb (node.ID), node.ID); + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_node_store_emit_row_inserted (IntPtr handle, IntPtr path, int node_idx); + + private void child_added_cb (object o, ITreeNode child) + { + node_hash [child.ID] = child; + + gtksharp_node_store_emit_row_inserted (Handle, get_path_cb (child.ID), child.ID); + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_node_store_emit_row_deleted (IntPtr handle, IntPtr path); + + [DllImport("gtksharpglue")] + static extern void gtksharp_node_store_emit_row_has_child_toggled (IntPtr handle, IntPtr path, int node_idx); + + private void child_deleted_cb (object o, int idx) + { + ITreeNode node = o as ITreeNode; + + TreePath path = new TreePath (get_path_cb (node.ID)); + TreePath child_path = path.Copy (); + child_path.AppendIndex (idx); + + gtksharp_node_store_emit_row_deleted (Handle, child_path.Handle); + + if (node.ChildCount <= 0) { + node_hash [node.ID] = node; + gtksharp_node_store_emit_row_has_child_toggled (Handle, path.Handle, node.ID); + } + } + + private void ConnectNode (ITreeNode node) + { + node.Changed += new EventHandler (changed_cb); + node.ChildAdded += new TreeNodeAddedHandler (child_added_cb); + node.ChildRemoved += new TreeNodeRemovedHandler (child_deleted_cb); + } + + public void AddNode (ITreeNode node) + { + nodes.Add (node); + node_hash [node.ID] = node; + ConnectNode (node); + for (int i = 0; i < node.ChildCount; i++) + ConnectNode (node [i]); + + gtksharp_node_store_emit_row_inserted (Handle, get_path_cb (node.ID), node.ID); + } + + public void RemoveNode (ITreeNode node) + { + int idx = nodes.IndexOf (node); + if (idx < 0) + return; + nodes.Remove (node); + + TreePath path = new TreePath (); + path.AppendIndex (idx); + + gtksharp_node_store_emit_row_deleted (Handle, path.Handle); + } + } +} diff --git a/gtk/TreeNode.cs b/gtk/TreeNode.cs new file mode 100644 index 000000000..dcc86666c --- /dev/null +++ b/gtk/TreeNode.cs @@ -0,0 +1,107 @@ +// TreeNode.cs - Abstract base class to subclass for TreeNode types +// +// Author: Mike Kestner +// +// 2003 Novell, Inc. + +namespace Gtk { + + using System; + using System.Collections; + + public abstract class TreeNode : ITreeNode { + + static int next_idx = 0; + + int id; + ITreeNode parent; + ArrayList children = new ArrayList (); + + public TreeNode () + { + id = next_idx++; + } + + public int ID { + get { + return id; + } + } + + public ITreeNode Parent { + get { + return parent; + } + set { + parent = value; + } + } + + public int ChildCount { + get { + return children.Count; + } + } + + public int IndexOf (object o) + { + return children.IndexOf (o); + } + + public ITreeNode this [int index] { + get { + if (index >= ChildCount) + return null; + + return children [index] as ITreeNode; + } + } + + public event EventHandler Changed; + + protected void OnChanged () + { + if (Changed == null) + return; + + Changed (this, new EventArgs ()); + } + + public event TreeNodeAddedHandler ChildAdded; + + private void OnChildAdded (ITreeNode child) + { + if (ChildAdded == null) + return; + + ChildAdded (this, child); + } + + public event TreeNodeRemovedHandler ChildRemoved; + + private void OnChildRemoved (int old_position) + { + if (ChildRemoved == null) + return; + + ChildRemoved (this, old_position); + } + + public void AddChild (ITreeNode child) + { + children.Add (child); + child.Parent = this; + OnChildAdded (child); + } + + public void RemoveChild (ITreeNode child) + { + int idx = children.IndexOf (child); + if (idx < 0) + return; + + children.Remove (child); + OnChildRemoved (idx); + } + } +} diff --git a/gtk/TreeNodeAttribute.cs b/gtk/TreeNodeAttribute.cs new file mode 100644 index 000000000..a93308552 --- /dev/null +++ b/gtk/TreeNodeAttribute.cs @@ -0,0 +1,25 @@ +// TreeNodeAttribute.cs - Attribute to specify TreeNode information for a class +// +// Author: Mike Kestner +// +// 2003 Novell, Inc. + +namespace Gtk { + + using System; + + [AttributeUsage(AttributeTargets.Class)] + public class TreeNodeAttribute : Attribute { + int col_count; + + public int ColumnCount { + get { + return col_count; + } + set { + col_count = value; + } + } + } +} + diff --git a/gtk/TreeNodeValueAttribute.cs b/gtk/TreeNodeValueAttribute.cs new file mode 100644 index 000000000..4bc2ec9ea --- /dev/null +++ b/gtk/TreeNodeValueAttribute.cs @@ -0,0 +1,25 @@ +// TreeNodeValueAttribute.cs - Attribute to mark properties as TreeNode column values +// +// Author: Mike Kestner +// +// 2003 Novell, Inc. + +namespace Gtk { + + using System; + + [AttributeUsage(AttributeTargets.Property)] + public class TreeNodeValueAttribute : Attribute { + int col; + + public int Column { + get { + return col; + } + set { + col = value; + } + } + } +} + diff --git a/gtk/TreeView.custom b/gtk/TreeView.custom index 03daa5497..255a024f3 100644 --- a/gtk/TreeView.custom +++ b/gtk/TreeView.custom @@ -10,6 +10,11 @@ // This code is inserted after the automatically generated code. + public TreeView (NodeStore store) + { + Raw = gtk_tree_view_new_with_model (store.Handle); + } + [DllImport("libgtk-win32-2.0-0.dll")] static extern IntPtr gtk_tree_view_get_model (IntPtr raw);