using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using VEPROMS.CSLA.Library; using Volian.Base.Library; using Volian.Pipe.Library; using System.Xml; using System.Diagnostics; using JR.Utils.GUI.Forms; namespace Volian.Controls.Library { public delegate void NewMessageDelegate(string NewMessage); public partial class AnnotationDetails : UserControl { private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #region Properties private bool _LoadingAnnotation = false; private bool _LoadingGrid = false; private XmlDocument _ProcList; private ItemInfo _ProcItem = null; public ItemInfo ProcItem { get { return _ProcItem; } set { // B2019-054 needed to add a check for value being NULL else we would always get a list of PROMS database to choose from (prematurely) if (!DesignMode && value != null) // B2019-043 need to check if we are just saving changes to the user interface { //if (_ProcItem == value) return; // Jeff (Westinghouse) requested list to be provided every time fixes both C2016-007 and B2016-097 _ProcItem = value; if (ExeType > 0) CreateProcList(); } } } private void CreateProcList() { _ProcList = null; if (_ProcItem == null) return; _ProcList = new XmlDocument(); _ProcList.LoadXml(""); AddItem(0,ProcItem); //Console.WriteLine(_ProcList.OuterXml); } private void AddItem(int parentID, ItemInfo myItemInfo) { if (myItemInfo.IsProcedure || myItemInfo.IsSection || myItemInfo.IsHigh || myItemInfo.IsRNOPart || myItemInfo.IsSequential || myItemInfo.IsNote || myItemInfo.IsCaution) { XmlElement xe = _ProcList.CreateElement(TypeName(myItemInfo)); AddAttribute(xe, "ItemID", myItemInfo.ItemID); AddAttribute(xe, "ParentID", parentID); if (myItemInfo.IsProcedure || myItemInfo.IsSection) AddAttribute(xe, "Number", myItemInfo.DisplayNumber); else AddAttribute(xe, "Number", myItemInfo.MyTab.CleanText); AddAttribute(xe, "Text", myItemInfo.DisplayText); _ProcList.DocumentElement.AppendChild(xe); if (myItemInfo.Cautions != null) foreach (StepInfo caui in myItemInfo.Cautions) AddItem(myItemInfo.ItemID, caui); if (myItemInfo.Notes != null) foreach (StepInfo noti in myItemInfo.Notes) AddItem(myItemInfo.ItemID, noti); if (myItemInfo.RNOs != null) foreach (StepInfo rnoi in myItemInfo.RNOs) AddItem(myItemInfo.ItemID, rnoi); if (myItemInfo.Sections != null) foreach (SectionInfo seci in myItemInfo.Sections) AddItem(myItemInfo.ItemID, seci); if (myItemInfo.Steps != null) { if(myItemInfo.IsSection || (myItemInfo.IsHigh && SubStepHasRNOs(myItemInfo.Steps))) foreach (StepInfo stpi in myItemInfo.Steps) AddItem(myItemInfo.ItemID, stpi); } } } private string TypeName(ItemInfo myItemInfo) { if (myItemInfo.IsProcedure) return "Procedure"; if (myItemInfo.IsSection) return "Section"; if (myItemInfo.IsHigh) return "Step"; if (myItemInfo.IsRNOPart) return "RNO"; if (myItemInfo.IsCaution) return "Caution"; if (myItemInfo.IsNote) return "Note"; return "Substep"; } private bool SubStepHasRNOs(ItemInfoList substeps) { foreach (ItemInfo ii in substeps) if (ii.RNOs != null) return true; return false; } private ItemInfo _CurrentItem = null; public ItemInfo CurrentItem { get { return _CurrentItem; } set { if (!DesignMode && value != null) // B2019-043 need to check if we are just saving changes to the user interface { _CurrentItem = value; SetupCurrentItemValues(); SetupConfigEdit(); // B2017-126 Only turn-on NamedPipe if Command Line parameter /NamedPipe is used. // This eliminates waiting for the Pipe if the command line parameter is not used. if (ExeType > 0 && Volian.Base.Library.VlnSettings.GetCommandFlag("NamedPipe")) SendPromsAnnotationData(); } } } private int _FromType; private string _ROPath; private void SetupCurrentItemValues() { _FromType = 0; if (CurrentItem.FirstSibling.ItemPartCount > 0) _FromType = CurrentItem.FirstSibling.ItemParts[0].FromType; _ROPath = ""; if (CurrentItem.MyDocVersion != null) if (CurrentItem.MyDocVersion.DocVersionAssociationCount > 0) _ROPath = CurrentItem.MyDocVersion.DocVersionAssociations[0].MyROFst.MyRODb.FolderPath; ProcItem = CurrentItem.MyProcedure; } public AnnotationInfo FirstExeAnnotation(ItemInfo ii) { if (ii == null) return null; if (ii.ItemAnnotationCount == 0) return null; foreach (AnnotationInfo ai in ii.ItemAnnotations) if (ai.TypeID == ExeType) return ai; return null; } private void SetupConfigEdit() { //if (ExeType == 0) ; // initialize ExeType } private string _ExePath; private string _PipeOut; private string _PipeIn; // Made _ExeType a lazy load to fix Jeff's (Westinghouse) request that ProcStep data be generated every time - fixes both C2016-007 and B2016-097 private int _ExeType = 0; public int ExeType { get { if (!DesignMode && _ExeType == 0) // B2019-043 need to check if we are just saving changes to the user interface { _ExeType = -1; foreach (AnnotationTypeInfo ati in AnnotationTypeInfoList.Get()) { if ((ati.Config ?? "") != "") { _ExePath = ati.AnnotationTypeConfig.Integration_Executable; _PipeIn = ati.AnnotationTypeConfig.Integration_PipeIn; _PipeOut = ati.AnnotationTypeConfig.Integration_PipeOut; if (_ExePath != "" && _PipeIn != "" && _PipeOut != "") { _ExeType = ati.TypeID; break; } } } } return _ExeType; } } private DisplaySearch _AnnotationSearch; private AnnotationInfoList _Annotations; public AnnotationInfoList Annotations { get { return _Annotations; } set { if (!DesignMode) // B2019-043 need to check if we are just saving changes to the user interface { _Annotations = value; itemAnnotationsBindingSource.DataSource = _Annotations; } } } private AnnotationInfo _CurrentAnnotation = null; public AnnotationInfo CurrentAnnotation { get { return _CurrentAnnotation; } set { if (DesignMode) return; // B2019-043 need to check if we are just saving changes to the user interface if (_CurrentAnnotation == null && value == null) return; // No Change if (_CurrentAnnotation != null && value != null) if (_CurrentAnnotation.AnnotationID == value.AnnotationID) return; // No Change //vlnStackTrace.ShowStack("CurrentAnnotation = '{0}' Old = '{1}'", value, _CurrentAnnotation); if (_CurrentAnnotation != null || _AddingAnnotation) { if (AnnotationDirty) SaveAnnotation(); } _CurrentAnnotation = value; InitializeAnnotation(); } } private bool _AnnotationDirty = false; public bool AnnotationDirty { get { return _AnnotationDirty; } set { btnRemoveAnnotation.Enabled = btnAddAnnotation.Enabled = !value; btnSaveAnnotation.Enabled = btnCancelAnnoation.Enabled = value; _AddingAnnotation = value && (CurrentAnnotation == null); _AnnotationDirty = value; } } public string AnnotationText { get { return rtxbComment.Text; } set { if (!DesignMode) // B2019-043 need to check if we are just saving changes to the user interface { rtxbComment.Text = value; if (rtxbComment.Text != string.Empty) rtxbComment.SelectionStart = rtxbComment.TextLength; // position cursor to end of text } } } public string AnnotationRTFText { get { return rtxbComment.Rtf; } set { if (!DesignMode) // B2019-043 need to check if we are just saving changes to the user interface { rtxbComment.Rtf = value; if (rtxbComment.Rtf != string.Empty) rtxbComment.SelectionStart = rtxbComment.TextLength; // position cursor to end of text } } } private UserInfo _MyUserInfo; public UserInfo MyUserInfo { get { return _MyUserInfo; } set { _MyUserInfo = value; } } #endregion #region Constructors public AnnotationDetails() { InitializeComponent(); //#if(DEBUG) //Resize+=new EventHandler(AnnotationDetails_Resize); // Debug the resize event //#endif Resize += AnnotationDetails_Resize; } void AnnotationDetails_Resize(object sender, EventArgs e) { if(Height > 0) rtxbComment.Height = Height - rtxbComment.Top; } #endregion #region Events private bool _AddingAnnotation = false; private void btnAddAnnotation_Click(object sender, EventArgs e) { dgAnnotations.ClearSelection(); CurrentAnnotation = null; _AddingAnnotation = true; rtxbComment.Focus(); } private void btnRemoveAnnotation_Click(object sender, EventArgs e) { // CSM B2024-068 / B2024-069 - check if current annotation is not selected before removal of annotation if (CurrentAnnotation != null) { //using (Annotation annotation = CurrentAnnotation.Get()) //{ // annotation.Delete(); _AnnotationSearch.LoadingList = true; Annotation.DeleteAnnotation(CurrentAnnotation); // annotation.Save(); _AnnotationSearch.LoadingList = false; CurrentAnnotation = null; UpdateAnnotationGrid(); _AnnotationSearch.UpdateAnnotationSearchResults(); // B2019-004: update search results list when an annotation is removed. //} } else { FlexibleMessageBox.Show("You Must Select an Annotation To Remove", "Annotation Not Selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } } private void btnSaveAnnotation_Click(object sender, EventArgs e) { if (cbGridAnnoType.SelectedIndex == -1) { FlexibleMessageBox.Show("You Must Select an Annotation Type", "Annotation Type Not Selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); cbGridAnnoType.Focus(); return; } if (rtxbComment.Text == string.Empty) { FlexibleMessageBox.Show("You Must Enter Annotation Text", "Annotation Text Is Blank", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); rtxbComment.Focus(); return; } SaveAnnotation(); } private void btnCancelAnnoation_Click(object sender, EventArgs e) { InitializeAnnotation(); } private void cbGridAnnoType_SelectedValueChanged(object sender, EventArgs e) { if (!_LoadingAnnotation) AnnotationDirty = true; } private void dgAnnotations_CellClick(object sender, DataGridViewCellEventArgs e) { if (!_LoadingGrid) // Only set the Current Annotation when not loading the grid { if ((_Annotations != null) && (dgAnnotations.Rows.Count > 0)) CurrentAnnotation = _Annotations[dgAnnotations.CurrentRow.Index]; else CurrentAnnotation = null; } } private void rtxbComment_TextChanged(object sender, EventArgs e) { if (!_LoadingAnnotation) AnnotationDirty = true; } #endregion #region LoadControlData public void SetupAnnotations(DisplaySearch annosrch) { _LoadingAnnotation = true; _AnnotationSearch = annosrch; // reference the Annotation Search to update its lists cbGridAnnoType.DisplayMember = "Name"; cbGridAnnoType.ValueMember = "TypeId"; cbGridAnnoType.DataSource = AnnotationTypeInfoList.Get().Clone(); // If there are no annotatons, then selected index is -1 (not defined), otherwise select the first. // This was done so that it could be saved if there was text entered but user moves to another steprtb without selecting save button // so that annotation gets saved. if (cbGridAnnoType.Items.Count == 0) cbGridAnnoType.SelectedIndex = -1; else cbGridAnnoType.SelectedIndex = 0; _LoadingAnnotation = false; } private void InitializeAnnotation() { //vlnCSLAStackTrace.ShowStack("InitializeAnnotation - CurrentAnnotation = {0}", CurrentAnnotation); _LoadingAnnotation = true; if (CurrentAnnotation == null) { if (cbGridAnnoType.Items.Count == 0) // see comment for SetupAnnotations cbGridAnnoType.SelectedIndex = -1; else cbGridAnnoType.SelectedIndex = 0; AnnotationText = ""; } else { cbGridAnnoType.SelectedValue = CurrentAnnotation.TypeID; if (CurrentAnnotation.RtfText != "") AnnotationRTFText = CurrentAnnotation.RtfText; else AnnotationText = CurrentAnnotation.SearchText; } _LoadingAnnotation = false; AnnotationDirty = false; if (!rtxbComment.Visible) rtxbComment.Visible = true; if (!_LoadingGrid) rtxbComment.Focus(); // Set the focus to the comment text // Bug Fix: B2016-274 if admin user also has reviewer set, allow admin user to modify existing annotations if (CurrentAnnotation != null && (!(MyUserInfo.IsAdministrator() || MyUserInfo.IsSetAdministrator(CurrentAnnotation.MyItem.MyDocVersion)) && (MyUserInfo.IsReviewer(CurrentAnnotation.MyItem.MyDocVersion ) && CurrentAnnotation.UserID != MyUserInfo.UserID))) { btnRemoveAnnotation.Enabled = false; cbGridAnnoType.Enabled = false; rtxbComment.Enabled = false; } else { btnRemoveAnnotation.Enabled = true; cbGridAnnoType.Enabled = true; rtxbComment.Enabled = true; } } private void CheckClientProcess() { if (ClientProcess.HasExited) { ClientProcess = null; StartClientProcess(); } } void ClientProcess_Exited(object sender, EventArgs e) { ClientProcess = null; } private Process _ClientProcess; public Process ClientProcess { get { if (_ClientProcess == null) { StartClientProcess(); } return _ClientProcess; } set { _ClientProcess = value; } } private void StartClientProcess() { if (_ExePath != null) // B2019-043 if we are just saving changes to the user interface don't do anything { _ClientProcess = Process.Start(_ExePath); _ClientProcess.WaitForInputIdle(); _ClientProcess.Exited += ClientProcess_Exited; } } private void SendPromsAnnotationData() { //Console.WriteLine("Send {0}", CurrentItem); XmlDocument xdMessage = new XmlDocument(); xdMessage.LoadXml(""); // Add Steps Data if(_ProcList != null) { xdMessage.DocumentElement.AppendChild(xdMessage.ImportNode(_ProcList.DocumentElement, true)); _ProcList = null; } // Add Config Data AnnotationInfo ai = FirstExeAnnotation(CurrentItem); if (ai != null && ai.Config.Length > 0) { XmlDocument xdConfig = new XmlDocument(); xdConfig.LoadXml(ai.Config); ProcedureInfo currentProc = CurrentItem.MyProcedure; XmlNode nd = xdMessage.DocumentElement.SelectSingleNode("//PromsAnnotationConfig"); nd.AppendChild(xdMessage.ImportNode(xdConfig.DocumentElement, true)); } // Add Local Info AddAttribute(xdMessage.DocumentElement, "ItemID", CurrentItem.ItemID); AddAttribute(xdMessage.DocumentElement, "ROPath", _ROPath); AddAttribute(xdMessage.DocumentElement, "FromType", _FromType); AddAttribute(xdMessage.DocumentElement, "Type", CurrentItem.MyContent.Type); PipeToClient.Send(xdMessage.OuterXml); PipeFromClient.Listen(); } private void AddAttribute(XmlElement xe, string name, object value) { XmlAttribute xa = xe.OwnerDocument.CreateAttribute(name); xa.Value= value.ToString(); xe.Attributes.Append(xa); } private PipeClient _PipeToClient; public PipeClient PipeToClient { get { if (_PipeToClient == null) _PipeToClient = new PipeClient(_PipeOut); return _PipeToClient; } } private PipeServer _PipeFromClient; public PipeServer PipeFromClient { get { if (_PipeFromClient == null) { _PipeFromClient = new PipeServer(_PipeIn); _PipeFromClient.PipeMessage += PipesMessageHandler; } return _PipeFromClient; } } void PipesMessageHandler(string message) { try { if (this.InvokeRequired) { this.Invoke(new NewMessageDelegate(PipesMessageHandler), message); } else { ProcessMessage(message); } } catch (Exception ex) { PipesMessageHandler(string.Format("{0} - {1}", ex.GetType().FullName, ex.Message)); } } private void ProcessMessage(string message) { //Console.WriteLine(message); XmlDocument xd = new XmlDocument(); xd.LoadXml(message); string Mode = GetAttribute(xd, "ClientToProms", "Mode"); switch (Mode) { case "SaveAnnotationConfig": // Get the AnnotationID int itemID = GetAttributeInt(xd,"ClientToProms","ItemID"); // Get the Config string config = GetNode(xd,"PromsAnnotationConfig").InnerXml; // Save updated Config Value AnnotationInfo ai = FirstExeAnnotation(ItemInfo.Get(itemID)); if(ai != null) // Update existing Annotation using(Annotation aa = Annotation.Get(ai.AnnotationID)) { if (config == "") { Annotation.DeleteAnnotation(ai); UpdateAnnotationGrid(); } else { aa.Config = config; aa.DTS = DateTime.Now; aa.UserID = Volian.Base.Library.VlnSettings.UserID; aa.Save(); AnnotationInfo.Refresh(aa); UpdateAnnotationGrid(); } } else // Add a new Annotation { if (config != "") { using (Item myItem = Item.Get(itemID)) { using (AnnotationType myType = AnnotationType.Get(ExeType)) { using (Annotation annotation = Annotation.MakeAnnotation(myItem, myType, null, "New", config)) { annotation.Save(); UpdateAnnotationGrid(); } } } } } break; default: Console.WriteLine("Unknown Message Type {0}", Mode); break; } } private XmlNode GetNode(XmlDocument xd, string nodeName) { return xd.DocumentElement.SelectSingleNode("//" + nodeName); } private string GetAttribute(XmlDocument xd, string nodeName, string attrName) { return GetNode(xd,nodeName).Attributes[attrName].Value; } private int GetAttributeInt(XmlDocument xd, string nodeName, string attrName) { return int.Parse(GetAttribute(xd, nodeName, attrName)); } #endregion #region VariousSupportMethods /// /// Set up the Annotation Grid for the given item /// This is called from frmVEPROMS /// /// public void UpdateAnnotationGrid(ItemInfo currentitem) { CurrentItem = currentitem; UpdateAnnotationGrid(); } private void UpdateAnnotationGrid() { _LoadingGrid = true; if (CurrentItem == null) _Annotations= null; else { CurrentItem.RefreshItemAnnotations(); _Annotations = CurrentItem.ItemAnnotations; } itemAnnotationsBindingSource.DataSource = _Annotations; dgAnnotations.Refresh(); if ((CurrentAnnotation == null || (CurrentItem.ItemID != CurrentAnnotation.ItemID))) { if (_Annotations != null && _Annotations.Count > 0) CurrentAnnotation = _Annotations[0]; else CurrentAnnotation = null; } FindCurrentAnnotation(); // position to the grid row of the current annotation _LoadingGrid = false; if (_Annotations == null || _Annotations.Count == 0) btnRemoveAnnotation.Enabled = false; } /// /// Find the Current Annotation in the Annotation Grid select the corresponding row /// Note: this is also called from AnnotationSearch.cs when a search results is selected /// public void FindCurrentAnnotation() { int row = 0; if (CurrentAnnotation != null) { if (_Annotations != null) { foreach (AnnotationInfo ai in _Annotations) { if (ai.AnnotationID == CurrentAnnotation.AnnotationID) { row = _Annotations.IndexOf(ai);// +1; break; } } try { dgAnnotations.Rows[row].Selected = true; if (!_LoadingGrid && (dgAnnotations.FirstDisplayedScrollingRowIndex != -1)) dgAnnotations.FirstDisplayedScrollingRowIndex = row; } catch (Exception ex) { _MyLog.InfoFormat("Trying to open an annotation which has been removed"); } } } } public void SaveAnnotation() { if (cbGridAnnoType.SelectedIndex == -1) return; if (rtxbComment.Text == string.Empty) return; using (AnnotationType annotationType = AnnotationType.Get((int)cbGridAnnoType.SelectedValue)) { if (_AddingAnnotation) { _AddingAnnotation = false; using (Item myItem = CurrentItem.Get()) { using (Annotation annotation = Annotation.MakeAnnotation(myItem, annotationType, rtxbComment.Rtf, rtxbComment.Text, "")) { CurrentAnnotation = AnnotationInfo.Get(annotation.AnnotationID); //annotation.DTS = DateTime.Now; //annotation.Save(); } } } else { using (Annotation annotation = CurrentAnnotation.Get()) { if (annotation != null) // B2024-061 check for null reference { annotation.RtfText = rtxbComment.Rtf; annotation.SearchText = rtxbComment.Text; annotation.MyAnnotationType = annotationType; annotation.DTS = DateTime.Now; annotation.UserID = Volian.Base.Library.VlnSettings.UserID; annotation.Save(); } } } } AnnotationDirty = false; UpdateAnnotationGrid(); AnnotationTypeInfoList.Reset(); // B2018-135: refresh annotation type list to update when annotations are used. } #endregion } }