/// <summary>
        /// load the transactions into the grid
        /// </summary>
        /// <param name="ALedgerNumber"></param>
        /// <param name="ABatchNumber"></param>
        /// <param name="AJournalNumber"></param>
        /// <param name="ACurrencyCode"></param>
        /// <param name="AFromBatchTab"></param>
        /// <param name="ABatchStatus"></param>
        /// <param name="AJournalStatus"></param>
        /// <returns>True if new GL transactions were loaded, false if transactions had been loaded already.</returns>
        public bool LoadTransactions(Int32 ALedgerNumber,
            Int32 ABatchNumber,
            Int32 AJournalNumber,
            string ACurrencyCode,
            bool AFromBatchTab = false,
            string ABatchStatus = MFinanceConstants.BATCH_UNPOSTED,
            string AJournalStatus = MFinanceConstants.BATCH_UNPOSTED)
        {
            TFrmStatusDialog dlgStatus = null;
            bool DifferentBatchSelected = false;

            FLoadCompleted = false;

            FBatchRow = GetBatchRow();
            FJournalRow = GetJournalRow();

            if ((FBatchRow == null) || (FJournalRow == null))
            {
                return false;
            }

            //FBatchNumber and FJournalNumber may have already been set outside
            //  so need to reset to previous value
            if ((txtBatchNumber.Text.Length > 0) && (FBatchNumber.ToString() != txtBatchNumber.Text))
            {
                FBatchNumber = Int32.Parse(txtBatchNumber.Text);
            }

            if ((txtJournalNumber.Text.Length > 0) && (FJournalNumber.ToString() != txtJournalNumber.Text))
            {
                FJournalNumber = Int32.Parse(txtJournalNumber.Text);
            }

            bool FirstRun = (FLedgerNumber != ALedgerNumber);
            bool BatchChanged = (FBatchNumber != ABatchNumber);
            bool BatchStatusChanged = (!BatchChanged && (FBatchStatus != ABatchStatus));
            bool JournalChanged = (BatchChanged || (FJournalNumber != AJournalNumber));
            bool JournalStatusChanged = (!JournalChanged && (FJournalStatus != AJournalStatus));
            bool CurrencyChanged = (FTransactionCurrency != ACurrencyCode);

            if (FirstRun)
            {
                FLedgerNumber = ALedgerNumber;
            }

            if (BatchChanged)
            {
                FBatchNumber = ABatchNumber;
            }

            if (BatchStatusChanged)
            {
                FBatchStatus = ABatchStatus;
            }

            if (JournalChanged)
            {
                FJournalNumber = AJournalNumber;
            }

            if (JournalStatusChanged)
            {
                FJournalStatus = AJournalStatus;
            }

            if (CurrencyChanged)
            {
                FTransactionCurrency = ACurrencyCode;
            }

            FIsUnposted = (FBatchRow.BatchStatus == MFinanceConstants.BATCH_UNPOSTED);

            if (FirstRun)
            {
                InitialiseControls();
            }

            try
            {
                this.Cursor = Cursors.WaitCursor;

                //Check if the same batch and journal is selected, so no need to apply filter
                if (!FirstRun
                    && !BatchChanged
                    && !JournalChanged
                    && !BatchStatusChanged
                    && !JournalStatusChanged
                    && !CurrencyChanged
                    && (FMainDS.ATransaction.DefaultView.Count > 0))
                {
                    //Same as previously selected batch and journal

                    //Need to reconnect FPrev in some circumstances
                    if (FPreviouslySelectedDetailRow == null)
                    {
                        DataRowView rowView = (DataRowView)grdDetails.Rows.IndexToDataSourceRow(FPrevRowChangedRow);

                        if (rowView != null)
                        {
                            FPreviouslySelectedDetailRow = (GLBatchTDSATransactionRow)(rowView.Row);
                        }
                    }

                    if (FIsUnposted && (GetSelectedRowIndex() > 0))
                    {
                        if (AFromBatchTab)
                        {
                            SelectRowInGrid(GetSelectedRowIndex());
                        }
                        else
                        {
                            GetDetailsFromControls(FPreviouslySelectedDetailRow);
                        }
                    }

                    FLoadCompleted = true;

                    return false;
                }

                // Different batch selected
                DifferentBatchSelected = true;
                bool requireControlSetup = (FLedgerNumber == -1) || (FTransactionCurrency != ACurrencyCode);

                //Handle dialog
                dlgStatus = new TFrmStatusDialog(FPetraUtilsObject.GetForm());

                if (FShowStatusDialogOnLoad == true)
                {
                    dlgStatus.Show();
                    FShowStatusDialogOnLoad = false;
                    dlgStatus.Heading = String.Format(Catalog.GetString("Batch {0}, Journal {1}"), ABatchNumber, AJournalNumber);
                    dlgStatus.CurrentStatus = Catalog.GetString("Loading transactions ...");
                }

                FLedgerNumber = ALedgerNumber;
                FBatchNumber = ABatchNumber;
                FJournalNumber = AJournalNumber;
                FTransactionNumber = -1;
                FTransactionCurrency = ACurrencyCode;
                FBatchStatus = ABatchStatus;
                FJournalStatus = AJournalStatus;

                FPreviouslySelectedDetailRow = null;
                grdDetails.SuspendLayout();
                //Empty grids before filling them
                grdDetails.DataSource = null;
                grdAnalAttributes.DataSource = null;

                // This sets the main part of the filter but excluding the additional items set by the user GUI
                // It gets the right sort order
                SetTransactionDefaultView();

                //Set the Analysis attributes filter as well
                FAnalysisAttributesLogic = new TAnalysisAttributes(FLedgerNumber, FBatchNumber, FJournalNumber);
                FAnalysisAttributesLogic.SetTransAnalAttributeDefaultView(FMainDS);
                FMainDS.ATransAnalAttrib.DefaultView.AllowNew = false;

                //Load from server if necessary
                if (FMainDS.ATransaction.DefaultView.Count == 0)
                {
                    dlgStatus.CurrentStatus = Catalog.GetString("Requesting transactions from server...");
                    FMainDS.Merge(TRemote.MFinance.GL.WebConnectors.LoadATransactionATransAnalAttrib(ALedgerNumber, ABatchNumber, AJournalNumber));
                }
                else if (FMainDS.ATransAnalAttrib.DefaultView.Count == 0) // just in case transactions have been loaded in a separate process without analysis attributes
                {
                    dlgStatus.CurrentStatus = Catalog.GetString("Requesting analysis attributes from server...");
                    FMainDS.Merge(TRemote.MFinance.GL.WebConnectors.LoadATransAnalAttribForJournal(ALedgerNumber, ABatchNumber, AJournalNumber));
                }

                FContainsSystemGenerated = false;

                // check if any of the rows are system generated (i.e. reversals)
                foreach (DataRowView rv in FMainDS.ATransaction.DefaultView)
                {
                    if (((ATransactionRow)rv.Row).SystemGenerated)
                    {
                        FContainsSystemGenerated = true;
                        break;
                    }
                }

                // We need to call this because we have not called ShowData(), which would have set it.  This differs from the Gift screen.
                grdDetails.DataSource = new DevAge.ComponentModel.BoundDataView(FMainDS.ATransaction.DefaultView);

                // Now we set the full filter
                dlgStatus.CurrentStatus = Catalog.GetString("Selecting the records...");
                FFilterAndFindObject.ApplyFilter();

                dlgStatus.CurrentStatus = Catalog.GetString("Configuring analysis attributes ...");

                if (grdAnalAttributes.Columns.Count == 1)
                {
                    grdAnalAttributes.SpecialKeys = GridSpecialKeys.Default | GridSpecialKeys.Tab;

                    FcmbAnalAttribValues = new SourceGrid.Cells.Editors.ComboBox(typeof(string));
                    FcmbAnalAttribValues.EnableEdit = true;
                    FcmbAnalAttribValues.EditableMode = EditableMode.Focus;
                    grdAnalAttributes.AddTextColumn(Catalog.GetString("Value"),
                        FMainDS.ATransAnalAttrib.Columns[ATransAnalAttribTable.GetAnalysisAttributeValueDBName()], 150,
                        FcmbAnalAttribValues);
                    FcmbAnalAttribValues.Control.SelectedValueChanged += new EventHandler(this.AnalysisAttributeValueChanged);

                    grdAnalAttributes.Columns[0].Width = 99;
                }

                grdAnalAttributes.DataSource = new DevAge.ComponentModel.BoundDataView(FMainDS.ATransAnalAttrib.DefaultView);
                grdAnalAttributes.SetHeaderTooltip(0, Catalog.GetString("Type"));
                grdAnalAttributes.SetHeaderTooltip(1, Catalog.GetString("Value"));

                // if this form is readonly or batch is posted, then we need all account and cost centre codes, because old codes might have been used
                bool ActiveOnly = false; //(this.Enabled && FIsUnposted && !FContainsSystemGenerated);

                if (requireControlSetup || (FActiveOnly != ActiveOnly))
                {
                    FActiveOnly = ActiveOnly;

                    //Load all analysis attribute values
                    if (FCacheDS == null)
                    {
                        dlgStatus.CurrentStatus = Catalog.GetString("Loading analysis attributes ...");
                        FCacheDS = TRemote.MFinance.GL.WebConnectors.LoadAAnalysisAttributes(FLedgerNumber, FActiveOnly);
                    }

                    SetupExtraGridFunctionality();

                    dlgStatus.CurrentStatus = Catalog.GetString("Initialising accounts and cost centres ...");

                    // We suppress change detection because these are the correct values
                    // Then initialise our combo boxes for the correct account codes and cost centres
                    bool prevSuppressChangeDetection = FPetraUtilsObject.SuppressChangeDetection;
                    FPetraUtilsObject.SuppressChangeDetection = true;
                    TFinanceControls.InitialiseAccountList(ref cmbDetailAccountCode, FLedgerNumber,
                        true, false, ActiveOnly, false, ACurrencyCode, true);
                    TFinanceControls.InitialiseCostCentreList(ref cmbDetailCostCentreCode, FLedgerNumber, true, false, ActiveOnly, false);
                    FPetraUtilsObject.SuppressChangeDetection = prevSuppressChangeDetection;

                    cmbDetailCostCentreCode.AttachedLabel.Text = TFinanceControls.SELECT_VALID_COST_CENTRE;
                    cmbDetailAccountCode.AttachedLabel.Text = TFinanceControls.SELECT_VALID_ACCOUNT;
                }

                UpdateTransactionTotals();
                grdDetails.ResumeLayout();
                FLoadCompleted = true;

                ShowData();
                SelectRowInGrid(1);
                ShowDetails(); //Needed because of how currency is handled
                UpdateChangeableStatus();

                UpdateRecordNumberDisplay();
                FFilterAndFindObject.SetRecordNumberDisplayProperties();

                //Check for missing analysis attributes and their values
                if (FIsUnposted && (grdDetails.Rows.Count > 1))
                {
                    string updatedTransactions = string.Empty;

                    dlgStatus.CurrentStatus = Catalog.GetString("Checking analysis attributes ...");
                    FAnalysisAttributesLogic.ReconcileTransAnalysisAttributes(FMainDS, FCacheDS, out updatedTransactions);

                    if (updatedTransactions.Length > 0)
                    {
                        //Remove trailing comma
                        updatedTransactions = updatedTransactions.Remove(updatedTransactions.Length - 2);
                        MessageBox.Show(String.Format(Catalog.GetString(
                                    "Analysis Attributes have been updated in transaction(s): {0}.{1}{1}Remeber to set their values before posting!"),
                                updatedTransactions,
                                Environment.NewLine),
                            "Analysis Attributes",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information);

                        FPetraUtilsObject.SetChangedFlag();
                    }
                }

                RefreshAnalysisAttributesGrid();
            }
            catch (Exception ex)
            {
                TLogging.Log(String.Format("Method:{0} - Unexpected error!{1}{1}{2}",
                        Utilities.GetMethodSignature(),
                        Environment.NewLine,
                        ex.Message));
                throw ex;
            }
            finally
            {
                if (dlgStatus != null)
                {
                    dlgStatus.Close();
                }

                this.Cursor = Cursors.Default;
            }

            return DifferentBatchSelected;
        }
        /// <summary>
        /// load the gifts into the grid
        /// </summary>
        /// <param name="ALedgerNumber"></param>
        /// <param name="ABatchNumber"></param>
        /// <param name="ABatchStatus"></param>
        /// <param name="AForceLoadFromServer">Set to true to get data from the server even though it is apparently the current batch number and status</param>
        /// <returns>True if gift transactions were loaded from server, false if transactions had been loaded already.</returns>
        public bool LoadGifts(Int32 ALedgerNumber, Int32 ABatchNumber, string ABatchStatus, bool AForceLoadFromServer = false)
        {
            //Set key flags
            bool FirstGiftTransLoad = (FLedgerNumber == -1);
            bool SameCurrentBatch =
                ((FLedgerNumber == ALedgerNumber) && (FBatchNumber == ABatchNumber) && (FBatchStatus == ABatchStatus) && !AForceLoadFromServer);

            //Read key fields
            FBatchRow = GetBatchRow();

            if ((FBatchRow == null) && (GetAnyBatchRow(ABatchNumber) == null))
            {
                MessageBox.Show(String.Format("Cannot load transactions for Gift Batch {0} as the batch is not currently loaded!", ABatchNumber));
                return false;
            }

            FLedgerNumber = ALedgerNumber;
            FBatchNumber = ABatchNumber;
            FBatchStatus = ABatchStatus;
            FBatchUnposted = (FBatchStatus == MFinanceConstants.BATCH_UNPOSTED);
            FBatchCurrencyCode = FBatchRow.CurrencyCode;
            FBatchMethodOfPayment = FBatchRow.MethodOfPaymentCode;

            if (FirstGiftTransLoad)
            {
                InitialiseControls();
            }

            UpdateCurrencySymbols(FBatchRow.CurrencyCode);

            //Check if the same batch is selected, so no need to apply filter
            if (SameCurrentBatch)
            {
                //Same as previously selected and we have not been asked to force a full refresh
                if (FBatchUnposted && (GetSelectedRowIndex() > 0))
                {
                    if (FGLEffectivePeriodChanged)
                    {
                        //Just in case for the currently selected row, the date field has not been updated
                        FGLEffectivePeriodChanged = false;
                        GetSelectedDetailRow().DateEntered = FBatchRow.GlEffectiveDate;
                        dtpDateEntered.Date = FBatchRow.GlEffectiveDate;
                    }

                    //Same as previously selected
                    if (GetSelectedRowIndex() > 0)
                    {
                        GetDetailsFromControls(GetSelectedDetailRow());
                    }
                }

                UpdateControlsProtection();

                if (FBatchUnposted
                    && ((FBatchCurrencyCode != FBatchRow.CurrencyCode)
                        || (FBatchExchangeRateToBase != FBatchRow.ExchangeRateToBase)))
                {
                    UpdateBaseAmount(false);
                }

                return false;
            }

            //New set of transactions to be loaded
            TFrmStatusDialog dlgStatus = new TFrmStatusDialog(FPetraUtilsObject.GetForm());

            if (FShowStatusDialogOnLoad == true)
            {
                dlgStatus.Show();
                FShowStatusDialogOnLoad = false;
                dlgStatus.Heading = String.Format(Catalog.GetString("Batch {0}"), ABatchNumber);
                dlgStatus.CurrentStatus = Catalog.GetString("Loading transactions ...");
            }

            FGiftTransactionsLoaded = false;
            FSuppressListChanged = true;

            //Apply new filter
            FPreviouslySelectedDetailRow = null;
            grdDetails.DataSource = null;

            // if this form is readonly, then we need all codes, because old (inactive) codes might have been used
            if (FirstGiftTransLoad || (FActiveOnly == (ViewMode || !FBatchUnposted)))
            {
                FActiveOnly = !(ViewMode || !FBatchUnposted);
                dlgStatus.CurrentStatus = Catalog.GetString("Initialising controls ...");

                try
                {
                    //Without this, the Save button enables even for Posted batches!
                    FPetraUtilsObject.SuppressChangeDetection = true;

                    TFinanceControls.InitialiseMotivationGroupList(ref cmbDetailMotivationGroupCode, FLedgerNumber, FActiveOnly);
                    TFinanceControls.InitialiseMotivationDetailList(ref cmbDetailMotivationDetailCode, FLedgerNumber, FActiveOnly);
                    TFinanceControls.InitialiseMethodOfGivingCodeList(ref cmbDetailMethodOfGivingCode, FActiveOnly);
                    TFinanceControls.InitialiseMethodOfPaymentCodeList(ref cmbDetailMethodOfPaymentCode, FActiveOnly);
                    TFinanceControls.InitialisePMailingList(ref cmbDetailMailingCode, FActiveOnly);
                }
                finally
                {
                    FPetraUtilsObject.SuppressChangeDetection = false;
                }
            }

            // This sets the incomplete filter but does check the panel enabled state
            ShowData();

            // This sets the main part of the filter but excluding the additional items set by the user GUI
            // It gets the right sort order
            SetGiftDetailDefaultView();

            // only load from server if there are no transactions loaded yet for this batch
            // otherwise we would overwrite transactions that have already been modified
            if (FMainDS.AGiftDetail.DefaultView.Count == 0)
            {
                dlgStatus.CurrentStatus = Catalog.GetString("Requesting transactions from server ...");
                LoadGiftDataForBatch(ALedgerNumber, ABatchNumber);
            }

            //Check if need to update batch period in each gift
            if (FBatchUnposted)
            {
                dlgStatus.CurrentStatus = Catalog.GetString("Updating batch period ...");
                ((TFrmGiftBatch)ParentForm).GetBatchControl().UpdateBatchPeriod();
            }

            // Now we set the full filter
            FFilterAndFindObject.ApplyFilter();
            UpdateRecordNumberDisplay();
            FFilterAndFindObject.SetRecordNumberDisplayProperties();

            SelectRowInGrid(1);

            UpdateControlsProtection();

            FSuppressListChanged = false;

            dlgStatus.CurrentStatus = Catalog.GetString("Updating totals for the batch ...");
            UpdateTotals();

            if ((FPreviouslySelectedDetailRow != null) && (FBatchUnposted))
            {
                bool disableSave = (FBatchRow.RowState == DataRowState.Unchanged && !FPetraUtilsObject.HasChanges);

                if (disableSave && FPetraUtilsObject.HasChanges && !DataUtilities.DataRowColumnsHaveChanged(FBatchRow))
                {
                    FPetraUtilsObject.DisableSaveButton();
                }
            }

            FGiftTransactionsLoaded = true;
            dlgStatus.Close();

            return true;
        }