/// /// Copyright (c) 2018 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using Common; namespace Results.Output { public enum TableLines { None, FirstAndLast, FirstSecondAndLast, All, } public class TableStyle { public float MarginX; public float MarginY; public Font Font; public Font HeaderFont; public int TopHeadersCount; public int LeftHeadersCount; public float LineWidth; public TableLines HorizLines; public TableLines VertLines; public float[] ColumnWidths; /// null = automatic } public class Table { public readonly int ColumnsCount; public readonly string AutoTestParam; public int RowsCount { get { return Rows.Count; } } public readonly IList Rows; public readonly IList HorizAlignments; public readonly IList VertAlignments; public TableStyle Style; public Table(int columnsCount, string autoTestParam = null) { this.ColumnsCount = columnsCount; this.AutoTestParam = autoTestParam; Rows = new List(); HorizAlignments = new List(); VertAlignments = new List(); Style = new TableStyle(); } public void AddRow(string[] texts, Alignment[] horizAlignment, VertAlignment[] vertAlignemnt) { Rows.Add(texts); HorizAlignments.Add(horizAlignment); VertAlignments.Add(vertAlignemnt); } /// /// Returns true when table has either rows or columns count == 0 /// /// true when empty public bool IsEmpty() { return (Rows == null || RowsCount == 0 || Rows[0] == null || Rows[0].Length == 0); } public SizeF Measure(System.Drawing.Printing.PrintPageEventArgs e) { SizeF retVal = new SizeF(0, 0); if (IsEmpty()) return retVal; /// Empty table => zero Size float[] columnWidth = new float[ColumnsCount]; float[] rowHeight = new float[RowsCount]; /// /// Measure table column widths and header height /// for (int colIx = 0; colIx < ColumnsCount; colIx++) { for (int rowIx = 0; rowIx < RowsCount; rowIx++) { if (Rows[rowIx] == null) { /// Separator row -> do nothing } else { bool isHeader = (colIx < Style.LeftHeadersCount) || (rowIx < Style.TopHeadersCount); SizeF size = Common.Printers.PrintersCommon.Measure(e, Rows[rowIx][colIx], isHeader ? Style.HeaderFont : Style.Font); if (size.Width > columnWidth[colIx]) columnWidth[colIx] = size.Width; if (size.Height > rowHeight[rowIx]) rowHeight[rowIx] = size.Height; } } bool hasLineToTheLeft = (Style.VertLines == TableLines.All) || ((Style.VertLines == TableLines.FirstAndLast) && (colIx == 0)) || ((Style.VertLines == TableLines.FirstSecondAndLast) && (colIx <= 1)); retVal.Width += columnWidth[colIx] + (hasLineToTheLeft ? (Style.LineWidth + Style.MarginX) : 0) + Style.MarginX; } for (int rowIx = 0; rowIx < RowsCount; rowIx++) { if (Rows[rowIx] == null) { /// Separator row -> do nothing } else { bool hasLineAbove = (Style.HorizLines == TableLines.All) || ((Style.HorizLines == TableLines.FirstAndLast) && (rowIx == 0)) || ((Style.HorizLines == TableLines.FirstSecondAndLast) && (rowIx <= 1)) || ((rowIx >= 1) && (Rows[rowIx - 1] == null)); retVal.Height += rowHeight[rowIx] + (hasLineAbove ? (Style.LineWidth + Style.MarginY) : 0) + Style.MarginY; } } if (Style.VertLines == TableLines.None) retVal.Width -= Style.MarginX; if (Style.HorizLines == TableLines.None) retVal.Height -= Style.MarginY; return retVal; } public float Draw(System.Drawing.Printing.PrintPageEventArgs e, float left, float top) { if (IsEmpty()) return top; /// Empty table int tblColumnsCount = Rows[0].Length; float[] columnWidth = new float[tblColumnsCount]; float[] columnPos = new float[tblColumnsCount]; float[] vertLinePos = new float[tblColumnsCount + 1]; float[] rowHeight = new float[RowsCount]; float[] rowPos = new float[RowsCount]; float[] horizLinePos = new float[RowsCount + 1]; /// /// Measure table column widths and header height /// vertLinePos[0] = left; horizLinePos[0] = top; for (int colIx = 0; colIx < tblColumnsCount; colIx++) { for (int rowIx = 0; rowIx < RowsCount; rowIx++) { if (Rows[rowIx] != null) { /// In not a separator line bool isHeader = (colIx < Style.LeftHeadersCount) || (rowIx < Style.TopHeadersCount); SizeF size = Common.Printers.PrintersCommon.Measure(e, Rows[rowIx][colIx], isHeader ? Style.HeaderFont : Style.Font); if ((Style.ColumnWidths != null) && (Style.ColumnWidths.Length > colIx)) { size.Width = Style.ColumnWidths[colIx]; /// Override measurement if column width is defined } if (size.Width > columnWidth[colIx]) columnWidth[colIx] = size.Width; if (size.Height > rowHeight[rowIx]) rowHeight[rowIx] = size.Height; } else { /// Separator line -> do nothing rowHeight[rowIx] = 0; } } bool hasLineToTheLeft = (Style.VertLines == TableLines.All) || ((Style.VertLines == TableLines.FirstAndLast) && (colIx == 0)) || ((Style.VertLines == TableLines.FirstSecondAndLast) && (colIx <= 1)); columnPos[colIx] = vertLinePos[colIx] + (hasLineToTheLeft ? (Style.LineWidth + Style.MarginX) : 0); vertLinePos[colIx + 1] = columnPos[colIx] + columnWidth[colIx] + Style.MarginX; } for (int rowIx = 0; rowIx < RowsCount; rowIx++) { if (Rows[rowIx] != null) { /// In not a separator line bool hasLineAbove = (Style.HorizLines == TableLines.All) || ((Style.HorizLines == TableLines.FirstAndLast) && (rowIx == 0)) || ((Style.HorizLines == TableLines.FirstSecondAndLast) && (rowIx <= 1)) || ((rowIx >= 1) && (Rows[rowIx - 1] == null)); rowPos[rowIx] = horizLinePos[rowIx] + (hasLineAbove ? Style.MarginY : 0); horizLinePos[rowIx + 1] = rowPos[rowIx] + rowHeight[rowIx] + Style.LineWidth + Style.MarginY; } else if (rowIx > 0) { /// Separator line rowPos[rowIx] = rowPos[rowIx - 1]; horizLinePos[rowIx + 1] = horizLinePos[rowIx]; } } /// Horizontal lines float tableLeftX = left; float tableRightX = vertLinePos[tblColumnsCount] + Style.LineWidth; if (Style.HorizLines != TableLines.None) { for (int rowIx = 0; rowIx <= RowsCount; rowIx++) { if (Style.HorizLines == TableLines.All || rowIx == 0 || rowIx == RowsCount || (Style.HorizLines == TableLines.FirstSecondAndLast && rowIx == 1) || ((rowIx >= 1) && (Rows[rowIx - 1] == null))) { e.Graphics.DrawLine(new Pen(Color.Black, Style.LineWidth), new PointF(tableLeftX, horizLinePos[rowIx] + Style.LineWidth / 2), new PointF(tableRightX, horizLinePos[rowIx] + Style.LineWidth / 2)); } } } /// Vertical lines float tableTopY = top; float tableBottomY = horizLinePos[RowsCount] + Style.LineWidth; if (Style.VertLines != TableLines.None) { for (int colIx = 0; colIx <= tblColumnsCount; colIx++) { if (Style.VertLines == TableLines.All || colIx == 0 || colIx == ColumnsCount || (Style.VertLines == TableLines.FirstSecondAndLast && colIx == 1)) { e.Graphics.DrawLine(new Pen(Color.Black, Style.LineWidth), new PointF(vertLinePos[colIx] + Style.LineWidth / 2, tableTopY), new PointF(vertLinePos[colIx] + Style.LineWidth / 2, tableBottomY)); } } } /// /// Draw table body /// for (int rowIndex = 0; rowIndex < RowsCount; rowIndex++) { string[] oneTableRow = Rows[rowIndex]; if (oneTableRow != null) { Alignment[] horizAlignment = HorizAlignments[(RowsCount > rowIndex) ? rowIndex : 0]; VertAlignment[] vertAlignment = VertAlignments[(RowsCount > rowIndex) ? rowIndex : 0]; for (int colIndex = 0; colIndex < tblColumnsCount; colIndex++) { bool isHeader = (colIndex < Style.LeftHeadersCount) || (rowIndex < Style.TopHeadersCount); Common.Printers.PrintersCommon.PrintAt(e, oneTableRow[colIndex], isHeader ? Style.HeaderFont : Style.Font, columnPos[colIndex], rowPos[rowIndex], columnWidth[colIndex], rowHeight[rowIndex], horizAlignment[colIndex], vertAlignment[colIndex]); } } } return tableBottomY; } public static Table Create_TestsAreRows(Results.Entities.WaterMeter wm, IList items, TableStyle style, string autoTestParam = null) { /// 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 string.IsNullOrEmpty(autoTestParam) ? wm.RegularMeterTestRslts() : wm.AutoMeterTestRslts(autoTestParam)) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == 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; } public static Table Create_TestsAreColumns(Results.Entities.WaterMeter wm, IList items, TableStyle style, string autoTestParam = null) { /// Left column contains row captions /// /// Calculate columns count /// int columnsCount = 1; /// Left column contains item caption foreach (var mtr in string.IsNullOrEmpty(autoTestParam) ? wm.RegularMeterTestRslts() : wm.AutoMeterTestRslts(autoTestParam)) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == Publish.Always) { columnsCount++; /// One additional column for each test to be published } } Table table = new Table(columnsCount); table.Style = style; /// /// Table content /// WMeterRsltItemSpec.TableRowNr = 1; for (int i = 0; i < items.Count; i++) { string[] oneTableRow = new string[columnsCount]; Alignment[] horizAlignment = new Alignment[columnsCount]; VertAlignment[] vertAlignment = new VertAlignment[columnsCount]; oneTableRow[0] = items[i].Caption; horizAlignment[0] = Alignment.Center; vertAlignment[0] = VertAlignment.Middle; WMeterRsltItemSpec.TableColumnNr = 1; foreach (var mtr in string.IsNullOrEmpty(autoTestParam) ? wm.RegularMeterTestRslts() : wm.AutoMeterTestRslts(autoTestParam)) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == Publish.Always) { /// Strip color information oneTableRow[WMeterRsltItemSpec.TableColumnNr] = items[i].Print(wm, mtr.Name()).Split(new char[] { '|' })[0]; horizAlignment[WMeterRsltItemSpec.TableColumnNr] = items[i].Alignment; vertAlignment[WMeterRsltItemSpec.TableColumnNr] = VertAlignment.Middle; WMeterRsltItemSpec.TableColumnNr++; } } table.AddRow(oneTableRow, horizAlignment, vertAlignment); WMeterRsltItemSpec.TableRowNr++; } return table; } public static Table Create_TestsAreColumnsPL(Results.Entities.WaterMeter wm, IList items, TableStyle style, string autoTestParam = null) { /// Left column contains row captions /// /// Calculate columns count /// int columnsCount = 2; /// Left two columns contain item caption and units foreach (var mtr in string.IsNullOrEmpty(autoTestParam) ? wm.RegularMeterTestRslts() : wm.AutoMeterTestRslts(autoTestParam)) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == Publish.Always) { columnsCount++; /// One additional column for each test to be published } } Table table = new Table(columnsCount); table.Style = style; /// /// Table content /// WMeterRsltItemSpec.TableRowNr = 1; for (int i = 0; i < items.Count; i++) { if (items[i].Uid == (int)ItemID.Separator) { table.AddRow(null, null, null); /// 'separator' row } else { string[] oneTableRow = new string[columnsCount]; Alignment[] horizAlignment = new Alignment[columnsCount]; VertAlignment[] vertAlignment = new VertAlignment[columnsCount]; oneTableRow[0] = items[i].Caption; horizAlignment[0] = Alignment.Center; vertAlignment[0] = VertAlignment.Middle; oneTableRow[1] = (i == 0) ? "Jednostka" : items[i].Units.ToDescription(); horizAlignment[1] = Alignment.Center; vertAlignment[1] = VertAlignment.Middle; WMeterRsltItemSpec.TableColumnNr = 1; foreach (var mtr in string.IsNullOrEmpty(autoTestParam) ? wm.RegularMeterTestRslts() : wm.AutoMeterTestRslts(autoTestParam)) { if (mtr != null && mtr.IsPilotRslt() && mtr.Publish() == Publish.Always) { int colIx = WMeterRsltItemSpec.TableColumnNr + 1; /// Strip color information oneTableRow[colIx] = items[i].Print(wm, mtr.Name()).Split(new char[] { '|' })[0]; horizAlignment[colIx] = items[i].Alignment; vertAlignment[colIx] = VertAlignment.Middle; WMeterRsltItemSpec.TableColumnNr++; } } table.AddRow(oneTableRow, horizAlignment, vertAlignment); } WMeterRsltItemSpec.TableRowNr++; } return table; } } }