protected override void OnRender(DrawingContext drawingContext)
        {
            try
            {
                using (IsGraphDrawnScope isGraphDrawnScope = new IsGraphDrawnScope())
                {
                    if (RenderSize.Width < 10.0 || RenderSize.Height < 10.0)
                    {
                        return;
                    }

                    if (PBMCommand.Instance == null)
                    {
                        return;
                    }

                    DTE2 dte = (DTE2)PBMCommand.Instance.ServiceProvider.GetService(typeof(DTE));

                    if (dte == null)
                    {
                        return;
                    }

                    if (DataModel.Instance.AllProjectsCount == 0)
                    {
                        return;
                    }

                    int    linesCount  = DataModel.CurrentBuilds.Count + DataModel.FinishedBuilds.Count + 1 + 1 + 1 + 1; // 1 for header, 1 for status, 1 for CPU, 1 for HDD
                    double totalHeight = rowHeight * linesCount;

                    Height = totalHeight + penThickness;

                    long tickStep = 100000000;
                    long maxTick  = tickStep;
                    long nowTick  = DateTime.Now.Ticks;
                    long t        = nowTick - DataModel.StartTime.Ticks;
                    if (DataModel.CurrentBuilds.Count > 0)
                    {
                        if (t > maxTick)
                        {
                            maxTick = t;
                        }
                    }
                    int    ii;
                    bool   atLeastOneError   = false;
                    uint   maxBuildOrderNbr  = 1;
                    double projectNameMaxLen = 10;
                    for (ii = 0; ii < DataModel.FinishedBuilds.Count; ii++)
                    {
                        FormattedText iname = new FormattedText(DataModel.FinishedBuilds[ii].ProjectName, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
                        double        ll    = iname.Width;
                        t = DataModel.FinishedBuilds[ii].end;
                        atLeastOneError = atLeastOneError || !DataModel.FinishedBuilds[ii].success;
                        if (t > maxTick)
                        {
                            maxTick = t;
                        }

                        if (ll > projectNameMaxLen)
                        {
                            projectNameMaxLen = ll;
                        }

                        if (DataModel.FinishedBuilds[ii].ProjectBuildOrderNumber > maxBuildOrderNbr)
                        {
                            maxBuildOrderNbr = DataModel.FinishedBuilds[ii].ProjectBuildOrderNumber;
                        }
                    }
                    foreach (KeyValuePair <string, Tuple <uint, long> > item in DataModel.CurrentBuilds)
                    {
                        FormattedText iname = new FormattedText(DataModel.GetHumanReadableProjectName(item.Key), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
                        double        ll    = iname.Width;
                        if (ll > projectNameMaxLen)
                        {
                            projectNameMaxLen = ll;
                        }

                        if (item.Value.Item1 > maxBuildOrderNbr)
                        {
                            maxBuildOrderNbr = item.Value.Item1;
                        }
                    }
                    if (isBuilding)
                    {
                        maxTick = (maxTick / tickStep + 1) * tickStep;
                    }

                    Spacings spacings = new Spacings();
                    { //setting spacings
                        string pattern = "> ";
                        int    len     = maxBuildOrderNbr.ToString().Length + pattern.Length;
                        pattern = pattern.PadLeft(len, '8'); // let's assume that 8 is the widest char
                        FormattedText bn = new FormattedText(pattern, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);

                        spacings.lProjName = Spacings.lOrder + bn.Width + 3;                            // let's add 3 pix just in case 8 is not the widest
                        spacings.lGanttC   = spacings.lProjName + projectNameMaxLen + penThickness + 3; // let's add 3 pix just in case
                    }

                    int rowNbr = 0;                            //first row has number 0
                    {                                          // Draw header
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        string headerText = DataModel.GetSolutionNameWithMachineInfo("  |  ", false /*WithBuildStartedStr*/);
                        // Draw text
                        FormattedText itext = new FormattedText(headerText, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
                        {
                            // Cut text when it is too long for window. Probably correct solution is to add horizontal scrollbar to window.
                            // Set a maximum width and height. If the text overflows these values, an ellipsis "..." appears.
                            itext.MaxTextWidth  = RenderSize.Width - Spacings.lOrder - Spacings.rGanttC;
                            itext.MaxTextHeight = rowHeight;
                        }
                        drawingContext.DrawText(itext, new Point(Spacings.lOrder, rowNbr * rowHeight));

                        rowNbr++;
                    }

                    foreach (BuildInfo item in DataModel.FinishedBuilds)
                    {
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        DrawOrderAndProjectNameText(drawingContext, rowNbr, item.ProjectBuildOrderNumber, item.ProjectName, spacings, (item.success ? greenSolidBrush : redSolidBrush));
                        DrawBar(drawingContext, rowNbr, item.begin, item.end, maxTick, spacings, (item.success ? greenGradientBrush : redGradientBrush), DataModel.CriticalPath.Contains(item));

                        rowNbr++;
                    }

                    foreach (KeyValuePair <string, Tuple <uint, long> > item in DataModel.CurrentBuilds)
                    {
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        DrawOrderAndProjectNameText(drawingContext, rowNbr, item.Value.Item1, DataModel.GetHumanReadableProjectName(item.Key), spacings, blueSolidBrush);
                        DrawBar(drawingContext, rowNbr, item.Value.Item2, (nowTick - DataModel.StartTime.Ticks), maxTick, spacings, blueGradientBrush, false /*markAsCriticalPath*/);

                        rowNbr++;
                    }

                    DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                    DrawGraph("CPU usage", drawingContext, DataModel.CpuUsage, cpuPen, cpuSoftPen, rowNbr, RenderSize, rowHeight, spacings, maxTick, nowTick, fontFace);
                    rowNbr++;

                    DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                    DrawGraph("HDD usage", drawingContext, DataModel.HddUsage, hddPen, hddSoftPen, rowNbr, RenderSize, rowHeight, spacings, maxTick, nowTick, fontFace);
                    rowNbr++;

                    if (DataModel.CurrentBuilds.Count > 0 || DataModel.FinishedBuilds.Count > 0)
                    {
                        string status = (isBuilding ? "Building..." : "Done");
                        if (DataModel.MaxParallelBuilds > 0)
                        {
                            status += " (" + DataModel.PercentageProcessorUse().ToString() + "% of " + DataModel.MaxParallelBuilds.ToString() + " CPUs)";
                        }

                        DrawText(drawingContext, status, rowNbr, Spacings.lOrder, blackBrush);
                    }

                    DrawVerticalSeparator(drawingContext, spacings.lGanttC - penThickness, rowNbr, false /*wholeSize*/);

                    drawingContext.DrawLine(new Pen(atLeastOneError ? redSolidBrush : greenSolidBrush, 1), new Point(0, rowNbr * rowHeight), new Point(RenderSize.Width, rowNbr * rowHeight));

                    DateTime      dt      = new DateTime(maxTick);
                    string        s       = Utils.SecondsToString(dt.Ticks);
                    FormattedText maxTime = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush);
                    double        m       = maxTime.Width;
                    drawingContext.DrawText(maxTime, new Point(RenderSize.Width - m - Spacings.rGanttC, rowNbr * rowHeight));

                    {                                                                                                       // Draw frame around - it looks better in window and definitelly in saved .png. Draw frame as last to be clearly visible
                        DrawSeparator(drawingContext, -1);                                                                  // Top
                        DrawSeparator(drawingContext, rowNbr);                                                              // Bottom
                        DrawVerticalSeparator(drawingContext, 0, rowNbr, true /*wholeSize*/);                               // Left
                        DrawVerticalSeparator(drawingContext, RenderSize.Width - penThickness, rowNbr, true /*wholeSize*/); // Right
                    }

                    isGraphDrawnScope.IsDrawn = true;
                } //End of IsGraphDrawnScope
            }
            catch (Exception)
            {   // Keep this try{} catch{}!
                // Actually code in try{} bail from time to time on windows resize.
                // I guess because there is division by (x - y), while x equals y, but it might be not the only case.
                Debug.Assert(false, "Gantt chart not refreshed! Exception thrown while drawing Gantt chart.");
            }
        }
Beispiel #2
0
        protected override void OnRender(DrawingContext drawingContext)
        {
            try
            {
                using (IsGraphDrawnScope isGraphDrawnScope = new IsGraphDrawnScope())
                {
                    if (RenderSize.Width < 10.0 || RenderSize.Height < 10.0)
                    {
                        return;
                    }

                    if (IsEmptyBuilds())
                    { // Case when no single build was started yet  -  display some info to ensure user that everything is OK
                        FormattedText captionFT = new FormattedText(emptyGanttMsg, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                        drawingContext.DrawText(captionFT, new Point(50.0, rowNbrNoProjectsFiller / 2 * rowHeight));

                        return;
                    }

                    int    linesCount  = DataModel.CurrentBuilds.Count + DataModel.FinishedBuilds.Count + 1 + 1 + 1 + 1; // 1 for header, 1 for status, 1 for CPU, 1 for HDD
                    double totalHeight = rowHeight * linesCount;

                    Height = totalHeight + penThickness;

                    long tickStep = 100000000;
                    long maxTick  = tickStep;
                    long nowTick  = ((nowTickForTest > 0) ? nowTickForTest : DateTime.Now.Ticks);
                    long t        = nowTick - DataModel.StartTime.Ticks;
                    if (DataModel.CurrentBuilds.Count > 0)
                    {
                        if (t > maxTick)
                        {
                            maxTick = t;
                        }
                    }
                    int    ii;
                    bool   atLeastOneError   = false;
                    uint   maxBuildOrderNbr  = 1;
                    double projectNameMaxLen = 10;
                    for (ii = 0; ii < DataModel.FinishedBuilds.Count; ii++)
                    {
                        FormattedText iname = new FormattedText(DataModel.FinishedBuilds[ii].ProjectName, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                        double        ll    = iname.Width;
                        t = DataModel.FinishedBuilds[ii].end;
                        atLeastOneError = atLeastOneError || !DataModel.FinishedBuilds[ii].success;
                        if (t > maxTick)
                        {
                            maxTick = t;
                        }

                        if (ll > projectNameMaxLen)
                        {
                            projectNameMaxLen = ll;
                        }

                        if (DataModel.FinishedBuilds[ii].ProjectBuildOrderNumber > maxBuildOrderNbr)
                        {
                            maxBuildOrderNbr = DataModel.FinishedBuilds[ii].ProjectBuildOrderNumber;
                        }
                    }
                    foreach (KeyValuePair <string, Tuple <uint, long> > item in DataModel.CurrentBuilds)
                    {
                        FormattedText iname = new FormattedText(DataModel.GetHumanReadableProjectName(item.Key), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                        double        ll    = iname.Width;
                        if (ll > projectNameMaxLen)
                        {
                            projectNameMaxLen = ll;
                        }

                        if (item.Value.Item1 > maxBuildOrderNbr)
                        {
                            maxBuildOrderNbr = item.Value.Item1;
                        }
                    }
                    if (DataModel.IsBuilding)
                    {
                        maxTick = (maxTick / tickStep + 1) * tickStep;
                    }

                    Spacings spacings = new Spacings();
                    { //setting spacings
                        string pattern = "> ";
                        int    len     = maxBuildOrderNbr.ToString().Length + pattern.Length;
                        pattern = pattern.PadLeft(len, '8'); // let's assume that 8 is the widest char
                        FormattedText bn = new FormattedText(pattern, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);

                        spacings.lProjName = Spacings.lOrder + bn.Width + 3;                            // let's add 3 pix just in case 8 is not the widest
                        spacings.lGanttC   = spacings.lProjName + projectNameMaxLen + penThickness + 3; // let's add 3 pix just in case
                    }

                    // check if usage text is longer than the longest project name, and yes, values greater than 1000% are possible
                    double usageTextLen = new FormattedText("HDD Usage (Avg. 1000%)", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip).Width;
                    spacings.lGanttC = Math.Max(spacings.lGanttC, Spacings.lOrder + usageTextLen + penThickness);

                    int rowNbr = 0;                            //first row has number 0

                    {                                          // Draw header
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        DrawMachineInfo(drawingContext, rowNbr);

                        rowNbr++;
                    }

                    foreach (BuildInfo item in DataModel.FinishedBuilds)
                    {
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        DrawOrderAndProjectNameText(drawingContext, rowNbr, item.ProjectBuildOrderNumber, item.ProjectName, spacings, (item.success ? greenSolidBrush : redSolidBrush));
                        DrawBar(drawingContext, rowNbr, item.begin, item.end, maxTick, spacings, (item.success ? greenGradientBrush : redGradientBrush), DataModel.CriticalPath.Contains(item));

                        rowNbr++;
                    }

                    foreach (KeyValuePair <string, Tuple <uint, long> > item in DataModel.CurrentBuilds)
                    {
                        DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                        DrawOrderAndProjectNameText(drawingContext, rowNbr, item.Value.Item1, DataModel.GetHumanReadableProjectName(item.Key), spacings, blueSolidBrush);
                        DrawBar(drawingContext, rowNbr, item.Value.Item2, (nowTick - DataModel.StartTime.Ticks), maxTick, spacings, blueGradientBrush, false /*markAsCriticalPath*/);

                        rowNbr++;
                    }

                    DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                    DrawGraph("CPU usage", drawingContext, DataModel.CpuUsage, cpuPen, cpuSoftPen, rowNbr, RenderSize, rowHeight, spacings, maxTick, nowTick, fontFace);
                    rowNbr++;

                    DrawSeparator(drawingContext, rowNbr); // draw backgroud things first due to anty-aliasing
                    DrawGraph("HDD usage", drawingContext, DataModel.HddUsage, hddPen, hddSoftPen, rowNbr, RenderSize, rowHeight, spacings, maxTick, nowTick, fontFace);
                    rowNbr++;

                    if (DataModel.CurrentBuilds.Count > 0 || DataModel.FinishedBuilds.Count > 0)
                    {
                        string status = (DataModel.IsBuilding ? "Building..." : "Done.");
                        if (DataModel.MaxParallelBuilds > 0)
                        {
                            status += " Max. no. of parallel projects: " + DataModel.MaxParallelBuilds.ToString() + " (Avg. " +
                                      Math.Round(DataModel.MaxParallelBuilds / 100.0 * DataModel.PercentageProcessorUse(), 1).ToString(format: "0.0") + ")";
                        }

                        DrawText(drawingContext, status, rowNbr, Spacings.lOrder, blackBrush);
                    }

                    DrawVerticalSeparator(drawingContext, spacings.lGanttC - penThickness, rowNbr, false /*wholeSize*/);

                    drawingContext.DrawLine(new Pen(atLeastOneError ? redSolidBrush : greenSolidBrush, 1), new Point(0, rowNbr * rowHeight), new Point(RenderSize.Width, rowNbr * rowHeight));

                    DateTime      dt      = new DateTime(maxTick);
                    string        s       = Utils.SecondsToString(dt.Ticks);
                    FormattedText maxTime = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, fontFace, FontSize, blackBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                    double        m       = maxTime.Width;
                    drawingContext.DrawText(maxTime, new Point(RenderSize.Width - m - Spacings.rGanttC, rowNbr * rowHeight));

                    {                                                                                                       // Draw frame around - it looks better in window and definitelly in saved .png. Draw frame as last to be clearly visible
                        DrawSeparator(drawingContext, -1);                                                                  // Top
                        DrawSeparator(drawingContext, rowNbr);                                                              // Bottom
                        DrawVerticalSeparator(drawingContext, 0, rowNbr, true /*wholeSize*/);                               // Left
                        DrawVerticalSeparator(drawingContext, RenderSize.Width - penThickness, rowNbr, true /*wholeSize*/); // Right
                    }

                    isGraphDrawnScope.IsDrawn = true;
                } //End of IsGraphDrawnScope
            }
            catch (Exception)
            {
                Debug.Assert(false, "Gantt chart not refreshed! Exception thrown while drawing Gantt chart.");
            }
        }