using System; using System.Collections.Generic; using System.Drawing; using System.Text; using System.Windows.Forms; using VEPROMS.CSLA.Library; using System.IO; using Volian.Controls.Library; using DevComponents.DotNetBar; using JR.Utils.GUI.Forms; using System.Linq; namespace VEPROMS { public partial class frmBatchRefresh : Form { private SessionInfo _MySessionInfo; public SessionInfo MySessionInfo { get { return _MySessionInfo; } set { _MySessionInfo = value; } } private bool IsAdministratorUser = false; //C2020-035 used to control what Set Amins can do // C2017-030 - new Admin Tools user interface // pass in session info to constructor private frmVEPROMS _veProms; public frmBatchRefresh(SessionInfo sessionInfo, frmVEPROMS veProms) { InitializeComponent(); _MySessionInfo = sessionInfo; _veProms = veProms; // When opening Admin tools Check tab will be default. this.sideNavItmCheck.Checked = true; if (sideNavItmDelete.Checked) { AdminToolType = (E_AdminToolType)4; if (swDeleteFolder.Value) { ResetDelTV(true); setupProgessSteps1(); } else ResetDelTV(false); } setupProgessSteps1(); // C2017-030 - new Admin Tools user interface UserInfo ui = UserInfo.GetByUserID(MySessionInfo.UserID); IsAdministratorUser = ui.IsAdministrator(); if (!IsAdministratorUser) { //C2020-035 if not full Admin disable repair tools // only full Admin users can run the repair tools btnRunRepair.Enabled = false; swRmObsoleteROData.Enabled = false; swRmOrphanDataRecs.Enabled = false; swRefreshWordAttmts.Enabled = false; swStandardHypenChars.Enabled = false; } } // Make txtProcess text box available to frmAnnotationsClean form. internal TextBox GettxtProcess() { return txtProcess; } // Make txtResults text box available to frmAnnotationsClean form. internal TextBox GettxtResults() { return txtResults; } // NOTE: removed the Refresh ROs and Refresh Transitions and ROs options (now only Transitions can be refreshed) // the Update ROs and Refresh ROs logic was merged together. The Update ROs will functionally do both // also annotations will be placed on step elements that have RO changes // make all of the hyphen character consistant so they can all be found with the Search function private void FixHyphens() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Standardizing Hyphens"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int affectedRows = ESP_FixHyphens.Execute("vesp_FixHyphens") / 2;// Two results for each change txtProcess.AppendText(string.Format("Fixed {0} Hyphens", affectedRows)); txtProcess.AppendText(Environment.NewLine); //txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("{0} Hyphens were Fixed.", affectedRows)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } private Dictionary myProcedures = new Dictionary(); private Dictionary myDocVersions = new Dictionary(); private Dictionary myFolders = new Dictionary(); private void frmBatchRefresh_Load(object sender, EventArgs e) { IsClosing = false;//B2017-221 Allow the batch dialog to close when waiting to process. } private bool IsClosing = false;//B2017-221 Allow the batch dialog to close when waiting to process. private void frmBatchRefresh_FormClosing(object sender, EventArgs e) { IsClosing = true;//B2017-221 Allow the batch dialog to close when waiting to process. } // C2017-030 - new Admin Tools user interface // check to see if at least one tree node is checked. // Used to determin whether to make the process button active for // Refresh Transitions and for Update RO Values // B2025-013 Admin Tool Tree Behavior //Made this generic so same logic for all the TreeViews on this form private bool AtLeastOneNodeChecked(TreeNodeCollection col) { foreach (TreeNode tn in col) if (NodeIsChecked(tn)) return true; return false; } private bool NodeIsChecked(TreeNode tn) { if (tn.Checked) return true; if (tn.GetNodeCount(true) > 0) foreach (TreeNode chnd in tn.Nodes) if (NodeIsChecked(chnd)) return true; return false; } private List myTreeNodePath; private void ResetTV() { ResetTV(false); } private void ResetTV(bool noProcs) { btnFixLinks.Enabled = false; this.Cursor = Cursors.WaitCursor; //myTreeNodePath = new List(); myTV.Nodes.Clear(); myDocVersions.Clear(); myFolders.Clear(); FolderInfo fi = FolderInfo.GetTop(); TreeNode tn = myTV.Nodes.Add(fi.Name); tn.Tag = fi; if (fi.ChildFolderCount > 0) LoadChildFolders(fi, tn, noProcs); if (myTV.SelectedNode != null) myTV.SelectedNode.Expand(); this.Cursor = Cursors.Default; } private void ResetDelTV() { ResetDelTV(false); } private void ResetDelTV(bool noProcs) { btnFixLinks.Enabled = false; this.Cursor = Cursors.WaitCursor; myTVdel.Nodes.Clear(); myDocVersions.Clear(); FolderInfo fi = FolderInfo.GetTop(); fi.RefreshChildFolders(); if (fi.ChildFolderCount > 0) { TreeNode tn = new TreeNode(fi.Name); tn.Tag = fi; tn.StateImageIndex = -1; // Hide the checkbox for the root node LoadChildFolders(fi, tn, noProcs); myTVdel.Nodes.Add(tn); } if (myTVdel.SelectedNode != null) myTVdel.SelectedNode.Expand(); //Expand if folders if (noProcs) myTVdel.ExpandAll(); this.Cursor = Cursors.Default; } // B2021-060 Higher level folders where being removed from the tree even if there was a child folder that containe a working draft set private bool LoadChildFolders(FolderInfo fi, TreeNode tn, bool noProcs) { bool loadedWorkingDraft = false; bool loadedChildWorkingDraft = false; // B2021-060 flag when child folder working draft is loaded foreach (FolderInfo fic in fi.SortedChildFolders) { TreeNode tnc = tn.Nodes.Add(fic.Name); tnc.Tag = fic; if (fic.ChildFolderCount > 0) { if (LoadChildFolders(fic, tnc, noProcs)) loadedChildWorkingDraft = true; } if (fic.FolderDocVersionCount > 0) { if (!LoadDocVersions(fic, tnc, noProcs)) tnc.Remove(); else loadedWorkingDraft = true; } else { // Add the folder to the dictionary if (!myFolders.ContainsKey(tnc)) myFolders.Add(tnc, fic); } } if (loadedChildWorkingDraft) { loadedWorkingDraft = true; } if (tn.Parent != null && !loadedWorkingDraft && fi.FolderDocVersionCount == 0) { tn.Remove(); } return loadedWorkingDraft; } private bool LoadDocVersions(FolderInfo fic, TreeNode tnc, bool noProcs) { bool rtnval = false; foreach (DocVersionInfo dvi in fic.FolderDocVersions) { UserInfo ui = UserInfo.GetByUserID(MySessionInfo.UserID); if (ui.IsAdministrator() || ui.IsSetAdministrator(dvi)) { tnc.Tag = dvi; myDocVersions.Add(tnc, dvi); if (!noProcs) { if (dvi.Procedures.Count > 0) LoadProcedures(dvi, tnc); } rtnval = true; } else { if (tnc != null && tnc.Text != "VEPROMS") // B2020-114 - mad if statement removed: && !IsUsedPath(tnc.FullPath)) { TreeNode tmp = tnc.Parent; tnc.Remove(); tnc = tmp; } } } return rtnval; } private void LoadProcedures(DocVersionInfo dvi, TreeNode tnc) { foreach (ProcedureInfo pi in dvi.Procedures) { TreeNode tn = tnc.Nodes.Add(string.Format("{0} {1}", pi.DisplayNumber, pi.DisplayText)); myProcedures.Add(tn, pi); tn.Tag = pi; } } private void LoadFolderInfo(FolderInfo f) { TreeNode tn = myTV.Nodes.Add(f.Name); tn.Tag = f; if (f.ChildFolderCount > 0) foreach (FolderInfo cf in f.SortedChildFolders) LoadFolderInfo(cf); } private void UpdateROValues() { this.Cursor = Cursors.WaitCursor; List pil = new List(); // C2023-002: list of checked out procedures, used in frmBatchRefreshCheckedOut dialog List dvil = new List(); foreach (TreeNode tn in myDocVersions.Keys) if (tn.Checked) dvil.Add(myDocVersions[tn]); DateTime pStart = DateTime.Now; txtProcess.AppendText("Update RO Values"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(pStart.ToString("MM/dd/yyyy @ HH:mm")); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); pbProcess.Minimum = 0; pbProcess.Maximum = dvil.Count; pbProcess.Step = 1; bool cancelledOut = false; // C2023-002: flags cancel out of frmBatchRefreshCheckedOut so that looping can end while (dvil.Count > 0 && !cancelledOut) { StringBuilder sbDocVersions = new StringBuilder(); Queue dviq = new Queue(); foreach (DocVersionInfo dvi in dvil) dviq.Enqueue(dvi); dvil.Clear(); // if we are processing more than one procedure set, use MessageList to hold the summary results for each set if (dviq.Count > 1) ROFstInfo.MessageList = new StringBuilder(); while (dviq.Count > 0) { string msg = string.Empty; DocVersionInfo dq = dviq.Dequeue(); if (!MySessionInfo.CanCheckOutItem(dq.VersionID, CheckOutType.DocVersion, ref msg)) { dvil.Add(dq); // C2023-002: Loop through the docversion's procedures to determine which cannot be open and add to // list. The frmBatchRefreshCheckedOut dialog operates on procedures, not docversions. string msgp = string.Empty; foreach (ProcedureInfo pi in dq.Procedures) { if (!MySessionInfo.CanCheckOutItem(pi.ItemID, CheckOutType.Procedure, ref msgp)) pil.Add(pi); } sbDocVersions.AppendLine(msg); } else { ContentInfo.StaticContentInfoChange += new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); ProcessUpdateROValues(dq); ContentInfo.StaticContentInfoChange -= new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); pbProcess.PerformStep(); Application.DoEvents(); } ClearCache(); } Application.DoEvents(); // when processing more than one procedure set, display only one completed message after all are processed if (ROFstInfo.MessageList != null) { FlexibleMessageBox.Show(ROFstInfo.MessageList.ToString(), "RO Update Complete"); ROFstInfo.MessageList = null; } if (dvil.Count > 0) { StringBuilder sb = new StringBuilder(); sb.AppendLine("The batch update process was not successful for all working drafts selected."); sb.AppendLine("The following working drafts were not able to be refreshed..."); sb.AppendLine(); sb.AppendLine(sbDocVersions.ToString()); sb.AppendLine(); sb.AppendLine("If you want to update these working drafts, please contact the respective users and have them close any procedures in the working draft."); sb.AppendLine("Once this is complete you can continue the process otherwise you may terminate the process immediately."); sb.AppendLine(); sb.AppendLine("Have you requested the users to close the procedures and do you want to continue the process?"); frmBatchRefreshCheckedOut frmCO = new frmBatchRefreshCheckedOut(1); frmCO.MySessionInfo = MySessionInfo; frmCO.CheckedOutProcedures = pil; // C2023-002: set list of checked out procedures frmCO.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - frmCO.Width, Screen.PrimaryScreen.WorkingArea.Height - frmCO.Height); // C2023-002: Allow close of dialog that has list of procedures that are checked out if (frmCO.ShowDialog(this) != DialogResult.Cancel) { while (!this.Visible) Application.DoEvents(); } else cancelledOut = true; } } DateTime pEnd = DateTime.Now; // C2023-002: Message depending on whether ro.fst update is completed. if (!cancelledOut) txtProcess.AppendText(string.Format("Completed: {0} {1} Seconds Elapsed", pEnd.ToString("MM/dd/yyyy @ HH:mm"), TimeSpan.FromTicks(pEnd.Ticks - pStart.Ticks).TotalSeconds)); else { txtProcess.AppendText(string.Format("Could Not Complete: {0} {1} Seconds Elapsed", pEnd.ToString("MM/dd/yyyy @ HH:mm"), TimeSpan.FromTicks(pEnd.Ticks - pStart.Ticks).TotalSeconds)); pbProcess.Value = pbProcess.Maximum; } this.Cursor = Cursors.Default; } //C2025-011 RO Update Admin Tool Memory Enhancements //Clear what we can from the cache //runs after each section private void ClearCache() { txtProcess.AppendText("Reclaiming memory used during previous sections."); PartInfo.ClearPartInfoCache(); ItemInfo.ClearItemInfoCache(); Item.ClearItemCache(); ContentInfo.ClearContentInfoCache(); GridInfo.ClearGridInfoCache(); GC.Collect(); GC.WaitForPendingFinalizers(); } //C2022-028 check for Bad RO Links - we will check all of the RO links found in procedure step text //B2022-144 Allow to check individual procedures for bad RO links private void CheckROLinks() { bool badLinksFound = false; this.Cursor = Cursors.WaitCursor; List pil = new List(); // populate a list of procedures that the user selected to process foreach (TreeNode tn in myProcedures.Keys) if (tn.Checked) pil.Add(myProcedures[tn]); DateTime pStart = DateTime.Now; txtProcess.AppendText("Check RO Links"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(pStart.ToString("MM/dd/yyyy @ HH:mm")); txtProcess.AppendText(Environment.NewLine); txtResults.Clear(); Application.DoEvents(); pbProcess.Minimum = 0; pbProcess.Maximum = pil.Count; pbProcess.Step = 1; int i = 0; while (pil.Count > 0) { StringBuilder sbProcs = new StringBuilder(); // Put the list of procedures in a queue Queue piq = new Queue(); foreach (ProcedureInfo pi in pil) piq.Enqueue(pi); pil.Clear(); string prevStatMsgSet = string.Empty; string statmsgproc = string.Empty; while (piq.Count > 0) { string msg = string.Empty; ProcedureInfo pq = piq.Dequeue(); // get next procedure from queue if (!MySessionInfo.CanCheckOutItem(pq.ItemID, CheckOutType.Procedure, ref msg)) { pil.Add(pq); // cannot open this procedure to process - save to a list of un-processed procedures sbProcs.AppendLine(msg); } else { string statmsgset = string.Format("Check ROs Links in Procedure Set \"{0}\"", pq.MyDocVersion.MyFolder.Name); if (statmsgset != prevStatMsgSet) { txtResults.AppendText(statmsgset); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); prevStatMsgSet = statmsgset; } ProcedureInfo.ResetCheckROLinkCounters(); DoProgressBarRefresh(++i, piq.Count, string.Format("{0} ({1}/{2} ROs)", pq.DisplayNumber, i, piq.Count)); ContentInfo.StaticContentInfoChange += new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); statmsgproc = string.Format(" Checking Procedure {0}", pq.DisplayNumber); txtResults.AppendText(statmsgproc); txtResults.AppendText(Environment.NewLine); int numBadROLinks = ROFstInfo.CheckROLinksInThisProcedure(pq, txtProcess); // check the procedure for bad RO links badLinksFound |= (numBadROLinks > 0); string smsg = (numBadROLinks > 0) ? string.Format(" {0} Bad RO Link(s) Found", numBadROLinks) : " No Bad RO Links Found"; txtResults.AppendText(smsg); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); ContentInfo.StaticContentInfoChange -= new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); pbProcess.PerformStep(); Application.DoEvents(); } } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0} {1} Seconds Elapsed", pEnd.ToString("MM/dd/yyyy @ HH:mm"), TimeSpan.FromTicks(pEnd.Ticks - pStart.Ticks).TotalSeconds)); Application.DoEvents(); // display a completed message after all are processed if (badLinksFound) FlexibleMessageBox.Show("Bad RO links were detected.\n\nSearch for the Annotation type 'Bad RO Link'\nto locate and fix the bad RO links", "Check RO Links Complete"); else FlexibleMessageBox.Show("No Bad RO links were detected.", "Check RO Links Complete"); ROFstInfo.MessageList = null; if (piq.Count > 0) { frmBatchRefreshCheckedOut frmCO = new frmBatchRefreshCheckedOut(0); frmCO.MySessionInfo = MySessionInfo; frmCO.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - frmCO.Width, Screen.PrimaryScreen.WorkingArea.Height - frmCO.Height); frmCO.Show(this); while (!this.Visible) Application.DoEvents(); } } this.Cursor = Cursors.Default; } // B2018-002 - Invalid Transitions - Define Transition Refresh Statistics private int numTransProcessed = 0; private int numTransFixed = 0; private int numTransCantFix = 0; private int numTransConverted = 0; // B2018-002 - Invalid Transitions - Initialize Transition Refresh Statistics private void ResetTransNumbers() { numTransProcessed = 0; numTransFixed = 0; numTransCantFix = 0; numTransConverted = 0; } private void RefreshTransitions() { // B2018-002 - Invalid Transitions - Initialize Transition Refresh Statistics ResetTransNumbers(); this.Cursor = Cursors.WaitCursor; List pil = new List(); foreach (TreeNode tn in myProcedures.Keys) if (tn.Checked) pil.Add(myProcedures[tn]); //PopulateTransitionInfoLists(pil); DateTime pStart = DateTime.Now; txtProcess.AppendText("Refresh Transitions"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText("Refresh Transitions"); txtResults.AppendText(Environment.NewLine); Application.DoEvents(); pbProcess.Minimum = 0; pbProcess.Maximum = pil.Count; pbProcess.Step = 1; while (pil.Count > 0) { ContentInfo.StaticContentInfoChange += new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); StringBuilder sbProcs = new StringBuilder(); Queue piq = new Queue(); foreach (ProcedureInfo pi in pil) piq.Enqueue(pi); pil.Clear(); while (piq.Count > 0) { string msg = string.Empty; ProcedureInfo pq = piq.Dequeue(); if (!MySessionInfo.CanCheckOutItem(pq.ItemID, CheckOutType.Procedure, ref msg)) { pil.Add(pq); sbProcs.AppendLine(msg); } else { myFixes = new StringBuilder(); RefreshProcedureTransitions(pq); // B2018-002 - Invalid Transitions - Update Transition Refresh Statistics numTransConverted += ProcedureInfo.TranConvertCount; numTransProcessed += ProcedureInfo.TranCheckCount; numTransFixed += ProcedureInfo.TranFixCount; numTransCantFix += ProcedureInfo.TranCantFixCount; //Bad Transition Link pbProcess.PerformStep(); Application.DoEvents(); } } if (numTransFixed == 0 && numTransConverted == 0 && numTransCantFix == 0) { txtResults.AppendText("No Transitions Needed Updated."); txtResults.AppendText(Environment.NewLine); } ContentInfo.StaticContentInfoChange -= new StaticContentInfoEvent(ContentInfo_StaticContentInfoChange); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Transitions Checked: {0}", numTransProcessed)); txtProcess.AppendText(Environment.NewLine); // B2018-002 - Invalid Transitions - Display Transition Refresh Statistics txtProcess.AppendText(string.Format("Transitions Correct As Is: {0}", numTransProcessed - (numTransConverted + numTransFixed + numTransCantFix))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Transitions Modified: {0}", numTransFixed)); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Transitions Converted to text: {0}", numTransConverted)); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Transitions Unable to be Automatically Fixed (Annotation: Bad Transition Link): {0}", numTransCantFix)); Application.DoEvents(); if (pil.Count > 0) { StringBuilder sb = new StringBuilder(); sb.AppendLine("The batch refresh process was not successful for all procedures selected."); sb.AppendLine("The following procedures were not able to be refreshed..."); sb.AppendLine(); sb.AppendLine(sbProcs.ToString()); sb.AppendLine(); sb.AppendLine("If you want to refresh these prcoedures, please contact the respective users and have them close the procedures."); sb.AppendLine("Once this is complete you can continue the process otherwise you may terminate the process immediately."); sb.AppendLine(); sb.AppendLine("Have you requested the users to close the procedures and do you want to continue the process?"); frmBatchRefreshCheckedOut frmCO = new frmBatchRefreshCheckedOut(0); frmCO.MySessionInfo = MySessionInfo; frmCO.CheckedOutProcedures = pil; frmCO.Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - frmCO.Width, Screen.PrimaryScreen.WorkingArea.Height - frmCO.Height); frmCO.Show(this); while (!this.Visible) Application.DoEvents(); } } this.Cursor = Cursors.Default; // B2018-002 - Invalid Transitions - Display Transition Refresh Statistic if (numTransFixed == 0 && numTransConverted == 0 && numTransCantFix == 0) MessageBox.Show(string.Format("{0} Transitions Checked.\n\nNo Transitions Modified.", numTransProcessed), "Refresh Transitions Completed"); else MessageBox.Show(string.Format("{0} Transitions Checked.\n\n {1} Correct as is.\n\n {2} Transitions modified.\n\n {3} Transitions converted to text.\n\n {4} Transitions unable to be automatically fixed (Annotation: Bad Transition Link).", numTransProcessed, numTransProcessed - (numTransFixed + numTransConverted + numTransCantFix), numTransFixed, numTransConverted, numTransCantFix), "Refresh Transitions Completed"); } // C2017-030 - new Admin Tools user interface // tool renamed to Refresh Word Attachments // removes the saved attachment PDFs from the database to force PROMS to regenerate them // the next time the procedures are printed. This also forces ROs to be refreshed in the attachments private void DeletePDFs() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Refreshing Word Attachments"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int affectedRows = ESP_DeletePDFs.Execute("vesp_DeletePDFs"); txtProcess.AppendText(string.Format("Word Attachments Refreshed: {0}", affectedRows)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("{0} Word Attachments Refreshed.", affectedRows)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // B2022-047 - refresh the Content/Text field for table, i.e. Grid, Data so that search will find text in the Grid // NOTE that an out of memeory error occurs when having to process alot of tables. A config flag is used on the // grid record to flag that this operation has been run. And a message is placed in the result window stating to // rerun until all tables/text fields are completed. private void RefreshTablesForSearch() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Refreshing Tables for Search"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int affectedRows = RefreshForSearch(); if (affectedRows < 0) { txtProcess.AppendText(string.Format("Error occurred in processing, completed {0} rows. Run again!", -affectedRows)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("Error occurred in processing, completed {0} rows. Run again!", -affectedRows)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); affectedRows = -affectedRows; } txtProcess.AppendText(string.Format("Tables for Search Refreshed: {0}", affectedRows)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("{0} Tables for Search Refreshed.", affectedRows)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } private int RefreshForSearch() { int cntfix = 0; List gids = GridInfoList.GetIds(); // get all grids in database pbProcess.Minimum = 0; pbProcess.Maximum = gids.Count; pbProcess.Step = 1; foreach (int cid in gids) { using (Content cc = Content.Get(cid)) { StepConfig sc = new StepConfig(cc.Config); if (!sc.Step_FixedTblForSrch) // if not processed through this code already, get searchable text & save { try { using (VlnFlexGrid MyFlexGrid = new VlnFlexGrid(cc.ContentItems[0])) { using (StringReader sr = new StringReader(cc.MyGrid.Data)) { MyFlexGrid.ReadXml(sr); sr.Close(); } string srchtxt = MyFlexGrid.GetSearchableText(); if (cc.Text != srchtxt) { cntfix++; cc.UserID = Volian.Base.Library.VlnSettings.UserID; cc.DTS = DateTime.Now; cc.Text = srchtxt; } sc.Step_FixedTblForSrch = true; cc.Config = sc.ToString(); cc.Save(); } } catch (Exception ex) { this.Cursor = Cursors.Default; return -cntfix; } } pbProcess.PerformStep(); Application.DoEvents(); } } return cntfix; } // C2017-030 - new Admin Tools user interface // tool renamed to Identify Orphan Items private void IdentifyDisconnectedItems() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Identifing Orphan Items"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCount = ESP_IdentifyDisconnectedItems.Execute("vesp_GetDisconnectedItemsCount"); txtProcess.AppendText(string.Format("Orphan Items Count: {0}", rowCount)); txtProcess.AppendText(Environment.NewLine); if (rowCount > 0) { txtResults.AppendText(string.Format("The database contains {0} Orphan items.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText("These can be removed via the Remove Orphan Data Records in the Repair tools"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } else { txtResults.AppendText("No Orphan Records Found");// B2017-108 Always output results even if there isn't any txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; //MessageBox.Show(string.Format("{0} Completed", "Orphan Items Check"), "Orphan Items"); } // C2017-030 - new Admin Tools user interface // tool renamed to Remove Orphan Items private void PurgeDisconnectedItems() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Purging Orphan Items"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCount = ESP_IdentifyDisconnectedItems.Execute("vesp_GetDisconnectedItemsCount"); if (rowCount > 0) { ESP_PurgeDisconnectedItems.Execute("vesp_PurgeDisconnectedData"); int rowCount2 = ESP_IdentifyDisconnectedItems.Execute("vesp_GetDisconnectedItemsCount"); txtProcess.AppendText(string.Format("Orphan Items Purged: {0}", rowCount)); txtProcess.AppendText(Environment.NewLine); //txtProcess.AppendText(Environment.NewLine); //txtResults.Clear(); txtResults.AppendText(string.Format("The database contained {0} Orphan items.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database now contains {0} Orphan items.", rowCount2)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); if (rowCount2 > 0) { txtResults.AppendText("** Some or all Orphan items could not be purged.**"); txtResults.AppendText("** It is recommended you contact Volian to assist in resolving this condition.**"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } } else { //txtResults.Clear(); txtResults.AppendText(string.Format("The database contained {0} Orphan items.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("No Orpan Items to Purge!")); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface // is one of two tools run from Check Obsolete RO Data private void IdentifyUnusedRoFstsAndFigures() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Identifing Unused RoFsts and Figures"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCountRoFst = ESP_GetUnusedRoFsts.Execute("vesp_GetUnusedRoFstsCount"); int rowCountFigures = ESP_GetUnusedFigures.Execute("vesp_GetUnusedFiguresCount"); txtProcess.AppendText(string.Format("Unused RoFsts Count: {0}, Unused Figures Count: {1}", rowCountRoFst, rowCountFigures)); txtProcess.AppendText(Environment.NewLine); if (rowCountRoFst > 0 || rowCountFigures > 0) { txtResults.AppendText(string.Format("The database contains {0} unused RoFsts.", rowCountRoFst)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database contains {0} unused Figures items.", rowCountFigures)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } else { txtResults.AppendText("No Unused RoFsts or Figures Found"); // B2017-108 Always output results even if there isn't any txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface is one of two tools run from Remove Obsolete RO Data private void RemoveUnusedRoFstsAndFigures() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Purging Unused RoFSTs and Figures Items"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCountRoFst = ESP_GetUnusedRoFsts.Execute("vesp_GetUnusedRoFstsCount"); int rowCountFigures = ESP_GetUnusedFigures.Execute("vesp_GetUnusedFiguresCount"); if (rowCountRoFst > 0 || rowCountFigures > 0) { ESP_PurgeUnusedRoFstsAndFigures.Execute("vesp_RemoveUnusedRoFstsAndFigures"); int rowCountRoFst2 = ESP_GetUnusedRoFsts.Execute("vesp_GetUnusedRoFstsCount"); int rowCountFigures2 = ESP_GetUnusedFigures.Execute("vesp_GetUnusedFiguresCount"); txtProcess.AppendText(string.Format("{0} Unsed ROFSTs Purged", rowCountRoFst)); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("{0} Unsed Figures Purged", rowCountFigures)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database contained {0} unused ROFSTs.", rowCountRoFst)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database contained {0} unused Figures items.", rowCountFigures)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database now contains {0} unused ROFSTs.", rowCountRoFst2)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database now contains {0} unused Figures.", rowCountFigures2)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); if (rowCountRoFst2 > 0 || rowCountFigures2 > 0) { txtResults.AppendText("** Could not purge all or some of the unsed ROFSTs and Figures.** "); txtResults.AppendText("** It is recommended you contact Volian to assist in resolving this condition. **"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } } else { txtProcess.AppendText(string.Format("The database contained {0} unused RoFSTs or Figures.", rowCountRoFst + rowCountFigures)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("No Unused ROFSTs To Remove.")); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface // is one of two tools run from Check Obsolete RO Data private void IdentifyROAssociations() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Identifing Unused RO Associations"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCount = ESP_GetROAssoc.Execute("vesp_GetUnusedROAssociationsCount"); txtProcess.AppendText(string.Format("Unused RO Associations Count: {0}", rowCount)); txtProcess.AppendText(Environment.NewLine); if (rowCount > 0) { txtResults.AppendText(string.Format("The database contains {0} unused RO Associations.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } else { txtResults.AppendText("No unused RO Associations Found");// B2017-108 Always output results even if there isn't any txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface // is one of two tools run from Remove Obsolete RO Data private void CleanUpROAssociations() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Purging Unused Referenced Object Associations"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); int rowCount = ESP_GetROAssoc.Execute("vesp_GetUnusedROAssociationsCount"); if (rowCount > 0) { ESP_CleanupROAssoc.Execute("vesp_GetUnusedROAssociationsCount"); int rowCount2 = ESP_GetROAssoc.Execute("vesp_GetUnusedROAssociationsCount"); txtProcess.AppendText(string.Format("{0} Unused Referenced Object Associations Purged", rowCount)); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database contained {0} Unused RO Associations.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("The database now contains {0} Unused RO Associations.", rowCount2)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); if (rowCount2 > 0) { txtResults.AppendText("** Could not purge all or some of the Unused RO Associations.** "); txtResults.AppendText("** It is recommended you contact Volian to assist in resolving this condition.**"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } } else { txtResults.AppendText(string.Format("The database contained {0} Unused RO Associations.", rowCount)); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(string.Format("No Unused RO Associations to Purge.")); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface // tool was renamed to Hidden Data Locations (on Check list) private void IdentifyNonEditableItems() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Identifing Hidden Item Locations"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); List myItems = ESP_IdentifyNonEditableItems.Execute("vesp_GetNonEditableItems"); txtProcess.AppendText(string.Format("Hidden Items Count: {0}", myItems.Count)); txtProcess.AppendText(Environment.NewLine); if (myItems.Count > 0) { txtResults.AppendText("The following items are hidden (non-editable)..."); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); foreach (ItemInfo ii in myItems) { txtResults.AppendText(ii.Path); txtResults.AppendText(Environment.NewLine); } txtResults.AppendText(Environment.NewLine); } else { txtResults.AppendText("No Hidden Data Found");// B2017-108 Always output results even if there isn't any txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); } //C2025-011 RO Update Admin Tool Memory Enhancements //clear the list since no longer using it myItems.Clear(); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); this.Cursor = Cursors.Default; } // C2017-030 - new Admin Tools user interface // tool was renamed to Show Users private void GetDatabaseSessions() { this.Cursor = Cursors.WaitCursor; DateTime pStart = DateTime.Now; txtProcess.AppendText("Show Users in PROMS"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(string.Format("Started: {0}", pStart.ToString("MM/dd/yyyy @ HH:mm"))); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); txtResults.Clear(); txtResults.AppendText(ESP_GetDatabaseSessions.Execute("vesp_GetDatabaseSessions")); DateTime pEnd = DateTime.Now; txtProcess.AppendText(string.Format("Completed: {0}", pEnd.ToString("MM/dd/yyyy @ HH:mm"))); Application.DoEvents(); this.Cursor = Cursors.Default; MessageBox.Show("Show Users Completed", "Show Users"); } private void ProcessUpdateROValues(DocVersionInfo dq) { string statmsg = string.Format("Updating ROs for {0}", dq.MyFolder.Name); InitialProgressBarMessage = statmsg; txtProcess.AppendText(statmsg); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText(statmsg); txtResults.AppendText(Environment.NewLine); Application.DoEvents(); if (dq.DocVersionAssociationCount < 1) { ProgressBar.ColorTable = eProgressBarItemColor.Error; FinalProgressBarMessage = "No ROs associated"; txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText("Error Updating ro.fst. No associated ro.fst"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText("Error Updating ro.fst. No associated ro.fst"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); return; } ROFstInfo roFstInfo = dq.DocVersionAssociations[0].MyROFst; string rofstPath = roFstInfo.MyRODb.FolderPath + @"\ro.fst"; //if (!pathExists(rofstPath)) if (!File.Exists(rofstPath)) { ProgressBar.ColorTable = eProgressBarItemColor.Error; FinalProgressBarMessage = "No existing RO.FST"; txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText("No existing ro.fst in path " + roFstInfo.MyRODb.FolderPath + ". Check for invalid path"); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText("No existing ro.fst in path " + roFstInfo.MyRODb.FolderPath + ". Check for invalid path"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); return; } //FileInfo fiRofst = new FileInfo(rofstPath); Cursor = Cursors.WaitCursor; using (DocVersion dv = DocVersion.Get(dq.VersionID)) { // B2022-026 RO Memory Reduction code - first load the new ro.fst so that we can assign the ROTableUpdate event to the correct roFstInfo if (dv.ROfstLoadingFigures || dv.NewerRoFst) // B2017-125 see if loading figures was completed { // only load the RO.fst ROFstInfo.UpdateRoFst(roFstInfo.MyRODb, dv, roFstInfo, DoProgressBarRefresh); roFstInfo = dq.DocVersionAssociations[0].MyROFst; } roFstInfo.ROTableUpdate += new ROFstInfoROTableUpdateEvent(roFstInfo_ROTableUpdate); ROFst newrofst = ROFstInfo.RefreshROFst(dv, roFstInfo, DoProgressBarRefresh, txtProcess); //ROFst newrofst = ROFstInfo.RefreshROFst(dv, roFstInfo, DoProgressBarRefresh, null); roFstInfo.ROTableUpdate -= new ROFstInfoROTableUpdateEvent(roFstInfo_ROTableUpdate); } Cursor = Cursors.Default; ProgressBar.ColorTable = eProgressBarItemColor.Normal; FinalProgressBarMessage = "ROs values updated"; txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); txtResults.AppendText("ROs values updated"); txtResults.AppendText(Environment.NewLine); txtResults.AppendText(Environment.NewLine); return; } private void RefreshProcedureTransitions(ProcedureInfo pq) { DateTime start = DateTime.Now; ProcedureInfo.ResetTranCounters(); ProcedureInfo.RefreshTransitions(pq);//, transitionsToDisconnected, transitionsToNonEditable); TimeSpan ts = DateTime.Now - start; // B2018-002 - Invalid Transitions - Display Transition Refresh Statistics txtProcess.AppendText(string.Format("Procedure: {1}{0}Checked {2} Transitions{0}Fixed {3} Transitions{0}Converted to Text {4} Transitions{0}Cant Fix (Annotation: Bad Transition Link) {5} Transitions{0}Elapsed Seconds:{6}{0}{0}", Environment.NewLine, pq.DisplayNumber, ProcedureInfo.TranCheckCount, ProcedureInfo.TranFixCount, ProcedureInfo.TranConvertCount, ProcedureInfo.TranCantFixCount, ts.TotalSeconds)); if (myFixes.Length > 0) { txtResults.AppendText(myFixes.ToString()); txtResults.AppendText(Environment.NewLine); } } public List roFstInfo_ROTableUpdate(object sender, ROFstInfoROTableUpdateEventArgs args) { return VlnFlexGrid.ROTableUpdate(sender, args); } private void PopulateTransitionInfoLists(List pil) { Dictionary dic = new Dictionary(); StringBuilder sb = new StringBuilder(); foreach (ProcedureInfo pi in pil) if (!dic.ContainsKey(pi.MyDocVersion.VersionID)) { dic.Add(pi.MyDocVersion.VersionID, pi.MyDocVersion.VersionID); sb.Append(sb.Length == 0 ? pi.MyDocVersion.VersionID.ToString() : "," + pi.MyDocVersion.VersionID.ToString()); } txtProcess.AppendText("Preparing to process..."); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); //transitionsToDisconnected = TransitionInfoList.GetTransitionsToDisconnected(sb.ToString()); //transitionsToNonEditable = TransitionInfoList.GetTransitionsToNonEditable(sb.ToString()); } private void ProgressBarShowText() { pbProcess.Refresh(); int percent = (int)(((double)(pbProcess.Value - pbProcess.Minimum) / (double)(pbProcess.Maximum - pbProcess.Minimum)) * 100); using (Graphics gr = pbProcess.CreateGraphics()) { gr.DrawString(percent.ToString() + "%", SystemFonts.DefaultFont, Brushes.Black, new PointF(pbProcess.Width / 2 - (gr.MeasureString(percent.ToString() + "%", SystemFonts.DefaultFont).Width / 2.0F), pbProcess.Height / 2 - (gr.MeasureString(percent.ToString() + "%", SystemFonts.DefaultFont).Height / 2.0F))); } Application.DoEvents(); } StringBuilder myFixes; int myFixesCount = 0; int myConvertCount = 0; // show the changes made in the Results pannel, include the ItemId of the step element void ContentInfo_StaticContentInfoChange(object sender, StaticContentInfoEventArgs args) { if (args.Type == "TX") { myFixesCount++; if (args.NewValue.StartsWith("Reason for Change:")) myFixes.AppendLine(string.Format("Fixed Transition for {1}({4}){0}Old Text: {2}{0}{3}{0}", Environment.NewLine, (sender as ItemInfo).ShortPath, args.OldValue, args.NewValue, (sender as ItemInfo).ItemID)); else myFixes.AppendLine(string.Format("Fixed Transition for {1}({4}){0}Old Text: {2}{0}New Text: {3}{0}", Environment.NewLine, (sender as ItemInfo).ShortPath, args.OldValue, args.NewValue, (sender as ItemInfo).ItemID)); } else if (args.Type == "RO") { txtResults.AppendText(string.Format("Fixed Referenced Object for {1}({4}){0}Old Text: {2}{0}New Text: {3}{0}{0}", Environment.NewLine, (sender as ItemInfo).ShortPath, args.OldValue, args.NewValue, (sender as ItemInfo).ItemID)); Application.DoEvents(); //myFixes.AppendLine(string.Format("Fixed Referenced Object for {1}{0}Old Text: {2}{0}New Text: {3}{0}", Environment.NewLine, (sender as ItemInfo).ShortPath, args.OldValue, args.NewValue)); } else // B2018-002 - Invalid Transitions - Display Transition Cconversion Statistics { myFixes.AppendLine(string.Format("Converted Transition to text for {0}({1})", (sender as ItemInfo).ShortPath, (sender as ItemInfo).ItemID)); } } private void btnClear_Click(object sender, EventArgs e) { txtResults.Clear(); } private void btnSave_Click(object sender, EventArgs e) { SaveFileDialog sfd = new SaveFileDialog(); sfd.DefaultExt = "txt"; sfd.AddExtension = true; sfd.Filter = "Text Files (*.txt)|*.txt"; sfd.FileName = string.Format("BatchRefreshResults_{0}", DateTime.Now.ToString("yyyyMMdd_HHmm")); sfd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\VEPROMS"; DialogResult dr = sfd.ShowDialog(); if (dr == DialogResult.OK) { System.IO.StreamWriter sw = new System.IO.StreamWriter(sfd.FileName); sw.Write(txtResults.Text); sw.Close(); } } private void myTV_AfterCheck(object sender, TreeViewEventArgs e) { //B2025 - 013 Admin Tool Tree Behavior //only want to perform this if // not an unknown action // aka is a mouse click // if this is fire-ing because clicked a parent or a child of an item // want this to only fire once - for the item clicked - not for parents/children if (e.Action != TreeViewAction.Unknown) { if (e.Node.Nodes.Count > 0) { CheckChildNodes(e.Node, e.Node.Checked); } //B2025-013 Admin Tool Tree Behavior //if a node gets unchecked, //then uncheck both its parents and children if (!e.Node.Checked) { DiselectParentNodes(e.Node.Parent); DiselectChildNodes(e.Node.Nodes); } btnFixLinks.Enabled = btnDeleteItems.Enabled = AtLeastOneNodeChecked(((TreeView)sender).Nodes); // C2017-030 support for Refresh Transitions/Update RO Values } } private void DiselectParentNodes(TreeNode parent) { while (parent != null) { if (parent.Checked) parent.Checked = false; parent = parent.Parent; } } private void DiselectChildNodes(TreeNodeCollection childes) { foreach (TreeNode oneChild in childes) { if (oneChild.Checked) oneChild.Checked = false; DiselectChildNodes(oneChild.Nodes); } } private void CheckChildNodes(TreeNode treeNode, bool ischecked) { foreach (TreeNode tn in treeNode.Nodes) { tn.Checked = ischecked; if (tn.Nodes.Count > 0) { CheckChildNodes(tn, ischecked); } } } private ProgressBarItem _ProgressBar = null; public ProgressBarItem ProgressBar { get { return _ProgressBar; } set { _ProgressBar = value; _ProgressBar.TextVisible = true; } } private void DoProgressBarRefresh(int value, int max, string text) { if (ProgressBar == null) return; ProgressBar.Maximum = max; ProgressBar.Value = value; ProgressBar.Text = text; Application.DoEvents(); } private string InitialProgressBarMessage { set { if (ProgressBar == null) return; ProgressBar.Maximum = 100; ProgressBar.Value = 0; ProgressBar.Text = value; txtProcess.AppendText(value); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); } } private string FinalProgressBarMessage { set { if (ProgressBar == null) return; ProgressBar.Value = 100; ProgressBar.Maximum = 100; ProgressBar.Text = value; txtProcess.AppendText(value); txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(Environment.NewLine); Application.DoEvents(); } } private void chkLater_CheckedChanged(object sender, EventArgs e) { pnlLater.Enabled = chkLater.Checked; } // C2017-030 new Admin Tools user interface private void sideNavItmCheck_Click(object sender, EventArgs e) { AdminToolType = E_AdminToolType.Check; lblAdmToolProgressType.Text = "Checking:"; setupProgessSteps1(); } // C2017-030 new Admin Tools user interface private void sideNavItmRepair_Click(object sender, EventArgs e) { AdminToolType = E_AdminToolType.Repair; lblAdmToolProgressType.Text = "Repairing:"; setupProgessSteps1(); if (!IsAdministratorUser) // C2020-035 notify Set Amin user that only Full Admins can run repair tools { MessageBox.Show("Only Full PROMS Administrator Users can run these data repair tools", "Data Repair Tools", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } // C2017-030 new Admin Tools user interface private void sideNavItmLinks_Click(object sender, EventArgs e) { AdminToolType = E_AdminToolType.Links; setupProgessSteps1(); if (swUpdateROVals.Value) ResetTV(true); else ResetTV(false); } // C2017-030 new Admin Tools user interface private void sideNavItmUsers_Click(object sender, EventArgs e) { AdminToolType = E_AdminToolType.Users; setupProgessSteps1(); } // C2017-030 new Admin Tools user interface private void sideNavItmExit_Click(object sender, EventArgs e) { this.Close(); } // new Admin Tools user interface for deletes private void sideNavItmDelete_Click(object sender, EventArgs e) { AdminToolType = E_AdminToolType.Delete; lblAdmToolProgressType.Text = ""; setupProgessSteps1(); if (swDeleteFolder.Value) ResetDelTV(true); else ResetDelTV(false); } // new Admin Tools user interface for deletes //private void sideNavItmDelete_Click_1(object sender, EventArgs e) //{ //} #region On/Off Swiches // C2017-030 new Admin Tools user interface private enum E_AdminToolType : int { Check = 0, Repair = 1, Links = 2, Users = 3, Delete = 4 }; private E_AdminToolType AdminToolType = 0; DevComponents.DotNetBar.StepItem siOrphDatRecs = new DevComponents.DotNetBar.StepItem("siOrphDatRecs", "Orphan Data Records"); DevComponents.DotNetBar.StepItem siHiddenDataLocs = new DevComponents.DotNetBar.StepItem("siHiddenDataLocs", "Hidden Data"); DevComponents.DotNetBar.StepItem siObsoleteROData = new DevComponents.DotNetBar.StepItem("siObsoleteROData", "Obsolete RO Data"); DevComponents.DotNetBar.StepItem siStandardHyphens = new DevComponents.DotNetBar.StepItem("siStandardHyphens", "Standardize Hyphens"); DevComponents.DotNetBar.StepItem siRefreshAttmts = new DevComponents.DotNetBar.StepItem("siRefreshAttmts", "Refresh Word Attachments"); DevComponents.DotNetBar.StepItem siRefreshTblsSrchTxt = new DevComponents.DotNetBar.StepItem("siRefreshTblsSrchTxt", "Refresh Tables For Search"); // this will update/rebuild the progress bar in the bottom panel of Admin Tools private void setupProgessSteps1() { progressSteps1.Visible = false; progressSteps1.Items.Clear(); switch (AdminToolType) { case E_AdminToolType.Check: if (swCkOrphanDataRecs.Value) progressSteps1.Items.Add(siOrphDatRecs); if (swHiddenDataLocs.Value) progressSteps1.Items.Add(siHiddenDataLocs); if (swCkObsoleteROData.Value) progressSteps1.Items.Add(siObsoleteROData); splitContainer3.Panel2Collapsed = false; progressSteps1.Visible = true; progressSteps1.Refresh(); break; case E_AdminToolType.Repair: if (swRmOrphanDataRecs.Value) progressSteps1.Items.Add(siOrphDatRecs); if (swRmObsoleteROData.Value) progressSteps1.Items.Add(siObsoleteROData); if (swStandardHypenChars.Value) progressSteps1.Items.Add(siStandardHyphens); if (swRefreshWordAttmts.Value) progressSteps1.Items.Add(siRefreshAttmts); if (swRefreshTblsForSrch.Value) progressSteps1.Items.Add(siRefreshTblsSrchTxt); splitContainer3.Panel2Collapsed = false; progressSteps1.Visible = true; progressSteps1.Refresh(); break; case E_AdminToolType.Links: case E_AdminToolType.Users: splitContainer3.Panel2Collapsed = true; progressSteps1.Visible = false; break; case E_AdminToolType.Delete: if (swDeleteFolder.Value) { splitContainer3.Panel2Collapsed = false; progressSteps1.Items.Add(siOrphDatRecs); lblAdmToolProgressType.Text = "Deleting: "; progressSteps1.Visible = true; progressSteps1.Refresh(); } else { lblAdmToolProgressType.Text = ""; splitContainer3.Panel2Collapsed = true; progressSteps1.Visible = false; } break; } } // used for all of the Switch buttons (ON/OFF buttons) private void swCk_ValueChanged(object sender, EventArgs e) { setupProgessSteps1(); } private void swUpdateROVals_ValueChanged(object sender, EventArgs e) { if (swUpdateROVals.Value) { swRefreshTrans.Value = false; swCheckROLinks.Value = false; ResetTV(true); } } private void swRefreshTrans_ValueChanged(object sender, EventArgs e) { if (swRefreshTrans.Value) { swUpdateROVals.Value = false; swCheckROLinks.Value = false; ResetTV(false); } } #endregion // C2017-030 New Admin Tools user interface // functions to handle the progress bar in the bottom panel of Admin Tools private void StepProgress(int prgStpIdx, int val) { ((DevComponents.DotNetBar.StepItem)progressSteps1.Items[prgStpIdx]).Value = val; return; } private void ClearStepProgress() { for (int i = 0; i < progressSteps1.Items.Count; i++) { ((DevComponents.DotNetBar.StepItem)progressSteps1.Items[i]).Value = 0; } } // C2017-030 New Admin Tools user interface // button clicks for processing selected tools //B2017-221 Allow the batch dialog to close when waiting to process. private bool CheckProcessLater() // see if we should delay processing until later { if (chkLater.Checked) { long later = long.Parse(dtpDate.Value.ToString("yyyyMMdd") + dtpTime.Value.ToString("HHmm")); long now = long.Parse(DateTime.Now.ToString("yyyyMMddHHmm")); while (now < later) { txtProcess.Clear(); txtProcess.AppendText("Waiting..."); System.Threading.Thread.Sleep(1000);//Check each second if (IsClosing) return false;//B2017-221 Allow the batch dialog to close when waiting to process. Application.DoEvents();// Allow user interface to react now = long.Parse(DateTime.Now.ToString("yyyyMMddHHmm")); } } return true;// Close after complete } // C2017-030 new Admin Tools user interface private void btn_ShowUsers_Click(object sender, EventArgs e) { if (!CheckProcessLater()) return; // delay processing if set//B2017-221 Allow the batch dialog to close when waiting to process. txtProcess.Clear(); txtResults.Clear(); GetDatabaseSessions(); } private void btnFixLinks_Click(object sender, EventArgs e) { if (!CheckProcessLater()) return; // delay processing if set//B2017-221 Allow the batch dialog to close when waiting to process. txtProcess.Clear(); txtResults.Clear(); if (swRefreshTrans.Value) RefreshTransitions(); if (swUpdateROVals.Value) UpdateROValues(); if (swCheckROLinks.Value) CheckROLinks(); // C2022-028 check for Bad RO Links } private void btnRunCheck_Click(object sender, EventArgs e) { if (!CheckProcessLater()) return; // delay processing if set//B2017-221 Allow the batch dialog to close when waiting to process. int prgStpIdx = -1; txtResults.Clear(); txtProcess.Clear(); if (swCkOrphanDataRecs.Value) { StepProgress(++prgStpIdx, 50); IdentifyDisconnectedItems(); // orphan items StepProgress(prgStpIdx, 100); } if (swHiddenDataLocs.Value) { StepProgress(++prgStpIdx, 50); IdentifyNonEditableItems(); // hidden items StepProgress(prgStpIdx, 100); } if (swCkObsoleteROData.Value) { StepProgress(++prgStpIdx, 25); IdentifyROAssociations(); StepProgress(prgStpIdx, 50); IdentifyUnusedRoFstsAndFigures(); StepProgress(prgStpIdx, 100); } MessageBox.Show("Check Functions Completed", "Check"); ClearStepProgress(); } private void btnRunRepair_Click(object sender, EventArgs e) { if (!CheckProcessLater()) return; // delay processing if set//B2017-221 Allow the batch dialog to close when waiting to process. int prgStpIdx = -1; txtResults.Clear(); txtProcess.Clear(); if (swRmOrphanDataRecs.Value) { StepProgress(++prgStpIdx, 50); PurgeDisconnectedItems(); // Orphan Items StepProgress(prgStpIdx, 100); } if (swRmObsoleteROData.Value) { StepProgress(++prgStpIdx, 25); CleanUpROAssociations(); StepProgress(prgStpIdx, 50); RemoveUnusedRoFstsAndFigures(); StepProgress(prgStpIdx, 100); } if (swStandardHypenChars.Value) { StepProgress(++prgStpIdx, 50); FixHyphens(); StepProgress(prgStpIdx, 100); } if (swRefreshWordAttmts.Value) { StepProgress(++prgStpIdx, 50); DeletePDFs(); // refresh word attachments StepProgress(prgStpIdx, 100); } if (swRefreshTblsForSrch.Value) { StepProgress(++prgStpIdx, 50); RefreshTablesForSearch(); StepProgress(prgStpIdx, 100); } MessageBox.Show("Repair Functions Completed", "Repair"); ClearStepProgress(); } //C2022-028 check for Bad RO Links private void swCheckROLinks_ValueChanged(object sender, EventArgs e) { if (swCheckROLinks.Value) { swUpdateROVals.Value = false; swRefreshTrans.Value = false; ResetTV(false); } } //C2024-005 Delete Annotations, Delete Folders private void swDeleteAnnotations_ValueChanged(object sender, EventArgs e) { setupProgessSteps1(); swDeleteFolder.Value = !swDeleteAnnotations.Value; if (swDeleteFolder.Value) ResetDelTV(true); else ResetDelTV(false); } private void swDeleteFolder_ValueChanged(object sender, EventArgs e) { setupProgessSteps1(); swDeleteAnnotations.Value = !swDeleteFolder.Value; if (swDeleteFolder.Value) ResetDelTV(true); else ResetDelTV(false); } private void btnDeleteItems_Click(object sender, EventArgs e) { //clear txtResults.Clear(); txtProcess.Clear(); this.Cursor = Cursors.WaitCursor; //Create checked proce and doc info lists. List pil = new List(); List dvil = new List(); //B2025-013 Admin Tool Tree Behavior //For Procedures & Doc Versions //To avoid processing duplicates //only want to add highest nodes selected // i.e. if both an item and it's parent is checked, then add the parent // not each individual item // if a parent isn't checked, then add the individual item // one exception to this is if the parent is not in the docversions // for example: the top node - VEPROMS //if that is selected, then we will add its children instead of it. // Create a list of procedures the user selected foreach (TreeNode tn in myProcedures.Keys) if (tn.Checked && (tn.Parent == null || !tn.Parent.Checked || !myDocVersions.ContainsKey(tn.Parent))) pil.Add(myProcedures[tn]); // Create a list of doc versions the user selected foreach (TreeNode tn in myDocVersions.Keys) if (tn.Checked && (tn.Parent == null || !tn.Parent.Checked || !myDocVersions.ContainsKey(tn.Parent))) dvil.Add(myDocVersions[tn]); bool cancelledOut = false; // Flag to indicate if the process should be cancelled StringBuilder sbDocVersions = new StringBuilder(); foreach (DocVersionInfo dq in dvil) { string msg = string.Empty; if (!MySessionInfo.CanCheckOutItem(dq.VersionID, CheckOutType.DocVersion, ref msg)) { string msgp = string.Empty; foreach (ProcedureInfo pi in dq.Procedures) { if (!MySessionInfo.CanCheckOutItem(pi.ItemID, CheckOutType.Procedure, ref msgp)) { FolderInfo fi = (FolderInfo)dq.ActiveParent; int itemID = (int)fi.FolderID; string folderName = fi.Name; if (swDeleteFolder.Value) sbDocVersions.AppendLine($"{folderName} - {msgp}"); else sbDocVersions.AppendLine(msgp); cancelledOut = true; } } } } //B2024-074 If only deleting annotations from an individual procedure, verify can check out procedure. string msgpi = string.Empty; foreach (ProcedureInfo pi in pil) { //LINQ used for 1st check of if statement //basically check if procedure was already part of a docVersionsFolder //before checking if procedure was checked out already //to avoid duplicate messages for checked out procedures if (!dvil.Any(x => x.Procedures.Any(y => y.ItemID == pi.ItemID)) && !MySessionInfo.CanCheckOutItem(pi.ItemID, CheckOutType.Procedure, ref msgpi)) { sbDocVersions.AppendLine(msgpi); cancelledOut = true; } } if (cancelledOut) { StringBuilder sb = new StringBuilder(); sb.AppendLine("The batch update process was not successful for all working drafts selected."); sb.AppendLine("The following procedures are currently checked out..."); sb.AppendLine(); sb.AppendLine(sbDocVersions.ToString()); sb.AppendLine(); if (swDeleteFolder.Value) sb.AppendLine("If you want to delete these folders, please contact the respective users and have them close any procedures in the working draft."); else sb.AppendLine("If you want to delete annotations from these working drafts, please contact the respective users and have them close any procedures in the working draft."); sb.AppendLine(); txtProcess.AppendText(sb.ToString()); this.Cursor = Cursors.Default; return; } if (swDeleteFolder.Value) { if (FlexibleMessageBox.Show(this, "Are you sure you want to remove the selected folders and their contents?", "Confirm Folder Deletion", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { txtProcess.AppendText("Deleting Folders..."); //Load Selected Folders List ef = new List(); foreach (TreeNode tn in myFolders.Keys) if (tn.Checked) ef.Add(myFolders[tn]); ProcessDelete(dvil, ef); } } else { // Write progress status txtProcess.AppendText("Deleting Annotations..."); frmAnnotationsCleanup frmAnnoDel = new frmAnnotationsCleanup(this, pil, dvil); frmAnnoDel.ShowDialog(); } this.Cursor = Cursors.Default; } private void ProcessDelete(List foldersToDelete, List emptyFoldersToDelete) { int foldersDeleted = 0; DateTime pStart = DateTime.Now; txtProcess.AppendText(Environment.NewLine); txtProcess.AppendText(pStart.ToString("MM/dd/yyyy @ HH:mm")); txtProcess.AppendText(Environment.NewLine); foreach (var kvp in foldersToDelete) { //Gather folder information FolderInfo fi = (FolderInfo)kvp.ActiveParent; int itemID = (int)fi.FolderID; string folderName = fi.Name; // Perform the deletion operation bool deletionSuccessful = DeleteFolderByID(itemID); // Update txtProcess with the progress if (deletionSuccessful) { txtProcess.AppendText($"Successfully deleted folder: {folderName} (ID: {itemID})"); foldersDeleted += 1; } else { txtProcess.AppendText($"Failed to delete folder: {folderName} (ID: {itemID})"); } txtProcess.AppendText(Environment.NewLine); } //Delete non working info folders. foreach (var kvp in emptyFoldersToDelete) { //Gather folder information FolderInfo fi = (FolderInfo)kvp; int itemID = (int)fi.FolderID; string folderName = fi.Name; // Perform the deletion operation bool deletionSuccessful = DeleteFolderByID(itemID); // Update txtProcess with the progress if (deletionSuccessful) { txtProcess.AppendText($"Successfully deleted folder: {folderName} (ID: {itemID})"); foldersDeleted += 1; } else { txtProcess.AppendText($"Failed to delete folder: {folderName} (ID: {itemID})"); } txtProcess.AppendText(Environment.NewLine); } //Run Repair int prgStpIdx = -1; StepProgress(++prgStpIdx, 50); PurgeDisconnectedItems(); // Orphan Items StepProgress(prgStpIdx, 100); //rebuild ResetDelTV(true); MessageBox.Show($"Folder deletion completed, {foldersDeleted} folders have been deleted.", "Delete Folders"); ClearStepProgress(); txtResults.AppendText($"Folder deletion process completed, {foldersDeleted} folders have been deleted."); txtResults.AppendText(Environment.NewLine); } private bool DeleteFolderByID(int folderID) { try { //Delete Folder.DeleteFolderAdmin(folderID); //update treeview UI via veProms _veProms.tv_FolderDelete(folderID); return true; } catch (Exception ex) { string err = ex.ToString(); return false; } } //C2025-011 RO Update Admin Tool Memory Enhancements private void txtProcess_TextChanged(object sender, EventArgs e) { //clears the stack to help with memory - should never need to undo text changes to this. txtProcess.ClearUndo(); } private void txtResults_TextChanged(object sender, EventArgs e) { //clears the stack to help with memory - should never need to undo text changes to this. txtResults.ClearUndo(); } } }