424 lines
15 KiB
C#
424 lines
15 KiB
C#
///
|
|
/// 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;
|
|
using Results.Resources;
|
|
|
|
namespace Results.Output.Printers.Zapiska
|
|
{
|
|
public class ZapiskaPrintDocument : PrintDocument
|
|
{
|
|
const int GapBetweenCommonColumns = 10;
|
|
|
|
/// 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 leftMarginCommon1;
|
|
readonly int leftMarginCommon2;
|
|
readonly int leftMarginCommon3;
|
|
readonly int leftMarginBelow1;
|
|
readonly int leftMarginBelow2;
|
|
readonly int leftMarginBelow3;
|
|
|
|
readonly int SpacingOne;
|
|
readonly int SpacingOneAndHalf;
|
|
readonly int SpacingOne4Header;
|
|
readonly int SpacingOneAndHalf4Header;
|
|
|
|
int CommonTop; /// = TitleY + 60
|
|
int BodyTop; /// = HdrTop + 160
|
|
///
|
|
int titleHeight;
|
|
int commonHeight;
|
|
|
|
/// <summary>
|
|
/// Property variable for the Font the user wishes to use
|
|
/// </summary>
|
|
Font font;
|
|
Font headerFont;
|
|
Font titleFont;
|
|
|
|
///
|
|
/// Data to print
|
|
///
|
|
Results.Entities.Batch batch;
|
|
|
|
ZapiskaPrinterCfg cfg;
|
|
|
|
///
|
|
/// Items to print
|
|
///
|
|
string header;
|
|
IList<WMeterRsltItemSpec> commonItems1;
|
|
IList<WMeterRsltItemSpec> commonItems2;
|
|
IList<WMeterRsltItemSpec> commonItems3;
|
|
IList<WMeterRsltItemSpec> selectedItems;
|
|
IList<WMeterRsltItemSpec> belowItems1;
|
|
IList<WMeterRsltItemSpec> belowItems2;
|
|
IList<WMeterRsltItemSpec> belowItems3;
|
|
string footer;
|
|
|
|
///
|
|
/// Layout and status
|
|
///
|
|
int tablesOnFirstPage;
|
|
int tablesOnNextPage;
|
|
int nrPages;
|
|
int pageNr; /// Page number to be printed at the bottom of the page
|
|
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="textToPrint">Text to be printed</param>
|
|
public ZapiskaPrintDocument(Results.Entities.Batch batch, ZapiskaPrinterCfg cfg)
|
|
{
|
|
this.batch = batch;
|
|
|
|
this.cfg = cfg;
|
|
topMargin = cfg.TopMargin;
|
|
bottomMargin = cfg.BottomMargin;
|
|
leftMargin = cfg.LeftMargin;
|
|
|
|
header = string.IsNullOrEmpty(cfg.Header) ? string.Empty : cfg.Header.Replace("~", Environment.NewLine);
|
|
commonItems1 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems1);
|
|
commonItems2 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems2);
|
|
commonItems3 = Results.WMeterRsltItemSpec.FromStrArray(cfg.CommonItems3);
|
|
selectedItems = Results.WMeterRsltItemSpec.FromStrArray(cfg.SelectedItems);
|
|
belowItems1 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems1);
|
|
belowItems2 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems2);
|
|
belowItems3 = Results.WMeterRsltItemSpec.FromStrArray(cfg.BelowItems3);
|
|
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);
|
|
|
|
/// 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;
|
|
}
|
|
|
|
leftMarginCommon1 = leftMargin + (int)(printWidth * cfg.ColW0Pct / 100.0f);
|
|
leftMarginCommon2 = leftMargin + (int)(printWidth * (cfg.ColW0Pct + cfg.ColW1Pct) / 100.0f);
|
|
leftMarginCommon3 = leftMargin + (int)(printWidth * (cfg.ColW0Pct + cfg.ColW1Pct + cfg.ColW2Pct) / 100.0f);
|
|
|
|
leftMarginBelow1 = leftMargin + (int)(printWidth * cfg.BelowW0Pct / 100.0f);
|
|
leftMarginBelow2 = leftMargin + (int)(printWidth * (cfg.BelowW0Pct + cfg.BelowW1Pct) / 100.0f);
|
|
leftMarginBelow3 = leftMargin + (int)(printWidth * (cfg.BelowW0Pct + cfg.BelowW1Pct + cfg.BelowW2Pct) / 100.0f);
|
|
|
|
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;
|
|
|
|
/// Calculate the table rows count
|
|
int tableRowsCount = batch.WaterMeters.Count;
|
|
|
|
/// Prepare document outline
|
|
titleHeight = System.Windows.Forms.TextRenderer.MeasureText(header, titleFont).Height;
|
|
CommonTop = cfg.TopMargin + titleHeight + SpacingOne4Header;
|
|
|
|
int commonCount = Math.Max(commonItems1.Count, Math.Max(commonItems2.Count, commonItems3.Count));
|
|
commonHeight = commonCount * SpacingOne;
|
|
BodyTop = CommonTop + commonHeight + SpacingOne4Header;
|
|
|
|
int wmSectionHeight = (tableRowsCount + 1) * SpacingOne + 3 * SpacingOne4Header;
|
|
|
|
tablesOnFirstPage = (printHeight - BodyTop + cfg.TopMargin - 2 * SpacingOne) / wmSectionHeight;
|
|
tablesOnNextPage = Math.Max((printHeight - 2 * SpacingOne) / wmSectionHeight, 1); /// Min. 1, prevent division by zero
|
|
|
|
if (tablesOnFirstPage >= 1)
|
|
{
|
|
nrPages = 1;
|
|
}
|
|
else
|
|
{
|
|
nrPages = 2;
|
|
}
|
|
|
|
pageNr = 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override the default onbeginPrint method of the PrintDocument Object
|
|
/// </summary>
|
|
/// <param name=e></param>
|
|
/// <remarks></remarks>
|
|
protected override void OnBeginPrint(System.Drawing.Printing.PrintEventArgs e)
|
|
{
|
|
base.OnBeginPrint(e);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override the default OnPrintPage method of the PrintDocument.
|
|
/// </summary>
|
|
/// <param name=e></param>
|
|
/// <remarks>This provides the print logic for our document</remarks>
|
|
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e)
|
|
{
|
|
/// Run base code
|
|
base.OnPrintPage(e);
|
|
|
|
if (File.Exists("C:\\TBF\\header.png"))
|
|
{
|
|
Image img = Image.FromFile("C:\\TBF\\header.png");
|
|
e.Graphics.DrawImage(new Bitmap(img), new Rectangle(0, 0, 827, 1169));
|
|
}
|
|
|
|
/// Use the StringFormat class for the text layout of our document
|
|
StringFormat format = new StringFormat(StringFormatFlags.LineLimit);
|
|
|
|
if (pageNr == 1)
|
|
{
|
|
///----------
|
|
/// Title
|
|
///----------
|
|
int titleWid = (int)(e.Graphics.MeasureString(header, titleFont).Width + 1);
|
|
RectangleF printArea = new RectangleF(cfg.LeftMargin + Math.Max(0, (printWidth - titleWid)) / 2, cfg.TopMargin,
|
|
titleWid, titleHeight);
|
|
e.Graphics.DrawString(header, titleFont, Brushes.Black, printArea);
|
|
|
|
///----------------
|
|
/// Common items
|
|
///----------------
|
|
for (int n = 1; n <= 3; n++)
|
|
{
|
|
IList<WMeterRsltItemSpec> commonItems;
|
|
int lMargin;
|
|
switch (n)
|
|
{
|
|
default:
|
|
case 1: commonItems = commonItems1; lMargin = leftMarginCommon1; break;
|
|
case 2: commonItems = commonItems2; lMargin = leftMarginCommon2; break;
|
|
case 3: commonItems = commonItems3; lMargin = leftMarginCommon3; break;
|
|
}
|
|
|
|
if (commonItems.Count == 0) continue; /// Common part is empty
|
|
|
|
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 left column width
|
|
int leftColWidth = 0;
|
|
foreach (var s in leftColumn)
|
|
{
|
|
int itemWidth = (int)e.Graphics.MeasureString(s, font).Width;
|
|
if (itemWidth > leftColWidth) leftColWidth = itemWidth;
|
|
}
|
|
|
|
/// Write aligned columns
|
|
for (int i = 0; i < Math.Min(leftColumn.Length, rightColumn.Length); i++)
|
|
{
|
|
PrintAt(e, lMargin, CommonTop + SpacingOne * i, leftColumn[i]);
|
|
PrintAt(e, lMargin + leftColWidth + GapBetweenCommonColumns, 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 : cfg.TopMargin;
|
|
|
|
if (tablesOnFirstPage > 0 || pageNr == 2)
|
|
{
|
|
PrintWMs(e, batch.WaterMeters, nextWmTop);
|
|
}
|
|
|
|
e.HasMorePages = (nrPages > 1) && (pageNr == 1);
|
|
|
|
///----------------
|
|
/// Below items
|
|
///----------------
|
|
for (int n = 1; n <= 3; n++)
|
|
{
|
|
IList<WMeterRsltItemSpec> belowItems;
|
|
int lMargin;
|
|
switch (n)
|
|
{
|
|
default:
|
|
case 1: belowItems = belowItems1; lMargin = leftMarginBelow1; break;
|
|
case 2: belowItems = belowItems2; lMargin = leftMarginBelow2; break;
|
|
case 3: belowItems = belowItems3; lMargin = leftMarginBelow3; break;
|
|
}
|
|
|
|
if (belowItems.Count == 0) continue; /// Below part is empty
|
|
|
|
string[] leftColumn = new string[belowItems.Count];
|
|
string[] rightColumn = new string[belowItems.Count];
|
|
|
|
int cnt = 0;
|
|
foreach (var v in belowItems)
|
|
{
|
|
leftColumn[cnt] = v.Caption;
|
|
rightColumn[cnt] = (batch.WaterMeters.Count > 0) ? v.Print(batch.WaterMeters[0]) : string.Empty;
|
|
cnt++;
|
|
}
|
|
|
|
/// Determine left column width
|
|
int leftColWidth = 0;
|
|
foreach (var s in leftColumn)
|
|
{
|
|
int itemWidth = (int)e.Graphics.MeasureString(s, font).Width;
|
|
if (itemWidth > leftColWidth) leftColWidth = itemWidth;
|
|
}
|
|
|
|
/// Write aligned columns
|
|
for (int i = 0; i < Math.Min(leftColumn.Length, rightColumn.Length); i++)
|
|
{
|
|
PrintAt(e, lMargin, nextWmTop + SpacingOne * i, leftColumn[i]);
|
|
PrintAt(e, lMargin + leftColWidth + GapBetweenCommonColumns, nextWmTop + SpacingOne * i, rightColumn[i]);
|
|
}
|
|
}
|
|
|
|
///----------
|
|
/// Footer
|
|
///----------
|
|
int footerWidth = (int)e.Graphics.MeasureString(footer, font).Width;
|
|
PrintAt(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);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Print one water meter results
|
|
/// </summary>
|
|
/// <param name="wm">Water meter</param>
|
|
/// <param name="printedWMNr">Number of the water meter printed</param>
|
|
/// <param name="top">Top coordinate of watermeter data</param>
|
|
/// <returns>The height of the printed section</returns>
|
|
int PrintWMs(System.Drawing.Printing.PrintPageEventArgs e,
|
|
IList<Results.Entities.WaterMeter> wms, int top)
|
|
{
|
|
/// Determine column widths
|
|
WMeterRsltItemSpec.TableRowNr = 99;
|
|
WMeterRsltItemSpec.TableColumnNr = 99;
|
|
float[] columnPos = new float[selectedItems.Count + 1];
|
|
columnPos[0] = (float)leftMargin;
|
|
|
|
for (int i = 0; i < selectedItems.Count; i++)
|
|
{
|
|
float columnWidth = e.Graphics.MeasureString(selectedItems[i].Caption, headerFont).Width;
|
|
foreach (var wm in wms)
|
|
{
|
|
string itemText = selectedItems[i].Print(wm);
|
|
|
|
/// Strip color information
|
|
string[] texts = itemText.Split(new char[] { '|' });
|
|
if (texts.Length == 2) { itemText = texts[0]; }
|
|
|
|
float width = e.Graphics.MeasureString(itemText, font).Width;
|
|
if (width > columnWidth) columnWidth = width;
|
|
}
|
|
columnPos[i + 1] = columnPos[i] + columnWidth + 20.0f;
|
|
}
|
|
int tableLeftX = (int)columnPos[0];
|
|
int tableRightX = (int)columnPos[selectedItems.Count] - 20;
|
|
|
|
/// Horizontal line
|
|
int horY = top + SpacingOneAndHalf4Header;
|
|
e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY));
|
|
|
|
for (int i = 0; i < selectedItems.Count; i++)
|
|
{
|
|
PrintHeaderAt(e, (int)columnPos[i], top + (int)(1.6 * SpacingOne4Header), selectedItems[i].Caption);
|
|
}
|
|
|
|
/// Horizontal line
|
|
horY = top + (int)(2.8 * SpacingOne4Header);
|
|
e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY));
|
|
|
|
int rowsCount = 0;
|
|
foreach (var wm in wms)
|
|
{
|
|
WMeterRsltItemSpec.TableRowNr = ++rowsCount;
|
|
|
|
for (int i = 0; i < selectedItems.Count; i++)
|
|
{
|
|
WMeterRsltItemSpec.TableColumnNr = i + 1;
|
|
|
|
string itemText = selectedItems[i].Print(wm);
|
|
|
|
/// Strip color information
|
|
string[] texts = itemText.Split(new char[] { '|' });
|
|
if (texts.Length == 2)
|
|
{
|
|
itemText = texts[0];
|
|
Color color = texts[1].Equals("Green") ? Color.Green : (texts[1].Equals("Red") ? Color.Red : Color.White);
|
|
/// TODO: How to print colors?
|
|
}
|
|
|
|
PrintAt(e, (int)columnPos[i], top + 2 * SpacingOne4Header + SpacingOne * rowsCount, itemText);
|
|
}
|
|
}
|
|
|
|
/// Horizontal line
|
|
horY = top + 2 * SpacingOneAndHalf4Header + SpacingOne * rowsCount;
|
|
e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY));
|
|
|
|
return (rowsCount + 1) * SpacingOne + 3 * SpacingOne4Header;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|