/// /// Copyright (c) 2016-2022 Sensus Slovensko a.s. /// using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using FluentNHibernate.Cfg; using FluentNHibernate.Cfg.Db; using log4net; using NHibernate; using SharedDatabase; using SharedDatabase.Entities; using SharedDatabase.Forms; using Workplace.Resources; namespace Workplace { public partial class WorkplaceDlg : Form { static readonly ILog log = LogManager.GetLogger(typeof(WorkplaceDlg)); [DllImport("User32.dll")] public static extern Int32 SetForegroundWindow(int hWnd); public const int NrGeneratorIx = 0; /// BaseNr1 and CurrentNr1 are used to generate and print serial numbers const int ErrorBeepFrequency = 500; /// Hz const int ErrorBeepDuration = 1000; /// ms public int ExtraBatteryLifetime; /// In months, default = 0 public ISessionFactory SessionFactory; public ISession dbSession; Common.Forms.ModelessForm modelessForm; public IList AllOrders; /// All orders including the finished ones IList orders; /// New and active orders from the database IList workflows; /// Workflows from the database WPlaceRegistrationMgmt wplaceRegistration; Timer runDeviceTimer; /// Timer for regular 1 second ticks DateTime lastActivity; /// Timestamp of the last users activity (OnBarcodeReceived, OnFocusPressed, etc.) DateTime lastLoginTime; /// Timestamp of the last user login bool isLoggedOut; /// This object processes records (=files) from a thirdparty program and extract reference part codes RecordProcessing.RecordProcessing recordProcessing; /// Currently displayed process and workstep public OrderInfo CurrentOrder; /// Currently used order public Process CurrentWorkflow; /// Currently used process public Workstep CurrentWorkstep; /// Currently used workstep IList workstepsOfTheCurrentWorkflow; /// ix=0, orderNr=1 string[] predefinedOrders = new[] { Strings.none }; /// Previous workstep verification Workstep verifiedWorkstep; Part verifiedPart; /// Applicable when verifyReferencePart == false bool verifyReferencePart; /// Items to be scanned/filled in IList komponenty; IList palety; bool isSNPrinting { get { return komponenty != null && komponenty.Count == 1 && komponenty[0] is CheckItems.SNGeneratorPrinter; } } bool loadedOnce; bool supressUINotifications; PartError errorFlag; public static void BuildSchema(NHibernate.Cfg.Configuration config) { /// This NHibernate tool takes a configuration (with mapping info in) /// and exports a database schema from it new NHibernate.Tool.hbm2ddl.SchemaExport(config).SetOutputFile("db_schema"); } public WorkplaceDlg() { try { string culture = Program.LocalSettings.Language.Replace('_', '-'); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture); System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture); } catch (Exception exc) { string msg = exc.Message; MessageBox.Show("Selected language is not supported.\nUsing English.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en"); System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en"); } modelessForm = new Common.Forms.ModelessForm(Strings.Loading_configuration_from_a_database); new System.Threading.Thread(() => Application.Run(modelessForm)).Start(); InitializeComponent(); supressUINotifications = true; ManageCheckGroupBox(batchesCheckBox, batchesGroupBox); wplaceRegistration = new WPlaceRegistrationMgmt(); komponenty = new List(); palety = new List(); do { dbSession = null; orders = null; AllOrders = null; workflows = null; try { SessionFactory = Fluently.Configure() .Database(MySQLConfiguration.Standard.ConnectionString(Program.LocalSettings.ConnectionString)) .Mappings(m => m.FluentMappings.AddFromAssemblyOf()) .ExposeConfiguration(BuildSchema).BuildSessionFactory(); dbSession = SessionFactory.OpenSession(); orders = ReadOrders(dbSession); AllOrders = ReadOrders(dbSession, false); workflows = ReadReleasedActiveProcesses(dbSession); } catch (Exception exc) { DialogResult rslt = MessageBox.Show(Strings.Opening_database_failed + Environment.NewLine + Environment.NewLine + exc.Message + Environment.NewLine + Environment.NewLine + Strings.Do_you_want_to_change_settings, Strings.Warning, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); if (rslt != DialogResult.Yes) { if (modelessForm != null) modelessForm.CloseForm(); throw new Common.QuitAppException(Strings.Opening_database_failed); } } if (dbSession == null || orders == null || AllOrders == null || workflows == null) { var dr = Configure(); if (dr != DialogResult.OK) { if (modelessForm != null) modelessForm.CloseForm(); throw new Common.QuitAppException(Strings.Opening_database_failed); } } } while (dbSession == null || orders == null || AllOrders == null || workflows == null); BarcodeReceivedHandler += delegate(object sndr, BarcodeReceivedEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(BarcodeReceived), sndr, args); } else { BarcodeReceived(sndr, args); } }; FocusPressedHandler += delegate(object sndr, FocusPressedEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(FocusPressed), sndr, args); } else { FocusPressed(sndr, args); } }; ColorFlashHandler += delegate(object sender, ColorFlashEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(OnColorFlash), sender, args); } else OnColorFlash(sender, args); }; workplaceTextBox.Text = Program.LocalSettings.WorkplaceId; workerTextBox.Text = Common.CurrentUser.UserName(); lastLoginTime = DateTime.Now; isLoggedOut = false; ResetIdleTime(); /// Timer for regular 1 second ticks runDeviceTimer = new System.Windows.Forms.Timer(); runDeviceTimer.Interval = Const.Interval; runDeviceTimer.Tick += new EventHandler(runDeviceTimer_Tick); runDeviceTimer.Start(); /// /// Activate processing of records (log files) created by a thirdparty program /// if (Program.LocalSettings.RecordProcessing == RecordProcessing.RecordType.CommTest) { recordProcessing = new RecordProcessing.RecordProcessing(RecordProcessing.RecordType.CommTest, RecordProcessing.RecordPostproc.None, "C:\\iPerl\\LogFiles\\CommTester", true, "*.log"); } else { recordProcessing = null; } if (recordProcessing != null) { recordProcessing.SubmitRecordHandler += delegate(object sender, RecordProcessing.SubmitRecordEventArgs args) { if (InvokeRequired) { Invoke(new EventHandler(SubmitRecordFromThirdpartyTester), sender, args); } else { SubmitRecordFromThirdpartyTester(sender, args); } }; } } /// /// Submits a reference part code from a record from a 3-rd party program /// /// /// Argument containing the reference part s/n void SubmitRecordFromThirdpartyTester(object sender, RecordProcessing.SubmitRecordEventArgs args) { if ((komponenty != null) && (komponenty.Count >= 1)) { if (komponenty.Count >= 2) this.Activate(); /// Activate this window if there is 2nd code to scan komponenty[0].SubmitCode(args.Record.SN); /// Submit the reference part code //this.BringToFront(); /// 1 Tested: Brings window to the top only, does not activate the window this.WindowState = FormWindowState.Minimized; /// 2 Works OK !!! this.Show(); this.WindowState = FormWindowState.Normal; //SetForegroundWindow(Handle.ToInt32()); /// 3 Should work as well //this.Activate(); /// 4 Tested: Does not activate the window //this.Focus(); } } private void WorkplaceDlg_Load(object sender, EventArgs e) { Localize(); CurrentOrder = null; CurrentWorkflow = null; CurrentWorkstep = null; UpdateOrderCombo(orders, string.Empty); workstepComboBox.Text = Program.LocalSettings.LastWorkstep; if (UpdateWorkflowCombo(workflows, Program.LocalSettings.LastWorkflow)) { if (UpdateWorkstepCombo(CurrentWorkflow, Program.LocalSettings.LastWorkstep)) { UpdateItems(); } } if (modelessForm != null) modelessForm.CloseForm(); loadedOnce = true; supressUINotifications = false; orderComboBox.Focus(); } void Localize() { orderLabel.Text = string.Format("{0}:", Strings.Order); workflowLabel.Text = string.Format("{0}:", Strings.Workflow); workstepLabel.Text = string.Format("{0}:", Strings.Workflow_step); workerLabel.Text = string.Format("{0}:", Strings.Production_operator); workplaceLabel.Text = string.Format("{0}:", Strings.Workplace); logoutButton.Text = Strings.Exchange_of_operator; configureButton.Text = Strings.Configure; groupBox2.Text = Strings.Codes_of_components; batchesCheckBox.Text = Strings.Codes_of_batches; clearButton.Text = Strings.New_codes; resetErrorStateButton.Text = Strings.Clear_errors; failedCheckBox.Text = Strings.Failure; saveAllCodesButton.Text = Strings.Save; completedGroupBox.Text = Strings.Completed; targetGroupBox.Text = Strings.Target; } /// /// Read released-active processes from the database. /// /// Production tracing DB session /// A list of processes (success) or null (failure) private IList ReadReleasedActiveProcesses(ISession session) { try { return session.QueryOver() .Where(x => (x.ReleaseStatus == ReleaseStatus.In_preparation || x.ReleaseStatus == ReleaseStatus.ToBeApproved || x.ReleaseStatus == ReleaseStatus.ReleasedActive || x.ReleaseStatus == ReleaseStatus.Released)) .OrderBy(x => x.Name).Asc .List(); } catch (Exception exc) { log.ErrorFormat("Failed to load processes from the tracing DB: {0}", exc.Message); return null; } } IList ReadOrders(ISession session, bool newOrActiveOrdersOnly = true) { try { if (newOrActiveOrdersOnly) { var list = session.QueryOver() .Where(x => (x.POState == (sbyte)OrderState.New || x.POState == (sbyte)OrderState.Active)) .OrderBy(x => x.POName).Asc .List(); for (int i = list.Count - 1; i >= 0; i--) { long orderNr; if (!long.TryParse(list[i].POName, out orderNr) || orderNr - 1 < predefinedOrders.Length) { list.RemoveAt(i); } } return list; } else { return session.QueryOver() .OrderBy(x => x.POName).Asc .List(); } } catch (Exception exc) { log.ErrorFormat("Failed to load processes from the tracing DB: {0}", exc.Message); return null; } } /// /// Updates target and completed pieces count and returns /// true when target pieces count was reached. /// /// true when target pieces count reached public bool UpdatePiecesCount() { if (CurrentOrder == null || predefinedOrders.Contains(orderComboBox.Text)) { targetGroupBox.Visible = false; targetLabel.Text = "0"; completedGroupBox.Visible = false; completedLabel.Text = "0"; completedGroupBox.BackColor = SystemColors.Control; completedGroupBox.ForeColor = SystemColors.ControlText; return false; } else { targetGroupBox.Visible = true; targetLabel.Text = CurrentOrder.PiecesCount.ToString(); if (CurrentWorkflow != null && CurrentWorkstep != null) { try { var pieces = dbSession.QueryOver() .Where(x => x.POName == CurrentOrder.POName) .And(x => x.Workflow == CurrentWorkflow.Name) .List(); completedGroupBox.Visible = true; completedLabel.Text = pieces.Count.ToString(); bool targetReached = pieces.Count >= CurrentOrder.PiecesCount; completedGroupBox.BackColor = targetReached ? Color.Green : SystemColors.Control; completedGroupBox.ForeColor = targetReached ? Color.White : SystemColors.ControlText; return targetReached; } catch (Exception exc) { completedGroupBox.Visible = true; completedLabel.Text = Strings.unknown; completedGroupBox.BackColor = SystemColors.Control; completedGroupBox.ForeColor = SystemColors.ControlText; log.ErrorFormat("Unable to read ReferenceRecords: o={0} w={1} s={2}: {3}", CurrentOrder.POName, CurrentWorkflow.Name, CurrentWorkstep.Name, exc.Message); return false; } } else { completedGroupBox.Visible = false; completedLabel.Text = "0"; completedGroupBox.BackColor = SystemColors.Control; completedGroupBox.ForeColor = SystemColors.ControlText; return false; } } } void UpdateOrderCombo(IList orders, string preferredOrderName) { bool anyChange = (orders == null) || (predefinedOrders.Length + orders.Count != orderComboBox.Items.Count); if (!anyChange) { for (int i = 0; i < orders.Count; i++) { if (orderComboBox.Items[i].ToString() != orders[i].POName) { anyChange = true; break; } } } if (!anyChange) return; int selectedIndex = -1; orderComboBox.Items.Clear(); if (orders != null) { for (int i = 0; i < predefinedOrders.Length; i++) { orderComboBox.Items.Add(predefinedOrders[i]); if (predefinedOrders[i] == preferredOrderName) { selectedIndex = i; CurrentOrder = AllOrders.FirstOrDefault(x => x.POName == (i + 1).ToString("D7")); } } for (int i = 0; i < orders.Count; i++) { orderComboBox.Items.Add(orders[i]); if (orders[i].POName == preferredOrderName) { selectedIndex = predefinedOrders.Length + i; CurrentOrder = orders[i]; } } } orderComboBox.SelectedIndex = selectedIndex; UpdatePiecesCount(); } /// /// Redraw processes in process combo box. Try to keep Program.LocalSettings.LastProcess selected. /// In case of a change in ReleaseActive processes in the DB it may not be possible to keep this selection. /// In such case function returns null. /// When process selection changes, 'processComboBox_SelectedIndexChanged' is invoked. /// /// true = list of processes changed bool UpdateWorkflowCombo(IList workflows, string preferredWorkflowName) { if (workflows == null || workflows.Count == 0) { supressUINotifications = true; workflowComboBox.Items.Clear(); workflowComboBox.Text = string.Empty; supressUINotifications = false; bool wflowChgnd = (CurrentWorkflow != null); CurrentWorkflow = null; return wflowChgnd; } Process preferredWorkflow = workflows.FirstOrDefault(x => x.Name == preferredWorkflowName); supressUINotifications = true; workflowComboBox.Items.Clear(); for (int i = 0; i < workflows.Count; i++) { workflowComboBox.Items.Add(workflows[i].Name); } workflowComboBox.Text = (preferredWorkflow != null) ? preferredWorkflowName : string.Empty; supressUINotifications = false; bool workflowChanged = CurrentWorkflow != preferredWorkflow; CurrentWorkflow = preferredWorkflow; return workflowChanged; } private void workflowComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (supressUINotifications) return; CurrentWorkflow = workflows.FirstOrDefault(x => x.Name == workflowComboBox.Text); if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text)) { UpdateItems(); ClearBatchNumbers(); Program.LocalSettings.LastWorkflow = CurrentWorkflow.Name; Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name; } } /// /// Updates workstep selection combo items and text. Clear it only if process == null. /// If there is a valid 'oriWorkstepName', the combo box text is set and the selected workstep is returned. /// Otherwise this function returns null. /// /// Process with worksteps to be used /// Originally selected workstep name /// New selected workstep or null private bool UpdateWorkstepCombo(Process workflow, string preferredWorkstepName) { if (workflow == null || workflow.Worksteps == null || workflow.Worksteps.Count == 0) { supressUINotifications = true; workstepComboBox.Items.Clear(); workstepComboBox.Text = string.Empty; supressUINotifications = false; bool wstepChgnd = (CurrentWorkstep != null); CurrentWorkstep = null; return wstepChgnd; } /// Todo: Select closes workstep Workstep prefferedWorkstep = workflow.Worksteps.FirstOrDefault(x => x.Name == preferredWorkstepName); supressUINotifications = true; workstepComboBox.Items.Clear(); for (int i = 0; i < workflow.Worksteps.Count; i++) { workstepComboBox.Items.Add(workflow.Worksteps[i].Name); } workstepComboBox.Text = (prefferedWorkstep != null) ? preferredWorkstepName : string.Empty; supressUINotifications = false; bool workstepChanged = CurrentWorkstep != prefferedWorkstep; CurrentWorkstep = prefferedWorkstep; return workstepChanged; } private void workstepComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (supressUINotifications) return; var oriWorkstep = CurrentWorkstep; CurrentWorkstep = CurrentWorkflow == null ? null : CurrentWorkflow.Worksteps.FirstOrDefault(x => x.Name == workstepComboBox.Text); if (CurrentWorkstep != oriWorkstep) { UpdateItems(); ClearBatchNumbers(); Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name; } } /// /// Updates screen items (polozky) and currentProcess, currentWorkstep variables. /// If either process or workstep is null, the screen is icleared. /// /// Process to be used (drawn) /// Workstep to be used (drawn) /// true = process or workstep changed, false = no change void UpdateItems() { if (recordProcessing != null) recordProcessing.StopProcessing(); workstepsOfTheCurrentWorkflow = CurrentWorkflow != null ? CurrentWorkflow.Worksteps : new List(); verifiedWorkstep = null; /// Disable any verification RedrawItems(); if (CurrentOrder != null) { completedGroupBox.Visible = targetGroupBox.Visible = true; UpdatePiecesCount(); } else { completedGroupBox.Visible = targetGroupBox.Visible = false; } if (CurrentWorkflow != null) { LoadCodesFromDictionary(CurrentWorkflow.Name, palety); } ScanVerificationInfo svi = TracingDB.AnalyzeProcess(dbSession, CurrentWorkflow, CurrentWorkstep); if (svi != null) { verifiedWorkstep = svi.Workstep; verifiedPart = svi.Part; verifyReferencePart = svi.VerifyReferencePart; } UpdateTitle(); /// Show acrive verification wplaceRegistration.UpdateRegistration(dbSession, Program.LocalSettings.WorkplaceId, Common.CurrentUser.UserName(), "1.2.3.4", (CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty, (CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty, DateTime.Now + new TimeSpan(8, 0, 0)); if (recordProcessing != null) recordProcessing.StartProcessing(); } /// /// Update main window title after AnalyzeProcesses() /// void UpdateTitle() { string title = string.Format("{0} ver. {1} ({2})", Strings.Workplace, Program.Version, Program.LocalSettings.WorkplaceId); if (verifiedWorkstep != null && verifiedPart != null) { title += string.Format(Strings.previous_workflow_step_0_verified_component_1, verifiedWorkstep.Name, verifiedPart.Name); } Text = title; } /// /// Redraw items (polozky) of the currentProcess and currentWorkstep /// or clear them if there is no current process or workstep. /// void RedrawItems() { /// /// Remove existing items (polozky) /// foreach (var k in komponenty) if (k is IDevice) (k as IDevice).StopDevice(); foreach (var p in palety) if (p is IDevice) (p as IDevice).StopDevice(); komponenty.Clear(); palety.Clear(); flowLayoutPanel1.Controls.Clear(); flowLayoutPanel2.Controls.Clear(); ICheckItem polozka; if (CurrentWorkstep != null) { /// Reference part if (CurrentWorkstep.ReferencePart != null) { if (CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.Barcode || CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.QRCode) { polozka = new CheckItems.Barcode(this, CurrentWorkstep.ReferencePart); polozka.IxPolozky = 1; komponenty.Add(polozka); flowLayoutPanel1.Controls.Add(polozka as UserControl); OptionalySetBlackList(polozka); } else if (CurrentWorkstep.ReferencePart.CodeForm == (sbyte)CodeForm.SNGenerator) { polozka = new CheckItems.SNGeneratorPrinter(this, CurrentWorkstep.ReferencePart); polozka.IxPolozky = 1; komponenty.Add(polozka); flowLayoutPanel1.Controls.Add(polozka as UserControl); } } /// All other parts foreach (var p in CurrentWorkstep.Parts) { if (komponenty.Count == 1 && p.CodeForm == (sbyte)CodeForm.SerialNr) { /// Complete serial number 'part' that is handled by PolozkaDouble => do not create any new control continue; } switch ((CodeForm)p.CodeForm) { case CodeForm.SNGenerator: polozka = new CheckItems.SNGeneratorPrinter(this, p); break; case CodeForm.Keyboard: polozka = new CheckItems.Keyboard(this, p); break; case CodeForm.Scale: RunWeightLimitsWizard(); /// Run wizard to determine weight limits before creating a scale CheckItem CheckItems.Scale scale = new CheckItems.Scale(this, p); try { scale.Initialize(); } catch (Exception) { scale.BackColor = System.Drawing.Color.Red; } scale.MinWeight = Program.LocalSettings.MinWeight / 1000; scale.MaxWeight = Program.LocalSettings.MaxWeight / 1000; polozka = scale; break; case CodeForm.DataStream: CheckItems.S640Stream datastream = new CheckItems.S640Stream(this, p); try { datastream.Initialize(); } catch (Exception) { datastream.BackColor = System.Drawing.Color.Red; } polozka = datastream; break; case CodeForm.Barcode: case CodeForm.QRCode: default: polozka = new CheckItems.Barcode(this, p); break; } if (p.CodeLocation == CodeLocation.OnPart) { polozka.IxPolozky = komponenty.Count + 1; komponenty.Add(polozka); flowLayoutPanel1.Controls.Add(polozka as UserControl); } else if (p.CodeLocation == CodeLocation.OnPallet) { polozka.IxPolozky = palety.Count + 100; palety.Add(polozka); flowLayoutPanel2.Controls.Add(polozka as UserControl); } OptionalySetBlackList(polozka); } InitializeSNGeneratorPrinter(); } } void RunWeightLimitsWizard() { while (true) { var dr = MessageBox.Show(Strings.Do_you_want_to_use_the_last + Environment.NewLine + string.Format(Strings.weight_limits_0g_1g_Q, Program.LocalSettings.MinWeight, Program.LocalSettings.MaxWeight) + Environment.NewLine + Program.LocalSettings.WeightOptionsWay, string.Empty, MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (dr == DialogResult.Yes) return; /// Use the last weight limits stored in Program.LocalSettings /// Ask how the new weight limits should be determined var dlg1 = new Forms.WeightLimitsWayDlg(); dlg1.ShowDialog(); switch (dlg1.Way) { case Forms.Way.Manually: /// Enter weight limits manually var dlg2 = new Forms.WeightLimitsDlg(Program.LocalSettings.MinWeight, Program.LocalSettings.MaxWeight); if (dlg2.ShowDialog() == DialogResult.OK) { Program.LocalSettings.MinWeight = dlg2.MinWeight; Program.LocalSettings.MaxWeight = dlg2.MaxWeight; Program.LocalSettings.WeightOptionsWay = dlg2.WeightOptionsWay; Program.LocalSettings.Save(); } return; case Forms.Way.Wizard: /// Use a wizard to determine the weight limits var dlg3 = new Forms.WeightLimitsWizardDlg(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\WizardDirTree"); if (dlg3.ShowDialog() == DialogResult.OK) { Program.LocalSettings.MinWeight = dlg3.MinWeight; Program.LocalSettings.MaxWeight = dlg3.MaxWeight; Program.LocalSettings.WeightOptionsWay = dlg3.WeightOptionsWay; Program.LocalSettings.Save(); return; } else { break; } case Forms.Way.Measurement: default: MessageBox.Show(Strings.Not_implemented_yet); break; } } } void ClearBatchNumbers() { if (loadedOnce) { foreach (var p in palety) { p.ClearCode(); } } } /// /// Check local settings and optionally set the black list for polozka. /// /// void OptionalySetBlackList(ICheckItem polozka) { if (polozka.IxPolozky == Program.LocalSettings.BlackListIx1) { BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile1); if (bl != null) polozka.BlackListedCodes = bl.Codes; } else if (polozka.IxPolozky == Program.LocalSettings.BlackListIx2) { BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile2); if (bl != null) polozka.BlackListedCodes = bl.Codes; } else if (polozka.IxPolozky == Program.LocalSettings.BlackListIx3) { BlackList bl = BlackList.FromFile(Program.LocalSettings.BlackListFile3); if (bl != null) polozka.BlackListedCodes = bl.Codes; } } /// /// Reset idle time measurement /// void ResetIdleTime() { lastActivity = DateTime.Now; } /// /// Get idle time in seconds /// /// Idle time [s] double GetIdleTimeSec() { TimeSpan ts = DateTime.Now - lastActivity; return (int)ts.TotalSeconds; } /// /// Get time in seconds sinc the last login /// /// Login time [s] double GetLoginTimeSec() { TimeSpan ts = DateTime.Now - lastLoginTime; return (int)ts.TotalSeconds; } static TimeSpan oneDay = new TimeSpan(1, 0, 0, 0); static int logoutDetectionCounter = 0; /// void runDeviceTimer_Tick(object sender, EventArgs args) { try { /// Before foreach (var k in komponenty) if (k is IDevice) (k as IDevice).RunDeviceBefore(); foreach (var p in palety) if (p is IDevice) (p as IDevice).RunDeviceBefore(); /// After foreach (var k in komponenty) if (k is IDevice) (k as IDevice).RunDeviceAfter(); foreach (var p in palety) if (p is IDevice) (p as IDevice).RunDeviceAfter(); if (++logoutDetectionCounter >= 30) { logoutDetectionCounter = 0; LogoutDetection(); } } catch (Exception) { } } /// void LogoutDetection() { TimeSpan smallestTimeDiff = oneDay; /// Smallest time difference from logout times - initialized to one day if (Program.LocalSettings.LogoutTime1.TimeOfDay != new TimeSpan(0)) { /// Logout time 1 enabled TimeSpan ts1 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime1.TimeOfDay; if (ts1 < new TimeSpan(0)) ts1 += oneDay; if (ts1 < smallestTimeDiff) smallestTimeDiff = ts1; } if (Program.LocalSettings.LogoutTime2.TimeOfDay != new TimeSpan(0)) { /// Logout time 2 enabled TimeSpan ts2 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime2.TimeOfDay; if (ts2 < new TimeSpan(0)) ts2 += oneDay; if (ts2 < smallestTimeDiff) smallestTimeDiff = ts2; } if (Program.LocalSettings.LogoutTime3.TimeOfDay != new TimeSpan(0)) { /// Logout time 3 enabled TimeSpan ts3 = DateTime.Now.TimeOfDay - Program.LocalSettings.LogoutTime3.TimeOfDay; if (ts3 < new TimeSpan(0)) ts3 += oneDay; if (ts3 < smallestTimeDiff) smallestTimeDiff = ts3; } int minTimeSec = (int)smallestTimeDiff.TotalSeconds; if ((minTimeSec < 900) && !isLoggedOut && (GetIdleTimeSec() > 120) && (GetLoginTimeSec() > 2700)) { logoutButton_Click(null, null); } } public void OnBarcodeReceived(object sender, BarcodeReceivedEventArgs data) { ResetIdleTime(); if (BarcodeReceivedHandler == null) return; try { BarcodeReceivedHandler(sender, data); } catch (Exception exc) { string msg = exc.Message; // log.Error("BarcodeReceivedHandler(...) failed", e); } } public event EventHandler BarcodeReceivedHandler; /// public void BarcodeReceived(object sender, BarcodeReceivedEventArgs data) { foreach (var k in komponenty) k.ResetFocus(); foreach (var p in palety) p.ResetFocus(); if (data.Error == PartError.BlacklistedPart) { /// /// This is a blacklisted component (s/n in on a blacklist) /// SetErrorFlag(PartError.BlacklistedPart, Color.DarkOrange); MessageBox.Show(string.Format("{0}{1}{2}", Strings.This_part_is_on_a_black_list, Environment.NewLine, Strings.Put_the_part_aside), Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } else if (data.Error == PartError.WrongPart) { /// /// This is a wrong part (s/n does not satisfy criteria) /// SetErrorFlag(PartError.WrongPart, Color.Red); MessageBox.Show(Strings.Wrong_part, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } else if (data.Error == PartError.ValueOutOfRange) { /// /// Measured value is out of range /// SetErrorFlag(PartError.ValueOutOfRange, Color.Red); MessageBox.Show(Strings.Value_out_of_range, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } else if (data.Error == PartError.UnspecifiedError) { /// /// Measured value is out of range /// SetErrorFlag(PartError.UnspecifiedError, Color.Red); MessageBox.Show(Strings.Unspecified_error, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } else if (data.CodeLocation == CodeLocation.OnPart) { /// /// This is a uniqueue part code ==> process it /// if (data.IxPolozky > 0 && data.IxPolozky < komponenty.Count) { /// /// This is not the last part ==> set focus onto the next part to be scanned /// komponenty[data.IxPolozky].SetFocus(); return; } /// /// This is the last part with uniqueue code (on the left side of the screen) /// if(IsAnyFieldEmpty()) { /// /// At least one of fields is empty ==> error /// SetErrorFlag(PartError.FieldEmpty, Color.Yellow); MessageBox.Show(Strings.Some_fileds_are_empty_Fill_them_in_please, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } if (errorFlag != PartError.None) { /// /// There is another error (see errorFlag) /// SetErrorFlag(PartError.UnspecifiedError, Color.Red); MessageBox.Show(Strings.Remove_errors_please, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } /// /// Everything is OK so far ==> verify previous records /// try { ISession session = SessionFactory.OpenSession(); if (verifiedWorkstep != null && verifiedPart != null) { string verifiedCode = string.Empty; for (int i = 0; i < komponenty.Count; i++) { if (komponenty[i].Part == verifiedPart) { verifiedCode = komponenty[i].ScannedCode; break; } } int codeIx = 1; /// /// Find reference records with s/n of the part to be verified /// IQueryOver query = dbSession.QueryOver(); switch (codeIx) { default: case 1: query = query.Where(rr => (rr.Code1 == verifiedCode)); break; case 2: query = query.Where(rr => (rr.Code2 == verifiedCode)); break; case 3: query = query.Where(rr => (rr.Code3 == verifiedCode)); break; case 4: query = query.Where(rr => (rr.Code4 == verifiedCode)); break; } var refRecords = query.OrderBy(rr => rr.Timestamp).Desc.List(); bool verificationPassed = false; if (refRecords.Count > 0 && refRecords[0].StepRecords != null) { foreach (var r in refRecords[0].StepRecords) { if (r.Workstep == verifiedWorkstep.Name) { /// This is the last good record from a verified workstep verificationPassed = true; break; } } } if (!verificationPassed) { SetErrorFlag(PartError.PrviousRecordMissing, Color.Blue); MessageBox.Show(Strings.Record_from_the_previous_workflow_step_is_missing, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } } #if false saveAllCodesButton.Enabled = true; saveAllCodesButton.Focus(); #else SaveCodes(session); #endif session.Close(); } catch (Exception exc) { log.ErrorFormat("SaveCodes, etc. failed: {0}", exc.Message); } } } void SaveCodes(ISession session) { ResetIdleTime(); if (Program.LocalSettings.Mode == Mode.Test || komponenty.Count == 0) { ColorFlash(this, new ColorFlashEventArgs(true, Color.Green, Program.LocalSettings.OkFlashDuration, Strings.Test)); return; } if (IsAnyFieldEmpty()) { SetErrorFlag(PartError.FieldEmpty, Color.Yellow); MessageBox.Show(Strings.Some_fileds_are_empty_Fill_them_in_please, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); ResetErrorFlag(); return; } if (errorFlag != PartError.None) { MessageBox.Show(Strings.Remove_errors_please, Strings.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } /// /// Save records to MySQL /// int result = 0; /// OK (default) bool wasAlreadyTested = false; bool componentsSaved = true; bool successfullySaved = false; ITransaction transaction = null; try { transaction = session.BeginTransaction(); CheckItems.SNGeneratorPrinter snGenerator = (komponenty[0] as CheckItems.SNGeneratorPrinter); /// null when there is no S/N generator /// /// Handle serial number generators /// if (snGenerator != null && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator) { if (CurrentOrder == null) { /// The 1st item is a S/N generator but no order is selected ==> Error komponenty[0].ScannedCode = "ERROR"; throw new Exception("No order selected"); } /// /// Negotiate and update the generated serial number /// string generatedCode; var orderInfoState = snGenerator.NegotiateSerialNr(session, CurrentOrder, CurrentWorkflow, CurrentWorkstep, out generatedCode, true); if (orderInfoState == OrderProgress.InProgress || orderInfoState == OrderProgress.Overproduction) { komponenty[0].ScannedCode = generatedCode; } else if (orderInfoState == OrderProgress.Completed) { komponenty[0].ScannedCode = "END"; throw new Exception("END"); } else //if (orderInfoState == OrderProgress.Error) { /// An unexpected error throw new Exception("No order selected"); } } /// /// Select or create a reference record /// var refRecords = session.QueryOver() .Where(x => x.Code1 == komponenty[0].ScannedCode) .List(); /// Handle or prevent reference record duplicity if (refRecords.Count > 1) throw new Exception("Unexpected error: two identical codes in the database"); else if (snGenerator != null && refRecords.Count == 1) throw new Exception("A duplicit code was generated"); ReferenceRecord refRecord = (refRecords.Count == 1) ? refRecords[0] : new ReferenceRecord(CurrentOrder.POName, CurrentWorkflow.Name, komponenty[0].Part.Name, komponenty[0].ScannedCode); /// Handle case of a double check item - update refRecord.Code2 if (komponenty[0] is IDoubleCheckItem) { refRecord.Code2 = (komponenty[0] as IDoubleCheckItem).ScannedCode2; } /// Prepare new records var records = new List(); var stepRecord = PrepareRecords(refRecord, result, records); /// De-referene existing recors with the same part name, a more recent record exists now foreach (var oriRecord in refRecord.Records) { var overridingRecord = records.FirstOrDefault(x => x.Name == oriRecord.Name); if (overridingRecord != null) { oriRecord.ReferenceRecord = null; session.SaveOrUpdate(oriRecord); } } /// Update the reference record refRecord.StepRecords.Add(stepRecord); foreach (var rcrd in records) refRecord.Records.Add(rcrd); if (stepRecord.Timestamp > refRecord.Timestamp) refRecord.Timestamp = stepRecord.Timestamp; session.SaveOrUpdate(refRecord); log.InfoFormat(" ReferenceRecord : {0}", refRecord); /// Save new records session.SaveOrUpdate(stepRecord); log.InfoFormat(" StepRecord : {0}", stepRecord); foreach (var rcrd in records) { session.SaveOrUpdate(rcrd); log.InfoFormat(" Record : {0}", rcrd); } transaction.Commit(); successfullySaved = true; } catch (Exception exc) { componentsSaved = false; if (transaction != null) transaction.Rollback(); log.ErrorFormat("MySQL database transaction rolled back, data not comitted: {0}", exc.Message); } /// In case of 'SNGeneratorPrinter' print a label after saving records successfully if (komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator && successfullySaved) { var matrix = new DataMatrix4Net.DataMatrix(komponenty[0].ScannedCode, DataMatrix4Net.SymbolSize.SquareAuto); new Printers.DataMatrixAndTextPrintDoc(matrix.Matrix, komponenty[0].ScannedCode.Replace("4V", "\n")).Print(); } /// Retrieve produced pieces count and compare with the target count bool targetCountReached = UpdatePiecesCount(); if (wasAlreadyTested && !componentsSaved) { ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.PCB_was_tested_already, Strings.Components_were_not_saved_to_Oracle)); } else if (wasAlreadyTested) { ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.PCB_was_tested_already)); } else if (!componentsSaved) { ColorFlash(this, new ColorFlashEventArgs(false, Color.Red, Program.LocalSettings.NokFlashDuration, Strings.Components_were_not_saved_to_Oracle)); } else if (targetCountReached) { ColorFlash(this, new ColorFlashEventArgs(false, Color.Yellow, Program.LocalSettings.NokFlashDuration, Strings.Target_count_reached)); } else { ColorFlash(this, new ColorFlashEventArgs(true, Color.Green, Program.LocalSettings.OkFlashDuration)); } UpdateAndSaveStoredCodesDictionary(CurrentWorkflow, palety); /// /// Find out whether the process has been changed, prepare UI /// orders = ReadOrders(dbSession); UpdateOrderCombo(orders, orderComboBox.Text); workflows = ReadReleasedActiveProcesses(dbSession); if (UpdateWorkflowCombo(workflows, workflowComboBox.Text)) { if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text)) { UpdateItems(); } } /// /// Clear all components/items, set focus to the first field /// foreach (var k in komponenty) { k.ClearCode(); k.ResetFocus(); } if (komponenty.Count >= 1) { if (komponenty.Count >= 2 && komponenty[0] is CheckItems.SNGeneratorPrinter && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator) { komponenty[1].SetFocus(); } else { komponenty[0].SetFocus(); } } if ((recordProcessing != null) && !wasAlreadyTested && componentsSaved) { /// Activate thirdparty program window Utils.Activate(Program.LocalSettings.WindowClassNameToActivate); } } /// /// Prepare records and a step record with scanned/generated/collected information /// /// Reference record /// Result: 0=OK, otherwise a non-zero error code /// List of records to be updated (initially an empty list) /// Step record StepRecord PrepareRecords(ReferenceRecord refRecord, int result, IList records) { var stepRecord = new StepRecord(refRecord, CurrentWorkstep.Name, workplaceTextBox.Text, workerTextBox.Text, result); int firstNoRefCompIx = (CurrentWorkstep.ReferencePart == null) ? 0 : (komponenty[0] is IDoubleCheckItem) ? 2 : 1; for (int i = firstNoRefCompIx; i < komponenty.Count; i++) { if (komponenty[i] is CheckItems.S640Stream) { /// eRegister number from data stream ... update refRecord.Code2 refRecord.Name2 = komponenty[i].Part.Name; refRecord.Code2 = komponenty[i].ScannedCode; } else { records.Add(new Record(refRecord, stepRecord, komponenty[i].Part.Name, komponenty[i].ScannedCode, result)); } } for (int i = 0; i < palety.Count; i++) { records.Add(new Record(refRecord, stepRecord, palety[i].Part.Name, palety[i].ScannedCode, result)); } return stepRecord; } void SetErrorFlag(PartError errorCode, Color backColor) { if (errorFlag == PartError.None) { Console.Beep(ErrorBeepFrequency, ErrorBeepDuration); errorFlag = errorCode; BackColor = backColor; saveAllCodesButton.Enabled = false; failedCheckBox.Checked = true; } } void ResetErrorFlag() { if (errorFlag != PartError.None) { errorFlag = PartError.None; BackColor = SystemColors.Control; saveAllCodesButton.Enabled = true; failedCheckBox.Checked = false; foreach (var k in komponenty) k.ClearCode(); ; if (komponenty.Count > 0) komponenty[0].SetFocus(); } } private void resetErrorStateButton_Click(object sender, EventArgs e) { ResetErrorFlag(); } public void OnFocusPressed(object sender, FocusPressedEventArgs data) { ResetIdleTime(); if (FocusPressedHandler == null) return; try { FocusPressedHandler(sender, data); } catch (Exception) { // log.Error("FocusPressedHandler(...) failed", e); } } public event EventHandler FocusPressedHandler; /// public void FocusPressed(object sender, FocusPressedEventArgs data) { foreach (var k in komponenty) k.ResetFocus(); foreach (var p in palety) p.ResetFocus(); if ((data.IxPolozky >= 1) && (data.IxPolozky <= komponenty.Count)) { komponenty[data.IxPolozky - 1].SetFocus(); } else if ((data.IxPolozky >= 100) && (data.IxPolozky - 100 < palety.Count)) { palety[data.IxPolozky - 100].SetFocus(); } } private void clearButton_Click(object sender, EventArgs e) { ResetIdleTime(); foreach (var k in komponenty) { k.ClearCode(); k.ResetFocus(); } foreach (var p in palety) { p.ResetFocus(); } InitializeSNGeneratorPrinter(); } void InitializeSNGeneratorPrinter() { if (komponenty.Count > 0 && komponenty[0] is CheckItems.SNGeneratorPrinter && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator && CurrentOrder != null) { try { var session = SessionFactory.OpenSession(); string generatedCode; var rslt = (komponenty[0] as CheckItems.SNGeneratorPrinter) .NegotiateSerialNr(session, CurrentOrder, CurrentWorkflow, CurrentWorkstep, out generatedCode, false); komponenty[0].ScannedCode = (rslt == OrderProgress.Error) ? "ERROR" : (rslt == OrderProgress.Completed) ? "END" : generatedCode; session.Close(); } catch (Exception exc) { log.ErrorFormat("Failed to negotiate s/n in InitializeSNGeneratorPrinter(): {0}", exc.Message); } } if (komponenty.Count > 1 && komponenty[0] is CheckItems.SNGeneratorPrinter && komponenty[0].Part.CodeForm == (sbyte)CodeForm.SNGenerator) { komponenty[1].SetFocus(); } else if (komponenty.Count > 0) { komponenty[0].SetFocus(); } } private void saveAllCodesButton_Click(object sender, EventArgs e) { if (isSNPrinting) saveAllCodesButton.Enabled = false; try { var session = SessionFactory.OpenSession(); SaveCodes(session); session.Close(); } catch (Exception exc) { string msg = string.Format("Failed to save codes: {0}", exc.Message); log.Error(msg); MessageBox.Show(msg); } } /// /// Update the dictionary of scanned codes of palettes and save it. /// Dictionary contains pairs (process.Name, '~'-separated strings of scanned codes). /// Update codes of parts with CodeType == CodeType.Silicon and shared between workflows as well. /// /// Current workflow name /// A list of palettes /// true = LocalSettings updated and saved bool UpdateAndSaveStoredCodesDictionary(Process process, IList palety) { if (process == null || string.IsNullOrEmpty(process.Name) || palety == null || palety.Count == 0) { return false; } StringBuilder sbSilicon = new StringBuilder(); StringBuilder sb = new StringBuilder(); bool firstSilicon = true; bool first = true; foreach (var p in palety) { if (p.Part.CodeType == (sbyte)CodeType.Silicon) { if (!firstSilicon) sbSilicon.Append("~"); firstSilicon = false; sbSilicon.Append(p.ScannedCode); } else { if (!first) sb.Append("~"); first = false; sb.Append(p.ScannedCode); } } string value = sb.ToString(); string key = process.Name; string storedValue; if (!Program.LocalSettings.LastData.TryGetValue(key, out storedValue)) { Program.LocalSettings.LastData.Add(key, value); Program.LocalSettings.LastSiliconData = sbSilicon.ToString(); Program.LocalSettings.Save(); return true; } else if (storedValue != value) { Program.LocalSettings.LastData[key] = value; Program.LocalSettings.LastSiliconData = sbSilicon.ToString(); Program.LocalSettings.Save(); return true; } else if (sbSilicon.ToString() != Program.LocalSettings.LastSiliconData) { Program.LocalSettings.LastSiliconData = sbSilicon.ToString(); Program.LocalSettings.Save(); return true; } return false; } /// /// Load codes of palettes from the dictionary. /// Dictionary contains pairs (process.Name, '~'-separated strings of scanned codes). /// /// Current process name /// A list of palettes void LoadCodesFromDictionary(string processName, IList palety) { if (string.IsNullOrEmpty(processName) || palety == null) return; string[] loadedCodes = new string[0]; string value; if (Program.LocalSettings.LastData.TryGetValue(processName, out value)) { loadedCodes = value.Split(new char[] { '~' }); } string[] loadedSiliconCodes = new string[0]; try { #if SILICON SiliconBatchNumbers.SiliconBatchNumbers sbn; if (null != (sbn = SiliconBatchNumbers.SiliconBatchNumbers.Load("N:\\iPERL vyroba Stara Tura\\software\\sarze silikonu\\Cfg\\silicon.xml")) || null != (sbn = SiliconBatchNumbers.SiliconBatchNumbers.Load("N:\\iPERL vyroba Stara Tura\\software\\sarze silikonu\\Cfg\\silicon.backup.xml"))) { /// silicon batch numbers loaded from silicon.backup.xml loadedSiliconCodes = sbn.GetSiliconBatchNumbers(Program.LocalSettings.WorkplaceId); } else #endif { loadedSiliconCodes = new string[0]; } } catch (Exception) { loadedSiliconCodes = new string[0]; } int ix = 0; int ixSilicon = 0; for (int i = 0; i < palety.Count; i++) { if ((palety[i].Part.CodeType == (sbyte)CodeType.Silicon) && (ixSilicon < loadedSiliconCodes.Length)) { palety[i].ScannedCode = loadedSiliconCodes[ixSilicon++]; } if (!string.IsNullOrEmpty(palety[i].Part.DefaultCode)) { palety[i].ScannedCode = palety[i].Part.DefaultCode; ix++; } else if (ix < loadedCodes.Length) { palety[i].ScannedCode = loadedCodes[ix++]; } else { palety[i].ClearCode(); } } } /// /// Returns true if any field is empty /// private bool IsAnyFieldEmpty() { foreach (var k in komponenty) { if (k.ScannedCode == string.Empty) return true; } foreach (var p in palety) { if (p.ScannedCode == string.Empty) return true; } return false; } /// /// Clear fields in the left pane and set focus to the beginning /// private void ClearFieldsResetFocus() { foreach (var k in komponenty) { k.ClearCode(); k.ResetFocus(); } foreach (var p in palety) { p.ResetFocus(); } komponenty[0].SetFocus(); } private void WorkplaceDlg_FormClosing(object sender, FormClosingEventArgs e) { bool anyChange = false; UpdateAndSaveStoredCodesDictionary(CurrentWorkflow, palety); if ((CurrentWorkflow != null) && (Program.LocalSettings.LastWorkflow != CurrentWorkflow.Name)) { Program.LocalSettings.LastWorkflow = CurrentWorkflow.Name; anyChange = true; } if ((CurrentWorkstep != null) && (Program.LocalSettings.LastWorkstep != CurrentWorkstep.Name)) { Program.LocalSettings.LastWorkstep = CurrentWorkstep.Name; anyChange = true; } if (anyChange) Program.LocalSettings.Save(); if (recordProcessing != null) recordProcessing.StopProcessing(); wplaceRegistration.UnregisterWorkplace(dbSession); } private void configureButton_Click(object sender, EventArgs e) { LoginAndConfigure(); } private void LoginAndConfigure() { ResetIdleTime(); if (new LoginDlg(Program.SettingsAccessLevel, null).ShowDialog() == DialogResult.OK) { string oriWorkplace = Program.LocalSettings.WorkplaceId; if (Configure() == DialogResult.OK) { orders = ReadOrders(dbSession); UpdateOrderCombo(orders, orderComboBox.Text); workflows = ReadReleasedActiveProcesses(dbSession); UpdateWorkflowCombo(workflows, workflowComboBox.Text); wplaceRegistration.UpdateRegistration(dbSession, Program.LocalSettings.WorkplaceId, Common.CurrentUser.UserName(), "1.2.3.4", (CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty, (CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty, DateTime.Now + new TimeSpan(8, 0, 0)); } } } /// /// Show settings dialog, return DialogResult.OK when any option changed. /// /// true on any change in Program.LoclSettings private DialogResult Configure() { var dlg = new Forms.SettingsDlg(Program.LocalSettings); if (dlg.ShowDialog() == DialogResult.OK) { Program.LocalSettings.Save(); return DialogResult.OK; } else { return DialogResult.Cancel; } } /// /// Called from the state machine when an operation forces a modeless dialog close. /// public static void ColorFlash(object sender, ColorFlashEventArgs args) { if (ColorFlashHandler == null) return; try { ColorFlashHandler(sender, args); } catch (Exception) { } } public static event EventHandler ColorFlashHandler; private static System.Windows.Forms.Timer colorFlashDurationTimer; void OnColorFlash(object sender, ColorFlashEventArgs args) { // start timer here if (colorFlashDurationTimer == null) { colorFlashDurationTimer = new System.Windows.Forms.Timer(); colorFlashDurationTimer.Tick += (s, e) => { ColorFlashAction(); }; } BackColor = args.Color; if (args.Message1 != null) { label1.Text = args.Message1; } if (args.Message2 != null) { label2.Text = args.Message2; } colorFlashDurationTimer.Interval = args.Interval; colorFlashDurationTimer.Start(); if (args.OK) { Console.Beep(); } else { Console.Beep(ErrorBeepFrequency, ErrorBeepDuration); } } // Specify what you want to happen when the Elapsed event is // raised. private void ColorFlashAction() { BackColor = SystemColors.Control; label1.Text = string.Empty; label2.Text = string.Empty; colorFlashDurationTimer.Stop(); colorFlashDurationTimer.Enabled = false; if (isSNPrinting) { saveAllCodesButton.Enabled = true; saveAllCodesButton.Focus(); } } private void logoutButton_Click(object sender, EventArgs e) { workerTextBox.Text = string.Empty; isLoggedOut = true; /// /// User login /// while (true) { DialogResult dr; switch (Program.LocalSettings.LocalWorkplacesCount) { default: case 1: dr = new LoginDlg().ShowDialog(); break; case 2: dr = new DoubleLoginDlg(Program.LocalSettings.LocalWorkplace1, Program.LocalSettings.LocalWorkplace2, this).ShowDialog(); break; case 3: dr = new TripleLoginDlg(Program.LocalSettings.LocalWorkplace1, Program.LocalSettings.LocalWorkplace2, Program.LocalSettings.LocalWorkplace3, this).ShowDialog(); break; } if (dr == DialogResult.OK) break; } workerTextBox.Text = Common.CurrentUser.UserName(); lastLoginTime = DateTime.Now; isLoggedOut = false; ClearBatchNumbers(); wplaceRegistration.UpdateRegistration(dbSession, Program.LocalSettings.WorkplaceId, Common.CurrentUser.UserName(), "1.2.3.4", (CurrentWorkflow != null) ? CurrentWorkflow.Name : string.Empty, (CurrentWorkstep != null) ? CurrentWorkstep.Name : string.Empty, DateTime.Now + new TimeSpan(8, 0, 0)); } private void refreshButton_Click(object sender, EventArgs e) { supressUINotifications = true; orders = ReadOrders(dbSession); UpdateOrderCombo(orders, orderComboBox.Text); workflows = ReadReleasedActiveProcesses(dbSession); if (UpdateWorkflowCombo(workflows, workflowComboBox.Text)) { if (UpdateWorkstepCombo(CurrentWorkflow, workstepComboBox.Text)) { UpdateItems(); } } } private void ManageCheckGroupBox(CheckBox chk, GroupBox grp) { /// Make sure the CheckBox isn't in the GroupBox. This will only happen the first time. if (chk.Parent == grp) { grp.Parent.Controls.Add(chk); /// Reparent the CheckBox so it's not in the GroupBox. chk.Location = new Point(chk.Left + grp.Left, chk.Top + grp.Top); /// Adjust the CheckBox's location. chk.BringToFront(); /// Move the CheckBox to the top of the stacking order. } /// Enable or disable the GroupBox. grp.Enabled = chk.Checked; } private void batchesCheckBox_CheckedChanged(object sender, EventArgs e) { ManageCheckGroupBox(batchesCheckBox, batchesGroupBox); } private void orderComboBox_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '\r' && orderComboBox.Enabled) { /// Enter key was pressed, check whether orderComboBox contains a valid order number orderComboBox_SelectedIndexChanged(sender, e); } } private void orderComboBox_SelectedIndexChanged(object sender, EventArgs e) { /// Check whether orderComboBox contains a valid order number /// Check for (int i = 0; i < predefinedOrders.Length; i++) { if (predefinedOrders[i] == orderComboBox.Text) { CurrentOrder = AllOrders.FirstOrDefault(x => x.POName == (i + 1).ToString("D7")); /// The following replaces UpdatePiecesCount() call targetGroupBox.Visible = false; completedGroupBox.Visible = false; completedGroupBox.BackColor = SystemColors.Control; workflowComboBox.Enabled = true; clearButton_Click(null, null); return; } } long orderNr; OrderInfo order; /// if (string.IsNullOrEmpty(orderComboBox.Text) || !long.TryParse(orderComboBox.Text, out orderNr) || orderNr <= Cnst.MaxPredefinedOrderNr || (order = orders.FirstOrDefault(x => x.POName == orderComboBox.Text)) == null) { CurrentOrder = null; workflowComboBox.Enabled = true; } else { CurrentOrder = order; if (UpdateWorkflowCombo(workflows, order.Workflow)) { if (UpdateWorkstepCombo(CurrentWorkflow, workplaceTextBox.Text)) { UpdateItems(); ClearBatchNumbers(); } } workflowComboBox.Enabled = false; InitializeSNGeneratorPrinter(); } UpdatePiecesCount(); } /// /// Determine the next base number for the specified number generator /// /// All orders (incl. OrderState.Finished ones) /// Number generator index (0 .. Cnst.NrGeneratorsCount - 1) /// Next base number public int GetNextBaseNr(IList allOrders, int nrGeneratorIx) { int nextBaseNr = 0; foreach (var o in allOrders) { int baseNr; switch (nrGeneratorIx) { default: case 0: baseNr = o.BaseNr1; break; case 1: baseNr = o.BaseNr2; break; case 2: baseNr = o.BaseNr3; break; case 3: baseNr = o.BaseNr4; break; case 4: baseNr = o.BaseNr5; break; } if (baseNr + o.PiecesCount + Cnst.ExtraPieces > nextBaseNr) { nextBaseNr = Math.Max(baseNr + o.PiecesCount + Cnst.ExtraPieces, Cnst.MinGeneratedNr); } } return nextBaseNr; } private void orderComboBox_GotFocus(object sender, System.EventArgs e) { orderLabel.ForeColor = Color.White; orderLabel.BackColor = Color.DarkBlue; } private void orderComboBox_LostFocus(object sender, System.EventArgs e) { orderLabel.ForeColor = SystemColors.ControlText; orderLabel.BackColor = SystemColors.Control; } private void orderLabel_Click(object sender, EventArgs e) { orderComboBox.Focus(); } } }