//****************************************************************************************************** // Devices.cs - Gbtc // // Copyright © 2010, 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: // ---------------------------------------------------------------------------------------------------- // 05/06/2011 - Mehulbhai P Thakkar // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Windows; using System.Windows.Input; using GSF.PhasorProtocols.UI.DataModels; using GSF.PhasorProtocols.UI.Modal; using GSF.PhasorProtocols.UI.UserControls; using GSF.TimeSeries.UI; using GSF.TimeSeries.UI.Commands; using GSF.TimeSeries.UI.DataModels; namespace GSF.PhasorProtocols.UI.ViewModels { /// /// Class to hold bindable collection and current selection information for UI. /// internal class Devices : PagedViewModelBase { #region [ Members ] // Fields private Dictionary m_nodeLookupList; private Dictionary m_concentratorDeviceLookupList; private Dictionary m_companyLookupList; private Dictionary m_historianLookupList; private Dictionary m_interconnectionLookupList; private Dictionary m_protocolLookupList; private Dictionary m_vendorDeviceLookupList; private Dictionary m_timezoneLookupList; private RelayCommand m_editCommand; private RelayCommand m_phasorCommand; private RelayCommand m_measurementCommand; private RelayCommand m_copyCommand; private RelayCommand m_initializeCommand; private RelayCommand m_buildConnectionStringCommand; private RelayCommand m_buildAlternateCommandChannelCommand; private RelayCommand m_updateConfigurationCommand; private RelayCommand m_configureConcentratorCommand; private string m_runtimeID; //private ObservableCollection m_devices; private RelayCommand m_searchCommand; private RelayCommand m_showAllCommand; private bool m_stayOnConfigurationScreen; private ObservableCollection m_pdcDevices; private string m_searchText; private IList m_allKeys; #endregion #region [ Constructors ] /// /// Creates an instance of class. /// /// /// /// to be edited. public Devices(int itemsPerPage, bool autoSave = true, Device device = null) : base(itemsPerPage, autoSave) { // When device is null, user wants to edit existing device's configuration. So we will load that by default. if ((object)device != null) { CurrentItem = device; OnPropertyChanged("IsNewRecord"); OnPropertyChanged("CanGoToPhasorOrMeasurement"); if (device.IsConcentrator) PdcDevices = Device.GetDevices(null, "WHERE ParentID = " + device.ID); } } #endregion #region [ Properties ] /// /// Gets or sets to build connection string. /// public ICommand BuildConnectionStringCommand { get { if ((object)m_buildConnectionStringCommand == null) m_buildConnectionStringCommand = new RelayCommand(BuildConnectionString); return m_buildConnectionStringCommand; } } /// /// Gets or sets to build alternate command channel. /// public ICommand BuildAlternateCommandChannelCommand { get { if ((object)m_buildAlternateCommandChannelCommand == null) m_buildAlternateCommandChannelCommand = new RelayCommand(BuildAlternateCommandChannel); return m_buildAlternateCommandChannelCommand; } } /// /// Gets or sets RuntimeID. /// public string RuntimeID { get { return m_runtimeID; } set { m_runtimeID = value; OnPropertyChanged("RuntimeID"); } } /// /// Gets type collection of defined in the database. /// public Dictionary NodeLookupList { get { return m_nodeLookupList; } } /// /// Gets type collection of concentrator defined in the database. /// public Dictionary ConcentratorDeviceLookupList { get { return m_concentratorDeviceLookupList; } } /// /// Gets type collection of defined in the database. /// public Dictionary CompanyLookupList { get { return m_companyLookupList; } } /// /// Gets type collection of defined in the database. /// public Dictionary HistorianLookupList { get { return m_historianLookupList; } } /// /// Gets type collection of defined in the database. /// public Dictionary InterconnectionLookupList { get { return m_interconnectionLookupList; } } /// /// Gets type collection of defined in the database. /// public Dictionary ProtocolLookupList { get { return m_protocolLookupList; } } /// /// Gets type collection of defined in the database. /// public Dictionary VendorDeviceLookupList { get { return m_vendorDeviceLookupList; } } /// /// Gets type collection of system time zones. /// public Dictionary TimezoneLookupList { get { return m_timezoneLookupList; } } /// /// Gets flag that determines if is a new record. /// public override bool IsNewRecord { get { return CurrentItem.ID == 0; } } /// /// Gets for edit operation. /// public ICommand EditCommand { get { if ((object)m_editCommand == null) m_editCommand = new RelayCommand(GoToEdit); return m_editCommand; } } /// /// Gets for copy operation. /// public ICommand CopyCommand { get { if ((object)m_copyCommand == null) m_copyCommand = new RelayCommand(MakeCopy); return m_copyCommand; } } /// /// Gets for updating configuration. /// public ICommand UpdateConfigurationCommand { get { if ((object)m_updateConfigurationCommand == null) m_updateConfigurationCommand = new RelayCommand(UpdateConfiguration); return m_updateConfigurationCommand; } } /// /// Gets to go to phasors configuration. /// public ICommand PhasorCommand { get { if ((object)m_phasorCommand == null) m_phasorCommand = new RelayCommand(GoToPhasors, () => CanGoToPhasorOrMeasurement); return m_phasorCommand; } } /// /// Gets a boolean flag indicating if Phasors and Measurements button are visible or not. /// public bool CanGoToPhasorOrMeasurement { get { return CurrentItem.ID > 0; } } /// /// Gets to go to measurements configuration. /// public ICommand MeasurementCommand { get { if ((object)m_measurementCommand == null) m_measurementCommand = new RelayCommand(GoToMeasurements, () => CanGoToPhasorOrMeasurement); return m_measurementCommand; } } /// /// Gets to send Initialize command to backed service. /// public ICommand InitializeCommand { get { if ((object)m_initializeCommand == null) m_initializeCommand = new RelayCommand(InitializeDevice, () => CanSave); return m_initializeCommand; } } /// /// Gets to search within measurements. /// public ICommand SearchCommand { get { if ((object)m_searchCommand == null) m_searchCommand = new RelayCommand(Search, param => true); return m_searchCommand; } } /// /// Gets to show all measurements. /// public ICommand ShowAllCommand { get { if ((object)m_showAllCommand == null) m_showAllCommand = new RelayCommand(ShowAll); return m_showAllCommand; } } public ICommand ConfigureConcentratorCommand { get { if ((object)m_configureConcentratorCommand == null) m_configureConcentratorCommand = new RelayCommand(ConfigureConcentrator); return m_configureConcentratorCommand; } } public ObservableCollection PdcDevices { get { return m_pdcDevices; } set { m_pdcDevices = value; OnPropertyChanged("PdcDevices"); } } public IList AllKeys { get { if ((object)m_allKeys == null) m_allKeys = Device.LoadKeys(null, 0, "", SortMember, SortDirection); return m_allKeys; } set { m_allKeys = value; } } #endregion #region [ Methods ] /// /// 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.Name; } /// /// Creates a new instance of and assigns it to CurrentItem. /// public override void Clear() { base.Clear(); // Reset all the dropdown fields so that first item displays as selected. if (m_nodeLookupList.Count > 0) CurrentItem.NodeID = m_nodeLookupList.First().Key; if (m_concentratorDeviceLookupList.Count > 0) CurrentItem.ParentID = m_concentratorDeviceLookupList.First().Key; if (m_companyLookupList.Count > 0) CurrentItem.CompanyID = m_companyLookupList.First().Key; if (m_historianLookupList.Count > 0) CurrentItem.HistorianID = m_historianLookupList.First().Key; if (m_interconnectionLookupList.Count > 0) CurrentItem.InterconnectionID = m_interconnectionLookupList.First().Key; if (m_protocolLookupList.Count > 0) CurrentItem.ProtocolID = m_protocolLookupList.First().Key; if (m_vendorDeviceLookupList.Count > 0) CurrentItem.VendorDeviceID = m_vendorDeviceLookupList.First().Key; if (m_timezoneLookupList.Count > 0) CurrentItem.TimeZone = m_timezoneLookupList.First().Key; } /// /// Initialization to be done before the initial call to . /// public override void Initialize() { base.Initialize(); m_nodeLookupList = Node.GetLookupList(null); m_concentratorDeviceLookupList = Device.GetLookupList(null, DeviceType.Concentrator, true); m_companyLookupList = Company.GetLookupList(null, true); m_historianLookupList = TimeSeries.UI.DataModels.Historian.GetLookupList(null, true, false); m_interconnectionLookupList = Interconnection.GetLookupList(null, true); m_protocolLookupList = Protocol.GetLookupList(null, true); m_vendorDeviceLookupList = VendorDevice.GetLookupList(null, true); m_timezoneLookupList = CommonFunctions.GetTimeZones(true); } /// /// Loads collection of information stored in the database. /// /// This method is overridden because MethodInfo.Invoke in the base class did not like optional parameters. public override void Load() { Mouse.OverrideCursor = Cursors.Wait; List pageKeys; try { if (OnBeforeLoadCanceled()) throw new OperationCanceledException("Load was canceled."); if ((object)ItemsKeys == null) { ItemsKeys = Device.LoadKeys(null, 0, m_searchText, SortMember, SortDirection); if ((object)SortSelector != null) { if (SortDirection == "ASC") ItemsKeys = ItemsKeys.OrderBy(SortSelector).ToList(); else ItemsKeys = ItemsKeys.OrderByDescending(SortSelector).ToList(); } if (string.IsNullOrEmpty(m_searchText)) AllKeys = ItemsKeys; } pageKeys = ItemsKeys.Skip((CurrentPageNumber - 1) * ItemsPerPage).Take(ItemsPerPage).ToList(); ItemsSource = Device.Load(null, pageKeys); OnLoaded(); } catch (Exception ex) { if ((object)ex.InnerException != null) { Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Load Devices Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Load Devices", ex.InnerException); } else { Popup(ex.Message, "Load Devices Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Load Devices", ex); } } finally { Mouse.OverrideCursor = null; } } /// /// Saves information into database. /// public override void Save() { Mouse.OverrideCursor = Cursors.Wait; try { Device originalDevice = null; // If it is an existing device being modified, get prior state so we can determine if a rename occurred. if (CurrentItem.ID > 0) originalDevice = Device.GetDevice(null, "WHERE ID = " + CurrentItem.ID); // Attempt to save base record before possible rename attempt as base record save can fail base.Save(); try { // If renaming a phasor device (e.g., a PMU not a PDC), check if user would like to update device acronym in output streams - this happens here // instead of in the view model such that a message box can be displayed in the UI to engage user about desire to update output streams. We only // perform this task for phasor style connections since renaming subscribed devices, although functional, will not "stick" - renamed devices will // be reverted back to their original names at the next meta-data refresh. if (!CurrentItem.IsConcentrator && (object)originalDevice != null && string.Compare(CurrentItem.ProtocolCategory, "Phasor", StringComparison.OrdinalIgnoreCase) == 0 && (string.CompareOrdinal(CurrentItem.Acronym, originalDevice.Acronym) != 0 || string.CompareOrdinal(CurrentItem.Name, originalDevice.Name) != 0) && Confirm("Device was renamed, do you want to also update the device name where it may exist in output streams?", "Update Output Stream Device")) { ObservableCollection outputStreamDevices = OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + originalDevice.Acronym + "'"); foreach (OutputStreamDevice device in outputStreamDevices) { device.Acronym = CurrentItem.Acronym; device.BpaAcronym = CurrentItem.Acronym.Substring(0, 4); device.Name = CurrentItem.Name; OutputStreamDevice.Save(null, device); } } } catch (Exception ex) { if ((object)ex.InnerException != null) { Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Device Rename:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Device Rename", ex.InnerException); } else { Popup(ex.Message, "Device Rename Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Device Rename", ex); } } // If user is on form page then go back to list page after save. if (ItemsPerPage == 0) { if (!m_stayOnConfigurationScreen) CommonFunctions.LoadUserControl("Browse Devices", typeof(DeviceListUserControl)); } } catch (Exception ex) { if ((object)ex.InnerException != null) { Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Save Device Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Save Device", ex.InnerException); } else { Popup(ex.Message, "Save Device Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Save Device", ex); } } finally { Mouse.OverrideCursor = null; } } /// /// Handles . /// /// Parameter to use for the command provided by command parameter from UI. private void GoToEdit(object parameter) { CommonFunctions.LoadUserControl("Manage Device Configuration", typeof(DeviceUserControl), (Device)parameter); } /// /// Handles . /// /// Parameter to use for the command provided by command parameter from UI. private void MakeCopy(object parameter) { Device deviceToCopy = (Device)parameter; string newAcronym; int i = 1; // Find unique acronym. do { newAcronym = deviceToCopy.Acronym + i; i++; } while (DeviceExists(newAcronym)); deviceToCopy.Acronym = newAcronym; // Change acronym of the device before going to edit screen. deviceToCopy.Name = "Copy of " + deviceToCopy.Name; // Change name of the device before going to edit screen. deviceToCopy.ID = 0; // Set id to zero so that it will be added as a new device. ItemsPerPage = 0; // Set this so that on Save() user will be sent back to list screen. deviceToCopy.Enabled = false; // Always set enabled to false for copied device. // Go to edit screen. CommonFunctions.LoadUserControl("Manage Device Configuration", typeof(DeviceUserControl), deviceToCopy); } private void UpdateConfiguration(object parameter) { CommonFunctions.LoadUserControl("Input Device Configuration Wizard", typeof(InputWizardUserControl), (Device)parameter); } private bool DeviceExists(string acronym) { foreach (Device device in ItemsSource) { if (device.Acronym == acronym) return true; } return false; } /// /// Handles . /// private void GoToMeasurements() { CommonFunctions.LoadUserControl("Manage Measurements for " + CurrentItem.Acronym, typeof(PhasorMeasurementUserControl), CurrentItem.ID); } /// /// Handles . /// private void GoToPhasors() { CommonFunctions.LoadUserControl("Manage Phasors for " + CurrentItem.Acronym, typeof(PhasorUserControl), CurrentItem.ID); } protected override void OnPropertyChanged(string propertyName) { base.OnPropertyChanged(propertyName); if (propertyName == "CurrentItem") { if ((object)CurrentItem == null) RuntimeID = string.Empty; else RuntimeID = CommonFunctions.GetRuntimeID("Device", CurrentItem.ID); } } private void InitializeDevice() { try { if (!string.IsNullOrEmpty(RuntimeID)) { if (Confirm("Do you want to send Initialize " + GetCurrentItemName() + "?", "Confirm Initialize")) { Device.NotifyService(CurrentItem); Popup("Successfully sent Initialize command.", "Initialize", MessageBoxImage.Information); } } } catch (Exception ex) { Popup("ERROR: " + ex.Message, "Failed To Initialize", MessageBoxImage.Error); } } private void BuildConnectionString() { if ((object)CurrentItem != null) { ConnectionStringBuilder csb = new ConnectionStringBuilder(ConnectionStringBuilder.ConnectionType.DeviceConnection); if (!string.IsNullOrEmpty(CurrentItem.ConnectionString)) csb.ConnectionString = CurrentItem.ConnectionString; csb.Closed += delegate { if (csb.DialogResult.GetValueOrDefault()) CurrentItem.ConnectionString = csb.ConnectionString; }; csb.Owner = Application.Current.MainWindow; csb.WindowStartupLocation = WindowStartupLocation.CenterOwner; csb.ShowDialog(); } } private void BuildAlternateCommandChannel() { if ((object)CurrentItem != null) { ConnectionStringBuilder csb = new ConnectionStringBuilder(ConnectionStringBuilder.ConnectionType.AlternateCommandChannel); if (!string.IsNullOrEmpty(CurrentItem.AlternateCommandChannel)) csb.ConnectionString = CurrentItem.AlternateCommandChannel; if (CurrentItem.ProtocolID != null && m_protocolLookupList[(int)CurrentItem.ProtocolID] == "Gateway Transport") csb.PgConnection = true; else csb.PgConnection = false; csb.Closed += delegate { if (csb.DialogResult.GetValueOrDefault()) CurrentItem.AlternateCommandChannel = csb.ConnectionString; }; csb.Owner = Application.Current.MainWindow; csb.WindowStartupLocation = WindowStartupLocation.CenterOwner; csb.ShowDialog(); } } /// /// Deletes current item from the database. /// public override void Delete() { try { if (CurrentItem.IsConcentrator) { IList keys = Device.LoadKeys(null, CurrentItem.ID); ObservableCollection deviceList = Device.Load(null, keys); int outputStreamDeviceCount = 0; string result; foreach (Device device in deviceList) { outputStreamDeviceCount += OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + device.Acronym + "'").Count; } string confirm = "Are you sure you want to delete concentrator device?"; if (deviceList.Count > 1) confirm += Environment.NewLine + "There are " + deviceList.Count.ToString() + " associated children devices."; else if (deviceList.Count > 0) confirm += Environment.NewLine + "There is " + deviceList.Count.ToString() + " associated child device."; if (outputStreamDeviceCount > 1) confirm += Environment.NewLine + "There are " + outputStreamDeviceCount.ToString() + " output stream devices that exist."; else if (outputStreamDeviceCount > 0) confirm += Environment.NewLine + "There is " + outputStreamDeviceCount.ToString() + " output stream device that exists."; if (Confirm(confirm, "Delete Device")) { foreach (Device device in deviceList) Device.Delete(null, device); result = Device.Delete(null, CurrentItem); DisplayStatusMessage(result); } } else { ObservableCollection outputStreamDevices = OutputStreamDevice.GetOutputStreamDevices(null, "WHERE Acronym = '" + CurrentItem.Acronym + "'"); string confirm = "Are you sure you want to delete this device?"; if (outputStreamDevices.Count > 1) confirm += Environment.NewLine + "It exists in " + outputStreamDevices.Count.ToString() + " output streams."; else if (outputStreamDevices.Count > 0) confirm += Environment.NewLine + "It exists in " + outputStreamDevices.Count.ToString() + " output stream."; if (Confirm(confirm, "Delete Device")) { string result = Device.Delete(null, CurrentItem); DisplayStatusMessage(result); } } Device.NotifyService(null, CurrentItem.HistorianID); CommonFunctions.LoadUserControl("Browse Devices", typeof(DeviceListUserControl)); } catch (Exception ex) { if ((object)ex.InnerException != null) { Popup(ex.Message + Environment.NewLine + "Inner Exception: " + ex.InnerException.Message, "Delete Device Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Delete Device", ex.InnerException); } else { Popup(ex.Message, "Delete Device Exception:", MessageBoxImage.Error); CommonFunctions.LogException(null, "Delete Device", ex); } } } /// /// Handles . /// /// string value to search for in measurement collection. public void Search(object parameter) { if ((object)parameter != null && !string.IsNullOrEmpty(parameter.ToString())) { SetCurrentPageNumber(1); m_searchText = parameter.ToString(); ItemsKeys = null; Load(); } } /// /// Handles . /// public void ShowAll() { if (!ReferenceEquals(AllKeys, ItemsKeys)) { SetCurrentPageNumber(1); m_searchText = null; ItemsKeys = AllKeys; Load(); } } private void ConfigureConcentrator() { if ((object)CurrentItem.ParentID != null && CurrentItem.ParentID > 0) { m_stayOnConfigurationScreen = true; Device device = Device.GetDevice(null, "WHERE ID = " + CurrentItem.ParentID); if ((object)device != null) { PdcDevices = Device.GetDevices(null, "WHERE ParentID = " + CurrentItem.ParentID); CurrentItem = device; } } } #endregion } }