diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs index 275eca5187..9b6eadd966 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/ProjectBrowserControl.cs @@ -57,6 +57,7 @@ namespace ICSharpCode.SharpDevelop.Project { InitializeComponent(); treeView.BeforeSelect += TreeViewBeforeSelect; + treeView.AfterExpand += TreeViewAfterExpand; FileService.FileRenamed += FileServiceFileRenamed; FileService.FileRemoved += FileServiceFileRemoved; @@ -110,7 +111,7 @@ namespace ICSharpCode.SharpDevelop.Project ViewSolution(((AbstractProjectBrowserTreeNode)treeView.Nodes[0]).Solution); } } - + FileNode FindFileNode(TreeNodeCollection nodes, string fileName) { FileNode fn; @@ -120,9 +121,11 @@ namespace ICSharpCode.SharpDevelop.Project if (FileUtility.IsEqualFileName(fn.FileName, fileName)) return fn; } - fn = FindFileNode(node.Nodes, fileName); - if (fn != null) - return fn; + if (node != null) { + fn = FindFileNode(node.Nodes, fileName); + if (fn != null) + return fn; + } } return null; } @@ -137,12 +140,18 @@ namespace ICSharpCode.SharpDevelop.Project return FindFileNode(treeView.Nodes, fileName); } + // stores the fileName of the last selected target so + // that we can select it again on opening a folder + string lastSelectionTarget; + /// - /// Selects the node of a file if it is visible + /// Selects the deepest node open on the path to a particular file. /// public void SelectFile(string fileName) { - FileNode node = FindFileNode(fileName); + lastSelectionTarget = fileName; + TreeNode node = FindFileNode(fileName); + if (node != null) { // select first parent that is not collapsed TreeNode nodeToSelect = node; @@ -155,8 +164,154 @@ namespace ICSharpCode.SharpDevelop.Project if (nodeToSelect != null) { treeView.SelectedNode = nodeToSelect; } + } else { + SelectDeepestOpenNodeForPath(fileName); } } + + #region SelectDeepestOpenNode internals +// +// SolutionNode RootSolutionNode { +// get { +// if (treeView.Nodes != null && treeView.Nodes.Count>0) { +// return treeView.Nodes[0] as SolutionNode; +// } +// return null; +// } +// } +// + void SelectDeepestOpenNodeForPath(string fileName) + { + LoggingService.DebugFormatted("Selecting Deepest for '{0}'", fileName); + Solution solution = ProjectService.OpenSolution; + + IProject project = ProjectService.OpenSolution.FindProjectContainingFile(fileName); + if (project == null) { + LoggingService.Debug("no IProject found"); + return; + } + + string relativePath = String.Empty; + TreeNode targetNode = FindProjectNode(project); + + if (targetNode == null) { + + // our project node is not yet created, + // so start at the root and work down. + + if (treeView.Nodes == null || treeView.Nodes.Count<1) { + // the treeView is not yet prepared to assist in this request. + return; + + } else { + targetNode = treeView.Nodes[0]; + if (fileName.StartsWith(solution.Directory)) { + relativePath = fileName.Replace(solution.Directory, ""); + } + } + + } else { + // start from the project node and work upwards + // to the first visible node + TreeNode t = targetNode; + TreeNode p = targetNode.Parent; + while (p != null) { + if (!p.IsExpanded) { + t = p; + } + p = p.Parent; + } + + if (t != targetNode) { + // project node is instantiated but not visible + // so select the most visible parent node. + treeView.SelectedNode = t; + return; + + } else { + // project node is instantiated and visible + // so we start here and work down + if (fileName.StartsWith((targetNode as ProjectNode).Directory)) { + relativePath = fileName.Replace((targetNode as ProjectNode).Directory, ""); + } + } + + } + + if (!targetNode.IsExpanded) { + // the targetNode is not expanded so it's as deep as we can go + treeView.SelectedNode = targetNode; + LoggingService.DebugFormatted("target node '{0};{1}' is not expanded.", targetNode, targetNode.Text); + return; + } + + LoggingService.Debug("entering depth loop..."); + LoggingService.DebugFormatted(@"\- looking for '{0}'", relativePath); + LoggingService.DebugFormatted(@"\- starting at '{0}'", targetNode != null ? targetNode.Text : "null"); + + string[] targets = relativePath.Trim('/','\\').Split('/', '\\'); + TreeNode nextNode = null; + foreach (string target in targets) { + LoggingService.Debug("-- looking for: "+target); + nextNode = null; + foreach (TreeNode node in targetNode.Nodes) { + if (node.Text == target) { + nextNode = node; + break; + } + } + if (nextNode == null) { + // targetNode is as deep as we can find + break; + } else { + targetNode = nextNode; + } + } + treeView.SelectedNode = targetNode; + } + + ProjectNode FindProjectNode(IProject project) + { + if (project == null) { + return null; + } + return FindProjectNodeByName(treeView.Nodes, project.Name); + } + + // derived from FindFileNode + ProjectNode FindProjectNodeByName(TreeNodeCollection nodes, string projectName) + { + ProjectNode pn; + foreach (TreeNode node in nodes) { + pn = node as ProjectNode; + if (pn != null) { + if (pn.Text == projectName) { + return pn; + } + } + pn = FindProjectNodeByName(node.Nodes, projectName); + if (pn != null) + return pn; + } + return null; + } + + // TODO: remove this debug code +// void LogTreeViewPaths(TreeNodeCollection nodes, int depth) +// { +// System.Text.StringBuilder sb = null; +// +// foreach (TreeNode node in nodes) { +// sb = new System.Text.StringBuilder(); +// for(int i = 0; i