// // CustomTreeModel.cs // // Author: // Lluis Sanchez // // Copyright (c) 2011 Xamarin Inc // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Gtk; #if XWT_GTK3 using TreeModelImplementor = Gtk.ITreeModelImplementor; #endif namespace Xwt.GtkBackend { public class CustomListModel: GLib.Object, TreeModelImplementor { IListDataSource source; Dictionary nodeHash = new Dictionary (); Dictionary handleHash = new Dictionary (); Type[] colTypes; int counter = 1; Gtk.TreeModelAdapter adapter; Gtk.Widget parent; public CustomListModel (IntPtr p): base (p) { } public CustomListModel (IListDataSource source, Gtk.Widget w) { parent = w; this.source = source; adapter = new Gtk.TreeModelAdapter (this); colTypes = source.ColumnTypes; source.RowChanged += HandleRowChanged; source.RowDeleted += HandleRowDeleted; source.RowInserted += HandleRowInserted; source.RowsReordered += HandleRowsReordered; } #if XWT_GTK3 protected override void Dispose(bool disposing) #else public override void Dispose () #endif { source.RowChanged -= HandleRowChanged; source.RowDeleted -= HandleRowDeleted; source.RowInserted -= HandleRowInserted; source.RowsReordered -= HandleRowsReordered; base.Dispose(); } void HandleRowsReordered (object sender, ListRowOrderEventArgs e) { var p = new Gtk.TreePath (new int[] { e.Row }); var it = IterFromNode (e.Row); adapter.EmitRowsReordered (p, it, e.ChildrenOrder); parent.QueueResize (); } void HandleRowInserted (object sender, ListRowEventArgs e) { var p = new Gtk.TreePath (new int[] { e.Row }); var it = IterFromNode (e.Row); adapter.EmitRowInserted (p, it); parent.QueueResize (); } void HandleRowDeleted (object sender, ListRowEventArgs e) { var p = new Gtk.TreePath (new int[] { e.Row }); adapter.EmitRowDeleted (p); parent.QueueResize (); } void HandleRowChanged (object sender, ListRowEventArgs e) { var p = new Gtk.TreePath (new int[] { e.Row }); var it = IterFromNode (e.Row); adapter.EmitRowChanged (p, it); parent.QueueResize (); } public Gtk.TreeModelAdapter Store { get { return adapter; } } Gtk.TreeIter IterFromNode (int node) { int gch; if (!handleHash.TryGetValue (node, out gch)) { gch = counter++; handleHash [node] = gch; nodeHash [gch] = node; } Gtk.TreeIter result = Gtk.TreeIter.Zero; result.UserData = (IntPtr)gch; return result; } int NodeFromIter (Gtk.TreeIter iter) { int node; int gch = (int)iter.UserData; nodeHash.TryGetValue (gch, out node); return node; } #region TreeModelImplementor implementation public GLib.GType GetColumnType (int index) { return (GLib.GType)colTypes [index]; } public bool GetIter (out Gtk.TreeIter iter, Gtk.TreePath path) { iter = Gtk.TreeIter.Zero; if (path.Indices.Length == 0) return false; int row = path.Indices [0]; if (row >= source.RowCount) { return false; } iter = IterFromNode (row); return true; } public Gtk.TreePath GetPath (Gtk.TreeIter iter) { int row = NodeFromIter (iter); return new Gtk.TreePath (new int[] { row }); } public void GetValue (Gtk.TreeIter iter, int column, ref GLib.Value value) { int row = NodeFromIter (iter); var v = source.GetValue (row, column); value = v != null ? new GLib.Value (v) : GLib.Value.Empty; } public bool IterNext (ref Gtk.TreeIter iter) { int row = NodeFromIter (iter); if (++row < source.RowCount) { iter = IterFromNode (row); return true; } else return false; } #if XWT_GTK3 public bool IterPrevious (ref Gtk.TreeIter iter) { int row = NodeFromIter (iter); if (--row >= 0) { iter = IterFromNode (row); return true; } else return false; } #endif public bool IterChildren (out Gtk.TreeIter iter, Gtk.TreeIter parent) { iter = Gtk.TreeIter.Zero; return false; } public bool IterHasChild (Gtk.TreeIter iter) { return false; } public int IterNChildren (Gtk.TreeIter iter) { if (iter.Equals (Gtk.TreeIter.Zero)) return source.RowCount; else return 0; } public bool IterNthChild (out Gtk.TreeIter iter, Gtk.TreeIter parent, int n) { if (parent.Equals (Gtk.TreeIter.Zero)) { iter = IterFromNode (n); return true; } else { iter = Gtk.TreeIter.Zero; return false; } } public bool IterParent (out Gtk.TreeIter iter, Gtk.TreeIter child) { iter = Gtk.TreeIter.Zero; return false; } public void RefNode (Gtk.TreeIter iter) { } public void UnrefNode (Gtk.TreeIter iter) { } public Gtk.TreeModelFlags Flags { get { return Gtk.TreeModelFlags.ItersPersist | Gtk.TreeModelFlags.ListOnly; } } public int NColumns { get { return colTypes.Length; } } #endregion } }