Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

GtkTreeView.cs

/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2005-2007  Ben Motmans  <ben.motmans@gmail.com>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

using System;
using System.Collections.Generic;

using Gtk;

using Galaxium.Core;
using Anculus.Core;

namespace Galaxium.Gui.GtkGui
{
      public class GtkTreeView<T> : TreeView, ITreeBuilderRenderer<T> where T : ITreeNodeRenderer
      {
            private List<ITreeNodeBuilder<T>> _nodeBuilders;
            private ITreeNodeBuilder<T> _fallbackNodeBuilder;
            
            private Dictionary<uint, TreeIter> _iterLookup;
            private Dictionary<TreeIter, uint> _nodeLookup;
            private Dictionary<object, List<uint>> _objectLookup;
            
            private Dictionary<TreeIter, TreeIter> _dummyNodes;
            
            private TreeStore _treeStore;
            private TreeModelFilter _filteredTreeStore;
            private TreeModelSort _sortedTreeStore;
            
            private T _renderer;
            
            private bool _usingFilter;
            private bool _sort;
            private SortOrder _sortOrder;
            private ITreeNodeFilter _filter;
            private ITreeNodeSorter _sorter;
            
            private uint _nodeIndex = 0;
            
            private Queue<object> _objectQueue;
            private object _dummyObject;
            private bool _addDummy;
            
            //TODO: DnD
            //TODO: ITreeNodeRendere as arg + check all NodeBuilders for the generic renderer type
            //FIXME: errors if there is no sorter applied
            public GtkTreeView ()
            {
                  _objectQueue = new Queue<object> ();
                  _dummyObject = new object ();
                  
                  _nodeBuilders = new List<ITreeNodeBuilder<T>> ();
                  _iterLookup = new Dictionary<uint, TreeIter> ();
                  _nodeLookup = new Dictionary<TreeIter, uint> ();
                  _objectLookup = new Dictionary<object, List<uint>> ();
                  
                  _treeStore = new TreeStore (typeof (object));
                  _treeStore.RowInserted += new RowInsertedHandler (RowInsertedAfter);
                  _treeStore.RowInserted += new RowInsertedHandler (RowInsertedBefore);
                  _dummyNodes = new Dictionary<TreeIter, TreeIter> ();
                  
                  Model = _treeStore;
                  
                  _renderer = (T)GetTreeNodeRenderer ();
                  
                  if (_renderer == null)
                        throw new InvalidOperationException ("The TreeView doesn't have a renderer!");
                  
                  InitializeLayout ();
                  
                  this.Selection.Changed += new EventHandler (GtkTreeViewSelectionChanged);
                  this.RowActivated += new RowActivatedHandler (GtkTreeViewRowActivated);
                  
                  this.DragBegin += new DragBeginHandler (GtkTreeDragBegin);
                  this.DragDataReceived += new DragDataReceivedHandler (GtkTreeDragDataReceived);
                  this.DragDrop += new DragDropHandler (GtkTreeDragDrop);
                  this.DragEnd += new DragEndHandler (GtkTreeDragEnd);
                  this.DragMotion += new DragMotionHandler (GtkTreeDragMotion);
                  
                  this.HeadersVisible = false;
                  this.Reorderable = true;
                  this.ShowAll ();
            }
            
            protected void RowInsertedAfter (object sender, RowInsertedArgs args)
            {
                  //this method is used to insert dummy nodes for every node that requires one
                  if (!_addDummy)
                        return;
                  
                  _addDummy = false;
                  
                  _objectQueue.Enqueue (_dummyObject);
                  TreeIter dummy = _treeStore.AppendNode (args.Iter);
                  _dummyNodes.Add (args.Iter, dummy);
            }
            
            [GLib.ConnectBefore]
            protected void RowInsertedBefore (object sender, RowInsertedArgs args)
            {
                  //this method is required to store the object in the TreeStore BEFORE the filter and sort functions are called
                  object obj = _objectQueue.Dequeue ();
                  
                  if (obj == _dummyObject)
                        return;
                  
                  AddRealNode (args.Iter, obj);
            }
            
            public ITreeNodeBuilder<T> FallbackNodeBuilder
            {
                  get { return _fallbackNodeBuilder; }
                  set { _fallbackNodeBuilder = value; }
            }
            
            public T TreeNodeRenderer
            {
                  get { return _renderer; }
            }
            
