From ca2705421b59cc1dc912eeca665761df83de941f Mon Sep 17 00:00:00 2001 From: Milan Hanajik Date: Sun, 24 Apr 2016 08:55:39 +0200 Subject: [PATCH] Results.FileWriters.Basic added, ver.2.5.274 --- TestBenchFramework.sln | 9 - .../FileWriters/Basic/FactoryCompound.cs | 24 ++ .../Output/FileWriters/Basic/FactorySingle.cs | 24 ++ .../FileWriters/Basic/ResultsConfigDlg.cs | 138 +++++++ .../Basic/ResultsConfigDlg.designer.cs | 168 ++++++++ .../FileWriters/Basic/ResultsConfigDlg.resx | 120 ++++++ .../Output/FileWriters/Basic/Writer.cs | 361 ++++++++++++++++++ .../Output/FileWriters/Basic/WriterCfg.cs | 67 ++++ .../Output/FileWriters/Basic/WriterCfgCtrl.cs | 163 ++++++++ .../Basic/WriterCfgCtrl.designer.cs | 217 +++++++++++ .../FileWriters/Basic/WriterCfgCtrl.resx | 120 ++++++ .../BenchControl/TbfComponents.cs | 2 + TestBenchFramework/Properties/AssemblyInfo.cs | 4 +- TestBenchFramework/TBF.csproj | 26 +- 14 files changed, 1431 insertions(+), 12 deletions(-) create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactoryCompound.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactorySingle.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.designer.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.resx create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/Writer.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfg.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.designer.cs create mode 100644 TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.resx diff --git a/TestBenchFramework.sln b/TestBenchFramework.sln index bba4a9774..cc1e46521 100644 --- a/TestBenchFramework.sln +++ b/TestBenchFramework.sln @@ -37,15 +37,6 @@ Global {8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}.Release|Mixed Platforms.Build.0 = Release|x86 {8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}.Release|x86.ActiveCfg = Release|x86 {8648FD92-CDA1-4C3A-B5F9-FE547CE1FA48}.Release|x86.Build.0 = Release|x86 - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Debug|Any CPU.ActiveCfg = Debug - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Debug|Mixed Platforms.ActiveCfg = Debug - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Debug|Mixed Platforms.Build.0 = Debug - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Debug|x86.ActiveCfg = Debug - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Release|Any CPU.ActiveCfg = Release - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Release|Any CPU.Build.0 = Release - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Release|Mixed Platforms.ActiveCfg = Release - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Release|Mixed Platforms.Build.0 = Release - {4890DE5C-9F68-40D7-B075-92C8EAB79833}.Release|x86.ActiveCfg = Release {9D0DCC88-DC81-47EB-9FDD-4C3907871BFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D0DCC88-DC81-47EB-9FDD-4C3907871BFB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {9D0DCC88-DC81-47EB-9FDD-4C3907871BFB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactoryCompound.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactoryCompound.cs new file mode 100644 index 000000000..b12345960 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactoryCompound.cs @@ -0,0 +1,24 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public class FactoryCompound : IComponentFactory + { + public string ClassName { get { return this.GetType().Namespace.Substring(17) + ".Compound"; } } + + public void ResetStaticProperties() { Writer.ResetStaticProperties(); } + + public IComponent DummyComponent() { return new Writer(); } + + public IComponentCfg DefaultConfig() { return new WriterCfg(this); } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(typeof(WriterCfg), component, this); + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactorySingle.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactorySingle.cs new file mode 100644 index 000000000..8d60d5a60 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/FactorySingle.cs @@ -0,0 +1,24 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public class FactorySingle : IComponentFactory + { + public string ClassName { get { return this.GetType().Namespace.Substring(17) + ".Single"; } } + + public void ResetStaticProperties() { Writer.ResetStaticProperties(); } + + public IComponent DummyComponent() { return new Writer(); } + + public IComponentCfg DefaultConfig() { return new WriterCfg(this); } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(typeof(WriterCfg), component, this); + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.cs new file mode 100644 index 000000000..f76e185c2 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.cs @@ -0,0 +1,138 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Config.Entities; +using TBF.Resources; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public partial class ResultsConfigDlg : Form + { + public IList AvailableItems; + public IList SelectedItems; + + public bool Compound; /// false = single meter items, true = combined meter items + + public ResultsConfigDlg() + { + InitializeComponent(); + } + + void Localize() + { + Text = Strings.Configuration; + availableResultsLabel.Text = Strings.Available_results; + selectedResultsLabel.Text = Strings.Selected_results; + addButton.Text = Strings.Add; + removeButton.Text = Strings.Remove; + removeAllButton.Text = Strings.Remove_all; + okButton.Text = Strings.OkBtnText; + cancelButton.Text = Strings.CancelBtnText; + } + + void ResultsConfig_Load(object sender, EventArgs e) + { + Localize(); + RedrawAvailable(); + RedrawSelected(); + } + + /// + /// Redraw selected items (right hand side) + /// + void RedrawAvailable() + { + availableResultsListBox.Items.Clear(); + AvailableItems = new List(); + foreach (var item in Results.ItemSpec.AllItems) + { + if (!SelectedItems.Contains(item) && (Compound ? item.CanPrintCombined : item.CanPrintSingle)) + { + AvailableItems.Add(item); + availableResultsListBox.Items.Add(item.Name); + } + } + } + + /// + /// Redraw selected items (right hand side) + /// + void RedrawSelected() + { + selectedResultsListBox.Items.Clear(); + foreach (var item in SelectedItems) + { + selectedResultsListBox.Items.Add(item.Name); + } + } + + void availableResultsListBox_DoubleClick(object sender, EventArgs e) + { + /// Double click works when just one item is selected + IList itemsToRemove = new List(); + if (availableResultsListBox.SelectedIndices.Count == 1) + { + var item = AvailableItems[availableResultsListBox.SelectedIndices[0]]; + SelectedItems.Add(item); + RedrawAvailable(); + RedrawSelected(); + } + } + + void addButton_Click(object sender, EventArgs e) + { + /// Append at the end, this code supports multiple selected items, + /// although ListBox control settings may limit the max.number of selected items to one. + + for (int i = availableResultsListBox.SelectedIndices.Count - 1; i >= 0; i--) + { + var item = AvailableItems[availableResultsListBox.SelectedIndices[i]]; + SelectedItems.Add(item); + } + RedrawAvailable(); + RedrawSelected(); + } + + private void selectedResultsListBox_DoubleClick(object sender, EventArgs e) + { + /// Double click works when just one item is selected + + if (selectedResultsListBox.SelectedIndices.Count == 1) + { + SelectedItems.RemoveAt(selectedResultsListBox.SelectedIndices[0]); + RedrawAvailable(); + RedrawSelected(); + } + } + + void removeButton_Click(object sender, EventArgs e) + { + /// Remove from the list (the last selected item first so that the indexes are not affected) + + for (int i = selectedResultsListBox.SelectedIndices.Count - 1; i >= 0; i--) + { + SelectedItems.RemoveAt(selectedResultsListBox.SelectedIndices[i]); + } + RedrawAvailable(); + RedrawSelected(); + } + + void removeAllButton_Click(object sender, EventArgs e) + { + /// Remove all items from 'Selected' list + + SelectedItems.Clear(); + RedrawAvailable(); + RedrawSelected(); + } + + void okButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.designer.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.designer.cs new file mode 100644 index 000000000..240afedaa --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.designer.cs @@ -0,0 +1,168 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + partial class ResultsConfigDlg + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.availableResultsListBox = new System.Windows.Forms.ListBox(); + this.selectedResultsListBox = new System.Windows.Forms.ListBox(); + this.availableResultsLabel = new System.Windows.Forms.Label(); + this.selectedResultsLabel = new System.Windows.Forms.Label(); + this.removeAllButton = new System.Windows.Forms.Button(); + this.removeButton = new System.Windows.Forms.Button(); + this.addButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // okButton + // + this.okButton.Location = new System.Drawing.Point(90, 236); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(104, 30); + this.okButton.TabIndex = 4; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // cancelButton + // + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(211, 236); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(104, 30); + this.cancelButton.TabIndex = 5; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + // + // availableResultsListBox + // + this.availableResultsListBox.FormattingEnabled = true; + this.availableResultsListBox.Location = new System.Drawing.Point(12, 31); + this.availableResultsListBox.Name = "availableResultsListBox"; + this.availableResultsListBox.Size = new System.Drawing.Size(135, 186); + this.availableResultsListBox.TabIndex = 6; + this.availableResultsListBox.DoubleClick += new System.EventHandler(this.availableResultsListBox_DoubleClick); + // + // selectedResultsListBox + // + this.selectedResultsListBox.FormattingEnabled = true; + this.selectedResultsListBox.Location = new System.Drawing.Point(252, 31); + this.selectedResultsListBox.Name = "selectedResultsListBox"; + this.selectedResultsListBox.Size = new System.Drawing.Size(135, 186); + this.selectedResultsListBox.TabIndex = 7; + this.selectedResultsListBox.DoubleClick += new System.EventHandler(this.selectedResultsListBox_DoubleClick); + // + // availableResultsLabel + // + this.availableResultsLabel.AutoSize = true; + this.availableResultsLabel.Location = new System.Drawing.Point(12, 9); + this.availableResultsLabel.Name = "availableResultsLabel"; + this.availableResultsLabel.Size = new System.Drawing.Size(86, 13); + this.availableResultsLabel.TabIndex = 8; + this.availableResultsLabel.Text = "Available results:"; + // + // selectedResultsLabel + // + this.selectedResultsLabel.AutoSize = true; + this.selectedResultsLabel.Location = new System.Drawing.Point(249, 9); + this.selectedResultsLabel.Name = "selectedResultsLabel"; + this.selectedResultsLabel.Size = new System.Drawing.Size(85, 13); + this.selectedResultsLabel.TabIndex = 9; + this.selectedResultsLabel.Text = "Selected results:"; + // + // removeAllButton + // + this.removeAllButton.Location = new System.Drawing.Point(153, 144); + this.removeAllButton.Name = "removeAllButton"; + this.removeAllButton.Size = new System.Drawing.Size(94, 30); + this.removeAllButton.TabIndex = 46; + this.removeAllButton.Text = "<< R&emove all"; + this.removeAllButton.UseVisualStyleBackColor = true; + this.removeAllButton.Click += new System.EventHandler(this.removeAllButton_Click); + // + // removeButton + // + this.removeButton.Location = new System.Drawing.Point(153, 109); + this.removeButton.Name = "removeButton"; + this.removeButton.Size = new System.Drawing.Size(93, 30); + this.removeButton.TabIndex = 45; + this.removeButton.Text = "< &Remove"; + this.removeButton.UseVisualStyleBackColor = true; + this.removeButton.Click += new System.EventHandler(this.removeButton_Click); + // + // addButton + // + this.addButton.Location = new System.Drawing.Point(153, 74); + this.addButton.Name = "addButton"; + this.addButton.Size = new System.Drawing.Size(93, 30); + this.addButton.TabIndex = 44; + this.addButton.Text = "&Add >"; + this.addButton.UseVisualStyleBackColor = true; + this.addButton.Click += new System.EventHandler(this.addButton_Click); + // + // ResultsConfig + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(399, 282); + this.Controls.Add(this.removeAllButton); + this.Controls.Add(this.removeButton); + this.Controls.Add(this.addButton); + this.Controls.Add(this.selectedResultsLabel); + this.Controls.Add(this.availableResultsLabel); + this.Controls.Add(this.selectedResultsListBox); + this.Controls.Add(this.availableResultsListBox); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Name = "ResultsConfig"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "ResultsConfig"; + this.Load += new System.EventHandler(this.ResultsConfig_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.ListBox availableResultsListBox; + private System.Windows.Forms.ListBox selectedResultsListBox; + private System.Windows.Forms.Label availableResultsLabel; + private System.Windows.Forms.Label selectedResultsLabel; + private System.Windows.Forms.Button removeAllButton; + private System.Windows.Forms.Button removeButton; + private System.Windows.Forms.Button addButton; + } +} \ No newline at end of file diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.resx b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/ResultsConfigDlg.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/Writer.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/Writer.cs new file mode 100644 index 000000000..26ed15acd --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/Writer.cs @@ -0,0 +1,361 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using System.Collections.Generic; +using System.IO; +using log4net; +using Config.Entities; +using TBF.BenchControl; +using TBF.Resources; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public class Writer : ComponentBase, IOperation, GenericDevices.IResultsWriter + { + private static readonly ILog log = LogManager.GetLogger(typeof(Writer)); + public override string ToString() { return string.Format("Output.FileWriters.Basic({0})", Cfg.ToString(1)); } + + readonly WriterCfg writerCfg; + readonly string separatorStr; + + /// + /// Result items to print + /// + IList rsltItems; + + /// + /// Results to print + /// + Results.Entities.Batch batch; + + StreamWriter writer; + + + public Writer() {} + + public Writer(WriterCfg cfg) + : base(cfg) + { + writerCfg = cfg; + + switch (cfg.Separator) + { + default: + case Separator.None: separatorStr = string.Empty; break; + case Separator.Space: separatorStr = " "; break; + case Separator.Tabulator: separatorStr = "\t"; break; + case Separator.Comma: separatorStr = ","; break; + case Separator.Semicolon: separatorStr = ";"; break; + } + + log.Debug(this.ToString()); + } + + + /// + /// Eliminate spaces conditionally, depesing on bool WriterCfg.EliminateSpaces + /// + /// Input string + /// Output string + string ElSpaces(string item) + { + if (writerCfg.EliminateSpaces) + return item.Replace(" ", string.Empty); + else + return item; + } + + + /// + /// Returns a file name derived from a DateTime structure. + /// Creates directories on this path as a side effect. + /// + /// Date and time + /// File name + string GetFilename(DateTime time) + { + string directory = writerCfg.DestinationPath; /// Ends with "\\"; + Directory.CreateDirectory(directory); + + if (writerCfg.YearFolders) + { + directory = string.Format("{0}{1}\\", directory, time.Year.ToString()); + Directory.CreateDirectory(directory); + } + + if (writerCfg.MonthFolders) + { + string monthStr /* = now.Month.ToString("D2")*/; + switch (time.Month) + { + default: + case 1: monthStr = "January"; break; + case 2: monthStr = "February"; break; + case 3: monthStr = "March"; break; + case 4: monthStr = "April"; break; + case 5: monthStr = "May"; break; + case 6: monthStr = "June"; break; + case 7: monthStr = "July"; break; + case 8: monthStr = "August"; break; + case 9: monthStr = "September"; break; + case 10: monthStr = "October"; break; + case 11: monthStr = "November"; break; + case 12: monthStr = "December"; break; + } + directory = string.Format("{0}{1}\\", directory, monthStr); + Directory.CreateDirectory(directory); + } + + if (writerCfg.DayFolders) + { + directory = string.Format("{0}{1}\\", directory, time.Day.ToString("D2")); + Directory.CreateDirectory(directory); + } + + return string.Format("{0}{1}{2}{3}-{4}{5}.txt", directory, (time.Year % 100).ToString("D2"), + time.Month.ToString("D2"), time.Day.ToString("D2"), time.Hour.ToString("D2"), time.Minute.ToString("D2")); + } + + /// + /// Writes the test cycle results into a file, Events: Event.ResultsWritten + /// + /// Procedure to print the results of + /// Results to write into the file + /// Reference to the operation + public IOperation WriteResultsOp(Results.Entities.Batch batchResults) + { + this.batch = batchResults; + + if (batch.WaterMeters.Count <= 0) + { + writer = null; + return this; + } + + rsltItems = Results.ItemSpec.FromStrArray(writerCfg.SelectedItems); + + try + { + writer = new StreamWriter(System.IO.File.Create(GetFilename(batch.EndTime))); + } + catch + { + writer = null; + } + + return this; + } + + /// Start this operation + public void Start() + { + if (writer == null) return; + + ///---------- + /// Header + ///---------- + writer.WriteLine(batch.ProtocolTitle); + writer.WriteLine(string.Empty); + + string[] leftColumn = new string[] + { + "Batch number: ", + "Date and time: ", + "Procedure:", + Strings.User_, + "Ambient temperature: ", + "Ambient pressure: ", + "Ambient humidity: ", + }; + + string[] rightColumn = new string[] + { + batch.BatchNr.ToString(), + //batch.EndTime.ToShortDateString() + " " + batch.EndTime.ToShortTimeString(), + string.Format("{0}.{1}.{2} {3}:{4}", batch.EndTime.Year.ToString("D4"), + batch.EndTime.Month.ToString("D2"), + batch.EndTime.Day.ToString("D2"), + batch.EndTime.Hour.ToString("D2"), + batch.EndTime.Minute.ToString("D2")), + batch.ProcedureName, + batch.UserName, + batch.AmbientTempAve().ToString("F1") + " °C", + batch.AmbientPressAve().ToString("F0") + " mbar", + batch.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++) + { + writer.Write(leftColumn[i]); + writer.Write(new string(' ', maxLen - leftColumn[i].Length + 3)); + writer.WriteLine(rightColumn[i]); + } + writer.WriteLine(string.Empty); + + + ///-------- + /// Body + ///-------- + foreach (var wm in batch.WaterMeters) WriteWM(wm); + } + + /// + /// Write one water meter results + /// + /// Water meter number (0-based) + void WriteWM(Results.Entities.WaterMeter wm) + { + /// Determine column widths + int[] columnWidths = new int[rsltItems.Count]; + int totalWidth = 0; + for (int i = 0; i < rsltItems.Count; i++) + { + columnWidths[i] = ElSpaces(rsltItems[i].ClmnHeaderText).Length; + foreach (var mtr in wm.MeterTestRslts) + { + if ((mtr != null) && (mtr.Publish() == Config.Entities.Publish.Always)) + { + string itemText; + + if (!wm.Compound()) + { + /// Single water meter + itemText = rsltItems[i].Print(mtr); + } + else if (mtr.CompoundMeterId == (byte)CompoundMeterId.Compound) + { + Results.Entities.MeterTestRslt mainMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundMain); + Results.Entities.MeterTestRslt auxMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundAux); + itemText = rsltItems[i].PrintCombined(mainMtr, auxMtr, mtr); + } + else + { + continue; + } + + /// Strip color information + string[] texts = itemText.Split(new char[] { '|' }); + if (texts.Length == 2) { itemText = texts[0]; } + + int len = ElSpaces(itemText).Length; + if (len > columnWidths[i]) columnWidths[i] = len; + } + } + totalWidth += columnWidths[i]; + } + totalWidth += 3 * (rsltItems.Count - 1); + if (totalWidth < 0) totalWidth = 0; + + + /// Write water meter number and s/n + writer.Write(string.Format("Water meter {0}", wm.WMPosition)); + if (!string.IsNullOrEmpty(wm.SerialNr)) writer.Write(string.Format(" s/n: {0}", wm.SerialNr)); + writer.WriteLine(string.Empty); + + + writer.WriteLine(new String('-', totalWidth)); /// Horizontal line above the header + + + /// Write column headers + for (int i = 0; i < rsltItems.Count; i++) + { + writer.Write(ElSpaces(rsltItems[i].ClmnHeaderText)); + + if (i < rsltItems.Count - 1) + { + if (!writerCfg.EliminateSpaces) + { + writer.Write(new string(' ', columnWidths[i] - rsltItems[i].ClmnHeaderText.Length + 3)); + } + writer.Write(separatorStr); + } + else + { + writer.WriteLine(string.Empty); + } + } + + + writer.WriteLine(new String('-', totalWidth)); /// Horizontal line between the header and the body + + + /// Write table data + foreach (var mtr in wm.MeterTestRslts) + { + if ((mtr != null) && (mtr.Publish() == Config.Entities.Publish.Always)) + { + for (int i = 0; i < rsltItems.Count; i++) + { + string itemText; + + /// + /// Fetch an item + /// + if (!wm.Compound()) + { + /// Single water meter + itemText = rsltItems[i].Print(mtr); + } + else if (mtr.CompoundMeterId == (byte)CompoundMeterId.Compound) + { + Results.Entities.MeterTestRslt mainMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundMain); + Results.Entities.MeterTestRslt auxMtr = wm.GetMeterTestRslt(mtr.Name(), CompoundMeterId.CompoundAux); + itemText = rsltItems[i].PrintCombined(mainMtr, auxMtr, mtr); + } + else + { + continue; + } + + /// + /// Print the item + /// + string[] texts = itemText.Split(new char[] { '|' }); + if (texts.Length == 2) { itemText = texts[0]; } /// Strip color information + + writer.Write(ElSpaces(itemText)); + + if (i < rsltItems.Count - 1) + { + if (!writerCfg.EliminateSpaces) + { + writer.Write(new string(' ', columnWidths[i] - itemText.Length + 3)); + } + writer.Write(separatorStr); + } + else + { + writer.WriteLine(string.Empty); + } + } + } + } + + writer.WriteLine(new String('-', totalWidth)); /// Horizontal line below the body + + writer.WriteLine(string.Empty); + } + + + /// Run this operation + /// Event.ResultsWritten + public Event Run() + { + return Event.ResultsWritten; + } + + + /// Stop this operation + public void Stop() + { + if (writer != null) writer.Close(); + writer = null; + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfg.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfg.cs new file mode 100644 index 000000000..563d52b6e --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfg.cs @@ -0,0 +1,67 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Serialization; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public enum Separator + { + None, + Space, + Tabulator, + Comma, + Semicolon, + Count + } + + public class WriterCfg : ComponentCfgBase, Generic.IComponentCfg + { + public IComponent GetComponent(IList components) { return new Writer(this); } + public IComponentCfgCtrl GetControl() { return new WriterCfgCtrl(); } + + public string DestinationPath; /// Directory path into which the results will be saved + public bool YearFolders; + public bool MonthFolders; + public bool DayFolders; + public Separator Separator; + public bool EliminateSpaces; + public string[] SelectedItems; + + + /// Private parameterless constructor invoked by all other (public) constructors + WriterCfg() + { + Name = "FileWriter"; + ParentName = string.Empty; + DestinationPath = Program.HomeDir + "Results\\"; + YearFolders = true; + MonthFolders = true; + DayFolders = false; + Separator = Separator.None; + EliminateSpaces = false; + } + + public WriterCfg(IComponentFactory factory) + : this() + { + this.Factory = factory; + } + + public string ToString(int i) + { + return string.Format("Name={0}, Path={1}, Y={2}, M={3}, D={4}, Elim.Spaces={5}, Separator={6}", + Name, + DestinationPath, + YearFolders, + MonthFolders, + DayFolders, + EliminateSpaces, + Separator); + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.cs new file mode 100644 index 000000000..845d10042 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.cs @@ -0,0 +1,163 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using log4net; +using TBF.BenchControl.Generic; + +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + public partial class WriterCfgCtrl : UserControl, IComponentCfgCtrl + { + static readonly ILog log = LogManager.GetLogger(typeof(WriterCfgCtrl)); + + public bool ShowMore { get { return false; } } + + public bool Compound; + + WriterCfg config; + public IComponentCfg Config + { + get { return config as IComponentCfg; } + set + { + config = value as WriterCfg; + Redraw(); + } + } + + public WriterCfgCtrl() + { + InitializeComponent(); + } + + private void WriterCfgCtrl_Load(object sender, EventArgs e) + { + for (int i = 0; i < (int)Separator.Count; i++) + { + separatorComboBox.Items.Add(((Separator)i).ToString()); + } + Redraw(); + } + + public void Closing() + { + } + + void Redraw() + { + if (config == null) return; /// Control was not loaded, settings were not changed + classNameLabel.Text = config.Factory.ClassName; + nameTextBox.Text = config.Name; + destinationTextBox.Text = config.DestinationPath; + yearFoldersCheckBox.Checked = config.YearFolders; + monthFoldersCheckBox.Checked = config.MonthFolders; + dayFoldersCheckBox.Checked = config.DayFolders; + separatorComboBox.Text = config.Separator.ToString(); + eliminateSpacesCheckBox.Checked = config.EliminateSpaces; + } + + public void Unlock() + { + nameTextBox.Enabled = true; + destinationTextBox.Enabled = true; + destinationButton.Enabled = true; + yearFoldersCheckBox.Enabled = true; + monthFoldersCheckBox.Enabled = true; + dayFoldersCheckBox.Enabled = true; + separatorComboBox.Enabled = true; + eliminateSpacesCheckBox.Enabled = true; + selectItemsButton.Enabled = true; + } + + public CfgUpdateFlags VerifyCfg(ref string message) + { + CfgUpdateFlags flags = CfgUpdateFlags.None; + + if (!separatorComboBox.Items.Contains(separatorComboBox.Text)) + { + flags |= CfgUpdateFlags.Error; + message += Environment.NewLine + "Invalid separator"; + } + return flags; + } + + public CfgUpdateFlags UpdateCfg() + { + CfgUpdateFlags flags = CfgUpdateFlags.None; + + if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed + + if (config.Name != nameTextBox.Text) { config.Name = nameTextBox.Text; flags = CfgUpdateFlags.RestartRqrd; } + + if (config.DestinationPath != destinationTextBox.Text) + { + config.DestinationPath = destinationTextBox.Text; + if (!config.DestinationPath.EndsWith("\\")) config.DestinationPath += "\\"; + flags = CfgUpdateFlags.RestartRqrd; + } + + if (yearFoldersCheckBox.Checked != config.YearFolders) + { + config.YearFolders = yearFoldersCheckBox.Checked; + flags = CfgUpdateFlags.RestartRqrd; + } + if (monthFoldersCheckBox.Checked != config.MonthFolders) + { + config.MonthFolders = monthFoldersCheckBox.Checked; + flags = CfgUpdateFlags.RestartRqrd; + } + if (dayFoldersCheckBox.Checked != config.DayFolders) + { + config.DayFolders = dayFoldersCheckBox.Checked; + flags = CfgUpdateFlags.RestartRqrd; + } + + for (int i = 0; i < (int)Separator.Count; i++) + { + if (((Separator)i).ToString().Equals(separatorComboBox.Text) && (config.Separator != (Separator)i)) + { + config.Separator = (Separator)i; + flags = CfgUpdateFlags.RestartRqrd; + break; + } + } + + if (eliminateSpacesCheckBox.Checked != config.EliminateSpaces) + { + config.EliminateSpaces = eliminateSpacesCheckBox.Checked; + flags = CfgUpdateFlags.RestartRqrd; + } + + return flags; + } + + private void destinationButton_Click(object sender, EventArgs e) + { + + } + + private void selectItemsButton_Click(object sender, EventArgs e) + { + ResultsConfigDlg dlg = new ResultsConfigDlg(); + dlg.Compound = config.Factory.ClassName.Contains("Compound"); + dlg.SelectedItems = Results.ItemSpec.FromStrArray(config.SelectedItems); + dlg.AvailableItems = new List(); + if (dlg.Compound) + { + foreach (var v in Results.ItemSpec.AllItems) if (v.CanPrintCombined) dlg.AvailableItems.Add(v); + } + else + { + foreach (var v in Results.ItemSpec.AllItems) if (v.CanPrintSingle) dlg.AvailableItems.Add(v); + } + + if (dlg.ShowDialog() == DialogResult.OK) + { + config.SelectedItems = Results.ItemSpec.ToStrArray(dlg.SelectedItems); + } + } + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.designer.cs b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.designer.cs new file mode 100644 index 000000000..7c5407dec --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.designer.cs @@ -0,0 +1,217 @@ +/// +/// Copyright (c) 2013-2016 Sensus Metering Systems +/// +namespace TBF.BenchControl.Output.FileWriters.Basic +{ + partial class WriterCfgCtrl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.nameTextBox = new System.Windows.Forms.TextBox(); + this.nameLabel = new System.Windows.Forms.Label(); + this.classNameLabel = new System.Windows.Forms.Label(); + this.destinationTextBox = new System.Windows.Forms.TextBox(); + this.destinationLabel = new System.Windows.Forms.Label(); + this.dayFoldersCheckBox = new System.Windows.Forms.CheckBox(); + this.destinationButton = new System.Windows.Forms.Button(); + this.yearFoldersCheckBox = new System.Windows.Forms.CheckBox(); + this.monthFoldersCheckBox = new System.Windows.Forms.CheckBox(); + this.eliminateSpacesCheckBox = new System.Windows.Forms.CheckBox(); + this.separatorLabel = new System.Windows.Forms.Label(); + this.separatorComboBox = new System.Windows.Forms.ComboBox(); + this.selectItemsButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // nameTextBox + // + this.nameTextBox.Enabled = false; + this.nameTextBox.Location = new System.Drawing.Point(108, 29); + this.nameTextBox.Name = "nameTextBox"; + this.nameTextBox.Size = new System.Drawing.Size(146, 20); + this.nameTextBox.TabIndex = 2; + // + // nameLabel + // + this.nameLabel.AutoSize = true; + this.nameLabel.Location = new System.Drawing.Point(17, 32); + this.nameLabel.Name = "nameLabel"; + this.nameLabel.Size = new System.Drawing.Size(35, 13); + this.nameLabel.TabIndex = 1; + this.nameLabel.Text = "Name"; + // + // classNameLabel + // + this.classNameLabel.AutoSize = true; + this.classNameLabel.Location = new System.Drawing.Point(105, 6); + this.classNameLabel.Name = "classNameLabel"; + this.classNameLabel.Size = new System.Drawing.Size(83, 13); + this.classNameLabel.TabIndex = 0; + this.classNameLabel.Text = "ComonentName"; + // + // destinationTextBox + // + this.destinationTextBox.Enabled = false; + this.destinationTextBox.Location = new System.Drawing.Point(108, 52); + this.destinationTextBox.Name = "destinationTextBox"; + this.destinationTextBox.Size = new System.Drawing.Size(146, 20); + this.destinationTextBox.TabIndex = 4; + // + // destinationLabel + // + this.destinationLabel.AutoSize = true; + this.destinationLabel.Location = new System.Drawing.Point(17, 55); + this.destinationLabel.Name = "destinationLabel"; + this.destinationLabel.Size = new System.Drawing.Size(60, 13); + this.destinationLabel.TabIndex = 3; + this.destinationLabel.Text = "Destination"; + // + // dayFoldersCheckBox + // + this.dayFoldersCheckBox.AutoSize = true; + this.dayFoldersCheckBox.Enabled = false; + this.dayFoldersCheckBox.Location = new System.Drawing.Point(109, 114); + this.dayFoldersCheckBox.Name = "dayFoldersCheckBox"; + this.dayFoldersCheckBox.Size = new System.Drawing.Size(79, 17); + this.dayFoldersCheckBox.TabIndex = 8; + this.dayFoldersCheckBox.Text = "Day folders"; + this.dayFoldersCheckBox.UseVisualStyleBackColor = true; + // + // destinationButton + // + this.destinationButton.Enabled = false; + this.destinationButton.Location = new System.Drawing.Point(259, 52); + this.destinationButton.Name = "destinationButton"; + this.destinationButton.Size = new System.Drawing.Size(30, 20); + this.destinationButton.TabIndex = 5; + this.destinationButton.Text = "..."; + this.destinationButton.UseVisualStyleBackColor = true; + this.destinationButton.Click += new System.EventHandler(this.destinationButton_Click); + // + // yearFoldersCheckBox + // + this.yearFoldersCheckBox.AutoSize = true; + this.yearFoldersCheckBox.Enabled = false; + this.yearFoldersCheckBox.Location = new System.Drawing.Point(109, 78); + this.yearFoldersCheckBox.Name = "yearFoldersCheckBox"; + this.yearFoldersCheckBox.Size = new System.Drawing.Size(82, 17); + this.yearFoldersCheckBox.TabIndex = 6; + this.yearFoldersCheckBox.Text = "Year folders"; + this.yearFoldersCheckBox.UseVisualStyleBackColor = true; + // + // monthFoldersCheckBox + // + this.monthFoldersCheckBox.AutoSize = true; + this.monthFoldersCheckBox.Enabled = false; + this.monthFoldersCheckBox.Location = new System.Drawing.Point(109, 96); + this.monthFoldersCheckBox.Name = "monthFoldersCheckBox"; + this.monthFoldersCheckBox.Size = new System.Drawing.Size(90, 17); + this.monthFoldersCheckBox.TabIndex = 7; + this.monthFoldersCheckBox.Text = "Month folders"; + this.monthFoldersCheckBox.UseVisualStyleBackColor = true; + // + // eliminateSpacesCheckBox + // + this.eliminateSpacesCheckBox.AutoSize = true; + this.eliminateSpacesCheckBox.Enabled = false; + this.eliminateSpacesCheckBox.Location = new System.Drawing.Point(109, 163); + this.eliminateSpacesCheckBox.Name = "eliminateSpacesCheckBox"; + this.eliminateSpacesCheckBox.Size = new System.Drawing.Size(165, 17); + this.eliminateSpacesCheckBox.TabIndex = 11; + this.eliminateSpacesCheckBox.Text = "Eliminate spaces in each field"; + this.eliminateSpacesCheckBox.UseVisualStyleBackColor = true; + // + // separatorLabel + // + this.separatorLabel.AutoSize = true; + this.separatorLabel.Location = new System.Drawing.Point(17, 139); + this.separatorLabel.Name = "separatorLabel"; + this.separatorLabel.Size = new System.Drawing.Size(53, 13); + this.separatorLabel.TabIndex = 9; + this.separatorLabel.Text = "Separator"; + // + // separatorComboBox + // + this.separatorComboBox.Enabled = false; + this.separatorComboBox.FormattingEnabled = true; + this.separatorComboBox.Location = new System.Drawing.Point(108, 136); + this.separatorComboBox.Name = "separatorComboBox"; + this.separatorComboBox.Size = new System.Drawing.Size(146, 21); + this.separatorComboBox.TabIndex = 10; + // + // selectItemsButton + // + this.selectItemsButton.Enabled = false; + this.selectItemsButton.Location = new System.Drawing.Point(109, 184); + this.selectItemsButton.Name = "selectItemsButton"; + this.selectItemsButton.Size = new System.Drawing.Size(145, 23); + this.selectItemsButton.TabIndex = 12; + this.selectItemsButton.Text = "Select items"; + this.selectItemsButton.UseVisualStyleBackColor = true; + this.selectItemsButton.Click += new System.EventHandler(this.selectItemsButton_Click); + // + // WriterCfgCtrl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.selectItemsButton); + this.Controls.Add(this.separatorComboBox); + this.Controls.Add(this.separatorLabel); + this.Controls.Add(this.eliminateSpacesCheckBox); + this.Controls.Add(this.monthFoldersCheckBox); + this.Controls.Add(this.yearFoldersCheckBox); + this.Controls.Add(this.destinationButton); + this.Controls.Add(this.dayFoldersCheckBox); + this.Controls.Add(this.destinationTextBox); + this.Controls.Add(this.destinationLabel); + this.Controls.Add(this.nameTextBox); + this.Controls.Add(this.nameLabel); + this.Controls.Add(this.classNameLabel); + this.Name = "WriterCfgCtrl"; + this.Size = new System.Drawing.Size(300, 230); + this.Load += new System.EventHandler(this.WriterCfgCtrl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.Label nameLabel; + private System.Windows.Forms.Label classNameLabel; + private System.Windows.Forms.TextBox destinationTextBox; + private System.Windows.Forms.Label destinationLabel; + private System.Windows.Forms.CheckBox dayFoldersCheckBox; + private System.Windows.Forms.Button destinationButton; + private System.Windows.Forms.CheckBox yearFoldersCheckBox; + private System.Windows.Forms.CheckBox monthFoldersCheckBox; + private System.Windows.Forms.CheckBox eliminateSpacesCheckBox; + private System.Windows.Forms.Label separatorLabel; + private System.Windows.Forms.ComboBox separatorComboBox; + private System.Windows.Forms.Button selectItemsButton; + } +} diff --git a/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.resx b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/TestBenchFramework/BenchControl/Output/FileWriters/Basic/WriterCfgCtrl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/TestBenchFramework/BenchControl/TbfComponents.cs b/TestBenchFramework/BenchControl/TbfComponents.cs index 86f2a60c5..db898b608 100644 --- a/TestBenchFramework/BenchControl/TbfComponents.cs +++ b/TestBenchFramework/BenchControl/TbfComponents.cs @@ -54,6 +54,8 @@ namespace TBF.BenchControl Factories.Add(new MettlerToledo.Standard.BalanceNewFactory()); /// MettlerToledoBalanceSN Factories.Add(new MettlerToledo.Multi.BalanceFactory()); /// MettlerToledo-Multi Factories.Add(new Modbus.Common.Factory()); /// Modbus + Factories.Add(new Output.FileWriters.Basic.FactorySingle()); /// Output.FileWriters.Basic.Single + Factories.Add(new Output.FileWriters.Basic.FactoryCompound()); /// Output.FileWriters.Basic.Compound Factories.Add(new TestMethods.PMaxTest.TestMethodFactory()); Factories.Add(new Elde.PressureMeter.PressureMeterFactory()); Factories.Add(new Elde.PressureMeterInternal.PressureMeterFactory()); diff --git a/TestBenchFramework/Properties/AssemblyInfo.cs b/TestBenchFramework/Properties/AssemblyInfo.cs index 9db530037..a1794337e 100644 --- a/TestBenchFramework/Properties/AssemblyInfo.cs +++ b/TestBenchFramework/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.5.273.1")] -[assembly: AssemblyFileVersion("2.5.273.1")] +[assembly: AssemblyVersion("2.5.274.1")] +[assembly: AssemblyFileVersion("2.5.274.1")] diff --git a/TestBenchFramework/TBF.csproj b/TestBenchFramework/TBF.csproj index 78d8d2334..2c439d7ae 100644 --- a/TestBenchFramework/TBF.csproj +++ b/TestBenchFramework/TBF.csproj @@ -391,6 +391,14 @@ + + + + Form + + + ResultsConfigDlg.cs + Component @@ -427,6 +435,14 @@ PrinterCfgCtrl.cs + + + + UserControl + + + WriterCfgCtrl.cs + @@ -1595,6 +1611,9 @@ MessageBoxForm.cs + + ResultsConfigDlg.cs + PrinterCfgCtrl.cs @@ -1613,6 +1632,9 @@ WriterCfgCtrl.cs + + WriterCfgCtrl.cs + TestMethodCfgCtrl.cs @@ -1970,7 +1992,9 @@ Results - + + +