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

Reply via email to