            protected override bool OnButtonPressEvent (Gdk.EventButton e)
            {
                  bool retVal = base.OnButtonPressEvent (e);
                  
                  if (e.Button == 3)
                  {
                        TreePath path = null;
                        
                        if (GetPathAtPos ((int)e.X, (int)e.Y, out path))
                        {
                              TreeIter iter;
                              if (Model.GetIter (out iter, path))
                              {
                                    TreeNodeContext context = null;
                                    ITreeNodeBuilder<T> nodeBuilder = null;
                                    
                                    if (GetTreeNodeBuilder (iter, out context, out nodeBuilder, true))
                                    {
                                          Menu menu = MenuUtility.CreateContextMenu (nodeBuilder.ContextMenuExtensionPoint, new DefaultExtensionContext (context));
                                          
                                          if (menu != null)
                                          {
                                                menu.Popup (null, null, null, e.Button, e.Time);
                                                menu.ShowAll ();
                                          }
                                    }
                              }
                        }
                  }
                  
                  return retVal;
            }
            
            protected virtual void GtkTreeViewRowActivated (object sender, RowActivatedArgs args)
            {
                  TreeIter iter;
                  
                  if (Model.GetIter (out iter, args.Path))
                  {
                        TreeNodeContext context = null;
                        ITreeNodeBuilder<T> nodeBuilder = null;
                        
                        if (GetTreeNodeBuilder (iter, out context, out nodeBuilder, true))
                              nodeBuilder.NodeActivated (context);
                  }
            }
            
            protected override void OnRowExpanded (TreeIter iter, TreePath path)
            {
                  TreeIter realIter = GetRealTreeIter (iter);
                  TreeIter dummy = TreeIter.Zero;
                  
                  if (_dummyNodes.TryGetValue (realIter, out dummy))
                  {
                        TreeNodeContext context = null;
                        ITreeNodeBuilder<T> nodeBuilder = null;
                        
                        if (GetTreeNodeBuilder (realIter, out context, out nodeBuilder, false))
                              nodeBuilder.BuildDynamicChildNodes (context);
                        
                        _dummyNodes.Remove (realIter);
                        _treeStore.Remove (ref dummy);
                  }
                  
                  base.OnRowExpanded (iter, path);
            }
            
            protected virtual void GtkTreeViewSelectionChanged (object sender, EventArgs e)
            {
            }
            
            protected virtual void GtkTreeDragBegin (object o, DragBeginArgs arg)
            {
            }
            
            protected virtual void GtkTreeDragDataReceived (object o, DragDataReceivedArgs args)
            {
            }
            
            protected virtual void GtkTreeDragDrop (object o, DragDropArgs args)
            {
            }
            
            protected virtual void GtkTreeDragEnd (object o, DragEndArgs args)
            {
            }
            
            [GLib.ConnectBefore]
            protected virtual void GtkTreeDragMotion (object o, DragMotionArgs args)
            {
            }
            
            protected virtual ITreeNodeRenderer GetTreeNodeRenderer ()
            {
                  return new DefaultTreeNodeRenderer (_treeStore);
            }
            
            protected virtual void InitializeLayout ()
            {
                  TreeViewColumn col = new TreeViewColumn ();
                  
                  CellRendererText textRenderer = new CellRendererText ();
                  CellRendererPixbuf pixbufRenderer = new CellRendererPixbuf ();
                  
                  col.PackStart (pixbufRenderer, false);
                  col.PackStart (textRenderer, true);
                  
                  col.SetCellDataFunc (textRenderer, new CellLayoutDataFunc (TextDataFunc));
                  col.SetCellDataFunc (pixbufRenderer, new CellLayoutDataFunc (PixbufDataFunc));
                  
                  this.AppendColumn(col);
                  
                  ApplyLayout (col, textRenderer, pixbufRenderer);
            }
            
            protected virtual void ApplyLayout (TreeViewColumn col, CellRendererText textRenderer, CellRendererPixbuf pixbufRenderer)
            {
                  col.Expand = true;
            }
            
            protected void TextDataFunc (CellLayout layout, CellRenderer cell, TreeModel model, TreeIter iter)
            {
                  TreeNodeContext context = null;
                  ITreeNodeBuilder<T> nodeBuilder = null;
                  
                  if (GetTreeNodeBuilder (iter, out context, out nodeBuilder, true))
                  {
                        ITreeNodeWidget widget = GetTreeNodeWidget (_treeStore, layout, cell, iter);
                        nodeBuilder.RenderText (context, _renderer, widget);
                  }
            }
            
