/// <summary>Occurs on the background thread immediately before <see cref="RootNode{TChild}.ReloadNodes"/> is called.</summary>
            protected override void OnReloading(ICollection <BaseBranchNode> olds, ICollection <BaseBranchNode> news)
            {
                base.OnReloading(olds, news);

                // recursive get branches...
                List <string> branches = new List <string>();

                Func <List <string>, BaseBranchNode, List <string> > getChildBranches = ((seed, node) =>
                {
                    BranchPathNode branchPath = node as BranchPathNode;
                    if (branchPath != null)
                    {// BranchPath
                        return(branchPath.Recurse(
                                   seed,
                                   (bbp, count) => (from branchNode in branchPath.Children
                                                    let branch = branchNode as BranchNode
                                                                 where branch != null
                                                                 select branch.FullPath).ToList()));
                    }// else Branch
                    return(new List <string> {
                        node.FullPath
                    });
                });


                foreach (BaseBranchNode baseBranchNode in news)
                {
                    branches.AddRange(getChildBranches(branches, baseBranchNode));
                }

                Branches = branches;

                SetFavorites(news);
            }
        /// <summary>Adds a <see cref="BaseBranchNode"/>, and recursivley, its children.</summary>
        TreeNode OnAddBranchNode(TreeNodeCollection nodes, BaseBranchNode branchNode)
        {
            bool     isBranch = branchNode is BranchNode;
            TreeNode treeNode = new TreeNode(branchNode.Name)
            {
                Name             = branchNode.FullPath,
                Tag              = branchNode,
                ContextMenuStrip = isBranch ? menuBranch : menuBranchPath,
                ImageKey         = isBranch ? branchKey : branchPathKey,
                SelectedImageKey = isBranch ? branchKey : branchPathKey,
            };

            nodes.Add(treeNode);
            branchNode.TreeNode = treeNode;

            BranchPathNode branchPath = branchNode as BranchPathNode;

            if (branchPath != null)
            {
                foreach (BaseBranchNode child in branchPath.Children)
                {// recurse children
                    OnAddBranchNode(treeNode.Nodes, child);
                }
            }

            return(null);// return null bypass duplicate call to ApplyStyle
        }
            /// <summary>Finds a specified <see cref="BaseBranchNode"/> with the given full name.</summary>
            /// <typeparam name="TBranchNode">Type of <see cref="BaseBranchNode"/> to search for.</typeparam>
            public static TBranchNode Find <TBranchNode>(IEnumerable <BaseBranchNode> nodes, string fullPath)
                where TBranchNode : BaseBranchNode
            {
                if (fullPath == null)
                {
                    return(null);
                }

                foreach (var branchNode in nodes)
                {
                    if (branchNode.FullPath.Equals(fullPath))
                    {
                        return(branchNode as TBranchNode);
                    }
                    BranchPathNode branchPath = branchNode as BranchPathNode;
                    if (branchPath != null)
                    {
                        var match = Find <TBranchNode>(branchPath.Children, fullPath);
                        if (match != null)
                        {
                            return(match);
                        }
                    }
                }
                return(null);
            }
 public BranchNode(GitUICommands uiCommands,
                   string branch, int level, string activeBranchPath = null,
                   BranchPathNode parent = null, bool isLocal = true)
     : base(uiCommands, BranchesNode.GetName(branch), level, parent, isLocal)
 {
     IsActive    = Equals(activeBranchPath, FullPath);
     IsDraggable = true;
     AllowDrop   = true;
 }
 protected BaseBranchNode(GitUICommands uiCommands,
                          string name, int level, BranchPathNode parent, bool isLocal)
     : base(uiCommands)
 {
     Name    = name;
     Parent  = parent;
     Level   = level;
     IsLocal = isLocal;
 }
 /// <summary>Indicates whether the specified</summary>
 static bool IsInFamilyTree(BranchPathNode parent, string branch, out BranchPathNode commonAncestor)
 {
     if (IsParentOf(parent, branch))
     {
         commonAncestor = parent;
         return(true);
     }
     commonAncestor = null;
     return
         ((parent.Parent != null)
          &&
          IsInFamilyTree(parent.Parent, branch, out commonAncestor));
 }
            public T Recurse <T>(T seed, Func <BaseBranchNode, T, T> aggregate)
            {
                T egg = seed;

                foreach (BaseBranchNode baseBranchNode in Children)
                {
                    egg = aggregate(baseBranchNode, seed);
                    BranchPathNode branchPath = baseBranchNode as BranchPathNode;
                    if (branchPath != null)
                    {
                        egg = branchPath.Recurse(egg, aggregate);
                    }
                }
                return(egg);
            }
            void SetFavorites(ICollection <BaseBranchNode> news)
            {
                favorites.Clear();
                var favs = (from section in UiCommands.Module.GetLocalConfig().ConfigSections
                            where Equals(section.SectionName, "branch")
                            let value = section.GetValue("fav")
                                        where value.IsNotNullOrWhitespace()
                                        select section.SubSection).ToList();

                if (favs.Any() == false)
                {// no branches config'd -> return
                    return;
                } // else...

                Func <List <BranchNode>, BaseBranchNode, List <BranchNode> > getFavBranches = ((seed, node) =>
                {
                    BranchPathNode branchPath = node as BranchPathNode;
                    if (branchPath != null)
                    {
                        // BranchPath
                        return(branchPath.Recurse(
                                   seed,
                                   (bbp, favors) => (from branchNode in branchPath.Children
                                                     let branch = branchNode as BranchNode
                                                                  where branch != null
                                                                  let isFav = favs.Any(fav => Equals(fav, branchNode.FullPath))
                                                                              where isFav
                                                                              select branch).ToList()));
                    } // else (Branch)
                    BranchNode branchNod = node as BranchNode;
                    if (branchNod != null && favs.Any(fav => Equals(fav, branchNod.FullPath)))
                    {// branch AND
                        return(new List <BranchNode> {
                            branchNod
                        });
                    }

                    return(new List <BranchNode>());
                });

                foreach (BaseBranchNode baseBranchNode in news)
                {
                    favorites.AddRange(getFavBranches(favorites, baseBranchNode));
                }
            }
            /// <summary>Gets the children of the specified <paramref name="parent"/> node OR
            /// Creates a new lineage of <see cref="BaseBranchNode"/>s.</summary>
            static BranchPathNode GetChildren(GitUICommands uiCommands, BranchPathNode parent, string branch, string activeBranch, out BranchPathNode currentParent)
            {
                string[] splits   = branch.Split(Separator);// issues/iss1334 -> issues, iss1334
                int      nParents = splits.Length - 1;

                currentParent = parent // common ancestor
                                ?? new BranchPathNode(uiCommands, splits[0], 0);

                // benchmarks/-main
                // benchmarks/get-branches

                // start adding children at Parent.Level +1
                for (int i = currentParent.Level + 1; i < nParents; i++)
                {// parent0:parentN
                    currentParent = currentParent.AddChild(
                        new BranchPathNode(uiCommands, splits[i], i, currentParent));
                }
                // child
                currentParent.AddChild(new BranchNode(uiCommands, splits[splits.Length - 1], nParents, activeBranch, currentParent));
                return(currentParent.Root);
            }
            internal BaseBranchNode CreateRootNode(IDictionary<string, BaseBranchNode> nodes)
            {
                if (ParentPath.IsNullOrEmpty())
                    return this;

                BaseBranchNode parent;
                BaseBranchNode result;

                if (nodes.TryGetValue(ParentPath, out parent))
                {
                    result = null;
                }
                else
                {
                    parent = new BranchPathNode(Tree, ParentPath);
                    nodes.Add(ParentPath, parent);
                    result = parent.CreateRootNode(nodes);
                }

                parent.Nodes.AddNode(this);

                return result;
            }
            /// <summary>Gets the hierarchical branch tree from the specified list of <paramref name="branches"/>.</summary>
            public static ICollection <BaseBranchNode> GetBranchTree(GitUICommands uiCommands, IEnumerable <string> branches)
            {
                // (input)
                // a-branch
                // develop/crazy-branch
                // develop/features/feat-next
                // develop/features/feat-next2
                // develop/issues/iss444
                // develop/wild-branch
                // issues/iss111
                // master
                //
                // ->
                // (output)
                // 0 a-branch
                // 0 develop/
                // 1   features/
                // 2      feat-next
                // 2      feat-next2
                // 1   issues/
                // 2      iss444
                // 1   wild-branch
                // 1   wilds/
                // 2      card
                // 0 issues/
                // 1     iss111
                // 0 master

                #region get active branch and scrub

                var    rawBranches  = branches.ToList();
                var    branchList   = rawBranches.ToList();
                string activeBranch =
                    branchList.FirstOrDefault(
                        branch => branch.StartsWith(GitModule.ActiveBranchIndicatorStr));
                if (activeBranch != null)
                {
                    activeBranch  = activeBranch.TrimStart(GitModule.ActiveBranchIndicator, ' ');
                    branchList[0] = activeBranch;
                }
                branches = branchList;
                #endregion get active branch and scrub

                branches = branches.OrderBy(branch => branch);// orderby name
                BranchPathNode        currentParent = null;
                List <BaseBranchNode> nodes         = new List <BaseBranchNode>();

                foreach (string branch in branches)
                {
                    if (IsOrHasParent(branch) == false)
                    {// just a plain branch (master)
                        nodes.Add(new BranchNode(uiCommands, branch, 1, activeBranch));
                    }
                    // (else has/is parent)

                    else if (currentParent == null)
                    {// (has/is parent) -> return all parents and branch
                        nodes.Add(GetChildren(uiCommands, null, branch, activeBranch, out currentParent));
                    }
                    // (else currentParent NOT null)

                    else if (IsInFamilyTree(currentParent, branch, out currentParent))
                    {
                        GetChildren(uiCommands, currentParent, branch, activeBranch, out currentParent);
                    }
                    else
                    {
                        nodes.Add(GetChildren(uiCommands, null, branch, activeBranch, out currentParent));
                    }
                }
                return(nodes);
            }
            public override bool Equals(object obj)
            {
                BranchPathNode other = obj as BranchPathNode;

                return(other != null && string.Equals(Name, other.Name));
            }
 /// <summary>Creates a new <see cref="BranchPathNode"/>.</summary>
 /// <param name="name">Short name for the path.</param>
 /// <param name="level">Level of the node in the tree.</param>
 /// <param name="parent">Parent node. Leave NULL if this is a Root.</param>
 /// <param name="isLocal">Indicates whether the <see cref="BranchPathNode"/> is for local branches.</param>
 public BranchPathNode(GitUICommands uiCommands,
                       string name, int level, BranchPathNode parent = null, bool isLocal = true)
     : base(uiCommands, name, level, parent, isLocal)
 {
     Children = new List <BaseBranchNode>();
 }
 public BranchPathNode AddChild(BranchPathNode path)
 {
     Children.Add(path);
     return(path);
 }