/// <summary>
        /// Before saving the document, I'll remove any ApAnalAttrib rows that have no values set
        /// (These may have been created by the overly keen method below and are not required at all,
        /// or perhaps they are required but the user has not yet provided values. )
        /// </summary>
        /// <param name="Sender"></param>
        /// <param name="e"></param>
        void BeforeDataSave(object Sender, EventArgs e)
        {
            for (Int32 RowNum = FMainDS.AApAnalAttrib.Rows.Count; RowNum > 0; RowNum--)
            {
                AApAnalAttribRow Row = (AApAnalAttribRow)FMainDS.AApAnalAttrib.Rows[RowNum - 1];

                if ((Row.RowState != DataRowState.Deleted) && (Row.AnalysisAttributeValue == ""))  // I need to delete empty rows
                {
                    Row.Delete();
                }
            }
        }
        private void AnalysisAttributesGrid_RowSelected(System.Object sender, RangeRegionChangedEventArgs e)
        {
            if (grdAnalAttributes.Selection.ActivePosition.IsEmpty() || (grdAnalAttributes.Selection.ActivePosition.Column == 0))
            {
                return;
            }

            if ((GetSelectedAttributeRow() == null) || (FPSAttributesRow == GetSelectedAttributeRow()))
            {
                return;
            }

            FPSAttributesRow = GetSelectedAttributeRow();

            FMainDS.AFreeformAnalysis.DefaultView.RowFilter = String.Format("{0}='{1}' AND {2}=true",
                                                                            AFreeformAnalysisTable.GetAnalysisTypeCodeDBName(),
                                                                            FPSAttributesRow.AnalysisTypeCode,
                                                                            AFreeformAnalysisTable.GetActiveDBName());

            //Refresh the combo values
            int analTypeCodeValuesCount = FMainDS.AFreeformAnalysis.DefaultView.Count;

            if (analTypeCodeValuesCount == 0)
            {
                MessageBox.Show(Catalog.GetString(
                                    "No attribute values are defined!"), FPSAttributesRow.AnalysisTypeCode, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            string[] analTypeValues = new string[analTypeCodeValuesCount];

            FMainDS.AFreeformAnalysis.DefaultView.Sort = AFreeformAnalysisTable.GetAnalysisValueDBName();
            int counter = 0;

            foreach (DataRowView dvr in FMainDS.AFreeformAnalysis.DefaultView)
            {
                AFreeformAnalysisRow faRow = (AFreeformAnalysisRow)dvr.Row;
                analTypeValues[counter++] = faRow.AnalysisValue;
            }

            cmbAnalAttribValues.StandardValuesExclusive = true;
            cmbAnalAttribValues.StandardValues          = analTypeValues;
        }
        private void UpdateAttributeLabel(AccountsPayableTDSAApDocumentDetailRow DetailRow)
        {
            string strAnalAttr = "";

            FMainDS.AApAnalAttrib.DefaultView.RowFilter =
                String.Format("{0}={1}", AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber);

            foreach (DataRowView rv in FMainDS.AApAnalAttrib.DefaultView)
            {
                AApAnalAttribRow Row = (AApAnalAttribRow)rv.Row;

                if (strAnalAttr.Length > 0)
                {
                    strAnalAttr += ", ";
                }

                strAnalAttr += (Row.AnalysisTypeCode + "=" + Row.AnalysisAttributeValue);
            }

            DetailRow.AnalAttr = strAnalAttr;
        }
        //
        // Called from cmbDetailAccountCode.SelectedValueChanged,
        // I need to load the Analysis Types Pane with the required attributes for this account,
        // and show any assignments already made.

        void ShowAnalysisAttributesForAccount(object sender, EventArgs e)
        {
            //
            // It's possible that my TDS doesn't even have an AnalAttrib table...

            if (FMainDS.AApAnalAttrib == null)
            {
                FMainDS.Merge(new AApAnalAttribTable());
            }

            if (FPetraUtilsObject.SuppressChangeDetection || (FPreviouslySelectedDetailRow == null))
            {
                return;
            }

            //Empty the grid
            FMainDS.AApAnalAttrib.DefaultView.RowFilter = "1=2";
            FPSAttributesRow = null;

            if (grdAnalAttributes.Columns.Count < 2) // This is initialisation but I moved it here because sometimes this is called before Show().
            {
                grdAnalAttributes.SpecialKeys = GridSpecialKeys.Default | GridSpecialKeys.Tab;

                cmbAnalAttribValues = new SourceGrid.Cells.Editors.ComboBox(typeof(string));
                cmbAnalAttribValues.Control.DropDownStyle         = ComboBoxStyle.DropDownList;
                cmbAnalAttribValues.EnableEdit                    = true;
                cmbAnalAttribValues.EditableMode                  = EditableMode.Focus;
                cmbAnalAttribValues.Control.SelectedValueChanged += new EventHandler(AnalysisAttributeValueChanged);
                grdAnalAttributes.AddTextColumn("Value",
                                                FMainDS.AApAnalAttrib.Columns[AApAnalAttribTable.GetAnalysisAttributeValueDBName()], 120,
                                                cmbAnalAttribValues);

                grdAnalAttributes.Selection.SelectionChanged += new RangeRegionChangedEventHandler(AnalysisAttributesGrid_RowSelected);
            }

            grdAnalAttributes.Columns[0].Width = 90; // for some unknown reason, this doesn't work.
            grdAnalAttributes.Columns[1].Width = 120;

            AccountsPayableTDSAApDocumentDetailRow DetailRow = GetSelectedDetailRow();

            DetailRow.AccountCode = cmbDetailAccountCode.GetSelectedString();

            //
            // So I want to remove any attributes attached to this row that don't have the new account code...
            FMainDS.AApAnalAttrib.DefaultView.RowFilter = String.Format("{0}={1} AND {2}={3} AND {4}={5} AND {6}<>'{7}'",
                                                                        AApAnalAttribTable.GetLedgerNumberDBName(), DetailRow.LedgerNumber,
                                                                        AApAnalAttribTable.GetApDocumentIdDBName(), DetailRow.ApDocumentId,
                                                                        AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber,
                                                                        AApAnalAttribTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            for (Int32 RowIdx = FMainDS.AApAnalAttrib.DefaultView.Count; RowIdx > 0; RowIdx--)
            {
                FMainDS.AApAnalAttrib.DefaultView[RowIdx - 1].Row.Delete();
            }

            FMainDS.AAnalysisAttribute.DefaultView.RowFilter =
                String.Format("{0}='{1}'", AAnalysisAttributeTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            String AccountCodeRowFilter = String.Format("{0}={1} AND {2}={3} AND {4}={5} AND {6}='{7}'",
                                                        AApAnalAttribTable.GetLedgerNumberDBName(), DetailRow.LedgerNumber,
                                                        AApAnalAttribTable.GetApDocumentIdDBName(), DetailRow.ApDocumentId,
                                                        AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber,
                                                        AApAnalAttribTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            foreach (DataRowView rv in FMainDS.AAnalysisAttribute.DefaultView) // List of attributes required for this account
            {
                AAnalysisAttributeRow AttrRow = (AAnalysisAttributeRow)rv.Row;

                FMainDS.AApAnalAttrib.DefaultView.RowFilter = AccountCodeRowFilter +
                                                              String.Format(" AND {0}='{1}'",
                                                                            AApAnalAttribTable.GetAnalysisTypeCodeDBName(), AttrRow.AnalysisTypeCode);

                if (FMainDS.AApAnalAttrib.DefaultView.Count == 0)   // No Entry yet for this attribute. This is likely, given I just deleted everything...
                {
                    AApAnalAttribRow AARow = FMainDS.AApAnalAttrib.NewRowTyped();
                    AARow.LedgerNumber     = DetailRow.LedgerNumber;
                    AARow.ApDocumentId     = DetailRow.ApDocumentId;
                    AARow.DetailNumber     = DetailRow.DetailNumber;
                    AARow.AnalysisTypeCode = AttrRow.AnalysisTypeCode;
                    AARow.AccountCode      = DetailRow.AccountCode;
                    FMainDS.AApAnalAttrib.Rows.Add(AARow);
                }
            }

            FMainDS.AApAnalAttrib.DefaultView.RowFilter = AccountCodeRowFilter;
            FMainDS.AApAnalAttrib.DefaultView.Sort      = AApAnalAttribTable.GetAnalysisTypeCodeDBName();

            grdAnalAttributes.DataSource = null;
            grdAnalAttributes.DataSource = new DevAge.ComponentModel.BoundDataView(FMainDS.AApAnalAttrib.DefaultView);
            UpdateAttributeLabel(DetailRow);

            if (grdAnalAttributes.Rows.Count > 2)
            {
                grdAnalAttributes.Enabled = true;
                grdAnalAttributes.SelectRowWithoutFocus(1);
                AnalysisAttributesGrid_RowSelected(null, null);
            }
            else
            {
                grdAnalAttributes.Enabled = false;
            }
        }
        private static bool DetailLineAttributesRequired(ref bool AllPresent, AccountsPayableTDS Atds, AApDocumentDetailRow DetailRow)
        {
            Atds.AAnalysisAttribute.DefaultView.RowFilter =
                String.Format("{0}='{1}'", AAnalysisAttributeTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            if (Atds.AAnalysisAttribute.DefaultView.Count > 0)
            {
                bool IhaveAllMyAttributes = true;

                //
                // It's possible that my TDS doesn't even have an AnalAttrib table...

                if (Atds.AApAnalAttrib == null)
                {
                    Atds.Merge(new AApAnalAttribTable());
                }

                foreach (DataRowView rv in Atds.AAnalysisAttribute.DefaultView)
                {
                    AAnalysisAttributeRow AttrRow = (AAnalysisAttributeRow)rv.Row;

                    Atds.AApAnalAttrib.DefaultView.RowFilter =
                        String.Format("{0}={1} AND {2}='{3}'",
                                      AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber,
                                      AApAnalAttribTable.GetAccountCodeDBName(), AttrRow.AccountCode);

                    if (Atds.AApAnalAttrib.DefaultView.Count == 0)
                    {
                        IhaveAllMyAttributes = false;
                        break;
                    }

                    foreach (DataRowView rv2 in Atds.AApAnalAttrib.DefaultView)
                    {
                        AApAnalAttribRow AttribValueRow = (AApAnalAttribRow)rv2.Row;

                        if (AttribValueRow.AnalysisAttributeValue == "")
                        {
                            IhaveAllMyAttributes = false;
                            break;
                        }

                        // Is the referenced AttribValue active?
                        AFreeformAnalysisRow referencedRow = (AFreeformAnalysisRow)Atds.AFreeformAnalysis.Rows.Find(
                            new Object[] { AttribValueRow.LedgerNumber, AttribValueRow.AnalysisTypeCode, AttribValueRow.AnalysisAttributeValue }
                            );

                        if ((referencedRow == null) || !referencedRow.Active)
                        {
                            IhaveAllMyAttributes = false;
                            break;
                        }
                    }

                    if (IhaveAllMyAttributes == false)  // because of the test above..
                    {
                        break;
                    }
                }

                AllPresent = IhaveAllMyAttributes;
                return(true);
            }
            else
            {
                AllPresent = true; // This detail line is fully specified
                return(false);     // No attributes are required
            }
        }
        //
        // Called from cmbDetailAccountCode.SelectedValueChanged,
        // I need to load the Analysis Types Pane with the required attributes for this account,
        // and show any assignments already made.

        void ShowAnalysisAttributesForAccount(object sender, EventArgs e)
        {
            //
            // It's possible that my TDS doesn't even have an AnalAttrib table...

            if (FMainDS.AApAnalAttrib == null)
            {
                FMainDS.Merge(new AApAnalAttribTable());
            }

            if (FPetraUtilsObject.SuppressChangeDetection || (FPreviouslySelectedDetailRow == null))
            {
                return;
            }

            //Empty the grid
            FMainDS.AApAnalAttrib.DefaultView.RowFilter = "1=2";
            FPSAttributesRow = null;

            if (grdAnalAttributes.Columns.Count < 2) // This is initialisation but I moved it here because sometimes this is called before Show().
            {
                grdAnalAttributes.SpecialKeys = GridSpecialKeys.Default | GridSpecialKeys.Tab;

                cmbAnalAttribValues = new SourceGrid.Cells.Editors.ComboBox(typeof(string));
                cmbAnalAttribValues.Control.DropDownStyle = ComboBoxStyle.DropDownList;
                cmbAnalAttribValues.EnableEdit = true;
                cmbAnalAttribValues.EditableMode = EditableMode.Focus;
                cmbAnalAttribValues.Control.SelectedValueChanged += new EventHandler(AnalysisAttributeValueChanged);
                grdAnalAttributes.AddTextColumn("Value",
                    FMainDS.AApAnalAttrib.Columns[AApAnalAttribTable.GetAnalysisAttributeValueDBName()], 120,
                    cmbAnalAttribValues);

                grdAnalAttributes.Selection.SelectionChanged += new RangeRegionChangedEventHandler(AnalysisAttributesGrid_RowSelected);
            }

            grdAnalAttributes.Columns[0].Width = 90; // for some unknown reason, this doesn't work.
            grdAnalAttributes.Columns[1].Width = 120;

            AccountsPayableTDSAApDocumentDetailRow DetailRow = GetSelectedDetailRow();
            DetailRow.AccountCode = cmbDetailAccountCode.GetSelectedString();

            //
            // So I want to remove any attributes attached to this row that don't have the new account code...
            FMainDS.AApAnalAttrib.DefaultView.RowFilter = String.Format("{0}={1} AND {2}={3} AND {4}={5} AND {6}<>'{7}'",
                AApAnalAttribTable.GetLedgerNumberDBName(), DetailRow.LedgerNumber,
                AApAnalAttribTable.GetApDocumentIdDBName(), DetailRow.ApDocumentId,
                AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber,
                AApAnalAttribTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            for (Int32 RowIdx = FMainDS.AApAnalAttrib.DefaultView.Count; RowIdx > 0; RowIdx--)
            {
                FMainDS.AApAnalAttrib.DefaultView[RowIdx - 1].Row.Delete();
            }

            FMainDS.AAnalysisAttribute.DefaultView.RowFilter =
                String.Format("{0}='{1}'", AAnalysisAttributeTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            String AccountCodeRowFilter = String.Format("{0}={1} AND {2}={3} AND {4}={5} AND {6}='{7}'",
                AApAnalAttribTable.GetLedgerNumberDBName(), DetailRow.LedgerNumber,
                AApAnalAttribTable.GetApDocumentIdDBName(), DetailRow.ApDocumentId,
                AApAnalAttribTable.GetDetailNumberDBName(), DetailRow.DetailNumber,
                AApAnalAttribTable.GetAccountCodeDBName(), DetailRow.AccountCode);

            foreach (DataRowView rv in FMainDS.AAnalysisAttribute.DefaultView) // List of attributes required for this account
            {
                AAnalysisAttributeRow AttrRow = (AAnalysisAttributeRow)rv.Row;

                FMainDS.AApAnalAttrib.DefaultView.RowFilter = AccountCodeRowFilter +
                                                              String.Format(" AND {0}='{1}'",
                    AApAnalAttribTable.GetAnalysisTypeCodeDBName(), AttrRow.AnalysisTypeCode);

                if (FMainDS.AApAnalAttrib.DefaultView.Count == 0)   // No Entry yet for this attribute. This is likely, given I just deleted everything...
                {
                    AApAnalAttribRow AARow = FMainDS.AApAnalAttrib.NewRowTyped();
                    AARow.LedgerNumber = DetailRow.LedgerNumber;
                    AARow.ApDocumentId = DetailRow.ApDocumentId;
                    AARow.DetailNumber = DetailRow.DetailNumber;
                    AARow.AnalysisTypeCode = AttrRow.AnalysisTypeCode;
                    AARow.AccountCode = DetailRow.AccountCode;
                    FMainDS.AApAnalAttrib.Rows.Add(AARow);
                }
            }

            FMainDS.AApAnalAttrib.DefaultView.RowFilter = AccountCodeRowFilter;
            FMainDS.AApAnalAttrib.DefaultView.Sort = AApAnalAttribTable.GetAnalysisTypeCodeDBName();

            grdAnalAttributes.DataSource = null;
            grdAnalAttributes.DataSource = new DevAge.ComponentModel.BoundDataView(FMainDS.AApAnalAttrib.DefaultView);
            UpdateAttributeLabel(DetailRow);

            if (grdAnalAttributes.Rows.Count > 2)
            {
                grdAnalAttributes.Enabled = true;
                grdAnalAttributes.SelectRowWithoutFocus(1);
                AnalysisAttributesGrid_RowSelected(null, null);
            }
            else
            {
                grdAnalAttributes.Enabled = false;
            }
        }
        private void AnalysisAttributesGrid_RowSelected(System.Object sender, RangeRegionChangedEventArgs e)
        {
            if (grdAnalAttributes.Selection.ActivePosition.IsEmpty() || (grdAnalAttributes.Selection.ActivePosition.Column == 0))
            {
                return;
            }

            if ((GetSelectedAttributeRow() == null) || (FPSAttributesRow == GetSelectedAttributeRow()))
            {
                return;
            }

            FPSAttributesRow = GetSelectedAttributeRow();

            FMainDS.AFreeformAnalysis.DefaultView.RowFilter = String.Format("{0}='{1}' AND {2}=true",
                AFreeformAnalysisTable.GetAnalysisTypeCodeDBName(),
                FPSAttributesRow.AnalysisTypeCode,
                AFreeformAnalysisTable.GetActiveDBName());

            //Refresh the combo values
            int analTypeCodeValuesCount = FMainDS.AFreeformAnalysis.DefaultView.Count;

            if (analTypeCodeValuesCount == 0)
            {
                MessageBox.Show(Catalog.GetString(
                        "No attribute values are defined!"), FPSAttributesRow.AnalysisTypeCode, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            string[] analTypeValues = new string[analTypeCodeValuesCount];

            FMainDS.AFreeformAnalysis.DefaultView.Sort = AFreeformAnalysisTable.GetAnalysisValueDBName();
            int counter = 0;

            foreach (DataRowView dvr in FMainDS.AFreeformAnalysis.DefaultView)
            {
                AFreeformAnalysisRow faRow = (AFreeformAnalysisRow)dvr.Row;
                analTypeValues[counter++] = faRow.AnalysisValue;
            }

            cmbAnalAttribValues.StandardValuesExclusive = true;
            cmbAnalAttribValues.StandardValues = analTypeValues;
        }