            protected void PixbufDataFunc (CellLayout layout, CellRenderer cell, TreeModel model, TreeIter iter)
            {
                  TreeNodeContext context = null;
                  ITreeNodeBuilder<T> nodeBuilder = null;
                  
                  if (GetTreeNodeBuilder (iter, out context, out nodeBuilder, true))
                  {
                        ITreeNodeWidget widget = GetTreeNodeWidget (_treeStore, layout, cell, iter);
                        nodeBuilder.RenderIcon (context, _renderer, widget);
                  }
            }
            
            protected virtual bool GetTreeNodeBuilder (TreeIter iter, out TreeNodeContext context, out ITreeNodeBuilder<T> nodeBuilder, bool convertIter)
            {
                  uint node;
                  
                  context = GetTreeNodeContext (iter, convertIter);
                  
                  if (context != null)
                  {
                        nodeBuilder = GetNodeBuilder (context.NodeObject);
                        
                        if (nodeBuilder == null)
                              Log.Error("Unable to find TreeNodeBuilder for type '{0}'.", context.NodeObject == null ? "null" : context.NodeObject.GetType ().FullName);
                        
                        return nodeBuilder != null;
                  }
                  
                  context = null;
                  nodeBuilder = null;
                  
                  return false;
            }
            
            public TreeNodeContext GetTreeNodeContext (uint node)
            {
                  TreeIter iter;
                  
                  if (_iterLookup.TryGetValue (node, out iter)) //this returns the real iter, so no conversion is needed
                        return new TreeNodeContext (this, node, _treeStore.GetValue (iter, 0));
                  
                  return null;
            }
            
            public virtual TreeIter GetRealTreeIter (TreeIter iter)
            {                 
                  if (_usingFilter)
                        iter = _filteredTreeStore.ConvertIterToChildIter (iter);
                  
                  if (_sort)
                        iter = _sortedTreeStore.ConvertIterToChildIter (iter);
                  
                  return iter;
            }
            
            public virtual TreeIter GetVirtualTreeIter (TreeIter iter)
            {
                  if (_sort)
                        iter = _sortedTreeStore.ConvertChildIterToIter (iter);
                  
                  if (_usingFilter)
                        iter = _filteredTreeStore.ConvertChildIterToIter (iter);
                  
                  return iter;
            }
            
            internal virtual TreeNodeContext GetTreeNodeContext (TreeIter iter, bool convertIter)
            {
                  uint node;
                  
                  if (convertIter)
                        iter = GetRealTreeIter (iter);
                  
                  if (_nodeLookup.TryGetValue (iter, out node))
                        return new TreeNodeContext (this, node, _treeStore.GetValue (iter, 0));
                  
                  return null;
            }
            
            protected virtual ITreeNodeWidget GetTreeNodeWidget (TreeModel model, CellLayout layout, CellRenderer cell, TreeIter iter)
            {
                  return new DefaultTreeNodeWidget (cell);
            }
            
            public ITreeNodeSorter Sorter
            {
                  get { return _sorter; }
                  set {
                        if (_sorter != value)
                        {
                              _sorter = value;
                              
                              if (value != null)
                              {
                                    _sort = true;
                                    
                                    if (_sortedTreeStore == null)
                                          this.Model = CreateTreeModel ();
                                    else
                                          this.Model = _sortedTreeStore;
                              }
                              else
                              {
                                    _sort = false;
                                    
                                    if (_sortedTreeStore != null)
                                    {
                                          _sortedTreeStore.Dispose ();
                                          _sortedTreeStore = null;
                                    }
                                    
                                    if (_usingFilter)
                                          this.Model = _filteredTreeStore;
                                    else
                                          this.Model = _treeStore;
                              }
                        }
                  }
            }
            
            private TreeModel CreateTreeModel ()
            {
                  //it's very important that the TreeModelFilter wraps around the TreeStore or TreeModelSort
                  //it looks sub-optimal since it will sort items that are filtered anyway, but the TreeModelFilter
                  //messes up the RowInserted event
                  TreeModel model;
                  
                  if (_sort)
                  {
                        _sortedTreeStore = new TreeModelSort (_treeStore);
                        _sortedTreeStore.SetSortFunc (0, new TreeIterCompareFunc (TreeNodeSortFunc));
                        _sortedTreeStore.SetSortColumnId (0, _sortOrder == SortOrder.Ascending ? SortType.Ascending : SortType.Descending);
                  }
                  
                  if (_usingFilter)
                  {
                        if (_sort)
                              _filteredTreeStore = new TreeModelFilter (_sortedTreeStore, null);
                        else
                              _filteredTreeStore = new TreeModelFilter (_treeStore, null);
                              
                        _filteredTreeStore.VisibleFunc = new TreeModelFilterVisibleFunc (TreeNodeFilterFunc);
                        
                        model = _filteredTreeStore;
                  }
                  else
                  {
                        if (_sort)
                              model = _sortedTreeStore;
                        else
                              model = _treeStore;
                  }
                  
                  return model;
            }
            
