//*************************************************************************
        //  Method: AddRow()
        //
        /// <summary>
        /// Adds a row with comments and a style to the overall metrics table.
        /// </summary>
        ///
        /// <param name="sMetricName">
        /// Name of the metric.  Can be empty but not null.
        /// </param>
        ///
        /// <param name="sMetricValue">
        /// Value of the metric.  Can be empty but not null.
        /// </param>
        ///
        /// <param name="sMetricComments">
        /// Comments for the metric.  Can be empty but not null.
        /// </param>
        ///
        /// <param name="sStyle">
        /// Style of the row, or null to not apply a style.
        /// </param>
        ///
        /// <param name="oOverallMetricRows">
        /// Contains the row data for the overall metrics table.
        /// </param>
        //*************************************************************************
        protected void AddRow(
            String sMetricName,
            String sMetricValue,
            String sMetricComments,
            String sStyle,
            OverallMetricRows oOverallMetricRows
            )
        {
            Debug.Assert(sMetricName != null);
            Debug.Assert(sMetricValue != null);
            Debug.Assert(sMetricComments != null);
            Debug.Assert(oOverallMetricRows != null);
            AssertValid();

            oOverallMetricRows.MetricNames.Add( new GraphMetricValueOrdered(
            sMetricName, sStyle) );

            oOverallMetricRows.MetricValues.Add( new GraphMetricValueOrdered(
            sMetricValue, sStyle) );

            oOverallMetricRows.MetricComments.Add( new GraphMetricValueOrdered(
            sMetricComments, sStyle) );
        }
        TryCalculateGraphMetrics
        (
            IGraph graph,
            CalculateGraphMetricsContext calculateGraphMetricsContext,
            out GraphMetricColumn [] graphMetricColumns
        )
        {
            Debug.Assert(graph != null);
            Debug.Assert(calculateGraphMetricsContext != null);
            AssertValid();

            // Note regarding cell styles:
            //
            // Versions of NodeXL earlier than 1.0.1.130 didn't merge duplicate
            // edges before calculating graph metrics, and as a result some metrics
            // were invalid.  That was indicated by applying the CellStyleNames.Bad
            // Excel style to the invalid cells.  Starting in version 1.0.1.130
            // there are no longer invalid metrics, but the
            // CellStyleNames.GraphMetricGood style is always applied to those old
            // potentially bad metric cells (instead of null, which uses the
            // current cell style) in case graph metrics are calculated on an old
            // workbook that had bad metric cells.  If null were used, the old Bad
            // style would always remain on the previously bad cells, even if they
            // are now filled with good metric values.

            graphMetricColumns = new GraphMetricColumn[0];

            if (!calculateGraphMetricsContext.ShouldCalculateGraphMetrics(
                    GraphMetrics.OverallMetrics))
            {
                return(true);
            }

            // Calculate the overall metrics using the OverallMetricCalculator
            // class in the Algorithms namespace, which knows nothing about Excel.

            OverallMetrics oOverallMetrics;

            if (!(new Algorithms.OverallMetricCalculator()).
                TryCalculateGraphMetrics(graph,
                                         calculateGraphMetricsContext.BackgroundWorker,
                                         out oOverallMetrics))
            {
                // The user cancelled.

                return(false);
            }

            OverallMetricRows oOverallMetricRows = new OverallMetricRows();


            //*********************************
            // Graph type
            //*********************************

            AddRow(OverallMetricNames.Directedness,
                   oOverallMetrics.Directedness.ToString(), oOverallMetricRows);


            //*********************************
            // Vertex count
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.Vertices, oOverallMetrics.Vertices,
                   oOverallMetricRows);


            //*********************************
            // Edge counts
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.UniqueEdges, oOverallMetrics.UniqueEdges,
                   oOverallMetricRows);

            AddRow(OverallMetricNames.EdgesWithDuplicates,
                   oOverallMetrics.EdgesWithDuplicates, oOverallMetricRows);

            AddRow(OverallMetricNames.TotalEdges, oOverallMetrics.TotalEdges,
                   oOverallMetricRows);


            //*********************************
            // Self-loops
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.SelfLoops, oOverallMetrics.SelfLoops,
                   oOverallMetricRows);


            //*********************************
            // Reciprocation ratios
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.ReciprocatedVertexPairRatio,

                   NullableToGraphMetricValue <Double>(
                       oOverallMetrics.ReciprocatedVertexPairRatio),

                   oOverallMetricRows);

            AddRow(OverallMetricNames.ReciprocatedEdgeRatio,

                   NullableToGraphMetricValue <Double>(
                       oOverallMetrics.ReciprocatedEdgeRatio),

                   oOverallMetricRows);


            //*********************************
            // Connected component counts
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.ConnectedComponents,
                   oOverallMetrics.ConnectedComponents, oOverallMetricRows);

            AddRow(OverallMetricNames.SingleVertexConnectedComponents,
                   oOverallMetrics.SingleVertexConnectedComponents,
                   oOverallMetricRows);

            AddRow(OverallMetricNames.MaximumConnectedComponentVertices,
                   oOverallMetrics.MaximumConnectedComponentVertices,
                   oOverallMetricRows);

            AddRow(OverallMetricNames.MaximumConnectedComponentEdges,
                   oOverallMetrics.MaximumConnectedComponentEdges,
                   oOverallMetricRows);


            //*********************************
            // Geodesic distances
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.MaximumGeodesicDistance,

                   NullableToGraphMetricValue <Int32>(
                       oOverallMetrics.MaximumGeodesicDistance),

                   oOverallMetricRows);

            AddRow(OverallMetricNames.AverageGeodesicDistance,

                   NullableToGraphMetricValue <Double>(
                       oOverallMetrics.AverageGeodesicDistance),

                   oOverallMetricRows);


            //*********************************
            // Graph density
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.GraphDensity,
                   NullableToGraphMetricValue <Double>(oOverallMetrics.GraphDensity),
                   oOverallMetricRows);

            AddRow(OverallMetricNames.Modularity,
                   NullableToGraphMetricValue <Double>(oOverallMetrics.Modularity),
                   oOverallMetricRows);


            //*********************************
            // NodeXL version
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow(OverallMetricNames.NodeXLVersion,
                   AssemblyUtil2.GetFileVersion(), oOverallMetricRows);


            graphMetricColumns = new GraphMetricColumn[] {
                CreateGraphMetricColumnOrdered(
                    OverallMetricsTableColumnNames.Name,
                    oOverallMetricRows.MetricNames),

                CreateGraphMetricColumnOrdered(
                    OverallMetricsTableColumnNames.Value,
                    oOverallMetricRows.MetricValues),
            };

            return(true);
        }
        //*************************************************************************
        //  Method: AddRow()
        //
        /// <overloads>
        /// Adds a row to the overall metrics table.
        /// </overloads>
        ///
        /// <summary>
        /// Adds an empty row to the overall metrics table.
        /// </summary>
        ///
        /// <param name="oOverallMetricRows">
        /// Contains the row data for the overall metrics table.
        /// </param>
        //*************************************************************************
        protected void AddRow(
            OverallMetricRows oOverallMetricRows
            )
        {
            Debug.Assert(oOverallMetricRows != null);
            AssertValid();

            AddRow(String.Empty, String.Empty, String.Empty,
            CellStyleNames.GraphMetricSeparatorRow, oOverallMetricRows);
        }
        //*************************************************************************
        //  Method: AddRow()
        //
        /// <summary>
        /// Adds a row to the overall metrics table.
        /// </summary>
        ///
        /// <param name="sMetricName">
        /// Name of the metric.  Can be empty but not null.
        /// </param>
        ///
        /// <param name="sMetricValue">
        /// Value of the metric.  Can be empty but not null.
        /// </param>
        ///
        /// <param name="oOverallMetricRows">
        /// Contains the row data for the overall metrics table.
        /// </param>
        //*************************************************************************
        protected void AddRow(
            String sMetricName,
            String sMetricValue,
            OverallMetricRows oOverallMetricRows
            )
        {
            Debug.Assert(sMetricName != null);
            Debug.Assert(sMetricValue != null);
            Debug.Assert(oOverallMetricRows != null);
            AssertValid();

            AddRow(sMetricName, sMetricValue, String.Empty, null,
            oOverallMetricRows);
        }
        //*************************************************************************
        //  Method: TryCalculateGraphMetrics()
        //
        /// <summary>
        /// Attempts to calculate a set of one or more related metrics.
        /// </summary>
        ///
        /// <param name="graph">
        /// The graph to calculate metrics for.  The graph may contain duplicate
        /// edges and self-loops.
        /// </param>
        ///
        /// <param name="calculateGraphMetricsContext">
        /// Provides access to objects needed for calculating graph metrics.
        /// </param>
        ///
        /// <param name="graphMetricColumns">
        /// Where an array of GraphMetricColumn objects gets stored if true is
        /// returned, one for each related metric calculated by this method.
        /// </param>
        ///
        /// <returns>
        /// true if the graph metrics were calculated, false if the user wants to
        /// cancel.
        /// </returns>
        ///
        /// <remarks>
        /// This method periodically checks BackgroundWorker.<see
        /// cref="BackgroundWorker.CancellationPending" />.  If true, the method
        /// immediately returns false.
        ///
        /// <para>
        /// It also periodically reports progress by calling the
        /// BackgroundWorker.<see
        /// cref="BackgroundWorker.ReportProgress(Int32, Object)" /> method.  The
        /// userState argument is a <see cref="GraphMetricProgress" /> object.
        /// </para>
        ///
        /// <para>
        /// Calculated metrics for hidden rows are ignored by the caller, because
        /// Excel misbehaves when values are written to hidden cells.
        /// </para>
        ///
        /// </remarks>
        //*************************************************************************
        public override Boolean TryCalculateGraphMetrics(
            IGraph graph,
            CalculateGraphMetricsContext calculateGraphMetricsContext,
            out GraphMetricColumn [] graphMetricColumns
            )
        {
            Debug.Assert(graph != null);
            Debug.Assert(calculateGraphMetricsContext != null);
            AssertValid();

            graphMetricColumns = new GraphMetricColumn[0];

            if ( !calculateGraphMetricsContext.GraphMetricUserSettings.
            CalculateGraphMetrics(GraphMetrics.OverallMetrics) )
            {
            return (true);
            }

            // Calculate the overall metrics using the OverallMetricCalculator
            // class in the Algorithms namespace, which knows nothing about Excel.

            OverallMetrics oOverallMetrics;

            if ( !( new Algorithms.OverallMetricCalculator() ).
            TryCalculateGraphMetrics(graph,
                calculateGraphMetricsContext.BackgroundWorker,
                out oOverallMetrics) )
            {
            // The user cancelled.

            return (false);
            }

            OverallMetricRows oOverallMetricRows = new OverallMetricRows();

            //*********************************
            // Graph type
            //*********************************

            AddRow("Graph Type", oOverallMetrics.Directedness.ToString(),
            oOverallMetricRows);

            //*********************************
            // Vertex count
            //*********************************

            AddRow(oOverallMetricRows);
            AddRow("Vertices", oOverallMetrics.Vertices, oOverallMetricRows);

            //*********************************
            // Edge counts
            //*********************************

            String sDuplicateEdgeStyle = CellStyleNames.GraphMetricGood;
            String sDuplicateEdgeComments = String.Empty;
            String sGraphDensityComments = String.Empty;

            if (oOverallMetrics.EdgesWithDuplicates > 0)
            {
            // The graph density is rendered invalid when the graph has
            // duplicate edges.

            sDuplicateEdgeStyle = CellStyleNames.GraphMetricBad;

            sDuplicateEdgeComments =
                "You can merge duplicate edges using NodeXL, Data, Prepare"
                + " Data, Merge Duplicate Edges."
                ;

            sGraphDensityComments =
                "The workbook contains duplicate edges that have caused the"
                + " graph density to be inaccurate.  "
                + sDuplicateEdgeComments
                ;
            }

            AddRow(oOverallMetricRows);
            AddRow("Unique Edges", oOverallMetrics.UniqueEdges, oOverallMetricRows);

            AddRow("Edges With Duplicates",
            FormatInt32(oOverallMetrics.EdgesWithDuplicates),
            sDuplicateEdgeComments, sDuplicateEdgeStyle,
            oOverallMetricRows);

            AddRow("Total Edges", oOverallMetrics.TotalEdges, oOverallMetricRows);

            //*********************************
            // Self-loops
            //*********************************

            AddRow(oOverallMetricRows);
            AddRow("Self-Loops", oOverallMetrics.SelfLoops, oOverallMetricRows);

            //*********************************
            // Connected component counts
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow("Connected Components", oOverallMetrics.ConnectedComponents,
            oOverallMetricRows);

            AddRow("Single-Vertex Connected Components",
            oOverallMetrics.SingleVertexConnectedComponents,
            oOverallMetricRows);

            AddRow("Maximum Vertices in a Connected Component",
            oOverallMetrics.MaximumConnectedComponentVertices,
            oOverallMetricRows);

            AddRow("Maximum Edges in a Connected Component",
            oOverallMetrics.MaximumConnectedComponentEdges,
            oOverallMetricRows);

            //*********************************
            // Geodesic distances
            //*********************************

            String sMaximumGeodesicDistance, sAverageGeodesicDistance;

            GetGeodesicDistanceStrings(oOverallMetrics,
            out sMaximumGeodesicDistance, out sAverageGeodesicDistance);

            AddRow(oOverallMetricRows);

            AddRow("Maximum Geodesic Distance (Diameter)",
            sMaximumGeodesicDistance, oOverallMetricRows);

            AddRow("Average Geodesic Distance", sAverageGeodesicDistance,
            oOverallMetricRows);

            //*********************************
            // Graph density
            //*********************************

            Nullable<Double> dGraphDensity = oOverallMetrics.GraphDensity;

            AddRow(oOverallMetricRows);

            AddRow("Graph Density", dGraphDensity.HasValue ?
            FormatDouble(dGraphDensity.Value) : NotApplicableMessage,
            sGraphDensityComments, sDuplicateEdgeStyle, oOverallMetricRows);

            //*********************************
            // NodeXL version
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow("NodeXL Version", AssemblyUtil2.GetFileVersion(),
            oOverallMetricRows);

            graphMetricColumns = new GraphMetricColumn[] {

            CreateGraphMetricColumnOrdered(
                OverallMetricsTableColumnNames.Name,
                oOverallMetricRows.MetricNames),

            CreateGraphMetricColumnOrdered(
                OverallMetricsTableColumnNames.Value,
                oOverallMetricRows.MetricValues),

            CreateGraphMetricColumnOrdered(
                OverallMetricsTableColumnNames.Comments,
                oOverallMetricRows.MetricComments),
            };

            return (true);
        }
        TryCalculateGraphMetrics
        (
            IGraph graph,
            CalculateGraphMetricsContext calculateGraphMetricsContext,
            out GraphMetricColumn [] graphMetricColumns
        )
        {
            Debug.Assert(graph != null);
            Debug.Assert(calculateGraphMetricsContext != null);
            AssertValid();

            graphMetricColumns = new GraphMetricColumn[0];

            if (!calculateGraphMetricsContext.GraphMetricUserSettings.
                CalculateGraphMetrics(GraphMetrics.OverallMetrics))
            {
                return(true);
            }

            // Calculate the overall metrics using the OverallMetricCalculator
            // class in the Algorithms namespace, which knows nothing about Excel.

            OverallMetrics oOverallMetrics;

            if (!(new Algorithms.OverallMetricCalculator()).
                TryCalculateGraphMetrics(graph,
                                         calculateGraphMetricsContext.BackgroundWorker,
                                         out oOverallMetrics))
            {
                // The user cancelled.

                return(false);
            }

            OverallMetricRows oOverallMetricRows = new OverallMetricRows();


            //*********************************
            // Graph type
            //*********************************

            AddRow("Graph Type", oOverallMetrics.Directedness.ToString(),
                   oOverallMetricRows);


            //*********************************
            // Vertex count
            //*********************************

            AddRow(oOverallMetricRows);
            AddRow("Vertices", oOverallMetrics.Vertices, oOverallMetricRows);


            //*********************************
            // Edge counts
            //*********************************

            String sDuplicateEdgeStyle    = CellStyleNames.GraphMetricGood;
            String sDuplicateEdgeComments = String.Empty;
            String sGraphDensityComments  = String.Empty;

            if (oOverallMetrics.EdgesWithDuplicates > 0)
            {
                // The graph density is rendered invalid when the graph has
                // duplicate edges.

                sDuplicateEdgeStyle = CellStyleNames.GraphMetricBad;

                sDuplicateEdgeComments =
                    "You can merge duplicate edges using NodeXL, Data, Prepare"
                    + " Data, Merge Duplicate Edges."
                ;

                sGraphDensityComments =
                    "The workbook contains duplicate edges that have caused the"
                    + " graph density to be inaccurate.  "
                    + sDuplicateEdgeComments
                ;
            }

            AddRow(oOverallMetricRows);
            AddRow("Unique Edges", oOverallMetrics.UniqueEdges, oOverallMetricRows);

            AddRow("Edges With Duplicates",
                   FormatInt32(oOverallMetrics.EdgesWithDuplicates),
                   sDuplicateEdgeComments, sDuplicateEdgeStyle,
                   oOverallMetricRows);

            AddRow("Total Edges", oOverallMetrics.TotalEdges, oOverallMetricRows);


            //*********************************
            // Self-loops
            //*********************************

            AddRow(oOverallMetricRows);
            AddRow("Self-Loops", oOverallMetrics.SelfLoops, oOverallMetricRows);


            //*********************************
            // Connected component counts
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow("Connected Components", oOverallMetrics.ConnectedComponents,
                   oOverallMetricRows);

            AddRow("Single-Vertex Connected Components",
                   oOverallMetrics.SingleVertexConnectedComponents,
                   oOverallMetricRows);

            AddRow("Maximum Vertices in a Connected Component",
                   oOverallMetrics.MaximumConnectedComponentVertices,
                   oOverallMetricRows);

            AddRow("Maximum Edges in a Connected Component",
                   oOverallMetrics.MaximumConnectedComponentEdges,
                   oOverallMetricRows);


            //*********************************
            // Geodesic distances
            //*********************************

            String sMaximumGeodesicDistance, sAverageGeodesicDistance;

            GetGeodesicDistanceStrings(oOverallMetrics,
                                       out sMaximumGeodesicDistance, out sAverageGeodesicDistance);

            AddRow(oOverallMetricRows);

            AddRow("Maximum Geodesic Distance (Diameter)",
                   sMaximumGeodesicDistance, oOverallMetricRows);

            AddRow("Average Geodesic Distance", sAverageGeodesicDistance,
                   oOverallMetricRows);


            //*********************************
            // Graph density
            //*********************************

            Nullable <Double> dGraphDensity = oOverallMetrics.GraphDensity;

            AddRow(oOverallMetricRows);

            AddRow("Graph Density", dGraphDensity.HasValue ?
                   FormatDouble(dGraphDensity.Value) : NotApplicableMessage,
                   sGraphDensityComments, sDuplicateEdgeStyle, oOverallMetricRows);


            //*********************************
            // NodeXL version
            //*********************************

            AddRow(oOverallMetricRows);

            AddRow("NodeXL Version", AssemblyUtil2.GetFileVersion(),
                   oOverallMetricRows);


            graphMetricColumns = new GraphMetricColumn[] {
                CreateGraphMetricColumnOrdered(
                    OverallMetricsTableColumnNames.Name,
                    oOverallMetricRows.MetricNames),

                CreateGraphMetricColumnOrdered(
                    OverallMetricsTableColumnNames.Value,
                    oOverallMetricRows.MetricValues),

                CreateGraphMetricColumnOrdered(
                    OverallMetricsTableColumnNames.Comments,
                    oOverallMetricRows.MetricComments),
            };

            return(true);
        }
    TryCalculateGraphMetrics
    (
        IGraph graph,
        CalculateGraphMetricsContext calculateGraphMetricsContext,
        out GraphMetricColumn [] graphMetricColumns
    )
    {
        Debug.Assert(graph != null);
        Debug.Assert(calculateGraphMetricsContext != null);
        AssertValid();

        // Note regarding cell styles:
        //
        // Versions of NodeXL earlier than 1.0.1.130 didn't merge duplicate
        // edges before calculating graph metrics, and as a result some metrics
        // were invalid.  That was indicated by applying the CellStyleNames.Bad
        // Excel style to the invalid cells.  Starting in version 1.0.1.130
        // there are no longer invalid metrics, but the
        // CellStyleNames.GraphMetricGood style is always applied to those old
        // potentially bad metric cells (instead of null, which uses the
        // current cell style) in case graph metrics are calculated on an old
        // workbook that had bad metric cells.  If null were used, the old Bad
        // style would always remain on the previously bad cells, even if they
        // are now filled with good metric values.

        graphMetricColumns = new GraphMetricColumn[0];

        if ( !calculateGraphMetricsContext.ShouldCalculateGraphMetrics(
            GraphMetrics.OverallMetrics) )
        {
            return (true);
        }

        // Calculate the overall metrics using the OverallMetricCalculator
        // class in the Algorithms namespace, which knows nothing about Excel.

        OverallMetrics oOverallMetrics;

        if ( !( new Algorithms.OverallMetricCalculator() ).
            TryCalculateGraphMetrics(graph,
                calculateGraphMetricsContext.BackgroundWorker,
                out oOverallMetrics) )
        {
            // The user cancelled.

            return (false);
        }

        OverallMetricRows oOverallMetricRows = new OverallMetricRows();


        //*********************************
        // Graph type
        //*********************************

        AddRow(OverallMetricNames.Directedness,
            oOverallMetrics.Directedness.ToString(), oOverallMetricRows);


        //*********************************
        // Vertex count
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.Vertices, oOverallMetrics.Vertices,
            oOverallMetricRows);


        //*********************************
        // Edge counts
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.UniqueEdges, oOverallMetrics.UniqueEdges,
            oOverallMetricRows);

        AddRow(OverallMetricNames.EdgesWithDuplicates,
            oOverallMetrics.EdgesWithDuplicates, oOverallMetricRows);

        AddRow(OverallMetricNames.TotalEdges, oOverallMetrics.TotalEdges,
            oOverallMetricRows);


        //*********************************
        // Self-loops
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.SelfLoops, oOverallMetrics.SelfLoops,
            oOverallMetricRows);


        //*********************************
        // Reciprocation ratios
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.ReciprocatedVertexPairRatio,

            NullableToGraphMetricValue<Double>(
                oOverallMetrics.ReciprocatedVertexPairRatio),

            oOverallMetricRows);

        AddRow(OverallMetricNames.ReciprocatedEdgeRatio,

            NullableToGraphMetricValue<Double>(
                oOverallMetrics.ReciprocatedEdgeRatio),

            oOverallMetricRows);


        //*********************************
        // Connected component counts
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.ConnectedComponents,
            oOverallMetrics.ConnectedComponents, oOverallMetricRows);

        AddRow(OverallMetricNames.SingleVertexConnectedComponents,
            oOverallMetrics.SingleVertexConnectedComponents,
            oOverallMetricRows);

        AddRow(OverallMetricNames.MaximumConnectedComponentVertices,
            oOverallMetrics.MaximumConnectedComponentVertices,
            oOverallMetricRows);

        AddRow(OverallMetricNames.MaximumConnectedComponentEdges,
            oOverallMetrics.MaximumConnectedComponentEdges,
            oOverallMetricRows);


        //*********************************
        // Geodesic distances
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.MaximumGeodesicDistance,

            NullableToGraphMetricValue<Int32>(
                oOverallMetrics.MaximumGeodesicDistance),

            oOverallMetricRows);

        AddRow(OverallMetricNames.AverageGeodesicDistance,

            NullableToGraphMetricValue<Double>(
                oOverallMetrics.AverageGeodesicDistance),

            oOverallMetricRows);


        //*********************************
        // Graph density
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.GraphDensity,
            NullableToGraphMetricValue<Double>(oOverallMetrics.GraphDensity),
            oOverallMetricRows);

        AddRow(OverallMetricNames.Modularity,
            NullableToGraphMetricValue<Double>(oOverallMetrics.Modularity),
            oOverallMetricRows);


        //*********************************
        // NodeXL version
        //*********************************

        AddRow(oOverallMetricRows);

        AddRow(OverallMetricNames.NodeXLVersion,
            AssemblyUtil2.GetFileVersion(), oOverallMetricRows);


        graphMetricColumns = new GraphMetricColumn[] {

            CreateGraphMetricColumnOrdered(
                OverallMetricsTableColumnNames.Name,
                oOverallMetricRows.MetricNames),

            CreateGraphMetricColumnOrdered(
                OverallMetricsTableColumnNames.Value,
                oOverallMetricRows.MetricValues),
            };

        return (true);
    }
    AddRow
    (
        String sMetricName,
        Object oMetricValue,
        String sStyle,
        OverallMetricRows oOverallMetricRows
    )
    {
        Debug.Assert(sMetricName != null);
        Debug.Assert(oMetricValue != null);
        Debug.Assert(oOverallMetricRows != null);
        AssertValid();

        oOverallMetricRows.MetricNames.Add( new GraphMetricValueOrdered(
            sMetricName, sStyle) );

        oOverallMetricRows.MetricValues.Add( new GraphMetricValueOrdered(
            oMetricValue, sStyle) );
    }
    AddRow
    (
        String sMetricName,
        Object oMetricValue,
        OverallMetricRows oOverallMetricRows
    )
    {
        Debug.Assert(sMetricName != null);
        Debug.Assert(oMetricValue != null);
        Debug.Assert(oOverallMetricRows != null);
        AssertValid();

        AddRow(sMetricName, oMetricValue, CellStyleNames.GraphMetricGood,
            oOverallMetricRows);
    }