using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using VEPROMS.CSLA.Library; using Volian.Base.Library; using JR.Utils.GUI.Forms; namespace Volian.Controls.Library { public delegate void StepRTBEvent(object sender, EventArgs args); public delegate void StepRTBCursorKeysEvent(object sender, KeyEventArgs args); public delegate void StepRTBCursorMovementEvent(object sender, StepRTBCursorMovementEventArgs args); public delegate void StepRTBModeChangeEvent(object sender, StepRTBModeChangeEventArgs args); public delegate void StepRTBMenuEvent(object sender, StepRTBMenuEventArgs args); public delegate void StepRTBTableWidthEvent(object sender, StepRTBTableWidthEventArgs args); public delegate bool StepRTBBooleanEvent(object sender, EventArgs args); public delegate void StepRTBLocationEvent(object sender, StepRTBLocationEventArgs args); public delegate void StepRTBMouseEvent(object sender, MouseEventArgs args); public delegate void StepRTBRoEvent(object sender, StepRTBRoEventArgs args); //public delegate void StepRTBMouseWheelEvent(object sender, MouseEventArgs args); public partial class StepRTB : RichTextBox // , IStepRTB { private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private bool _Disposed = false; private static int _CountCreated = 0; private static int _CountDisposed = 0; private static int _CountFinalized = 0; private static int IncrementCountCreated { get { return ++_CountCreated; } } private int _CountWhenCreated = IncrementCountCreated; public static int CountCreated { get { return _CountCreated; } } public static int CountNotDisposed { get { return _CountCreated - _CountDisposed; } } public static int CountNotFinalized { get { return _CountCreated - _CountFinalized; } } private bool _Finalized = false; ~StepRTB() { if (!_Finalized) _CountFinalized++; _Finalized = true; } #region Events public event StepRTBRoEvent RoInsert; public void OnRoInsert(object sender, StepRTBRoEventArgs args) { if (RoInsert != null) RoInsert(sender, args); } public event StepRTBEvent ReturnToEditor; public void OnReturnToEditor(object sender, EventArgs args) { if (ReturnToEditor != null) ReturnToEditor(sender, args); } public event StepRTBEvent EditModeChanged; public void OnEditModeChanged(object sender, EventArgs args) { if (EditModeChanged != null) EditModeChanged(sender, args); } public event StepRTBEvent DoSaveContents; public void OnDoSaveContents(object sender, EventArgs args) { if (DoSaveContents != null) DoSaveContents(sender, args); } public event StepRTBMouseEvent DoMouseWheel; public void OnDoMouseWheel(object sender, MouseEventArgs args) { if (DoMouseWheel != null) DoMouseWheel(sender, args); } public event StepRTBLocationEvent OpenContextMenu; public void OnOpenContextMenu(object sender, StepRTBLocationEventArgs args) { if (OpenContextMenu != null) OpenContextMenu(sender, args); } public event StepRTBEvent CopyStep; public void OnCopyStep(object sender, EventArgs args) { if (CopyStep != null) CopyStep(sender, args); } public event StepRTBBooleanEvent CheckClipboard; public bool OnCheckClipboard(object sender, EventArgs args) { if (CheckClipboard != null) return CheckClipboard(sender, args); return false; } public event StepRTBCursorKeysEvent EnterKeyPressed; public void OnEnterKeyPressed(object sender, KeyEventArgs args) { if (EnterKeyPressed != null) EnterKeyPressed(sender, args); } public event StepRTBEvent ToggleChangeBar; // shortcut key public void OnToggleChangeBar(object sender, EventArgs args) { if (ToggleChangeBar != null) ToggleChangeBar(sender, args); } public event StepRTBEvent ToggleContinuousActionSummary; // shortcut key public void OnToggleContinuousActionSummary(object sender, EventArgs args) { if (ToggleContinuousActionSummary != null) ToggleContinuousActionSummary(sender, args); } public event StepRTBEvent TogglePlaceKeeper; // shortcut key public void OnTogglePlaceKeeper(object sender, EventArgs args) { if (TogglePlaceKeeper != null) TogglePlaceKeeper(sender, args); } public event StepRTBEvent TogglePlaceKeeperContAct; // shortcut key public void OnTogglePlaceKeeperContAct(object sender, EventArgs args) { if (TogglePlaceKeeperContAct != null) TogglePlaceKeeperContAct(sender, args); } public event StepRTBEvent ToggleSuperScript; // shortcut key <=> public void OnToggleSuperScript(object sender, EventArgs args) { if (ToggleSuperScript != null) ToggleSuperScript(sender, args); } public event StepRTBEvent ToggleSubScript; // shortcut key <=> public void OnToggleSubScript(object sender, EventArgs args) { if (ToggleSubScript != null) ToggleSubScript(sender, args); } public event StepRTBEvent InsertPgBrk; // short key public void OnInsertPgBrk(object sender, EventArgs args) { if (InsertPgBrk != null) InsertPgBrk(sender, args); } public event StepRTBEvent OpenAnnotations; public void OnOpenAnnotations(object sender, EventArgs args) { if (OpenAnnotations != null) OpenAnnotations(sender, args); } public event StepRTBBooleanEvent IsNotCurrentSelection; public bool OnIsNotCurrentSelection(object sender, EventArgs args) { if (IsNotCurrentSelection != null) return IsNotCurrentSelection(sender, args); return false; } public event StepRTBTableWidthEvent AdjustTableWidth; public void OnAdjustTableWidth(object sender, StepRTBTableWidthEventArgs args) { if (AdjustTableWidth != null) AdjustTableWidth(sender, args); } public event StepRTBMenuEvent SetMenu; private void OnSetMenu(object sender, StepRTBMenuEventArgs args) { if (SetMenu != null) SetMenu(sender, args); } public event StepRTBEvent RTBSelectionChanged; private void OnRTBSelectionChanged(object sender, EventArgs args) { if (RTBSelectionChanged != null) RTBSelectionChanged(sender, args); } public event StepRTBEvent LinkLocationsChanged; private void OnLinkLocationChanged(object sender, EventArgs args) { if (LinkLocationsChanged != null) LinkLocationsChanged(sender, args); } public event StepRTBEvent RTBRangeStatusChanged; private void OnRTBRangeStatusChanged(object sender, EventArgs args) { if (RTBRangeStatusChanged != null) RTBRangeStatusChanged(sender, args); } public event StepRTBCursorKeysEvent CursorKeyPress; private void OnCursorKeyPress(object sender, KeyEventArgs args) { if (CursorKeyPress != null) CursorKeyPress(sender, args); } public event StepRTBCursorMovementEvent CursorMovement; private void OnCursorMovement(object sender, StepRTBCursorMovementEventArgs args) { if (CursorMovement != null) CursorMovement(sender, args); } //public event StepRTBModeChangeEvent ModeChange; //private void OnModeChange(object sender, StepRTBModeChangeEventArgs args) //{ // //_MyModeChangeEventArgs = args; // if (ModeChange != null) ModeChange(sender, args); // else MessageBox.Show("StepRTB - no mode change defined"); //} //public event StepRTBMouseWheelEvent MouseWheel; //private void OnMouseWheel(object sender, MouseEventArgs args) //{ // if (MouseWheel != null) MouseWheel(sender, args); //} /// /// This event is not raised during all the in-between changes for link deletions /// public event StepRTBEvent RTBTextChanged; private void OnRTBTextChanged(object sender, EventArgs args) { if (RTBTextChanged != null) RTBTextChanged(sender, args); } #endregion #region Properties and Variables public bool IsRoFigure { get { return (MyItemInfo.IsFigure && MyItemInfo.MyContent.MyImage == null); } } public bool IsRoTable { get { return (Parent is VlnFlexGrid && (Parent as VlnFlexGrid).IsRoTable); } } public bool HasVScroll { get { return RTBAPI.HasVertScroll(this); } } public bool HasHScroll { get { return RTBAPI.HasHorzScroll(this); } } private bool _EditMode = true; /// /// Allows insert of links. If false, don't allow selection of links. /// public bool EditMode { get { return _EditMode; } set { _EditMode = value; OnEditModeChanged(this, new EventArgs()); } } private DocVersionInfo _MyDVI = null; public DocVersionInfo MyDVI { get { ItemInfo procInfo = _MyItemInfo.MyProcedure as ItemInfo; if (procInfo == null) _MyDVI = null; else _MyDVI = procInfo.ActiveParent as DocVersionInfo; return _MyDVI; } } private static UserInfo _MyUserInfo = null; public static UserInfo MyUserInfo { get { return _MyUserInfo; } set { _MyUserInfo = value; } } private static string _MySymbolFontName; public static string MySymbolFontName { get { return StepRTB._MySymbolFontName; } set { StepRTB._MySymbolFontName = value; } } private static FontFamily _MyFontFamily = null; public static FontFamily MyFontFamily { get { return StepRTB._MyFontFamily; } set { _MyFontFamily = value; if (value != null) { Font font; if (value.IsStyleAvailable(FontStyle.Regular)) font = new Font(value, 10); else if (value.IsStyleAvailable(FontStyle.Bold)) font = new Font(value, 10, FontStyle.Bold); else // (value.IsStyleAvailable(FontStyle.Italic)) font = new Font(value, 10, FontStyle.Italic); using (StepRTB srtb = new StepRTB()) { if (srtb.FontIsFixed(font)) MySymbolFontName = "FreeMono"; // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing else MySymbolFontName = Volian.Base.Library.vlnFont.ProportionalSymbolFont; // C2017-036 get best available proportional font for symbols } } else { MySymbolFontName = null; } } } // use newer rich text box.... //[DllImport("kernel32.dll", CharSet = CharSet.Auto)] //static extern IntPtr LoadLibrary(string lpFileName); //protected override CreateParams CreateParams //{ // get // { // CreateParams prams = base.CreateParams; // if (LoadLibrary("msftedit.dll") != IntPtr.Zero) // { // //prams.ExStyle |= 0x020; // transparent // prams.ClassName = "RICHEDIT50W"; // } // return prams; // } //} private E_FieldToEdit _FieldToEdit = E_FieldToEdit.StepText; public E_FieldToEdit FieldToEdit { get { return _FieldToEdit; } set { _FieldToEdit = value; } } private string _RtfPrefix; // contains Font table and styles (bold/underline/italics) for rtb from step style public string RtfPrefixForSymbols { get { //B2020-100 RHM Use SelectionFont rather than the font from the format file. //if (_RtfPrefix == null) //{ StringBuilder selectedRtfSB = new StringBuilder(); //AddFontTable(selectedRtfSB, FormatFont, FontIsFixed(FormatFont)); // B2021-100: if SelectionFont is null, use the FormatFont AddFontTable(selectedRtfSB, SelectionFont==null?FormatFont:SelectionFont, FontIsFixed(FormatFont)); _RtfPrefix = selectedRtfSB.ToString(); //} return _RtfPrefix + @"\f1\fs" + FormatFont.SizeInPoints * 2 + " "; } } public string RtfPrefix { get { if (_RtfPrefix == null) { StringBuilder selectedRtfSB = new StringBuilder(); AddFontTable(selectedRtfSB, FormatFont, FontIsFixed(FormatFont)); _RtfPrefix = selectedRtfSB.ToString(); } return _RtfPrefix;// +@"{\colortbl ;\red255\green0\blue0;}"; } } // August 5, 2009 - KBR & RHM: // Insert/Overwrite will be developed later if needed. various issues // were found during initial development that made its scope larger than // expected. Problems were related to having overstrike on in the following // cases: // 1) left arrow when on link - positions after link // 2) left arrow and after link - does not move // 3) shift left arrow does not move past links correctly and also, first // shift left arrow looks more like insert mode. // private bool _OverWrite; // _IsDirty compares the original rtf to the current rtf from the // richtextbox to see if a change was made. public bool IsDirty { get { return OrigRTF != Rtf; } } private bool _InitializingRTB; private bool _IsExperimenting = false; public bool IsExperimenting { get { return _IsExperimenting; } set { _IsExperimenting = value; } } private IContainer _Container = null; private string _MyClassName=string.Empty; public string MyClassName { get { if (_MyClassName == string.Empty)_MyClassName = CreateParams.ClassName; return _MyClassName; } set { _MyClassName = value; } } //private E_EditPrintMode _epMode = E_EditPrintMode.Edit; //public E_EditPrintMode EpMode //{ // get { return _epMode; } // set { // if (value == E_EditPrintMode.Print) Console.WriteLine(""); // _epMode = value; } //} private E_ViewMode _vwMode = E_ViewMode.Edit; public E_ViewMode VwMode { get { return _vwMode; } set { _vwMode = value; } } private VE_Font _MyStyleFont; public VE_Font MyStyleFont { get { if (_MyStyleFont == null && MyItemInfo != null) _MyStyleFont = MyItemInfo.GetItemFont(); // B2017-023 null reference check for empty workdraft set information dialog return _MyStyleFont; } } private bool _ActiveMode = false; public bool ActiveMode { get { return _ActiveMode; } set { _ActiveMode = value; } } private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { if (_MyItemInfo == null && Parent is EditItem) _MyItemInfo = (Parent as EditItem).MyItemInfo; else if (_MyItemInfo == null && Parent != null && Parent.Parent is EditItem) _MyItemInfo = (Parent.Parent as EditItem).MyItemInfo; return _MyItemInfo; } set { _MyItemInfo = value; } } private string _OrigRTF; public string OrigRTF { get { return _OrigRTF; } set { _OrigRTF = value; } } private Font _FormatFont; public Font FormatFont { get { if (_FormatFont == null) { Font formatFont; if (MyItemInfo != null) formatFont = MyItemInfo.GetItemFont().WindowsFont; // OrigDisplayText.TextFont.WindowsFont; else formatFont = Font; if (MyItemInfo != null && (MyItemInfo.IsTable || MyItemInfo.IsFigure)) _FormatFont = formatFont; else { //if (VlnSettings.DebugMode || VlnSettings.ProductionMode) _FormatFont = new Font(MyFontFamily == null ? formatFont.FontFamily : MyFontFamily, formatFont.Size, formatFont.Style); //else // _FormatFont = new Font("Bookman Old Style", formatFont.Size, formatFont.Style); // TODO: Release Mode //Font = _origDisplayText.TextFont.WindowsFont; // font defined in plant's format } } // We found that the characters in the Letter Gothic font do not all use the same spacing. // Also, the character spacing is even more different between screen resolutions. // But the Letter Gothic font will print just fine. // We also found that the Letter Gothic Tall font works just fine on the screen, the only difference // is that the characters are a little bit taller. // So we decided to use the Letter Gothic Tall font for the screen display any time that Letter Gothic is used. if (_FormatFont.Name.ToUpper().Equals("LETTER GOTHIC")) _FormatFont = new Font("Letter Gothic Tall", _FormatFont.Size, _FormatFont.Style); return _FormatFont; } set { _FormatFont = value; } } public void SetupRichText(string rtf, VE_Font vFont) { //FormatFont = vFont.WindowsFont; DisplayText vlnText = new DisplayText(rtf, vFont, true); AddRtfText(vlnText.StartText); ReadOnly = true; } public void RefreshDisplay() { if (Closed) return; try { RefreshDisplay(ActiveMode); } catch (Exception ex) { _MyLog.Error(string.Format("MyItemInfo: {0} - {1} Problem doing RefreshDisplay",MyItemInfo.ItemID,MyItemInfo.ShortPath), ex); } } private static string FontKey(System.Drawing.Font font) { return string.Format("{0}_{1}_{2}", font.FontFamily.Name, font.Size, font.Style); } // RefreshDisplay is used to update the rtb for an entire Item as defined by MyItemInfo. public void RefreshDisplay(bool activeMode) { if (IsExperimenting) return; if (IsDisposed) return; ActiveMode = activeMode; OnAdjustTableWidth(this, new StepRTBTableWidthEventArgs(true)); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "RefreshDisplay 2"); _InitializingRTB = true; DisplayText vlntxt = new DisplayText(MyItemInfo, E_EditPrintMode.Edit, VwMode, !ActiveMode, FieldToEdit, true,null, null,false); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "RefreshDisplay 3"); //if (_origDisplayText != null && vlntxt.StartText == _origDisplayText.StartText) //{ // ReadOnly = !(EpMode == E_EditPrintMode.Edit && VwMode == E_ViewMode.Edit); // if (!ReadOnly && !edit) ReadOnly = true; // return; //} OrigDisplayText = vlntxt; //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "RefreshDisplay 4"); // RHM 20101201 - Don't reset the text. Calculate the text and compare it with the existing text in AddRTFText //Text = ""; // Initialize text before add text // IMPORTANT: SetLineSpacing must be set before Links, otherwise it // was confusing the 'handle' of the rtf box. //Console.WriteLine("'font',{0}", Font); //if(Text == "")SelectionFont = Font; // Initialize SelectionFont //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "1"); if (FieldToEdit == E_FieldToEdit.StepText) { if (MyItemInfo != null) { //if (MyItemInfo.IsStep) Font = MyFontFamily == null ? MyItemInfo.FormatStepData.Font.WindowsFont : new Font(MyFontFamily, MyItemInfo.FormatStepData.Font.WindowsFont.Size, MyItemInfo.FormatStepData.Font.WindowsFont.Style); //else Font = Font = MyFontFamily == null ? MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont : new Font(MyFontFamily, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont.Size, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont.Style); if (MyItemInfo.IsStep) { if (MyFontFamily == null) { //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "Before WindowsFont1"); System.Drawing.Font fnt = MyItemInfo.FormatStepData.Font.WindowsFont; //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After WindowsFont1a"); Application.DoEvents(); if (FontKey(Font) != FontKey(fnt)) Font = fnt; //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After WindowsFont1b"); } else Font = VE_Font.GetWinSysFont(MyFontFamily, MyItemInfo.FormatStepData.Font.WindowsFont.Size, MyItemInfo.FormatStepData.Font.WindowsFont.Style); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "RefreshDisplay 4"); } else { if (MyFontFamily == null) { //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "Before WindowsFont2"); Font = MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont; //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After WindowsFont2"); } else Font = VE_Font.GetWinSysFont(MyFontFamily, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont.Size, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font.WindowsFont.Style); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "RefreshDisplay 5"); } LastRtf = Rtf; } } //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "StepRTB.RefreshDisplay Before SetLineSpacing"); RTBAPI.SetLineSpacing(this, RTBAPI.ParaSpacing.PFS_EXACT); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "StepRTB.RefreshDisplay After SetLineSpacing"); bool readOnlyStep = MyItemInfo == null || MyItemInfo.FormatStepData == null ? false : MyItemInfo.FormatStepData.ReadOnly; if (!readOnlyStep) { StepConfig sc = new StepConfig(MyItemInfo.MyContent.Config); if (IsDerived(sc) && !MyItemInfo.EnhAllowMod()) readOnlyStep = true; } ReadOnly = readOnlyStep || VwMode == E_ViewMode.View || ActiveMode == false; //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "Before AddRTFText"); AddRtfText(vlntxt.StartText); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After AddRTFText"); //AddRtfStyles(); // set readonly based on initial modes, however, these may change if // user selected view mode. ClearUndo(); // RHM: 20101122 - Not sure why the RightMargin is set. The following line was added in Rev 23 // in May of 2008. // // RightMargin = Width; // // Normally a the Right Margin is handled by the RichTextBox it defaults to a value of 0. // // If the RightMargin is equal to the width of the RichTextBox the word-wrap occurs just beyond // the visible extent (right edge) of the RichTextBox when it is in view mode. In edit mode it // wraps within the visible extent. An example of this is Step 24 of ES02 in HLP EOPs. // // If the RightMargin is greater than the width of the RichTextBox, the word-wrap occurs beyond // the visible extent of the RichTextBox for both view and edit modes. // // Setting the RightMargin to the Width minus one, accounts for the slight indent (1 pixel) of // the text within the RichTextBox. //RightMargin = Width > 0 ? Width - 1 : 0; RightMargin = ActiveMode ? Width : Width > 0 ? Width - 1 : 0; // > 0 ? Width - 1 : 0; // figure out if needs outlined, depends on table/figure type if (!ActiveMode) { RemoveEventHandlers(); OnAdjustTableWidth(this, new StepRTBTableWidthEventArgs(false));// View Mode //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "Before SelectAll"); SelectAll(); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After SelectAll"); //if (SelectionHangingIndent !=0) SelectionHangingIndent = 0; int indchar = 0; string indentToken = MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.IndentToken; if (indentToken == null || indentToken == "0") indentToken = "\x5"; // this line of code was moved before the find for the indent so that // the window gets resized if the indent changes the height, i.e. more line(s) in window. AddEventHandlers(); //if (MyItemInfo.InList(186722)) Console.WriteLine("here"); if ((indchar = Find(indentToken, indchar, RichTextBoxFinds.None)) >= 0) { int nindents = 0; while ((indchar = Find(indentToken, indchar, RichTextBoxFinds.None)) >= 0) { nindents++; Point indent = GetPositionFromCharIndex(indchar); SelectionHangingIndent = indent.X; // RHM 02/20/2013 // The following line attempts to remove the indent character for display purposes. // However, if the indent is followed immediately by an RO or Transition the // RichTextBox will not allow the character to be removed this way and the RichTextBox // will beep. So, to keep from going in an infintie loop, the value of indchar is incremented. SelectedRtf = SelectedRtf.Replace(@"\'05", ""); indchar++;// Don't do the same one twice. } if (MyItemInfo != null && MyItemInfo.ActiveFormat != null && MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.DontResetIndentOnNewline) { if (nindents == 1) Rtf = Rtf.Replace("\\par\r\n", @"\line "); Rtf = Rtf.Replace(@"\line\pard", @"\line"); } } HideSelection = true; // fix for B2016-093: this is needed so an rtb that is not focused is not highlighted. } // This is to fix an issue with Hard Spaces. To Summarize: // The Microsoft RichTextBox has a problem with hardspaces, that they don't work between numbers and lettters // This is the majority of cases for PROMS including ROs (Sepoint Number and Units) and transtions (Step ###) // As I investigated this further I found that if you pass a rtf unicode value for a hard space (\u160?) to // the RichTextBox, the RichTextBox will return an ASCII representation (\'A0). If you pass an ASCII representation // the RichTextBox will return a space. // Alternatively, If you pass a unicode representation of zero (\u0?) it acts like a hard space and returns an ASCII // representation (\'00). If you pass in the ASCII representation, it truncates the text. // The following two lines replace hard spaces (ASCII) with the UNICODE represntation of Zero. // Lastly, If you pass a unicode representation of one (\u1?) it acts like a hard space and returns an ASCII // representation (\'01). If you pass in the ASCII representation, it keeps the ASCII representation. // The following two lines replace hard spaces (ASCII) with the UNICODE represntation of Zero. // Other characters which behave like hard spaces are 28-31 and 128-159. if (!activeMode && Rtf.Contains(@"\'a0")) { // The following 3 lines were added to fix B2016-069. The issue was in the RichTextBox for the Arial // (Proportional) font, the hardspace appeared to be 2 spaces (really it was showing the space as the widest // width character). So instead of a hard space, a single quote "'" was used to designate where the hardspace // would be. This is only used for display, printing works. //B2019-155 Hard spaces were displace as a square box for non-proportional fonts. // To fix this, we removed the check for a proportional font and now replace the hard space with a "'" mark for all fonts Rtf = Rtf.Replace(@"\'a0", "'"); } OrigRTF = Rtf; _InitializingRTB = false; AdjustSizeForContents(!ActiveMode); //Volian.Base.Library.HWndCounter.GetWindowHandlesForCurrentProcess(this.Handle, "After RefreshDisplay"); Application.DoEvents(); } private bool IsDerived(StepConfig sc) { foreach (EnhancedDocument ed in sc.MyEnhancedDocuments) if (ed.Type == 0) //New Design return true; return false; } private bool _ProcessKeystrokes = true; public bool ProcessKeystrokes { get { return _ProcessKeystrokes; } set { _ProcessKeystrokes = value; } } private Point ScrollPos { get { return RTBAPI.GetScrollLocation(this); } set { RTBAPI.SetScrollLocation(this, value); } } private Rectangle _ContentsRectangle = new Rectangle(0,0,0,0); public Rectangle ContentsRectangle { get { if (_ContentsRectangle.X == 0 && _ContentsRectangle.Y == 0 && _ContentsRectangle.Width == 0 && _ContentsRectangle.Height == 0) _ContentsRectangle = this.ClientRectangle; return _ContentsRectangle; } set { _ContentsRectangle = value; AdjustSizeForContents(false); } } public Size ContentsSize { get { return _ContentsRectangle.Size; } } private Size _AdjustSize = new Size(0,0); // if 0,0 puts text right next to bottom of box. public Size AdjustSize { get { return _AdjustSize; } set { _AdjustSize = value; AdjustSizeForContents(false); } } public System.Windows.Forms.AutoScaleMode AutoScaleMode; private DisplayText _OrigDisplayText; public DisplayText OrigDisplayText { get { return _OrigDisplayText; } set { _OrigDisplayText = value; } } private RichTextBox _rtbTemp = new RichTextBox(); private string _MyLinkText; public string MyLinkText { get { return _MyLinkText; } set { if (value != _MyLinkText) { //updates to the info panel were not always occurring when the previous two lines were active _MyLinkText = value; OnLinkChanged(this, new StepPanelLinkEventArgs(_MyLinkText)); } else { _MyLinkText = value; } } } #endregion #region Constructors public StepRTB() { InitializeComponent(); SetUpStepRTB(); AddEventHandlers(); this.BorderStyleChanged += new EventHandler(StepRTB_BorderStyleChanged); } public StepRTB(IContainer container) { container.Add(this); InitializeComponent(); _Container = container; SetUpStepRTB(); AddEventHandlers(); this.BorderStyleChanged += new EventHandler(StepRTB_BorderStyleChanged); } protected override void OnMouseWheel(MouseEventArgs e) { OnDoMouseWheel(this, e); //MyRTBItem.MyStepPanel.MouseWheel(e); //base.OnMouseWheel(e); } // When a border style is changed, the richtextbox's handle is 'destroyed', so that the handleDestroyed // event is done. This was causing the event handlers to be removed (RemoveEventHandler) so that the // keypress event handler was not run. public void RemoveEventHandlers() { if (_EventHandlersForKeyPress==0) return; ContentsResized -= new ContentsResizedEventHandler(StepRTB_ContentsResized); this.Click -= new EventHandler(StepRTB_Click); this.KeyPress -= new KeyPressEventHandler(StepRTB_KeyPress); this.KeyDown -= new KeyEventHandler(StepRTB_KeyDown); this.KeyUp -= new KeyEventHandler(StepRTB_KeyUp); this.TextChanged -= new EventHandler(StepRTB_TextChanged); this.MouseUp -= new MouseEventHandler(StepRTB_MouseUp); this.MouseDown -= new MouseEventHandler(StepRTB_MouseDown); this.MouseLeave -= new EventHandler(StepRTB_MouseLeave); this.SelectionChanged -= new EventHandler(StepRTB_SelectionChanged); this.ContextMenuStripChanged -= new EventHandler(StepRTB_ContextMenuStripChanged); this.RTBSelectionChanged -= new StepRTBEvent(StepRTB_RTBSelectionChanged); this.HandleCreated -= new EventHandler(StepRTB_HandleCreated); this.HandleDestroyed -= new EventHandler(StepRTB_HandleDestroyed); _EventHandlersForKeyPress = _EventHandlersForKeyPress - 1; } private int _EventHandlersForKeyPress = 0; // When a border style is changed, the richtextbox's handle is 'destroyed', so that the handleDestroyed // event is done. This was causing the event handlers to be removed (RemoveEventHandler) so that the // keypress event handler was not run. private void AddEventHandlers() { if (_EventHandlersForKeyPress>0) return; // Always be sure to add the same event handlers to RemoveEventHandlers BorderStyle = System.Windows.Forms.BorderStyle.None; this.DetectUrls = false; ContentsResized += new ContentsResizedEventHandler(StepRTB_ContentsResized); this.Click +=new EventHandler(StepRTB_Click); this.KeyPress += new KeyPressEventHandler(StepRTB_KeyPress); this.KeyDown += new KeyEventHandler(StepRTB_KeyDown); this.KeyUp += new KeyEventHandler(StepRTB_KeyUp); this.TextChanged += new EventHandler(StepRTB_TextChanged); this.MouseUp += new MouseEventHandler(StepRTB_MouseUp); this.MouseDown += new MouseEventHandler(StepRTB_MouseDown); this.MouseLeave += new EventHandler(StepRTB_MouseLeave); this.SelectionChanged +=new EventHandler(StepRTB_SelectionChanged); this.ContextMenuStripChanged += new EventHandler(StepRTB_ContextMenuStripChanged); this.RTBSelectionChanged += new StepRTBEvent(StepRTB_RTBSelectionChanged); this.HandleCreated += new EventHandler(StepRTB_HandleCreated); this.HandleDestroyed += new EventHandler(StepRTB_HandleDestroyed); _EventHandlersForKeyPress = _EventHandlersForKeyPress+1; } private int _HandleCount = 0; void StepRTB_HandleCreated(object sender, EventArgs e) { _HandleCount++; } // When a border style is changed, the richtextbox's handle is 'destroyed', so that the handleDestroyed // event is done. This was causing the event handlers to be removed (RemoveEventHandler) so that the // keypress event handler was not run. The following was added so that the keypress event is restored // after the border style was changed. This is specifically for the steprtb's on property pages. void StepRTB_BorderStyleChanged(object sender, EventArgs e) { if (_EventHandlersForKeyPress==0) this.KeyPress += new KeyPressEventHandler(StepRTB_KeyPress); _EventHandlersForKeyPress++; } private bool _Closed = false; public bool Closed { get { return _Closed; } set { _Closed = value; } } void StepRTB_HandleDestroyed(object sender, EventArgs e) { if (_HandleCount == 0) { Closed = true; RemoveEventHandlers(); } _HandleCount--; } void StepRTB_RTBSelectionChanged(object sender, EventArgs args) { //Console.WriteLine("RTBSelectionChanged id= {0}", MyItemInfo.ItemID); if (!Focused) Focus(); } void StepRTB_ContextMenuStripChanged(object sender, EventArgs e) { //Console.WriteLine("********** StepRTB_ContextMenuStripChanged"); int sublocation = 0; try { //Console.WriteLine("{0}", ContextMenuStrip.GetType().FullName); OnSetMenu(this, new StepRTBMenuEventArgs(null)); sublocation = 1; _ContextMenuStripChanged = true; sublocation = 2; _ContextMenuStepRTB = this; sublocation = 3; _ContextMenuStrip = ContextMenuStrip; sublocation = 4; } catch(Exception ex) { Console.WriteLine("StepRTB_ContextMenuStripChanged {0} - {1} [{2}]", ex.GetType().Name, ex.Message, sublocation); } } // Bug fix B2017-059, toggle the spellchecking status on only when being used - to control how many window handles are created by the spellchecker // This fixed the issue of the spell checker closing PROMS - Callaway SAMG Background TSG-1, also reproduced on long procedure in calvert EOPs private bool _SpellCheckStatus = false; public bool SpellCheckStatus { get { return _SpellCheckStatus; } set { if (_SpellCheckStatus != value) { _SpellCheckStatus = value; if (DoSpellCheck) C1SpellChecker2.SetActiveSpellChecking(this, value); } } } private void SetUpStepRTB() { DetectUrls = false; SpellCheckStatus = false; this.Height = 10; // initialize the height to 10, the default height was too big for the cells in grid tables BorderStyle = System.Windows.Forms.BorderStyle.None; this.ScrollBars = RichTextBoxScrollBars.None; this.DetectUrls = false; } // An event is needed to set MouseDown to false on mouse leave, because additional rtb's may // have been exposed based on entering a step, which causes the underlying item/rtb for which // the mouse event occurs to not be the current rtb. RTB gets selected on MouseDown, MouseEnter // and MouseUp are void StepRTB_MouseLeave(object sender, EventArgs e) { _MouseDown = false; } //void MyConfig_PropertyChanged(object sender, PropertyChangedEventArgs e) //{ // SaveConfig(); //} private void StepRTB_Click(object sender, EventArgs e) { if (ReadOnly) return; } // B2019-161 When tracking timing time this action private static VolianTimer _TimeActivity = new VolianTimer("StepRTB CloseWordApp_Tick", 902); void StepRTB_SelectionChanged(object sender, EventArgs e) { _TimeActivity.Open(); if (_InitializingRTB || _IsExperimenting || (MyItemInfo!=null && MyItemInfo.IsRtfRaw)) return; HandleSelectionChange(); _TimeActivity.Close(); } private bool _MouseDown = false; private bool _ContextMenuStripChanged = false; private void StepRTB_MouseDown(object sender, MouseEventArgs e) { //The following line fixes bugs B2016-121 and B2016-146 if(!Focused)this.Focus();// If it doesn't have focus, set focus to the selected item //Console.WriteLine("vvvvvvvvvv StepRTB Mouse Down id= {0}",MyItemInfo.ItemID); bool inPsi = this.Parent.FindForm().Name.Contains("frmPSI") || this.Parent.FindForm().Name.Contains("frmSI"); if (!_ContextMenuStripChanged) OnSetMenu(this, new StepRTBMenuEventArgs(inPsi?"PSI":"OpenContextMenu")); _ContextMenuStripChanged = false; CorrectSelectionAtEndOfLine(); // B2017-023 null reference check for empty workdraft set information dialog if (e.Button == System.Windows.Forms.MouseButtons.Right && (MyItemInfo == null || MyItemInfo.IsRtfRaw)) OnSetMenu(this, new StepRTBMenuEventArgs((MyItemInfo != null && MyItemInfo.IsRtfRaw)?"OpenRtfRawContextMenu":"PSI")); _MouseDown = true; } void StepRTB_MouseUp(object sender, MouseEventArgs e) { _MouseDown = false; //Console.WriteLine("^^^^^^^^^^ StepRTB Mouse Up id= {0}", MyItemInfo.ItemID); if(this.Focused) // Only HandleSelectionChange if this control has focus. { HandleSelectionChange(); // save our context menu to add to the spell checker's context menu ThisContextMenuStrip = this.ContextMenuStrip; // B2017-231 force the right mouse click to bring up word list if on a mis-spelled word if (e.Button == System.Windows.Forms.MouseButtons.Right && Parent is RTBItem) // right mouse click and we are not on a table cell { if (ThisContextMenuStrip != null) { (Parent as RTBItem).MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ClearContextMenu(); this.ContextMenuStrip.Show(this, e.X, e.Y); } else { (Parent as RTBItem).MyStepPanel.MyStepTabPanel.MyStepTabRibbon.OpenContextMenu(this.PointToScreen(e.Location), this); } } } } #endregion #region ApplicationSupport // Used in StepTabRibbon: //public void ToggleEditView(E_ViewMode vwMode) //{ // OnDoSaveContents(this, new EventArgs()); // SaveText(); // //ItemInfo tmp = MyItemInfo; // //MyItemInfo = null; // //ReadOnly = !ReadOnly; // //EpMode = ReadOnly ? E_EditPrintMode.Print : E_EditPrintMode.Edit; // VwMode = vwMode; // ReadOnly = VwMode == E_ViewMode.View; // ViewRTB = ReadOnly; // Clear(); // RefreshDisplay(!ViewRTB); // //MyItemInfo = tmp; // SelectionStart = 0; // SelectionLength = 0; // //OnModeChange(this, new StepRTBModeChangeEventArgs(ViewRTB?E_ViewMode.View:E_ViewMode.Edit)); //} //public string InsertSymbolInRO(string val) //{ // string retval = val; // C2019-043 convert a "->" to the Right Arrow symbol and a "<-" to the Left Arrow Symbol // note that at the dash character gets convert to a non-breaking hyphen "\u8209?" //if (MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.UseDashGreaterLessThenForArrowsInROValue) //{ // retval = retval.Replace("\\u8209?>", GetAddSymbolTextForROs(@"\u8594?")); // Right Arrow // retval = retval.Replace("<\\u8209?", GetAddSymbolTextForROs(@"\u8592?")); // Left Arrow //} //// C2022-021 convert a "<=" to a less than or equal symbol, a ">=" to a greather than or equal symbol and +- to a //// plus/minus symbol in ROs //if (MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.ConvertGTELTEPMinROValue) //{ // retval = retval.Replace("<=", GetAddSymbolTextForROs(@"\u8804?")); // Less than or Equal // retval = retval.Replace(">=", GetAddSymbolTextForROs(@"\u8805?")); // Greater than or Equal // retval = retval.Replace("+\\u8209?", @"\'b1"); // plus/minus - note - is stored as \u8209 and plus/minus is < 256, i.e. handled differently //} // return retval; //} public void InsertRO(string value, string link) { // B2023-037: Remove code that saves the unicode characters for <=, >=, +-, <- and -> into the link text. The characters // now get resolved when used. InsertSymbolInRo was commented out also AddRtfLink(value, link); } public void InsertTran(string value, string link) { AddRtfLink(value, link); } public void InsertSymbol(int symbcode) { string sym = string.Format(symbcode < 256 ? "\'{0:X2}" : @"\u{0}", symbcode); if (symbcode < 256) AddText(((char)symbcode).ToString()); else AddSymbol(sym); // Adds font commands around symbol, needed for higher codes } public void InsertSymbol(string symbol) { AddSymbol(symbol); } public void InsertIndent(string indentToken) { if (indentToken == null || indentToken == "0") indentToken = "\x5"; AddText(indentToken); } public void InsertText(string txt) { AddText(txt); } private void ToggleCase() { char type = 'l'; // do not change case on linked text RangeStatus rs = FindRangeStatus(); string tmp = null; if (rs != RangeStatus.NoContainedLinks) { int start = SelectionStart; int ostart = SelectionStart; int end = SelectionStart + SelectionLength; bool processed = false; while (!processed && start <= end) { foreach (LinkLocation ll in LinkLocations) { if (ll.Start >= start && ll.End <= end) { processed = true; if (start < ll.Start) { SelectionStart = start; SelectionLength = ll.Start - start; } start = ll.End + 1; break; } } } } string ostring = SelectedText; if (ostring.Length == 0) return; // nothing selected if (ostring.Length == 1) type = char.IsUpper(ostring, 0) ? 'l' : 'U'; else if ((char.IsUpper(ostring, 0) && char.IsUpper(ostring, 1)) || (char.IsLower(ostring, 0) && char.IsUpper(ostring, 1))) type = 'l'; // lower case else if ((char.IsUpper(ostring, 0) && char.IsLower(ostring, 1))) type = 'U'; // upper case else type = 'T'; // Title case SetSelectedCase(type); } public void SetSelectedCase(char type) { // do not change case on linked text RangeStatus rs = FindRangeStatus(); string tmp = null; if (rs == RangeStatus.NoContainedLinks) SetCase(type); else { int start = SelectionStart; int ostart = SelectionStart; int end = SelectionStart + SelectionLength; StringBuilder sb = new StringBuilder(); while (start <= end) { bool processed = false; foreach (LinkLocation ll in LinkLocations) { if (ll.Start >= start && ll.End <= end) { processed = true; if (start < ll.Start) { SelectionStart = start; SelectionLength = ll.Start - start; SetCase(type); } start = ll.End + 1; break; } } // if none were processed, no more links, copy over any remaining text. if (!processed) { SelectionStart = start; SelectionLength = end-start; SetCase(type); start = end + 1; } } SelectionStart = ostart; SelectionLength = end - ostart; } } private void SetCase(char type) { int ostart = SelectionStart; int olen = SelectionLength; string ostring = SelectedText; string tmp = null; bool docap = true; // go character by character. Because of symbols, setting entire // to upper or lower set symbols incorrectly some of time (depending // on symbol) . for (int i = 0; i < olen; i++) { SelectionStart = ostart + i; SelectionLength = 1; switch (type) { case 'l': if (SelectedText[0] >= 'A' && SelectedText[0] <= 'Z') SelectedText = SelectedText.ToLower(); break; case 'U': if (SelectedText[0] >= 'a' && SelectedText[0] <= 'z') SelectedText = SelectedText.ToUpper(); break; case 'T': if (docap && SelectedText[0] >= 'a' && SelectedText[0] <= 'z') SelectedText = SelectedText.ToUpper(); else if (!docap && SelectedText[0] >= 'A' && SelectedText[0] <= 'Z') SelectedText = SelectedText.ToLower(); docap = ostring[i] == ' '; break; } } SelectionStart = ostart; SelectionLength = olen; } #endregion #region AddRtfTextAndStyles private string _LastRtf = ""; public string LastRtf { get { return _LastRtf; } set { _LastRtf = value; } } private bool _lastReadOnly = false; public override string ToString() { return string.Format("[StepRTB {0},{1},{2}]", MyItemInfo.ItemID, MyItemInfo.DisplayNumber, MyItemInfo.DisplayText); } public void AddRtfText(string txt) { if (MyItemInfo != null && MyItemInfo.IsRtfRaw) { if (txt != null && txt != "") SelectedRtf = _LastRtf = txt; _lastReadOnly = ReadOnly; OrigRTF = txt; return; } //Console.WriteLine("ItemID:{0}", MyItemInfo.ItemID); //if(MyItemInfo.ItemID==10256) // Volian.Base.Library.vlnStackTrace.ShowStackLocal("ItemID:{0}", MyItemInfo.ItemID.ToString()); StringBuilder selectedRtfSB = new StringBuilder(); AddFontTable(selectedRtfSB, FormatFont, FontIsFixed(FormatFont)); _RtfPrefix = selectedRtfSB.ToString(); selectedRtfSB.Append(txt); string newRtf = selectedRtfSB.ToString() + "}"; if(newRtf != _LastRtf || ReadOnly != _lastReadOnly) { //Console.WriteLine("ItemID:{0}\r\nOld:'{1}'\r\nNew:'{2}'\r\n", MyItemInfo.ItemID, Rtf, newRtf); this.ContentsResized -= new ContentsResizedEventHandler(StepRTB_ContentsResized); Text = ""; this.ContentsResized += new ContentsResizedEventHandler(StepRTB_ContentsResized); // indents went from being handled by code support of an indent character (usually \05) to // using rtf commands to fix various indent bugs including B2015-103). The following code // puts the rtf indent characters that are stored at beginning of string into correct location // of rtf header (have to be after the \pard). Otherwise the indents did not show up. Match match = Regex.Match(txt,@"\\fi([-0-9]+) ?\\li([0-9]+)"); if (match.Success) { string indentStr = @"\fi" + match.Groups[1].Value + @"\li" + match.Groups[2].Value; Rtf = Rtf.Replace(@"\pard", @"\pard" + indentStr); } // B2017-048, B2017-052, B2017-055 ROs sometimes have two start tokens which make them uneditable. newRtf = newRtf.Replace(""); // return new Point(mcStart.Count, mcEnd.Count); //} public void SetTableGridCellRTFPrefix(Font myfont) { if (_FormatFont == null) _FormatFont = myfont; if (_RtfPrefix == null) { StringBuilder selectedRtfSB = new StringBuilder(); AddFontTable(selectedRtfSB, myfont, FontIsFixed(myfont)); _RtfPrefix = selectedRtfSB.ToString(); } } // The following code is used to display the little 'tic' marks to show indenting: private const int WM_PAINT = 15; protected override void WndProc(ref Message m) { if (m.Msg == WM_PAINT) { this.Invalidate(); base.WndProc(ref m); // B2015-135 Don't Show Hanging Indent if MyItemInfo is null if (MyItemInfo == null) return; if ((FieldToEdit == E_FieldToEdit.StepText) && (SelectionHangingIndent > 0 || SelectionIndent > 0) && (ActiveMode || MyItemInfo.IsTable)) { using (Graphics g = Graphics.FromHwnd(this.Handle)) { int size = 2; g.DrawLine(Pens.DarkBlue, SelectionIndent, 0, SelectionIndent + size, 0); g.DrawLine(Pens.DarkBlue, SelectionIndent, 2 * size, SelectionIndent, 0); g.DrawLine(Pens.DarkBlue, SelectionHangingIndent, Height - 1, SelectionHangingIndent + size, Height - 1); g.DrawLine(Pens.DarkBlue, SelectionHangingIndent, Height - 1 - 2 * size, SelectionHangingIndent, Height - 1); } } } else { try { base.WndProc(ref m); } catch (Exception ex) { } } } private static void AddFontTable(StringBuilder selectedRtfSB, Font myFont, bool isFixed) { StringBuilder sbbeg = new StringBuilder(); StringBuilder sbend = new StringBuilder(); if (myFont.Bold) { sbbeg.Append(@"\b"); sbend.Append(@"\b0"); } if (myFont.Underline) { sbbeg.Append(@"\ul"); sbend.Insert(0, @"\ulnone"); } if (myFont.Italic) { sbbeg.Append(@"\i"); sbend.Insert(0, @"\i0"); } selectedRtfSB.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset2 " + myFont.FontFamily.Name + @";}"); //}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}}"; if (!isFixed) selectedRtfSB.Append(@"{\f1\fnil\fcharset0 " + Volian.Base.Library.vlnFont.ProportionalSymbolFont + @";}}{\colortbl ;\red255\green0\blue0;}"); // C2017-036 get best available proportional font for symbols else selectedRtfSB.Append(@"{\f1\fnil\fcharset0 FreeMono;}}{\colortbl ;\red255\green0\blue0;}"); // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing selectedRtfSB.Append("\r\n"); // use styles to construct rtf commands to insert into next line (where \b, etc is) // B2015-134 Hanging Indent with Hard Returns was not being saved- removed \sl-240\slmult0 selectedRtfSB.Append(@"\viewkind4\uc1\pard" + sbbeg.ToString() + @"\fs" + Convert.ToInt32(myFont.SizeInPoints * 2).ToString() + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}"; //selectedRtfSB.Append(@"\viewkind4\uc1\pard\sl-240\slmult0" + sbbeg.ToString() + @"\fs" + Convert.ToInt32(myFont.SizeInPoints * 2).ToString() + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}"; } private bool FontIsFixed(Font myFont) { Graphics grph = Graphics.FromHwnd(this.Handle); SizeF sfW = grph.MeasureString("W", myFont); SizeF sfE = grph.MeasureString("!", myFont); if (sfW.Width == sfE.Width) return true; return false; } private void AddRtf(string str) { // Because we're inserting rtf with { }, the surrounding styles are not included. Get the font // style of current position & use it after the insert to set the style. RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this); int positionStart = SelectionStart; SelectedRtf = @"{\rtf1{\fonttbl{\f0\fcharset2 " + this.Font.FontFamily.Name + @";}}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + str + @"}}"; // Note that SelectedRtf does not contain the inserted text after the previous line. We need // to determine how long the inserted string is in order to set its style. SelectionStart contains // the location after the insertion. int positionAfter = SelectionStart; Select(positionStart, positionAfter - positionStart); RTBAPI.SetFontStyle(this, fs); Select(positionAfter, 0); } private void AddText(string str) { // See comments in AddRtf(string str) to explain the font style setting RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this); int positionStart = SelectionStart; SelectedText = str; int positionAfter = SelectionStart; Select(positionStart, positionAfter - positionStart); RTBAPI.SetFontStyle(this, fs); Select(positionAfter, 0); } private void AddSymbol(string str) { // See comments in AddRtf(string str) to explain the font style setting RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this); Font locfont = this.Font; int position = SelectionStart; // B2021-100: if SelectionFont is null set it, it is used in RtfPrefixForSymbols if (SelectionFont == null) { if (FieldToEdit == E_FieldToEdit.StepText && MyItemInfo!=null) SelectionFont = MyItemInfo.GetItemFont().WindowsFont; else SelectionFont = locfont; } SelectedRtf = RtfPrefixForSymbols + str + @"}"; Select(position, 1); Select(position + 1, 0); if (FieldToEdit == E_FieldToEdit.StepText) { SelectionFont = MyItemInfo.GetItemFont().WindowsFont; RTBAPI.SetFontStyle(this, fs);// B2020-100 Keep the font style } else // if doing properties for folder, docversion, proc or sect, don't get item's font. SelectionFont = locfont; } private string GetAddSymbolText(string symtxt) { return (@"{\f1\fs" + this.Font.SizeInPoints * 2 + @" " + symtxt + @"}"); // B2016-281 fixed font selection when inserting a symbol character } private string GetAddSymbolTextForROs(string symtxt) { return (@"\f1\fs" + this.Font.SizeInPoints * 2 + @" " + symtxt); //C2019-043 Don't need curly braces when used in RO return value } public void AddRtfLink(string linkUrl, string linkValue) { if (CreateParams.ClassName == "RICHEDIT50W") AddLink50(linkUrl, linkValue); else AddLink20(linkUrl, linkValue); } public string FontTable { get { StringBuilder sb = new StringBuilder(); sb.Append(@"{\fonttbl{\f0\fnil\fcharset2 " + this.Font.FontFamily.Name + @";}"); if (!FontIsFixed(this.Font)) sb.Append(@"{\f1\fnil\fcharset0 " + Volian.Base.Library.vlnFont.ProportionalSymbolFont + @";}}"); // C2017-036 get best available proportional font for symbols else sb.Append(@"{\f1\fnil\fcharset0 FreeMono;}}"); // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing return sb.ToString(); } } private string FontSize { get { Match match = Regex.Match(Rtf, @"\\fs[0-9]+"); // B2018-012 Make sure that there is at least 1 digit return match.Value; } } private void AddLink20(string linkValue, string linkUrl) { string fonttab = FontTable; string fontsize = FontSize; //if (this.DetectUrls) this.DetectUrls = false; if (SelectionLength > 0)HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), null); int position = SelectionStart; SelectionLength = 0; linkValue = linkValue.Replace("\\u8209?", "\\f1\\u8209?\\f0 "); linkValue = linkValue.Replace("\\u9586?", "\\f1\\u9586?\\f0 "); // backslash symbol linkValue = linkValue.Replace("\\u916?", "\\f1\\u916?\\f0 "); linkValue = linkValue.Replace(@"{", @"\{"); linkValue = linkValue.Replace(@"}", @"\}"); SelectedRtf = @"{\rtf1\ansi" + FontTable + @"{\colortbl ;\red255\green0\blue0;}\v" + FontSize + @" \v0 }"; this.SelectionLength = 0; this.SelectionStart = position; FindAllLinks(); } private void AddLink50(string linkValue, string linkUrl) { //this.DetectUrls = false; int position = SelectionStart; SelectionLength = 0; SelectedRtf = string.Format(@"{{\rtf\field{{\*\fldinst{{HYPERLINK ""www.volian.com #{0}"" }}}}{{\fldrslt{{\cf2\ul {1}}}}}}}", linkUrl, linkValue); this.SelectionStart = this.TextLength; this.SelectionLength = 0; } private void AddRtfStyles() { if ((OrigDisplayText.TextFont.Style & E_Style.Bold) > 0) { this.SelectAll(); RTBAPI.ToggleBold(true, this, RTBAPI.RTBSelection.SCF_SELECTION); this.Select(0, 0); } // Bug Fix // The code below was changed to select all of the text and then // apply the underlining to the selected text, because if the // the underlining was applied to RTBAPI.RTBSelection.SCF_ALL // the Links were changed so that they were no longer hidden. if ((OrigDisplayText.TextFont.Style & E_Style.Underline) > 0) // RTBAPI.ToggleUnderline(true, this, RTBAPI.RTBSelection.SCF_ALL); { this.SelectAll(); RTBAPI.ToggleUnderline(true, this, RTBAPI.RTBSelection.SCF_SELECTION); this.Select(0, 0); } // Bug Fix // The code below was changed to select all of the text and then // apply the italics to the selected text, because if the // the italics was applied to RTBAPI.RTBSelection.SCF_ALL // the Links were changed so that they were no longer hidden. if ((OrigDisplayText.TextFont.Style & E_Style.Italics) > 0) // RTBAPI.ToggleItalic(true, this, RTBAPI.RTBSelection.SCF_ALL); { this.SelectAll(); RTBAPI.ToggleItalic(true, this, RTBAPI.RTBSelection.SCF_SELECTION); this.Select(0, 0); } } #endregion #region HeightSupport public event StepRTBEvent HeightChanged; private void OnHeightChanged(object sender, EventArgs args) { if (HeightChanged != null) HeightChanged(sender, args); } private void AdjustSizeForContents(bool adjustWidth) { if (!_InitializingRTB) { Size offset = Size - ClientSize; int widthNew = (this is TableCellEditor) ? Width : (ContentsSize.Width + offset.Width + AdjustSize.Width); //int widthNew = Width; //if (!(this is TableCellEditor)) // widthNew = ContentsSize.Width + offset.Width + AdjustSize.Width; int heightNew = ContentsSize.Height + offset.Height + AdjustSize.Height; // Don't make the window narrower unless it has text - RHM - 20100107 Size szNew = new Size(((Text != "" && adjustWidth) ? widthNew : (widthNew > Width ? widthNew : Width)), heightNew); if (this.Size != szNew) { int heightOld = Height; //Console.WriteLine("before {0}, {1}, {2}, {3}, {4}", Size, szNew, widthNew, Width, this.GetType().Name); this.Size = szNew; //Console.WriteLine("after {0}, {1}, {2}, {3}", Size, szNew, widthNew, Width); if (heightOld != Height) { OnHeightChanged(this, new EventArgs()); if (ScrollPos.Y != 0) // Adjust ScrollPosition if it isn't Zero ScrollPos = new Point(0, 0); } } } } private float GetStringWidth(string strMeasureString) { using (Graphics g = Graphics.FromHwnd(Handle)) { return g.MeasureString(strMeasureString, Font).Width; } } private int Ceiling(float f) { return (int)(Math.Ceiling(f)); } public int MaxTextWidth { get { int maxWidth = 0; for (int i = 0; i < TextLength; i++) { int w = GetPositionFromCharIndex(i).X; maxWidth = Math.Max(maxWidth, w); } return maxWidth+10; // add 10 to account for the last character } } public void AdjustWidthForContent() { AdjustWidthForContent(0); } public void AdjustWidthForContent(int count) { int widthNL = Ceiling(GetStringWidth("\n")); int widthMax = 0; int widthMaxWW = 0; int indexStart = 0; int lineCountFromLines = Lines.Length; int lineCountFromGet = GetLineFromCharIndex(TextLength)+1; for (int i = 0; i < Lines.Length; i++) { int lineStart = GetLineFromCharIndex(indexStart); int indexEnd = indexStart + Lines[i].Length; int lineEnd = GetLineFromCharIndex(indexEnd); Point pointStart = GetPositionFromCharIndex(indexStart); Point pointEnd = GetPositionFromCharIndex(indexEnd); int indexEndPos = GetCharIndexFromPosition(pointEnd); if (indexEndPos + 1 < indexEnd) // This indicates that the text is wider than the Rich Text Box { int w = pointEnd.X + (indexEnd - indexEndPos) * widthNL; if (w > widthMaxWW) widthMaxWW = w; } if (lineEnd > lineStart)// this indicates that there was word-wrap on this line. { int w = pointEnd.X + Width * (lineEnd - lineStart); if (w > widthMaxWW) widthMaxWW = w; } else { if (pointEnd.X > widthMax) widthMax = pointEnd.X; } indexStart = indexEnd + 1; } if (widthMaxWW == 0) { int widthBorder = Width - ClientSize.Width; int w = widthMax + widthNL + widthBorder; if (Width != w) { if (count < 5 || Width < w) { Width = w; AdjustWidthForContent(count + 1);// Try one more time } } } else { if (count < 5 || Width < widthMaxWW) { Width = widthMaxWW; AdjustWidthForContent(count + 1); } } } public int CalculateHeight() { if (this.CreateParams.ClassName == "RICHEDIT50W") return CalculateHeight50(); else return CalculateHeight20(); } private int CalculateHeight20() { Application.DoEvents(); int yBottom = GetPositionFromCharIndex(TextLength).Y; int yTop = GetPositionFromCharIndex(0).Y; int heightFont = SelectionFont.Height; int borderSize = this.Height - this.ClientSize.Height; int heightNext = (yBottom - yTop) + heightFont + borderSize + 2;// 2 pixels - 1 at the top and 1 at the bottom if (heightNext != Height) { Height = heightNext; OnHeightChanged(this, new EventArgs()); ScrollPos = new Point(0, 0); // Scroll to make sure that the first line is displayed as the first line } return heightNext; } private int CalculateHeight50() { Application.DoEvents(); int heightFont = SelectionFont.Height; int borderSize = this.Height - this.ClientSize.Height; int heightNext = (1 + GetLineFromCharIndex(TextLength)) * heightFont + borderSize + 2;// 2 pixels - 1 at the top and 1 at the bottom return heightNext; } #endregion #region ColorSupport - Not currently used. //private void SetBackGroundColor(ItemInfo itemInfo) //{ // string backcolor = null; // int type = (int)itemInfo.MyContent.Type; // FormatInfo formatinfo = itemInfo.ActiveFormat; // if (type == (int)E_FromType.Procedure) // backcolor = formatinfo.PlantFormat.FormatData.ProcData.BackColor; // else if (type == (int)E_FromType.Section) // backcolor = formatinfo.PlantFormat.FormatData.SectData.BackColor; // else // { // int typindx = (int)itemInfo.MyContent.Type - 20000; // what to do for other types rather than steps // backcolor = formatinfo.PlantFormat.FormatData.StepDataList[typindx].StepLayoutData.BackColor; // } // BackColor = Color.FromName(backcolor); //} #endregion #region EventSupport #region LinkEvents private StepPanelLinkEventArgs _MyLinkClickedEventArgs; public event StepRTBLinkEvent LinkChanged; private void OnLinkChanged(object sender, StepPanelLinkEventArgs args) { _MyLinkClickedEventArgs = args; if (LinkChanged != null) LinkChanged(sender, args); } public event StepRTBLinkEvent LinkGoTo; private void OnLinkGoTo(object sender, StepPanelLinkEventArgs args) { _MyLinkClickedEventArgs = args; if (LinkGoTo != null) LinkGoTo(sender, args); } public event StepRTBLinkEvent LinkModifyTran; private void OnLinkModifyTran(object sender, StepPanelLinkEventArgs args) { _MyLinkClickedEventArgs = args; if (LinkModifyTran != null) LinkModifyTran(sender, args); } public event StepRTBLinkEvent LinkModifyRO; private void OnLinkModifyRO(object sender, StepPanelLinkEventArgs args) { _MyLinkClickedEventArgs = args; if (LinkModifyRO != null) LinkModifyRO(sender, args); } #endregion #region TextAndContentsEvents void StepRTB_TextChanged(object sender, EventArgs e) { //if (Rtf.Contains("Beginning: SelectionStart {0}, SelectionLength {1}", SelectionStart, SelectionLength); _AdjustingSelection = true; LinkLocation ll = FindLinkLocation(); LinkLocation llend = null; if (SelectionLength != 0) llend = FindLinkLocation(SelectionStart + SelectionLength - 1); if (ll != null) { if (SelectionStart == ll.Start && SelectionLength == 0) { if (SelectionStart >= 7) { // If the cursor is at the beginning of the line and a link is at the beginning of the line // then select the link rather than postitioning the cursor at the end of the previous line if (!_LastWasLeftArrow && GetFirstCharIndexOfCurrentLine() == SelectionStart) SetSelection(ll); else { DebugPrint("HSC===================>ll Insert: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length); SelectionStart = ll.Start - 7; } } } else if (SelectionStart + SelectionLength > ll.End) // Beyond the end of the starting link { int end = SelectionStart + SelectionLength; if (llend != null) end = llend.End; // If it extends into another link extend the end to the end of that link DebugPrint("HSC===================>ll After: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length); SetSelection(ll.Start, end - ll.Start); } else if (SelectionStart >= ll.Start || SelectionLength > 0)// Within the starting link { DebugPrint("HSC===================>ll: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length); SetSelection(ll); } } else if (llend != null) { DebugPrint("HSC===================>llend: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, llend.Start, llend.Length); // Check to see if the beginning starts before the Removing ending Removing starting _AdjustingSelection problem"); DebugPrint("RS------ SelectionChange > {0}", FindRangeStatus()); if (SelectionLength > 0 && IsSelectionLinked(SelectionStart, SelectionLength)) { if (SelectedText.IndexOf(@"[END>") > 0) { MyLinkText = SelectedText.Substring(0, SelectedText.IndexOf(@"[END>")); } else { MyLinkText = SelectedText; } } else { MyLinkText = null; } OnRTBSelectionChanged(this, new EventArgs()); _LastWasLeftArrow = false; } /// /// If the Selection is beyond the end of the line, move the selection back one character /// /// private bool CorrectSelectionAtEndOfLine() { if (SelectionStart > 0 && SelectionLength == 0 && GetFirstCharIndexFromLine(GetLineFromCharIndex(SelectionStart)) > GetFirstCharIndexOfCurrentLine()) { SelectionStart--; // Move the cursor back one character return true; } return false; } //private void HandleOverWrite() //{ // if (!_OverWrite) return; // if (SelectionLength > 0) return; // if (SelectionStart == TextLength) return; // Console.WriteLine("Handle Overwrite, SelectionStart = {0}, SelectionLength = {1}", SelectionStart, SelectionLength); // SelectionLength = 1; //} private bool _CheckSelection = false; #endregion #region Delete Handlers private void HandleDeleteKeyWithSelectedText(KeyEventArgs e, string keychars) { _ProcessingDelete = true; FindRangeStatus(); //DebugPrint("RS---------------- Delete > {0}", _RTBRangeStatus); switch (_RTBRangeStatus) { case RangeStatus.NoContainedLinks: case RangeStatus.Before_After: case RangeStatus.Before_EndLink: case RangeStatus.Before_EndBox: default: DeleteCurrentSelection(keychars); e.SuppressKeyPress = true; break; case RangeStatus.Before_Between: //myRTB1.SelectedText.EndsWith(@"[END> /// This inserts a space in between two links. /// It actually inserts "\v0 {space}\v " between the END tag and the START tag /// /// /// /// private void InsertCharBetweenLinks(LinkLocation ll, char charToAdd, bool setSelect) { //_InsertingSpaceBetweenLinks = true; DebugPrint("ICBLvvvvvvvvvvvvvvv>>>"); Rtf = Rtf.Substring(0, ll.StartRtf) + @"\v0 " + charToAdd.ToString() + @"\v " + Rtf.Substring(ll.StartRtf); //_InsertingSpaceBetweenLinks = false; if (setSelect) SelectionStart = ll.Start - 6; // account for >>"); } private void ExpandSelectionToIncludeStart() { //_AdjustingSelection = true; SetSelection(SelectionStart - 7, SelectionLength + 7); // Expand selection to include start //_AdjustingSelection = false; } public string GetSelectionForClipBoard() { string selTxtRTF = SelectedRtf; LinkLocation llstart = FindLinkLocation(); if (llstart != null) { selTxtRTF = Rtf.Substring(llstart.StartRtf, llstart.EndRtf - llstart.StartRtf); string lookfor = selTxtRTF.Substring(selTxtRTF.IndexOf(' ')); return SelectedRtf.Replace(lookfor, @"\v " + selTxtRTF); } return (selTxtRTF); } private void DeleteBetweenBetweenLinks(string keychars) { DebugSelection("DeleteBetweenBetweenLinks"); int selStart = SelectionStart - 7; int selLength = SelectionLength + 2; // Include the two added spaces InsertCharBetweenLinks(_RangeEndLink.NextLink); // Add a space at the end link InsertCharBetweenLinks(_RangeStartLink); // Add a space a the start link SetSelection(selStart, selLength);// Select everything including the spaces DeleteCurrentSelection(keychars);// Delete Selection } /// /// This is added to handle a glitch in richtextbox. Depending on /// which direction that selection is made (left -> right or right -> left) /// a replacement or delete may not work, you'll just get a 'beep'. /// This approach consistently works. /// public bool WasXDelete = false; private void DeleteCurrentSelection(string keys) { DebugPrint("vvvvvvvvvvvvxxxxxxxxxxxx>"); DebugSelection("Before X"); DebugPrint(keys == null ? "NULL" : "NOT NULL"); SelectedText = keys==null?"X":keys; // replace text with X WasXDelete = (keys == null); DebugSelection("After X"); DebugPrint("------------xxxxxxxxxxxx>"); if (keys == null) { _SendBackSpace = true; RtbSendKeys("{BS}"); // remove X //this.ClearUndo(); // undo was redisplay 'X' and then deleted text Application.DoEvents(); DebugSelection("After BS"); } DebugPrint("^^^^^^^^^^^^xxxxxxxxxxxx>"); } private void DeleteSelection(int start, int length, string keychars) { SetSelection(start, length); DeleteCurrentSelection(keychars); } private void DeleteEndBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteEndBetweenLinks"); int sstart = SelectionStart; int slen = SelectionLength + 1 - 7; // This puts a space at the link that starts at the end of the selection InsertCharBetweenLinks(_RangeEndLink.NextLink); //_AdjustingSelection = true; DeleteSelection(sstart, slen, keychars); //_AdjustingSelection = false; _ProcessingKeys--; } private void DeleteStartBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteStartBetweenLinks"); int slen = SelectionLength + 8; int sstart = SelectionStart - 7; //LinkLocation ll = FindBetweenLinks(SelectionStart); InsertCharBetweenLinks(_RangeStartLink); DeleteSelection(sstart, slen, keychars); _ProcessingKeys--; } private void DeleteFromStartOfBox(string keychars) { _ProcessingKeys++; DebugSelection("DeleteFromStartOfBox"); int slen = SelectionLength; SetSelection(0, 0); //RtbSendKeys(" "); // open for space between links which separates END/START tokens SelectedText = " "; DeleteSelection(0, slen + 8, keychars); _ProcessingKeys--; } private void DeleteFromStartOfBoxEndBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteFromStartOfBoxEndBetweenLinks"); // This puts a space at the link that starts at the end of the selection int sLen = SelectionStart + SelectionLength - 7 + 2;// -7 for 0) SetSelection(SelectionStart, newend - SelectionStart); break; case Keys.Space: if (e.Control && MyDVI != null && UserInfo.CanEdit(MyUserInfo, MyDVI)) // Hardspace - Ctrl+Shift+Space { InsertSymbol(@"\u160?"); e.Handled = true; } break; case Keys.F3: // shift F3 e.Handled = true; ToggleCase(); // toggle through Upper, Lower, and Title case break; default: break; } } private string GetSelectedDisplayableText() { using (StepRTB srtb = new StepRTB()) { srtb.Rtf = this.SelectedRtf.Replace(@"\u8209?", "-"); srtb.Rtf = srtb.Rtf.Replace(@"\u9586?", @"\\"); string rtnstr = ""; string ctxt = srtb.Text;//this.SelectedText; if (ctxt.EndsWith(""); if ((strtidx == -1 || strtidx > lnkidx) && lnkidx > -1 && endidx > -1) { rtnstr += ctxt.Substring(idx, lnkidx); idx = endidx + 5; strtidx = ctxt.IndexOf("", idx); } while (strtidx > -1) { rtnstr += ctxt.Substring(idx, strtidx - idx); idx = strtidx + 7; rtnstr += ctxt.Substring(idx, lnkidx - idx); idx = endidx + 5; strtidx = ctxt.IndexOf("", idx); } if (idx < ctxt.Length) rtnstr += ctxt.Substring(idx); return rtnstr; } } private bool IsControlChar = false; private bool _SendBackSpace = false; private int _ImageWidth = 0; public int ImageWidth { get { return _ImageWidth; } set { _ImageWidth = value; } } void StepRTB_KeyDown(object sender, KeyEventArgs e) { // added jcb 20130103 to support set ro from word doc with annotation when right click menu is opened by keyboard if (e.KeyCode == Keys.Apps) OnSetMenu(this, new StepRTBMenuEventArgs("OpenContextMenu")); // the following code only allows arrow keys & pageup/down for rtf raw items: if (!e.Control && !e.Shift && MyItemInfo != null && MyItemInfo.IsRtfRaw) // error message is displayed in keypress for this. { if (e.KeyCode != Keys.Up && e.KeyCode != Keys.Down && e.KeyCode != Keys.Right && e.KeyCode != Keys.Left && e.KeyCode != Keys.PageDown && e.KeyCode != Keys.PageUp) { e.Handled = true; return; } } if (e.Control) { IsControlChar = true; if (e.Shift) { //Console.WriteLine("keycode = {0} key value = {1}",e.KeyCode,e.KeyValue); switch (e.KeyCode) { // The following keys are supported in underlying RTB (with ctrl+shift key), // but PROMS should not do anything for that functionality: case Keys.Add: // the plus on the key pad case Keys.Subtract: case Keys.L: case Keys.Oemplus: // the plus on the keyboard (not the key pad) e.Handled = true; break; } } else { switch (e.KeyCode) { case Keys.X: //ctrl-X case Keys.C: //ctrl-C // handle the clipboard copy and cut when a Transition or RO is selected // For now, we are coping/cutting just the displayed text to the clipboard (like 16-bit VE-PROMS) string ts = GetSelectedDisplayableText(); if (ts != null && ts != "") Clipboard.SetText(GetSelectedDisplayableText()); e.Handled = true; e.SuppressKeyPress = true; if (ts != null && ts != "" && e.KeyCode == Keys.X) // cut to clipboard - delete the selected text HandleDeleteKeyWithSelectedText(e, null); break; case Keys.V: // NOTE that if in a Properties Dialog StepRTB (for numbers and titles) or in a Procedure Specific // Information (PSI) Dialog, i.e. any non-EditItem/Step editor field, the following code is run // for the ctrl-V. For EditItems & Grid cells, the code in StepTabRibbon's btnPaste_Click is // run. The way this occurs is that in the designer for StepTabRibbon (StepTabRibbon.designer.cs), // the line of code: // this.btnPaste.Shortcuts.Add(DevComponents.DotNetBar.eShortcut.CtrlV); // maps the Ctrl-V to btnPaste for those StepRTB's that are associated with the StepTabRibbon, i.e. // EditItems & Grid cells. IDataObject iData = Clipboard.GetDataObject(); // verify that data in clipboard is valid for this type. If inserting an equation, need to verify that // input data has an 'equation', and if not inserting into an equation step type, it must not have // equation data. //DataFormats.Format frm = DataFormats.GetFormat("Embed Source"); //System.Windows.Forms.RichTextBox richTextBox1; using (System.Windows.Forms.RichTextBox richTextBox1 = new System.Windows.Forms.RichTextBox()) { richTextBox1.Location = new System.Drawing.Point(35, 32); richTextBox1.Name = "richTextBox1"; richTextBox1.Size = new System.Drawing.Size(67, 58); richTextBox1.TabIndex = 0; richTextBox1.Text = ""; richTextBox1.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None; bool hasEquation = false; try { DataFormats.Format frm = DataFormats.GetFormat("Embed Source"); richTextBox1.Paste(frm); if (richTextBox1.Rtf.ToUpper().Contains("OBJCLASS EQU")) hasEquation = true; if (richTextBox1.Rtf.ToUpper().Contains("OBJCLASS VIS")) hasEquation = true; // Support Visio } catch (Exception ex) { hasEquation = true; } /// B2020-051: Don't allow pasting of a mathtype equation into an item that isn't the correct type if (iData.GetDataPresent("Embed Source")) hasEquation = true; // mathtype if (MyItemInfo != null && MyItemInfo.IsRtfRaw && MyItemInfo.FormatStepData.Type.ToUpper().Contains("EQUATION") && !hasEquation) { FlexibleMessageBox.Show("Cannot paste non-equation data into an equation step type.", "Invalid data", MessageBoxButtons.OK); //richTextBox1.Dispose(); e.Handled = true; return; } // if inserting anything other than equation, be sure that an equation is not in the buffer: else if (hasEquation && (MyItemInfo == null || (MyItemInfo != null && !MyItemInfo.IsRtfRaw && !MyItemInfo.FormatStepData.Type.ToUpper().Contains("EQUATION")))) { FlexibleMessageBox.Show("Cannot paste equation data into an non-equation step type.", "Invalid data", MessageBoxButtons.OK); //richTextBox1.Dispose(); e.Handled = true; return; } // only allow the paste of a screen shot image if using the shortcut switch "/EmbedImages" if (Volian.Base.Library.VlnSettings.GetCommandFlag("EmbedImages") && iData.GetDataPresent(DataFormats.Dib)) // Device Independent Bitmap { System.Drawing.Image img = Clipboard.GetImage(); ImageWidth = img.Width; Width = ImageWidth + 2; Paste(); e.Handled = true; return; } else if (iData.GetDataPresent("Embed Source")) //DS Equation") || iData.GetDataPresent("MathType EF")) { Size sz = RtfRawItem.GetRtfRawSize(richTextBox1.Rtf); this.Rtf = richTextBox1.Rtf; Width = sz.Width; Height = sz.Height; e.Handled = true; return; } else if (iData.GetDataPresent(DataFormats.Dib)) { System.Drawing.Image img = Clipboard.GetImage(); ImageWidth = img.Width; Width = ImageWidth + 2; Paste(); e.Handled = true; return; } else { if (!iData.GetDataPresent(DataFormats.Text) && !iData.GetDataPresent(DataFormats.Rtf)) { FlexibleMessageBox.Show("Cannot paste, text has special characters or symbols that will not paste correctly."); } else { // if contains bad rtf (from Word), paste as text, otherwise, do the paste here. if (!PasteRtfAsText(true)) Paste(); if (SelectionLength == 0 && MyStyleFont != null) SelectionFont = MyStyleFont.WindowsFont; // B2017-023 null reference check for empty workdraft set information dialog } } } // end using e.Handled = true; return; case Keys.Home: StepRTB_HomeEndPressed(e); e.Handled = true; break; case Keys.End: StepRTB_HomeEndPressed(e); e.Handled = true; break; // 16bit Proms used 'ctrl-enter' for Hard returns. 32bit Proms uses 'shift-enter' // because the richtextbox does this by default. Also Word uses 'shift-enter' // for Hard return. And Word uses 'ctrl-enter' for inserting of page break. So // 'ctrl-enter' for 32bit will insert page break case Keys.Enter: OnInsertPgBrk(this, new EventArgs()); e.Handled = true; break; // The following keys are supported in underlying RTB (with ctrl key), but PROMS should not // do anything for that functionality: case Keys.R: // Right Align text case Keys.L: // Left Align text case Keys.E: // Center Align text case Keys.D1: // Single space text (D1 is the '1' key) case Keys.D2: // Double space text case Keys.D5: // 1.5 space text case Keys.H: // Find (proms uses Ctrl+F for find) case Keys.Oemplus: // plus on the keyboard (not the key pad) e.Handled = true; break; } } } if (((int)e.KeyCode) == 220) e.Handled = true; switch (e.KeyCode) { case Keys.Left: if (e.Shift) { int linkWidth = FindlinkWidth(false,e.Control); if (linkWidth == 0)// if not link, don't do special processing { if (e.Control) { this.AutoWordSelection = true; // this will select a word at a time } return; } else linkWidth++; int len = SelectionLength - linkWidth; SetSelection(SelectionStart, len); // adjust the selcection around the linked text e.Handled = true; return; } if (e.Control || SelectionStart == 0) { StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlLeft : E_ArrowKeys.Left); e.Handled = true; } HandleLocalSelectionChange(); break; case Keys.Up: int ln = GetLineFromCharIndex(SelectionStart); if (e.Control || ln == 0) { StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlUp : E_ArrowKeys.Up); e.Handled = true; } // if shift-up & at selection had a link, handle this as special case. if (e.Shift && SelectionLength > 0) { RangeStatus rs = FindRangeStatus(); if (rs != RangeStatus.NoContainedLinks) { int curend = SelectionStart + SelectionLength; SelectionLength = 0; RtbSendKeys("{Up}"); Application.DoEvents(); Select(SelectionStart, curend - SelectionStart); e.Handled = true; } } else { HandleLocalSelectionChange(); } break; case Keys.Right: // If at beginning of box that starts with a link, don't worry about shift or not, // because selection is first character or link without any other selection. Don't // need to write code to handle link at beginning of box in Shift Right code because // it's handled in HandleSelectionChange. if (e.Shift && ((SelectionStart > 0) || (SelectionStart == 0 && _LinkLocations.Count > 0 && _LinkLocations[0].Start != 7))) { int newlen = FindlinkWidth(true,e.Control); if (newlen == 0) // not on linked text { if (e.Shift && e.Control) this.AutoWordSelection = true; return; } else if (e.Shift && e.Control) newlen++; int len = SelectionLength + newlen; SetSelection(SelectionStart, len); // adjust the selection around the linked text e.Handled = true; return; } if(e.Control && e.Shift && SelectionStart == 0)//b2016-246 Ctrl-Shift-Right Arrow extend select * from ITEMS IIon a word at a time { SelectionLength++; this.AutoWordSelection = true; return; } if (e.Control || SelectionStart == this.Text.Length) { StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlRight : E_ArrowKeys.Right); e.Handled = true; } HandleLocalSelectionChange(); break; case Keys.Down: int l = GetLineFromCharIndex(SelectionStart); Point pos = new Point(); pos.X = ClientRectangle.Width; pos.Y = ClientRectangle.Height; int lastIndex = this.GetCharIndexFromPosition(pos); int lastLine = this.GetLineFromCharIndex(lastIndex); if (e.Control || l >= lastLine) { StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlDown : E_ArrowKeys.Down); HandleLocalSelectionChange(); e.Handled = true; return; } if (!e.Shift) HandleLocalSelectionChange(); // if shift-down & on link at beginning of box - do special processing (regular processing // didn't handle it correctly. if (e.Shift && lastLine > 0 && SelectionStart == 0 && _LinkLocations.Count > 0 && _LinkLocations[0].Start == 7) { Point cpos = GetPositionFromCharIndex(SelectionStart); int addon = ClientRectangle.Height / (lastLine + 1); cpos.Y = cpos.Y + addon; int selend = GetCharIndexFromPosition(cpos); Select(7, selend - 7); e.Handled = true; } break; case Keys.PageUp: StepRTB_PageKeyPressed(e); e.Handled = true; break; case Keys.PageDown: StepRTB_PageKeyPressed(e); e.Handled = true; break; case Keys.Delete: if (SelectionLength == 0) { foreach (LinkLocation lls in _LinkLocations) { if (SelectionStart >= lls.Start - 7 && SelectionStart < lls.End) { SetSelection(lls);// Select the link to the right HandleDeleteKeyWithSelectedText(e, null); e.SuppressKeyPress = true; return; } } if (SelectionStart != TextLength) { if (e.Control) { // B2016-245 [ctrl][delete] deletes rest of word to the right of the cursor RtbSendKeys("+^{RIGHT}{BS}"); //[shift][ctrl][right arrow] (selects rest of word to the right) folowed by a backspace (delete) e.SuppressKeyPress = true; } else { SelectionStart++;// A Delete can be accomplished with a right arrow followed by a backspace. RtbSendKeys("{BS}"); // This is done due to a glitch in the RichTextBox that sometimes causes a beep rather than a delete e.SuppressKeyPress = true; } } } else HandleDeleteKeyWithSelectedText(e, null); break; case Keys.Back: if (_SendBackSpace) { _SendBackSpace = false; return; } _CheckSelection = true; if (SelectionLength == 0) { foreach (LinkLocation lls in _LinkLocations) { if (SelectionStart > lls.Start - 7 && SelectionStart <= lls.End) { SetSelection(lls); break; } } } if (SelectionLength > 0) HandleDeleteKeyWithSelectedText(e, null); break; case Keys.Insert: //_OverWrite = !_OverWrite; //if (_OverWrite) //{ // HandleSelectionChange(); //} //else //{ // SelectionLength = 0; // HandleSelectionChange(); //} // For now, don't allow for toggling between insert/overwrite mode - see // comment on _OverWrite e.Handled = true; break; case Keys.F5: if (!UserInfo.CanEdit(MyUserInfo, MyItemInfo.MyDocVersion)) { e.Handled = true; break; } if (e.Shift) { e.Handled = true; ItemInfo myCopyStep = (this.Parent.Parent.Parent as StepTabPanel).MyDisplayTabControl.MyCopyStep; if (myCopyStep != null) { // commented out as part of bug fix B2016-148 to fix the not popping up the paste options //if (this.MyItemInfo.IsSection && myCopyStep.IsSection) // OnSetMenu(this, new StepRTBMenuEventArgs("StepPaste")); //if (this.MyItemInfo.IsStep && myCopyStep.IsStep) //{ // if ((this.MyItemInfo.IsHigh && myCopyStep.IsHigh) || (!this.MyItemInfo.IsHigh && !myCopyStep.IsHigh)) // OnSetMenu(this, new StepRTBMenuEventArgs("StepPaste")); //} OnSetMenu(this, new StepRTBMenuEventArgs("StepPaste")); } //if (!OnCheckClipboard(this, new EventArgs())) return; // check if 'clipboard' contains a step. //OnSetMenu(this, new StepRTBMenuEventArgs("StepPaste")); } else if (!e.Control && !e.Alt) { e.Handled = true; OnCopyStep(this, new EventArgs()); } break; case Keys.F6: e.Handled = true; SendKeys.Send("%H{ESC}"); break; case Keys.Tab: VlnFlexGrid myGrid = Parent as VlnFlexGrid; if (myGrid == null) { e.SuppressKeyPress = true; e.Handled = true; Form frm = ParentForm(this); if (frm != null) frm.SelectNextControl(this, true, true, true, true); else StepRTB_ArrowPressed(e.Shift ? E_ArrowKeys.CtrlUp : E_ArrowKeys.CtrlRight); } else { if (e.Shift) { e.SuppressKeyPress = true; e.Handled = true; if (!myGrid.SelectPrevCell()) { // don't do anything if at top (for now) } } else { e.SuppressKeyPress = true; e.Handled = true; if (!myGrid.SelectNextCell()) { myGrid.MyBorders.InsertRow(myGrid.Rows.Count - 1); myGrid.MyShading.InsertRow(myGrid.Rows.Count - 1); // C2021-004 Table Cell Shading information myGrid.Rows.Add(1); myGrid.SelectNextCell(); } } } break; case Keys.Enter: if (!e.Control && !e.Shift && !e.Alt) { if (UserInfo.CanEdit(MyUserInfo,MyItemInfo.MyDocVersion)) OnEnterKeyPressed(sender, e); else { // user cannot change data so just move to the next step element StepRTB_ArrowPressed(E_ArrowKeys.CtrlDown); // perform a HandleLocalSelectionChange(); e.Handled = true; } } break; case Keys.F2: if (e.Alt && !e.Control && !e.Shift) // toggle change bar { if (MyUserInfo.IsAdministrator() || MyUserInfo.IsSetAdministrator(MyDVI) || MyUserInfo.IsWriter(MyDVI)) OnToggleChangeBar(this, new EventArgs()); e.Handled = true; } break; case Keys.F7: if (!e.Alt) // for the Include On check boxes on the step properties page { if (e.Control && e.Shift) // Toggle include on Placekeeper as Continuous Action OnTogglePlaceKeeperContAct(this, new EventArgs()); else if (e.Control) // Toggle include on Placekeeper OnTogglePlaceKeeper(this, new EventArgs()); else if (e.Shift) // toggle include on Continuous Action Summary OnToggleContinuousActionSummary(this, new EventArgs()); e.Handled = true; } break; } if (e.KeyValue == 187 && e.Control) // equal key pressed { if (e.Shift) // superscript { OnToggleSuperScript(this, new EventArgs()); } else // subscript { OnToggleSubScript(this, new EventArgs()); } e.Handled = true; } } // C2021-005 set the selected cell(s) or cell text to the passed in font size public void SetFontSize(float newSize) { if (SelectedText == null || SelectedText == "") // empty table cell selected Rtf = SetFontSizeReplace(Rtf, newSize); else { // table cell text selected int selst = SelectionStart; int selln = SelectionLength; string newrtf = SelectedRtf; //B2021-052 use a temporary variable to allow easy debugging newrtf = SetFontSizeReplace(newrtf, newSize); // changes the /fs## command in the rtf string SelectedRtf = newrtf;// replace the selected portion with the updated font size version of the rtf Select(selst, selln); // re-select the cell text } } // C2021-005 set the font size of the passed in RTF text private string SetFontSizeReplace(string rtf, float newSize) { MatchCollection mc = Regex.Matches(rtf, @"\\fs([0-9]+)"); foreach (Match match in mc) { float sz = float.Parse(match.Groups[1].Value); float repwith = newSize * 2; // RTF font size is double the selected point size string repsz = match.Value; // use \fs## rather than number in replace in case text contains the number string repwithsz = match.Value.Replace(sz.ToString(), ((int)repwith).ToString()); rtf = rtf.Replace(repsz, repwithsz); } return rtf; } // C2021-005 parse the rtf for the font sizes. // if there are different font sizes, then return 0 public float GetRTFFontSize() { string rtf; if (SelectedText == null || SelectedText == "") rtf = Rtf; else rtf = SelectedRtf; MatchCollection mc = Regex.Matches(rtf, @"\\fs([0-9]+)"); bool differentFonts = false; float lastSZ = 0; foreach (Match match in mc) { float sz = float.Parse(match.Groups[1].Value); if (lastSZ == 0) lastSZ = sz; else if (lastSZ != sz) differentFonts = true; } return (differentFonts || lastSZ == 0) ? 0 : lastSZ/2; // divide the RTF font size by two to get the font point size } // F2022-137 Table performance improvements public static float GetRTFFontSize(string rtf) { MatchCollection mc = Regex.Matches(rtf, @"\\fs([0-9]+)"); bool differentFonts = false; float lastSZ = 0; foreach (Match match in mc) { float sz = float.Parse(match.Groups[1].Value); if (lastSZ == 0) lastSZ = sz; else if (lastSZ != sz) differentFonts = true; } return (differentFonts || lastSZ == 0) ? 0 : lastSZ / 2; // divide the RTF font size by two to get the font point size } private static Form ParentForm(Control ctrl) { while (!(ctrl.Parent is Form || ctrl.Parent is EditItem)) ctrl = ctrl.Parent; return ctrl.Parent as Form; } private void StepRTB_HomeEndPressed(KeyEventArgs keyargs) { if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return; // Cursor moves out of box only if control is pressed too - otherwise key is // handled in rtb. //if (keyargs.Control)MyRTBItem.MyStepPanel.StepCursorKeys(this, keyargs); // Replaced with an event if (keyargs.Control) OnCursorKeyPress(this, keyargs); } private void StepRTB_PageKeyPressed(KeyEventArgs keyargs) { if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return; //MyRTBItem.MyStepPanel.StepCursorKeys(this, keyargs); Replaced with an event OnCursorKeyPress(this, keyargs); } public void StepRTB_ArrowPressed(E_ArrowKeys key) { Point cp = PointToClient(Cursor.Position); //MyRTBItem.MyStepPanel.CursorMovement(this, cp, key); Replaced with an event OnCursorMovement(this, new StepRTBCursorMovementEventArgs(cp, key)); } private void StepRTB_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { if (!ReadOnly) { if (!IsControlChar && MyItemInfo != null && MyItemInfo.IsRtfRaw) { string err = string.Format("Cannot enter text into an equation or incorrect keystroke entered for equation"); FlexibleMessageBox.Show(err, "Invalid text.", MessageBoxButtons.OK); e.Handled = true; return; } if (Text == "" && Parent != null && Parent is VlnFlexGrid) { //ShowMyParentsFonts(); SelectionFont = Parent.Font; } // add the character with its font depending on the char.... if (!IsControlChar) { if (e.KeyChar >= ' ') { // B2016-281 if entered keystroke is a character that converted to a symbol (i.e. dash or backslash) // or if it's a RFT special character (i.e. open and close curly brackets) // then flag it and replace selected text with a null string (removing selected text) // and then insert the symbol or RTF escape codes for those characters bool isSymbolOrRTF = e.KeyChar == '-' || e.KeyChar == '\\' || e.KeyChar == '{' || e.KeyChar == '}'; LinkLocation ll = FindBetweenLinks(); if (ll != null && SelectionLength == 0) // SelectionLength = 0 means insert { // replacing between links, this is a special case string strpressed = null; if (e.KeyChar == '-') strpressed = GetAddSymbolText(@"\u8209?"); else if (e.KeyChar == '\\') strpressed = GetAddSymbolText(@"\u9586?"); else if (e.KeyChar == '}') strpressed = @"\}"; else if (e.KeyChar == '{') strpressed = @"\{"; else strpressed = e.KeyChar.ToString(); InsertCharBetweenLinks(ll, strpressed); e.Handled = true; } else if (SelectionLength != 0) { // B2016-281 if replacing with a dash, backslash, or curly brackets, first replace with nother (to delete selection) // and set the e.Handled to false so that AddSybol or AddRTF is used to insert that character. HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), isSymbolOrRTF ? "" : e.KeyChar.ToString()); e.Handled = !isSymbolOrRTF; } } if (!e.Handled) { if (e.KeyChar == '-') AddSymbol(@"\u8209?"); else if (e.KeyChar == '{') AddRtf(@"\{"); else if (e.KeyChar == '}') AddRtf(@"\}"); else if (e.KeyChar == '\\') AddSymbol(@"\u9586?"); // unicode hex 2572 else return; e.Handled = true; // flag that it's been handled, otherwise, will get 2 chars. } if (e.Handled && SelectionLength != 0) SelectionFont = MyStyleFont.WindowsFont; } IsControlChar = false; } } public void RtbSendKeys(string keys) { Focus(); SendKeys.Send(keys); // list of keys https://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send%28v=vs.80%29.aspx // With .Net Framework 3.0 this can be replaced with EditingCommands http://msdn.microsoft.com/en-us/library/ms771634.aspx } public bool PasteRtfAsText(bool PasteNoReturnsSetting) { // check if rtf is coming from Word, i.e. if it has 'SCHEMAS.MICROSOFT.COM/OFFICE/WORD'. // If it is coming from Word, it will be pasted as text so as not to get any rtf commands // that PROMS does not support such as odd Fonts, other symbols, etc. This isn't a complete // solution, clipboard data may come from other 3rd-party tools and unsupported Rtf may get // pasted in. But the hope is that this will happen less often than getting it from MS Word. IDataObject myDO = Clipboard.GetDataObject(); if (myDO.GetDataPresent(DataFormats.Text)) return false; string tmpForLink = myDO.GetData(DataFormats.Rtf).ToString(); if (tmpForLink.ToUpper().Contains(@"SCHEMAS.MICROSOFT.COM/OFFICE/WORD")) { SelectedText = GetPasteText(PasteNoReturnsSetting, myDO); return true; } return false; } public string GetPasteText(bool PasteNoReturnsSetting, IDataObject myDO) { // B2021-0039: symbols not pasting correctly from ctrl-v: // get base list of valid symbols, use base format if MyItemInfo is null. Use symbols from // the format file versus a list in code FormatData fmtd = MyItemInfo != null ? MyItemInfo.ActiveFormat.PlantFormat.FormatData : FormatInfo.PROMSBaseFormat.FormatData; SymbolList sl = fmtd.SymbolList; string[] allowableSymbols = new string[sl.Count]; for (int i = 0; i < sl.Count; i++) allowableSymbols[i] = string.Format(@"{0}", sl[i].Unicode); // allowable symbols are those symbols in the format file that the proms editor supports that // can be pasted from word as is. string ptext = (string)myDO.GetData(DataFormats.UnicodeText); ptext = ptext.TrimEnd("\r\n\t ".ToCharArray()); if (PasteNoReturnsSetting) ptext = ptext.Replace("\r\n", " "); StringBuilder sb = new StringBuilder(); bool didCharReplace = false; bool hasBadChar = false; for (int i = 0; i < ptext.Length; i++) { didCharReplace = false; string sym = string.Format(@"{0}", Convert.ToInt32(ptext[i])); if ((ptext[i] > 0x7e)) { // is this an allowable symbol/character: for (int j = 0; j < sl.Count; j++) { if (sym == allowableSymbols[j]) { sb = sb.Append((char)(Convert.ToInt32(allowableSymbols[j]))); didCharReplace = true; break; } } // if not allowable, put in a "?" and give a message to user (below) if (!didCharReplace) { sb = sb.Append("?"); didCharReplace = true; hasBadChar = true; } if (!didCharReplace) sb = sb.Append(ptext[i]); } if (!didCharReplace) sb = sb.Append(ptext[i]); } ptext = sb.ToString(); ptext = ptext.Replace("\u2013", "-"); // Replace EN Dash with hyphen ptext = ptext.Replace("\u2014", "-"); // Replace EM Dash with hyphen ptext = ptext.Replace("\u2011", "-"); // Replace non-breaking hyphen with hyphen ptext = ptext.Replace("\u2572", "\\"); // Replace backslash symbol with backslash character if (hasBadChar) FlexibleMessageBox.Show("Replacing pasted characters that are not supported by Proms with a '?'."); return ptext; } private void DoDeleteEndBetweenLinks() { DebugSelection("Beginning"); int sstart = SelectionStart; RtbSendKeys("{RIGHT} "); // open for space between links which separates END/START tokens SetSelection(sstart, SelectionStart - sstart - 1); // 1 is accounting for typed space DebugSelection("SetSelection"); RtbSendKeys("{DELETE}"); // deletes text including link RtbSendKeys("{RIGHT}{BS}"); // deletes space that was added } private void DoDeleteStartBetweenLinks() { int slen = SelectionLength; RtbSendKeys("{LEFT} "); SetSelection(SelectionStart, slen + 7); RtbSendKeys("{DELETE}"); RtbSendKeys("{BS}"); } #endregion #region LinkSelectionAndHandling public bool IsSelectionLinked(int index, int len) { if (_LinkLocations == null)return false; int sel = index; int selLength = len; foreach (LinkLocation ll in _LinkLocations) { // When the selector moved to the right of a link, the GOTO button was still lit. // Removing the "+7" seems to have fixed this. - jsj 1/08/2010 //if (sel >= ll.Start && sel < ll.Start + ll.Length + 7) return true; if (sel >= ll.Start && sel < ll.Start + ll.Length) return true; } return false; } /// /// For use in Find/Replace. /// If text is found is part of the link information and not the link value, /// then we want to continue searching. /// /// /// /// public bool SkipLinkInfo(int index, int len) { if (_LinkLocations == null)return false; int sel = index; int selLength = len; foreach (LinkLocation ll in _LinkLocations) { if (sel >= ll.Start - 7 && sel < ll.Start + ll.Length) { int pos = ll.Text.IndexOf("#Link:"); if (sel < ll.Start || sel >= ll.Start-7+pos) return (true); } } return false; } #endregion #endregion #region SelectionStack Stack _SelectionStack = null; public Stack SelectionStack { get { if (_SelectionStack == null) _SelectionStack = new Stack(); return _SelectionStack; } } public void PushSelection() { SelectionStack.Push(new SelectionData(this)); } public void PopSelection() { SelectionData selection = SelectionStack.Pop(); if (SelectionStack.Count == 0) _SelectionStack = null; Select(selection.SelectionStart, selection.SelectionLength); selection = null; } public class SelectionData { int _SelectionStart; public int SelectionStart { get { return _SelectionStart; } set { _SelectionStart = value; } } int _SelectionLength; public int SelectionLength { get { return _SelectionLength; } set { _SelectionLength = value; } } public SelectionData(RichTextBox richTextBox) { _SelectionStart = richTextBox.SelectionStart; _SelectionLength = richTextBox.SelectionLength; } } #endregion #region Link Support int _ProcessingKeys = 0; List _LinkLocations; public List LinkLocations { get { return _LinkLocations; } } private int _FALLevel = 0; private bool _IdentifyingLinks = false; public void FindAllLinks() { if (_IdentifyingLinks || _ProcessingDelete) return; //DebugPrint("FAL{0}vvvvvvvvvvvvvvvvvvvvvvvvv>>", ++_FALLevel); _AdjustingSelection = true; PushSelection(); FindLinks(); //IdentifyLinks(); PopSelection(); LinkLocation llx = FindLinkLocation(); if (_CheckSelection) { if (llx != null) SetSelection(llx.End, 0); _CheckSelection = false; } _AdjustingSelection = false; if (!_ProcessingDelete) OnLinkLocationChanged(this, new EventArgs()); //DebugPrint("FAL{0}^^^^^^^^^^^^^^^^^^^^^^^^^>>", _FALLevel--); } private void FindLinks() { string str = Text; _LinkLocations = new List(); MatchCollection matches = Regex.Matches(str, @"", RegexOptions.Singleline); MatchCollection matchesRtf = Regex.Matches(Rtf, "", RegexOptions.Singleline); LinkLocation thisLink = null; for (int i = 0; i < matches.Count; i++) //each (Match match in matches) { Match match = matches[i]; Match matchrtf = matchesRtf[i]; thisLink = new LinkLocation(match.Index + 7, // If the [END> is immediately followed by "); if (_LinkLocations == null) return null; foreach (LinkLocation ll in _LinkLocations) if (ll.Start == start && ll.StartsBetween) return ll; return null; } private LinkLocation FindLinkLocation() { return FindLinkLocation(SelectionStart); } private LinkLocation FindLinkLocation(int sel) { //DebugPrint("FL----------------Location>"); if (_LinkLocations == null) return null; foreach (LinkLocation ll in _LinkLocations) { // Moving right: // if less than, allows stopping between two links if (ll.Start < sel && ll.End > sel) { DebugPrint("Greater Than {0} {1} {2}", sel, ll.Start, ll.End); return ll; } // if less than or equal, does not stop between two links if ((!ll.StartsBetween) && ll.Start <= sel && ll.End > sel) { DebugPrint("Greater Than or Equal {0} {1} {2}", sel, ll.Start, ll.End); return ll; } } return null; } public DialogResult ReplaceText(string rpltxt, string fndstr, bool caseSensitive, bool matchWholeWord, bool reverse, bool prompt, IWin32Window fndrpldlg) { DialogResult dlgrslt = DialogResult.Yes; if (SelectionLength > 0) { if (IsSelectionLinked(SelectionStart, SelectionLength)) { FlexibleMessageBox.Show(fndrpldlg, "Cannot replace linked text!", "Find/Replace"); dlgrslt = DialogResult.No; } else { if (prompt) dlgrslt = FlexibleMessageBox.Show(fndrpldlg, "Replace This Occurrence?", "Replace Text", MessageBoxButtons.YesNoCancel); if (dlgrslt == DialogResult.Yes) SelectedText = rpltxt; } } return dlgrslt; } private RichTextBoxFinds _FindOptions = RichTextBoxFinds.None; public bool FindText(string str, bool caseSensitive, bool matchWholeWord, bool reverse) { using (StepRTB savRTF = new StepRTB()) { int startpos = SelectionStart + SelectionLength; savRTF.Text = this.Text; _FindOptions = RichTextBoxFinds.None; if (caseSensitive) _FindOptions |= RichTextBoxFinds.MatchCase; if (matchWholeWord) _FindOptions |= RichTextBoxFinds.WholeWord; if (reverse) { _FindOptions |= RichTextBoxFinds.Reverse; savRTF.Text = this.Text.Substring(0, SelectionStart); startpos = savRTF.Text.Length; if (startpos == 0) return false; // at beginning of rtfbox during a reverse find } else { if (startpos >= savRTF.Text.Length) return false; // at end of rtfbox during a forward find } // look for the find string in the temporary rtfbox // then set the cursor selection in the real rtfbox bool keepgoing = true; while (keepgoing) { str = str.Replace("\\", "\u2572").Replace("-","\u2011"); int pos = savRTF.Find(str, startpos, _FindOptions); keepgoing = false; if (pos >= 0) { if (this.SkipLinkInfo(pos, str.Length)) { if (reverse) { startpos--; savRTF.Text = savRTF.Text.Substring(0, startpos); } else startpos++; if (startpos > 0 && startpos < savRTF.Text.Length) keepgoing = true; } else { SelectionStart = pos; SelectionLength = str.Length; } } else return false; } return true; } } private int FindStart() { foreach (LinkLocation ll in _LinkLocations) { if (SelectionStart == ll.End) return ll.Start; if (SelectionStart == ll.Start) { if (ll.Start == 7) return 7; return ll.Start - 8; } } if (SelectionStart > 0) return SelectionStart - 1; return 0; } private int FindEnd() { foreach (LinkLocation ll in _LinkLocations) { if (SelectionStart + SelectionLength + 7 == ll.Start) return ll.Length + 7; // this is for in-between links if (SelectionStart + SelectionLength == ll.Start) return ll.Length; } if (SelectionStart + SelectionLength < TextLength) return 1; return 0; } private int FindEndDown() { foreach (LinkLocation ll in _LinkLocations) { if (SelectionStart + SelectionLength >= ll.Start && SelectionStart + SelectionLength <= ll.End) return ll.End; } return 0; } // if the selection is on linked text, then return the length of that linked text (the rtf length) private int FindlinkWidth(bool movingRight, bool ctrlKey) { foreach (LinkLocation ll in _LinkLocations) { int selLen = SelectionLength + ((movingRight) ? 7 : 0); if (SelectionStart + selLen >= ll.Start && SelectionStart + selLen - ((!movingRight && ctrlKey)?1:0) <= ll.End) return ll.End - ll.Start + 7; } return 0; } private int FindStartUp() { foreach (LinkLocation ll in _LinkLocations) { if ((SelectionStart >= ll.Start) && (SelectionStart <= ll.End)) return ll.Start; } return -1; } public void SetSelection(LinkLocation ll) { SetSelection(ll.Start, ll.Length); } public void SetSelection(int locStart, int locLength) { //Application.DoEvents(); // Not needed since SendKeys is always done last. if (_IdentifyingLinks) DebugPrint("SS------------------------> {0} {1}", locStart, locLength); else DebugPrint("SS========================> {0} {1}", locStart, locLength); Select(locStart, locLength); } #endregion //#region FontAndStylesSupport //private void ToggleFontStyle(FontStyle style, bool att_on) //{ // int start = SelectionStart; // int len = SelectionLength; // System.Drawing.Font currentFont; // FontStyle fs; // for (int i = 0; i < len; ++i) // { // Select(start + i, 1); // currentFont = SelectionFont; // fs = currentFont.Style; // //add or remove style // if (!att_on)fs = fs | style; // else fs = fs & ~style; // SelectionFont = new Font( // currentFont.FontFamily, // currentFont.Size, // fs // ); // } //} /// /// Returns a Font with: /// 1) The font applying to the entire selection, if none is the default font. /// 2) The font size applying to the entire selection, if none is the size of the default font. /// 3) A style containing the attributes that are common to the entire selection, default regular. /// /// //public Font GetFontDetails() //{ // //This method should handle cases that occur when multiple fonts/styles are selected // int start = SelectionStart; // int len = SelectionLength; // int TempStart = 0; // if (len <= 1) // { // // Return the selection or default font // if (SelectionFont != null) // return SelectionFont; // else // return Font; // should be default from format. // } // // Step through the selected text one char at a time // // after setting defaults from first char // _rtbTemp.Rtf = SelectedRtf; // //Turn everything on so we can turn it off one by one // FontStyle replystyle = // FontStyle.Bold | FontStyle.Italic | FontStyle.Underline; // // Set reply font, size and style to that of first char in selection. // _rtbTemp.Select(TempStart, 1); // string replyfont = _rtbTemp.SelectionFont.Name; // float replyfontsize = _rtbTemp.SelectionFont.Size; // replystyle = replystyle & _rtbTemp.SelectionFont.Style; // // Search the rest of the selection // for (int i = 1; i < len; ++i) // { // _rtbTemp.Select(TempStart + i, 1); // // Check reply for different style // replystyle = replystyle & _rtbTemp.SelectionFont.Style; // // Check font // if (replyfont != _rtbTemp.SelectionFont.FontFamily.Name) // replyfont = ""; // // Check font size // if (replyfontsize != _rtbTemp.SelectionFont.Size) // replyfontsize = (float)0.0; // } // // Now set font and size if more than one font or font size was selected // if (replyfont == "") // replyfont = _rtbTemp.Font.FontFamily.Name; // if (replyfontsize == 0.0) // replyfontsize = _rtbTemp.Font.Size; // // generate reply font // Font reply // = new Font(replyfont, replyfontsize, replystyle); // return reply; //} //#endregion #region EnumsSelectionRange private enum StartStatus : int { Before = 100, Between = 200, StartLink = 300, StartBox = 400 }; private enum EndStatus : int { After = 1, Between = 2, EndLink = 3, EndBox = 4, StartLink = 5 }; public enum RangeStatus : int { NoContainedLinks = 0, Before_After = StartStatus.Before + EndStatus.After, Before_Between = StartStatus.Before + EndStatus.Between, Before_EndLink = StartStatus.Before + EndStatus.EndLink, Before_EndBox = StartStatus.Before + EndStatus.EndBox, Before_StartLink = StartStatus.Before + EndStatus.StartLink, Between_After = StartStatus.Between + EndStatus.After, Between_Between = StartStatus.Between + EndStatus.Between, Between_EndLink = StartStatus.Between + EndStatus.EndLink, Between_EndBox = StartStatus.Between + EndStatus.EndBox, Between_StartLink = StartStatus.Between + EndStatus.StartLink, StartLink_After = StartStatus.StartLink + EndStatus.After, StartLink_Between = StartStatus.StartLink + EndStatus.Between, StartLink_EndLink = StartStatus.StartLink + EndStatus.EndLink, StartLink_EndBox = StartStatus.StartLink + EndStatus.EndBox, StartLink_StartLink = StartStatus.StartLink + EndStatus.StartLink, StartBox_After = StartStatus.StartBox + EndStatus.After, StartBox_Between = StartStatus.StartBox + EndStatus.Between, StartBox_EndLink = StartStatus.StartBox + EndStatus.EndLink, StartBox_EndBox = StartStatus.StartBox + EndStatus.EndBox, StartBox_StartLink = StartStatus.StartBox + EndStatus.StartLink }; private RangeStatus _RTBRangeStatus; public RangeStatus RTBRangeStatus { get { return _RTBRangeStatus; } set { _RTBRangeStatus = value; if (!_ProcessingDelete) OnRTBRangeStatusChanged(this, new EventArgs()); } } private LinkLocation _RangeStartLink = null; private LinkLocation _RangeEndLink = null; public RangeStatus FindRangeStatus() { _RangeStartLink = null; _RangeEndLink = null; if (_LinkLocations == null || _LinkLocations.Count == 0) { return RTBRangeStatus = RangeStatus.NoContainedLinks; } LinkLocation foundLink = null; int start = SelectionStart; int end = start + SelectionLength; foreach (LinkLocation ll in _LinkLocations) { if (foundLink == null && ((ll.Start >= start && ll.Start < end) || (ll.End >= start && ll.End < end))) foundLink = ll; if (_RangeStartLink == null && start >= ll.Start - 7 && start < ll.End) _RangeStartLink = ll; if (_RangeEndLink == null && end >= ll.Start && end <= ll.End) _RangeEndLink = ll; } DebugPrint("SelectionStart {0}, SelectionEnd {1}, TextLength {2}", SelectionStart, SelectionStart + SelectionLength, TextLength); //if (_RangeStartLink != null) // _RangeStartLink.Show("startLink"); //if (_RangeEndLink != null) // _RangeEndLink.Show("endLink"); //if (foundLink != null) // foundLink.Show("foundLink"); if (foundLink == null) return RTBRangeStatus = RangeStatus.NoContainedLinks; StartStatus myStartStatus = StartStatus.Before; EndStatus myEndStatus = EndStatus.After; if (_RangeStartLink != null) { if (_RangeStartLink.Start == 7) myStartStatus = StartStatus.StartBox; else if (_RangeStartLink.StartsBetween) myStartStatus = StartStatus.Between; else myStartStatus = StartStatus.StartLink; } if (_RangeEndLink != null) { if (_RangeEndLink.End == TextLength) myEndStatus = EndStatus.EndBox; else if (_RangeEndLink.NextStart == _RangeEndLink.End) myEndStatus = EndStatus.Between; else if (end == _RangeEndLink.Start) myEndStatus = EndStatus.StartLink; // Should not happen because of code in HandleSelectionChange else //if (end == endLink.End) myEndStatus = EndStatus.EndLink; } return RTBRangeStatus = (RangeStatus)((int)myStartStatus + (int)myEndStatus); } #endregion #region OutlineTable private string _CheckRight = "-\u2500\u2011"; public string CheckRight { get { return _CheckRight; } set { _CheckRight = value; } } private string _CheckAbove = "|\u2502\u2514\u252c\u253c\u251c\u250c\u2534\u2510\u2524"; public string CheckAbove { get { return _CheckAbove; } set { _CheckAbove = value; } } private string _CheckLeft = "-\u2500\u2524\u252c\u251c\u253c\u250c\u2510\u2514\u2011"; public string CheckLeft { get { return _CheckLeft; } set { _CheckLeft = value; } } private string _CheckBelow = "|\u2502"; public string CheckBelow { get { return _CheckBelow; } set { _CheckBelow = value; } } // This is a table of graphics characters // The index into this table (0-15) is a bitmask with each bit representing // a different direction from the current character. // Right is Bit 0 (0 or 1) // Above is Bit 1 (0 or 2) // Left is Bit 2 (0 or 4) // Below is Bit 3 (0 or 8) // The index is contolled in the following way: // If there is a graphics character to the right, then you add 1 // If there is a graphics character above, then you add 2 // If there is a graphics character left, then you add 4 // If there is a graphics character below, then you add 8 // The total results in an index into this array and gives the appropriate character // combining horizontal and vertical lines. static private string [] TableCharsU = { "\x0", // HEX"\x0", // No character @"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4' @"\u9474", // HEX@"\u2502",// | Vertical line - 16-bit char: '\xB3' @"\u9492", // HEX@"\u2514",// L Bottom Left corner - 16-bit char: '\xC0' @"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4' @"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4' @"\u9496", // HEX@"\u2518",// Bottom Right Corner - 16-bit char: '\xD9' @"\u9524", // HEX@"\u2534",// Bottom Tee - 16-bit char: '\xC1' @"\u9474", // HEX@"\u2502",// | Vertical Bar - 16-bit char: '\xB3' @"\u9484", // HEX@"\u250c",// Upper Left corner - 16-bit char: '\xDA' @"\u9474", // HEX@"\u2502",// | Vertical Bar - 16-bit char: '\xB3' @"\u9500", // HEX@"\u251c",// Left Tee - 16-bit char: '\xC3' @"\u9488", // HEX@"\u2510",// Upper Right corner - 16-bit char: '\xBF' @"\u9516", // HEX@"\u252c",// T Top Tee - 16-bit char: '\xC2' @"\u9508", // HEX@"\u2524",// Right Tee - 16-bit char: '\xB4' @"\u9532", // HEX@"\u253c" // + Plus - 16-bit char: '\xC5' }; private int MaxCharacterWidth() { // loop through lines and get the width in characters int w = 0; foreach (string line in Lines) { string cleanLine = RemoveLinkComments(line); if (w < cleanLine.Length) w = cleanLine.Length; } return w; } internal static string RemoveLinkComments(string line) { StringBuilder sb = new StringBuilder(); int lastIndex = 0; MatchCollection mc = Regex.Matches(line, @"", RegexOptions.Singleline); foreach (Match m in mc) { sb.Append(line.Substring(lastIndex, m.Index - lastIndex)); // Append text before the link sb.Append(m.Groups[1].Value); // Append the text portion of the link lastIndex = m.Index + m.Length; // Calculate the beginning of the remaining text } sb.Append(line.Substring(lastIndex)); // Append the text following the last link string result = sb.ToString(); result = result.Replace(@""); if (mcEnd.Count > 0) { result = result.Substring(0, mcEnd[0].Index) + result.Substring(mcEnd[0].Index + mcEnd[0].Length); } return result; } private void ReplaceLinesInTable(bool withBorder) { int rowWidth = Lines[0].Length; for (int row=1;row", RegexOptions.Singleline);// this last parameter was commented out in 7/24/09 but it appears to be valid if (matchCollection.Count == 0) matchCollection = Regex.Matches(line, @""); Match match = matchCollection.Count > 0 ? matchCollection[0] : null; int matchOffset = 0; for (int col = 1; col < rowWidth - 1; col++) { if (match != null && match.Index == matchOffset + col) { matchOffset += match.Length - match.Groups[1].Length; // Increment the offset by the link comment length col += match.Groups[1].Length; // increment the column by the link value length if (col >= rowWidth - 1) break;// Don't continue if beyond the contents match = match.NextMatch(); // Watch for the next match } int coll = matchOffset + col; char chr = line[coll]; char chrLast = line[coll - 1]; char chrNext = line[coll + 1]; char chrAbove = lineAbove[col]; char chrBelow = lineBelow[col]; // The following is all using symbol font (either unicode for proportional or // VeSymbFix for fixed font): // if this character is a table line draw character, i.e. a dash or vertical bar, or // graphics characters for those, look around it to see what table character it is // replaced with // Look for -||-- (last three are graphics chars or unicode dash) if ("-|\u2500\u2502\u2011".IndexOf(chr) > -1) { bool horizontalCharacter = "-\u2500\u2011".IndexOf(chr) > -1; int lineDrawRight = (CheckRight.IndexOf(chrNext) > -1 || (horizontalCharacter && "\u2502".IndexOf(chrNext) > -1)) ? 1 : 0; int lineDrawAbove = (CheckAbove.IndexOf(chrAbove) > -1 || (!horizontalCharacter && "\u2500\u2011".IndexOf(chrAbove) > -1)) ? 2 : 0; int lineDrawLeft = (CheckLeft.IndexOf(chrLast) > -1 || (horizontalCharacter && "\u2502".IndexOf(chrLast) > -1)) ? 4 : 0; int lineDrawBelow = (CheckBelow.IndexOf(chrBelow) > -1 || (!horizontalCharacter && "-\u2500\u2011".IndexOf(chrBelow) > -1)) ? 8 : 0; int tableCharIndx = lineDrawRight + lineDrawAbove + lineDrawLeft + lineDrawBelow; if (tableCharIndx > 0) { SetTableChar(row, coll, tableCharIndx); if (withBorder) // Adjust the border as it intersects with lines within the box { if (row == 1 && !horizontalCharacter ) SetTableChar(row - 1, col, 13); // Top Row if (row == Lines.Length - 2 && !horizontalCharacter) SetTableChar(row + 1, col, 7); // Bottom Row if (col == 1 && horizontalCharacter && ((tableCharIndx & 4)==4)) SetTableChar(row, col - 1, 11); // First Column if (col == rowWidth - 2 && horizontalCharacter && ((tableCharIndx & 1) == 1)) SetTableChar(row, coll + 1, 14); // Last Column } } } } } } private void SetTableChar(int row, int col, int tableCharIndx) { int rowOffset = GetFirstCharIndexFromLine(row); Select(rowOffset + col, 1); string charToBeReplaced = SelectedText; if (Text.Length > (rowOffset + col + 7) && Text.Substring(rowOffset + col + 1, 6) != "#Link:") SelectedRtf = RtfPrefixForSymbols + TableCharsU[tableCharIndx] + "?}"; else { SelectionStart++; int lenComment = 1 + SelectionStart - (rowOffset + col); //Console.WriteLine("{0},{1},{2}", rowOffset + col, SelectionStart, SelectionLength); Select(rowOffset + col, 0); SelectedRtf = RtfPrefixForSymbols + TableCharsU[tableCharIndx] + "?}"; Select(rowOffset + col, lenComment); //Console.WriteLine("'{0}',{1},{2},{3}", SelectedText, lenComment, SelectionLength, SelectionStart); //Console.WriteLine("'{0}'", SelectedRtf); SelectedRtf = SelectedRtf.Replace(" " + charToBeReplaced, ""); } } #endregion #region SpellChecker private static bool _DoSpellCheck = true; public static bool DoSpellCheck { get { return StepRTB._DoSpellCheck; } set { StepRTB._DoSpellCheck = value; } } // We made the Spell Checker method a static so that all of the StepRTB boxes will share the same instance of the dictionary. // This allow all the StepRTB's to automatically update when a new word is added. private static C1.Win.C1SpellChecker.C1SpellChecker _C1SpellChecker2; private static C1.Win.C1SpellChecker.C1SpellChecker C1SpellChecker2 { get { if (_C1SpellChecker2 == null) { _C1SpellChecker2 = new C1.Win.C1SpellChecker.C1SpellChecker(); _C1SpellChecker2.ContextMenuCreated += new C1.Win.C1SpellChecker.ContextMenuEventHandler(_C1SpellChecker2_ContextMenuCreated); // The veproms.dct file is the main spell checker dictionary. // We edited the C1 dictionary (C:\Program Files\ComponentOne\Dictionaries\C1Spell_en-US.dct) using ComponentOne's // dictionary editor (C:\Program Files\ComponentOne\Studio for WinForms\C1SpellChecker\C1DictionaryEditor.exe) // and added the veproms.words list as another word list in the dictionary. We saved the resulting file as veproms.dct. string dictpath = string.Format(@"{0}\veproms.dct", Application.StartupPath); // Only use the veproms.dct if it is found in the BIN folder. Otherwise, let it default to use the standard dictionary. if (File.Exists(dictpath)) _C1SpellChecker2.MainDictionary.FileName = dictpath; // looks in the bin folder by default // NOTE: By default, a "Custom.dct" file (UserDictionary) will be created in the BIN folder when a user adds words to the // spell checker dictionary. The words that the user adds are not placed in the Volian.dct file. //_C1SpellChecker2.UserDictionary.FileName = @"C:\Development\proms\VEPROMS User Interface\bin\Debug\MYDictionary.dct"; } return StepRTB._C1SpellChecker2; } } // the grid uses this to reference the same instance of the spell checker public C1.Win.C1SpellChecker.C1SpellChecker SpellCheckerInstance { get { return C1SpellChecker2; } } // Get or Save our context menu // This is added to the the spell checker's context menu for a mis-spelled word private static ContextMenuStrip _ThisContextMenuStrip; public ContextMenuStrip ThisContextMenuStrip { get { return _ThisContextMenuStrip; } set { _ThisContextMenuStrip = value; } } private static StepRTB _ContextMenuStepRTB; private static object _ContextMenuStrip; static void _C1SpellChecker2_ContextMenuCreated(object sender, C1.Win.C1SpellChecker.ContextMenuEventArgs e) { // Adjust their bad word context menu //Console.WriteLine("==========> spell check context menu {0}",e.Menu.Items[0].Text); if (e.Menu.Equals(_ContextMenuStrip)) { // Add an item for our "Edit Menu" context menu on their spell check context menu // This gives the user access to our regular context menu when on a mis-spelled word ToolStripItem tsi = e.Menu.Items.Add("Edit Menu"); tsi.Click += new EventHandler(tsi_Click); //Now replace their "Spell" item with ours, so that we can display our custom spell check dialog bool onword = true; for (int i = 0; i < e.Menu.Items.Count; i++) { ToolStripItem tsi1 = e.Menu.Items[i]; if (tsi1 is ToolStripMenuItem && tsi1.Text == "Spell") { e.Menu.Items.RemoveAt(i); // remove their spell check dialog item ToolStripMenuItem tsi2 = new ToolStripMenuItem("Spell"); tsi2.Click += new EventHandler(tsi2_Click); e.Menu.Items.Insert(i, tsi2); // add our spell check dialog item } else if (tsi1 is ToolStripMenuItem && tsi1.Text == "Clip Board") // B2017-024 added the Clip Board context menu in FrmSi design { e.Menu.Items.RemoveAt(i + 1); // if Clip Board menu item is there, then remove o ur Edit Menu } else { // B2016-242: check for editorial change on spell check word click. // Add an event to any context menu items that have a corrected word. // Note that a line separates corrected words from menu item selections // and the line does not have any text. So once we hit the line, don't add // event handler to flag the user selected to use the correction. if (onword) e.Menu.Items[i].Click += new EventHandler(spellcheckWord_Click); if (e.Menu.Items[i].Text == null || e.Menu.Items[i].Text == "") onword = false; } } } } static void spellcheckWord_Click(object sender, EventArgs e) { ToolStripMenuItem tsmi = sender as ToolStripMenuItem; if (tsmi != null) { // B2016-242: because this is a static method, the format flag for EditorialSpellCheck cannot be checked // before setting 'DidEditorialSpellCheck'. But the format flag is checked before the 'DidEditorialSpellCheck' // is actually used in rtbitem. DidEditorialSpellCheck = true; } } static void tsi2_Click(object sender, EventArgs e) { C1SpellChecker2.CheckControl(_ContextMenuStepRTB, true, MySpellCheckDlg); } // Click event to display our "Edit Menu" (StepRTB context menu) static void tsi_Click(object sender, EventArgs e) { ToolStripMenuItem tsmi = sender as ToolStripMenuItem; //_ContextMenuStepRTB.MyRTBItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.OpenContextMenu(tsmi.Owner.Location); _ContextMenuStepRTB.OnOpenContextMenu(sender, new StepRTBLocationEventArgs(tsmi.Owner.Location)); } // This is our customized Spell Check dialog // This is display when the use clicks the Spell button from the Ribbon // or when the "Spell" item is selected from the context menu when on a mis-spelled word static VlnSpellCheckDlg _MySpellCheckDlg; public static VlnSpellCheckDlg MySpellCheckDlg { get { if (_MySpellCheckDlg == null) _MySpellCheckDlg = new VlnSpellCheckDlg(); return _MySpellCheckDlg; } } // B2015-024 have Spell Checker text changes be in editorial mode (not assign a change bar but keep existing change bar) public static bool DidEditorialSpellCheck = false; // This is used when walking through the section doing a spell check // (from the Spell button on the ribbon) public bool SpellCheckNext() { int nBad = C1SpellChecker2.CheckControl(this, false, MySpellCheckDlg); if (MyItemInfo.ActiveFormat.PlantFormat.FormatData.EditData.EditoralSpellCheck) DidEditorialSpellCheck = MySpellCheckDlg.DidCorrectSpelling; // B2015-024 spell checker in editoral mode return (nBad >= 0); // nBad = -1 means user pressed Cancel button } // This allows us to turn off/on the spell check context menu when we toggle in and out of View Mode. // see btnToggleEditView_Click() in StepTabRibbon.cs public void SpellCheckContextMenuOn(bool turnOnMenu) { C1SpellChecker2.Options.ShowSuggestionsInContextMenu = turnOnMenu; } #endregion #region public string DoNewLinkInGridCell() { // first find the new link and determine whether it's RO or transition. int indx = Rtf.IndexOf(@"#Link:ReferencedObject:"); if (indx > 0) { Match mro = Regex.Match(Rtf.Substring(indx, Rtf.Length - indx), @"([A-Za-z]*):(.*?)\[END>"); string linkstr = mro.Groups[2].Value; string[] roparts = linkstr.Split(" ".ToCharArray()); ContentRoUsage rousg = null; int oldid = -1; using (Item itm = MyItemInfo.Get()) { using (RODb rodb = RODb.GetJustRoDb(Convert.ToInt32(roparts[2]))) { rousg = itm.MyContent.ContentRoUsages.Add(roparts[1], rodb); } //get temporary rousageid oldid = rousg.ROUsageID; Rtf = Rtf.Replace("", string.Format("", rousg.ROUsageID)); //save temporary rousageid to get real rousageid itm.Save(); //replace temprorary rousageid with real rousageid Rtf = Rtf.Replace(string.Format("", oldid), rousg.ROUsageID.ToString()); //save real rousageid itm.Save(); MyItemInfo.MyContent.RefreshContentRoUsages(); } } // Need to look for any 'New' transitions, don't include existing ones. Match mt = Regex.Match(Rtf, @"#Link:Transition:([0-9]+) "); if (mt.Length <= 0) mt = Regex.Match(Rtf, @"#Link:TransitionRange:([0-9]+) "); if (mt.Length > 0) { indx = mt.Index+6; // get past '#Link:" Match m = Regex.Match(Rtf.Substring(indx, Rtf.Length - indx), @"([A-Za-z]*):(.*?)\[END>"); bool isSingleTran = true; if (Rtf.Substring(indx, 16).IndexOf("TransitionRange") >= 0) isSingleTran = false; string linkstr = m.Groups[2].Value; string[] tparts = linkstr.Split(" ".ToCharArray()); int type = System.Convert.ToInt32(tparts[0]); int tr1 = System.Convert.ToInt32(tparts[2]); // tparts[2] is token for tranid int tr2 = tr1; if (tparts.Length > 3) tr2 = System.Convert.ToInt32(tparts[3]); // tparts[3] is token for rangeid bool dispose1 = false; Item itm1 = null; bool dispose2 = false; Item itm2 = null; using (Item itm = MyItemInfo.Get()) { if (itm.ItemID == tr1) itm1 = itm; // a transition that points to itself should not dispose else { dispose1 = true; itm1 = Item.Get(tr1); } if (itm.ItemID == tr2) itm2 = itm; // a transition that points to itself should not dispose else if (tr1 == tr2) itm2 = itm1; // if both destinations are the same only dispose the first one else { dispose2 = true; itm2 = Item.Get(tr2); } ContentTransition ct = itm.MyContent.ContentTransitions.Add(itm1, itm2); //Console.WriteLine("CT {0},{1},{2},{3}", ct.TransitionID, itm.ItemID, itm.MyContent.MyContentUnique, itm.MyContent.ContentTransitions.Count); ct.TranType = type; if (isSingleTran) ct.IsRange = 0; else if (tr1 != tr2) ct.IsRange = 1; else ct.IsRange = 2; int oldidt = ct.TransitionID; Rtf = Rtf.Replace("", string.Format("", ct.TransitionID)); itm.Save(); Rtf = Rtf.Replace(string.Format("", oldidt), ct.TransitionID.ToString()); itm.Save(); MyItemInfo.MyContent.RefreshContentTransitions(); } if (dispose2) itm2.Dispose(); if (dispose1) itm1.Dispose(); } return Rtf; } #endregion #region RoInsertInterface public void UpdateStepRtb(string linktxt, string valtxt) { int ss = SelectionStart; // Remember where the link is being added int sl = SelectionLength; OnReturnToEditor(this, new EventArgs()); Select(ss, sl); InsertRO(valtxt, linktxt); // Insert the LINK OnDoSaveContents(this, new EventArgs()); // .SaveText(); // Save the text with the LINK - This also moves the cursor to the end of the text // By selecting a starting position within a link, StepRTB (HandleSelectionChange) will select the link Select(ss + 7 + valtxt.Length, 0);// Select the link, Try 7 for "