From b74f1fd644f2bf877dceac895d42dfc8d2eed39b Mon Sep 17 00:00:00 2001 From: Marek Frniak Date: Fri, 3 Jul 2026 12:46:56 +0200 Subject: [PATCH] Add (develop) - first succesfull test - new component ResultsWriter - note: IResultsProcessor type componet, store result variables to database by using of component UniDataStorageWriter to the user-configured storage. The selection of variables is done using the standard UI for selecting the display of measurement results . In other words: The measurement results selected by the user are saved to a user-defined storage. --- TBF/Rig/Output/DB/ResultsWriter/Factory.cs | 39 +++ .../Output/DB/ResultsWriter/ResultsWriter.cs | 279 ++++++++++++++++++ .../DB/ResultsWriter/ResultsWriterCfg.cs | 88 ++++++ .../ResultsWriterCfgCtrl.Designer.cs | 142 +++++++++ .../DB/ResultsWriter/ResultsWriterCfgCtrl.cs | 243 +++++++++++++++ .../DB/ResultsWriter/ResultsWriterItemCfg.cs | 44 +++ .../ResultsWriterResultsDlg.Designer.cs | 72 +++++ .../ResultsWriter/ResultsWriterResultsDlg.cs | 45 +++ TBF/Rig/TbfComponents.cs | 1 + TBF/TBF.csproj | 16 + 10 files changed, 969 insertions(+) create mode 100644 TBF/Rig/Output/DB/ResultsWriter/Factory.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriter.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfg.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.Designer.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterItemCfg.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.Designer.cs create mode 100644 TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.cs diff --git a/TBF/Rig/Output/DB/ResultsWriter/Factory.cs b/TBF/Rig/Output/DB/ResultsWriter/Factory.cs new file mode 100644 index 000000000..af590a324 --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/Factory.cs @@ -0,0 +1,39 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +using System.Collections.Generic; +using TBF.Rig.Generic; + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + /// + /// Factory component 'ResultsWriter'. + /// Writes selected result items to database using parent UniDataStorageWriter. + /// + public class Factory : IComponentFactory + { + public string ClassName { get { return GetType().Namespace.Substring(8); } } + public override string ToString() { return ClassName; } + + public IComponent DummyComponent() + { + return new ResultsWriter(); + } + + public IComponent GetComponent(IComponentCfg cfg, IList components) + { + return new ResultsWriter(cfg, components); + } + + public IComponentCfg DefaultConfig() + { + return new ResultsWriterCfg("ResultsWriter", this); + } + + public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component) + { + return ComponentCfgBase.CreateFromDbEntity(ResultsWriterCfg.Serializer, component, this); + } + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriter.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriter.cs new file mode 100644 index 000000000..fb3dc3b3c --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriter.cs @@ -0,0 +1,279 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +using Common; +using log4net; +using Results.Entities; +using System; +using System.Collections.Generic; +using System.Linq; +using TBF.Rig.Generic; +using TBF.Rig.Output.DataStorage.UniDataStorageWriter; +using TBF.Rig.Output.DataStorage.UniDataStorageWriter.Interfaces; +using TBF.Rig.Sequences; + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + public class ResultsWriter : ComponentBase, IOperation, GenericDevices.IResultsWriter, Generic.IDevice + { + private static readonly ILog log = LogManager.GetLogger(typeof(ResultsWriter)); + + public override string ToString() + { + return string.Format("{0}({1})", ClassName, Cfg.ToString(-1)); + } + + ResultsWriterCfg resultsWriterCfg; + + Batch batch; + + bool opCompleted; + bool anyError; + + enum OpState + { + None, + WriteResultsScheduled, + WriteResultsRunning, + } + + OpState currentOpState; + + TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer dataStorageWriter; + + public ResultsWriter() + { + } + + public ResultsWriter(IComponentCfg cfg, IList components) : base(cfg) + { + resultsWriterCfg = cfg as ResultsWriterCfg; + if (resultsWriterCfg == null) + throw new ArgumentException("resultsWriterCfg"); + + currentOpState = OpState.None; + + log.Warn(this.ToString()); + + IComponent parent = + components.FirstOrDefault(c => c.Name == resultsWriterCfg.ParentName); + + if (parent == null) + { + throw new Exception( + string.Format("Parent '{0}' was not found.", + resultsWriterCfg.ParentName)); + } + + log.WarnFormat( + "ResultsWriter parent found: Name={0}, Type={1}", + parent.Name, + parent.GetType().FullName); + + dataStorageWriter = parent as TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer; + + if (dataStorageWriter == null) + { + throw new Exception( + string.Format( + "Parent '{0}' of type '{1}' is not UniDataStorageWriter.Writer.", + resultsWriterCfg.ParentName, + parent.GetType().FullName)); + } + } + + public ResultsWriter(IComponentCfg cfg) : base(cfg) + { + resultsWriterCfg = cfg as ResultsWriterCfg; + if (resultsWriterCfg == null) + throw new ArgumentException("resultsWriterCfg"); + + currentOpState = OpState.None; + + log.Warn(this.ToString()); + } + + /// + /// IDevice interface implementation + /// + public override void Initialize() + { + } + + public void RunDeviceBefore() + { + } + + public void RunDeviceAfter() + { + } + + public void StopDevice() + { + } + + public void StopDevice2() + { + } + + /// + /// GenericDevices.IResultsWriter + /// + public IOperation ProcessResultsOp(Batch batch) + { + if (!resultsWriterCfg.Enabled) + { + return null; + } + + if (currentOpState == OpState.WriteResultsRunning) + { + throw new Exception("Sequence error"); + } + + this.batch = batch; + currentOpState = OpState.WriteResultsScheduled; + return this; + } + + /// + /// IOperation + /// + public void Start() + { + if (currentOpState == OpState.WriteResultsScheduled) + { + currentOpState = OpState.WriteResultsRunning; + } + + opCompleted = false; + anyError = false; + } + + public Event Run() + { + log.WarnFormat("{0} : Run() : currentOp = {1}", Name, currentOpState); + + if (currentOpState == OpState.WriteResultsRunning) + { + if (resultsWriterCfg.DebugLevel == DebugMode.Simulate) + { + return Event.ResultsWritten; + } + + if (batch == null || batch.WaterMeters == null || batch.WaterMeters.Count == 0) + { + return Event.ResultsWritten; + } + + if (opCompleted) + { + return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten; + } + + opCompleted = true; + + try + { + WriteBatchResults(batch); + } + catch (Exception exc) + { + anyError = true; + log.ErrorFormat("Failed to write results by ResultsWriter: {0}", exc); + } + + return anyError ? Event.ErrorProcessingResults : Event.ResultsWritten; + } + + return Event.None; + } + + public void Stop() + { + currentOpState = OpState.None; + } + + public void WriteBatchResults(Batch batch) + { + resultsWriterCfg.UpdateRuntimeModel(); + + foreach (var wm in batch.WaterMeters) + { + if (wm == null || wm.Disabled) + continue; + + DataWriteRequest request = BuildWriteRequest(wm); + + if (request.InsertItems.Count == 0) + { + log.WarnFormat("No values to write for WM position {0}", wm.WMPosition); + continue; + } + + var result = dataStorageWriter.SetData(request); + + if (!result.Success) + { + throw new Exception(result.Message); + } + + log.WarnFormat( + "ResultsWriter wrote {0} value(s) for WM position {1}", + request.InsertItems.Count, + wm.WMPosition); + } + } + + DataWriteRequest BuildWriteRequest(WaterMeter wm) + { + var request = new DataWriteRequest(); + request.Mode = WriteMode.Insert; + + if (resultsWriterCfg.SelectedItems == null) + return request; + + foreach (var item in resultsWriterCfg.SelectedItems) + { + if (item == null) + continue; + + string columnName = item.Caption; + + if (string.IsNullOrWhiteSpace(columnName)) + { + log.WarnFormat("Result item with empty Caption skipped: {0}", item); + continue; + } + + request.InsertItems.Add(new InsertWriteItem() + { + ColumnName = columnName, + Value = item.Print(wm) + }); + } + + return request; + } + + public void InitializeParent() + { + IComponent parent = TbfComponents.FindComponent(resultsWriterCfg.ParentName); + + if (parent == null) + throw new Exception( + string.Format("Parent '{0}' was not found.", resultsWriterCfg.ParentName)); + + dataStorageWriter = + parent as TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writer; + + if (dataStorageWriter == null) + throw new Exception( + string.Format( + "Parent '{0}' of type '{1}' is not UniDataStorageWriter.Writer.", + resultsWriterCfg.ParentName, + parent.GetType().FullName)); + } + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfg.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfg.cs new file mode 100644 index 000000000..fe240d6bd --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfg.cs @@ -0,0 +1,88 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +using System.Collections.Generic; +using System.Xml.Serialization; +using Results; +using TBF.Rig.Generic; + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + public class ResultsWriterCfg : ComponentCfgBase, IComponentCfg + { + public static XmlSerializer Serializer = + XmlSerializer.FromTypes(new[] { typeof(ResultsWriterCfg) })[0]; + + public override XmlSerializer GetSerializer() + { + return Serializer; + } + + public IComponentCfgCtrl GetControl(IList cmpntEntities) + { + return new ResultsWriterCfgCtrl(cmpntEntities); + } + + /// + /// Enables or disables writing. + /// + public bool Enabled; + + /// + /// Target table or logical storage name for UniDataStorageWriter. + /// + public string StorageName; + + /// Runtime model používaný ResultsConfigCtrl + [XmlIgnore] + public List SelectedItems; + + public string[] Items; + + /// Serializable model + public List SelectedItemsCfg; + + ResultsWriterCfg() + { + ParentName = string.Empty; // here should be UniDataStorageWriter component name + SelectedItems = new List(); + SelectedItemsCfg = new List(); + Enabled = true; + StorageName = "Results"; + } + + public ResultsWriterCfg(string name, IComponentFactory factory) + : this() + { + Name = name; + Factory = factory; + } + + public string ToString(int i) + { + return string.Format( + "Name={0}, Parent={1}, Enabled={2}, StorageName={3}, Items={4}", + Name, + ParentName, + Enabled, + StorageName, + SelectedItems != null ? SelectedItems.Count : 0); + } + + public void UpdateSerializableModel() + { + Items = WMeterRsltItemSpec.ToStrArray(SelectedItems); + } + + public void UpdateRuntimeModel() + { + SelectedItems = new List(); + + if (Items == null) + return; + + SelectedItems.AddRange(WMeterRsltItemSpec.FromStrArray(Items)); + } + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.Designer.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.Designer.cs new file mode 100644 index 000000000..d01e59c1a --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.Designer.cs @@ -0,0 +1,142 @@ +namespace TBF.Rig.Output.DB.ResultsWriter +{ + partial class ResultsWriterCfgCtrl + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) components.Dispose(); + base.Dispose(disposing); + } + + private void InitializeComponent() + { + this.classNameLabel = new System.Windows.Forms.Label(); + this.nameTextBox = new System.Windows.Forms.TextBox(); + this.nameLabel = new System.Windows.Forms.Label(); + this.parentLabel = new System.Windows.Forms.Label(); + this.parentComboBox = new System.Windows.Forms.ComboBox(); + this.enabledCheckBox = new System.Windows.Forms.CheckBox(); + this.storageNameLabel = new System.Windows.Forms.Label(); + this.storageNameTextBox = new System.Windows.Forms.TextBox(); + this.configureResultsButton = new System.Windows.Forms.Button(); + this.selectedItemsLabel = new System.Windows.Forms.Label(); + this.previewRequestButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + + this.previewRequestButton.Enabled = false; + this.previewRequestButton.Location = new System.Drawing.Point(150, 204); + this.previewRequestButton.Name = "previewRequestButton"; + this.previewRequestButton.Size = new System.Drawing.Size(160, 30); + this.previewRequestButton.TabIndex = 10; + this.previewRequestButton.Text = "Preview request..."; + this.previewRequestButton.UseVisualStyleBackColor = true; + this.previewRequestButton.Click += new System.EventHandler(this.previewRequestButton_Click); + + this.classNameLabel.AutoSize = true; + this.classNameLabel.Location = new System.Drawing.Point(14, 12); + this.classNameLabel.Name = "classNameLabel"; + this.classNameLabel.Size = new System.Drawing.Size(75, 13); + this.classNameLabel.TabIndex = 0; + this.classNameLabel.Text = "ResultsWriter"; + + this.nameLabel.AutoSize = true; + this.nameLabel.Location = new System.Drawing.Point(14, 45); + this.nameLabel.Name = "nameLabel"; + this.nameLabel.Size = new System.Drawing.Size(38, 13); + this.nameLabel.TabIndex = 1; + this.nameLabel.Text = "Name:"; + + this.nameTextBox.Enabled = false; + this.nameTextBox.Location = new System.Drawing.Point(150, 42); + this.nameTextBox.Name = "nameTextBox"; + this.nameTextBox.Size = new System.Drawing.Size(260, 20); + this.nameTextBox.TabIndex = 2; + + this.parentLabel.AutoSize = true; + this.parentLabel.Location = new System.Drawing.Point(14, 75); + this.parentLabel.Name = "parentLabel"; + this.parentLabel.Size = new System.Drawing.Size(123, 13); + this.parentLabel.TabIndex = 3; + this.parentLabel.Text = "UniDataStorageWriter:"; + + this.parentComboBox.Enabled = false; + this.parentComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.parentComboBox.FormattingEnabled = true; + this.parentComboBox.Location = new System.Drawing.Point(150, 72); + this.parentComboBox.Name = "parentComboBox"; + this.parentComboBox.Size = new System.Drawing.Size(260, 21); + this.parentComboBox.TabIndex = 4; + + this.enabledCheckBox.AutoSize = true; + this.enabledCheckBox.Enabled = false; + this.enabledCheckBox.Location = new System.Drawing.Point(150, 103); + this.enabledCheckBox.Name = "enabledCheckBox"; + this.enabledCheckBox.Size = new System.Drawing.Size(65, 17); + this.enabledCheckBox.TabIndex = 5; + this.enabledCheckBox.Text = "Enabled"; + this.enabledCheckBox.UseVisualStyleBackColor = true; + + this.storageNameLabel.AutoSize = true; + this.storageNameLabel.Location = new System.Drawing.Point(14, 133); + this.storageNameLabel.Name = "storageNameLabel"; + this.storageNameLabel.Size = new System.Drawing.Size(77, 13); + this.storageNameLabel.TabIndex = 6; + this.storageNameLabel.Text = "Storage name:"; + + this.storageNameTextBox.Enabled = false; + this.storageNameTextBox.Location = new System.Drawing.Point(150, 130); + this.storageNameTextBox.Name = "storageNameTextBox"; + this.storageNameTextBox.Size = new System.Drawing.Size(260, 20); + this.storageNameTextBox.TabIndex = 7; + + this.configureResultsButton.Enabled = false; + this.configureResultsButton.Location = new System.Drawing.Point(150, 168); + this.configureResultsButton.Name = "configureResultsButton"; + this.configureResultsButton.Size = new System.Drawing.Size(160, 30); + this.configureResultsButton.TabIndex = 8; + this.configureResultsButton.Text = "Configure results..."; + this.configureResultsButton.UseVisualStyleBackColor = true; + this.configureResultsButton.Click += new System.EventHandler(this.configureResultsButton_Click); + + this.selectedItemsLabel.AutoSize = true; + this.selectedItemsLabel.Location = new System.Drawing.Point(325, 176); + this.selectedItemsLabel.Name = "selectedItemsLabel"; + this.selectedItemsLabel.Size = new System.Drawing.Size(92, 13); + this.selectedItemsLabel.TabIndex = 9; + this.selectedItemsLabel.Text = "0 selected item(s)"; + + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.selectedItemsLabel); + this.Controls.Add(this.configureResultsButton); + this.Controls.Add(this.storageNameTextBox); + this.Controls.Add(this.storageNameLabel); + this.Controls.Add(this.enabledCheckBox); + this.Controls.Add(this.parentComboBox); + this.Controls.Add(this.parentLabel); + this.Controls.Add(this.nameTextBox); + this.Controls.Add(this.nameLabel); + this.Controls.Add(this.classNameLabel); + this.Controls.Add(this.previewRequestButton); + this.Name = "ResultsWriterCfgCtrl"; + this.Size = new System.Drawing.Size(620, 260); + this.Load += new System.EventHandler(this.ResultsWriterCfgCtrl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + } + + private System.Windows.Forms.Label classNameLabel; + private System.Windows.Forms.TextBox nameTextBox; + private System.Windows.Forms.Label nameLabel; + private System.Windows.Forms.Label parentLabel; + private System.Windows.Forms.ComboBox parentComboBox; + private System.Windows.Forms.CheckBox enabledCheckBox; + private System.Windows.Forms.Label storageNameLabel; + private System.Windows.Forms.TextBox storageNameTextBox; + private System.Windows.Forms.Button configureResultsButton; + private System.Windows.Forms.Label selectedItemsLabel; + private System.Windows.Forms.Button previewRequestButton; + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.cs new file mode 100644 index 000000000..f8c9a9f00 --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterCfgCtrl.cs @@ -0,0 +1,243 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Common; +using Config.Entities; +using TBF.Rig.Generic; + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + public partial class ResultsWriterCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl + { + public bool ShowMore { get { return false; } } + + ResultsWriterCfg config; + IList cmpntEntities; + + bool resultsConfigChanged; + + public IComponentCfg Config + { + get { return config as IComponentCfg; } + set + { + config = value as ResultsWriterCfg; + Redraw(); + } + } + + public ResultsWriterCfgCtrl(IList cmpntEntities) + { + InitializeComponent(); + this.cmpntEntities = cmpntEntities; + } + + private void ResultsWriterCfgCtrl_Load(object sender, EventArgs e) + { + if (config == null) return; + Redraw(); + } + + public void Closing() + { + } + + void Redraw() + { + if (config == null) return; + + config.UpdateRuntimeModel(); + + classNameLabel.Text = config.Factory.ClassName; + nameTextBox.Text = config.Name; + enabledCheckBox.Checked = config.Enabled; + storageNameTextBox.Text = config.StorageName; + + parentComboBox.Items.Clear(); + parentComboBox.Items.Add(string.Empty); + + if (cmpntEntities != null) + { + foreach (Component cmpnt in cmpntEntities) + { + if (cmpnt == null) continue; + + // zatiaľ jednoduchý filter podľa názvu/classname + if (cmpnt.ClassName != null && + cmpnt.ClassName.IndexOf("UniDataStorageWriter") >= 0) + { + parentComboBox.Items.Add(cmpnt.Name); + } + } + } + + parentComboBox.Text = config.ParentName; + + selectedItemsLabel.Text = string.Format( + "{0} selected item(s)", + config.SelectedItems != null ? config.SelectedItems.Count : 0); + + resultsConfigChanged = false; + } + + public void Unlock() + { + nameTextBox.Enabled = true; + enabledCheckBox.Enabled = true; + parentComboBox.Enabled = true; + storageNameTextBox.Enabled = true; + configureResultsButton.Enabled = true; + previewRequestButton.Enabled = true; + } + + public CfgUpdateFlags VerifyCfg(ref string message) + { + if (string.IsNullOrEmpty(nameTextBox.Text)) + { + message = "Component name is empty."; + return CfgUpdateFlags.Error; + } + + if (enabledCheckBox.Checked && string.IsNullOrEmpty(parentComboBox.Text)) + { + message = "Parent UniDataStorageWriter is not selected."; + return CfgUpdateFlags.Error; + } + + if (enabledCheckBox.Checked && string.IsNullOrEmpty(storageNameTextBox.Text)) + { + message = "Storage name is empty."; + return CfgUpdateFlags.Error; + } + + return CfgUpdateFlags.None; + } + + public CfgUpdateFlags UpdateCfg() + { + CfgUpdateFlags flags = CfgUpdateFlags.None; + + if (config == null) return CfgUpdateFlags.Error; + + if (config.Name != nameTextBox.Text) + { + config.Name = nameTextBox.Text; + flags |= CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd; + } + + if (config.ParentName != parentComboBox.Text) + { + config.ParentName = parentComboBox.Text; + flags |= CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd; + } + + flags |= UpdateDifferent( + ref config.Enabled, + enabledCheckBox.Checked, + CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); + + flags |= UpdateDifferent( + ref config.StorageName, + storageNameTextBox.Text, + CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd); + + if (resultsConfigChanged) + { + flags |= CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd; + resultsConfigChanged = false; + } + + return flags; + } + + private void configureResultsButton_Click(object sender, EventArgs e) + { + if (config == null) return; + + using (ResultsWriterResultsDlg dlg = new ResultsWriterResultsDlg()) + { + dlg.SelectedItems = config.SelectedItems; + + if (dlg.ShowDialog(this) == DialogResult.OK) + { + config.SelectedItems = new List(dlg.SelectedItems); + config.UpdateSerializableModel(); + resultsConfigChanged = true; + + selectedItemsLabel.Text = string.Format( + "{0} selected item(s)", + config.SelectedItems != null ? config.SelectedItems.Count : 0); + } + } + } + + private void previewRequestButton_Click(object sender, EventArgs e) + { + if (config == null) return; + + Results.Entities.Batch batch = CreateSimulationBatch(); + + if (batch == null || batch.WaterMeters == null || batch.WaterMeters.Count == 0) + { + MessageBox.Show( + "No current batch results are available.", + "ResultsWriter", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + return; + } + + try + { + config.UpdateRuntimeModel(); + + ResultsWriter writer = new ResultsWriter(config); + writer.InitializeParent(); + writer.WriteBatchResults(batch); + + MessageBox.Show( + "Current batch was written by ResultsWriter.", + "ResultsWriter", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + catch (Exception ex) + { + MessageBox.Show( + ex.Message, + "ResultsWriter write failed", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + private Results.Entities.Batch CreateSimulationBatch() + { + Results.Entities.Batch batch = new Results.Entities.Batch(); + + batch.BatchNr = 999999; + batch.ProcedureName = "ResultsWriter simulation"; + batch.StartTime = DateTime.Now; + batch.EndTime = DateTime.Now; + batch.TestBenchName = "Mexico"; + + Results.Entities.WaterMeter wm1 = new Results.Entities.WaterMeter(); + wm1.Batch = batch; + wm1.WMPosition = 1; + wm1.SerialNr = "SN000001"; + batch.WaterMeters.Add(wm1); + + Results.Entities.WaterMeter wm2 = new Results.Entities.WaterMeter(); + wm2.Batch = batch; + wm2.WMPosition = 2; + wm2.SerialNr = "SN000002"; + batch.WaterMeters.Add(wm2); + + return batch; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterItemCfg.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterItemCfg.cs new file mode 100644 index 000000000..e74f763ab --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterItemCfg.cs @@ -0,0 +1,44 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + /// + /// Serializable representation of one configured Results item. + /// Source identifies the original TBF variable, Caption represents + /// the destination database column name. + /// + public class ResultsWriterItemCfg + { + /// + /// Original Results expression (for rebuilding the model). + /// Example: "Conduct.ME()" + /// + public string Source; + + /// + /// Destination database column name. + /// + public string Caption; + + public string Units; + public string Format; + + public int Precision; + public int Width; + + public string Alignment; + public bool Merge; + + public ResultsWriterItemCfg() + { + Source = string.Empty; + Caption = string.Empty; + Units = string.Empty; + Format = string.Empty; + Alignment = string.Empty; + Merge = false; + } + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.Designer.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.Designer.cs new file mode 100644 index 000000000..4616194cc --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.Designer.cs @@ -0,0 +1,72 @@ +namespace TBF.Rig.Output.DB.ResultsWriter +{ + partial class ResultsWriterResultsDlg + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) components.Dispose(); + base.Dispose(disposing); + } + + private void InitializeComponent() + { + this.resultsConfigCtrl = new Results.Forms.ResultsConfigCtrl(); + this.okButton = new System.Windows.Forms.Button(); + this.cancelButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + + this.resultsConfigCtrl.Anchor = + ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | + System.Windows.Forms.AnchorStyles.Bottom) | + System.Windows.Forms.AnchorStyles.Left) | + System.Windows.Forms.AnchorStyles.Right))); + this.resultsConfigCtrl.Location = new System.Drawing.Point(3, 3); + this.resultsConfigCtrl.Name = "resultsConfigCtrl"; + this.resultsConfigCtrl.Size = new System.Drawing.Size(925, 496); + this.resultsConfigCtrl.TabIndex = 0; + this.resultsConfigCtrl.Unlocked = true; + + this.okButton.Anchor = + ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Right))); + this.okButton.Location = new System.Drawing.Point(714, 512); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(104, 30); + this.okButton.TabIndex = 1; + this.okButton.Text = "OK"; + this.okButton.UseVisualStyleBackColor = true; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + + this.cancelButton.Anchor = + ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(824, 512); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(104, 30); + this.cancelButton.TabIndex = 2; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + + this.AcceptButton = this.okButton; + this.CancelButton = this.cancelButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(940, 554); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.okButton); + this.Controls.Add(this.resultsConfigCtrl); + this.Name = "ResultsWriterResultsDlg"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "ResultsWriter configuration"; + this.Load += new System.EventHandler(this.ResultsWriterResultsDlg_Load); + this.ResumeLayout(false); + } + + private Results.Forms.ResultsConfigCtrl resultsConfigCtrl; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.Button cancelButton; + } +} \ No newline at end of file diff --git a/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.cs b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.cs new file mode 100644 index 000000000..ae5021d82 --- /dev/null +++ b/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.cs @@ -0,0 +1,45 @@ +/// +/// Copyright (c) 2026 Sensus Slovensko a.s. +/// + +using Results; +using Results.Forms; +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using TBF.Resources; + +namespace TBF.Rig.Output.DB.ResultsWriter +{ + public partial class ResultsWriterResultsDlg : Form + { + public IList SelectedItems + { + set { resultsConfigCtrl.SelectedItems = value; } + get { return resultsConfigCtrl.SelectedItems; } + } + + public ResultsWriterResultsDlg() + { + InitializeComponent(); + + this.Icon = Properties.Resources.TBF_icon; + resultsConfigCtrl.SupressTestIDColumn = true; + } + + private void ResultsWriterResultsDlg_Load(object sender, EventArgs e) + { + Text = "ResultsWriter configuration"; + okButton.Text = Strings.OkBtnText; + cancelButton.Text = Strings.CancelBtnText; + + resultsConfigCtrl.Unlocked = true; + } + + private void okButton_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + Close(); + } + } +} \ No newline at end of file diff --git a/TBF/Rig/TbfComponents.cs b/TBF/Rig/TbfComponents.cs index 677fc5fb7..c8993abaa 100644 --- a/TBF/Rig/TbfComponents.cs +++ b/TBF/Rig/TbfComponents.cs @@ -99,6 +99,7 @@ namespace TBF.Rig new Output.DataStorage.UniDataStorageWriter.Factory(), new Output.DB.DatabaseWriter.Factory(), new Output.DB.ProductionTracing.Factory(), + new Output.DB.ResultsWriter.Factory(), new Output.DB.SaveDiverterCorrections.Factory(), new Output.DB.SaveFlowmeterCorrections.Factory(), new Output.DB.SensusOracle.Factory(), diff --git a/TBF/TBF.csproj b/TBF/TBF.csproj index 35f912781..8e4c09a81 100644 --- a/TBF/TBF.csproj +++ b/TBF/TBF.csproj @@ -1236,6 +1236,22 @@ + + + + + UserControl + + + ResultsWriterCfgCtrl.cs + + + + Form + + + ResultsWriterResultsDlg.cs +