            public SortOrder SortOrder
            {
                  get { return _sortOrder; }
                  set
                  {
                        if (_sortOrder != value)
                        {
                              _sortOrder = value;
                              
                              if (_sort)
                                    _sortedTreeStore.SetSortColumnId (0, value == SortOrder.Ascending ? SortType.Ascending : SortType.Descending);
                        }
                  }
            }
            
            public ITreeNodeFilter Filter
            {
                  get { return _filter; }
                  set {
                        if (_filter != value)
                        {
                              _filter = value;
                              
                              if (value == null)
                              {
                                    _usingFilter = false;
                                    
                                    if (_sort)
                                          this.Model = _sortedTreeStore;
                                    else
                                          this.Model = _treeStore;
                                    
                                    if (_filteredTreeStore != null)
                                    {
                                          _filteredTreeStore.Dispose ();
                                          _filteredTreeStore = null;
                                    }
                              }
                              else
                              {
                                    _usingFilter = true;
                                    
                                    if (_filteredTreeStore == null)
                                          this.Model = CreateTreeModel ();
                                    else
                                          this.Model = _treeStore;
                                    
                                    _filteredTreeStore.Refilter ();
                              }
                        }
                  }
            }
            
            public void Refilter ()
            {
                  if (_usingFilter)
                        _filteredTreeStore.Refilter ();
            }
            
            public void Resort ()
            {
                  if (_sort)
                        _sortedTreeStore.ChangeSortColumn ();
            }
            
            protected virtual bool TreeNodeFilterFunc (TreeModel model, TreeIter iter)
            {
                  if (model is TreeModelSort) //only convert the iter if it is coming from the TreeModelSort
                        iter = _sortedTreeStore.ConvertIterToChildIter (iter);
                  
                  TreeNodeContext ctx = GetTreeNodeContext (iter, false);
                  if (ctx == null)
                        return true;
                  
                  return _filter.Filter (ctx);
            }
            
            protected virtual int TreeNodeSortFunc (TreeModel model, TreeIter iter1, TreeIter iter2)
            {
                  //the iters are real iters and must not be converted
                  TreeNodeContext ctx1 = GetTreeNodeContext (iter1, false);
                  TreeNodeContext ctx2 = GetTreeNodeContext (iter2, false);
                  
                  if (ctx1 == null || ctx1.NodeObject == null)
                  {
                        if (ctx2 == null || ctx2.NodeObject == null)
                              return 0;
                        
                        return _sortOrder == SortOrder.Ascending ? 1 : -1;
                  }
                  else if (ctx2 == null || ctx2.NodeObject == null)
                  {
                        return _sortOrder == SortOrder.Ascending ? -1 : 1;
                  }
                  
                  return _sorter.Compare (ctx1, ctx2);
            }
            
            public string GetComparableContent (TreeNodeContext ctx)
            {
                  ITreeNodeBuilder<T> nodeBuilder = GetNodeBuilder (ctx.NodeObject);
                  return nodeBuilder.GetComparableContent (ctx);
            }
            
            public void AddNodeBuilder (Gui.ITreeNodeBuilder<T> nodeBuilder)
            {
                  ThrowUtility.ThrowIfNull ("nodeBuilder", nodeBuilder);
                  
                  if (!_nodeBuilders.Contains (nodeBuilder))
                        _nodeBuilders.Add (nodeBuilder);
            }
            
            public void RemoveNodeBuilder (Gui.ITreeNodeBuilder<T> nodeBuilder)
            {
                  ThrowUtility.ThrowIfNull ("nodeBuilder", nodeBuilder);
                  
                  if (_nodeBuilders.Contains (nodeBuilder))
                        _nodeBuilders.Remove (nodeBuilder);
            }
            
            public ITreeNodeBuilder<T> GetNodeBuilder (object obj)
            {
                  ThrowUtility.ThrowIfNull ("obj", obj);
                  
                  return GetNodeBuilder (obj.GetType ());
            }
            
