/// <summary> /// Attempts to collapse parent and child if there is only one child. /// </summary> private static void PruneTree(FileItemViewModel root) { if (root.Children.Count == 1) { var child = root.Children[0]; // Update root's name to include child's root.Name = root.Name + Path.AltDirectorySeparatorChar + child.Name; // Remove child from list of children root.Children.Clear(); // Assign child's children to root. Re-assign parent to point to root. foreach (var grandchild in child.Children) { root.Children.Add(grandchild); grandchild.Parent = root; } } foreach (var child in root.Children) { WorkspacePageViewModel.PruneTree(child); } }
private static List <FileItemViewModel> BuildTreeFromFiles(List <Tuple <string, float> > files) { // Step 3: Contruct a tree based on files var cache = new Dictionary <string, FileItemViewModel>(); var roots = new List <FileItemViewModel>(); for (var i = 0; i < files.Count; i++) { var filePath = files[i]; // Get the path components var filePathParts = filePath.Item1.Split(Path.AltDirectorySeparatorChar); // Create the leaf using the file name var fileItemViewModel = new FileItemViewModel( filePath.Item1, filePathParts[filePathParts.Length - 1], filePath.Item2); // Go through each file and add every nodes in the tree for each folder as well as leaves for each file var currentChild = fileItemViewModel; for (var j = filePathParts.Length - 2; j >= 0; j--) { var ancestorName = filePathParts[j]; var ancestorId = currentChild.Id.Substring( 0, currentChild.Id.LastIndexOf(Path.AltDirectorySeparatorChar)); if (!cache.ContainsKey(ancestorId)) { cache[ancestorId] = new FileItemViewModel(ancestorId, ancestorName, 0); if (j == 0) { roots.Add(cache[ancestorId]); } } var ancestor = cache[ancestorId]; if (!ancestor.Children.Contains(currentChild)) { currentChild.Parent = ancestor; ancestor.Children.Add(currentChild); } currentChild = ancestor; } } // Go through the entire tree and remove nodes with a single child, collapsing their info // into their parent node. SortBiggerFirst(roots); foreach (var root in roots) { WorkspacePageViewModel.PruneTree(root); } return(roots); }
/// <summary> /// Open the log file and process it into a set of FileItemViewModels suitable for use /// in a tree view. /// </summary> private async Task LoadFile() { using (var stream = new FileStream(this.fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new StreamReader(stream)) { // Step 1: Read the raw input data and convert it into a list of <file names, file size> tuples. List <Tuple <string, float> > files = new List <Tuple <string, float> >(); bool startProcessing = false; var line = string.Empty; while (!reader.EndOfStream) { line = await reader.ReadLineAsync(); if (line.Trim() == WorkspacePageViewModel.LogStartWord) { // This is the line before the size breakdown startProcessing = true; continue; } if (!startProcessing) { // Still haven't reached the size breakdown continue; } Tuple <string, float> data; if (WorkspacePageViewModel.GetPathAndMegabytesFrom(line, out data)) { files.Add(data); } else { // We've reached the end of the size breakdown break; } } // Step 2: Sort the list of files by file name. files.Sort(new PathAndSizeComparer()); // Step 3: Contruct a tree based on files Dictionary <string, FileItemViewModel> cache = new Dictionary <string, FileItemViewModel>(); List <FileItemViewModel> roots = new List <FileItemViewModel>(); for (int i = 0; i < files.Count; i++) { var filePath = files[i]; // Get the path components var filePathParts = filePath.Item1.Split(Path.AltDirectorySeparatorChar); // Create the leaf using the file name var fileItemViewModel = new FileItemViewModel( filePath.Item1, filePathParts[filePathParts.Length - 1], filePath.Item2); // Go through each file and add every nodes in the tree for each folder as well as leaves for each file var currentChild = fileItemViewModel; for (int j = filePathParts.Length - 2; j >= 0; j--) { var ancestorName = filePathParts[j]; var ancestorId = currentChild.Id.Substring(0, currentChild.Id.LastIndexOf(Path.AltDirectorySeparatorChar)); if (!cache.ContainsKey(ancestorId)) { cache[ancestorId] = new FileItemViewModel(ancestorId, ancestorName, 0); if (j == 0) { roots.Add(cache[ancestorId]); } } var ancestor = cache[ancestorId]; if (!ancestor.Children.Contains(currentChild)) { currentChild.Parent = ancestor; ancestor.Children.Add(currentChild); } currentChild = ancestor; } } // Step 4: A little warm up to get the root properties in the proper state and ready to draw. foreach (var root in roots) { root.IsEnabled = true; root.Visibility = Visibility.Visible; root.ChartVisibility = Visibility.Visible; } // Step 5: Add the root nodes to the observable list for the view to process this.Roots.AddRange(roots); } }