using System; using System.ComponentModel; using System.Collections.Generic; using System.Windows.Forms; using VEPROMS.CSLA.Library; using System.Drawing; using Volian.Base.Library; using JR.Utils.GUI.Forms; using System.Linq; namespace Volian.Controls.Library { public partial class StepPanel : Panel { #region Fields /// /// Procedure Item Info - Top ItemInfo /// private ItemInfo _MyProcedureItemInfo; public E_ViewMode VwMode { get; set; } = E_ViewMode.Edit; public EditItem TopMostEditItem { get; set; } = null; public ItemInfo ExpandingHLS { get; set; } = null; // TODO: This is not correct. There should be a dictionary of Section Layouts /// /// Lookup Table to convert ItemInfo.ItemID to EditItem /// internal Dictionary _LookupEditItems; public EditItem FindItem(ItemInfo itemInfo) { if (itemInfo == null) return null; if (!_LookupEditItems.ContainsKey(itemInfo.ItemID)) return null; return _LookupEditItems[itemInfo.ItemID]; } private int _ApplDisplayMode = -1; public int ApplDisplayMode { get { return _ApplDisplayMode; } set { if(_ApplDisplayMode == value) return; _ApplDisplayMode = value; foreach (Control c in Controls) { if (c is EditItem ei) { ei.Enabled = ei.MyItemInfo.IsApplicable(value); } } } } /// /// Currently selected ItemInfo /// internal ItemInfo _SelectedItemInfo; private StepPanelSettings _MyStepPanelSettings; private Font _MyFont = null; private Color _ActiveColor = Color.SkyBlue; private Color _PanelColor = Color.LightGray; // Whether panel is in view or edit mode. Toggled from steprtb // or set based on approval/multi-user (these two will be done // later. internal string _LastAdjust=""; private Graphics _MyGraphics = null; private int _DPI = 0; #endregion #region Item Events /// /// Occurs when the user clicks tab of a EditItem /// public event StepPanelEvent ItemClick; /// /// Checks to see if the 'ItemClick' event is handled and launches it /// /// /// internal void OnItemClick(object sender, StepPanelEventArgs args) { ItemClick?.Invoke(sender, args); } public bool ItemSelectionChangeShown = false; // This keeps OnItemSelectedChanged from being called twice when an item is selected. /// /// Occurs when the selected EditItem changes /// public event ItemSelectedChangedEvent ItemSelectedChanged; /// /// Checks to see if the 'ItemSelectedChanged' event is handled and launches it /// /// /// internal void OnItemSelectedChanged(object sender, ItemSelectedChangedEventArgs args) { ItemSelectionChangeShown = true;//Remember that you have run already //vlnStackTrace.ShowStack(string.Format("OnItemSelectedChanged {0}",args.MyItemInfo.ItemID)); ItemSelectedChanged?.Invoke(sender, args); } /// /// Occurs when the user clicks on the Attachment Expander /// public event StepPanelAttachmentEvent AttachmentClicked; /// /// Checks to see if the 'AttachmentClicked' event is handled and launches it /// /// /// internal void OnAttachmentClicked(object sender, StepPanelAttachmentEventArgs args) { if (AttachmentClicked != null) AttachmentClicked(sender, args); else FlexibleMessageBox.Show(args.MyEditItem.MyItemInfo.MyContent.MyEntry.MyDocument.DocumentTitle, "Unhandled Attachment Click", MessageBoxButtons.OK, MessageBoxIcon.Information); } public event StepPanelTabDisplayEvent TabDisplay; internal void OnTabDisplay(object sender, StepPanelTabDisplayEventArgs args) => TabDisplay(sender, args); // close section, if deleting word doc section public event StepPanelWordSectionCloseEvent WordSectionClose; internal void OnWordSectionClose(object sender, WordSectionEventArgs args) => WordSectionClose(sender, args); // if section deleted, have event to flag in other UI panels public event StepPanelWordSectionDeletedEvent WordSectionDeleted; internal void OnWordSectionDeleted(object sender, WordSectionEventArgs args) => WordSectionDeleted(sender, args); // if item pasted, have event to flag in other UI panels public event StepPanelItemPastedEvent ItemPasted; internal void OnItemPasted(object sender, vlnTreeItemInfoPasteEventArgs args) => ItemPasted(sender, args); #endregion #region Link Events /// /// Occurs when the user moves onto or off of a Link /// public event StepPanelLinkEvent LinkActiveChanged; /// /// Checks to see if the 'LinkActiveChanged' event is handled and launches it /// /// /// internal void OnLinkActiveChanged(object sender, StepPanelLinkEventArgs args) { if (LinkActiveChanged != null) LinkActiveChanged(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Active Changed", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Occurs when the user chooses to Insert a Transition /// public event StepPanelLinkEvent LinkInsertTran; /// /// Checks to see if the 'LinkInsertTran' event is handled and launches it /// /// /// internal void OnLinkInsertTran(object sender, StepPanelLinkEventArgs args) { if (LinkInsertTran != null) LinkInsertTran(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Insert Tran", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Occurs when the user chooses to Insert an RO /// public event StepPanelLinkEvent LinkInsertRO; /// /// Checks to see if the 'LinkInsertRO' event is handled and launches it /// /// /// internal void OnLinkInsertRO(object sender, StepPanelLinkEventArgs args) { if (LinkInsertRO != null) LinkInsertRO(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Insert RO", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Occurs when the user clicks a Link /// public event StepPanelLinkEvent LinkClicked; /// /// Checks to see if the 'LinkClicked' event is handled and launches it /// /// /// internal void OnLinkClicked(object sender, StepPanelLinkEventArgs args) { if (LinkClicked != null) LinkClicked(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Click", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Occurs when the user chooses to modify a Transition /// public event StepPanelLinkEvent LinkModifyTran; /// /// Checks to see if the 'LinkModifyTran' event is handled and launches it /// /// /// internal void OnLinkModifyTran(object sender, StepPanelLinkEventArgs args) { if (LinkModifyTran != null) LinkModifyTran(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Modify Tran", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// /// Occurs when the user chooses to modify an RO /// public event StepPanelLinkEvent LinkModifyRO; /// /// Checks to see if the 'LinkModifyRO' event is handled and launches it /// /// /// internal void OnLinkModifyRO(object sender, StepPanelLinkEventArgs args) { if (LinkModifyRO != null) LinkModifyRO(sender, args); else FlexibleMessageBox.Show(args.LinkInfoText, "Unhandled Link Modify RO", MessageBoxButtons.OK, MessageBoxIcon.Information); } #endregion #region Constructors public StepPanel() { InitializeComponent(); SetupStepPanel(); } private void SetupStepPanel() { this.BackColorChanged += new EventHandler(StepPanel_BackColorChanged); if (VlnSettings.DebugMode) { InactiveColor = Color.Linen; TabColor = Color.Beige; _PanelColor = Color.LightGray; this.DoubleClick += new EventHandler(StepPanel_DoubleClick); // Toggles Vertical lines on and off } else { InactiveColor = Color.White; TabColor = Color.White; _PanelColor = Color.White; this.BackColor = Color.White; } this.AutoScroll = true; } public StepPanel(IContainer container) { container.Add(this); InitializeComponent(); SetupStepPanel(); } void StepPanel_BackColorChanged(object sender, EventArgs e) { // Walk through controls & set colors InactiveColor = PanelColor = BackColor; foreach (Control ctrl in Controls) { if (ctrl is EditItem ei) { ei.BackColor = BackColor; } } } #endregion #region Private Methods /// /// Expands an Item and It's Parents as need to display an item /// /// Item to Expand private void ExpandAsNeeded(ItemInfo myItemInfo) { int id = myItemInfo.ItemID; if (!_LookupEditItems.ContainsKey(id)) // If the item is not currently displayed ExpandAsNeeded((ItemInfo)myItemInfo.ActiveParent); // Expand it's parent if (_LookupEditItems.ContainsKey(id)) // Expanding Parent should have added it to _LookupEditItems { EditItem itm = _LookupEditItems[id]; if (!itm.Visible && myItemInfo.ActiveParent is ItemInfo ii) ExpandAsNeeded(ii); itm.AutoExpand(); // Expand it if it should expand } } #endregion #region Properties public StepTabPanel MyStepTabPanel { get { return Parent as StepTabPanel; } } /// /// Procedure Item Info - Top ItemInfo /// Get and Set - Set stes-up all of the /// public ItemInfo MyProcedureItemInfo { get { return _MyProcedureItemInfo; } set { _MyProcedureItemInfo = value; Controls.Clear(); _LookupEditItems = new Dictionary(); new RTBItem(_MyProcedureItemInfo, this, null, ChildRelation.None, false); } } public bool AutoExpand { get { // This is temporary to get the code working for this particular procedure if (MyProcedureItemInfo.DisplayNumber == "PMS-810") return false; if (MyProcedureItemInfo.DisplayNumber == "PMS-809") return false; return true; } } public void Reset() { if (SelectedItemInfo.ActiveParent is ItemInfo parent) ItemInfo.ResetParts(parent.ItemID); // Force data to reload else ItemInfo.ResetParts(SelectedItemInfo.ItemID); // The following line actually reloads the procedure item MyProcedureItemInfo = MyProcedureItemInfo; // see get/set above. - Load Procedure and Sections // The following line expands the items needed to display SelectedItemInfo ExpandAsNeeded(SelectedItemInfo); } public void Reset(ItemInfo myItemInfo) { if (myItemInfo.ActiveParent is ItemInfo parent) ItemInfo.ResetParts(parent.ItemID); // Force data to reload else ItemInfo.ResetParts(myItemInfo.ItemID); // The following line actually reloads the procedure item MyProcedureItemInfo = MyProcedureItemInfo; // see get/set above. - Load Procedure and Sections // The following line expands the items needed to display SelectedItemInfo ExpandAsNeeded(myItemInfo); } //C2019-036 View Only mode work with Checked Out Procedures public void ResetAll() { List itemIDs = Controls.OfType().Where(t => t?.MyItemInfo?.ActiveParent != null && t.MyItemInfo.ActiveParent.GetType() == typeof(ItemInfo)).Select(x => (x.MyItemInfo.ActiveParent as ItemInfo).ItemID).Distinct().ToList(); foreach (int itemID in itemIDs) { ItemInfo.ResetParts(itemID); } // The following line actually reloads the procedure item MyProcedureItemInfo = ItemInfo.Get(MyProcedureItemInfo.ItemID, true); MyProcedureItemInfo.RefreshConfig(); ContentInfo.Refresh(Content.Get(MyProcedureItemInfo.MyContent.ContentID, true)); // The following line expands the items needed to display SelectedItemInfo ExpandAsNeeded(SelectedItemInfo); } /// /// Gets or Sets the SelectedItemInfo /// Activates and Expands as necessary /// public ItemInfo SelectedItemInfo { get { return _SelectedItemInfo; } set { _SelectedItemInfo = value; ItemSelectionChangeShown = false; //OnItemSelectedChanged has not run yet. SelectedEditItem.ItemSelect(); if (!ItemSelectionChangeShown) OnItemSelectedChanged(this, new ItemSelectedChangedEventArgs(SelectedEditItem)); } } public EditItem GetEditItem(ItemInfo itemInfo) { ExpandAsNeeded(itemInfo); if (_SelectedItemInfo == null) _SelectedItemInfo = itemInfo; if (itemInfo.Moving) { Reset(itemInfo); itemInfo.Moving = false; } else if ( !_LookupEditItems.ContainsKey(itemInfo.ItemID)) Reset(itemInfo); if (!_LookupEditItems.ContainsKey(itemInfo.ItemID)) return null; return _LookupEditItems[itemInfo.ItemID]; } public bool DisplayItemChanging { get; set; } = false; /// /// Returns the SelectedEditItem /// private EditItem _SelectedEditItem; public EditItem SelectedEditItem { get { return _SelectedEditItem; } set { EditItem newFocus = null; // B2018-152 when empty step is deleted, will contain the new step element focus bool deletingParent = false; // B2018-152 used to tell us user clicked on subtep of step element who's text was removed (special case) EditItem lastEI = _SelectedEditItem; value?.SetActive(); // Set the active color if (lastEI == value) return; // Same - No Change // B2018-002 - Invalid Transitions - If the current step contains an invalid transition convert it to text if(value != null) ItemInfo.ConvertInvalidTransitionsToText(value.MyItemInfo); if (lastEI != null && lastEI.BeingDisposed == false) { // B2019-139 if a procedure with out a title, or a section without a title, don't try to delete when you are moving off of the title while in the step editor bool shouldDelete = !lastEI.BeingRemoved && lastEI.Empty && (lastEI.MyItemInfo.MyContent.ContentEntryCount <= 0) && !_SelectedItemInfo.IsProcedure && !_SelectedItemInfo.IsSection; if (shouldDelete) { if (lastEI.HasChildren) { // B2018-152 Added a messagebox for when user clicks on a substep of a step element who's text was just deleted // Also made the message for when we ask about removing a step and its substeps more descriptive string msg1 = "Do you want to delete it and its substeps?"; string msg2 = "Select YES to remove the empty step"; string msg3 = "Select NO to keep the empty step which can be restored via the History tab on the Step Properties panel."; if (value != null && value.MyItemInfo.HasAncestor(lastEI.MyItemInfo)) { msg1 = $"This step does not have text but you had selected one of its substeps. {msg1}"; msg2 += " including the substep you had selected. You will be placed at the next location."; deletingParent = true; // B2018-152 this will tell us that the user selected a substep of a parent being deleted } else { msg1 = $"This step does not have text but has substeps. {msg1}"; msg2 += " and its substeps."; } DialogResult result = FlexibleMessageBox.Show($"{msg1}\n\n{msg2}\n\n{msg3}", "Verify Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.No) shouldDelete = false; } } if (shouldDelete) { // if this item has enhanced edititems, remove them. Note that this code supports // deleting text in an rtbitem that may be a step or section level. EnhancedDocuments eds = null; if (lastEI.MyItemInfo.MyConfig is StepConfig sc) eds = sc.MyEnhancedDocuments; else { // if a section, just the title or all contents may be linked. If just title, // don't delete enhanced, but clear links back from enhanced. if (lastEI.MyItemInfo.IsSection) { if (lastEI.MyItemInfo.MyConfig is SectionConfig sec) { if (sec.Section_LnkEnh == "Y") eds = sec.MyEnhancedDocuments; else lastEI.MyItemInfo.ClearEnhancedSectionLink(); } } } List enhIds = new List(); if (eds != null) { foreach (EnhancedDocument ed in eds) { if (ed.Type != 0) enhIds.Add(ed.ItemID); } } float oldTop = lastEI.Top; newFocus = lastEI.DeleteItem(); //B2018-152 made "newFocus" available outside this IF statement if (newFocus == null) { lastEI.RefreshContent(); return; } float newTop = newFocus.Top; lastEI.Dispose(); newFocus.SetAllTabs(); // If the step being deleted appears above the step to recieve focus, find another step // to use so that the steps are positioned properly (vertically) if (oldTop < newTop) { if (newFocus.MyParentEditItem != null) { if (newFocus.Top > newFocus.MyParentEditItem.Top) newFocus.MyParentEditItem.AdjustLocation(); else if (newFocus.MyParentEditItem.MyPreviousEditItem != null && newFocus.Top > newFocus.MyParentEditItem.MyPreviousEditItem.Top) newFocus.MyParentEditItem.MyPreviousEditItem.AdjustLocation(); else if (newFocus.MyParentEditItem.MyParentEditItem != null && newFocus.Top > newFocus.MyParentEditItem.MyParentEditItem.Top) newFocus.MyParentEditItem.MyParentEditItem.AdjustLocation(); else newFocus.AdjustLocation(); } else if (newFocus.MyPreviousEditItem != null) newFocus.MyPreviousEditItem.AdjustLocation(); else newFocus.AdjustLocation(); } else newFocus.AdjustLocation(); foreach (int enhId in enhIds) { ItemInfo ii = ItemInfo.Get(enhId); bool success = MyStepTabPanel.MyDisplayTabControl.DeleteRTBItem(ii); if (!success) // item was not displayed in editor, just delete from database (add tree if necessarY) Item.DeleteItemAndChildren(ii); } } else { lastEI.SaveContents(); if (!(lastEI.MyItemInfo.IsTable)) lastEI.RefreshDisplay(false); } } //B2018-152 if we are deleteing a step element that has substeps and the user click on one of those substep, // use resulting focus position returned from lastEI.DeleteItem() instead of current "value" if (deletingParent && newFocus != null) value = newFocus; _SelectedEditItem = value; if (MyStepTabPanel != null) MyStepTabPanel.MyStepTabRibbon.MyEditItem = value;// Update StepTabRibbon.MyEditItem to match if (value != null) { _SelectedEditItem.RefreshDisplay(true); if (_SelectedItemInfo.ItemID != value.MyItemInfo.ItemID) { ExpandAsNeeded(value.MyItemInfo); SelectedItemInfo = value.MyItemInfo; } } lastEI?.IdentifyMe(false); } } /// /// Displays the selected EditItem /// public void ItemShow() { if (_SelectedEditItem != null && SelectedEditItem.BeingDisposed == false) { SelectedEditItem.ItemShow(); OnItemSelectedChanged(this, new ItemSelectedChangedEventArgs(SelectedEditItem)); } } public new void MouseWheel(MouseEventArgs e) => base.OnMouseWheel(e); /// /// Used to track movement other than scrolling /// 0 - Indicates no other movement /// > 0 - Indicates that other movement is happening /// public int ItemMoving { get; set; } = 0; /// /// Lazy loaded StepPanelSettings /// public StepPanelSettings MyStepPanelSettings { get { if (_MyStepPanelSettings == null) _MyStepPanelSettings = new StepPanelSettings(this); return _MyStepPanelSettings; } set { _MyStepPanelSettings = value;} } /// /// Gets or Sets the font for the Panel /// public Font MyFont { get { return _MyFont; } set { ProcFont = SectFont = StepFont = _MyFont = value; } } /// /// Gets or sets the font for the Procedure Text /// public Font ProcFont { get; set; } = new Font("Arial", 12, FontStyle.Bold); /// /// Gets or sets the font for the Section Text /// public Font SectFont { get; set; } = new Font("Arial", 10, FontStyle.Bold); /// /// Gets or sets the Step Font /// public Font StepFont { get; set; } = new Font("Arial", 10); /// /// Gets or Sets the Active Color for the Panel /// public Color ActiveColor { get { // C2015-028 Add Editorial Mode to PROMS Step Editor // if in Editorial Mode, use LightGreen background _ActiveColor = MyStepTabPanel != null && MyStepTabPanel.MyDisplayTabControl.IsInEditorialMode ? Color.LightGreen : Color.SkyBlue; return _ActiveColor; } set { _ActiveColor = value; } } /// /// Gets or Sets the Annotation backcolor for StepRTBs in the Panel /// public Color AnnotationColor { get; set; } = Color.FromArgb(255, 255, 128); /// /// Gets or sets the InActive Color for the Panel /// public Color InactiveColor { get; set; } = Color.Linen; /// /// Gets or sets the Tab Color /// public Color TabColor { get; set; } = Color.Beige; /// /// Gets or sets the Panel Color /// public Color PanelColor { get { return _PanelColor; } set { _PanelColor = value; BackColor = value; } } #endregion #region DisplayConversions /// /// gets a Graphic object for the panel /// public Graphics MyGraphics { get { if (_MyGraphics == null) _MyGraphics = CreateGraphics(); return _MyGraphics; } } /// /// Gets the DPI setting for the current graphics setting /// internal int DPI { get { if (_DPI == 0) _DPI = Convert.ToInt32(MyGraphics.DpiX); return _DPI; } } /// /// Converts an integer value from Twips to Pixels /// /// /// public int ToDisplay(int value) => (DPI * value) / 72; public int ToDisplay(float? value) => (int)(DPI * (value ?? 0)) / 72; /// /// Converts an integer? value from Twips to Pixels /// /// /// public int ToDisplay(int? value) => ToDisplay((int)value); /// /// Converts an string value from Twips to Pixels /// /// /// public int ToDisplay(string value) => ToDisplay(Convert.ToSingle(value)); /// /// Converts a value from a list in a string from Twips to Pixels /// /// /// public int ToDisplay(string value,int i) { if (i < 0) return 0; string s = value.Split(",".ToCharArray())[i]; return ToDisplay(s); } #endregion #region Debug Methods /// /// Gets or sets ShowLines so that vertical lines are shown for debugging purposes /// public bool ShowLines { get; set; } = true; /// /// Toggle the vertical lines on and off /// /// /// private void StepPanel_DoubleClick(object sender, EventArgs e) { ShowLines = !ShowLines; Refresh(); } #endregion #region Cursor Movement Methods /// /// Finds the Displayed 'top' child for a given item. Used for down arrow. /// /// ItemInfo /// private ItemInfo TopPart(ItemInfo ii) { ExpandAsNeeded(ii); if (ii.Cautions != null && ii.Cautions.Count > 0) return TopPart(ii.Cautions[0]); if (ii.Notes != null && ii.Notes.Count > 0) return TopPart(ii.Notes[0]); return (ii); } /// /// Finds the Displayed 'bottom' child for a given item. Used for up arrow. /// /// ItemInfo /// private ItemInfo BottomPart(ItemInfo ii) { ExpandAsNeeded(ii); if (ii.RNOs != null && ii.RNOs.Count > 0 && ii.RNOLevel >= ii.ColumnMode) return BottomPart(ii.RNOs[0]); if (ii.Sections != null && ii.Sections.Count > 0) return BottomPart(ii.Sections[0].LastSibling); if (ii.Steps != null && ii.Steps.Count > 0) return BottomPart(ii.Steps[0].LastSibling); if (ii.Tables != null && ii.Tables.Count > 0) return BottomPart(ii.Tables[0].LastSibling); return ii; } /// /// Supports cursor movement between richtext boxes, including arrow keys/page up,down/ /// ctrl Home,End /// /// StepRTB /// Point /// E_ArrowKeys [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0059:Unnecessary assignment of a value", Justification = "Values assigned to ItemInfo ii for Debugging")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Point position kept for consistancy")] public void CursorMovement(EditItem ei, Point position, E_ArrowKeys arrow) { ItemInfo ii = null; // The following lines are debug to check that the results of moving down and moving up are the same //ItemInfo ix = null; switch (arrow) { case E_ArrowKeys.Up: case E_ArrowKeys.CtrlUp: ii = ArrowUp(ei.MyItemInfo); // The following lines are debug to check that the results of moving down and moving up are the same //ix = ArrowDown(ii); //Console.WriteLine("'Up',{0},{1},{2},{3}", rtb.MyItemInfo.ItemID, rtb.MyItemInfo.DBSequence, ii.DBSequence, ix.DBSequence); if (ii != null) SelectedEditItem = _LookupEditItems[ii.ItemID]; break; case E_ArrowKeys.Down: case E_ArrowKeys.CtrlDown: ii = MoveDown(ei, ii); break; case E_ArrowKeys.Right: case E_ArrowKeys.CtrlRight: if (!ei.MyItemInfo.IsInRNO && ei.MyItemInfo.RNOs != null) SelectedEditItem = _LookupEditItems[ei.MyItemInfo.RNOs[0].ItemID]; else ii = MoveDown(ei, ii); break; case E_ArrowKeys.Left: if (!ei.MyItemInfo.IsProcedure) { ii = ArrowUp(ei.MyItemInfo); if (ii != null) { ItemInfo tmpII = ii; while (!ei.MyItemInfo.IsInRNO && tmpII.RNOs != null) tmpII = GetLowestRNOEditItem(tmpII, ei.MyItemInfo); if (tmpII != ei.MyItemInfo) ii = tmpII; SelectedEditItem = _LookupEditItems[ii.ItemID]; } } break; case E_ArrowKeys.CtrlLeft: // this logic is same as in 16-bit VE-PROMS if (!ei.MyItemInfo.IsProcedure) SelectedEditItem = _LookupEditItems[ei.MyItemInfo.MyParent.ItemID]; break; default: break; } } // This is used for the Left Arrow key when we move off the current edit window private ItemInfo GetLowestRNOEditItem(ItemInfo newII, ItemInfo startII) { EditItem tmpEI = _LookupEditItems[newII.RNOs[newII.RNOs.Count - 1].ItemID]; ItemInfo tmpII = tmpEI.MyItemInfo; while (tmpII != startII && tmpII.RNOs != null) { tmpEI = _LookupEditItems[tmpII.RNOs[tmpII.RNOs.Count - 1].ItemID]; tmpII = tmpEI.MyItemInfo; } if (tmpII != startII && tmpEI.MyAfterEditItems != null) tmpEI = tmpEI.MyAfterEditItems[tmpEI.MyAfterEditItems.Count - 1]; return tmpEI.MyItemInfo; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "ItemInfo ii Kept for Debugging")] private ItemInfo MoveDown(EditItem ei, ItemInfo ii) { ii = ArrowDown(ei.MyItemInfo); // The following lines are debug to check that the results of moving down and moving up are the same //ix = ArrowUp(ii); //Console.WriteLine("'Down',{0},{1},{2},{3}", rtb.MyItemInfo.ItemID, rtb.MyItemInfo.DBSequence, ii.DBSequence, ix.DBSequence); if (ii != null) SelectedEditItem = _LookupEditItems[ii.ItemID]; return ii; } private ItemInfo ArrowUp(ItemInfo ii) { // Arrow-Up from a Substep should look for a Table. if (ii.IsStepPart && (ii.MyPrevious == null) && (ii.ActiveParent as ItemInfo).Tables != null) return BottomPart((ii.ActiveParent as ItemInfo).Tables[0]); // if on RNO, check display mode (1 column/2 column, etc) and how deep RNO is before going to // parents substeps. if (ii.IsRNOPart && ii.MyParent.Steps != null && ii.RNOLevel >= ii.ColumnMode) return BottomPart(ii.MyParent.Steps[0].LastSibling); // If on top note and parent has cautions - go to bottom caution if (ii.IsFirstNotePart && ii.MyParent != null && ii.MyParent.Cautions != null) return BottomPart(ii.MyParent.Cautions[0].LastSibling); if (ii.IsFirstCautionPart || ii.IsFirstNotePart) { if (ii.MyParent.MyPrevious != null) return BottomPart(ii.MyParent.MyPrevious); return ii.MyParent.MyParent; } // If has note, BottomPart of last sibling of the note if (ii.Notes != null) return BottomPart(ii.Notes[0].LastSibling); // If has caution, BottomPart of last sibling of the caution if (ii.Cautions != null) return BottomPart(ii.Cautions[0].LastSibling); // If previous sibling, BottomPart of previous sibling if (ii.MyPrevious != null && ii.IsProcedure == false) return BottomPart(ii.MyPrevious); // Go to parent until at procedure if (!ii.IsProcedure) return (ii.MyParent); return null; } private ItemInfo ArrowDown(ItemInfo ii) => ArrowDown(ii, true, true); private ItemInfo ArrowDown(ItemInfo ii, bool lookAtSub, bool lookAtRNO) { if (ii.IsSection || ii.IsProcedure) { if (lookAtSub && ii.Sections != null) return TopPart(ii.Sections[0]); if (lookAtSub && ii.Steps != null) return TopPart(ii.Steps[0]); ItemInfo nxt = ii.GetNext(); if (nxt != null) return TopPart(nxt); } else { // Subitems - go to top part of subitem // (the lookAtSub prevented looping within a substep group at same level) // Arrow down from a Table should look for a Substep if(ii.IsTablePart && (ii.ActiveParent as ItemInfo).Steps != null) return TopPart((ii.ActiveParent as ItemInfo).Steps[0]); // if this is enhanced background, the RNO is displayed after the HLS, so check // for this, arrow down should go to the RNO. If on the RNO, then go to substeps if they exist. if (((ii.ActiveFormat.PlantFormat.FormatData.PurchaseOptions.Value & E_PurchaseOptions.EnhancedBackgrounds) == E_PurchaseOptions.EnhancedBackgrounds)) { if (lookAtRNO && ii.RNOs != null) return TopPart(ii.RNOs[0]); if (ii.IsRNOPart && ii.MyHLS.Steps != null) return TopPart(ii.MyHLS.Steps[0]); } if (lookAtSub && ii.Tables != null) return TopPart(ii.Tables[0]); if (lookAtSub && ii.Steps != null) return TopPart(ii.Steps[0]); // RNOs: Use PMode (column) if (lookAtRNO && ii.RNOs != null && ii.RNOLevel >= ii.ColumnMode) return TopPart(ii.RNOs[0]); // Nextsibling - go to top part of sibling // TODO: RHM - NextItems was not null when it should have been after delete of a note below a caution ItemInfo nxt = ii.GetNext(); if (nxt != null) return TopPart(nxt); // If on caution, if parent has note - go to note if (ii.IsCautionPart && ii.MyParent.Notes != null) return ii.MyParent.Notes[0]; // If on caution, if parent !has note or if on note go to parent if ((ii.IsCautionPart && ii.MyParent.Notes == null) || ii.IsNotePart) return ii.MyParent; // Recursively call with parent until at procedure if (!ii.IsProcedure) return (ArrowDown(ii.MyParent, false, ii.MyParent.RNOLevel==ii.RNOLevel)); } return null; } internal void StepCursorKeys(EditItem ei, KeyEventArgs keyargs) { ItemInfo ii = ei.MyItemInfo; if (ii.IsSection || ii.IsProcedure) return; while (!ii.IsHigh) { ii = ii.MyParent; } switch (keyargs.KeyCode) { // for home/end, control key must be pressed too, but this is checked // before here. case Keys.Home: ii = ii.FirstSibling; break; case Keys.End: ii = ii.LastSibling; break; case Keys.PageDown: ii = ii.GetNext(); break; case Keys.PageUp: ii = ii.MyPrevious; break; } if (ii == null) return; SelectedEditItem = _LookupEditItems[ii.ItemID]; } #endregion } [TypeConverter(typeof(ExpandableObjectConverter))] public partial class StepPanelSettings { public StepPanelSettings(StepPanel panel) => MyStepPanel = panel; public StepPanelSettings() { } [Browsable(false)] public StepPanel MyStepPanel { get; set; } private float _CircleXOffset = -4; [Category("Circle")] [DisplayName("Circle Horizontal Offset")] public float CircleXOffset { get { return _CircleXOffset; } set { _CircleXOffset = value; MyStepPanel?.Refresh(); } } private float _CircleYOffset = -13; [Category("Circle")] [DisplayName("Circle Vertical Offset")] public float CircleYOffset { get { return _CircleYOffset; } set { _CircleYOffset = value; MyStepPanel?.Refresh(); } } private Color _CircleColor = Color.Black; [Category("Circle")] [DisplayName("Circle Color")] public Color CircleColor { get { return _CircleColor; } set { _CircleColor = value; MyStepPanel?.Refresh(); } } private int _CircleDiameter = 25; [Category("Circle")] [DisplayName("Circle Diameter")] public int CircleDiameter { get { return _CircleDiameter; } set { _CircleDiameter = value; MyStepPanel?.Refresh(); } } private int _CircleWeight = 2; [Category("Circle")] [DisplayName("Circle Pen Weight")] public int CircleWeight { get { return _CircleWeight; } set { _CircleWeight = value; MyStepPanel?.Refresh(); } } private float _NumberLocationX = 20F; [Category("Number")] [DisplayName("Number Location X")] public float NumberLocationX { get { return _NumberLocationX; } set { _NumberLocationX = value; MyStepPanel?.Refresh(); } } private float _NumberLocationY = 4; [Category("Number")] [DisplayName("Number Location Y")] public float NumberLocationY { get { return _NumberLocationY; } set { _NumberLocationY = value; MyStepPanel?.Refresh(); } } private SizeF _NumberSize = new SizeF(200F, 23F); [Category("Number")] [DisplayName("Number Size")] public SizeF NumberSize { get { return _NumberSize; } set { _NumberSize = value; MyStepPanel?.Refresh(); } } private int _TableWidthAdjust = 4; [Category("Table")] [DisplayName("Table Width Adjust")] public int TableWidthAdjust { get { return _TableWidthAdjust; } set { _TableWidthAdjust = value; MyStepPanel?.Refresh(); } } private int _CheckOffWeight = 1; [Category("CheckOff")] [DisplayName("CheckOff Pen Weight")] public int CheckOffWeight { get { return _CheckOffWeight; } set { _CheckOffWeight = value; MyStepPanel?.Refresh(); } } private Color _CheckOffColor = Color.Black; [Category("CheckOff")] [DisplayName("CheckOff Color")] public Color CheckOffColor { get { return _CheckOffColor; } set { _CheckOffColor = value; MyStepPanel?.Refresh(); } } private int _CheckOffSize =12; [Category("CheckOff")] [DisplayName("CheckOff Size")] public int CheckOffSize { get { return _CheckOffSize; } set { _CheckOffSize = value; MyStepPanel?.Refresh(); } } private int _CheckOffX =0; [Category("CheckOff")] [DisplayName("CheckOff X")] public int CheckOffX { get { return _CheckOffX; } set { _CheckOffX = value; MyStepPanel?.Refresh(); } } private int _CheckOffY =5; [Category("CheckOff")] [DisplayName("CheckOff Y")] public int CheckOffY { get { return _CheckOffY; } set { _CheckOffY = value; MyStepPanel?.Refresh(); } } private int _ChangeBarWeight = 1; [Category("ChangeBar")] [DisplayName("ChangeBar Pen Weight")] public int ChangeBarWeight { get { return _ChangeBarWeight; } set { _ChangeBarWeight = value; MyStepPanel?.Refresh(); } } private Color _ChangeBarColor = Color.Black; [Category("ChangeBar")] [DisplayName("ChangeBar Color")] public Color ChangeBarColor { get { return _ChangeBarColor; } set { _ChangeBarColor = value; MyStepPanel?.Refresh(); } } } public partial class StepPanelEventArgs { public EditItem MyEditItem { get; set; } public MouseEventArgs MyMouseEventArgs { get; set; } public StepPanelEventArgs(EditItem myEditItem, MouseEventArgs myMouseEventArgs) { MyEditItem = myEditItem; MyMouseEventArgs = myMouseEventArgs; } } public partial class ItemSelectedChangedEventArgs { public ItemInfo MyItemInfo { get; set; } public EditItem MyEditItem { get; set; } = null; public ItemSelectedChangedEventArgs(ItemInfo myItemInfo) { MyItemInfo = myItemInfo; } public ItemSelectedChangedEventArgs(EditItem myEditItem) { MyItemInfo = myEditItem?.MyItemInfo; MyEditItem = myEditItem; } } public partial class StepPanelAttachmentEventArgs { public EditItem MyEditItem { get; set; } public StepPanelAttachmentEventArgs(EditItem myEditItem) { MyEditItem = myEditItem; } } public partial class StepPanelLinkEventArgs : EventArgs { public string LinkInfoText { get; } public LinkText MyLinkText { get; } public StepPanelLinkEventArgs(string linkInfoText) { LinkInfoText = linkInfoText; MyLinkText = new LinkText(LinkInfoText); //for Debugging: linkInfo.LinkText } } public partial class StepPanelTabDisplayEventArgs : EventArgs { public string PanelTabName { get; } public StepPanelTabDisplayEventArgs(string panelTabname) => PanelTabName = panelTabname; } public partial class WordSectionEventArgs : EventArgs { public SectionInfo MySectionInfo { get; } public WordSectionEventArgs(SectionInfo mySectionInfo) { MySectionInfo = mySectionInfo; } } public delegate void StepPanelEvent(object sender, StepPanelEventArgs args); public delegate void ItemSelectedChangedEvent(object sender, ItemSelectedChangedEventArgs args); public delegate void StepPanelLinkEvent(object sender, StepPanelLinkEventArgs args); public delegate void StepPanelAttachmentEvent(object sender, StepPanelAttachmentEventArgs args); public delegate void StepRTBLinkEvent(object sender, StepPanelLinkEventArgs args); public delegate void StepPanelModeChangeEvent(object sender, StepRTBModeChangeEventArgs args); public delegate void StepPanelTabDisplayEvent(object sender, StepPanelTabDisplayEventArgs args); public delegate void StepPanelWordSectionCloseEvent(object sender, WordSectionEventArgs args); public delegate void StepPanelWordSectionDeletedEvent(object sender, WordSectionEventArgs args); public delegate void StepPanelItemPastedEvent(object sender, vlnTreeItemInfoPasteEventArgs args); }