2003-11-04 Mike Kestner <mkestner@ximian.com>
* 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) svn path=/trunk/gtk-sharp/; revision=19630
This commit is contained in:
parent
8c74eb6186
commit
912980c396
11 changed files with 1004 additions and 0 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2003-11-04 Mike Kestner <mkestner@ximian.com>
|
||||
|
||||
* 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 <jluke@cfl.rr.com>
|
||||
|
||||
* sources/makefile: add gstreamer 0.6.4 sources
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -12,6 +12,7 @@ BASESOURCES = \
|
|||
fileselection.c \
|
||||
layout.c \
|
||||
list.c \
|
||||
nodestore.c \
|
||||
object.c \
|
||||
paned.c \
|
||||
selection.c \
|
||||
|
|
|
@ -15,6 +15,7 @@ GLUE_OBJS = \
|
|||
fileselection.o \
|
||||
layout.o \
|
||||
list.o \
|
||||
nodestore.o \
|
||||
object.o \
|
||||
paned.o \
|
||||
selection.o \
|
||||
|
|
346
glue/nodestore.c
Normal file
346
glue/nodestore.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* nodestore.c
|
||||
*
|
||||
* Copyright (C) 2003 Novell, Inc.
|
||||
*
|
||||
* Authors: Mike Kestner <mkestner@ximian.com>
|
||||
*
|
||||
* 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 <gtk/gtktreemodel.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
33
gtk/ITreeNode.cs
Normal file
33
gtk/ITreeNode.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// ITreeNode.cs - Interface and delegates for tree node navigation and updating.
|
||||
//
|
||||
// Author: Mike Kestner <mkestner@ximian.com>
|
||||
//
|
||||
// <c> 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;
|
||||
}
|
||||
}
|
414
gtk/NodeStore.cs
Normal file
414
gtk/NodeStore.cs
Normal file
|
@ -0,0 +1,414 @@
|
|||
// NodeStore.cs - Tree store implementation for TreeView.
|
||||
//
|
||||
// Author: Mike Kestner <mkestner@ximian.com>
|
||||
//
|
||||
// <c> 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);
|
||||
}
|
||||
}
|
||||
}
|
107
gtk/TreeNode.cs
Normal file
107
gtk/TreeNode.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
// TreeNode.cs - Abstract base class to subclass for TreeNode types
|
||||
//
|
||||
// Author: Mike Kestner <mkestner@ximian.com>
|
||||
//
|
||||
// <c> 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);
|
||||
}
|
||||
}
|
||||
}
|
25
gtk/TreeNodeAttribute.cs
Normal file
25
gtk/TreeNodeAttribute.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// TreeNodeAttribute.cs - Attribute to specify TreeNode information for a class
|
||||
//
|
||||
// Author: Mike Kestner <mkestner@ximian.com>
|
||||
//
|
||||
// <c> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
gtk/TreeNodeValueAttribute.cs
Normal file
25
gtk/TreeNodeValueAttribute.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// TreeNodeValueAttribute.cs - Attribute to mark properties as TreeNode column values
|
||||
//
|
||||
// Author: Mike Kestner <mkestner@ximian.com>
|
||||
//
|
||||
// <c> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue