public void StartsWith4() { var nr = new HierarchicalPath("/this/is"); var sr = new HierarchicalPath("/this"); Assert.AreEqual(true, nr.StartsWith(sr)); }
public void StartsWith2() { var nr = new HierarchicalPath("/this/is"); var sr = new HierarchicalPath("/not/in/is/a/path"); Assert.AreEqual(false, nr.StartsWith(sr)); }
/// <summary> /// Shuffles the contents of the list so that each HierarchicalPath is /// followed directly by the items underneath it, but still retain the /// relative order elements that aren't in the hierarchicy. /// /// For example, given "/z/a", "/z", and "/b", it would sort them into /// "/z", "/z/a", "/b". /// </summary> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="list">The list.</param> public static void OrderByHierarchicalPath <TItem>(this IList <TItem> list) where TItem : IHierarchicalPathContainer { // If the list is empty or has a single time, we don't have to do // anything. int count = list.Count; if (count <= 1) { return; } // For the first path, go through the list and perform a bubble // sort to reorder the elements so that parent elements will be // before the child ones. for (int startIndex = 0; startIndex < count - 1; startIndex++) { // Pull out the path at this index. HierarchicalPath startPath = list[startIndex].HierarchicalPath; bool startOver = false; // Go through all the items after the start index. for (int testIndex = startIndex + 1; testIndex < count; testIndex++) { // Pull out the test path for comparison. HierarchicalPath testPath = list[testIndex].HierarchicalPath; // Check for equal levels since we don't swap equal-level // elements. if (startPath.Count == testPath.Count) { continue; } // Check to see which one has the least number of elements // since that will be "higher" on the list. if (startPath.StartsWith(testPath)) { // We have to insert the parent before the current start // index, then start processing again. TItem item = list[testIndex]; list.RemoveAt(testIndex); list.Insert(startIndex, item); // Decrement the start index to start again. startOver = true; break; } } // If we are starting over, we shift the index back slight and // start the outer loop again. if (startOver) { startIndex--; break; } } // The second pass involves grouping the related items together. // This is a 2-loop process. The first loop is the item we are // comparing against. The second looks for items that are underneath // the test path and brings them before items that are not. for (int startIndex = 0; startIndex < count - 1; startIndex++) { // Pull out the path at this index. HierarchicalPath startPath = list[startIndex].HierarchicalPath; // Go through all the items after the start index. int lastChildIndex = startIndex; bool foundNonChild = false; for (int testIndex = startIndex + 1; testIndex < count; testIndex++) { // Pull out the test path for comparison. HierarchicalPath testPath = list[testIndex].HierarchicalPath; // Check to see if testPath is underneath the startPath. if (testPath.StartsWith(startPath)) { // Check to see if we have a non-child between the last // child path and this one. if (foundNonChild) { // Increment the last child index since we'll be // inserting this new item there. lastChildIndex++; // Remove the item from the test position and insert // it into the updated child index. TItem item = list[testIndex]; list.RemoveAt(testIndex); list.Insert(lastChildIndex, item); // Move the index back to it (and a bit more to // handle the for() loop incrementer. testIndex = lastChildIndex - 1; // Clear out the non child flag. foundNonChild = false; } else { // This is a child item, just mark it and continue. lastChildIndex = testIndex; } } else { // This isn't a child path foundNonChild = true; } } } }
/// <summary> /// Converts the given list of path containers into a Gtk.TreeStore. /// The resulting store will have three fields: the part of the path /// that represents the item, the full path, and the item. If the level /// doesn't exist (such as the created "/a" when "/a/b" is the only item), /// then the third column will be the default value. /// </summary> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="list">The list.</param> /// <param name="reorderInPlace">if set to <c>true</c> [reorder in place].</param> /// <returns></returns> public static TreeStore ToTreeStore <TItem>( this IList <TItem> list, bool reorderInPlace) where TItem : IHierarchicalPathContainer { // Create a new tree store to populate. var store = new TreeStore( typeof(string), typeof(HierarchicalPath), typeof(TItem)); // If we are not reordering the list in place, then create a new one // that we can reorder. if (!reorderInPlace) { var newList = new List <TItem>(list); list = newList; } // Order the list so everything is grouped together. list.OrderByHierarchicalPath(); // Go through the ordered list and append all the tree elements. // Because of the ordering, we can do this as a single pass through // the list. HierarchicalPath lastPath = null; var iterPath = new List <TreeIter>(); foreach (TItem item in list) { // Pull out the path we'll be appending. HierarchicalPath path = item.HierarchicalPath; // Roll up the list to a common root. while (lastPath != null && lastPath.Count > 0 && !path.StartsWith(lastPath)) { // We don't have a common root, so move up a level. iterPath.RemoveLast(); lastPath = lastPath.Parent; } // Add any parent items to the list that we don't already // have. We do this by adding placeholders up to the current // TreeIter list until we get to the parent. TreeIter treeIter; while (iterPath.Count < path.Count - 1) { // Pull out the path we'll be inserting. string parentName = path[iterPath.Count]; lastPath = path.Splice(iterPath.Count, 1); // We have to add a placeholder item for this inserted // parent item. if (iterPath.Count == 0) { // We are at the top, so insert it there. treeIter = store.AppendValues(parentName, lastPath, default(TItem)); } else { // Append it to the parent item above it. treeIter = store.AppendValues( iterPath[iterPath.Count - 2], parentName, lastPath, default(TItem)); } // Append the newly inserted iterator into the list. iterPath.Add(treeIter); } // Once we get through this, we insert the current item. lastPath = item.HierarchicalPath; string name = lastPath.Last; if (iterPath.Count == 0) { // We are at the top, so insert it there. treeIter = store.AppendValues(name, lastPath, item); } else { // Append it to the parent item above it. treeIter = store.AppendValues( iterPath[iterPath.Count - 1], name, lastPath, item); } // Append the newly inserted iterator into the list. iterPath.Add(treeIter); } // Return the resulting store. return(store); }