//****************************************************************************************************** // Alarms.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 02/10/2012 - Stephen C. Wills // Generated original version of source code. // 12/20/2012 - Starlynn Danyelle Gilliam // Modified Header. // 07/29/2015 - J. Ritchie Carroll // Adjusted alarm severity and operation lists to load from source enumerations. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Windows; using GSF.TimeSeries.UI.DataModels; namespace GSF.TimeSeries.UI.ViewModels { /// /// Class to hold bindable collection and current selection information for UI. /// internal class Alarms : PagedViewModelBase { #region [ Members ] // Fields private Dictionary m_nodeLookupList; private Dictionary m_operationList; private Dictionary m_severityList; private Dictionary m_measurementLabels; private string m_selectedMeasurementLabel; #endregion #region [ Constructors ] /// /// Creates a new instance of the class. /// /// Integer value to determine number of items per page. /// Boolean value to determine is user changes should be saved automatically. public Alarms(int itemsPerPage, bool autoSave = true) : base(itemsPerPage, autoSave) { } #endregion #region [ Properties ] /// /// Gets flag that determines if is a new record. /// public override bool IsNewRecord { get { return CurrentItem.ID == 0; } } /// /// Gets the list of nodes. /// public Dictionary NodeLookupList { get { return m_nodeLookupList; } } /// /// Gets a list of operations that can be performed to trigger an alarm. /// public Dictionary OperationList { get { return m_operationList; } } /// /// Gets a list of levels of severity that can be assigned to alarms. /// public Dictionary SeverityList { get { return m_severityList; } } /// /// Gets a list of the measurement labels for the alarms on the current page. /// public Dictionary MeasurementLabels { get { return m_measurementLabels; } } /// /// Gets or sets the label of the measurement selected by the user. /// public string SelectedMeasurementLabel { get { return m_selectedMeasurementLabel; } set { m_selectedMeasurementLabel = value; OnPropertyChanged("SelectedMeasurementLabel"); } } #endregion #region [ Methods ] /// /// Initialization to be done before the initial call to . /// public override void Initialize() { m_measurementLabels = new Dictionary(); base.Initialize(); m_nodeLookupList = Node.GetLookupList(null); m_operationList = CreateOperationList(); m_severityList = CreateSeverityList(); } /// /// Loads collection of defined in the database. /// public override void Load() { try { base.Load(); foreach (DataModels.Alarm alarm in ItemsSource) { alarm.OperationDescription = GetOperationDescription(alarm); alarm.SeverityName = SeverityList[alarm.Severity]; } } catch (Exception ex) { if (ex.InnerException != null) { Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Load " + DataModelName + " Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Load " + DataModelName, ex.InnerException); } else { Popup(ex.Message, "Load " + DataModelName + " Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Load " + DataModelName, ex); } } } /// /// Gets the primary key value of the . /// /// The primary key value of the . public override int GetCurrentItemKey() { return CurrentItem.ID; } /// /// Gets the string based named identifier of the . /// /// The string based named identifier of the . public override string GetCurrentItemName() { return CurrentItem.TagName; } /// /// Clears the record for the associated . /// public override void Clear() { base.Clear(); SelectedMeasurementLabel = string.Empty; if (m_operationList.Count > 0) CurrentItem.Operation = m_operationList.First().Key; if (m_severityList.Count > 0) CurrentItem.Severity = m_severityList.First().Key; } /// /// Handles PropertyChanged event on CurrentItem. /// /// Source of the event. /// Event arguments. protected override void m_currentItem_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case "OperationDescription": case "SeverityName": case "SetPointEnabled": case "ToleranceEnabled": case "HysteresisEnabled": case "DelayEnabled": break; default: base.m_currentItem_PropertyChanged(sender, e); break; } if (e.PropertyName == "SignalID") m_measurementLabels = GetMeasurementLabels(); if (e.PropertyName == "SignalID" || e.PropertyName == "Operation" || e.PropertyName == "SetPoint" || e.PropertyName == "Delay") CurrentItem.OperationDescription = GetOperationDescription(CurrentItem); if (e.PropertyName == "Severity") CurrentItem.SeverityName = SeverityList[CurrentItem.Severity]; if (e.PropertyName == "Operation") UpdateEnableFlags(); if (e.PropertyName == "SignalID" || e.PropertyName == "Operation" || e.PropertyName == "Severity") CurrentItem.TagName = GetTagName(CurrentItem); } /// /// Raises the event. /// /// Property name that has changed. protected override void OnPropertyChanged(string propertyName) { string selectedMeasurementLabel; if (propertyName == "ItemsSource") m_measurementLabels = GetMeasurementLabels(); base.OnPropertyChanged(propertyName); if (propertyName == "CurrentItem") { m_measurementLabels.TryGetValue(CurrentItem.SignalID, out selectedMeasurementLabel); SelectedMeasurementLabel = selectedMeasurementLabel; UpdateEnableFlags(); } } // Creates a list of operations that can be performed to trigger an alarm. private Dictionary CreateOperationList() { Dictionary operationList = new Dictionary(); foreach (AlarmOperation operation in Enum.GetValues(typeof(AlarmOperation)).Cast()) operationList.Add((int)operation, operation.GetDescription()); return operationList; } // Creates a list of levels of severity that can be assigned to alarms. private Dictionary CreateSeverityList() { Dictionary severityList = new Dictionary(); foreach (AlarmSeverity severity in Enum.GetValues(typeof(AlarmSeverity)).Cast()) severityList.Add((int)severity, severity.GetFormattedName()); return severityList; } // Creates a list of measurement labels for the current page of alarms. private Dictionary GetMeasurementLabels() { List signals = ItemsSource.Select(alarm => alarm.SignalID).Distinct().ToList(); if (IsNewRecord && CurrentItem.SignalID != Guid.Empty && !signals.Contains(CurrentItem.SignalID)) signals.Add(CurrentItem.SignalID); IList measurements = DataModels.Measurement.LoadFromKeys(null, signals); return measurements.ToDictionary(measurement => measurement.SignalID, measurement => measurement.PointTag); } // Generates an alarm tag name private string GetTagName(DataModels.Alarm item) { string measurementLabel; StringBuilder description = new StringBuilder("AL-"); AlarmSeverity severity = item.Severity.GetEnumValueOrDefault(AlarmSeverity.None); AlarmOperation operation = item.Operation.GetEnumValueOrDefault(AlarmOperation.Equal); switch (severity) { case AlarmSeverity.None: description.Append("EXEMPT"); break; case AlarmSeverity.Unreasonable: switch (operation) { case AlarmOperation.GreaterThan: case AlarmOperation.GreaterOrEqual: description.Append("HIGH"); break; case AlarmOperation.LessThan: case AlarmOperation.LessOrEqual: description.Append("LOW"); break; default: description.Append(severity.GetDescription()); break; } break; default: description.Append(severity.GetDescription()); break; } description.Append(':'); if (m_measurementLabels.TryGetValue(item.SignalID, out measurementLabel)) description.Append(measurementLabel); return description.ToString(); } // Generates a description of the operation that triggers the alarm. private string GetOperationDescription(DataModels.Alarm item) { if (item.ID > 0) { string measurementLabel; if (!m_measurementLabels.TryGetValue(item.SignalID, out measurementLabel)) measurementLabel = m_selectedMeasurementLabel; return DataModels.Alarm.GetOperationDescription(item, measurementLabel); } return string.Empty; } /// /// Updates the enable flags which determine whether /// or not certain input fields are enabled. /// private void UpdateEnableFlags() { bool[] enabledFlags = { true, true, true, true }; switch ((AlarmOperation)CurrentItem.Operation) { case AlarmOperation.Equal: case AlarmOperation.NotEqual: enabledFlags = new[] { true, true, true, false }; break; case AlarmOperation.GreaterOrEqual: case AlarmOperation.LessOrEqual: case AlarmOperation.GreaterThan: case AlarmOperation.LessThan: enabledFlags = new[] { true, false, true, true }; break; case AlarmOperation.Flatline: enabledFlags = new[] { false, false, true, false }; break; } CurrentItem.SetPointEnabled = enabledFlags[0]; CurrentItem.ToleranceEnabled = enabledFlags[1]; CurrentItem.DelayEnabled = enabledFlags[2]; CurrentItem.HysteresisEnabled = enabledFlags[3]; } #endregion } }