/// /// Copyright (c) 2021 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Threading; using System.Windows.Forms; using log4net; using TBF.BenchControl.RegisterReaders.DataStream.MefImport; using TBF.Resources; namespace TBF.BenchControl.DataEntry.DataStream { public enum CommErr { None = 0, CommFailed, /// 1 HeadDisabledByUser, /// 2 } public partial class CycleBeginningForm : Form, GenericDevices.IHasCompleted { private static readonly ILog log = LogManager.GetLogger(typeof(CycleBeginningForm)); public static Color InitialColor = Color.LightGray; public static Color DisabledColor = Color.DarkGray; public static Color OptoOKColor = Color.Green; public static Color OptoNokColor = Color.Red; public static Color BusyColor = Color.Yellow; /// Number of water meters IList waterMeters; MefImport mefImport; /// To be retrieved after the form is closed public string PurchaseOrder; public string[] SNText; public bool[] Disabled; /// Set to 'true' when the form closes public bool Completed { get { return formCompleted; } } bool formCompleted; Thread thread; public int DataStreamsCount; int busyIx; /// Number of text boxes for serial numbers Label[] labels; CheckBoxImage[] checkBoxes; PictureBox[] pictures; TextBox[] serialNrBoxes; IList enabledSerialNrBoxes; /// Parameterless constructor for common functionality public CycleBeginningForm() { InitializeComponent(); ControlBox = false; labels = new Label[] { label1, label2, label3, label4, label5, label6, label7, label8, label9, label10, label11, label12, label13, label14, label15, label16, label17, label18, label19, label20, label21, label22, label23, label24, }; checkBoxes = new CheckBoxImage[] { checkBoxImage1, checkBoxImage2, checkBoxImage3, checkBoxImage4, checkBoxImage5, checkBoxImage6, checkBoxImage7, checkBoxImage8, checkBoxImage9, checkBoxImage10, checkBoxImage11, checkBoxImage12, checkBoxImage13, checkBoxImage14, checkBoxImage15, checkBoxImage16, checkBoxImage17, checkBoxImage18, checkBoxImage19, checkBoxImage20, checkBoxImage21, checkBoxImage22, checkBoxImage23, checkBoxImage24, }; pictures = new PictureBox[] { pictureBox1, pictureBox2, pictureBox3, pictureBox4, pictureBox5, pictureBox6, pictureBox7, pictureBox8, pictureBox9, pictureBox10, pictureBox11, pictureBox12, pictureBox13, pictureBox14, pictureBox15, pictureBox16, pictureBox17, pictureBox18, pictureBox19, pictureBox20, pictureBox21, pictureBox22, pictureBox23, pictureBox24, }; serialNrBoxes = new TextBox[] { serialNrBox1, serialNrBox2, serialNrBox3, serialNrBox4, serialNrBox5, serialNrBox6, serialNrBox7, serialNrBox8, serialNrBox9, serialNrBox10, serialNrBox11, serialNrBox12, serialNrBox13, serialNrBox14, serialNrBox15, serialNrBox16, serialNrBox17, serialNrBox18, serialNrBox19, serialNrBox20, serialNrBox21, serialNrBox22, serialNrBox23, serialNrBox24, }; } /// /// Constructor /// /// Number of text boxes for serial numbers public CycleBeginningForm(IList waterMeters, MefImport mefImport) : this() { this.waterMeters = waterMeters; this.mefImport = mefImport; SNText = new string[waterMeters.Count]; Disabled = new bool[waterMeters.Count]; Localize(); PrepareOrderCombo(orderComboBox); int wmsCount = Math.Min(mefImport.DataStreamIFace.GetMetersCount(), waterMeters.Count); int right, bottom; enabledSerialNrBoxes = ShuffleTextBoxes(wmsCount, TBF.Data.LineSize, out right, out bottom); Height = bottom + 60; DataStreamsCount = enabledSerialNrBoxes.Count; SetCheckBoxStates(Program.LocalSettings.OptoHeadsEnabled); busyIx = -1; formCompleted = false; StartForceCloseHandler(); /// Attach to handlers OpenConnStartedHandler += delegate(object sender, OpenConnectionEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(DoOnOpenConnStarted), sender, args); } else { DoOnOpenConnStarted(sender, args); } }; OpenConnCompletedHandler += delegate(object sender, OpenConnectionEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(DoOnOpenConnCompleted), sender, args); } else { DoOnOpenConnCompleted(sender, args); } }; /// /// Start communication with water meters in the worker thread /// thread = new Thread(Worker); thread.CurrentCulture = CultureInfo.CurrentCulture; thread.CurrentUICulture = CultureInfo.CurrentUICulture; thread.Start(); } void Localize() { Text = Strings.Opening_connections_with_water_meters; orderGroupBox.Text = Strings.Purchase_order; okButton.Text = Strings.OkBtnText; retryButton.Text = Strings.RetryBtnText; } /// /// Load Purchase order combo box items from the LocalSettings PurchaseOrderHistory array /// /// Puchase order ComboBox void PrepareOrderCombo(ComboBox orderComboBox) { for (int i = 0; i < Program.LocalSettings.PurchaseOrderHistoryCount; i++) { orderComboBox.Items.Add(Program.LocalSettings.PurchaseOrderHistory[i]); } if (orderComboBox.Items.Count > 0) { orderComboBox.Text = orderComboBox.Items[0].ToString(); } } /// /// Makes layout of labels/text boxes on the screen the same /// as the layout of watermeters on the test bench. /// To be used only once in the constructor or in the form load handler. /// /// Number of water meters /// Number of water meters in one line /// Right coordinate of the rightmost TextBox /// Bottom coordinate of the bottommost TextBox /// List of enabled text boxes IList ShuffleTextBoxes(int wmsCount, int lineSize, out int right, out int bottom) { int uiBoxesCount = serialNrBoxes.Length; IList enabledSerialNrBoxes = new List(); if (wmsCount < uiBoxesCount && lineSize > 0) { int nrLines = (wmsCount + lineSize - 1) / lineSize; int gap = (uiBoxesCount - wmsCount) / nrLines; int dest = 0; for (int l = 0; l < nrLines; l++) { for (int i = 0; i < lineSize; i++) { int origin = l * lineSize + l * gap + i; labels[dest] = labels[origin]; checkBoxes[dest] = checkBoxes[origin]; pictures[dest] = pictures[origin]; serialNrBoxes[dest] = serialNrBoxes[origin]; labels[dest].Visible = true; checkBoxes[dest].Visible = true; pictures[dest].Visible = true; serialNrBoxes[dest].Visible = true; labels[dest].Text = (dest + 1).ToString(); enabledSerialNrBoxes.Add(serialNrBoxes[dest]); dest++; if (dest >= wmsCount) break; } if (dest >= wmsCount) break; } } else { int activatedWMsCount = Math.Min(wmsCount, uiBoxesCount); for (int i = 0; i < activatedWMsCount; i++) { labels[i].Visible = true; checkBoxes[i].Visible = true; pictures[i].Visible = true; serialNrBoxes[i].Visible = true; labels[i].Text = (i + 1).ToString(); enabledSerialNrBoxes.Add(serialNrBoxes[i]); } } int xMax = 0; int yMax = 0; foreach (var tb in enabledSerialNrBoxes) { if (tb.Left + tb.Width > xMax) xMax = tb.Left + tb.Width; if (tb.Top + tb.Height > yMax) yMax = tb.Top + tb.Height; } right = xMax; bottom = yMax; return enabledSerialNrBoxes; } /// /// Set checkbox states accroding to TBF program level configuration /// void SetCheckBoxStates(long optoHeadsConfig) { for (int i = 0; i < DataStreamsCount; i++) { if ((optoHeadsConfig & (1L << i)) == 0) { /// Opto head is disabled in configuration checkBoxes[i].Checked = false; checkBoxes[i].Enabled = false; pictures[i].BackColor = DisabledColor; serialNrBoxes[i].Text = Strings.Disabled_in_configuration; SNText[i] = string.Empty; Disabled[i] = waterMeters[i].Disabled = true; } else { /// Opto head is enabled checkBoxes[i].Checked = true; checkBoxes[i].Enabled = true; Disabled[i] = waterMeters[i].Disabled = false; if (string.IsNullOrEmpty(SNText[i])) { serialNrBoxes[i].Text = string.Empty; pictures[i].BackColor = InitialColor; } else { serialNrBoxes[i].Text = SNText[i]; pictures[i].BackColor = OptoOKColor; } } } } /// /// Worker thread /// void Worker() { do { for (int wmNr0 = 0; wmNr0 < DataStreamsCount; wmNr0++) { if (formCompleted) break; bool isLast = (wmNr0 == DataStreamsCount - 1); if (!Disabled[wmNr0]) { OnOpenConnStarted(this, new OpenConnectionEventArgs(wmNr0, isLast, waterMeters[wmNr0])); string waterMeterID; bool connected = mefImport.OpenConnection(wmNr0, "", out waterMeterID); log.WarnFormat("{0} : mefImport.OpenConnection({1}, ...) returned {2}, ID={3}", Name, wmNr0, connected, waterMeterID); if (!formCompleted) { OnOpenConnCompleted(this, new OpenConnectionEventArgs(wmNr0, isLast, waterMeters[wmNr0], connected, waterMeterID)); } } else { if (!formCompleted) { OnOpenConnCompleted(this, new OpenConnectionEventArgs(wmNr0, isLast, waterMeters[wmNr0])); } } } } while (!formCompleted); } private void checkBoxImage1_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage1); } private void checkBoxImage2_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage2); } private void checkBoxImage3_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage3); } private void checkBoxImage4_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage4); } private void checkBoxImage5_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage5); } private void checkBoxImage6_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage6); } private void checkBoxImage7_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage7); } private void checkBoxImage8_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage8); } private void checkBoxImage9_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage9); } private void checkBoxImage10_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage10); } private void checkBoxImage11_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage11); } private void checkBoxImage12_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage12); } private void checkBoxImage13_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage13); } private void checkBoxImage14_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage14); } private void checkBoxImage15_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage15); } private void checkBoxImage16_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage16); } private void checkBoxImage17_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage17); } private void checkBoxImage18_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage18); } private void checkBoxImage19_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage19); } private void checkBoxImage20_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage20); } private void checkBoxImage21_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage21); } private void checkBoxImage22_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage22); } private void checkBoxImage23_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage23); } private void checkBoxImage24_Click(object sender, EventArgs e) { ProcessCheckBoxClick(checkBoxImage24); } void ProcessCheckBoxClick(CheckBoxImage checkBox) { for (int ix = 0; ix < DataStreamsCount; ix++) { if (checkBoxes[ix] == checkBox) { Disabled[ix] = waterMeters[ix].Disabled ? true : !checkBoxes[ix].Checked; CheckAllOK(); break; } } } private void serialNrBox1_TextChanged(object sender, EventArgs e) { checkBoxImage1.Checked = true; } private void serialNrBox2_TextChanged(object sender, EventArgs e) { checkBoxImage2.Checked = true; } private void serialNrBox3_TextChanged(object sender, EventArgs e) { checkBoxImage3.Checked = true; } private void serialNrBox4_TextChanged(object sender, EventArgs e) { checkBoxImage4.Checked = true; } private void serialNrBox5_TextChanged(object sender, EventArgs e) { checkBoxImage5.Checked = true; } private void serialNrBox6_TextChanged(object sender, EventArgs e) { checkBoxImage6.Checked = true; } private void serialNrBox7_TextChanged(object sender, EventArgs e) { checkBoxImage7.Checked = true; } private void serialNrBox8_TextChanged(object sender, EventArgs e) { checkBoxImage8.Checked = true; } private void serialNrBox9_TextChanged(object sender, EventArgs e) { checkBoxImage9.Checked = true; } private void serialNrBox10_TextChanged(object sender, EventArgs e) { checkBoxImage10.Checked = true; } private void serialNrBox11_TextChanged(object sender, EventArgs e) { checkBoxImage11.Checked = true; } private void serialNrBox12_TextChanged(object sender, EventArgs e) { checkBoxImage12.Checked = true; } private void serialNrBox13_TextChanged(object sender, EventArgs e) { checkBoxImage13.Checked = true; } private void serialNrBox14_TextChanged(object sender, EventArgs e) { checkBoxImage14.Checked = true; } private void serialNrBox15_TextChanged(object sender, EventArgs e) { checkBoxImage15.Checked = true; } private void serialNrBox16_TextChanged(object sender, EventArgs e) { checkBoxImage16.Checked = true; } private void serialNrBox17_TextChanged(object sender, EventArgs e) { checkBoxImage17.Checked = true; } private void serialNrBox18_TextChanged(object sender, EventArgs e) { checkBoxImage18.Checked = true; } private void serialNrBox19_TextChanged(object sender, EventArgs e) { checkBoxImage19.Checked = true; } private void serialNrBox20_TextChanged(object sender, EventArgs e) { checkBoxImage20.Checked = true; } private void serialNrBox21_TextChanged(object sender, EventArgs e) { checkBoxImage21.Checked = true; } private void serialNrBox22_TextChanged(object sender, EventArgs e) { checkBoxImage22.Checked = true; } private void serialNrBox23_TextChanged(object sender, EventArgs e) { checkBoxImage23.Checked = true; } private void serialNrBox24_TextChanged(object sender, EventArgs e) { checkBoxImage24.Checked = true; } private void serialNrBox1_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox1); } private void serialNrBox2_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox2); } private void serialNrBox3_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox3); } private void serialNrBox4_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox4); } private void serialNrBox5_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox5); } private void serialNrBox6_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox6); } private void serialNrBox7_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox7); } private void serialNrBox8_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox8); } private void serialNrBox9_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox9); } private void serialNrBox10_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox10); } private void serialNrBox11_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox11); } private void serialNrBox12_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox12); } private void serialNrBox13_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox13); } private void serialNrBox14_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox14); } private void serialNrBox15_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox15); } private void serialNrBox16_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox16); } private void serialNrBox17_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox17); } private void serialNrBox18_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox18); } private void serialNrBox19_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox19); } private void serialNrBox20_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox20); } private void serialNrBox21_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox21); } private void serialNrBox22_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox22); } private void serialNrBox23_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox23); } private void serialNrBox24_KeyPress(object sndr, KeyPressEventArgs e) { ProcKeyPress(sndr, e, serialNrBox24); } /// /// Process a key press within any enabled text boxe /// /// /// /// TextBox control which received the event private void ProcKeyPress(object sender, KeyPressEventArgs e, TextBox currentFocusOwner) { if (e.KeyChar == '+') { /// Process '+' key ..... Form completed okButton_Click(sender, e); } if (e.KeyChar == '\r') { /// Process key ..... Next text field if (enabledSerialNrBoxes.Count < 2) return; /// There is just one enabled textbox for (int i = 0; i < enabledSerialNrBoxes.Count; i++) { if (enabledSerialNrBoxes[i] == currentFocusOwner) { /// Change focus to the next enabled text box enabledSerialNrBoxes[(i + 1) % enabledSerialNrBoxes.Count].Focus(); return; } } } } private void allCheckBox_CheckedChanged(object sender, EventArgs e) { foreach (var cb in checkBoxes) { cb.Checked = allCheckBox.Checked; } } #region Forced close handling public void StartForceCloseHandler() { UiBridge.Bridge.CloseModelessFormHandler += delegate(object sender, EventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(OnForceClose), sender, args); } else OnForceClose(sender, args); }; } private void OnForceClose(object sender, EventArgs args) { DialogResult = DialogResult.Cancel; Close(); } #endregion /// /// Called when communication with one watermeter is completed /// public static void OnOpenConnStarted(object sender, OpenConnectionEventArgs data) { if (OpenConnStartedHandler == null) return; try { OpenConnStartedHandler(sender, data); } catch (Exception e) { log.Error("OpenConnStartedHandler(...) failed", e); } } public static event EventHandler OpenConnStartedHandler; void DoOnOpenConnStarted(object sender, OpenConnectionEventArgs data) { busyIx = data.WMNr0; pictures[busyIx].BackColor = BusyColor; } /// /// Called when communication with one watermeter is completed /// public static void OnOpenConnCompleted(object sender, OpenConnectionEventArgs data) { if (OpenConnCompletedHandler == null) return; try { OpenConnCompletedHandler(sender, data); } catch (Exception e) { log.Error("OpenConnCompletedHandler(...) failed", e); } } public static event EventHandler OpenConnCompletedHandler; void DoOnOpenConnCompleted(object sender, OpenConnectionEventArgs data) { busyIx = -1; int ix = data.WMNr0; if (data.Wm != null) { if (data.Wm.Disabled) { /// Disabled in configuration SNText[ix] = Strings.Disabled_in_configuration; pictures[ix].BackColor = DisabledColor; } else { serialNrBoxes[ix].Text = SNText[ix] = string.IsNullOrEmpty(data.WaterMeterID) ? string.Empty : data.WaterMeterID; pictures[ix].BackColor = data.Connected ? OptoOKColor : OptoNokColor; } } else { serialNrBoxes[ix].Text = SNText[ix] = string.Empty; pictures[ix].BackColor = OptoNokColor; } CheckAllOK(); } void CheckAllOK() { bool allOk = true; for (int i = 0; i < DataStreamsCount; i++) { if (!Disabled[i] && string.IsNullOrEmpty(SNText[i])) { allOk = false; break; } } if (allOk) okButton_Click(this, null); } void okButton_Click(object sender, EventArgs e) { formCompleted = true; PurchaseOrder = orderComboBox.Text; for (int i = 0; i < DataStreamsCount; i++) { if (SNText != null && SNText.Length > i) SNText[i] = serialNrBoxes[i].Text; if (Disabled != null && Disabled.Length > i) Disabled[i] = !checkBoxes[i].Checked; if (waterMeters != null && waterMeters.Count > i && waterMeters[i] != null && !waterMeters[i].Disabled) { waterMeters[i].SerialNr = serialNrBoxes[i].Text; waterMeters[i].Disabled = !checkBoxes[i].Checked; } } Program.LocalSettings.UpdateHistory(orderComboBox.Text, ref Program.LocalSettings.PurchaseOrderHistory); Program.LocalSettings.LastSNTexts = SNText; Close(); } void retryButton_Click(object sender, EventArgs e) { SetCheckBoxStates(Program.LocalSettings.OptoHeadsEnabled); } } }