From b2db2cda9e4323fef960c47d1eb45fdb30b3f0e1 Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Tue, 2 Oct 2007 15:57:45 +0000 Subject: [PATCH] 2007-10-02 Mike Kestner * generator/*.cs: implement the interfaces on the adapters too. Generate an Implementor interface for users which exposes the methods to implement. Register based on the Implementor sub-iface. * gtk/*Adapter.custom: custom implementations for the custom interface members. * gtk/TreeIter.custom: make UserData public. * sample/TreeModelDemo.cs: sample for implementing a TreeModel interface. svn path=/trunk/gtk-sharp/; revision=86753 --- ChangeLog | 11 ++ generator/InterfaceGen.cs | 197 +++++++++++++-------- generator/Parameters.cs | 9 + generator/ReturnValue.cs | 8 + generator/Signal.cs | 90 ++++++---- generator/VMSignature.cs | 3 + generator/VirtualMethod.cs | 69 +++++--- gtk/CellLayoutAdapter.custom | 31 ++++ gtk/FileChooserAdapter.custom | 43 +++++ gtk/Makefile.am | 4 + gtk/TreeIter.custom | 2 +- gtk/TreeModelAdapter.custom | 181 +++++++++++++++++++ gtk/TreeSortableAdapter.custom | 36 ++++ sample/Makefile.am | 5 +- sample/TreeModelDemo.cs | 313 +++++++++++++++++++++++++++++++++ 15 files changed, 869 insertions(+), 133 deletions(-) create mode 100644 gtk/CellLayoutAdapter.custom create mode 100644 gtk/FileChooserAdapter.custom create mode 100644 gtk/TreeModelAdapter.custom create mode 100644 gtk/TreeSortableAdapter.custom create mode 100644 sample/TreeModelDemo.cs diff --git a/ChangeLog b/ChangeLog index 4f67309f3..749489e57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2007-10-02 Mike Kestner + + * generator/*.cs: implement the interfaces on the adapters too. + Generate an Implementor interface for users which exposes the + methods to implement. Register based on the Implementor sub-iface. + * gtk/*Adapter.custom: custom implementations for the custom + interface members. + * gtk/TreeIter.custom: make UserData public. + * sample/TreeModelDemo.cs: sample for implementing a TreeModel + interface. + 2007-10-01 Mike Kestner * generator/OpaqueGen.cs: disable Copy generation fix until I can diff --git a/generator/InterfaceGen.cs b/generator/InterfaceGen.cs index 3165b0374..99171b7e9 100644 --- a/generator/InterfaceGen.cs +++ b/generator/InterfaceGen.cs @@ -42,7 +42,10 @@ namespace GtkSharp.Generation { members.Add (vm); break; case "signal": - members.Add ((node as XmlElement).GetAttribute ("cname").Replace ('-', '_')); + object sig = sigs [(node as XmlElement).GetAttribute ("name")]; + if (sig == null) + sig = new Signal (node as XmlElement, this); + members.Add (sig); break; default: if (!IsNodeNameHandled (node.Name)) @@ -52,6 +55,11 @@ namespace GtkSharp.Generation { } } + public override string FromNative (string var, bool owned) + { + return QualifiedName + "Adapter.GetObject (" + var + ", " + (owned ? "true" : "false") + ")"; + } + public override bool ValidateForSubclass () { ArrayList invalids = new ArrayList (); @@ -85,14 +93,15 @@ namespace GtkSharp.Generation { sw.WriteLine (); foreach (object member in members) { - if (member is System.String) - sw.WriteLine ("\t\t\tpublic IntPtr " + member + ";"); - else if (member is VirtualMethod) { + if (member is Signal) { + Signal sig = member as Signal; + sw.WriteLine ("\t\t\tpublic IntPtr {0};", sig.ClassFieldName); + } else if (member is VirtualMethod) { VirtualMethod vm = member as VirtualMethod; - bool has_method = methods [vm.Name] != null; - if (!has_method) + bool has_target = methods [vm.Name] != null; + if (!has_target) Console.WriteLine ("Interface " + QualifiedName + " virtual method " + vm.Name + " has no matching method to invoke."); - string type = has_method && vm.IsValid ? vm.Name + "Delegate" : "IntPtr"; + string type = has_target && vm.IsValid ? vm.Name + "Delegate" : "IntPtr"; sw.WriteLine ("\t\t\tpublic " + type + " " + vm.CName + ";"); } } @@ -106,8 +115,8 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\tstatic " + Name + "Adapter ()"); sw.WriteLine ("\t\t{"); foreach (VirtualMethod vm in vms) { - bool has_method = methods [vm.Name] != null; - if (has_method && vm.IsValid) + bool has_target = methods [vm.Name] != null; + if (has_target && vm.IsValid) sw.WriteLine ("\t\t\tiface.{0} = new {1}Delegate ({1}Callback);", vm.CName, vm.Name); } sw.WriteLine ("\t\t}"); @@ -131,20 +140,27 @@ namespace GtkSharp.Generation { void GenerateCallbacks (StreamWriter sw) { foreach (VirtualMethod vm in vms) { - if (methods [vm.Name] == null) - continue; - sw.WriteLine (); - vm.GenerateCallback (sw); + if (methods [vm.Name] != null) { + sw.WriteLine (); + vm.GenerateCallback (sw); + } } } - void GenerateCtor (StreamWriter sw) + void GenerateCtors (StreamWriter sw) { sw.WriteLine ("\t\tpublic " + Name + "Adapter ()"); sw.WriteLine ("\t\t{"); sw.WriteLine ("\t\t\tInitHandler = new GLib.GInterfaceInitHandler (Initialize);"); sw.WriteLine ("\t\t}"); sw.WriteLine (); + sw.WriteLine ("\t\t{0}Implementor implementor;", Name); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic {0}Adapter ({0}Implementor implementor)", Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tthis.implementor = implementor;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); } void GenerateGType (StreamWriter sw) @@ -159,6 +175,43 @@ namespace GtkSharp.Generation { sw.WriteLine (); } + void GenerateHandleProp (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic IntPtr Handle {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn implementor == null ? IntPtr.Zero : implementor.Handle;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateGetObject (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic static " + Name + " GetObject (IntPtr handle, bool owned)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tGLib.Object obj = GLib.Object.GetObject (handle, owned);"); + sw.WriteLine ("\t\t\tif (obj is " + Name + "Implementor)"); + sw.WriteLine ("\t\t\t\treturn new {0}Adapter (obj as {0}Implementor);", Name); + sw.WriteLine ("\t\t\telse"); + sw.WriteLine ("\t\t\t\treturn obj as {0};", Name); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateCastOperators (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic static implicit operator {0}Adapter ({0}Implementor implementor)", Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\treturn new {0}Adapter (implementor);", Name); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static implicit operator {0}Implementor ({0}Adapter adapter)", Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\treturn adapter.implementor;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + void GenerateAdapter (GenerationInfo gen_info) { StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name + "Adapter"); @@ -169,74 +222,50 @@ namespace GtkSharp.Generation { sw.WriteLine ("\tusing System.Runtime.InteropServices;"); sw.WriteLine (); sw.WriteLine ("#region Autogenerated code"); - sw.WriteLine ("\tinternal class " + Name + "Adapter : GLib.GInterfaceAdapter {"); + sw.WriteLine ("\tpublic class " + Name + "Adapter : GLib.GInterfaceAdapter, " + QualifiedName + " {"); sw.WriteLine (); GenerateIfaceStruct (sw); GenerateStaticCtor (sw); GenerateCallbacks (sw); GenerateInitialize (sw); - GenerateCtor (sw); + GenerateCtors (sw); GenerateGType (sw); + GenerateHandleProp (sw); + GenerateGetObject (sw); + + GenProperties (gen_info, null); + + foreach (Signal sig in sigs.Values) { + sig.GenCallback (sw); + sig.GenEvent (sw, null, "GLib.Object.GetObject (Handle)"); + } + + Method temp = methods ["GetType"] as Method; + if (temp != null) + methods.Remove ("GetType"); + GenMethods (gen_info, new Hashtable (), this); + if (temp != null) + methods ["GetType"] = temp; + + sw.WriteLine ("#endregion"); + + string custom = Path.Combine (gen_info.CustomDir, Name + "Adapter.custom"); + if (File.Exists (custom)) { + sw.WriteLine ("#region Customized extensions"); + sw.WriteLine ("#line 1 \"" + Name + "Adapter.custom\""); + using (StreamReader sr = new StreamReader(new FileStream (custom, FileMode.Open, FileAccess.Read))) + sw.WriteLine (sr.ReadToEnd ()); + + sw.WriteLine ("#endregion"); + } sw.WriteLine ("\t}"); - sw.WriteLine ("#endregion"); sw.WriteLine ("}"); sw.Close (); gen_info.Writer = null; } - void GenSignals (GenerationInfo gen_info) - { - if (sigs.Count == 0) - return; - - StreamWriter sw = gen_info.Writer; - - sw.WriteLine (); - sw.WriteLine ("\t\t// signals"); - foreach (Signal sig in sigs.Values) { - sig.GenerateDecl (sw); - sig.GenEventHandler (gen_info); - } - } - - Hashtable GenVMDecls (StreamWriter sw) - { - if (vms.Count == 0) - return new Hashtable (); - - sw.WriteLine (); - sw.WriteLine ("\t\t// virtual methods"); - Hashtable vm_decls = new Hashtable (); - foreach (VirtualMethod vm in vms) { - sw.WriteLine ("\t\t" + vm.Declaration); - vm_decls [vm.Declaration] = vm; - } - return vm_decls; - } - - void GenMethodDecls (StreamWriter sw, Hashtable vm_decls) - { - if (methods.Count == 0) - return; - - bool need_comment = true; - foreach (Method method in methods.Values) { - //if (IgnoreMethod (method)) - //continue; - - if (!vm_decls.Contains (method.Declaration) && method.Name != "GetGType") { - if (need_comment) { - sw.WriteLine (); - sw.WriteLine ("\t\t// non-virtual methods"); - need_comment = false; - } - method.GenerateDecl (sw); - } - } - } - public override void Generate (GenerationInfo gen_info) { GenerateAdapter (gen_info); @@ -247,7 +276,6 @@ namespace GtkSharp.Generation { sw.WriteLine ("\tusing System;"); sw.WriteLine (); sw.WriteLine ("#region Autogenerated code"); - sw.WriteLine ("\t[GLib.GInterface (typeof (" + Name + "Adapter))]"); sw.WriteLine ("\tpublic interface " + Name + " : GLib.IWrapper {"); sw.WriteLine (); @@ -267,6 +295,37 @@ namespace GtkSharp.Generation { AppendCustom (sw, gen_info.CustomDir); + sw.WriteLine ("\t}"); + sw.WriteLine (); + sw.WriteLine ("\t[GLib.GInterface (typeof (" + Name + "Adapter))]"); + sw.WriteLine ("\tpublic interface " + Name + "Implementor : GLib.IWrapper {"); + sw.WriteLine (); + Hashtable vm_table = new Hashtable (); + foreach (VirtualMethod vm in vms) + vm_table [vm.Name] = vm; + foreach (VirtualMethod vm in vms) { + if (vm_table [vm.Name] == null) + continue; + else if (!vm.IsValid) { + vm_table.Remove (vm.Name); + continue; + } else if (vm.IsGetter || vm.IsSetter) { + string cmp_name = (vm.IsGetter ? "Set" : "Get") + vm.Name.Substring (3); + VirtualMethod cmp = vm_table [cmp_name] as VirtualMethod; + if (cmp != null && (cmp.IsGetter || cmp.IsSetter)) { + if (vm.IsSetter) + cmp.GenerateDeclaration (sw, vm); + else + vm.GenerateDeclaration (sw, cmp); + vm_table.Remove (cmp.Name); + } else + vm.GenerateDeclaration (sw, null); + vm_table.Remove (vm.Name); + } else { + vm.GenerateDeclaration (sw, null); + vm_table.Remove (vm.Name); + } + } sw.WriteLine ("\t}"); sw.WriteLine ("#endregion"); sw.WriteLine ("}"); diff --git a/generator/Parameters.cs b/generator/Parameters.cs index cc9c64c31..eb9a8ac13 100644 --- a/generator/Parameters.cs +++ b/generator/Parameters.cs @@ -552,6 +552,15 @@ namespace GtkSharp.Generation { set { has_cb = value; } } + public bool HasOutParam { + get { + foreach (Parameter p in this) + if (p.PassAs == "out") + return true; + return false; + } + } + bool hide_data; public bool HideData { get { return hide_data; } diff --git a/generator/ReturnValue.cs b/generator/ReturnValue.cs index 0d0fa3a22..8b06cfebb 100644 --- a/generator/ReturnValue.cs +++ b/generator/ReturnValue.cs @@ -52,6 +52,14 @@ namespace GtkSharp.Generation { } } + public string DefaultValue { + get { + if (IGen == null) + return String.Empty; + return IGen.DefaultValue; + } + } + string ElementCType { get { if (elem != null && elem.HasAttribute ("element_type")) diff --git a/generator/Signal.cs b/generator/Signal.cs index daa489746..0eb4b8d87 100644 --- a/generator/Signal.cs +++ b/generator/Signal.cs @@ -103,7 +103,6 @@ namespace GtkSharp.Generation { result += p.PassAs + " "; result += (p.MarshalType + " arg" + i); } - result += ", IntPtr gch"; return result; } @@ -153,6 +152,12 @@ namespace GtkSharp.Generation { } } + public string ClassFieldName { + get { + return elem.GetAttribute("cname").Replace ("-", "_"); + } + } + private bool HasOutParams { get { foreach (Parameter p in parms) { @@ -199,21 +204,8 @@ namespace GtkSharp.Generation { } } - public void GenCallback (StreamWriter sw) + public string GenArgsInitialization (StreamWriter sw) { - SymbolTable table = SymbolTable.Table; - - sw.WriteLine ("\t\t[GLib.CDeclCallback]"); - sw.WriteLine ("\t\tdelegate " + retval.ToNativeType + " " + DelegateName + " (" + CallbackSig + ");"); - sw.WriteLine (); - sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")"); - sw.WriteLine("\t\t{"); - sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName); - sw.WriteLine("\t\t\ttry {"); - sw.WriteLine("\t\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); - sw.WriteLine("\t\t\t\tif (sig == null)"); - sw.WriteLine("\t\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); - sw.WriteLine(); if (parms.Count > 1) sw.WriteLine("\t\t\t\targs.Args = new object[" + (parms.Count - 1) + "];"); string finish = ""; @@ -235,16 +227,13 @@ namespace GtkSharp.Generation { else if (p.PassAs != "") finish += "\t\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n"; } - sw.WriteLine("\t\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); - sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (arg0), args);"); - sw.WriteLine("\t\t\t} catch (Exception e) {"); - sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);"); - sw.WriteLine("\t\t\t}"); + return finish; + } - if (IsVoid && finish.Length == 0) { - sw.WriteLine("\t\t}\n"); + public void GenArgsCleanup (StreamWriter sw, string finish) + { + if (IsVoid && finish.Length == 0) return; - } sw.WriteLine("\n\t\t\ttry {"); sw.Write (finish); @@ -253,7 +242,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\t\t\tif (args.RetVal == null)"); sw.WriteLine ("\t\t\t\t\treturn false;"); } - sw.WriteLine("\t\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); + sw.WriteLine("\t\t\t\treturn " + SymbolTable.Table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); } sw.WriteLine("\t\t\t} catch (Exception) {"); sw.WriteLine ("\t\t\t\tException ex = new Exception (\"args.RetVal or 'out' property unset or set to incorrect type in " + EventHandlerQualifiedName + " callback\");"); @@ -262,6 +251,31 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\t\t\t// NOTREACHED: above call doesn't return."); sw.WriteLine ("\t\t\t\tthrow ex;"); sw.WriteLine("\t\t\t}"); + } + + public void GenCallback (StreamWriter sw) + { + if (IsEventHandler) + return; + + sw.WriteLine ("\t\t[GLib.CDeclCallback]"); + sw.WriteLine ("\t\tdelegate " + retval.ToNativeType + " " + DelegateName + " (" + CallbackSig + ", IntPtr gch);"); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ", IntPtr gch)"); + sw.WriteLine("\t\t{"); + sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName); + sw.WriteLine("\t\t\ttry {"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); + sw.WriteLine("\t\t\t\tif (sig == null)"); + sw.WriteLine("\t\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); + sw.WriteLine(); + string finish = GenArgsInitialization (sw); + sw.WriteLine("\t\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); + sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (arg0), args);"); + sw.WriteLine("\t\t\t} catch (Exception e) {"); + sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);"); + sw.WriteLine("\t\t\t}"); + GenArgsCleanup (sw, finish); sw.WriteLine("\t\t}"); sw.WriteLine(); } @@ -403,17 +417,8 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\t}\n"); } - public void Generate (GenerationInfo gen_info, ClassBase implementor) + public void GenEvent (StreamWriter sw, ClassBase implementor, string target) { - StreamWriter sw = gen_info.Writer; - - if (implementor == null) - GenEventHandler (gen_info); - - if (!IsEventHandler) - GenCallback (sw); - GenDefaultHandlerDelegate (sw, implementor); - GenVirtualMethod (sw, implementor); string marsh = IsEventHandler ? "" : ", new " + DelegateName + "(" + CallbackName + ")"; sw.WriteLine("\t\t[GLib.Signal("+ CName + ")]"); @@ -422,15 +427,28 @@ namespace GtkSharp.Generation { sw.Write("new "); sw.WriteLine("event " + EventHandlerQualifiedName + " " + Name + " {"); sw.WriteLine("\t\t\tadd {"); - sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (this, " + CName + marsh + ");"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (" + target + ", " + CName + marsh + ");"); sw.WriteLine("\t\t\t\tsig.AddDelegate (value);"); sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t\tremove {"); - sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (this, " + CName + marsh + ");"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (" + target + ", " + CName + marsh + ");"); sw.WriteLine("\t\t\t\tsig.RemoveDelegate (value);"); sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t}"); sw.WriteLine(); + } + + public void Generate (GenerationInfo gen_info, ClassBase implementor) + { + StreamWriter sw = gen_info.Writer; + + if (implementor == null) + GenEventHandler (gen_info); + + GenCallback (sw); + GenDefaultHandlerDelegate (sw, implementor); + GenVirtualMethod (sw, implementor); + GenEvent (sw, implementor, "this"); Statistics.SignalCount++; } diff --git a/generator/VMSignature.cs b/generator/VMSignature.cs index f9e7dc177..3f2b70145 100644 --- a/generator/VMSignature.cs +++ b/generator/VMSignature.cs @@ -48,6 +48,9 @@ namespace GtkSharp.Generation { if (p.CType == "GError**") continue; + if (p.Scope == "notified") + i += 2; + this.parms.Add (p); } } diff --git a/generator/VirtualMethod.cs b/generator/VirtualMethod.cs index 3f658ff37..ff6089fc9 100644 --- a/generator/VirtualMethod.cs +++ b/generator/VirtualMethod.cs @@ -27,39 +27,26 @@ namespace GtkSharp.Generation { using System.Xml; // FIXME: handle static VMs - public class VirtualMethod { + public class VirtualMethod : MethodBase { XmlElement elem; ReturnValue retval; Parameters parms; - public VirtualMethod (XmlElement elem, ClassBase container_type) + public VirtualMethod (XmlElement elem, ClassBase container_type) : base (elem, container_type) { this.elem = elem; retval = new ReturnValue (elem ["return-type"]); parms = new Parameters (elem["parameters"]); } - public string CName { - get { - return elem.GetAttribute("cname"); - } - } - - public string Declaration { - get { - VMSignature vmsig = new VMSignature (parms); - return retval.CSType + " " + Name + " (" + vmsig + ");"; - } - } - - bool IsGetter { + public bool IsGetter { get { return (Name.StartsWith ("Get") || Name.StartsWith ("Has")) && ((!retval.IsVoid && parms.Count == 1) || (retval.IsVoid && parms.Count == 2 && parms [1].PassAs == "out")); } } - bool IsSetter { + public bool IsSetter { get { if (!Name.StartsWith ("Set") || !retval.IsVoid) return false; @@ -89,7 +76,7 @@ namespace GtkSharp.Generation { return; ManagedCallString call = new ManagedCallString (parms); - string type = parms [0].CSType; + string type = parms [0].CSType + "Implementor"; string name = parms [0].Name; string call_string = "__obj." + Name + " (" + call + ")"; if (IsGetter) @@ -102,25 +89,55 @@ namespace GtkSharp.Generation { sw.WriteLine (); sw.WriteLine ("\t\tstatic " + MarshalReturnType + " " + Name + "Callback (" + parms.ImportSignature + ")"); sw.WriteLine ("\t\t{"); - sw.WriteLine ("\t\t\t" + type + " __obj = GLib.Object.GetObject (" + name + ", false) as " + type + ";"); - sw.Write (call.Setup ("\t\t\t")); + sw.WriteLine ("\t\t\ttry {"); + sw.WriteLine ("\t\t\t\t" + type + " __obj = GLib.Object.GetObject (" + name + ", false) as " + type + ";"); + sw.Write (call.Setup ("\t\t\t\t")); if (retval.IsVoid) { if (IsGetter) { Parameter p = parms [1]; string out_name = p.Name; if (p.MarshalType != p.CSType) out_name = "my" + out_name; - sw.WriteLine ("\t\t\t" + out_name + " = " + call_string + ";"); + sw.WriteLine ("\t\t\t\t" + out_name + " = " + call_string + ";"); } else - sw.WriteLine ("\t\t\t" + call_string + ";"); + sw.WriteLine ("\t\t\t\t" + call_string + ";"); } else - sw.WriteLine ("\t\t\t" + retval.ToNativeType + " result = " + retval.ToNative (call_string) + ";"); - sw.Write (call.Finish ("\t\t\t")); + sw.WriteLine ("\t\t\t\t" + retval.ToNativeType + " result = " + retval.ToNative (call_string) + ";"); + string finish = call.Finish ("\t\t\t\t"); + bool fatal = parms.HasOutParam || !retval.IsVoid; + sw.Write (call.Finish ("\t\t\t\t")); if (!retval.IsVoid) - sw.WriteLine ("\t\t\treturn result;"); + sw.WriteLine ("\t\t\t\treturn result;"); + + sw.WriteLine ("\t\t\t} catch (Exception e) {"); + sw.WriteLine ("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, " + (fatal ? "true" : "false") + ");"); + if (fatal) { + sw.WriteLine ("\t\t\t\t// NOTREACHED: above call does not return."); + sw.WriteLine ("\t\t\t\tthrow e;"); + } + sw.WriteLine ("\t\t\t}"); sw.WriteLine ("\t\t}"); } + public void GenerateDeclaration (StreamWriter sw, VirtualMethod complement) + { + VMSignature vmsig = new VMSignature (parms); + if (IsGetter) { + string name = Name.StartsWith ("Get") ? Name.Substring (3) : Name; + string type = retval.IsVoid ? parms [1].CSType : retval.CSType; + if (complement != null && complement.parms [1].CSType == type) + sw.WriteLine ("\t\t" + type + " " + name + " { get; set; }"); + else { + sw.WriteLine ("\t\t" + type + " " + name + " { get; }"); + if (complement != null) + sw.WriteLine ("\t\t" + complement.retval.CSType + " " + complement.Name + " (" + (new VMSignature (complement.parms)) + ");"); + } + } else if (IsSetter) + sw.WriteLine ("\t\t" + parms[1].CSType + " " + Name.Substring (3) + " { set; }"); + else + sw.WriteLine ("\t\t" + retval.CSType + " " + Name + " (" + vmsig + ");"); + } + enum ValidState { Unvalidated, Invalid, @@ -138,7 +155,7 @@ namespace GtkSharp.Generation { } } - bool Validate () + public override bool Validate () { if (!parms.Validate () || !retval.Validate ()) { Console.Write ("in virtual method " + Name + " "); diff --git a/gtk/CellLayoutAdapter.custom b/gtk/CellLayoutAdapter.custom new file mode 100644 index 000000000..e420f18d4 --- /dev/null +++ b/gtk/CellLayoutAdapter.custom @@ -0,0 +1,31 @@ +// Gtk.CellLayoutAdaptor.custom - Gtk CellLayoutAdaptor customizations +// +// Authors: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + + + public void SetAttributes (CellRenderer cell, params object[] attrs) + { + if (attrs.Length % 2 != 0) + throw new ArgumentException ("attrs should contain pairs of attribute/col"); + + ClearAttributes (cell); + for (int i = 0; i < attrs.Length - 1; i += 2) { + AddAttribute (cell, (string) attrs [i], (int) attrs [i + 1]); + } + } diff --git a/gtk/FileChooserAdapter.custom b/gtk/FileChooserAdapter.custom new file mode 100644 index 000000000..e5b78dcb4 --- /dev/null +++ b/gtk/FileChooserAdapter.custom @@ -0,0 +1,43 @@ +// Gtk.FileChooserAdapter.custom - Gtk FileChooserAdapter customizations +// +// Authors: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + + + [DllImport ("libgtk-win32-2.0-0.dll")] + static extern IntPtr gtk_file_chooser_get_filenames (IntPtr raw); + + public string[] Filenames { + get { + IntPtr raw_ret = gtk_file_chooser_get_filenames (Handle); + GLib.SList list = new GLib.SList (raw_ret, typeof (GLib.ListBase.FilenameString), true, true); + return (string[]) GLib.Marshaller.ListToArray (list, typeof (string)); + } + } + + [DllImport ("libgtk-win32-2.0-0.dll")] + static extern IntPtr gtk_file_chooser_list_shortcut_folders (IntPtr raw); + + public string[] ShortcutFolders { + get { + IntPtr raw_ret = gtk_file_chooser_list_shortcut_folders (Handle); + GLib.SList list = new GLib.SList (raw_ret, typeof (GLib.ListBase.FilenameString), true, true); + return (string[]) GLib.Marshaller.ListToArray (list, typeof (string)); + } + } + diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 0281f7168..4cee7ac98 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -49,6 +49,7 @@ customs = \ CellRendererText.custom \ CellRendererToggle.custom \ CellLayout.custom \ + CellLayoutAdapter.custom \ CellView.custom \ CheckMenuItem.custom \ Clipboard.custom \ @@ -63,6 +64,7 @@ customs = \ Entry.custom \ EntryCompletion.custom \ FileChooser.custom \ + FileChooserAdapter.custom \ FileChooserButton.custom \ FileChooserDialog.custom \ FileChooserWidget.custom \ @@ -115,11 +117,13 @@ customs = \ TooltipsData.custom \ TreeIter.custom \ TreeModel.custom \ + TreeModelAdapter.custom \ TreeModelFilter.custom \ TreeModelSort.custom \ TreePath.custom \ TreeSelection.custom \ TreeSortable.custom \ + TreeSortableAdapter.custom \ TreeStore.custom \ TreeViewColumn.custom \ TreeView.custom \ diff --git a/gtk/TreeIter.custom b/gtk/TreeIter.custom index d0b462afb..2ddfabe42 100644 --- a/gtk/TreeIter.custom +++ b/gtk/TreeIter.custom @@ -35,7 +35,7 @@ ti._user_data3 == _user_data3; } - internal IntPtr UserData { + public IntPtr UserData { get { return _user_data; } diff --git a/gtk/TreeModelAdapter.custom b/gtk/TreeModelAdapter.custom new file mode 100644 index 000000000..a1f5d9943 --- /dev/null +++ b/gtk/TreeModelAdapter.custom @@ -0,0 +1,181 @@ +// Gtk.TreeModelAdapter.custom - Gtk TreeModelAdapter customizations +// +// Author: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + + + [DllImport("libgtk-win32-2.0-0.dll")] + static extern bool gtk_tree_model_iter_children (IntPtr raw, out Gtk.TreeIter iter, IntPtr parent); + public bool IterChildren (out Gtk.TreeIter iter) { + bool raw_ret = gtk_tree_model_iter_children (Handle, out iter, IntPtr.Zero); + bool ret = raw_ret; + return ret; + } + + public int IterNChildren () { + int raw_ret = gtk_tree_model_iter_n_children (Handle, IntPtr.Zero); + int ret = raw_ret; + return ret; + } + + [DllImport("libgtk-win32-2.0-0.dll")] + static extern bool gtk_tree_model_iter_nth_child (IntPtr raw, out Gtk.TreeIter iter, IntPtr parent, int n); + public bool IterNthChild (out Gtk.TreeIter iter, int n) { + bool raw_ret = gtk_tree_model_iter_nth_child (Handle, out iter, IntPtr.Zero, n); + bool ret = raw_ret; + return ret; + } + + public void SetValue (Gtk.TreeIter iter, int column, bool value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, double value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, int value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, string value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, float value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, uint value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public void SetValue (Gtk.TreeIter iter, int column, object value) { + SetValue (iter, column, new GLib.Value (value)); + } + + public object GetValue (Gtk.TreeIter iter, int column) { + GLib.Value val = GLib.Value.Empty; + GetValue (iter, column, ref val); + object ret = val.Val; + val.Dispose (); + return ret; + } + + [GLib.CDeclCallback] + delegate void RowsReorderedSignalDelegate (IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch); + + static void RowsReorderedSignalCallback (IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch) + { + Gtk.RowsReorderedArgs args = new Gtk.RowsReorderedArgs (); + try { + GLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal; + if (sig == null) + throw new Exception("Unknown signal GC handle received " + gch); + + TreeModelFilter sender = GLib.Object.GetObject (arg0) as TreeModelFilter; + args.Args = new object[3]; + args.Args[0] = arg1 == IntPtr.Zero ? null : (Gtk.TreePath) GLib.Opaque.GetOpaque (arg1, typeof (Gtk.TreePath), false); + args.Args[1] = Gtk.TreeIter.New (arg2); + int child_cnt = sender.IterNChildren ((TreeIter)args.Args[1]); + int[] new_order = new int [child_cnt]; + Marshal.Copy (arg3, new_order, 0, child_cnt); + args.Args[2] = new_order; + Gtk.RowsReorderedHandler handler = (Gtk.RowsReorderedHandler) sig.Handler; + handler (sender, args); + } catch (Exception e) { + GLib.ExceptionManager.RaiseUnhandledException (e, false); + } + } + +#if false + [GLib.CDeclCallback] + delegate void RowsReorderedVMDelegate (IntPtr tree_model, IntPtr path, IntPtr iter, IntPtr new_order); + + static RowsReorderedVMDelegate RowsReorderedVMCallback; + + static void rowsreordered_cb (IntPtr tree_model, IntPtr path_ptr, IntPtr iter_ptr, IntPtr new_order) + { + try { + TreeModelFilter store = GLib.Object.GetObject (tree_model, false) as TreeModelFilter; + TreePath path = GLib.Opaque.GetOpaque (path_ptr, typeof (TreePath), false) as TreePath; + TreeIter iter = TreeIter.New (iter_ptr); + int child_cnt = store.IterNChildren (iter); + int[] child_order = new int [child_cnt]; + Marshal.Copy (new_order, child_order, 0, child_cnt); + store.OnRowsReordered (path, iter, child_order); + } catch (Exception e) { + GLib.ExceptionManager.RaiseUnhandledException (e, true); + // NOTREACHED: above call doesn't return + throw e; + } + } + + private static void OverrideRowsReordered (GLib.GType gtype) + { + if (RowsReorderedVMCallback == null) + RowsReorderedVMCallback = new RowsReorderedVMDelegate (rowsreordered_cb); + OverrideVirtualMethod (gtype, "rows_reordered", RowsReorderedVMCallback); + } + + [Obsolete ("Replaced by int[] new_order overload.")] + [GLib.DefaultSignalHandler(Type=typeof(Gtk.TreeModelFilter), ConnectionMethod="OverrideRowsReordered")] + protected virtual void OnRowsReordered (Gtk.TreePath path, Gtk.TreeIter iter, out int new_order) + { + new_order = -1; + } + + [GLib.DefaultSignalHandler(Type=typeof(Gtk.TreeModelFilter), ConnectionMethod="OverrideRowsReordered")] + protected virtual void OnRowsReordered (Gtk.TreePath path, Gtk.TreeIter iter, int[] new_order) + { + int dummy; + OnRowsReordered (path, iter, out dummy); + GLib.Value ret = GLib.Value.Empty; + GLib.ValueArray inst_and_params = new GLib.ValueArray (4); + GLib.Value[] vals = new GLib.Value [4]; + vals [0] = new GLib.Value (this); + inst_and_params.Append (vals [0]); + vals [1] = new GLib.Value (path); + inst_and_params.Append (vals [1]); + vals [2] = new GLib.Value (iter); + inst_and_params.Append (vals [2]); + int cnt = IterNChildren (iter); + IntPtr new_order_ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (int)) * cnt); + Marshal.Copy (new_order, 0, new_order_ptr, cnt); + vals [3] = new GLib.Value (new_order_ptr); + inst_and_params.Append (vals [3]); + g_signal_chain_from_overridden (inst_and_params.ArrayPtr, ref ret); + Marshal.FreeHGlobal (new_order_ptr); + + foreach (GLib.Value v in vals) + v.Dispose (); + } + +#endif + [GLib.Signal("rows_reordered")] + public event Gtk.RowsReorderedHandler RowsReordered { + add { + GLib.Signal sig = GLib.Signal.Lookup (GLib.Object.GetObject (Handle), "rows_reordered", new RowsReorderedSignalDelegate(RowsReorderedSignalCallback)); + sig.AddDelegate (value); + } + remove { + GLib.Signal sig = GLib.Signal.Lookup (GLib.Object.GetObject (Handle), "rows_reordered", new RowsReorderedSignalDelegate(RowsReorderedSignalCallback)); + sig.RemoveDelegate (value); + } + } + diff --git a/gtk/TreeSortableAdapter.custom b/gtk/TreeSortableAdapter.custom new file mode 100644 index 000000000..f133a4e84 --- /dev/null +++ b/gtk/TreeSortableAdapter.custom @@ -0,0 +1,36 @@ +// Gtk.TreeSortableAdapter.Custom - Gtk TreeSortableAdapter class customizations +// +// Author: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This code is inserted after the automatically generated code. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + + + [Obsolete ("Replaced by SetSortFunc (int, TreeIterCompareFunc) overload.")] + public void SetSortFunc (int sort_column_id, TreeIterCompareFunc sort_func, IntPtr user_data, Gtk.DestroyNotify destroy) + { + SetSortFunc (sort_column_id, sort_func); + } + + [Obsolete ("Replaced by DefaultSortFunc property.")] + public void SetDefaultSortFunc (TreeIterCompareFunc sort_func, IntPtr user_data, Gtk.DestroyNotify destroy) + { + DefaultSortFunc = sort_func; + } + + diff --git a/sample/Makefile.am b/sample/Makefile.am index 43c47cdc1..03302677b 100755 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -16,7 +16,7 @@ DOTNET_TARGETS= DOTNET_ASSEMBLY= endif -TARGETS = polarfixed.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe testdnd.exe actions.exe $(GLADE_TARGETS) $(DOTNET_TARGETS) +TARGETS = polarfixed.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe treemodeldemo.exe testdnd.exe actions.exe $(GLADE_TARGETS) $(DOTNET_TARGETS) DEBUGS = $(addsuffix .mdb, $(TARGETS)) @@ -59,6 +59,9 @@ managedtreeviewdemo.exe: $(srcdir)/ManagedTreeViewDemo.cs $(assemblies) nodeviewdemo.exe: $(srcdir)/NodeViewDemo.cs $(assemblies) $(CSC) /out:nodeviewdemo.exe $(references) $(srcdir)/NodeViewDemo.cs +treemodeldemo.exe: $(srcdir)/TreeModelDemo.cs $(assemblies) + $(CSC) /out:treemodeldemo.exe $(references) $(srcdir)/TreeModelDemo.cs + glade-viewer.exe: $(srcdir)/GladeViewer.cs $(assemblies) $(CSC) /out:glade-viewer.exe $(references) $(srcdir)/GladeViewer.cs diff --git a/sample/TreeModelDemo.cs b/sample/TreeModelDemo.cs new file mode 100644 index 000000000..4539cd444 --- /dev/null +++ b/sample/TreeModelDemo.cs @@ -0,0 +1,313 @@ +// TreeModelSample.cs - TreeModelSample application. +// +// Author: Mike Kestner +// +// Copyright (c) 2007 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser 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. + +namespace GtkSamples { + + using System; + using System.Collections; + using System.Reflection; + using System.Runtime.InteropServices; + using Gtk; + + public class TreeModelDemo : Gtk.Window { + + public TreeModelDemo () : base ("TreeModel demo") + { + DefaultSize = new Gdk.Size (640,480); + ScrolledWindow sw = new ScrolledWindow (); + TreeView view = new TreeView (new TreeModelAdapter (new MyTreeModel ())); + view.HeadersVisible = true; + view.AppendColumn ("Name", new CellRendererText (), "text", 0); + view.AppendColumn ("Type", new CellRendererText (), "text", 1); + sw.Add (view); + sw.ShowAll (); + Add (sw); + } + + protected override bool OnDeleteEvent (Gdk.Event ev) + { + Application.Quit (); + return true; + } + + public static void Main (string[] args) + { + Application.Init (); + Gtk.Window win = new TreeModelDemo (); + win.Show (); + Application.Run (); + } + + } + + public class MyTreeModel : GLib.Object, TreeModelImplementor { + + Assembly[] assemblies; + + public MyTreeModel () + { + assemblies = AppDomain.CurrentDomain.GetAssemblies (); + } + + object GetNodeAtPath (TreePath path) + { + if (path.Indices.Length > 0) { + Assembly assm = assemblies [path.Indices [0]]; + if (path.Indices.Length > 1) { + Type t = assm.GetTypes ()[path.Indices [1]]; + if (path.Indices.Length < 2) + return t.GetMembers () [path.Indices [2]]; + else + return t; + } else + return assm; + } else + return null; + } + + Hashtable node_hash = new Hashtable (); + + public TreeModelFlags Flags { + get { + return TreeModelFlags.ItersPersist; + } + } + + public int NColumns { + get { + return 2; + } + } + + public GLib.GType GetColumnType (int col) + { + GLib.GType result = GLib.GType.String; + return result; + } + + TreeIter IterFromNode (object node) + { + GCHandle gch; + if (node_hash [node] != null) + gch = (GCHandle) node_hash [node]; + else + gch = GCHandle.Alloc (node); + TreeIter result = TreeIter.Zero; + result.UserData = (IntPtr) gch; + return result; + } + + object NodeFromIter (TreeIter iter) + { + GCHandle gch = (GCHandle) iter.UserData; + return gch.Target; + } + + TreePath PathFromNode (object node) + { + if (node == null) + return new TreePath (); + + object work = node; + TreePath path = new TreePath (); + + if (work is MemberInfo) { + Type parent = (work as MemberInfo).ReflectedType; + path.PrependIndex (Array.IndexOf (parent.GetMembers (), work)); + work = parent; + } + + if (work is Type) { + Assembly assm = (work as Type).Assembly; + path.PrependIndex (Array.IndexOf (assm.GetTypes (), work)); + work = assm; + } + + if (work is Assembly) + path.PrependIndex (Array.IndexOf (assemblies, node)); + + return path; + } + + public bool GetIter (out TreeIter iter, TreePath path) + { + if (path == null) + throw new ArgumentNullException ("path"); + + iter = TreeIter.Zero; + + object node = GetNodeAtPath (path); + if (node == null) + return false; + + iter = IterFromNode (node); + return true; + } + + public TreePath GetPath (TreeIter iter) + { + object node = NodeFromIter (iter); + if (node == null) + throw new ArgumentException ("iter"); + + return PathFromNode (node); + } + + public void GetValue (TreeIter iter, int col, ref GLib.Value val) + { + object node = NodeFromIter (iter); + if (node == null) + return; + + if (node is Assembly) + val = new GLib.Value (col == 0 ? (node as Assembly).GetName ().Name : "Assembly"); + else if (node is Type) + val = new GLib.Value (col == 0 ? (node as Type).Name : "Type"); + else + val = new GLib.Value (col == 0 ? (node as MemberInfo).Name : "Member"); + } + + public bool IterNext (ref TreeIter iter) + { + object node = NodeFromIter (iter); + if (node == null) + return false; + + int idx; + if (node is Assembly) { + idx = Array.IndexOf (assemblies, node) + 1; + if (idx < assemblies.Length) { + iter = IterFromNode (assemblies [idx]); + return true; + } + } else if (node is Type) { + Type[] siblings = (node as Type).Assembly.GetTypes (); + idx = Array.IndexOf (siblings, node) + 1; + if (idx < siblings.Length) { + iter = IterFromNode (siblings [idx]); + return true; + } + } else { + MemberInfo[] siblings = (node as MemberInfo).ReflectedType.GetMembers (); + idx = Array.IndexOf (siblings, node) + 1; + if (idx < siblings.Length) { + iter = IterFromNode (siblings [idx]); + return true; + } + } + return false; + } + + int ChildCount (object node) + { + if (node is Assembly) + return (node as Assembly).GetTypes ().Length; + else if (node is Type) + return (node as Type).GetMembers ().Length; + else + return 0; + } + + public bool IterChildren (out TreeIter child, TreeIter parent) + { + child = TreeIter.Zero; + + if (parent.UserData == IntPtr.Zero) { + child = IterFromNode (assemblies [0]); + return true; + } + + object node = NodeFromIter (parent); + if (node == null || ChildCount (node) <= 0) + return false; + + if (node is Assembly) + child = IterFromNode ((node as Assembly).GetTypes () [0]); + else if (node is Type) + child = IterFromNode ((node as Type).GetMembers () [0]); + return true; + } + + public bool IterHasChild (TreeIter iter) + { + object node = NodeFromIter (iter); + if (node == null || ChildCount (node) <= 0) + return false; + + return true; + } + + public int IterNChildren (TreeIter iter) + { + if (iter.UserData == IntPtr.Zero) + return assemblies.Length; + + object node = NodeFromIter (iter); + if (node == null) + return 0; + + return ChildCount (node); + } + + public bool IterNthChild (out TreeIter child, TreeIter parent, int n) + { + child = TreeIter.Zero; + + if (parent.UserData == IntPtr.Zero) { + if (assemblies.Length <= n) + return false; + child = IterFromNode (assemblies [n]); + return true; + } + + object node = NodeFromIter (parent); + if (node == null || ChildCount (node) <= n) + return false; + + if (node is Assembly) + child = IterFromNode ((node as Assembly).GetTypes () [n]); + else if (node is Type) + child = IterFromNode ((node as Type).GetMembers () [n]); + return true; + } + + public bool IterParent (out TreeIter parent, TreeIter child) + { + parent = TreeIter.Zero; + object node = NodeFromIter (child); + if (node == null || node is Assembly) + return false; + + if (node is Type) + parent = IterFromNode ((node as Type).Assembly); + else if (node is MemberInfo) + parent = IterFromNode ((node as MemberInfo).ReflectedType); + return true; + } + + public void RefNode (TreeIter iter) + { + } + + public void UnrefNode (TreeIter iter) + { + } + } +}