/// <summary> /// Inserts subtotals into an enumerable set of flights, returning an enumerable set of LogbookPrintedPages. /// </summary> /// <param name="lstIn">The input set of flights. Should be ALL RowType=Flight and should have rowheight property set</param> /// <param name="po">Options that guide pagination</param> /// <returns>A new enumerable with per-page subtotals and (optional) running totals</returns> public static IEnumerable <LogbookPrintedPage> Paginate(IEnumerable <LogbookEntryDisplay> lstIn, PrintingOptions po) { if (lstIn == null) { throw new ArgumentNullException(nameof(lstIn)); } if (po == null) { throw new ArgumentNullException(nameof(po)); } int cIn = lstIn.Count(); if (cIn == 0) { return(Array.Empty <LogbookPrintedPage>()); } // For speed, cache the names of each category/class Dictionary <int, string> dictCatClasses = new Dictionary <int, string>(); foreach (CategoryClass cc in CategoryClass.CategoryClasses()) { dictCatClasses.Add(cc.IDCatClassAsInt, cc.CatClass); } List <LogbookPrintedPage> lstOut = new List <LogbookPrintedPage>(); Dictionary <string, LogbookEntryDisplay> dictPageTotals = null, dictPreviousTotals, dictRunningTotals = new Dictionary <string, LogbookEntryDisplay>(); List <LogbookEntryDisplay> lstFlightsThisPage = null; LogbookPrintedPage currentPage = null; int flightIndexOnPage = 0; int index = 0; int pageNum = 0; DateTime?dtLastEntry = null; foreach (LogbookEntryDisplay led in lstIn) { // force a page break if a new month is starting IF the option to do so has been set if (po.FlightsPerPage > 0 && po.BreakAtMonthBoundary && dtLastEntry != null && dtLastEntry.HasValue && (led.Date.Month != dtLastEntry.Value.Month || led.Date.Year != dtLastEntry.Value.Year)) { flightIndexOnPage = po.FlightsPerPage; } dtLastEntry = led.Date; led.SetOptionalColumns(po.OptionalColumns); if ((po.FlightsPerPage > 0 && flightIndexOnPage >= po.FlightsPerPage) || currentPage == null) // need to start a new page. { flightIndexOnPage = 0; // reset dictPageTotals = new Dictionary <string, LogbookEntryDisplay>(); // COPY the running totals to the new previous totals, since AddFrom modifies the object, dictPreviousTotals = new Dictionary <string, LogbookEntryDisplay>(); Dictionary <string, LogbookEntryDisplay> dictNewRunningTotals = new Dictionary <string, LogbookEntryDisplay>(); foreach (string szKeySrc in dictRunningTotals.Keys) { LogbookEntryDisplay ledRunningNew = JsonConvert.DeserializeObject <LogbookEntryDisplay>(JsonConvert.SerializeObject(dictRunningTotals[szKeySrc])); ledRunningNew.RowType = LogbookEntryDisplay.LogbookRowType.PreviousTotal; dictPreviousTotals[szKeySrc] = ledRunningNew; ledRunningNew = JsonConvert.DeserializeObject <LogbookEntryDisplay>(JsonConvert.SerializeObject(dictRunningTotals[szKeySrc])); ledRunningNew.RowType = LogbookEntryDisplay.LogbookRowType.RunningTotal; dictNewRunningTotals[szKeySrc] = ledRunningNew; } dictRunningTotals = dictNewRunningTotals; // set up for the new page to pick up where the last one left off... lstFlightsThisPage = new List <LogbookEntryDisplay>(); currentPage = new LogbookPrintedPage() { RunningTotals = dictRunningTotals, TotalsPreviousPages = dictPreviousTotals, TotalsThisPage = dictPageTotals, Flights = lstFlightsThisPage, PageNum = ++pageNum }; lstOut.Add(currentPage); } flightIndexOnPage += led.RowHeight; string szCatClassKey = dictCatClasses[led.EffectiveCatClass]; // should never not be present!! led.Index = ++index; // Add the flight to the page lstFlightsThisPage.Add(led); // And add the flight to the page catclass totals and running catclass totals if (po.FlightsPerPage > 0) { if (!dictPageTotals.ContainsKey(szCatClassKey)) { dictPageTotals[szCatClassKey] = new LogbookEntryDisplay(po.OptionalColumns) { RowType = LogbookEntryDisplay.LogbookRowType.PageTotal, CatClassDisplay = szCatClassKey } } ; dictPageTotals[szCatClassKey].AddFrom(led); } if (!dictRunningTotals.ContainsKey(szCatClassKey)) { dictRunningTotals[szCatClassKey] = new LogbookEntryDisplay(po.OptionalColumns) { RowType = LogbookEntryDisplay.LogbookRowType.RunningTotal, CatClassDisplay = szCatClassKey } } ; dictRunningTotals[szCatClassKey].AddFrom(led); } // Assign page number, and index totals foreach (LogbookPrintedPage lpp in lstOut) { // And add unstriped totals as needed ConsolidateTotals(lpp.TotalsThisPage, LogbookEntryDisplay.LogbookRowType.PageTotal, po.OptionalColumns); ConsolidateTotals(lpp.TotalsPreviousPages, LogbookEntryDisplay.LogbookRowType.PreviousTotal, po.OptionalColumns); ConsolidateTotals(lpp.RunningTotals, LogbookEntryDisplay.LogbookRowType.RunningTotal, po.OptionalColumns); lpp.TotalPages = pageNum; int iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.TotalsThisPage.Values) { lep.Index = iTotal++; } iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.TotalsPreviousPages.Values) { lep.Index = iTotal++; } iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.RunningTotals.Values) { lep.Index = iTotal++; } if (!po.StripeSubtotalsByCategoryClass) { RemoveStripedSubtotals(lpp.TotalsThisPage); RemoveStripedSubtotals(lpp.TotalsPreviousPages); RemoveStripedSubtotals(lpp.RunningTotals); } if (!po.IncludePullForwardTotals) { lpp.TotalsPreviousPages.Clear(); } } return(lstOut); }
/// <summary> /// Inserts subtotals into an enumerable set of flights, returning an enumerable set of LogbookPrintedPages. /// </summary> /// <param name="lstIn">The input set of flights. Should be ALL RowType=Flight and should have rowheight property set</param> /// <param name="pageSize">Max # of flights per table to subtotal; flights with rowheight > 1 will take up more rows</param> /// <param name="optionalColumns">Any optional columns to add</param> /// <param name="pullForwardTotals">Whether or not to pull forward totals from the previous page</param> /// <returns>A new enumerable with per-page subtotals and (optional) running totals</returns> public static IEnumerable <LogbookPrintedPage> Paginate(IEnumerable <LogbookEntryDisplay> lstIn, int pageSize, OptionalColumn[] optionalColumns, bool pullForwardTotals) { if (lstIn == null) { throw new ArgumentNullException("lstIn"); } int cIn = lstIn.Count(); if (cIn == 0) { return(new LogbookPrintedPage[0]); } // For speed, cache the names of each category/class Dictionary <int, string> dictCatClasses = new Dictionary <int, string>(); foreach (CategoryClass cc in CategoryClass.CategoryClasses()) { dictCatClasses.Add(cc.IDCatClassAsInt, cc.CatClass); } List <LogbookPrintedPage> lstOut = new List <LogbookPrintedPage>(); Dictionary <string, LogbookEntryDisplay> dictPageTotals = null, dictPreviousTotals = new Dictionary <string, LogbookEntryDisplay>(), dictRunningTotals = new Dictionary <string, LogbookEntryDisplay>(); List <LogbookEntryDisplay> lstFlightsThisPage = null; LogbookPrintedPage currentPage = null; int flightIndexOnPage = 0; int index = 0; int pageNum = 0; foreach (LogbookEntryDisplay led in lstIn) { led.OptionalColumns = optionalColumns; if ((pageSize > 0 && flightIndexOnPage >= pageSize) || currentPage == null) // need to start a new page. { flightIndexOnPage = 0; // reset dictPageTotals = new Dictionary <string, LogbookEntryDisplay>(); // COPY the running totals to the new previous totals, since AddFrom modifies the object, dictPreviousTotals = new Dictionary <string, LogbookEntryDisplay>(); Dictionary <string, LogbookEntryDisplay> dictNewRunningTotals = new Dictionary <string, LogbookEntryDisplay>(); foreach (string szKeySrc in dictRunningTotals.Keys) { LogbookEntryDisplay ledRunningNew = JsonConvert.DeserializeObject <LogbookEntryDisplay>(JsonConvert.SerializeObject(dictRunningTotals[szKeySrc])); ledRunningNew.RowType = LogbookEntryDisplay.LogbookRowType.PreviousTotal; dictPreviousTotals[szKeySrc] = ledRunningNew; ledRunningNew = JsonConvert.DeserializeObject <LogbookEntryDisplay>(JsonConvert.SerializeObject(dictRunningTotals[szKeySrc])); ledRunningNew.RowType = LogbookEntryDisplay.LogbookRowType.RunningTotal; dictNewRunningTotals[szKeySrc] = ledRunningNew; } dictRunningTotals = dictNewRunningTotals; // set up for the new page to pick up where the last one left off... lstFlightsThisPage = new List <LogbookEntryDisplay>(); currentPage = new LogbookPrintedPage() { RunningTotals = dictRunningTotals, TotalsPreviousPages = dictPreviousTotals, TotalsThisPage = dictPageTotals, Flights = lstFlightsThisPage, PageNum = ++pageNum }; lstOut.Add(currentPage); } flightIndexOnPage += led.RowHeight; string szCatClassKey = dictCatClasses[led.EffectiveCatClass]; // should never not be present!! led.Index = ++index; // Add the flight to the page lstFlightsThisPage.Add(led); // And add the flight to the page catclass totals and running catclass totals if (pageSize > 0) { if (!dictPageTotals.ContainsKey(szCatClassKey)) { dictPageTotals[szCatClassKey] = new LogbookEntryDisplay() { RowType = LogbookEntryDisplay.LogbookRowType.PageTotal, CatClassDisplay = szCatClassKey, OptionalColumns = optionalColumns } } ; dictPageTotals[szCatClassKey].AddFrom(led); } if (!dictRunningTotals.ContainsKey(szCatClassKey)) { dictRunningTotals[szCatClassKey] = new LogbookEntryDisplay() { RowType = LogbookEntryDisplay.LogbookRowType.RunningTotal, CatClassDisplay = szCatClassKey, OptionalColumns = optionalColumns } } ; dictRunningTotals[szCatClassKey].AddFrom(led); } // Assign page number, and index totals foreach (LogbookPrintedPage lpp in lstOut) { // And add unstriped totals as needed ConsolidateTotals(lpp.TotalsThisPage, LogbookEntryDisplay.LogbookRowType.PageTotal, optionalColumns); ConsolidateTotals(lpp.TotalsPreviousPages, LogbookEntryDisplay.LogbookRowType.PreviousTotal, optionalColumns); ConsolidateTotals(lpp.RunningTotals, LogbookEntryDisplay.LogbookRowType.RunningTotal, optionalColumns); lpp.TotalPages = pageNum; int iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.TotalsThisPage.Values) { lep.Index = iTotal++; } iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.TotalsPreviousPages.Values) { lep.Index = iTotal++; } iTotal = 0; foreach (LogbookEntryDisplay lep in lpp.RunningTotals.Values) { lep.Index = iTotal++; } if (!pullForwardTotals) { lpp.TotalsPreviousPages.Clear(); } } return(lstOut); }
public static PrintLayout LayoutLogbook(Profile pf, IList <LogbookEntryDisplay> lstFlights, IPrintingTemplate pt, PrintingOptions printingOptions, bool fSuppressFooter) { if (pf == null) { throw new ArgumentNullException(nameof(pf)); } if (pt == null) { throw new ArgumentNullException(nameof(pt)); } if (printingOptions == null) { throw new ArgumentNullException(nameof(printingOptions)); } if (lstFlights == null) { throw new ArgumentNullException(nameof(lstFlights)); } PrintLayout pl = PrintLayout.LayoutForType(printingOptions.Layout, pf); // Exclude both excluded properties and properties that have been moved to their own columns HashSet <int> lstPropsToExclude = new HashSet <int>(printingOptions.ExcludedPropertyIDs); HashSet <int> lstPropsInOwnColumns = new HashSet <int>(); foreach (OptionalColumn oc in printingOptions.OptionalColumns) { if (oc.ColumnType == OptionalColumnType.CustomProp) { lstPropsInOwnColumns.Add(oc.IDPropType); } } string szPropSeparator = printingOptions.PropertySeparatorText; // set up properties per flight, and compute rough lineheight foreach (LogbookEntryDisplay led in lstFlights) { // Fix up properties according to the printing options List <CustomFlightProperty> lstProps = new List <CustomFlightProperty>(led.CustomProperties); // And fix up model as well. switch (printingOptions.DisplayMode) { case PrintingOptions.ModelDisplayMode.Full: break; case PrintingOptions.ModelDisplayMode.Short: led.ModelDisplay = led.ShortModelName; break; case PrintingOptions.ModelDisplayMode.ICAO: led.ModelDisplay = led.FamilyName; break; } // Remove from the total property set all explicitly excluded properties... lstProps.RemoveAll(cfp => lstPropsToExclude.Contains(cfp.PropTypeID)); // ...and then additionally exclude from the display any that's in its own column to avoid redundancy. lstProps.RemoveAll(cfp => lstPropsInOwnColumns.Contains(cfp.PropTypeID)); led.CustPropertyDisplay = CustomFlightProperty.PropListDisplay(lstProps, pf.UsesHHMM, szPropSeparator); if (printingOptions.IncludeImages) { led.PopulateImages(true); } if (!printingOptions.IncludeSignatures) { led.CFISignatureState = LogbookEntryBase.SignatureState.None; } led.RowHeight = pl.RowHeight(led); } pt.BindPages(LogbookPrintedPage.Paginate(lstFlights, printingOptions), pf, printingOptions, !fSuppressFooter); return(pl); }