Example #1
0
        /// <summary>
        /// This methods draws the graph for the changeset history grid.
        /// </summary>
        public void Draw(ItemCollection commitList)
        {
            if (graph == null)
                return;

            Console.WriteLine("Drawing graph.");

            var repo = new LibGit2Sharp.Repository(repositoryViewModel.RepositoryFullPath);
            commitDotPositions.Clear();
            SetBranchColors(repo.Branches);

            // Loop through all commits and draw the graph, in reverse order.
            commitList.MoveCurrentToLast();

            // Clear the existing graph.
            graph.Children.Clear();

            TotalHeight = 0;

            while (true)
            {
                Commit commit = commitList.CurrentItem as Commit;
                int rowNumber = commitList.CurrentPosition;

                if (commit == null)
                    break;

                // Get a list of branches around this commit.
                List<Branch> branchesAroundCommit = commit.BranchesAround;

                // Sort the lists alphabetically.
                branchesAroundCommit.OrderBy(o => o.Name.ToString());

                // Retrieve the index of this commit's branch on the list. This index determines the horizontal positions of dots (commit dots).
                int indexOfCurrentBranch;
                if (commit.Branches.Count > 0)
                    indexOfCurrentBranch = branchesAroundCommit.IndexOf(commit.Branches.ElementAt(0));
                else
                    indexOfCurrentBranch = 0;

                int horizontalIndex = indexOfCurrentBranch + commit.VisualPosition;
                for (var i = indexOfCurrentBranch - 1; i >= 0; i--)
                    horizontalIndex += ((Branch) branchesAroundCommit.ElementAt(i)).RightMostVisualPosition;

                // Draw the dot/ellipse based on the index of the current branch.
                byte dotSize = 10;
                byte horizontalDotSpacing = 12;

                int dotX = horizontalDotSpacing + dotSize * horizontalIndex + horizontalDotSpacing * horizontalIndex;
                int dotY = cellHeight * rowNumber + cellHeight / 2 - dotSize / 2;

                if (TotalHeight == 0)
                    TotalHeight = cellHeight * (rowNumber + 1);

                // Store the dot position on the dictionary.
                commitDotPositions.Add(commit.Hash, new int[2] { dotX, dotY });

                Ellipse dot = new Ellipse
                {
                    Fill = Brushes.Black,
                    StrokeThickness = 0,
                    Width = dotSize + 2,
                    Height = dotSize + 2
                };

                Canvas.SetLeft(dot, dotX - 1);
                Canvas.SetTop(dot, dotY - 1);
                Canvas.SetZIndex(dot, 1);

                graph.Children.Add(dot);

                // ToolTip for commits.
                var commitTooltip = new TextBlock
                {
                    MaxWidth = 320,
                    TextWrapping = TextWrapping.Wrap
                };

                // ToolTip for paths.
                var pathTooltip = new TextBlock
                {
                    MaxWidth = 320,
                    TextWrapping = TextWrapping.Wrap
                };

                if (commit.Branches.Count == 1)
                {
                    pathTooltip.Text = commit.Branches.ElementAt(0).Name;
                }
                else
                {
                    int i = 0, count = commit.Branches.Count;

                    commit.Branches.ForEach(b =>
                    {
                        i++;
                        pathTooltip.Inlines.AddRange(new Inline[]
                        {
                            new Run(b.Name + (i < count ? ", " : "")),
                        });
                    });
                }

                // Regular commits have a white circle inside.
                if (commit.IsMergeCommit() == false && commit.ParentCount < 2)
                {
                    Ellipse dotInner = new Ellipse
                    {
                        Fill = Brushes.White,
                        StrokeThickness = 0,
                        Width = dotSize,
                        Height = dotSize
                    };

                    Canvas.SetLeft(dotInner, dotX);
                    Canvas.SetTop(dotInner, dotY);
                    Canvas.SetZIndex(dotInner, 2);

                    graph.Children.Add(dotInner);

                    // ToolTip.
                    commitTooltip.Inlines.AddRange(new Inline[]
                    {
                        new Run("Commit: ")  {FontWeight = FontWeights.Bold},
                        new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold},
                        new LineBreak(),
                        new Run("Author: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.AuthorName) ,
                        new LineBreak(),
                        new Run("Date: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.FormattedDate),
                        new LineBreak(),
                        new LineBreak(),
                        new Run(commit.Description.TrimEnd())
                    });

                    dotInner.ToolTip = commitTooltip;
                    ToolTipService.SetShowDuration(dotInner, 60000);
                    ToolTipService.SetInitialShowDelay(dotInner, 1);
                }
                else
                {
                    // Tooltip.
                    commitTooltip.Inlines.AddRange(new Inline[]
                    {
                        new Run("Merge commit: ")  {FontWeight = FontWeights.Bold},
                        new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold},
                        new LineBreak(),
                        new Run("Author: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.AuthorName) ,
                        new LineBreak(),
                        new Run("Date: ") {FontWeight = FontWeights.Bold},
                        new Run(commit.FormattedDate),
                        new LineBreak(),
                        new LineBreak(),
                        new Run(commit.Description.TrimEnd())
                    });

                    dot.ToolTip = commitTooltip;
                    ToolTipService.SetShowDuration(dot, 60000);
                    ToolTipService.SetInitialShowDelay(dot, 1);
                }

                if (commit.Branches.Count > 0)
                {
                    // Draw the line to the parent dot(s)/commit(s).
                    foreach (string hash in commit.ParentHashes)
                    {
                        // Retrieve the parent commit dot position.
                        var positions = commitDotPositions.Where(o => o.Key == hash);

                        if (positions.Count() > 0)
                        {
                            int[] parentPosition = commitDotPositions.Where(o => o.Key == hash).First().Value;

                            Brush lineColor = BranchColors[commit.Branches.ElementAt(0).Name];

                            // Calculate line positions.
                            float startLineX1 = dotX + dotSize / 2;
                            float startLineY1 = dotY + dotSize / 2;
                            float endLineX2 = parentPosition[0] + dotSize / 2;
                            float endLineY2 = parentPosition[1] + dotSize / 2;
                            float startLineX2;
                            float startLineY2;
                            float endLineX1;
                            float endLineY1;

                            if (commit.IsMergeCommit())
                            {
                                startLineX2 = endLineX2;
                                startLineY2 = startLineY1;

                                endLineX1 = endLineX2;
                                endLineY1 = startLineY1;
                            }
                            else
                            {
                                startLineX2 = startLineX1;
                                startLineY2 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 6;

                                endLineX1 = startLineX1;
                                endLineY1 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 12;
                            }

                            // Construct and draw the line path.
                            Path path = new Path
                            {
                                Stroke = lineColor,
                                StrokeThickness = 4,
                                Data = new PathGeometry
                                {
                                    Figures = new PathFigureCollection
                                    {
                                        new PathFigure
                                        {
                                            StartPoint = new Point(startLineX1, startLineY1),
                                            Segments = new PathSegmentCollection
                                            {
                                                new PolyBezierSegment
                                                {
                                                    Points = new PointCollection
                                                    {
                                                        new Point(startLineX2, startLineY2),
                                                        new Point(endLineX1, endLineY1),
                                                        new Point(endLineX2, endLineY2)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            graph.Children.Add(path);

                            path.ToolTip = pathTooltip;
                            ToolTipService.SetShowDuration(path, 60000);
                            ToolTipService.SetInitialShowDelay(path, 1);
                        }
                    }
                }

                commitList.MoveCurrentToPrevious();
                if (commitList.IsCurrentBeforeFirst)
                {
                    break;
                }
            }

            repo.Dispose();
        }