            public ITreeNodeBuilder<T> GetNodeBuilder (Type type)
            {
                  ThrowUtility.ThrowIfNull ("type", type);
                  
                  foreach (ITreeNodeBuilder<T> nodeBuilder in _nodeBuilders)
                  {
                        if (type.Equals (nodeBuilder.NodeType))
                              return nodeBuilder;
                  }
                  
                  return _fallbackNodeBuilder;
            }
            
            public bool NodeExists (uint node)
            {
                  return _iterLookup.ContainsKey (node);
            }
            
            public virtual uint AddNode (object node)
            {
                  return AddNode (null, node);
            }
            
            public uint AddNode (uint? parent, object node)
            {
                  ThrowUtility.ThrowIfNull ("node", node);
                  
                  TreeIter iter = TreeIter.Zero;
                  
                  if (!parent.HasValue)
                  {
                        _objectQueue.Enqueue (node);
                        GetUniqueNodeIndex ();
                        iter = _treeStore.AppendNode ();
                  }
                  else
                  {
                        TreeIter parentIter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out parentIter))
                        {
                              _objectQueue.Enqueue (node);
                              GetUniqueNodeIndex ();
                              iter = _treeStore.AppendNode (parentIter);
                        }
                        else
                        {
                              return AddNode (null, node);
                        }
                  }
                  
