647 lines · 23.7 KB · C#
RawDownload
//******************************************************************************************************//  BulkCalculationState.cs - Gbtc////  Copyright © 2020, 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://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/25/2020 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Threading;using System.Windows.Forms;using System.Xml.Linq;using BulkCalculationState.Model;using GSF;using GSF.Collections;using GSF.ComponentModel;using GSF.Data;using GSF.Data.Model;using GSF.Diagnostics;using GSF.IO;using GSF.Threading;using GSF.Windows.Forms; namespace BulkCalculationState{    public partial class BulkCalculationState : Form    {        private Settings m_settings;        private readonly LogPublisher m_log;        private string m_sourceApp;        private bool m_formLoaded;        private volatile bool m_formClosing;        private AdoDataConnection m_connection;        private TableOperations<CustomActionAdapter> m_actionAdapterTable;        private List<CustomActionAdapter> m_actionAdapters;        private List<FilteredActionAdapter> m_filteredActionAdapters;        private ShortSynchronizedOperation m_updateTotals;        private Process m_consoleProcess;        private string m_consoleOutput;        private bool m_updatingSelectAllStates;        private bool m_reconnecting;         public BulkCalculationState()        {            InitializeComponent();             // Create a new log publisher instance            m_log = Logger.CreatePublisher(typeof(BulkCalculationState), MessageClass.Application);        }         private string GetConfigurationFileName()        {            // Search through list of known source applications (faster than manual search)            foreach (string sourceApp in new[] { "openHistorian", "openPDC" })            {                string absolutePath = FilePath.GetAbsolutePath($"{sourceApp}.exe.config");                 if (File.Exists(absolutePath))                {                    m_sourceApp = sourceApp;                    return absolutePath;                }            }             // Fall back on manual search            foreach (string configFile in FilePath.GetFileList($"{FilePath.AddPathSuffix(FilePath.GetAbsolutePath(""))}*.exe.config"))            {                try                {                    XDocument serviceConfig = XDocument.Load(configFile);                     string applicationName = serviceConfig                        .Descendants("securityProvider")                        .SelectMany(systemSettings => systemSettings.Elements("add"))                        .Where(element => "ApplicationName".Equals((string)element.Attribute("name"), StringComparison.OrdinalIgnoreCase))                        .Select(element => (string)element.Attribute("value"))                        .FirstOrDefault();                     if (string.IsNullOrWhiteSpace(applicationName))                        continue;                     if (applicationName.Trim().Equals(FilePath.GetFileNameWithoutExtension(FilePath.GetFileNameWithoutExtension(configFile)), StringComparison.OrdinalIgnoreCase))                    {                        m_sourceApp = applicationName;                        return configFile;                    }                }                catch (Exception ex)                {                    m_log.Publish(MessageLevel.Warning, "GetConfigurationFileName", $"Failed parse config file \"{configFile}\".", exception: ex);                }            }             m_sourceApp = "unknown";            return "unknown";        }         private void BulkCalculationState_Load(object sender, EventArgs e)        {            try            {                // Load current settings registering a symbolic reference to this form instance for use by default value expressions                m_settings = new Settings(new Dictionary<string, object> { { "Form", this } }.RegisterSymbols());                 // Restore last window size/location                this.RestoreLayout();                 string configFile = GetConfigurationFileName();                 if (!File.Exists(configFile))                    throw new FileNotFoundException("Host service config file was not found.");                 XDocument serviceConfig = XDocument.Load(configFile);                 string connectionString = serviceConfig                    .Descendants("systemSettings")                    .SelectMany(systemSettings => systemSettings.Elements("add"))                    .Where(element => "ConnectionString".Equals((string)element.Attribute("name"), StringComparison.OrdinalIgnoreCase))                    .Select(element => (string)element.Attribute("value"))                    .FirstOrDefault();                 string dataProviderString = serviceConfig                    .Descendants("systemSettings")                    .SelectMany(systemSettings => systemSettings.Elements("add"))                    .Where(element => "DataProviderString".Equals((string)element.Attribute("name"), StringComparison.OrdinalIgnoreCase))                    .Select(element => (string)element.Attribute("value"))                    .FirstOrDefault();                 m_connection = new AdoDataConnection(connectionString, dataProviderString);                m_actionAdapterTable = new TableOperations<CustomActionAdapter>(m_connection);                RefreshActionAdapters();                 m_updateTotals = new ShortSynchronizedOperation(UpdateTotals);                SyncCheckedListBox();                ConnectConsole();                 m_formLoaded = true;            }            catch (Exception ex)            {                m_log.Publish(MessageLevel.Error, "FormLoad", "Failed while loading settings", exception: ex);             #if DEBUG                throw;            #else                MessageBox.Show(this, $"Failed during initialization: {ex.Message}", "Initialization Failure", MessageBoxButtons.OK, MessageBoxIcon.Error);                Application.Exit();            #endif            }        }         private void ConnectConsole()        {            lock (m_settings)            {                Invoke(new Action(() => { buttonEnableSelected.Enabled = false; }));                Invoke(new Action(() => { buttonDelete.Enabled = false; }));                 if (!(m_consoleOutput is null))                {                    m_consoleProcess.OutputDataReceived -= m_consoleProcess_OutputDataReceived;                    m_consoleProcess.Close();                    m_consoleProcess.Dispose();                }                 ClearConsoleOutput();                 ProcessStartInfo startInfo = new ProcessStartInfo                {                    UseShellExecute = false,                    RedirectStandardInput = true,                    RedirectStandardOutput = true,                    WindowStyle = ProcessWindowStyle.Hidden,                    CreateNoWindow = true,                    FileName = FilePath.GetAbsolutePath($"{m_sourceApp}Console.exe")                };                 // Pre-start console process for quick update responses                m_consoleProcess = new Process                {                    StartInfo = startInfo,                    EnableRaisingEvents = true                };                 m_consoleProcess.OutputDataReceived += m_consoleProcess_OutputDataReceived;                m_consoleProcess.Start();                m_consoleProcess.BeginOutputReadLine();            }        }         private void ClearConsoleOutput()        {            lock (m_settings)                m_consoleOutput = "";        }         private void m_consoleProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)        {            const int MaxOutput = 524288;             Debug.WriteLine(e.Data);             lock (m_settings)            {                string output = m_consoleOutput + e.Data;                 if (output.Length > MaxOutput)                    output = output.TruncateLeft(MaxOutput);                 m_consoleOutput = output;                 if ((!buttonEnableSelected.Enabled || !buttonDelete.Enabled) && m_consoleOutput.Contains("Remote client connected"))                {                    ClearConsoleOutput();                    BeginInvoke(new Action(() => { buttonEnableSelected.Enabled = true; }));                    BeginInvoke(new Action(() => { buttonDelete.Enabled = true; }));                    m_reconnecting = false;                }            }        }         private void BulkCalculationState_FormClosing(object sender, FormClosingEventArgs e)        {            try            {                m_formClosing = true;                 // Save current window size/location                this.SaveLayout();                 // Save any updates to current screen values                m_settings.Save();                 // Close associated console process                m_consoleProcess.Close();            }            catch (Exception ex)            {                m_log.Publish(MessageLevel.Error, "FormClosing", "Failed while saving settings", exception: ex);             #if DEBUG                throw;            #endif            }        }         private void BulkCalculationState_FormClosed(object sender, FormClosedEventArgs e)        {            m_settings?.Dispose();        }         private void FormElementChanged(object sender, EventArgs e)        {            if (InvokeRequired)            {                BeginInvoke(new Action<object, EventArgs>(FormElementChanged), sender, e);            }            else            {                if (Visible && m_formLoaded)                    m_settings?.UpdateProperties();            }        }         private bool FilterApplied => checkBoxGroupByPrefix.Checked || !string.IsNullOrWhiteSpace(textBoxFilter.Text);         private void RefreshActionAdapters()        {            string filter = textBoxFilter.Text.ToLowerInvariant();             lock (m_actionAdapterTable)            {                m_actionAdapters = m_actionAdapterTable.QueryRecordsWhere("TypeName = 'DynamicCalculator.DynamicCalculator'").ToList();                m_actionAdapters.Sort();                 Dictionary<string, FilteredActionAdapter> filteredAdapters = new Dictionary<string, FilteredActionAdapter>(StringComparer.OrdinalIgnoreCase);                 foreach (CustomActionAdapter actionAdapter in m_actionAdapters)                {                    string name = actionAdapter.AdapterName;                     if (checkBoxGroupByPrefix.Checked)                    {                        int dash = name.IndexOf('-');                        name = dash < 0 ? name : name.Substring(0, dash);                         if (name.EndsWith("CALC", StringComparison.OrdinalIgnoreCase) && name.Length > 4)                            name = name.Substring(0, name.Length - 4);                    }                     if (!string.IsNullOrWhiteSpace(filter) && !name.ToLowerInvariant().Contains(filter))                        continue;                     FilteredActionAdapter filteredAdapter = filteredAdapters.GetOrAdd(name, _ => new FilteredActionAdapter { AdapterName = name });                    filteredAdapter.Adapters.Add(actionAdapter);                }                 m_filteredActionAdapters = filteredAdapters.Values.ToList();                m_filteredActionAdapters.Sort();                 foreach (FilteredActionAdapter filteredActionAdapter in m_filteredActionAdapters)                {                    filteredActionAdapter.Enabled = filteredActionAdapter.Adapters.All(adapter => adapter.Enabled);                     if (FilterApplied)                        filteredActionAdapter.SyncEnabledAdapterStates();                }            }             BeginInvoke(new Action(() =>            {                lock (m_actionAdapterTable)                {                    UseWaitCursor = true;                     // Force full refresh of list                    checkedListBoxDevices.DataSource = null;                    checkedListBoxDevices.DataSource = FilterApplied ? (object)m_filteredActionAdapters : m_actionAdapters;                    checkedListBoxDevices.DisplayMember = "AdapterName";                    checkedListBoxDevices.ValueMember = "Enabled";                    SyncCheckedListBox();                     UseWaitCursor = false;                }            }));        }         private void textBoxFilter_TextChanged(object sender, EventArgs e)        {            if (!m_formLoaded || m_formClosing)                return;             RefreshActionAdapters();            FormElementChanged(sender, e);        }         private void checkBoxGroupByPrefix_CheckedChanged(object sender, EventArgs e)        {            if (!m_formLoaded || m_formClosing)                return;             RefreshActionAdapters();            FormElementChanged(sender, e);        }         private void checkedListBoxDevices_ItemCheck(object sender, ItemCheckEventArgs e)        {            if (!m_formLoaded || m_formClosing)                return;             object item = checkedListBoxDevices.Items[e.Index];            bool state = e.NewValue == CheckState.Checked;             if (item is CustomActionAdapter actionAdapter)                actionAdapter.Enabled = state;             if (item is FilteredActionAdapter filteredActionAdapter)            {                filteredActionAdapter.Enabled = state;                 if (FilterApplied)                    filteredActionAdapter.SyncEnabledAdapterStates();            }             UpdateSelectAllStates();        }         private void SelectAllCheckedChanged(object sender, EventArgs e)        {            if (m_updatingSelectAllStates || !m_formLoaded || m_formClosing)                return;             bool enabled = radioButtonSelectAll.Checked;             lock (m_actionAdapterTable)            {                if (FilterApplied)                {                    foreach (FilteredActionAdapter actionAdapter in m_filteredActionAdapters)                        actionAdapter.Enabled = enabled;                }                else                {                    foreach (CustomActionAdapter actionAdapter in m_actionAdapters)                        actionAdapter.Enabled = enabled;                }            }             SyncCheckedListBox();        }         private bool ReloadConfigComplete()        {            lock (m_settings)            {                return m_consoleOutput.Contains("System configuration was successfully reloaded.") ||                       m_consoleOutput.Contains("Database connection closed.");            }        }         private void ReloadConfig()        {            ClearConsoleOutput();            m_consoleProcess.StandardInput.WriteLine("ReloadConfig");             const int SleepInterval = 100;            const int MaxSleeps = 50; // 5 seconds            int sleepCount = 0;             while (!ReloadConfigComplete() && sleepCount++ < MaxSleeps && !m_reconnecting)                Thread.Sleep(SleepInterval);             if (sleepCount > MaxSleeps)                throw new TimeoutException("Timeout while waiting on reload configuration response");        }         private void buttonEnableSelected_Click(object sender, EventArgs e)        {            if (!m_formLoaded || m_formClosing)                return;             buttonEnableSelected.Enabled = false;            buttonEnableSelected.Text = "Working...";            UseWaitCursor = true;             ThreadPool.QueueUserWorkItem(_ =>            {                try                {                    SyncDataSource();                     lock (m_actionAdapterTable)                    {                        foreach (CustomActionAdapter actionAdapter in m_actionAdapters)                            m_actionAdapterTable.UpdateRecord(actionAdapter);                    }                     ReloadConfig();                }                catch (Exception ex)                {                    BeginInvoke(new Action(() => MessageBox.Show(this, $"Error updating calculation states: {ex.Message}", "Update Error", MessageBoxButtons.OK, MessageBoxIcon.Error)));                }                finally                {                    BeginInvoke(new Action(() =>                    {                        UseWaitCursor = false;                        buttonEnableSelected.Text = buttonEnableSelected.Tag.ToString();                         if (!m_reconnecting)                            buttonEnableSelected.Enabled = true;                    }));                }            });        }         private void buttonDelete_Click(object sender, EventArgs e)        {            if (!m_formLoaded || m_formClosing)                return;             if (MessageBox.Show(this, $"Are you sure you want to delete {m_actionAdapters.Count(adapter => adapter.Enabled):N0} selected devices?", "Delete Devices", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)                return;             buttonDelete.Enabled = false;            buttonDelete.Text = "Working...";            UseWaitCursor = true;             ThreadPool.QueueUserWorkItem(_ =>            {                try                {                    SyncDataSource();                     lock (m_actionAdapterTable)                    {                        foreach (CustomActionAdapter actionAdapter in m_actionAdapters)                        {                            if (actionAdapter.Enabled)                                m_actionAdapterTable.DeleteRecord(actionAdapter);

Lines 1–500 of 647.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t