private void CalculateFileSizes(List <DirectoryData> subDataList) { try { int fileCount = 0; long fileSize = 0; Parallel.ForEach( this.directoryInfo.EnumerateFiles(), info => { Interlocked.Add(ref fileSize, info.Length); Interlocked.Increment(ref fileCount); }); this.AdjustStats(fileSize, fileCount, 0, false); // Only add a [Files] node if we found some files (even 0 byte files). if (fileCount > 0) { // Add a faux node for files const string FilesNodeName = "[Files]"; DirectoryData data = new DirectoryData(FilesNodeName, Path.Combine(this.directoryInfo.FullName, FilesNodeName), fileSize, fileCount); subDataList.Add(data); } } catch (Exception ex) { AddErrorData(subDataList, "File Error: ", ex.Message); } }
private static void SetDirectoryNodeImage(TreeNode node) { if (IsNodeADirectory(node)) { DirectoryData data = GetDataForNode(node); int imageIndex = GetImageForData(data); node.ImageIndex = imageIndex; node.SelectedImageIndex = node.ImageIndex; } }
private void UpdateStatusBar(TreeNode selectedNode) { if (selectedNode != null) { DirectoryData selectedData = GetDataForNode(selectedNode); this.UpdateStatusBar(selectedData); } else { this.UpdateStatusBar(string.Empty); } }
private static bool IsNodeADirectory(TreeNode node) { bool result = false; if (node != null) { DirectoryData data = GetDataForNode(node); result = data.DataType == DirectoryDataType.Directory; } return(result); }
private void CalculateDirectorySize(List <DirectoryData> subDataList, BackgroundWorker worker, DirectoryInfo info) { // Never report progress for sub-directories. It adds too much blocking, which makes things take forever. // Add 1 to the folder count to account for the current directory. DirectoryData data = new DirectoryData(info, worker, false); this.AdjustStats(data.Size, data.FileCount, 1 + data.FolderCount, false); lock (subDataList) { subDataList.Add(data); } }
private void OpenFolder_Click(object sender, System.EventArgs e) { TreeNode selectedNode = this.Tree.SelectedNode; if (selectedNode != null) { DirectoryData selectedData = GetDataForNode(selectedNode); if (selectedData.DataType == DirectoryDataType.Directory) { selectedData.Explore(this); } } }
private void Map_NodeDoubleClick(object sender, NodeEventArgs e) { // Because the tree auto-populates as its nodes are expanded, // we have to drill down one level at a time by parsing the path. // We can't assume that a given Treemap.Node will already have // an associated TreeViewNode. Node node = e.Node; if (node != null && this.Tree.Nodes.Count > 0) { TreeNode rootTreeNode = this.Tree.Nodes[0]; DirectoryData rootData = GetDataForNode(rootTreeNode); DirectoryData data = GetDataForNode(node); if (data != null && rootData != null) { string fullName = data.FullName; string rootFullName = rootData.FullName; if (!string.IsNullOrEmpty(fullName) && !string.IsNullOrEmpty(rootFullName) && fullName.StartsWith(rootFullName, StringComparison.CurrentCultureIgnoreCase)) { // Remove the root path first. fullName = fullName.Remove(0, rootFullName.Length); // Now get the remaining path parts, so we can find their tree nodes. string[] parts = fullName.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); TreeNode currentNode = rootTreeNode; foreach (var partName in parts) { currentNode.Expand(); int childIndex = currentNode.Nodes.IndexOfKey(partName); if (childIndex >= 0) { currentNode = currentNode.Nodes[childIndex]; } else { currentNode = null; break; } } if (currentNode != null) { this.Tree.SelectedNode = currentNode; } } } } }
#pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. private void MainWorker_DoWork(object sender, DoWorkEventArgs e) #pragma warning restore CC0091 // Use static method { string directoryName = (string)e.Argument; DirectoryInfo dirInfo = new DirectoryInfo(directoryName); // This does all the directory walking and sizing. BackgroundWorker bw = (BackgroundWorker)sender; DirectoryData data = new DirectoryData(dirInfo, bw); e.Result = data; e.Cancel = bw.CancellationPending; }
#pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. private void RefreshWorker_DoWork(object sender, DoWorkEventArgs e) #pragma warning restore CC0091 // Use static method { e.Result = e.Argument; var selection = (Tuple <TreeNode, DirectoryData, DirectoryData>)e.Argument; DirectoryData selectedData = selection.Item2; BackgroundWorker bw = (BackgroundWorker)sender; selectedData.Refresh(bw); e.Cancel = bw.CancellationPending; }
private static void AddDirectoryNode(TreeNodeCollection parentNodes, DirectoryData data) { TreeNode node = new TreeNode(); node.Tag = data; node.ImageIndex = GetImageForData(data); node.SelectedImageIndex = node.ImageIndex; node.Name = data.Name; // Map_NodeDoubleClick needs this so Nodes.IndexOfKey will work. SetNodeText(node, data); parentNodes.Add(node); if (data.SubData.Count > 0) { node.Nodes.Add(new DummyNode()); } }
private void UpdateMap(TreeNode treeNode) { using (new WaitCursor(this)) { DirectoryData data = GetDataForNode(treeNode); this.Map.BeginUpdate(); try { this.Map.Clear(); this.Map.Nodes.Add(data.TreeMapNode); } finally { this.Map.EndUpdate(); } } }
private void RefreshBranch_Click(object sender, System.EventArgs e) { TreeNode selectedNode = this.Tree.SelectedNode; if (selectedNode != null) { // Force it to collapse first since we're populating the tree on-demand. selectedNode.Collapse(); // Do the refresh asynchronously. Make a copy of the data now, so we can // adjust the stats all the way up the tree later. DirectoryData selectedData = GetDataForNode(selectedNode); DirectoryData selectedDataClone = selectedData.Clone(); this.Progress.Value = 0; this.RefreshWorker.RunWorkerAsync(Tuple.Create(selectedNode, selectedData, selectedDataClone)); } }
private void MainWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { using (new WaitCursor(this)) { this.Tree.BeginUpdate(); this.Map.BeginUpdate(); try { DirectoryData data; if (e.Error != null) { data = new DirectoryData(e.Error.Message); } else if (e.Cancelled) { data = new DirectoryData("Cancelled"); } else { data = (DirectoryData)e.Result; } // This populates the root of the tree. AddDirectoryNode(this.Tree.Nodes, data); // Select the first tree node so the map will update. if (this.Tree.SelectedNode == null) { this.Tree.SelectedNode = this.Tree.Nodes[0]; // Expand it since that's almost always desired too. this.Tree.SelectedNode.Expand(); } // Show the total time it took. this.stopwatch.Stop(); this.UpdateStatusBar(this.stopwatch.Elapsed); } finally { this.Tree.EndUpdate(); this.Map.EndUpdate(); } } }
#pragma warning disable CC0091 // Use static method. Designer likes instance event handlers. private void Tree_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) #pragma warning restore CC0091 // Use static method { TreeNode node = e.Node; SetDirectoryNodeImage(node); if (node.FirstNode is DummyNode) { node.Nodes.Clear(); DirectoryData data = GetDataForNode(node); foreach (DirectoryData childData in data.SubData) { AddDirectoryNode(node.Nodes, childData); } } }
private static int GetImageForData(DirectoryData data) { int result; switch (data.DataType) { case DirectoryDataType.Directory: result = FolderImageIndex; break; case DirectoryDataType.Files: result = FilesImageIndex; break; default: result = ErrorImageIndex; // Error or Unknown break; } return(result); }
private void UpdateStatusBar(DirectoryData selectedData) { string message = string.Empty; if (selectedData != null) { switch (selectedData.DataType) { case DirectoryDataType.Directory: case DirectoryDataType.Files: DirectoryData rootData = GetDataForNode(this.Tree.Nodes[0]); double percentage = rootData.Size != 0 ? selectedData.Size / (double)rootData.Size : 0; message = string.Format( "{0:F2}% of total space usage. {1}. {2}. {3}.", 100 * percentage, FormatLongUnits(selectedData.Size, "byte"), FormatLongUnits(selectedData.FileCount, "file"), FormatLongUnits(selectedData.FolderCount, "folder")); break; } } this.UpdateStatusBar(message); }
public DirectoryData Clone() { DirectoryData result = (DirectoryData)this.MemberwiseClone(); return(result); }
private void UpdateFolderView(TreeNode treeNode) { using (new WaitCursor(this)) { DirectoryData data = GetDataForNode(treeNode); string directory = null; bool clearView = false; switch (data.DataType) { case DirectoryDataType.Directory: directory = data.FullName; break; case DirectoryDataType.Files: // Show the directory where the files are located. directory = Path.GetDirectoryName(data.FullName); break; case DirectoryDataType.Error: clearView = true; break; } if (!string.IsNullOrEmpty(directory)) { // Make sure the directory is accessible for navigation. Otherwise, the // WebBrowser control pops up a modal error dialog. if (Directory.Exists(directory)) { try { // See if we can read anything in the directory (by looking for a GUID filename that should never exist). // This throws an exception if we can't read from the folder. Directory.GetFiles(directory, "4322F6AF-27BA-419C-AB4D-5FF8862B338C", SearchOption.TopDirectoryOnly); // When arrowing down quickly between tree nodes, the browser may not finish navigating to one folder // before the next navigation request comes in (since it navigates asynchronously from the UI thread). // To prevent a COMException from being thrown, we'll request that any pending navigation stop first. this.Browser.Stop(); this.Browser.Navigate(new Uri(directory, UriKind.Absolute), false); } catch (COMException) { clearView = true; } catch (UnauthorizedAccessException) { clearView = true; } } else { clearView = true; } } if (clearView) { this.ClearFolderView(); } } }
private void RefreshWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { using (new WaitCursor(this)) { this.Tree.BeginUpdate(); this.Map.BeginUpdate(); try { if (e.Error != null || e.Cancelled) { TreeNode selectedNode = this.Tree.SelectedNode; TreeNodeCollection nodes; if (selectedNode != null) { nodes = selectedNode.Nodes; } else { nodes = this.Tree.Nodes; } nodes.Clear(); string message = e.Error != null ? e.Error.Message : "Cancelled"; DirectoryData data = new DirectoryData(message); AddDirectoryNode(nodes, data); this.UpdateStatusBar(message); } else { var selection = (Tuple <TreeNode, DirectoryData, DirectoryData>)e.Result; TreeNode selectedNode = selection.Item1; DirectoryData selectedData = selection.Item2; DirectoryData oldData = selection.Item3; SetNodeText(selectedNode, selectedData); // The nodes will have to be rebuilt below it. selectedNode.Nodes.Clear(); if (selectedData.SubData.Count > 0) { selectedNode.Nodes.Add(new DummyNode()); } // Recalculate the stats for everything above it. TreeNode parentNode = selectedNode.Parent; long sizeAdjustment = selectedData.Size - oldData.Size; long fileCountAdjustment = selectedData.FileCount - oldData.FileCount; long folderCountAdjustment = selectedData.FolderCount - oldData.FolderCount; while (parentNode != null) { DirectoryData parentData = GetDataForNode(parentNode); parentData.AdjustStats(sizeAdjustment, fileCountAdjustment, folderCountAdjustment); SetNodeText(parentNode, parentData); parentNode = parentNode.Parent; } // Refresh the treemap this.UpdateMap(selectedNode); // Refresh the status bar this.UpdateStatusBar(selectedNode); // Expand it if it's the root node since that's almost always desired too. if (selectedNode == this.Tree.Nodes[0]) { selectedNode.Expand(); } } } finally { this.Tree.EndUpdate(); this.Map.EndUpdate(); } } }
private static void SetNodeText(TreeNode node, DirectoryData data) { node.Text = string.Format("{0}: {1:N1} MB", data.Name, data.SizeInMegabytes); }