diff --git a/TestBenchFramework/PrintOrderDocument.cs b/TestBenchFramework/PrintOrderDocument.cs index 647123750..8331afc50 100644 --- a/TestBenchFramework/PrintOrderDocument.cs +++ b/TestBenchFramework/PrintOrderDocument.cs @@ -16,7 +16,10 @@ namespace TBF const int TitleX = 100; const int TitleY = 180; /// Depends on the size of the header const int HdrTop = 240; /// Depends on the size of the header - const int BodyTop = 400; + const int TableTopFirstPage = 390; + const int TableTopNextPage = 180; + const int Padding = 10; + /// /// Property variable for the Font the user wishes to use @@ -30,7 +33,6 @@ namespace TBF /// readonly Entities.Procedure procedure; readonly IList allResults; - readonly bool combined; readonly DateTime dateTime; readonly int batchMin; readonly int batchMax; @@ -38,19 +40,32 @@ namespace TBF /// /// Items to print /// + readonly IList testNames; readonly int testsPerMeter; readonly IList resultItems; + /// + /// Data to print + /// readonly int maxNrRows; readonly int nrRows; readonly int nrColumns; - - IList unsortedResults; - string[,] dataToPrint; + /// + /// Layout and status + /// + int nrTabLinesOnFirstPage; + int nrTabLinesOnNextPage; + int nextTableRow; /// nr. of table row 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 + /// Constructor. + /// Precalculates some values and dimensions and stores strings for the table + /// to be printed into a 2-dimensional array of strings 'dataToprint'. /// /// Procedure belonging to the results /// Results to be printed (multiple batches) @@ -70,9 +85,9 @@ namespace TBF } resultItems = Forms.ResultItemSpec.FromStrArray(Program.LocalSettings.RsltItems_Printer_SingleWM); - combined = false; - testsPerMeter = Utils.GetSortedTestResults(procedure, null, 1).Count; + testNames = Utils.GetDecoratedTestNames(procedure, 1); + testsPerMeter = testNames.Count; maxNrRows = (batchMax - batchMin + 1) * Program.WMsCount; nrColumns = testsPerMeter * resultItems.Count + 2; @@ -85,7 +100,7 @@ namespace TBF for (int i = batchMin; i <= batchMax; i++) { /// Collect all results belonging to one batch - unsortedResults = new List(); + IList unsortedResults = new List(); foreach (var tr in allResults) if (tr.BatchNr == i) unsortedResults.Add(tr); if (unsortedResults.Count == 0) continue; @@ -106,7 +121,11 @@ namespace TBF { int k = 2 + j * resultItems.Count; foreach (var item in resultItems) - dataToPrint[nrRows, k++] = item.Print(results[j].Meters[wmNr]); + { + string str = item.Print(results[j].Meters[wmNr]); + int pos = str.IndexOf('|'); + dataToPrint[nrRows, k++] = (pos < 0) ? str : str.Substring(0, pos); + } } } @@ -115,7 +134,8 @@ namespace TBF } } - int z = 7; + pageNr = 1; + nextTableRow = 0; } /// @@ -142,255 +162,238 @@ namespace TBF /// 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)); - } - /// Set print area size and margins (in dots using 80 dpi) int printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom; int printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right; int leftMargin = base.DefaultPageSettings.Margins.Left; /// X int topMargin = base.DefaultPageSettings.Margins.Top; /// Y - /// Check if the user selected to print in Landscape mode - /// if they did then we need to swap height/width parameters if (base.DefaultPageSettings.Landscape) { + /// Landscape mode: we need to swap height/width parameters int tmp = printHeight; printHeight = printWidth; printWidth = tmp; + + if (File.Exists("C:\\TBF\\header-landscape.png")) + { + Image img = Image.FromFile("C:\\TBF\\header-landscape.png"); + e.Graphics.DrawImage(new Bitmap(img), new Rectangle(0, 0, 1169, 827)); + } + } + else + { + if (File.Exists("C:\\TBF\\header-portrait.png")) + { + Image img = Image.FromFile("C:\\TBF\\header-portrait.png"); + e.Graphics.DrawImage(new Bitmap(img), new Rectangle(0, 0, 827, 1169)); + } } - int x = leftMargin; - int y = topMargin; - - /// Use the StringFormat class for the text layout of our document - StringFormat format = new StringFormat(StringFormatFlags.LineLimit); - - ///---------- - /// Header - ///---------- - RectangleF printArea = new RectangleF(TitleX, TitleY, 667, 40); - e.Graphics.DrawString(allResults[0].ProtocolTitle, titleFont, Brushes.Black, printArea); - - string[] leftColumn = new string[] - { - "Purchase order: ", - "Date and time: ", - "Procedure:", - Strings.User_, - "Ambient temperature: ", - "Ambient pressure: ", - "Ambient humidity: ", - }; - - string[] rightColumn = new string[] - { - allResults[0].PurchaseOrder, - //dateTime.ToShortDateString() + " " + dateTime.ToShortTimeString(), - string.Format("{0}.{1}.{2} {3}:{4}", dateTime.Year.ToString("D4"), - dateTime.Month.ToString("D2"), - dateTime.Day.ToString("D2"), - dateTime.Hour.ToString("D2"), - dateTime.Minute.ToString("D2")), - procedure.Name, - Entities.User.CurrentUser.Name, - allResults[0].AmbientTempAve.ToString("F1") + " °C", - allResults[0].AmbientPressAve.ToString("F0") + " mbar", - allResults[0].AmbientHumiAve.ToString("F0") + " %", - }; - - /// 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++) + ///--------------- + /// Common info + ///--------------- + if (pageNr == 1) { - PrintAt(e, 100, HdrTop + SpacingOne* i, leftColumn[i]); - PrintAt(e, 300, HdrTop + SpacingOne * i, rightColumn[i]); + RectangleF printArea = new RectangleF(TitleX, TitleY, 667, 40); + e.Graphics.DrawString(allResults[0].ProtocolTitle, titleFont, Brushes.Black, printArea); + + string[] leftColumn = new string[] + { + "Purchase order: ", + "Date and time: ", + "Procedure:", + Strings.User_, + "Ambient temperature: ", + "Ambient pressure: ", + "Ambient humidity: ", + }; + + string[] rightColumn = new string[] + { + allResults[0].PurchaseOrder, + //dateTime.ToShortDateString() + " " + dateTime.ToShortTimeString(), + string.Format("{0}.{1}.{2} {3}:{4}", dateTime.Year.ToString("D4"), + dateTime.Month.ToString("D2"), + dateTime.Day.ToString("D2"), + dateTime.Hour.ToString("D2"), + dateTime.Minute.ToString("D2")), + procedure.Name, + Entities.User.CurrentUser.Name, + allResults[0].AmbientTempAve.ToString("F1") + " °C", + allResults[0].AmbientPressAve.ToString("F0") + " mbar", + allResults[0].AmbientHumiAve.ToString("F0") + " %", + }; + + /// 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, 100, HdrTop + SpacingOne * i, leftColumn[i]); + PrintAt(e, 300, HdrTop + SpacingOne * i, rightColumn[i]); + } + } + + ///---------------- + /// More pages ? + ///---------------- + if (pageNr == 1) + { + /// Determine the number of pages once + nrTabLinesOnNextPage = (topMargin + printHeight - TableTopNextPage - 70) / SpacingOne; + nrTabLinesOnFirstPage = (topMargin + printHeight - TableTopFirstPage - 70) / SpacingOne; + + if (nrRows <= nrTabLinesOnFirstPage) + { + nrPages = 1; + } + else + { + nrPages = 1 + ((nrRows - nrTabLinesOnFirstPage) + nrTabLinesOnNextPage - 1) / nrTabLinesOnNextPage; + } + } + int nrTabLinesOnThisPage = (pageNr == 1) ? nrTabLinesOnFirstPage : nrTabLinesOnNextPage; + int rowFrom = nextTableRow; + int rowTo; + if (nrRows <= nextTableRow + nrTabLinesOnThisPage) + { + rowTo = nrRows - 1; + e.HasMorePages = false; + } + else + { + rowTo = rowFrom + nrTabLinesOnThisPage - 1; + nextTableRow = rowFrom + nrTabLinesOnThisPage; + e.HasMorePages = true; } ///-------- /// Body ///-------- + int[] columnPos = GetColumnPositions(e, dataToPrint, rowFrom, rowTo, leftMargin + Padding, 2 * Padding); + int tableLeft = leftMargin; + int tableRight = columnPos[nrColumns] - Padding; - /// 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 = BodyTop; + int currentTableTop = (pageNr == 1) ? TableTopFirstPage : TableTopNextPage; + int yyy = currentTableTop; - e.HasMorePages = false; + /// Horizontal line + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeft, yyy), new Point(tableRight, yyy)); + yyy += 2; + + /// Line with test names (larger columns, names centered) + for (int bigcol = 0; bigcol < testsPerMeter; bigcol++) + { + float width = e.Graphics.MeasureString(testNames[bigcol], font).Width; + int bc = 2 + bigcol * resultItems.Count; + int xxx = (columnPos[bc] + columnPos[bc + resultItems.Count]) / 2 - Padding - (int)(width / 2 + 0.5f); + PrintAt(e, xxx, yyy, testNames[bigcol]); + } + yyy += SpacingOne; + + int tableTop2 = yyy; + + /// Indented horizontal line + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(columnPos[2] - Padding, yyy), new Point(tableRight, yyy)); + yyy += 2; + + /// Line with header texts + PrintAt(e, columnPos[0], yyy - SpacingOne / 2, GetHeaderItem(0)); + PrintAt(e, columnPos[1], yyy - SpacingOne / 2, GetHeaderItem(1)); + for (int col = 2; col < nrColumns; col++) + { + PrintAt(e, columnPos[col], yyy, GetHeaderItem(col)); + } + yyy += SpacingOne; + + /// Horizontal line + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeft, yyy), new Point(tableRight, yyy)); + yyy += 2; + + /// Table with results + for (int row = rowFrom; row <= rowTo; row++) + { + for (int col = 0; col < nrColumns; col++) + { + PrintAt(e, columnPos[col], yyy, dataToPrint[row, col]); + } + yyy += SpacingOne; + } + + /// Horizontal line + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeft, yyy), new Point(tableRight, yyy)); + int tableBottom = yyy; + + /// Vertical lines + for (int col = 0; col <= nrColumns; col++) + { + if (col < 2 || ((col-2) % resultItems.Count) == 0) + { + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(columnPos[col] - Padding, currentTableTop), + new Point(columnPos[col] - Padding, tableBottom)); + } + else + { + e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(columnPos[col] - Padding, tableTop2), + new Point(columnPos[col] - Padding, tableBottom)); + } + } + + ///---------- + /// Footer + ///---------- + PrintAt(e, leftMargin, topMargin + printHeight - SpacingOne, string.Format("Page {0}/{1}", pageNr++, nrPages)); } - /// - /// Print one water meter results + /// Returns header text for each column of the table. /// - /// Water meter number (0-based) - /// Top coordinate of watermeter data - /// The height of the printed section - int PrintSingleWM(System.Drawing.Printing.PrintPageEventArgs e, int wmNr, int printedWMNr, int top) + /// COlumn nymber (0-based) + /// Header text + string GetHeaderItem(int column) { - IList results = Utils.GetSortedTestResults(procedure, unsortedResults, wmNr + 1); - - /// - /// Determine column widths - /// - float[] columnPos = new float[resultItems.Count + 1]; - columnPos[0] = 100.0f; - - for (int i = 0; i < resultItems.Count; i++) + switch (column) { - float columnWidth = e.Graphics.MeasureString(resultItems[i].ClmnHeaderText, font).Width; - foreach (var tr in results) - { - if (tr != null) - { - float width = e.Graphics.MeasureString(resultItems[i].Print(tr.Meters[wmNr]), font).Width; - if (width > columnWidth) columnWidth = width; - } - } - columnPos[i + 1] = columnPos[i] + columnWidth + 20.0f; + case 0: return "Nr."; + case 1: return "S/N"; + default: return resultItems[(column - 2) % resultItems.Count].ClmnHeaderText; } - int tableLeftX = (int)columnPos[0]; - int tableRightX = (int)columnPos[resultItems.Count] - 20; - - string wmText = string.Format("Water meter {0}", printedWMNr); - PrintAt(e, 100, top, wmText); - if (!string.IsNullOrEmpty(unsortedResults[0].Meters[wmNr].SerialNr)) - { - PrintAt(e, 100 + (int)e.Graphics.MeasureString(wmText, font).Width, top, - string.Format(" s/n = {0}", unsortedResults[0].Meters[wmNr].SerialNr)); - } - - /// Horizontal line - int horY = top + 25; - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - for (int i = 0; i < resultItems.Count; i++) - { - PrintAt(e, (int)columnPos[i], top + 27, resultItems[i].ClmnHeaderText); - } - - /// Horizontal line - horY = top + 27 + SpacingOne; - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - for (int r = 0; r < results.Count; r++) - { - if (results[r] != null) - { - for (int i = 0; i < resultItems.Count; i++) - { - string text = resultItems[i].Print(results[r].Meters[wmNr]); - - string[] texts = text.Split(new char[] { '|' }); - - if (texts.Length == 2) - { - Color color = texts[1].Equals("Green") ? Color.Green : (texts[1].Equals("Red") ? Color.Red : Color.White); - text = texts[0]; - /// TODO: How to print colors? - } - - PrintAt(e, (int)columnPos[i], top + 30 + SpacingOne * (r + 1), text); - } - } - } - - /// Horizontal line - horY = top + 30 + SpacingOne * (results.Count + 1); - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - return (results.Count + 4) * SpacingOne; } - /// - /// Print one combined water meter results + /// Determine column widths and return column left positions for a subset of table rows /// - /// Water meter number (1-based) - /// Top coordinate of watermeter data - /// The height of the printed section - int PrintCombinedWM(System.Drawing.Printing.PrintPageEventArgs e, int wmNr1, int top) + /// string[nrRows, nrColumns] + /// First row to consider + /// Last row to consider + /// Left column positions and right side float[nrColumns + 1] + int[] GetColumnPositions(System.Drawing.Printing.PrintPageEventArgs e, + string[,] dataToPrint, int rowFrom, int rowTo, + int leftMargin, int padding) { - IList results = Utils.GetSortedTestResults(procedure, unsortedResults, wmNr1); + int nrColumns = dataToPrint.GetLength(1); + int[] columnPos = new int[nrColumns + 1]; + columnPos[0] = leftMargin; - /// Determin column widths - float[] columnPos = new float[resultItems.Count + 1]; - columnPos[0] = 100.0f; - - for (int i = 0; i < resultItems.Count; i++) + for (int column = 0; column < nrColumns; column++) { - float columnWidth = e.Graphics.MeasureString(resultItems[i].ClmnHeaderText, font).Width; - foreach (var tr in results) + float columnWidth = e.Graphics.MeasureString(GetHeaderItem(column), font).Width; + + for (int row = rowFrom; row <= rowTo; row++) { - if (tr != null) - { - float width = e.Graphics.MeasureString(resultItems[i].PrintCombined(tr.Meters[2 * wmNr1 - 2], - tr.Meters[2 * wmNr1 - 1], - tr.CombinedMeters[wmNr1 - 1]), font).Width; - if (width > columnWidth) columnWidth = width; - } + float itemWidth = e.Graphics + .MeasureString(dataToPrint[row, column] == null ? string.Empty : dataToPrint[row, column], font) + .Width; + if (itemWidth > columnWidth) columnWidth = itemWidth; } - columnPos[i + 1] = columnPos[i] + columnWidth + 20.0f; - } - int tableLeftX = (int)columnPos[0]; - int tableRightX = (int)columnPos[resultItems.Count] - 20; - string wmText = string.Format("Water meter {0}", wmNr1); - PrintAt(e, 100, top, wmText); - if (!string.IsNullOrEmpty(unsortedResults[0].Meters[2 * wmNr1 - 2].SerialNr)) - { - PrintAt(e, 100 + (int)e.Graphics.MeasureString(wmText, font).Width, top, - string.Format(" Main s/n: {0} Aux. s/n:{1}", - unsortedResults[0].Meters[2 * wmNr1 - 2].SerialNr, - unsortedResults[0].Meters[2 * wmNr1 - 1].SerialNr)); + columnPos[column + 1] = columnPos[column] + (int)(columnWidth + 0.5f) + padding; } - /// Horizontal line - int horY = top + 25; - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - for (int i = 0; i < resultItems.Count; i++) - { - PrintAt(e, (int)columnPos[i], top + 27, resultItems[i].ClmnHeaderText); - } - - /// Horizontal line - horY = top + 27 + SpacingOne; - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - for (int r = 0; r < results.Count; r++) - { - if (results[r] != null) - { - for (int i = 0; i < resultItems.Count; i++) - { - string text = resultItems[i].PrintCombined(results[r].Meters[2 * wmNr1 - 2], - results[r].Meters[2 * wmNr1 - 1], - results[r].CombinedMeters[wmNr1 - 1]); - string[] texts = text.Split(new char[] { '|' }); - - if (texts.Length == 2) - { - Color color = texts[1].Equals("Green") ? Color.Green : (texts[1].Equals("Red") ? Color.Red : Color.White); - text = texts[0]; - /// TODO: How to print colors? - } - - PrintAt(e, (int)columnPos[i], top + 30 + SpacingOne * (r + 1), text); - } - } - } - - /// Horizontal line - horY = top + 30 + SpacingOne * (results.Count + 1); - e.Graphics.DrawLine(new Pen(Color.Black, 2), new Point(tableLeftX, horY), new Point(tableRightX, horY)); - - return (results.Count + 4) * SpacingOne; + return columnPos; } diff --git a/TestBenchFramework/Utils.cs b/TestBenchFramework/Utils.cs index 3266ad506..816bdd962 100644 --- a/TestBenchFramework/Utils.cs +++ b/TestBenchFramework/Utils.cs @@ -169,7 +169,7 @@ namespace TBF /// /// Pre-fetch the test results from the currently available results. - /// The order or the returned results is the same as the order of tests in the procedure specification. + /// The order of the returned results is the same as the order of tests in the procedure specification. /// /// Current procedure, it is used to determine the order of resulting test results /// Currently available unsorted test results (can also be null) @@ -211,6 +211,40 @@ namespace TBF } + /// + /// Pre-fetch the test names given the procedure and the meter number. + /// The order or test names is the same as in the procedure specification. + /// + /// Procedure + /// Water meter number (1-based) or 0=all (also compared with nonzero 'Part' number) + /// Ordered list of test names + public static IList GetDecoratedTestNames(Entities.Procedure procedure, int meterNr) + { + IList names = new List(); + + if (procedure == null) return names; /// Return an empty list if no procedure specified + + foreach (var test in procedure.Tests) + { + BenchControl.GenericDevices.ITestMethod method = + BenchControl.TbfComponents.FindComponent(test.Method) as BenchControl.GenericDevices.ITestMethod; + + if ((method != null) && method.Publish && ((test.Part == 0) || (meterNr == 0) || (test.Part == meterNr))) + { + if (test.Repeats == 1) + { + names.Add(test.Name); + continue; + } + for (int rpt = 1; rpt <= test.Repeats; rpt++) + { + names.Add(test.Name + string.Format(" ({0}/{1})", rpt, test.Repeats)); + } + } + } + return names; + } + /// /// Converts float number to a string with the specified number of valid digits ///