/// /// Copyright (c) 2017 Sensus Metering Systems /// using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.IO; using Config.Entities; using Results.Resources; namespace Results.Output.Printers.Enhanced { public class EnhancedPrintDocument : PrintDocument { /// Size of the printed area without margins, after taking into account 'pageOrientation' readonly int printHeight; readonly int printWidth; readonly int topMargin; readonly int bottomMargin; readonly int leftMargin; readonly int TitleX; readonly int TitleY; /// Depends on the size of the header readonly int SpacingOne; readonly int SpacingOneAndHalf; readonly int SpacingOne4Header; readonly int SpacingOneAndHalf4Header; readonly int SpacingOne4Footer; int CommonTop; /// = TitleY + 60 int BodyTop; /// = HdrTop + 160 /// int titleHeight; int commonHeight; /// /// Property variable for the Font the user wishes to use /// Font titleFont; Font headerFont; Font font; Font footerFont; TableStyle style; /// /// Data to print /// Results.Entities.Batch batch; EnhancedPrinterCfg cfg; /// /// Items to print /// string header; IList commonItems; IList testItems; string footer; /// /// Layout and status /// int nrWMsOnFirstPage; int nrWMsOnNextPage; int nextWMNr; /// nr. of watermeter to be printed as the first one on the next page int nrPages; int pageNr; /// Page number to be printed at the bottom of the page /// /// Constructor /// /// Text to be printed public EnhancedPrintDocument(Results.Entities.Batch batch, EnhancedPrinterCfg cfg, string documentName) { this.batch = batch; this.cfg = cfg; DocumentName = documentName; topMargin = cfg.TopMargin; bottomMargin = cfg.BottomMargin; leftMargin = cfg.LeftMargin; header = string.IsNullOrEmpty(cfg.Header) ? string.Empty : cfg.Header.Replace("~", Environment.NewLine); commonItems = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems); testItems = Results.WMeterRsltItemSpec.FromStrArray(cfg.TestItems); /// TestID info will be overwritten later on footer = string.IsNullOrEmpty(cfg.Footer) ? string.Empty : cfg.Footer.Replace("~", Environment.NewLine); /// Initialize fonts titleFont = new Font((cfg.TitFntFml != null ? cfg.TitFntFml : "Arial"), (cfg.TitFntSz > 0 ? cfg.TitFntSz : 10), (FontStyle)cfg.TitFntSty); headerFont = new Font((cfg.HdrFntFml != null ? cfg.HdrFntFml : "Arial"), (cfg.HdrFntSz > 0 ? cfg.HdrFntSz : 10), (FontStyle)cfg.HdrFntSty); font = new Font((cfg.BodyFntFml != null ? cfg.BodyFntFml : "Arial"), (cfg.BodyFntSz > 0 ? cfg.BodyFntSz : 10), (FontStyle)cfg.BodyFntSty); footerFont = new Font((cfg.FooterFntFml != null ? cfg.FooterFntFml : "Arial"), (cfg.FooterFntSz > 0 ? cfg.FooterFntSz : 10), (FontStyle)cfg.FooterFntSty); /// Table style of one water meter table where tests are rows style = new TableStyle { Font = font, HeaderFont = headerFont, MarginX = 5, MarginY = 3, LineWidth = 1, TopHeadersCount = 1, HorizLines = TableLines.FirstSecondAndLast, VertLines = TableLines.All }; /// Set print area size and margins (in dots using 100 dpi) DefaultPageSettings.Landscape = (cfg.PageOrientation == PageOrientation.Landscape); /// if (DefaultPageSettings.Landscape) { printHeight = base.DefaultPageSettings.PaperSize.Width - topMargin - bottomMargin; printWidth = base.DefaultPageSettings.PaperSize.Height - leftMargin - leftMargin; } else { printHeight = base.DefaultPageSettings.PaperSize.Height - topMargin - bottomMargin; printWidth = base.DefaultPageSettings.PaperSize.Width - leftMargin - leftMargin; } /// Document outline preliminary calculations SpacingOne = System.Windows.Forms.TextRenderer.MeasureText("Abcgq", font).Height; SpacingOneAndHalf = (3 * SpacingOne) / 2; SpacingOne4Header = System.Windows.Forms.TextRenderer.MeasureText("Abcgq", headerFont).Height; SpacingOneAndHalf4Header = (3 * SpacingOne4Header) / 2; SpacingOne4Footer = System.Windows.Forms.TextRenderer.MeasureText("Abcgq", footerFont).Height; TitleX = cfg.LeftMargin; TitleY = cfg.TopMargin; pageNr = 1; nextWMNr = 0; } /// /// Override the default onbeginPrint method of the PrintDocument Object /// /// /// protected override void OnBeginPrint(System.Drawing.Printing.PrintEventArgs e) { base.OnBeginPrint(e); } /// /// Override the default OnPrintPage method of the PrintDocument. /// /// /// This provides the print logic for our document protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e) { /// Run base code base.OnPrintPage(e); if (!string.IsNullOrEmpty(cfg.Template)) { string templatePath = Path.Combine("C:\\TBF\\Templates\\", cfg.Template); if (File.Exists(templatePath)) { if (cfg.PageOrientation == PageOrientation.Portrait) e.Graphics.DrawImage(new Bitmap(Image.FromFile(templatePath), 827, 1169), new Rectangle(0, 0, 827, 1169)); else e.Graphics.DrawImage(new Bitmap(Image.FromFile(templatePath), 1169, 827), new Rectangle(0, 0, 1169, 827)); } } /// Use the StringFormat class for the text layout of our document StringFormat format = new StringFormat(StringFormatFlags.LineLimit); if (pageNr == 1) { ///---------- /// Prepare document outline ///---------- titleHeight = System.Windows.Forms.TextRenderer.MeasureText(header, titleFont).Height; CommonTop = TitleY + titleHeight + SpacingOne4Header; commonHeight = commonItems.Count * SpacingOne; BodyTop = CommonTop + commonHeight + SpacingOne4Header; Table table0 = GetTable_TestsAreRows(batch.WaterMeters[0], testItems, style); SizeF tableSize = table0.Measure(e); int wmSectionHeight = (int)tableSize.Height + 3 * SpacingOne4Header; nrWMsOnFirstPage = (printHeight - BodyTop + TitleY - 2 * SpacingOne) / wmSectionHeight; nrWMsOnNextPage = (printHeight - 2 * SpacingOne) / wmSectionHeight; nrWMsOnNextPage = Math.Max(nrWMsOnNextPage, 1); /// Prevent division by zero if there are too many WM tests nrPages = 1 + (batch.WaterMeters.Count - nrWMsOnFirstPage + nrWMsOnNextPage - 1) / nrWMsOnNextPage; ///---------- /// Title ///---------- RectangleF printArea = new RectangleF(TitleX, TitleY, printWidth, titleHeight); e.Graphics.DrawString(header, titleFont, Brushes.Black, printArea); ///---------------- /// Common items ///---------------- string[] leftColumn = new string[commonItems.Count]; string[] rightColumn = new string[commonItems.Count]; int cnt = 0; foreach (var v in commonItems) { leftColumn[cnt] = v.Caption; rightColumn[cnt] = (batch.WaterMeters.Count > 0) ? v.Print(batch.WaterMeters[0]) : string.Empty; cnt++; } /// Determine max. left column width in characters int maxLen = 0; foreach (var s in leftColumn) if (s.Length > maxLen) maxLen = s.Length; /// Write aligned columns for (int i = 0; i < Math.Min(leftColumn.Length, rightColumn.Length); i++) { PrintAt(e, leftMargin, CommonTop + SpacingOne * i, leftColumn[i]); PrintAt(e, 300, CommonTop + SpacingOne * i, rightColumn[i]); } } ///-------- /// Body ///-------- /// This variable represents the top coordinate of the area where WM results are printed /// and it is updated (increased by) the value returned by PrintXyzWM() - the section size. int nextWmTop = (pageNr == 1) ? BodyTop : TitleY; int nrWMsOnPage = (pageNr == 1) ? nrWMsOnFirstPage : nrWMsOnNextPage; for (int wmNr = nextWMNr; wmNr < Math.Min(nextWMNr + nrWMsOnPage, batch.WaterMeters.Count); wmNr++) /// wmNr is 0-based { int wmPosition = true ? batch.WaterMeters[wmNr].WMPosition : (wmNr + 1); nextWmTop = (int)PrintWM(e, batch.WaterMeters[wmNr], wmPosition, nextWmTop) + SpacingOneAndHalf4Header; } nextWMNr += nrWMsOnPage; e.HasMorePages = (nextWMNr < batch.WaterMeters.Count); ///---------- /// Footer ///---------- int footerWidth = (int)e.Graphics.MeasureString(footer, footerFont).Width; PrintFooterAt(e, leftMargin + (printWidth - footerWidth) / 2, topMargin + printHeight - 2 * SpacingOne, footer); string pageNrText = string.Format("{0} {1}/{2}", Strings.Page, pageNr++, nrPages); int pageNrWidth = (int)e.Graphics.MeasureString(pageNrText, font).Width; PrintAt(e, leftMargin + (printWidth - pageNrWidth) / 2, topMargin + printHeight - SpacingOne, pageNrText); } /// /// Print one water meter results /// /// Water meter /// Number of the water meter printed /// Top coordinate of watermeter data /// The height of the printed section float PrintWM(System.Drawing.Printing.PrintPageEventArgs e, Results.Entities.WaterMeter wm, int printedWMNr, int top) { /// Print the water meter number and the serial number string wmText = string.Format("{0} {1}", Strings.Water_Meter, printedWMNr); PrintHeaderAt(e, leftMargin, top, wmText); if (!string.IsNullOrEmpty(wm.SerialNr)) { PrintHeaderAt(e, leftMargin + (int)e.Graphics.MeasureString(wmText, headerFont).Width, top, string.Format(" {0} = {1}", Strings.sn, wm.SerialNr)); } Table table = GetTable_TestsAreRows(wm, testItems, style); return table.Draw(e, leftMargin, top + SpacingOneAndHalf4Header); } void PrintAt(System.Drawing.Printing.PrintPageEventArgs e, Point p, string text) { PrintAt(e, p.X, p.Y, text); } void PrintAt(System.Drawing.Printing.PrintPageEventArgs e, int x, int y, string text) { RectangleF printArea = new RectangleF(x, y, 2000, SpacingOne); e.Graphics.DrawString(text, this.font, Brushes.Black, printArea); } void PrintHeaderAt(System.Drawing.Printing.PrintPageEventArgs e, Point p, string text) { PrintHeaderAt(e, p.X, p.Y, text); } void PrintHeaderAt(System.Drawing.Printing.PrintPageEventArgs e, int x, int y, string text) { RectangleF printArea = new RectangleF(x, y, 2000, SpacingOne4Header); e.Graphics.DrawString(text, this.headerFont, Brushes.Black, printArea); } void PrintFooterAt(System.Drawing.Printing.PrintPageEventArgs e, Point p, string text) { PrintFooterAt(e, p.X, p.Y, text); } void PrintFooterAt(System.Drawing.Printing.PrintPageEventArgs e, int x, int y, string text) { RectangleF printArea = new RectangleF(x, y, 2000, SpacingOne4Footer); e.Graphics.DrawString(text, this.footerFont, Brushes.Black, printArea); } Table GetTable_TestsAreRows(Results.Entities.WaterMeter wm, IList items, TableStyle style) { /// Top row contains column captions Table table = new Table(items.Count); table.Style = style; string[] tableHeader = new string[table.ColumnsCount]; Alignment[] horizAlignment = new Alignment[table.ColumnsCount]; VertAlignment[] vertAlignment = new VertAlignment[table.ColumnsCount]; for (int i = 0; i < table.ColumnsCount; i++) { tableHeader[i] = items[i].Caption; horizAlignment[i] = Alignment.Center; vertAlignment[i] = VertAlignment.Middle; } table.AddRow(tableHeader, horizAlignment, vertAlignment); WMeterRsltItemSpec.TableRowNr = 1; foreach (var mtr in wm.MeterTestRslts) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == Config.Entities.Publish.Always) { string[] oneTableRow = new string[table.ColumnsCount]; horizAlignment = new Alignment[table.ColumnsCount]; vertAlignment = new VertAlignment[table.ColumnsCount]; for (int i = 0; i < table.ColumnsCount; i++) { WMeterRsltItemSpec.TableColumnNr = i + 1; oneTableRow[i] = items[i].Print(wm, mtr.Name()).Split(new char[] { '|' })[0]; horizAlignment[i] = items[i].Alignment; vertAlignment[i] = VertAlignment.Middle; } table.AddRow(oneTableRow, horizAlignment, vertAlignment); WMeterRsltItemSpec.TableRowNr++; } } return table; } } }