1 // Gtk.TreeStore.cs - Gtk TreeStore class customizations
2 //
3 // Authors: Kristian Rietveld <kris@gtk.org>
4 //          Mike Kestner <mkestner@ximian.com>
5 //
6 // Copyright (c) 2002 Kristian Rietveld
7 // Copyright (c) 2004 Novell, Inc.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of version 2 of the Lesser GNU General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this program; if not, write to the
20 // Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 // Boston, MA 02111-1307, USA.
22 
23 namespace Gtk {
24 
25 	using System;
26 	using System.Runtime.InteropServices;
27 
28 	public partial class TreeStore {
29 
30 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_append(IntPtr raw, out TreeIter iter, ref TreeIter parent)31 		static extern void gtk_tree_store_append (IntPtr raw, out TreeIter iter, ref TreeIter parent);
32 
33 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_append(IntPtr raw, out TreeIter iter, IntPtr parent)34 		static extern void gtk_tree_store_append (IntPtr raw, out TreeIter iter, IntPtr parent);
35 
AppendNode()36 		public TreeIter AppendNode ()
37 		{
38 			TreeIter iter;
39 			gtk_tree_store_append (Handle, out iter, IntPtr.Zero);
40 			return iter;
41 		}
42 
AppendNode(TreeIter parent)43 		public TreeIter AppendNode (TreeIter parent)
44 		{
45 			TreeIter iter;
46 			gtk_tree_store_append (Handle, out iter, ref parent);
47 			return iter;
48 		}
49 
50 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert(IntPtr raw, out TreeIter iter, ref TreeIter parent, int position)51 		static extern void gtk_tree_store_insert (IntPtr raw, out TreeIter iter, ref TreeIter parent, int position);
52 
53 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert(IntPtr raw, out TreeIter iter, IntPtr parent, int position)54 		static extern void gtk_tree_store_insert (IntPtr raw, out TreeIter iter, IntPtr parent, int position);
55 
InsertNode(TreeIter parent, int position)56 		public TreeIter InsertNode (TreeIter parent, int position)
57 		{
58 			TreeIter iter;
59 			gtk_tree_store_insert (Handle, out iter, ref parent, position);
60 			return iter;
61 		}
62 
InsertNode(int position)63 		public TreeIter InsertNode (int position)
64 		{
65 			TreeIter iter;
66 			gtk_tree_store_insert (Handle, out iter, IntPtr.Zero, position);
67 			return iter;
68 		}
69 
70 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_prepend(IntPtr raw, out TreeIter iter, ref TreeIter parent)71 		static extern void gtk_tree_store_prepend (IntPtr raw, out TreeIter iter, ref TreeIter parent);
72 
73 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_prepend(IntPtr raw, out TreeIter iter, IntPtr parent)74 		static extern void gtk_tree_store_prepend (IntPtr raw, out TreeIter iter, IntPtr parent);
75 
PrependNode(TreeIter parent)76 		public TreeIter PrependNode (TreeIter parent)
77 		{
78 			TreeIter iter;
79 			gtk_tree_store_prepend (Handle, out iter, ref parent);
80 			return iter;
81 		}
82 
PrependNode()83 		public TreeIter PrependNode ()
84 		{
85 			TreeIter iter;
86 			gtk_tree_store_prepend (Handle, out iter, IntPtr.Zero);
87 			return iter;
88 		}
89 
90 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_before(IntPtr raw, out TreeIter iter, ref TreeIter parent, ref TreeIter sibling)91 		static extern void gtk_tree_store_insert_before (IntPtr raw, out TreeIter iter, ref TreeIter parent, ref TreeIter sibling);
92 
93 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_before(IntPtr raw, out TreeIter iter, IntPtr parent, ref TreeIter sibling)94 		static extern void gtk_tree_store_insert_before (IntPtr raw, out TreeIter iter, IntPtr parent, ref TreeIter sibling);
95 
InsertNodeBefore(TreeIter sibling)96 		public TreeIter InsertNodeBefore (TreeIter sibling)
97 		{
98 			TreeIter iter;
99 			gtk_tree_store_insert_before (Handle, out iter, IntPtr.Zero, ref sibling);
100 			return iter;
101 		}
102 
InsertNodeBefore(TreeIter parent, TreeIter sibling)103 		public TreeIter InsertNodeBefore (TreeIter parent, TreeIter sibling)
104 		{
105 			TreeIter iter;
106 			gtk_tree_store_insert_before (Handle, out iter, ref parent, ref sibling);
107 			return iter;
108 		}
109 
110 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_after(IntPtr raw, out TreeIter iter, ref TreeIter parent, ref TreeIter sibling)111 		static extern void gtk_tree_store_insert_after (IntPtr raw, out TreeIter iter, ref TreeIter parent, ref TreeIter sibling);
112 
113 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_after(IntPtr raw, out TreeIter iter, IntPtr parent, ref TreeIter sibling)114 		static extern void gtk_tree_store_insert_after (IntPtr raw, out TreeIter iter, IntPtr parent, ref TreeIter sibling);
115 
InsertNodeAfter(TreeIter sibling)116 		public TreeIter InsertNodeAfter (TreeIter sibling)
117 		{
118 			TreeIter iter;
119 			gtk_tree_store_insert_after (Handle, out iter, IntPtr.Zero, ref sibling);
120 			return iter;
121 		}
122 
InsertNodeAfter(TreeIter parent, TreeIter sibling)123 		public TreeIter InsertNodeAfter (TreeIter parent, TreeIter sibling)
124 		{
125 			TreeIter iter;
126 			gtk_tree_store_insert_after (Handle, out iter, ref parent, ref sibling);
127 			return iter;
128 		}
129 
130 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_model_iter_children(IntPtr raw, out Gtk.TreeIter iter, IntPtr parent)131 		static extern bool gtk_tree_model_iter_children (IntPtr raw, out Gtk.TreeIter iter, IntPtr parent);
IterChildren(out Gtk.TreeIter iter)132 		public bool IterChildren (out Gtk.TreeIter iter) {
133 			bool raw_ret = gtk_tree_model_iter_children (Handle, out iter, IntPtr.Zero);
134 			bool ret = raw_ret;
135 			return ret;
136 		}
137 
IterNChildren()138 		public int IterNChildren () {
139 			int raw_ret = gtk_tree_model_iter_n_children (Handle, IntPtr.Zero);
140 			int ret = raw_ret;
141 			return ret;
142 		}
143 
144 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_model_iter_nth_child(IntPtr raw, out Gtk.TreeIter iter, IntPtr parent, int n)145 		static extern bool gtk_tree_model_iter_nth_child (IntPtr raw, out Gtk.TreeIter iter, IntPtr parent, int n);
IterNthChild(out Gtk.TreeIter iter, int n)146 		public bool IterNthChild (out Gtk.TreeIter iter, int n) {
147 			bool raw_ret = gtk_tree_model_iter_nth_child (Handle, out iter, IntPtr.Zero, n);
148 			bool ret = raw_ret;
149 			return ret;
150 		}
151 
SetValue(Gtk.TreeIter iter, int column, bool value)152 		public void SetValue (Gtk.TreeIter iter, int column, bool value)
153 		{
154 			GLib.Value val = new GLib.Value (value);
155 			SetValue (iter, column, val);
156 			val.Dispose ();
157 		}
158 
SetValue(Gtk.TreeIter iter, int column, double value)159 		public void SetValue (Gtk.TreeIter iter, int column, double value)
160 		{
161 			GLib.Value val = new GLib.Value (value);
162 			SetValue (iter, column, val);
163 			val.Dispose ();
164 		}
165 
SetValue(Gtk.TreeIter iter, int column, int value)166 		public void SetValue (Gtk.TreeIter iter, int column, int value)
167 		{
168 			GLib.Value val = new GLib.Value (value);
169 			SetValue (iter, column, val);
170 			val.Dispose ();
171 		}
172 
SetValue(Gtk.TreeIter iter, int column, string value)173 		public void SetValue (Gtk.TreeIter iter, int column, string value)
174 		{
175 			GLib.Value val = new GLib.Value (value);
176 			SetValue (iter, column, val);
177 			val.Dispose ();
178 		}
179 
SetValue(Gtk.TreeIter iter, int column, float value)180 		public void SetValue (Gtk.TreeIter iter, int column, float value)
181 		{
182 			GLib.Value val = new GLib.Value (value);
183 			SetValue (iter, column, val);
184 			val.Dispose ();
185 		}
186 
SetValue(Gtk.TreeIter iter, int column, uint value)187 		public void SetValue (Gtk.TreeIter iter, int column, uint value)
188 		{
189 			GLib.Value val = new GLib.Value (value);
190 			SetValue (iter, column, val);
191 			val.Dispose ();
192 		}
193 
SetValue(Gtk.TreeIter iter, int column, object value)194 		public void SetValue (Gtk.TreeIter iter, int column, object value)
195 		{
196 			GLib.Value val = new GLib.Value (value);
197 			SetValue (iter, column, val);
198 			val.Dispose ();
199 		}
200 
_AppendValues(Gtk.TreeIter iter, Array values)201 		private void _AppendValues (Gtk.TreeIter iter, Array values) {
202 			int col = 0;
203 			foreach (object value in values) {
204 				if (value != null)
205 					SetValue (iter, col, value);
206 				col++;
207 			}
208 		}
209 
AppendValues(Gtk.TreeIter parent, Array values)210 		public Gtk.TreeIter AppendValues (Gtk.TreeIter parent, Array values) {
211 			Gtk.TreeIter iter = AppendNode (parent);
212 			_AppendValues (iter, values);
213 			return iter;
214 		}
215 
AppendValues(Gtk.TreeIter parent, params object[] values)216 		public Gtk.TreeIter AppendValues (Gtk.TreeIter parent, params object[] values) {
217 			return AppendValues (parent, (Array) values);
218 		}
219 
AppendValues(Array values)220 		public Gtk.TreeIter AppendValues (Array values) {
221 			Gtk.TreeIter iter = AppendNode ();
222 			_AppendValues (iter, values);
223 			return iter;
224 		}
225 
AppendValues(params object[] values)226 		public Gtk.TreeIter AppendValues (params object[] values) {
227 			return AppendValues ((Array) values);
228 		}
229 
230 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_with_valuesv(IntPtr raw, out TreeIter iter, IntPtr parent, int position, int[] columns, GLib.Value[] values, int n_values)231 		static extern void gtk_tree_store_insert_with_valuesv(IntPtr raw, out TreeIter iter, IntPtr parent, int position, int[] columns, GLib.Value[] values, int n_values);
232 
233 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_insert_with_valuesv(IntPtr raw, out TreeIter iter, ref TreeIter parent, int position, int[] columns, GLib.Value[] values, int n_values)234 		static extern void gtk_tree_store_insert_with_valuesv(IntPtr raw, out TreeIter iter, ref TreeIter parent, int position, int[] columns, GLib.Value[] values, int n_values);
235 
InsertWithValues(int position, params object[] values)236 		public TreeIter InsertWithValues (int position, params object[] values)
237 		{
238 			return InsertWithValues(false, TreeIter.Zero, position, values);
239 		}
240 
InsertWithValues(TreeIter parent, int position, params object[] values)241 		public TreeIter InsertWithValues (TreeIter parent, int position, params object[] values)
242 		{
243 			return InsertWithValues(true, parent, position, values);
244 		}
245 
InsertWithValues(bool hasParent, TreeIter parent, int position, params object[] values)246 		private TreeIter InsertWithValues (bool hasParent, TreeIter parent, int position, params object[] values)
247 		{
248 			int[] columns = new int[values.Length];
249 			GLib.Value[] vals = new GLib.Value[values.Length];
250 			int n_values = 0;
251 
252 			for (int i = 0; i < values.Length; i++) {
253 				if (values[i] != null) {
254 					columns[n_values] = i;
255 					vals[n_values] = new GLib.Value (values[i]);
256 					n_values++;
257 				}
258 			}
259 
260 			TreeIter iter;
261 			if (hasParent)
262 				gtk_tree_store_insert_with_valuesv (Handle, out iter, ref parent, position, columns, vals, n_values);
263 			else
264 				gtk_tree_store_insert_with_valuesv (Handle, out iter, IntPtr.Zero, position, columns, vals, n_values);
265 
266 			for (int i = 0; i < n_values; i++)
267 				vals[i].Dispose ();
268 
269 			return iter;
270 		}
271 
272 		[DllImport (Global.GtkNativeDll, CallingConvention = CallingConvention.Cdecl)]
gtk_tree_store_set_valuesv(IntPtr raw, ref TreeIter iter, int[] columns, GLib.Value[] values, int n_values)273 		static extern void gtk_tree_store_set_valuesv(IntPtr raw, ref TreeIter iter, int[] columns, GLib.Value[] values, int n_values);
274 
SetValues(TreeIter iter, params object[] values)275 		public void SetValues (TreeIter iter, params object[] values)
276 		{
277 			int[] columns = new int[values.Length];
278 			GLib.Value[] vals = new GLib.Value[values.Length];
279 			int n_values = 0;
280 
281 			for (int i = 0; i < values.Length; i++) {
282 				if (values[i] != null) {
283 					columns[n_values] = i;
284 					vals[n_values] = new GLib.Value (values[i]);
285 					n_values++;
286 				}
287 			}
288 
289 			gtk_tree_store_set_valuesv (Handle, ref iter, columns, vals, n_values);
290 
291 			for (int i = 0; i < n_values; i++)
292 				vals[i].Dispose ();
293 		}
294 
TreeStore(params GLib.GType[] types)295 		public TreeStore (params GLib.GType[] types) : base (IntPtr.Zero)
296 		{
297 			CreateNativeObject (new string [0], new GLib.Value [0]);
298 			ColumnTypes = types;
299 		}
300 
TreeStore(params Type[] types)301 		public TreeStore (params Type[] types) : base (IntPtr.Zero)
302 		{
303 			GLib.GType[] gtypes = new GLib.GType[types.Length];
304 			int i = 0;
305 			foreach (Type type in types) {
306 				gtypes[i] = (GLib.GType) type;
307 				i++;
308 			}
309 
310 			CreateNativeObject (new string [0], new GLib.Value [0]);
311 			ColumnTypes = gtypes;
312 		}
313 
GetValue(Gtk.TreeIter iter, int column)314 		public object GetValue (Gtk.TreeIter iter, int column) {
315 			GLib.Value val = GLib.Value.Empty;
316 			GetValue (iter, column, ref val);
317 			object ret = val.Val;
318 			val.Dispose ();
319 			return ret;
320 		}
321 
322 		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
RowsReorderedSignalDelegate(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch)323 		delegate void RowsReorderedSignalDelegate (IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch);
324 
RowsReorderedSignalCallback(IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch)325 		static void RowsReorderedSignalCallback (IntPtr arg0, IntPtr arg1, IntPtr arg2, IntPtr arg3, IntPtr gch)
326 		{
327 			Gtk.RowsReorderedArgs args = new Gtk.RowsReorderedArgs ();
328 			try {
329 				GLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;
330 				if (sig == null)
331 					throw new Exception("Unknown signal GC handle received " + gch);
332 
333 				TreeStore sender = GLib.Object.GetObject (arg0) as TreeStore;
334 				args.Args = new object[3];
335 				args.Args[0] = arg1 == IntPtr.Zero ? null : (Gtk.TreePath) GLib.Opaque.GetOpaque (arg1, typeof (Gtk.TreePath), false);
336 				args.Args[1] = Gtk.TreeIter.New (arg2);
337 				int child_cnt = arg2 == IntPtr.Zero ? sender.IterNChildren () : sender.IterNChildren ((TreeIter)args.Args[1]);
338 				int[] new_order = new int [child_cnt];
339 				Marshal.Copy (arg3, new_order, 0, child_cnt);
340 				args.Args[2] = new_order;
341 				Gtk.RowsReorderedHandler handler = (Gtk.RowsReorderedHandler) sig.Handler;
342 				handler (sender, args);
343 			} catch (Exception e) {
344 				GLib.ExceptionManager.RaiseUnhandledException (e, false);
345 			}
346 		}
347 
348 		[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
RowsReorderedVMDelegate(IntPtr tree_model, IntPtr path, IntPtr iter, IntPtr new_order)349 		delegate void RowsReorderedVMDelegate (IntPtr tree_model, IntPtr path, IntPtr iter, IntPtr new_order);
350 
351 		static RowsReorderedVMDelegate RowsReorderedVMCallback;
352 
rowsreordered_cb(IntPtr tree_model, IntPtr path_ptr, IntPtr iter_ptr, IntPtr new_order)353 		static void rowsreordered_cb (IntPtr tree_model, IntPtr path_ptr, IntPtr iter_ptr, IntPtr new_order)
354 		{
355 			try {
356 				TreeStore store = GLib.Object.GetObject (tree_model, false) as TreeStore;
357 				TreePath path = GLib.Opaque.GetOpaque (path_ptr, typeof (TreePath), false) as TreePath;
358 				TreeIter iter = TreeIter.New (iter_ptr);
359 				int child_cnt = store.IterNChildren (iter);
360 				int[] child_order = new int [child_cnt];
361 				Marshal.Copy (new_order, child_order, 0, child_cnt);
362 				store.OnRowsReordered (path, iter, child_order);
363 			} catch (Exception e) {
364 				GLib.ExceptionManager.RaiseUnhandledException (e, true);
365 				// NOTREACHED: above call doesn't return
366 				throw e;
367 			}
368 		}
369 
OverrideRowsReordered(GLib.GType gtype)370 		private static void OverrideRowsReordered (GLib.GType gtype)
371 		{
372 			if (RowsReorderedVMCallback == null)
373 				RowsReorderedVMCallback = new RowsReorderedVMDelegate (rowsreordered_cb);
374 			OverrideVirtualMethod (gtype, "rows_reordered", RowsReorderedVMCallback);
375 		}
376 
377 		[GLib.DefaultSignalHandler(Type=typeof(Gtk.TreeStore), ConnectionMethod="OverrideRowsReordered")]
OnRowsReordered(Gtk.TreePath path, Gtk.TreeIter iter, int[] new_order)378 		protected virtual void OnRowsReordered (Gtk.TreePath path, Gtk.TreeIter iter, int[] new_order)
379 		{
380 			GLib.Value ret = GLib.Value.Empty;
381 			GLib.ValueArray inst_and_params = new GLib.ValueArray (4);
382 			GLib.Value[] vals = new GLib.Value [4];
383 			vals [0] = new GLib.Value (this);
384 			inst_and_params.Append (vals [0]);
385 			vals [1] = new GLib.Value (path);
386 			inst_and_params.Append (vals [1]);
387 			vals [2] = new GLib.Value (iter);
388 			inst_and_params.Append (vals [2]);
389 			int cnt = IterNChildren (iter);
390 			IntPtr new_order_ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (int)) * cnt);
391 			Marshal.Copy (new_order, 0, new_order_ptr, cnt);
392 			vals [3] = new GLib.Value (new_order_ptr);
393 			inst_and_params.Append (vals [3]);
394 			g_signal_chain_from_overridden (inst_and_params.ArrayPtr, ref ret);
395 			Marshal.FreeHGlobal (new_order_ptr);
396 
397 			foreach (GLib.Value v in vals)
398 				v.Dispose ();
399 		}
400 
401 		[GLib.Signal("rows_reordered")]
402 		public event Gtk.RowsReorderedHandler RowsReordered {
403 			add {
404 				AddSignalHandler ("rows_reordered", value, new RowsReorderedSignalDelegate(RowsReorderedSignalCallback));
405 			}
406 			remove {
407 				RemoveSignalHandler ("rows_reordered", value);
408 			}
409 		}
410 	}
411 }
412