                  return _nodeIndex;
            }
            
            public uint[] AddNodes (object parent, object obj)
            {
                  ThrowUtility.ThrowIfNull ("parent", parent);
                  ThrowUtility.ThrowIfNull ("obj", obj);
                  
                  uint[] indices = GetNodes (parent);
                  uint[] nodes = new uint[indices.Length];
                  int i = 0;
                  
                  foreach (uint index in indices)
                        nodes[i++] = AddNode (index, obj);
                  
                  return new uint[0];
            }
            
            protected virtual uint GetUniqueNodeIndex ()
            {
                  if (_nodeIndex == uint.MaxValue)
                  {
                        _nodeIndex = 0; //FIXME: use better method without conflicts
                        Log.Warn ("The maximum number of tree nodes is reached, this will be buggy!");
                  }
                  
                  return ++_nodeIndex;
            }
            
            private uint AddRealNode (TreeIter iter, object value)
            {
                  _treeStore.SetValue (iter, 0, value);
                  
                  uint uid = _nodeIndex;
                  
                  _iterLookup.Add (uid, iter);
                  _nodeLookup.Add (iter, uid);
                  
                  List<uint> nodes = null;
                  
                  if (_objectLookup.TryGetValue (value, out nodes))
                  {
                        nodes.Add (uid);
                  }
                  else
                  {
                        nodes = new List<uint> ();
                        nodes.Add (uid);
                        
                        _objectLookup.Add (value, nodes);
                  }
                  
                  AddDummyNode (iter, uid, value);
                  return uid;
            }
            
            private void AddDummyNode (TreeIter iter, uint node, object obj)
            {
                  ITreeNodeBuilder<T> builder = GetNodeBuilder (obj);
                  
                  if (builder != null)
                        _addDummy = builder.HasDynamicChildNodes (new TreeNodeContext (this, node, obj));
            }
            
            public uint InsertNode (int index, object node)
            {
                  return InsertNode (index, null, node);
            }
            
            public uint InsertNode (int index, uint? parent, object node)
            {
                  ThrowUtility.ThrowIfNull ("node", node);
                  
                  TreeIter iter = TreeIter.Zero;
                  
                  if (!parent.HasValue)
                  {
                        _objectQueue.Enqueue (node);
                        GetUniqueNodeIndex ();
                        iter = _treeStore.InsertNode (index);
                  }
                  else
                  {
                        TreeIter parentIter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out parentIter))
                        {
                              _objectQueue.Enqueue (node);
                              GetUniqueNodeIndex ();
                              iter = _treeStore.InsertNode (parentIter, index);
                              
                              // This is purely to force expansion of the tree until it gets fixed.
                              ExpandNode (parent.Value);
                        }
                        else
                        {
                              AddNode (null, node);
                        }
                  }
                  
                  return _nodeIndex;
            }
            
            public bool UpdateNode (uint node)
            {
                  return UpdateNode (node, false);
            }
            
            public bool UpdateNode (uint node, bool updateChildren)
            {
                  TreeIter iter = TreeIter.Zero;
                        
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreePath path = _treeStore.GetPath (iter);
                        _treeStore.EmitRowChanged (path, iter);
                        
                        if (updateChildren)
                        {
                              foreach (uint child in GetChildren (node))
                                    UpdateNode (child, updateChildren);
                              
                              if (!_dummyNodes.ContainsKey (iter))
                              {
                                    //no dummy child node, so remove all child nodes and build again
                                    //TODO: remove+add children ??
                              }
                        }
                        
                        Refilter ();
                        return true;
                  }
                  return false;
            }
            
            public bool RemoveNode (uint node)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        _nodeLookup.Remove (iter);
                        _iterLookup.Remove (node);
                        
                        _treeStore.Remove (ref iter);
                        return true;
                  }
                  
                  return false;
            }
            
            public object GetNodeObject (uint node)
            {
                  TreeNodeContext context = GetTreeNodeContext (node);
                  if (context != null)
                        return context.NodeObject;
                  
                  return null;
            }
            
            public bool SwapNode (uint node1, uint node2)
            {
                  TreeIter iter1 = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node1, out iter1))
                  {
                        TreeIter iter2 = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (node2, out iter2))
                        {
                              _treeStore.Swap (iter1, iter2);
                              return true;
                        }
                  }
                  
                  return false;
            }
            
            public int GetNodeIndex (uint node)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreePath path = _treeStore.GetPath (iter);
                        int[] indices = path.Indices;
                        int len = indices.Length;
                        
                        return indices[len - 1];
                  }
                  return -1;
            }
            
            public int[] GetNodeIndices (uint node)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreePath path = _treeStore.GetPath (iter);
                        return path.Indices;
                  }
                  
                  return new int[0];
            }
            
            public void Clear ()
            {
                  _nodeIndex = 0;
                  _treeStore.Clear ();
                  
                  _iterLookup.Clear ();
                  _nodeLookup.Clear ();
                  _objectLookup.Clear ();
            }
            
            public uint[] GetNodes (object obj)
            {
                  return GetNodes (null, obj);
            }
            
            public uint[] GetNodes (uint? parent, object obj)
            {
                  ThrowUtility.ThrowIfNull ("obj", obj);
                  
                  if (!parent.HasValue)
                  {
                        List<uint> nodes = null;
                        
                        if (_objectLookup.TryGetValue (obj, out nodes))
                              return nodes.ToArray ();
                  }
                  else
                  {
                        List<uint> nodes = null;
                        
                        if (_objectLookup.TryGetValue (obj, out nodes))
                        {
                              List<uint> filter = new List<uint> ();
                              
                              foreach (uint node in nodes)
                              {
                                    uint? nodeParent = GetParent (node);
                                    
                                    if (nodeParent.HasValue && nodeParent.Value == parent.Value)
                                          filter.Add (node);
                              }
                              
                              return filter.ToArray ();
                        }
                  }
                  
                  return new uint[0];
            }
            
            public bool GetFirstNode (object obj, out uint node)
            {
                  return GetFirstNode (null, obj, out node);
            }
            
            public bool GetFirstNode (uint? parent, object obj, out uint node)
            {
                  ThrowUtility.ThrowIfNull ("obj", obj);
                  
                  if (!parent.HasValue)
                  {
                        List<uint> nodes = null;
                        
                        if (_objectLookup.TryGetValue (obj, out nodes))
                        {
                              if (nodes.Count > 0) 
                              {
                                    node = nodes[0];
                                    return true;
                              }
                        }
                  }
                  else
                  {
                        List<uint> nodes = null;
                        
                        if (_objectLookup.TryGetValue (obj, out nodes))
                        {
                              foreach (uint n in nodes)
                              {
                                    uint? nodeParent = GetParent (n);
                                    
                                    if (nodeParent.HasValue && nodeParent.Value == parent.Value)
                                    {
                                          node = n;
                                          return true;
                                    }
                              }
                        }
                  }
                  
                  node = uint.MaxValue;
                  
                  return false;
            }
            
            public uint? GetParent (uint node)
            {
                  TreeIter iter;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreeIter parent;
                        uint parentNode;
                        
                        if (_treeStore.IterParent (out parent, iter))
                        {
                              if (_nodeLookup.TryGetValue (parent, out parentNode))
                                    return parentNode;
                        }
                  }
                  return null;
            }
            
            public object GetParentObject (uint node)
            {
                  uint? parent = GetParent (node);
                  if (parent.HasValue)
                        return GetNodeObject (parent.Value);
                  return null;
            }
            
            public bool GetNextNode (uint node, out uint next)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        if (_treeStore.IterNext (ref iter))
                        {
                              next = _nodeLookup[iter];
                              return true;
                        }
                  }
                  
                  next = uint.MaxValue;
                  
                  return false;
            }
            
            public bool GetPreviousNode (uint node, out uint previous)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreePath path = _treeStore.GetPath (iter);
                        
                        if (path.Prev ())
                        {
                              _treeStore.GetIter (out iter, path);
                              previous = _nodeLookup[iter];
                              
                              return true;
                        }
                  }
                  
                  previous = uint.MaxValue;
                  return false;
            }
            
            public uint[] GetSelectedNodes ()
            {
                  uint[] nodes = new uint[GetSelectionCount ()];
                  int index=0;
                  
                  foreach (TreePath path in this.Selection.GetSelectedRows ())
                  {
                        uint node;
                        
                        if (GetNodeFromPath (path, out node))
                              nodes[index++] = node;
                        else
                              throw new ArgumentException ("Internal error: invalid TreePath.");
                  }
                  
                  return nodes;
            }
            
            public bool GetNodeFromPath (TreePath path, out uint node)
            {
                  TreeIter iter;
                  if (Model.GetIter (out iter, path))
                  {
                        iter = GetRealTreeIter (iter);
                        if (_nodeLookup.TryGetValue (iter, out node))
                              return true;
                  }
                  
                  node = uint.MaxValue;
                  return false;
            }
            
            public bool GetNodeFromIter (TreeIter iter, out uint node)
            {
                  TreeIter realIter = GetRealTreeIter (iter);
                  if (_nodeLookup.TryGetValue (iter, out node))
                        return true;
                  
                  node = uint.MaxValue;
                  return false;
            }
            
            public bool GetSelectedNode (out uint node)
            {
                  TreeSelection selection = this.Selection;
                  
                  if (selection.Mode == SelectionMode.Single || selection.Mode == SelectionMode.Browse)
                  {
                        TreeIter iter;
                        
                        if (selection.GetSelected (out iter))
                        {
                              iter = GetRealTreeIter (iter);
                              node = _nodeLookup[iter];
                              return true;
                        }
                  }
                  else if (selection.Mode == SelectionMode.Multiple || selection.Mode == SelectionMode.Extended)
                  {
                        if (GetSelectionCount () >= 1)
                        {
                              TreePath path = selection.GetSelectedRows ()[0];
                              
                              if (GetNodeFromPath (path, out node))
                                    return true;
                        }
                  }
                  
                  node = uint.MaxValue;
                  return false;
            }
            
            public int GetSelectionCount ()
            {
                  return this.Selection.CountSelectedRows ();
            }
            
            public bool IsNodeSelected (uint node)
            {
                  TreeIter iter;
                  
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        iter = GetVirtualTreeIter (iter);
                        return this.Selection.IterIsSelected (iter);
                  }
                  
                  return false;
            }
            
            public uint[] GetChildren (uint? parent)
            {
                  TreeIter iter = TreeIter.Zero;
                  
                  if (!parent.HasValue)
                  {
                        int count = _treeStore.IterNChildren ();
                        uint[] children = new uint[count];
                        
                        TreeIter child = TreeIter.Zero;
                        int index = 0;
                        
                        if (_treeStore.IterNthChild (out child, 0))
                        {
                              do
                              {
                                    children[index++] = _nodeLookup[child];
                              }
                              while (_treeStore.IterNext (ref child));
                              
                              return children;
                        }
                  }
                  else
                  {
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                        {
                              int count = _treeStore.IterNChildren (iter);
                              uint[] children = new uint[count];
                              
                              TreeIter child = TreeIter.Zero;
                              int index = 0;
                              
                              if (_treeStore.IterNthChild (out child, iter, 0))
                              {
                                    do
                                    {
                                          children[index++] = _nodeLookup[child];
                                    }
                                    while (_treeStore.IterNext (ref child));
                                    
                                    return children;
                              }
                        }
                  }
                  
                  return new uint[0];
            }
            
            public uint[] GetChildren ()
            {
                  return GetChildren (null);
            }
            
            public bool GetFirstChild (out uint node)
            {
                  return GetFirstChild (null, out node);
            }
            
            public bool GetFirstChild (uint? parent, out uint node)
            {
                  TreeIter child = TreeIter.Zero;
                  
                  if (!parent.HasValue)
                  {
                        if (_treeStore.IterNthChild (out child, 0))
                        {
                              node = _nodeLookup[child];
                              return true;
                        }
                  }
                  else
                  {
                        TreeIter iter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                        {
                              if (_treeStore.IterNthChild (out child, iter, 0))
                              {
                                    node = _nodeLookup[child];
                                    return true;
                              }
                        }
                  }
                  
                  node = uint.MaxValue;
                  
                  return false;
            }
            
            public int GetChildCount ()
            {
                  return GetChildCount (null);
            }
            
            public int GetChildCount (uint? parent)
            {
                  if (!parent.HasValue)
                  {
                        return _treeStore.IterNChildren ();
                  }
                  else
                  {
                        TreeIter iter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                              return _treeStore.IterNChildren (iter);
                  }
                  
                  return 0;
            }
            
            public uint[] GetVisibleChildren (uint? parent)
            {
                  if (!parent.HasValue)
                  {
                        int count = Model.IterNChildren ();
                        uint[] children = new uint[count];
                        
                        TreeIter child = TreeIter.Zero;
                        int index = 0;
                        
                        if (Model.IterNthChild (out child, 0))
                        {
                              do
                              {
                                    TreeIter realChild = GetRealTreeIter (child);
                                    children[index++] = _nodeLookup[realChild];
                              } while (Model.IterNext (ref child));
                              
                              return children;
                        }
                  }
                  else
                  {
                        TreeIter iter = TreeIter.Zero;
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                        {
                              TreeIter virtualIter = GetVirtualTreeIter (iter);
                              int count = Model.IterNChildren (virtualIter);
                              uint[] children = new uint[count];
                              
                              TreeIter child = TreeIter.Zero;
                              int index = 0;
                              
                              if (Model.IterNthChild (out child, virtualIter, 0))
                              {
                                    do
                                    {
                                          TreeIter realChild = GetRealTreeIter (child);
                                          children[index++] = _nodeLookup[realChild];
                                    }
                                    while (Model.IterNext (ref child));
                                    
                                    return children;
                              }
                        }
                  }
                  
                  return new uint[0];
            }
            
            public uint[] GetVisibleChildren ()
            {
                  return GetChildren (null);
            }
            
            public bool GetVisibleFirstChild (out uint node)
            {
                  return GetFirstChild (null, out node);
            }
            
            public bool GetVisibleFirstChild (uint? parent, out uint node)
            {
                  TreeIter child = TreeIter.Zero;
                  
                  if (!parent.HasValue)
                  {
                        if (Model.IterNthChild (out child, 0))
                        {
                              TreeIter realChild = GetRealTreeIter (child);
                              node = _nodeLookup[realChild];
                              return true;
                        }
                  }
                  else
                  {
                        TreeIter iter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                        {
                              TreeIter virtualIter = GetVirtualTreeIter (iter);
                              if (Model.IterNthChild (out child, virtualIter, 0))
                              {
                                    TreeIter realChild = GetRealTreeIter (child);
                                    node = _nodeLookup[realChild];
                                    return true;
                              }
                        }
                  }
                  
                  node = uint.MaxValue;
                  
                  return false;
            }
            
            public int GetVisibleChildCount ()
            {
                  return GetChildCount (null);
            }
            
            public int GetVisibleChildCount (uint? parent)
            {
                  if (!parent.HasValue)
                  {
                        return Model.IterNChildren ();
                  }
                  else
                  {
                        TreeIter iter = TreeIter.Zero;
                        
                        if (_iterLookup.TryGetValue (parent.Value, out iter))
                        {
                              TreeIter virtualIter = GetVirtualTreeIter (iter);
                              return Model.IterNChildren (virtualIter);
                        }
                  }
                  
                  return 0;
            }
            
            public void ExpandNode (uint node)
            {
                  TreeIter iter;
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreeIter virtualIter = GetVirtualTreeIter (iter);
                        TreePath path = Model.GetPath (virtualIter);
                        ExpandRow (path, true);
                  }
            }
            
            public void CollapseNode (uint node)
            {
                  TreeIter iter;
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreeIter virtualIter = GetVirtualTreeIter (iter);
                        TreePath path = Model.GetPath (virtualIter);
                        CollapseRow (path);
                  }
            }
            
            public void SelectNode (uint node)
            {
                  TreeIter iter;
                  if (_iterLookup.TryGetValue (node, out iter))
                  {
                        TreeIter virtualIter = GetVirtualTreeIter (iter);
                        TreePath path = Model.GetPath (virtualIter);
                        
                        SetCursor (path, Columns[0], false);
                  }
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index