private String GetRowDescr(TResult row) { String ReturnValue; ReturnValue = ""; if ((row.header != null) && (row.header[0].ToString().Length > 0)) { if (ReturnValue.Length > 0) { ReturnValue = ReturnValue + " "; } ReturnValue = ReturnValue + row.header[0].ToString(); } if ((row.header != null) && (row.header[1].ToString().Length > 0)) { if (ReturnValue.Length > 0) { ReturnValue = ReturnValue + " "; } ReturnValue = ReturnValue + row.header[1].ToString(); } if ((row.descr != null) && (row.descr[0].ToString().Length > 0)) { if (ReturnValue.Length > 0) { ReturnValue = ReturnValue + " "; } ReturnValue = ReturnValue + row.descr[0].ToString(); } if ((row.descr != null) && (row.descr[1].ToString().Length > 0)) { if (ReturnValue.Length > 0) { ReturnValue = ReturnValue + " "; } ReturnValue = ReturnValue + row.descr[1].ToString(); } return ReturnValue; }
/// <summary> /// find the next sibling of the parent row /// </summary> /// <param name="currentRow"></param> /// <returns></returns> protected TResult FindNextUncle(TResult currentRow) { TResult ReturnValue; ReturnValue = null; if (currentRow.masterRow > 0) { ReturnValue = FindNextRow(FindRow(currentRow.masterRow)); } if (ReturnValue != null) { FNextElementLineToPrint[ReturnValue.depth] = eStageElementPrinting.eHeader; } return ReturnValue; }
/// <summary> /// find the next row on the same level /// </summary> /// <param name="currentRow"></param> /// <returns></returns> protected TResult FindNextSibling(TResult currentRow) { TResult ReturnValue; Int32 i; Int32 masterRow; Int32 childRow; // if currentRow is nil assume the root (needed to find first printable element) if (currentRow != null) { masterRow = currentRow.masterRow; childRow = currentRow.childRow; } else { masterRow = 0; childRow = 0; } ReturnValue = null; foreach (TResult row in FResults) { if (row.masterRow == masterRow) { if ((row.childRow > childRow) && ((ReturnValue == null) || (row.childRow < ReturnValue.childRow))) { if ((row.depth == 1) && (FLowestLevel != 1) && (FParameters.GetOrDefault("HasSubReports", -1, new TVariant(false)).ToBool() == true)) { // reset the FLowestLevel, because this is basically a new report (several lowerlevelreports in main level) // todo: be careful: some reports have several rows in the main level, I just assumed one total for the finance reports // it works now for reports with just one row depth, for others this still needs to be sorted properly. another parameter? FLowestLevel = FResultList.GetDeepestVisibleLevel(row.childRow); FPrinter.LineSpaceFeed(eFont.eDefaultFont); FPrinter.DrawLine(FPrinter.LeftMargin, FPrinter.RightMargin, eLinePosition.eAbove, eFont.eDefaultBoldFont); FPrinter.LineSpaceFeed(eFont.eDefaultFont); FParameters.Add("CurrentSubReport", FParameters.Get("CurrentSubReport").ToInt() + 1); for (i = 0; i <= FLowestLevel; i += 1) { FNextElementLineToPrint.Add(eStageElementPrinting.eHeader); } FNextElementLineToPrint[FLowestLevel] = eStageElementPrinting.eDetails; } ReturnValue = row; FNextElementLineToPrint[ReturnValue.depth] = eStageElementPrinting.eHeader; } } } return ReturnValue; }
/// <summary> /// find first row that is in the hierarchy below the current row /// </summary> /// <param name="currentRow"></param> /// <returns></returns> protected TResult FindFirstChild(TResult currentRow) { TResult ReturnValue; ReturnValue = null; foreach (TResult row in FResults) { if ((row.masterRow == currentRow.childRow) && (row.depth <= FLowestLevel)) { if ((ReturnValue == null) || (row.childRow < ReturnValue.childRow)) { ReturnValue = row; } } } return ReturnValue; }
/// <summary> /// can either print or simulate /// </summary> /// <returns>s the current y position after printing or simulating /// </returns> protected virtual double PrintNormalLevelFooter(TResult row) { return 0.0; }
/// <summary> /// copy constructor; creates a copy of the given object /// /// </summary> /// <returns>void</returns> public TResult(TResult copy) { Assign(copy); }
/// <summary> /// print the lowest level (no children) /// </summary> /// <param name="row"></param> /// <returns></returns> protected virtual Boolean PrintLowestLevel(TResult row) { return false; }
/// <summary> /// print a normal level /// </summary> /// <param name="row"></param> /// <returns></returns> protected Boolean PrintNormalLevel(TResult row) { if ((eStageElementPrinting)FNextElementLineToPrint[row.depth] == eStageElementPrinting.eHeader) { if (!PrintNormalLevelHeader(row)) { return false; } } if ((eStageElementPrinting)FNextElementLineToPrint[row.depth] == eStageElementPrinting.eDetails) { if (!PrintNormalLevelDetails(row)) { return false; } } if ((eStageElementPrinting)FNextElementLineToPrint[row.depth] == eStageElementPrinting.eFooter) { // try if footer will still fit on the page; it can consist of 2 lines, and there is no page length check in there FPrinter.StartSimulatePrinting(); PrintNormalLevelFooter(row); if (!FPrinter.ValidYPos()) { // not enoughSpace FPrinter.FinishSimulatePrinting(); FNextElementLineToPrint[row.depth] = eStageElementPrinting.eFooter; FNextElementToPrint = row.childRow; return false; } FPrinter.FinishSimulatePrinting(); PrintNormalLevelFooter(row); } return true; }
/// <summary> /// print the lowest level (has no child levels) /// </summary> /// <param name="row"></param> /// <returns></returns> protected override Boolean PrintLowestLevel(TResult row) { Boolean ReturnValue; String descr0 = ""; String descr1 = ""; if (!FPrinter.ValidYPos()) { // not enoughSpace ReturnValue = false; FNextElementToPrint = row.childRow; FNextElementLineToPrint[row.depth] = eStageElementPrinting.eDetails; } else { // can either print descr or header if ((row.descr != null) && (row.descr[0].ToString().Length > 0)) { descr0 = row.descr[0].ToString(); } else if ((row.header != null) && (row.header[0].ToString().Length > 0)) { descr0 = row.header[0].ToString(); } if ((row.descr != null) && (row.descr[1].ToString().Length > 0)) { descr1 = row.descr[1].ToString(); } else if ((row.header != null) && (row.header[1].ToString().Length > 0)) { descr1 = row.header[1].ToString(); } FPrinter.PrintString(descr0, eFont.eDefaultFont, GetPosition(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(COLUMNLEFT1_POS)), GetWidth(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(1)), GetAlignment(ReportingConsts.COLUMNLEFT + 1, row.depth, eAlignment.eLeft)); FPrinter.PrintString(descr1, eFont.eDefaultFont, GetPosition(ReportingConsts.COLUMNLEFT + 2, row.depth, FPrinter.Cm(COLUMNLEFT2_POS)), GetWidth(ReportingConsts.COLUMNLEFT + 2, row.depth, FPrinter.Cm(3)), GetAlignment(ReportingConsts.COLUMNLEFT + 2, row.depth, eAlignment.eLeft)); PrintColumns(row); FNextElementLineToPrint[row.depth] = eStageElementPrinting.eFinished; ReturnValue = true; } return ReturnValue; }
/// <summary> /// print all columns of a given row /// </summary> /// <param name="ARow"></param> /// <returns></returns> protected bool PrintColumns(TResult ARow) { Int32 columnNr; float YPosBefore; float LowestYPos; YPosBefore = FPrinter.CurrentYPos; // we need at least one row, otherwise the strings on the left are written in the same row FPrinter.LineFeed(eFont.eDefaultFont); LowestYPos = FPrinter.CurrentYPos; for (columnNr = 0; columnNr <= FNumberColumns - 1; columnNr += 1) { FPrinter.CurrentYPos = YPosBefore; PrintColumn(columnNr, ARow.depth, ARow.column[columnNr]); // store the highest column if (FPrinter.CurrentYPos > LowestYPos) { LowestYPos = FPrinter.CurrentYPos; } } FPrinter.CurrentYPos = LowestYPos; return true; }
/// <summary> /// recalculate row after all the columns have been calculated already, /// but now the functions based on other columns are calculated. /// </summary> /// <param name="situation"></param> /// <param name="row"></param> public static void RecalculateRow(TRptSituation situation, TResult row) { int counter; string strCalculation; TVariant ColumnCalc; TVariant levelCalc; TRptDataCalcResult rptDataCalcResult; String ColumnFormat; TVariant value; for (counter = 0; counter <= row.column.Length - 1; counter += 1) { // calculation is used for display in the GUI, formula is used for adding ledgers ColumnCalc = situation.GetParameters().Get("param_formula", counter, -1, eParameterFit.eExact); if (ColumnCalc.IsZeroOrNull()) { ColumnCalc = situation.GetParameters().Get("param_calculation", counter, -1, eParameterFit.eExact); } levelCalc = situation.GetParameters().Get("param_formula", ReportingConsts.ALLCOLUMNS, row.depth, eParameterFit.eExact); if (levelCalc.IsZeroOrNull()) { levelCalc = situation.GetParameters().Get("param_calculation", ReportingConsts.ALLCOLUMNS, row.depth, eParameterFit.eExact); } strCalculation = ""; if ((!ColumnCalc.IsZeroOrNull() && situation.GetReportStore().IsFunctionCalculation(situation.GetCurrentReport(), ColumnCalc.ToString()))) { // e.g. add(Column(1), Column(2)) strCalculation = ColumnCalc.ToString(); } else if ((!levelCalc.IsZeroOrNull() && situation.GetReportStore().IsFunctionCalculation(situation.GetCurrentReport(), levelCalc.ToString()))) { // e.g. getSumLowerReport strCalculation = levelCalc.ToString(); } if (situation.GetReportStore().IsFunctionCalculation(situation.GetCurrentReport(), strCalculation)) { rptDataCalcResult = new TRptDataCalcResult(situation, row.depth, counter, row.childRow, row.masterRow); ColumnFormat = ""; if (situation.GetParameters().Exists("ColumnFormat", counter, row.depth)) { ColumnFormat = situation.GetParameters().Get("ColumnFormat", counter, row.depth).ToString(); } value = rptDataCalcResult.Precalculate(row.column); value.ApplyFormatString(ColumnFormat); if (value.ToFormattedString().Length > 0) { row.column[counter] = value; } } } }
/// <summary> /// sort the results by their childrow code; using sort by insertion /// needed for excel export /// </summary> /// <returns>void</returns> public Boolean SortChildren() { int left = 0; int right = results.Count - 1; for (int i = left + 1; i <= right; i += 1) { int j = i; TResult current = (TResult)results[j]; TResult tempRow = new TResult(current); TResult previous; if (j > left) { previous = (TResult)results[j - 1]; } else { previous = null; } while ((j > left) && (previous.childRow > tempRow.childRow)) { current = (TResult)results[j]; current.Assign(previous); j--; if (j > left) { previous = (TResult)results[j - 1]; } else { previous = null; } } current = (TResult)results[j]; current.Assign(tempRow); } return true; }
/// <summary> /// add a row to the result /// </summary> /// <param name="masterRow"></param> /// <param name="childRow"></param> /// <param name="display"></param> /// <param name="depth"></param> /// <param name="code"></param> /// <param name="condition"></param> /// <param name="debit_credit_indicator"></param> /// <param name="header"></param> /// <param name="descr"></param> /// <param name="column"></param> /// <returns></returns> public TResult AddRow(int masterRow, int childRow, Boolean display, int depth, String code, string condition, Boolean debit_credit_indicator, TVariant[] header, TVariant[] descr, TVariant[] column) { // // I wonder why we care about this "duplicate code"? Certainly this code generates lots of warnings, but reports are still generated OK: /* * foreach (TResult existingElement in results) * { * if (existingElement.code == code) * { * TLogging.Log("Warning: TResult.AddRow: duplicate row codes! there is already a row with code " + * code); * // throw new Exception("TResult.AddRow: duplicate row codes! there is already a row with code " + * // code); * } * } */ TResult element = new TResult(masterRow, childRow, display, depth, code, condition, debit_credit_indicator, header, descr, column); results.Add(element); return element; }
/// <summary> /// copies the values of the given object into the self object /// /// </summary> /// <returns>void</returns> public void Assign(TResult copy) { int i; this.masterRow = copy.masterRow; this.childRow = copy.childRow; this.display = copy.display; this.depth = copy.depth; this.code = copy.code; this.condition = copy.condition; this.debit_credit_indicator = copy.debit_credit_indicator; for (i = 0; i <= 1; i += 1) { this.header[i] = new TVariant(copy.header[i]); } for (i = 0; i <= 1; i += 1) { this.descr[i] = new TVariant(copy.descr[i]); } column = new TVariant[copy.column.Length]; for (i = 0; i < copy.column.Length; i += 1) { this.column[i] = new TVariant(copy.column[i]); } }
/// <summary> /// find the next sibling of currentRow. /// if there is none, then try to find the next row up one hierarchy /// if currentRow is the last row, return nil /// /// </summary> /// <returns>void</returns> protected TResult FindNextRow(TResult currentRow) { TResult ReturnValue; ReturnValue = FindNextSibling(currentRow); if ((ReturnValue == null) && (currentRow.masterRow > 0)) { // see if the father is already fully printed ReturnValue = FindRow(currentRow.masterRow); if (ReturnValue != null) { if ((eStageElementPrinting)FNextElementLineToPrint[ReturnValue.depth] == eStageElementPrinting.eFinished) { ReturnValue = null; } else { FNextElementLineToPrint[ReturnValue.depth] = eStageElementPrinting.eFooter; } } } if (ReturnValue == null) { ReturnValue = FindNextUncle(currentRow); } return ReturnValue; }
/// <summary> /// print the details of a normal level (not lowest level) /// </summary> /// <param name="row"></param> /// <returns></returns> protected Boolean PrintNormalLevelDetails(TResult row) { Boolean ReturnValue; TResult childRow; FNextElementLineToPrint[row.depth] = eStageElementPrinting.eDetails; childRow = FindFirstChild(row); while (childRow != null) { FNextElementLineToPrint[childRow.depth] = eStageElementPrinting.eHeader; if (!PrintRow(childRow)) { return false; } childRow = FindNextSibling(childRow); } ReturnValue = true; FNextElementLineToPrint[row.depth] = eStageElementPrinting.eFooter; return ReturnValue; }
/// <summary> /// print the header of a normal level /// </summary> /// <param name="row"></param> /// <returns></returns> protected override Boolean PrintNormalLevelHeader(TResult row) { Boolean ReturnValue; Boolean linePrinted; if (!FPrinter.ValidYPos()) { // not enoughSpace FNextElementToPrint = row.childRow; FNextElementLineToPrint[row.depth] = eStageElementPrinting.eHeader; ReturnValue = false; } else { linePrinted = FPrinter.PrintString(row.header[0].ToString(), eFont.eDefaultFont, GetPosition(ReportingConsts.HEADERCOLUMN + 1, row.depth, FPrinter.Cm(COLUMNLEFT1_POS)), GetWidth(ReportingConsts.HEADERCOLUMN + 1, row.depth, FPrinter.Cm(3)), GetAlignment(ReportingConsts.HEADERCOLUMN + 1, row.depth, eAlignment.eLeft)); linePrinted = FPrinter.PrintString(row.header[1].ToString(), eFont.eDefaultFont, GetPosition(ReportingConsts.HEADERCOLUMN + 2, row.depth, FPrinter.Cm(COLUMNLEFT2_POS)), GetWidth(ReportingConsts.HEADERCOLUMN + 2, row.depth, FPrinter.Cm(3)), GetAlignment(ReportingConsts.HEADERCOLUMN + 1, row.depth, eAlignment.eLeft)) || linePrinted; if (linePrinted) { FPrinter.LineFeed(eFont.eDefaultFont); } ReturnValue = true; } FNextElementLineToPrint[row.depth] = eStageElementPrinting.eDetails; return ReturnValue; }
/// <summary> /// prints the current Row /// </summary> /// <returns>s true if all were printed; false if page was full /// side effects: will set the NextElementToPrint /// </returns> protected Boolean PrintRow(TResult row) { Boolean ReturnValue; bool LowestLevel; LowestLevel = false; if (FindFirstChild(row) == null) { // if both descr and header are set, don't use lowestlevel, but normal level // to print both. // situations to test: // a) Account Detail, acc/cc with no transaction, but a balance // b) some situation with analysis attributes on account detail if ((row.descr == null) || (row.header == null)) { LowestLevel = true; } } if (row.depth == FLowestLevel) { LowestLevel = true; } if (LowestLevel) { if (!PrintLowestLevel(row)) { return false; } } else { if (!PrintNormalLevel(row)) { return false; } } ReturnValue = true; FNextElementToPrint = -1; return ReturnValue; }
/// <summary> /// can either print or simulate /// </summary> /// <returns>s the current y position after printing or simulating /// </returns> protected override double PrintNormalLevelFooter(TResult row) { Boolean linePrinted; linePrinted = false; // footer if (FParameters.Get("SpaceLineAbove", -1, row.depth, eParameterFit.eExact).ToBool() == true) { FPrinter.LineSpaceFeed(eFont.eDefaultFont); } if (FParameters.Get("FullLineAbove", -1, row.depth, eParameterFit.eExact).ToBool() == true) { FPrinter.DrawLine(FPrinter.LeftMargin, FPrinter.Width, eLinePosition.eAbove, eFont.eDefaultFont); FPrinter.LineSpaceFeed(eFont.eDefaultFont); } FPrinter.PrintString(row.descr[0].ToString(), eFont.eDefaultFont, GetPosition(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(COLUMNLEFT1_POS)), GetWidth(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(3)), GetAlignment(ReportingConsts.COLUMNLEFT + 1, row.depth, eAlignment.eLeft)); PrintColumns(row); linePrinted = FPrinter.PrintString(row.descr[1].ToString(), eFont.eDefaultFont, GetPosition(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(COLUMNLEFT1_POS)), GetWidth(ReportingConsts.COLUMNLEFT + 1, row.depth, FPrinter.Cm(3)), GetAlignment(ReportingConsts.COLUMNLEFT + 1, row.depth, eAlignment.eLeft)); if (linePrinted) { FPrinter.LineFeed(eFont.eDefaultFont); } if (FParameters.Get("FullLineBelow", -1, row.depth, eParameterFit.eExact).ToBool() == true) { FPrinter.DrawLine(FPrinter.LeftMargin, FPrinter.Width, eLinePosition.eAbove, eFont.eDefaultFont); FPrinter.LineSpaceFeed(eFont.eDefaultFont); } if (FParameters.Get("SpaceLineBelow", -1, row.depth, eParameterFit.eExact).ToBool() == true) { FPrinter.LineSpaceFeed(eFont.eDefaultFont); } FNextElementLineToPrint[row.depth] = eStageElementPrinting.eFinished; return FPrinter.CurrentYPos; }
/// <summary> /// print the header for a normal level (not deepest level) /// </summary> /// <param name="row"></param> /// <returns></returns> protected virtual Boolean PrintNormalLevelHeader(TResult row) { return false; }