/// <summary> /// Gets the path to a specified iter. /// </summary> /// <param name="iter">The iter to get the path of.</param> /// <returns>The TreePath corresponding to the given iter.</returns> public TreePath GetPath(TreeIter iter) { if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } TreePath result = new TreePath(); FileNode node = this.Tree.GetNode((ulong)iter.UserData); if (node == null) { return(result); } while (node.ParentOffset > -1) { FileNode parentNode = this.Tree.GetNode((ulong)node.ParentOffset); ulong nodeOffset = this.Tree.GetNodeOffset(node); result.PrependIndex(parentNode.ChildOffsets.IndexOf(nodeOffset)); node = parentNode; } result.PrependIndex(this.Tree.Root.ChildOffsets.IndexOf((ulong)iter.UserData)); return(result); }
/// <summary> /// Gets the iter of the first child of the given iter. /// </summary> /// <param name="iter">Will contain the first child.</param> /// <param name="parent">The iter to get the first child from.</param> /// <returns>true if the iter is now set to the first child of the parent; false otherwise</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> /// <exception cref="ArgumentException">Thrown if the iter is not valid.</exception> public bool IterChildren(out TreeIter iter, TreeIter parent) { if (parent.Stamp != this.Stamp) { throw new InvalidDataException("The given parent was not valid for this model."); } iter = TreeIter.Zero; FileNode node = parent.Equals(TreeIter.Zero) ? this.Tree.Root : this.Tree.GetNode((ulong)parent.UserData); if (node == null) { throw new ArgumentException("The given iter was not valid.", nameof(parent)); } if (!node.HasChildren()) { return(false); } iter.UserData = new IntPtr((long)node.ChildOffsets.First()); iter.Stamp = this.Stamp; return(true); }
/// <summary> /// Gets the parent of the given iter. /// </summary> /// <param name="iter">Will contain the parent iter.</param> /// <param name="child">The iter to get the parent of.</param> /// <returns>true if the iter is now set to the parent iter of the child; false otherwise</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> /// <exception cref="ArgumentException">Thrown if the iter is not valid.</exception> public bool IterParent(out TreeIter iter, TreeIter child) { if (child.Stamp != this.Stamp) { throw new InvalidDataException("The given child was not valid for this model."); } iter = TreeIter.Zero; FileNode childNode = this.Tree.GetNode((ulong)child.UserData); if (childNode == null) { throw new ArgumentException("The given iter was not valid.", nameof(child)); } FileNode parentNode = this.Tree.GetNode((ulong)childNode.ParentOffset); if (parentNode == null) { return(false); } iter.UserData = new IntPtr((long)this.Tree.GetNodeOffset(parentNode)); iter.Stamp = this.Stamp; return(true); }
/// <summary> /// Gets the nth child of the provided iter. /// </summary> /// <param name="iter">Will contain the nth child.</param> /// <param name="parent">The iter to get the child of.</param> /// <param name="n">The value of n.</param> /// <returns>true if the iter is now set to the nth child of the parent; false otherwise</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> /// <exception cref="ArgumentException">Thrown if the iter is not valid.</exception> public bool IterNthChild(out TreeIter iter, TreeIter parent, int n) { if (parent.Stamp != this.Stamp && !parent.Equals(TreeIter.Zero)) { throw new InvalidDataException("The given parent was not valid for this model."); } iter = TreeIter.Zero; if (n < 0) { return(false); } FileNode node = iter.Equals(TreeIter.Zero) ? this.Tree.Root : this.Tree.GetNode((ulong)iter.UserData); if (node == null) { throw new ArgumentException("The given iter was not valid.", nameof(parent)); } if (!node.HasChildren() || n > (int)node.ChildCount - 1) { return(false); } iter.UserData = new IntPtr((long)node.ChildOffsets[n]); iter.Stamp = this.Stamp; return(true); }
/// <summary> /// Gets the package the given node belongs to. /// </summary> /// <param name="node">The node to get the package of.</param> /// <returns>The name of the package.</returns> public string GetNodePackage(FileNode node) { var currentNode = node; while (!(currentNode.Type.HasFlag(NodeType.Package) || currentNode.Type.HasFlag(NodeType.Meta))) { currentNode = this.Tree.GetNode((ulong)currentNode.ParentOffset); } return(GetNodeName(currentNode)); }
/// <summary> /// Sorts the game explorer row. /// </summary> /// <returns>The sorting priority of the row. This value can be -1, 0 or 1 if /// A sorts before B, A sorts with B or A sorts after B, respectively.</returns> /// <param name="model">Model.</param> /// <param name="a">Iter a.</param> /// <param name="b">Iter b.</param> private int SortGameTreeRow(ITreeModel model, TreeIter a, TreeIter b) { const int sortABeforeB = -1; const int sortAWithB = 0; const int sortAAfterB = 1; FileNode nodeA = (FileNode)model.GetValue(a, 0); FileNode nodeB = (FileNode)model.GetValue(b, 0); NodeType typeofA = nodeA.Type; NodeType typeofB = nodeB.Type; // Special case for meta nodes - if A is a meta node, but B is not if (typeofA.HasFlag(NodeType.Meta) && !typeofB.HasFlag(NodeType.Meta)) { // Then it should always sort after B return(sortAAfterB); } if (typeofB.HasFlag(NodeType.Meta) && !typeofA.HasFlag(NodeType.Meta)) { // Then it should always sort before B return(sortABeforeB); } if (typeofA < typeofB) { return(sortAAfterB); } if (typeofA > typeofB) { return(sortABeforeB); } string nodeAName = this.TreeModel.GetNodeName(nodeA); string nodeBName = this.TreeModel.GetNodeName(nodeB); int result = string.CompareOrdinal(nodeAName, nodeBName); if (result <= sortABeforeB) { return(sortAAfterB); } if (result >= sortAAfterB) { return(sortABeforeB); } return(sortAWithB); }
/// <summary> /// Gets a <see cref="FileReference"/> from a given iter in the tree. /// </summary> /// <param name="packageGroup">The package group to create a reference for.</param> /// <param name="iter">The iter in the tree.</param> /// <returns>The FileReference pointed to by the given iter.</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> public FileReference GetReferenceByIter(PackageGroup packageGroup, TreeIter iter) { if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } FileNode node = this.Tree.GetNode((ulong)iter.UserData); if (node == null) { return(null); } return(new FileReference(packageGroup, node, GetNodePackage(node), GetNodeFilePath(node))); }
/// <summary> /// Determines whether or not the given iter has any children. /// </summary> /// <param name="iter">The iter to check.</param> /// <returns>true if the iter has any children; false otherwise</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> /// <exception cref="ArgumentException">Thrown if the iter is not valid.</exception> public bool IterHasChild(TreeIter iter) { if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } FileNode node = iter.Equals(TreeIter.Zero) ? this.Tree.Root : this.Tree.GetNode((ulong)iter.UserData); if (node == null) { throw new ArgumentException("The given iter was not valid.", nameof(iter)); } return(node.HasChildren()); }
/// <summary> /// Enumerates all references pointing to files under the given reference. If the reference already points to /// a file, it is returned back. If it is null, nothing is returned. The search is performed as a depth-first /// level scan. /// </summary> /// <param name="fileReference">The reference to enumerate.</param> /// <returns>A set of all the child references of the given reference.</returns> public IEnumerable <FileReference> EnumerateFilesOfReference(FileReference fileReference) { if (fileReference == null) { yield break; } if (fileReference.IsFile) { yield return(fileReference); yield break; } List <FileNode> folderNodes = new List <FileNode> { fileReference.Node }; while (folderNodes.Count > 0) { FileNode folderNode = folderNodes.First(); foreach (ulong offset in folderNode.ChildOffsets) { FileNode childNode = this.Tree.GetNode(offset); if (childNode.Type.HasFlag(NodeType.File)) { yield return(new FileReference ( fileReference.PackageGroup, childNode, fileReference.PackageName, GetNodeFilePath(childNode) )); } if (childNode.Type.HasFlag(NodeType.Directory)) { folderNodes.Add(childNode); } } folderNodes.Remove(folderNode); } }
/// <summary> /// Gets the value stored in the model at a given iter. /// </summary> /// <param name="iter">The iter where the value is stored.</param> /// <param name="column">The column to get the value from</param> /// <param name="value">Will contain the value.</param> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> public void GetValue(TreeIter iter, int column, ref Value value) { if (iter.Stamp != this.Stamp && !iter.Equals(TreeIter.Zero)) { throw new InvalidDataException("The given iter was not valid for this model."); } FileNode node = iter.Equals(TreeIter.Zero) ? this.Tree.Root : this.Tree.GetNode((ulong)iter.UserData); if (node == null) { return; } value.Init(LookupGType(typeof(FileNode))); value.Val = node; }
/// <summary> /// This function is used internally by the tree filter to determine which rows are visible and which are not. /// </summary> /// <param name="model">The model of the tree.</param> /// <param name="iter">The iter to determine visibility for.</param> /// <returns>true if the iter should be visible; false otherwise.</returns> private bool TreeModelVisibilityFunc(ITreeModel model, TreeIter iter) { if (!this.IsFiltered) { return(true); } FileNode node = (FileNode)model.GetValue(iter, 0); WarcraftFileType nodeTypes = node.FileType; // If the file types of the node and the filtered types overlap in any way, then it should // be displayed. if ((nodeTypes & this.FilteredFileTypes) != 0) { return(true); } return(false); }
/// <summary> /// Gets the absolute file path of a node within the package. /// </summary> /// <param name="node">The node to get the path of.</param> /// <returns>The file path of the node in the package.</returns> public string GetNodeFilePath(FileNode node) { StringBuilder sb = new StringBuilder(); var currentNode = node; while (!(currentNode.Type.HasFlag(NodeType.Package) || currentNode.Type.HasFlag(NodeType.Meta))) { if (currentNode.Type.HasFlag(NodeType.Directory)) { sb.Insert(0, '\\'); } sb.Insert(0, GetNodeName(currentNode)); currentNode = this.Tree.GetNode((ulong)currentNode.ParentOffset); } return(sb.ToString()); }
/// <summary> /// Determines the number of children an iter has. /// </summary> /// <param name="iter">The iter to count the children of.</param> /// <returns>The number of children that the iter has.</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> /// <exception cref="ArgumentException">Thrown if the iter is not valid.</exception> public int IterNChildren(TreeIter iter) { if (iter.Equals(TreeIter.Zero)) { return((int)this.Tree.Root.ChildCount); } if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } FileNode node = this.Tree.GetNode((ulong)iter.UserData); if (node == null) { throw new ArgumentException("The given iter was not valid.", nameof(iter)); } return((int)node.ChildCount); }
/// <summary> /// Moves the given iter to the next one at the same level. /// </summary> /// <param name="iter">The iter to move.</param> /// <returns>true if the iter is now set to the next iter at the same level; false otherwise</returns> /// <exception cref="InvalidDataException">Thrown if the iter doesn't belong to the model.</exception> public bool IterNext(ref TreeIter iter) { if (iter.Stamp != this.Stamp) { throw new InvalidDataException("The given iter was not valid for this model."); } ulong currentOffset = (ulong)iter.UserData; FileNode currentNode = this.Tree.GetNode(currentOffset); FileNode parentNode = this.Tree.GetNode((ulong)currentNode.ParentOffset); int currentIndex = parentNode.ChildOffsets.IndexOf(currentOffset); int nextIndex = currentIndex + 1; if (nextIndex < (int)parentNode.ChildCount) { iter.UserData = new IntPtr((long)parentNode.ChildOffsets[nextIndex]); return(true); } return(false); }
/// <summary> /// Handles rendering of the name of a node in the tree. /// </summary> /// <param name="column">The column which the cell is in.</param> /// <param name="cell">The cell which the name is in.</param> /// <param name="model">The model of the treeview.</param> /// <param name="iter">The <see cref="TreeIter"/> pointing to the row the name is in.</param> private void RenderNodeName(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { CellRendererText cellText = cell as CellRendererText; FileNode node = (FileNode)model.GetValue(iter, 0); if (node == null || cellText == null) { return; } cellText.Text = this.TreeModel.GetNodeName(node); if (node.Type.HasFlag(NodeType.Deleted)) { cellText.Style = Style.Italic; cellText.Foreground = "#D74328"; } else { cellText.Style = Style.Normal; cellText.Foreground = null; } }
/// <summary> /// Gets an iter at a specified path. /// </summary> /// <param name="iter">Will contain the iter.</param> /// <param name="path">The path to the iter.</param> /// <returns>true if the iter is now set to the iter at the given path; false otherwise.</returns> public bool GetIter(out TreeIter iter, TreePath path) { iter = TreeIter.Zero; ulong currentOffset = 0; FileNode currentNode = this.Tree.Root; foreach (int index in path.Indices) { ulong longIndex = (ulong)index; if (longIndex > currentNode.ChildCount - 1) { return(false); } currentOffset = currentNode.ChildOffsets[index]; currentNode = this.Tree.GetNode(currentOffset); } iter.UserData = new IntPtr((long)currentOffset); iter.Stamp = this.Stamp; return(true); }
/// <summary> /// Handles rendering of the icon of a node in the tree. /// </summary> /// <param name="column">The column which the icon is in.</param> /// <param name="cell">The cell which the reference is in.</param> /// <param name="model">The model of the treeview.</param> /// <param name="iter">The <see cref="TreeIter"/> pointing to the row the icon is in.</param> private void RenderNodeIcon(TreeViewColumn column, CellRenderer cell, ITreeModel model, TreeIter iter) { CellRendererPixbuf cellIcon = cell as CellRendererPixbuf; FileNode node = (FileNode)model.GetValue(iter, 0); if (node == null || cellIcon == null) { return; } if (node.Type.HasFlag(NodeType.Directory)) { cellIcon.Pixbuf = IconManager.GetIconForFiletype(WarcraftFileType.Directory); return; } if (node.Type.HasFlag(NodeType.Deleted)) { cellIcon.Pixbuf = IconManager.GetIcon("package-broken"); return; } if (node.Type.HasFlag(NodeType.Meta) && this.TreeModel.GetNodeName(node) == "Packages") { cellIcon.Pixbuf = IconManager.GetIcon("applications-other"); return; } if (node.Type.HasFlag(NodeType.Package)) { cellIcon.Pixbuf = IconManager.GetIcon("package-x-generic"); return; } cellIcon.Pixbuf = IconManager.GetIconForFiletype(node.FileType); }
/// <summary> /// Gets the name of a given node. /// </summary> /// <param name="node">The node to get the name of.</param> /// <returns>The name of the node.</returns> public string GetNodeName(FileNode node) { return(this.Tree.GetNodeName(node)); }