Hi,
I have figured out two related bugs in the TreeModelFilter and
TreeModelAdapter classes of Gtk#.
Since the SetValue(iter, column, value) methods are not members of the
underlying Gtk+ TreeModel class, they have been added in the Gtk#
implementation(in TreeModel.custom). This makes sense because the two
main implementors of this interface - TreeStore and ListStore - both
provide these methods.
But the TreeModelFilter(which also extends these interfaces) does NOT
implement these SetValue methods. That's why Gtk# has to call the
SetValue method of the child model whenever this method is called in the
TreeModelFilter.
Currently Gtk# assumes that there is a SetValue method for the
TreeModelFilter(something like tree_model_filter_set_value) and calls it
everytime:
public void SetValue (Gtk.TreeIter iter, int column, object value) {
SetValue (iter, column, new GLib.Value (value));
}
But this function is calling itself since a GLib.Value is also an
object. This finally leads to a stack overflow when calling this method
from a Gtk.TreeModelFilter.
I have fixed this error via calling the SetValue method of the child model:
this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
There is just one case when this solution won't work: When using a
ModifyFunc that replaces the original columns in the child model(then
the column number in the filter cannot be converted into an "original"
column number in the child model). But as I already reported(maybe a bit
angrily) the ModifyFunc won't work anyway with Gtk#(or at least it has
not worked half a year ago). Maybe a check should be implemented whether
the user has set up a ModifyFunc on the filter and then, if so, throw an
exception.
The second similar bug affects the TreeModelAdapter. Calling the
SetValue methods will also result in a stack overflow due to the same
reason. But this time the adapter has to pass the call to SetValue
method of the implementor class. I implemented this functionality using
reflection and the Invoke() method of the MethodInfo class. A better or
more faster solution is in my opinion not possible.
I have attached two patches for the mentioned problems, both are tested
and work for me; I would be great if you commit them or post me a little
feedback.
Christian Hoff
43c43,66
<
---
>
> // This hashtable will hold MethodInfos containing the methods in the underlying implementor class that are to be called
> private System.Collections.Hashtable ImplementedSetMethods;
> private void GetImplementedMethods() {
> System.Type ImplementorType = this.Implementor.GetType();
> ImplementedSetMethods = new System.Collections.Hashtable(7);
> System.Type[] SetValueTypes = new System.Type[7] {typeof(object), typeof(bool), typeof(double), typeof(int), typeof(string), typeof(float), typeof(uint)};
> for(int TypeIndex = 0; TypeIndex < 7; TypeIndex++) {
> System.Reflection.MethodInfo SetMethod = ImplementorType.GetMethod("SetValue", System.Reflection.BindingFlags.ExactBinding|System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance, null, new System.Type[] {typeof(Gtk.TreeIter), typeof(int), SetValueTypes[TypeIndex]} , new System.Reflection.ParameterModifier[] {});
> if(SetMethod == null) {
> // Method not implemented by the implementor
> if(SetValueTypes[TypeIndex] == typeof(object)) {
> // Method(Gtk.TreeIter, int, object) not implemented by the implementor
> // Throw error
> throw(new System.NotImplementedException("The underlying implementor does not implement interface method SetValue(Gtk.TreeIter, int, object)"));
> } else {
> // Use SetValue(Gtk.TreeIter, int, object) instead
> SetMethod = (System.Reflection.MethodInfo) ImplementedSetMethods[typeof(object)];
> }
> }
> ImplementedSetMethods.Add(SetValueTypes[TypeIndex], SetMethod);
> }
> }
>
45c68,70
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(bool)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
49c74,76
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(double)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
53c80,82
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(int)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
57c86,88
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(string)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
61c92,94
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(float)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
65c98,100
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(uint)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
69c104,106
< SetValue (iter, column, new GLib.Value (value));
---
> if(ImplementedSetMethods == null)
> GetImplementedMethods();
> (ImplementedSetMethods[typeof(object)] as System.Reflection.MethodInfo).Invoke(this.Implementor, new System.Object[] {iter, column, value} );
70a108
>
24c24
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
28c28
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
32c32
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
36c36
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
40c40
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
44c44
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
48c48
< SetValue (iter, column, new GLib.Value (value));
---
> this.Model.SetValue(this.ConvertIterToChildIter(iter), column, value);
50c50
<
---
>
_______________________________________________
Gtk-sharp-list maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/gtk-sharp-list