Inheritance: NodeXLApplicationSettingsBase
    //*************************************************************************
    //  Constructor: AutoFillWorkbookDialog()
    //
    /// <summary>
    /// Initializes a new instance of the <see cref="AutoFillWorkbookDialog" />
    /// class.
    /// </summary>
    ///
    /// <param name="mode">
    /// Indicates the mode in which the dialog is being used.
    /// </param>
    ///
    /// <param name="workbook">
    /// Workbook containing the graph data.
    /// </param>
    //*************************************************************************

    public AutoFillWorkbookDialog
    (
        DialogMode mode,
        Microsoft.Office.Interop.Excel.Workbook workbook
    )
    {
        Debug.Assert(workbook != null);

        InitializeComponent();

        m_eMode = mode;
        m_oWorkbook = workbook;

        m_oAutoFillUserSettings = new AutoFillUserSettings();

        if (m_eMode == DialogMode.EditOnly)
        {
            this.Text += " Options";
            btnAutoFill.Text = "OK";
            btnClose.Text = "Cancel";

            // The column header text "When Autofill is clicked..." makes no
            // sense when the "Autofill" button text has been changed to "OK".

            lblDestinationColumnHeader1.Text =
                lblDestinationColumnHeader2.Text =
                lblDestinationColumnHeader3.Text =
                lblDestinationColumnHeader1.Text.Replace("clicked", "run");
        }

        // Instantiate an object that retrieves and saves the position of this
        // dialog.  Note that the object automatically saves the settings when
        // the form closes.

        m_oAutoFillWorkbookDialogUserSettings =
            new AutoFillWorkbookDialogUserSettings(this);

        // Initialize the ComboBoxes used to specify the data sources for the
        // table columns.

        InitializeVertexComboBoxes(m_oWorkbook);
        InitializeEdgeComboBoxes(m_oWorkbook);
        InitializeGroupComboBoxes(m_oWorkbook);

        DoDataExchange(false);

        AssertValid();
    }
    AutoFillWorkbook
    (
        Microsoft.Office.Interop.Excel.Workbook workbook,
        AutoFillUserSettings autoFillUserSettings
    )
    {
        Debug.Assert(workbook != null);
        Debug.Assert(autoFillUserSettings != null);

        Application oApplication = workbook.Application;

        oApplication.ScreenUpdating = false;

        try
        {
            AutoFillWorkbookInternal(workbook, autoFillUserSettings);
        }
        finally
        {
            oApplication.ScreenUpdating = true;
        }
    }
    AddCollapsedGroupAttributesInternal
    (
        Microsoft.Office.Interop.Excel.Workbook oWorkbook,
        ReadWorkbookContext oReadWorkbookContext,
        ListObject oEdgeTable,
        ListObject oVertexTable,
        GroupInfo[] aoGroups
    )
    {
        Debug.Assert(oWorkbook != null);
        Debug.Assert(oReadWorkbookContext != null);
        Debug.Assert(oEdgeTable != null);
        Debug.Assert(oVertexTable != null);
        Debug.Assert(aoGroups != null);
        Debug.Assert(aoGroups.Length > 0);

        // Check whether relevant columns have been autofilled using numerical
        // source columns.

        PerWorkbookSettings oPerWorkbookSettings =
            new PerWorkbookSettings(oWorkbook);

        AutoFillColorColumnResults oVertexColorResults =
            oPerWorkbookSettings.AutoFillWorkbookResults.VertexColorResults;

        Boolean bVertexColorColumnAutoFilled =
            oVertexColorResults.ColumnAutoFilled &&
            !oVertexColorResults.ColumnAutoFilledWithCategories;

        AutoFillColorColumnResults oEdgeColorResults =
            oPerWorkbookSettings.AutoFillWorkbookResults.EdgeColorResults;

        Boolean bEdgeColorColumnAutoFilled =
            oEdgeColorResults.ColumnAutoFilled &&
            !oEdgeColorResults.ColumnAutoFilledWithCategories;

        AutoFillNumericRangeColumnResults oEdgeWidthResults =
            oPerWorkbookSettings.AutoFillWorkbookResults.EdgeWidthResults;

        Boolean bEdgeWidthColumnAutoFilled =
            oEdgeWidthResults.ColumnAutoFilled;

        // Some user settings for autofill may be needed.
        //
        // Note: This is a design bug.  The user's current settings should not
        // be required; everything needed here should come from the autofill
        // results.  The long-term fix is to add a UseLogs property to the
        // AutoFillColorColumnResults class.

        AutoFillUserSettings oAutoFillUserSettings =
            new AutoFillUserSettings();

        ColorColumnAutoFillUserSettings oVertexColorDetails =
            oAutoFillUserSettings.VertexColorDetails;

        ColorColumnAutoFillUserSettings oEdgeColorDetails =
            oAutoFillUserSettings.EdgeColorDetails;

        NumericRangeColumnAutoFillUserSettings oEdgeWidthDetails =
            oAutoFillUserSettings.EdgeWidthDetails;

        // The key is the row ID for each visible row in the vertex table and
        // the value is value of the source column cell in that row that was
        // used to autofill the vertex color column, if it was autofilled.

        Dictionary<Int32, Object> oVertexColorSourceDictionary =
            bVertexColorColumnAutoFilled ?

            GetRowIDDictionary(oVertexTable,
                oVertexColorResults.SourceColumnName)
            :
            null;

        // Ditto for edge colors and edge widths.

        Dictionary<Int32, Object> oEdgeColorSourceDictionary =
            bEdgeColorColumnAutoFilled ?

            GetRowIDDictionary(oEdgeTable, oEdgeColorResults.SourceColumnName)
            :
            null;

        Dictionary<Int32, Object> oEdgeWidthSourceDictionary =
            bEdgeWidthColumnAutoFilled ?

            GetRowIDDictionary(oEdgeTable, oEdgeWidthResults.SourceColumnName)
            :
            null;

        // Only motifs need to have attributes added to them.

        foreach ( ExcelTemplateGroupInfo oGroup in aoGroups.Where(
            oGroup => oGroup.CollapsedAttributes != null) )
        {
            CollapsedGroupAttributes oCollapsedGroupAttributes =
                CollapsedGroupAttributes.FromString(
                    oGroup.CollapsedAttributes);

            String sType = oCollapsedGroupAttributes.GetGroupType();

            if (
                sType == CollapsedGroupAttributeValues.FanMotifType
                ||
                sType == CollapsedGroupAttributeValues.DConnectorMotifType
                ||
                sType == CollapsedGroupAttributeValues.CliqueMotifType
                )
            {
                AddVertexColorAttributeToMotif(oGroup, sType,
                    bVertexColorColumnAutoFilled, oVertexColorResults,
                    oVertexColorDetails, oVertexColorSourceDictionary,
                    oReadWorkbookContext, oCollapsedGroupAttributes);
            }

            if (sType == CollapsedGroupAttributeValues.DConnectorMotifType)
            {
                Int32 iAnchorVertices;

                if ( oCollapsedGroupAttributes.TryGetValue(
                    CollapsedGroupAttributeKeys.AnchorVertices,
                    out iAnchorVertices) )
                {
                    AddEdgeColorAttributesToDConnectorMotif(oGroup, 
                        bEdgeColorColumnAutoFilled, oEdgeColorResults,
                        oEdgeColorDetails, oEdgeColorSourceDictionary,
                        oReadWorkbookContext, oCollapsedGroupAttributes,
                        iAnchorVertices);

                    AddEdgeWidthAttributesToDConnectorMotif(oGroup,
                        bEdgeWidthColumnAutoFilled, oEdgeWidthResults,
                        oEdgeWidthDetails, oEdgeWidthSourceDictionary,
                        oReadWorkbookContext, oCollapsedGroupAttributes,
                        iAnchorVertices);
                }
            }

            oGroup.CollapsedAttributes = oCollapsedGroupAttributes.ToString();
        }
    }
    AutoFillGroupTable
    (
        ListObject oGroupTable,
        AutoFillUserSettings oAutoFillUserSettings,
        AutoFillWorkbookResults oAutoFillWorkbookResults
    )
    {
        Debug.Assert(oGroupTable != null);
        Debug.Assert(oAutoFillUserSettings != null);
        Debug.Assert(oAutoFillWorkbookResults != null);

        AutoFillNumericComparisonColumn(oGroupTable,
            oAutoFillUserSettings.GroupCollapsedSourceColumnName,
            GroupTableColumnNames.Collapsed,
            oAutoFillUserSettings.GroupCollapsedDetails
            );

        if (
            AutoFillColumnViaCopy(oGroupTable,
                oAutoFillUserSettings.GroupLabelSourceColumnName,
                GroupTableColumnNames.Label)
            &&
            oAutoFillUserSettings.GroupLabelDetails.PrependWithGroupName
            )
        {
            PrependGroupLabelsWithGroupNames(oGroupTable);
        }
    }
    AutoFillVertexTable
    (
        ListObject oVertexTable,
        AutoFillUserSettings oAutoFillUserSettings,
        AutoFillWorkbookResults oAutoFillWorkbookResults
    )
    {
        Debug.Assert(oVertexTable != null);
        Debug.Assert(oAutoFillUserSettings != null);
        Debug.Assert(oAutoFillWorkbookResults != null);

        Boolean bSourceColumnContainsNumbers;
        Double dSourceCalculationNumber1, dSourceCalculationNumber2;
        Int32 iDecimalPlaces;
        ICollection<String> oCategoryNames;

        if ( TryAutoFillColorColumn(oVertexTable,
                oAutoFillUserSettings.VertexColorSourceColumnName,
                VertexTableColumnNames.Color,
                oAutoFillUserSettings.VertexColorDetails,
                out bSourceColumnContainsNumbers,
                out dSourceCalculationNumber1,
                out dSourceCalculationNumber2,
                out iDecimalPlaces, out oCategoryNames
                ) )
        {
            oAutoFillWorkbookResults.VertexColorResults =
                new AutoFillColorColumnResults(
                    bSourceColumnContainsNumbers,
                    oAutoFillUserSettings.VertexColorSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.VertexColorDetails.DestinationColor1,
                    oAutoFillUserSettings.VertexColorDetails.DestinationColor2,
                    oCategoryNames
                    );
        }

        AutoFillNumericComparisonColumn(oVertexTable,
            oAutoFillUserSettings.VertexShapeSourceColumnName,
            VertexTableColumnNames.Shape,
            oAutoFillUserSettings.VertexShapeDetails
            );

        if ( TryAutoFillNumericRangeColumn(oVertexTable,
                oAutoFillUserSettings.VertexRadiusSourceColumnName,
                VertexTableColumnNames.Radius,
                oAutoFillUserSettings.VertexRadiusDetails,
                out dSourceCalculationNumber1, out dSourceCalculationNumber2,
                out iDecimalPlaces
                ) )
        {
            oAutoFillWorkbookResults.VertexRadiusResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.VertexRadiusSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.VertexRadiusDetails.
                        DestinationNumber1,
                    oAutoFillUserSettings.VertexRadiusDetails.
                        DestinationNumber2,
                    oAutoFillUserSettings.VertexRadiusDetails.UseLogs
                    );
        }

        if ( TryAutoFillNumericRangeColumn(oVertexTable,
                oAutoFillUserSettings.VertexAlphaSourceColumnName,
                CommonTableColumnNames.Alpha,
                oAutoFillUserSettings.VertexAlphaDetails,
                out dSourceCalculationNumber1, out dSourceCalculationNumber2,
                out iDecimalPlaces
                ) )
        {
            oAutoFillWorkbookResults.VertexAlphaResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.VertexAlphaSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.VertexAlphaDetails.DestinationNumber1,
                    oAutoFillUserSettings.VertexAlphaDetails.DestinationNumber2,
                    oAutoFillUserSettings.VertexAlphaDetails.UseLogs
                    );
        }

        AutoFillColumnViaCopy(oVertexTable,
            oAutoFillUserSettings.VertexLabelSourceColumnName,
            VertexTableColumnNames.Label
            );

        TryAutoFillColorColumn(oVertexTable,
            oAutoFillUserSettings.VertexLabelFillColorSourceColumnName,
            VertexTableColumnNames.LabelFillColor,
            oAutoFillUserSettings.VertexLabelFillColorDetails,
            out bSourceColumnContainsNumbers,
            out dSourceCalculationNumber1, out dSourceCalculationNumber2,
            out iDecimalPlaces, out oCategoryNames
            );

        AutoFillNumericComparisonColumn(oVertexTable,
            oAutoFillUserSettings.VertexLabelPositionSourceColumnName,
            VertexTableColumnNames.LabelPosition,
            oAutoFillUserSettings.VertexLabelPositionDetails
            );

        AutoFillColumnViaCopy(oVertexTable,
            oAutoFillUserSettings.VertexToolTipSourceColumnName,
            VertexTableColumnNames.ToolTip
            );

        AutoFillNumericComparisonColumn(oVertexTable,
            oAutoFillUserSettings.VertexVisibilitySourceColumnName,
            CommonTableColumnNames.Visibility,
            oAutoFillUserSettings.VertexVisibilityDetails
            );

        TryAutoFillNumericRangeColumn(oVertexTable,
            oAutoFillUserSettings.VertexLayoutOrderSourceColumnName,
            VertexTableColumnNames.LayoutOrder,
            oAutoFillUserSettings.VertexLayoutOrderDetails,
            out dSourceCalculationNumber1, out dSourceCalculationNumber2,
            out iDecimalPlaces
            );

        Boolean bXAutoFilled = TryAutoFillNumericRangeColumn(oVertexTable,
            oAutoFillUserSettings.VertexXSourceColumnName,
            VertexTableColumnNames.X,
            oAutoFillUserSettings.VertexXDetails,
            out dSourceCalculationNumber1, out dSourceCalculationNumber2,
            out iDecimalPlaces
            );

        Double dYSourceCalculationNumber1, dYSourceCalculationNumber2;

        Boolean bYAutoFilled = TryAutoFillNumericRangeColumn(oVertexTable,
            oAutoFillUserSettings.VertexYSourceColumnName,
            VertexTableColumnNames.Y,
            oAutoFillUserSettings.VertexYDetails,
            out dYSourceCalculationNumber1, out dYSourceCalculationNumber2,
            out iDecimalPlaces
            );

        if (bXAutoFilled && bYAutoFilled)
        {
            // (Note that the decimal places for the Y column take precedence
            // here.)

            oAutoFillWorkbookResults.VertexXResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.VertexXSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.VertexXDetails.DestinationNumber1,
                    oAutoFillUserSettings.VertexXDetails.DestinationNumber2,
                    oAutoFillUserSettings.VertexXDetails.UseLogs
                    );

            oAutoFillWorkbookResults.VertexYResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.VertexYSourceColumnName,
                    dYSourceCalculationNumber1, dYSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.VertexYDetails.DestinationNumber1,
                    oAutoFillUserSettings.VertexYDetails.DestinationNumber2,
                    oAutoFillUserSettings.VertexYDetails.UseLogs
                    );
        }

        TryAutoFillNumericRangeColumn(oVertexTable,
            oAutoFillUserSettings.VertexPolarRSourceColumnName,
            VertexTableColumnNames.PolarR,
            oAutoFillUserSettings.VertexPolarRDetails,
            out dSourceCalculationNumber1, out dSourceCalculationNumber2,
            out iDecimalPlaces
            );

        TryAutoFillNumericRangeColumn(oVertexTable,
            oAutoFillUserSettings.VertexPolarAngleSourceColumnName,
            VertexTableColumnNames.PolarAngle,
            oAutoFillUserSettings.VertexPolarAngleDetails,
            out dSourceCalculationNumber1, out dSourceCalculationNumber2,
            out iDecimalPlaces
            );
    }
    AutoFillEdgeTable
    (
        ListObject oEdgeTable,
        AutoFillUserSettings oAutoFillUserSettings,
        AutoFillWorkbookResults oAutoFillWorkbookResults
    )
    {
        Debug.Assert(oEdgeTable != null);
        Debug.Assert(oAutoFillUserSettings != null);
        Debug.Assert(oAutoFillWorkbookResults != null);

        Boolean bSourceColumnContainsNumbers;
        Double dSourceCalculationNumber1, dSourceCalculationNumber2;
        Int32 iDecimalPlaces;
        ICollection<String> oCategoryNames;

        if ( TryAutoFillColorColumn(oEdgeTable,
                oAutoFillUserSettings.EdgeColorSourceColumnName,
                EdgeTableColumnNames.Color,
                oAutoFillUserSettings.EdgeColorDetails,
                out bSourceColumnContainsNumbers,
                out dSourceCalculationNumber1, out dSourceCalculationNumber2,
                out iDecimalPlaces, out oCategoryNames
                ) )
        {
            oAutoFillWorkbookResults.EdgeColorResults =
                new AutoFillColorColumnResults(
                    bSourceColumnContainsNumbers,
                    oAutoFillUserSettings.EdgeColorSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.EdgeColorDetails.DestinationColor1,
                    oAutoFillUserSettings.EdgeColorDetails.DestinationColor2,
                    oCategoryNames
                    );
        }

        if ( TryAutoFillNumericRangeColumn(oEdgeTable,
                oAutoFillUserSettings.EdgeWidthSourceColumnName,
                EdgeTableColumnNames.Width,
                oAutoFillUserSettings.EdgeWidthDetails,
                out dSourceCalculationNumber1, out dSourceCalculationNumber2,
                out iDecimalPlaces
                ) )
        {
            oAutoFillWorkbookResults.EdgeWidthResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.EdgeWidthSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.EdgeWidthDetails.DestinationNumber1,
                    oAutoFillUserSettings.EdgeWidthDetails.DestinationNumber2,
                    oAutoFillUserSettings.EdgeWidthDetails.UseLogs
                    );
        }

        AutoFillNumericComparisonColumn(oEdgeTable,
            oAutoFillUserSettings.EdgeStyleSourceColumnName,
            EdgeTableColumnNames.Style, oAutoFillUserSettings.EdgeStyleDetails
            );

        if ( TryAutoFillNumericRangeColumn(oEdgeTable,
                oAutoFillUserSettings.EdgeAlphaSourceColumnName,
                CommonTableColumnNames.Alpha,
                oAutoFillUserSettings.EdgeAlphaDetails,
                out dSourceCalculationNumber1, out dSourceCalculationNumber2,
                out iDecimalPlaces
                ) )
        {
            oAutoFillWorkbookResults.EdgeAlphaResults =
                new AutoFillNumericRangeColumnResults(
                    oAutoFillUserSettings.EdgeAlphaSourceColumnName,
                    dSourceCalculationNumber1, dSourceCalculationNumber2,
                    iDecimalPlaces,
                    oAutoFillUserSettings.EdgeAlphaDetails.DestinationNumber1,
                    oAutoFillUserSettings.EdgeAlphaDetails.DestinationNumber2,
                    oAutoFillUserSettings.EdgeAlphaDetails.UseLogs
                    );
        }

        AutoFillNumericComparisonColumn(oEdgeTable,
            oAutoFillUserSettings.EdgeVisibilitySourceColumnName,
            CommonTableColumnNames.Visibility,
            oAutoFillUserSettings.EdgeVisibilityDetails
            );

        AutoFillColumnViaCopy(oEdgeTable,
            oAutoFillUserSettings.EdgeLabelSourceColumnName,
            EdgeTableColumnNames.Label
            );
    }
    AutoFillTable
    (
        Microsoft.Office.Interop.Excel.Workbook oWorkbook,
        AutoFillUserSettings oAutoFillUserSettings,
        AutoFillWorkbookResults oAutoFillWorkbookResults,
        String sWorksheetName,
        String sTableName,
        AutoFillTableMethod oAutoFillTableMethod
    )
    {
        Debug.Assert(oWorkbook != null);
        Debug.Assert(oAutoFillUserSettings != null);
        Debug.Assert(oAutoFillWorkbookResults != null);
        Debug.Assert( !String.IsNullOrEmpty(sWorksheetName) );
        Debug.Assert( !String.IsNullOrEmpty(sTableName) );
        Debug.Assert(oAutoFillTableMethod != null);

        ListObject oTable;
        ExcelHiddenColumns oHiddenColumns;

        if (ExcelTableUtil.TryGetTable(oWorkbook, sWorksheetName, sTableName,
            out oTable) )
        {
            // The TableColumnMapper class that does the actual autofilling
            // fills only visible cells.  Temporarily show all hidden columns
            // in the table.

            oHiddenColumns = ExcelColumnHider.ShowHiddenColumns(oTable);

            try
            {
                oAutoFillTableMethod(oTable, oAutoFillUserSettings,
                    oAutoFillWorkbookResults);
            }
            finally
            {
                ExcelColumnHider.RestoreHiddenColumns(oTable, oHiddenColumns);
            }
        }
    }
    AutoFillWorkbookInternal
    (
        Microsoft.Office.Interop.Excel.Workbook oWorkbook,
        AutoFillUserSettings oAutoFillUserSettings
    )
    {
        Debug.Assert(oWorkbook != null);
        Debug.Assert(oAutoFillUserSettings != null);

        // Populate the vertex worksheet with the name of each unique vertex in
        // the edge worksheet.

        ( new VertexWorksheetPopulator() ).PopulateVertexWorksheet(
            oWorkbook, false);

        AutoFillWorkbookResults oAutoFillWorkbookResults =
            new AutoFillWorkbookResults();

        AutoFillTable(oWorkbook, oAutoFillUserSettings,
            oAutoFillWorkbookResults, WorksheetNames.Edges,
            TableNames.Edges, AutoFillEdgeTable);

        AutoFillTable(oWorkbook, oAutoFillUserSettings,
            oAutoFillWorkbookResults, WorksheetNames.Vertices,
            TableNames.Vertices, AutoFillVertexTable);

        AutoFillTable(oWorkbook, oAutoFillUserSettings,
            oAutoFillWorkbookResults, WorksheetNames.Groups,
            TableNames.Groups, AutoFillGroupTable);

        // Save the results.

        ( new PerWorkbookSettings(oWorkbook) ).AutoFillWorkbookResults =
            oAutoFillWorkbookResults;
    }