using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Text.RegularExpressions; using System.Drawing; namespace VEPROMS.CSLA.Library { public class DisplayText { #region Properties private ItemInfo _MyItemInfo; // list of 'pieces of text' for this item. Pieces include symbols, ros, // transitions & plain text. private List _DisplayTextElementList; public List DisplayTextElementList { get { return _DisplayTextElementList; } set { _DisplayTextElementList = value; } } // dictionary for the font table for this item. Note that this may // go away (it is not really used). private Dictionary _dicRtfFontTable; public Dictionary dicRtfFontTable { get { return _dicRtfFontTable; } set { _dicRtfFontTable = value; } } private VE_Font _textFont; // Font from format for this item public VE_Font TextFont { get { return _textFont; } set { _textFont = value; } } public string StartText; public string OriginalText; // compare for save to see if change. private FormatInfo _MyFormat; #endregion #region Constructors /// /// DisplayText constructor: /// Creates a DisplayText object that converts the database text into rtf text /// Arguments are: /// ItemInfo itemInfo - the item whose text will be resolved /// E_EditPrintMode ep_mode - edit or print. /// E_ViewMode vw_mode - view or edit. /// bool noEdit - flags whether to edit or not (used to set data in /// rtb as resolved replacewords for non-active rtb. /// public DisplayText(ItemInfo itemInfo, E_EditPrintMode epMode, E_ViewMode vwMode, bool noEdit) { _MyItemInfo = itemInfo; OriginalText = itemInfo.MyContent.Text; TextFont = GetItemFont(); string text = _MyItemInfo.MyContent.Text; // if in print mode, view mode, or non-active richtextbox do replace words. Only if in // actual edit mode are replace words left as is. _MyFormat = itemInfo.ActiveFormat; if (epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit) text = DoReplaceWords(text); // adjust formatting of exponents if (!_MyFormat.PlantFormat.FormatData.SectData.StepSectionData.FortranFormatNumbers && (epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit)) text = DoFortranFormat(text); // as a precaution, convert any \~ to \u160?. This is for Hard spaces. see the commentary in the // save portion of this code for an explanation. text = text.Replace(@"\~", @"\u160?"); text = text.Replace(@"\r\n", @"\par "); text = text.Replace(@"\line", @"\par"); // add colors around links: text = Regex.Replace(text, @"( x103 where 3 is superscripted // and 10.E5 -> 10x10-5 where 5 is superscripted string pat = @"(\d*).E([+-]*\d+)"; string retstr = text; // for each one that needs translated: foreach (Match m in Regex.Matches(text, pat)) { string fnum = m.Groups[1].Value; string supnum = m.Groups[2].Value; string newstr = string.Format(@"{0}x10\super {1}\nosupersub ", fnum, supnum); retstr = retstr.Replace(m.Value, newstr); } return retstr; } #endregion #region SaveData public bool Save(RichTextBox rtb) { try { Item itm = _MyItemInfo.Get(); // check for different text, i.e. text from this itm doesn't match // original text, a change occurred in database, but not from this user. if (OriginalText != itm.MyContent.Text) { Console.WriteLine("Save Failed because text changed outside of this edit session."); return false; } // remove rtf codes that aren't defining attributes, symbols, or links string modtext = RtfToDbText(rtb.Rtf); if (modtext != OriginalText) { // if there are links, we'll need to do extra processing to see if // there were additions, deletions or modifications. bool haslinks = ((modtext.IndexOf(@" -1) || (OriginalText != null && OriginalText != "" && OriginalText.IndexOf(@" -1)); if (haslinks) { // Get all links in original list RtfToDisplayTextElements(OriginalText); List origList = GetLinkList(DisplayTextElementList); // now get new text into displaytext elements for comparison for links: RtfToDisplayTextElements(rtb.Rtf); // Compare ro/transition lists and delete or add any to the item for any ros/transitions that have been // added/deleted or modified. ProcessRoTranChanges(itm, origList); itm.MyContent.Text = DteToString(); } else { itm.MyContent.Text = modtext; itm.Save(); } if (haslinks) { // if new transitions/ros, we need to 'fix' the string in the embedded link to contain the // transition or usage record. Dictionary ctReplacements = BuildCtReplacements(itm.MyContent.ContentTransitions); Dictionary roUsgReplacements = BuildRoUsgReplacements(itm.MyContent.ContentRoUsages); itm.Save(); if (ctReplacements.Count > 0) { itm.MyContent.Text = FixCtReplacements(itm.MyContent.Text, ctReplacements); itm.Save(); } if (roUsgReplacements.Count > 0) { itm.MyContent.Text = FixRoUsgReplacements(itm.MyContent.Text, roUsgReplacements); itm.Save(); } modtext = itm.MyContent.Text; } OriginalText = modtext; } else return true; // no text changed, but did not fail so return true. } catch (Exception ex) { Console.WriteLine("Save Failed with error: {0}", ex.Message); return false; } return true; } private string DteToString() { StringBuilder sret = new StringBuilder(); foreach (displayTextElement vte in DisplayTextElementList) { if (vte.Type == E_TextElementType.Text || vte.Type == E_TextElementType.Symbol) sret.Append(vte.Text); else { displayLinkElement dle = vte as displayLinkElement; if (vte != null) sret.Append(dle.TextAndLink); } } string modtext = sret.ToString(); return modtext; } private string FixRoUsgReplacements(string p, Dictionary roUsgReplacements) { foreach (int oldid in roUsgReplacements.Keys) { p = p.Replace(string.Format("", oldid), roUsgReplacements[oldid].ROUsageID.ToString()); } return p; } private Dictionary BuildRoUsgReplacements(ContentRoUsages contentRoUsages) { Dictionary retval = new Dictionary(); foreach (ContentRoUsage rou in contentRoUsages) { if (rou.ROUsageID < 0) retval.Add(rou.ROUsageID, rou); } return retval; } private string FixCtReplacements(string p, Dictionary ctReplacements) { foreach (int oldid in ctReplacements.Keys) { p = p.Replace(string.Format("",oldid),ctReplacements[oldid].TransitionID.ToString()); } return p; } private Dictionary BuildCtReplacements(ContentTransitions contentTransitions) { Dictionary retval = new Dictionary(); foreach (ContentTransition ct in contentTransitions) { if (ct.TransitionID < 0) retval.Add(ct.TransitionID, ct); } return retval; } private void ProcessRoTranChanges(Item itm, List origList) { // go through list. Note that only linked items are in the origList. // 1) delete any that are in origList but not in the DisplayTextElementList // (that represents the current text & links) // 2) add any that are only in DisplayTextElementList // 3) delete/add for modify? // delete first - if in original, but not in current list, delete the one // in the original list. foreach (displayLinkElement odte in origList) { bool found = false; foreach (displayTextElement dte in DisplayTextElementList) { if (dte.Type == odte.Type) { displayLinkElement l_dte = (displayLinkElement)dte; if (odte.Link == l_dte.Link) { found = true; break; } } } // remove the link element from the item. if (!found) { // Get record id for ro or trans and then find the associated ro or transition // in the item's list. remove it. int recid = -1; if (odte.Type != E_TextElementType.ReferencedObject) { int sp = odte.Link.IndexOf(" ") + 1; // get past tran type string srecid = odte.Link.Substring(sp, odte.Link.IndexOf(" ", sp) - sp); recid = System.Convert.ToInt32(srecid); foreach (ContentTransition ct in itm.MyContent.ContentTransitions) { if (ct.TransitionID == recid) { itm.MyContent.ContentTransitions.Remove(ct); break; } } } else { int sp = odte.Link.IndexOf(" "); //rousageid starts after "ReferencedObject:", i.e. index in link of 17 string srecid = odte.Link.Substring(17, sp-17); recid = System.Convert.ToInt32(srecid); foreach (ContentRoUsage cr in itm.MyContent.ContentRoUsages) { if (cr.ROUsageID == recid) { itm.MyContent.ContentRoUsages.Remove(cr); break; } } } } } // now do insert, i.e. in new list, but not in old. foreach (displayTextElement dte in DisplayTextElementList) { bool found = false; if (dte.Type == E_TextElementType.ReferencedObject || dte.Type == E_TextElementType.Transition || dte.Type == E_TextElementType.TransitionRange) { foreach (displayLinkElement odte in origList) { if (dte.Type == odte.Type) { // if the link is the same, it exists, so no action is required. displayLinkElement l_dte = (displayLinkElement)dte; if (odte.Link == l_dte.Link) { found = true; break; } } } // Insert the link (ro or transition) to the item if (!found) { if (dte.Type == E_TextElementType.ReferencedObject) // do ro { displayLinkElement l_dte = (displayLinkElement)dte; Match m = Regex.Match(l_dte.Link, "([A-Za-z]*):(.*)"); string linkstr = m.Groups[2].Value; string[] roparts = linkstr.Split(" ".ToCharArray()); ContentRoUsage rousg = null; using (RODb rodb = RODb.Get(Convert.ToInt32(roparts[2]))) { rousg = itm.MyContent.ContentRoUsages.Add(roparts[1], rodb); } l_dte.Link = l_dte.Link.Replace("", string.Format("", rousg.ROUsageID)); l_dte.TextAndLink = l_dte.TextAndLink.Replace("", string.Format("", rousg.ROUsageID)); break; } else if (dte.Type == E_TextElementType.TransitionRange || dte.Type == E_TextElementType.Transition) { displayLinkElement l_dte = (displayLinkElement)dte; Match m = Regex.Match(l_dte.Link, "([A-Za-z]*):(.*)"); 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[1] is token for tranid Item itm1 = Item.Get(tr1); Item itm2 = null; if (dte.Type == E_TextElementType.TransitionRange) { itm2 = Item.Get(System.Convert.ToInt32(tparts[2])); } else itm2 = itm1; ContentTransition ct = itm.MyContent.ContentTransitions.Add(itm1, itm2); ct.TranType = type; l_dte.Link = l_dte.Link.Replace("", string.Format("", ct.TransitionID)); l_dte.TextAndLink = l_dte.TextAndLink.Replace("", string.Format("", ct.TransitionID)); } } } } } private List GetLinkList(List locDisplayTextElementList) { List retList = new List(); foreach (displayTextElement vte in locDisplayTextElementList) { if (vte.Type == E_TextElementType.ReferencedObject || vte.Type == E_TextElementType.TransitionRange || vte.Type == E_TextElementType.Transition) { displayLinkElement tmp = (displayLinkElement)vte; displayLinkElement copy_vte = new displayLinkElement(); copy_vte.Type = tmp.Type; copy_vte.Link = tmp.Link; copy_vte.Text = tmp.Text; retList.Add(copy_vte); } } return retList; } private void RtfToDisplayTextElements(string text) { // get original text into displaytext elements for comparison for links: if (DisplayTextElementList == null) DisplayTextElementList = new List(); else DisplayTextElementList.Clear(); if (text == null || text == "") return; string noExtraRtfStr = RtfToDbText(text); int startIndex = 0; int index = -1; while ((index = FindTokenChar(noExtraRtfStr, startIndex)) > -1) { // Do any 'plain' text that preceeds the token. if (index > startIndex) DoTextElement(noExtraRtfStr, startIndex, index); if (noExtraRtfStr[index + 1] == 'v') index = DoLink(noExtraRtfStr, index); else index = DoSymbol(noExtraRtfStr, startIndex, index); startIndex = index; // +1; if (startIndex >= noExtraRtfStr.Length) break; } // Add any remaining text. if (startIndex < noExtraRtfStr.Length) DoTextElement(noExtraRtfStr, startIndex, index); } private string RtfToDbText(string text) { // For hardspaces, the windows richtextbox does some 'quirky' things: // A unicode representation of \u160? is sent INTO the rtb. Coming out, // that \u160? was translated to a \~ (by the underlying windows rtb). // Note that if the \~ is sent to the rtb, it is treated as a regular space, // i.e. no longer a hardspace, and actually is converted to a regular space. // SO, on the way out, convert any \~ to \u160? string noExtraRtfStr = text.Replace(@"\~", @"\u160?"); // Check for two links in a row & if found, add separating rtf comment // commands (these get removed in the richtextbox: noExtraRtfStr = noExtraRtfStr.Replace(@"[END>\v0 \v -1) noExtraRtfStr = noExtraRtfStr.Replace(@"\'05", "\x05"); return noExtraRtfStr; } private string RemoveRtfStyles(string rtf) { string retval = rtf; // remove rtf commands for any styles that were added. Note that if // the entire item has a style, and also contains 'pieces' of text with // the same style, the underlying rtf box removes the embedded rtf commands, // for example, if the entire step is bolded, and 'THEN' has bold on/off // surrounding it, the rtf box removes the bold around the 'THEN' // These remove the command with a following space or the command alone, // either case may exist, because if there are rtf commands following the // style command, there will be no space character following the style command. if (((TextFont.Style & E_Style.Bold) > 0) || ((TextFont.Style & E_Style.MmBold) > 0)) { retval = Regex.Replace(retval, @"\\b0 ?", ""); retval = Regex.Replace(retval, @"\\b ?",""); } if ((TextFont.Style & E_Style.Underline) > 0) { retval = Regex.Replace(retval, @"\\ulnone ?", ""); retval = Regex.Replace(retval, @"\\ul ?", ""); } if ((TextFont.Style & E_Style.Italics) > 0) { retval = Regex.Replace(retval, @"\\i0 ?", ""); retval = Regex.Replace(retval, @"\\i ?", ""); } return retval; } public string ReplaceRTFClause(Match m) { switch (m.Value[1]) { case 'u': if (Regex.IsMatch(m.Value, @"\\u[0-9]+")) return m.Value; // Special Charcaters if (Regex.IsMatch(m.Value, @"\\ulnone")) return m.Value; if (Regex.IsMatch(m.Value, @"\\ul.*")) return m.Value; // Underline break; case '\'': // Special Character return m.Value; case 'b': // Bold return m.Value; case 's': // sub or super.... if (m.Value == @"\sub") return m.Value; if (m.Value == @"\super") return m.Value; break; case 'n': // nosubsuper... if (m.Value == @"\nosupersub") return m.Value; break; case 'i': // Italics return m.Value; case '{': // look for escape for curly braces: return m.Value; case '}': return m.Value; case 'v': // save link hidden info if (m.Value == @"\v") return m.Value; // comment part of link // end comment may end in space or may end in '\' if another rtf command, // or may end at end of string. First check for space, keep it in string // if it is there. if (Regex.IsMatch(m.Value, @"\\v0 ")) return m.Value; if (Regex.IsMatch(m.Value, @"\\v0")) return m.Value; break; case 'l': if (m.Value == @"\line") return m.Value; break; case 'p': if (m.Value == @"\par") return @"\par"; //if (m.Value == @"\protect") // return m.Value; //if (m.Value == @"\protect0") // return m.Value; if (m.Value.Length>=6 && m.Value.Substring(0,6) == "\\par\r\n") return m.Value.Replace("\r\n", " "); break; case 'f': // handle fonts separately because they may or may not have a space after them if (m.Value[2]>='0' && m.Value[2]<='9')return m.Value; break; } return "";//Strip All } private string StripRtfCommands(string rtf) { // replace \{ & \} with (![ & (!] respectively and then redo at end. The curly braces // are rtf so were getting removed and/or not handled correctly. string retval = rtf.Replace(@"\{", @"(!["); retval = retval.Replace(@"\}", @"(!]"); // remove carriage return/newlines after \par commands (these are introduced by rtb // for hard returns, goes into rtb as \par and comes out as \par\r\n): retval = Regex.Replace(retval, @"\\par\r\n([^\\.*?])", "\\par $1"); retval = Regex.Replace(retval, @"\\par\r\n([\\.*?])", "\\par$1"); retval = Regex.Replace(retval, @"[\r\n]", "", RegexOptions.Singleline); // Strip Carriage Returns and Newlines retval = Regex.Replace(retval, @"^\{(.*)\}$", "$1", RegexOptions.Singleline); // Strip Opening and Closing Braces retval = Regex.Replace(retval, @"\{[^{]*?\}", "", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces retval = Regex.Replace(retval, @"\{[^{]*?\}", "", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces retval = Regex.Replace(retval, @"\\f[0-9] ", ""); // remove font command with ending space retval = Regex.Replace(retval, @"\\f[0-9]", ""); // remove font command without ending space retval = Regex.Replace(retval, @"\\[^ \\?]+", new MatchEvaluator(ReplaceRTFClause)); // take backslash xyz and evaluates them // remove a space if there is one as the first character or the last character if (retval[0]==' ')retval = retval.Remove(0, 1); retval = retval.TrimEnd(' '); // remove \r\n and \par at end of string. if (retval.Substring(retval.Length - 2, 2) == "\r\n") retval = retval.Remove(retval.Length - 2, 2); if (retval.Substring(retval.Length - 4, 4) == @"\par") retval = retval.Remove(retval.Length - 4, 4); if (retval.Length == 0) return ""; if (retval.Substring(retval.Length - 2, 2) == @"\v") retval = retval.Remove(retval.Length - 2, 2); retval = RemoveRtfStyles(retval); retval = retval.Replace(@"(![", @"\{"); retval = retval.Replace(@"(!]", @"\}"); return retval; } #endregion #region StyleData private VE_Font GetItemFont() { VE_Font font = null; FormatInfo format = _MyItemInfo.ActiveFormat; int type = (int)_MyItemInfo.MyContent.Type; switch (type/10000) { case 0: // procedure font = format.PlantFormat.FormatData.Font; break; case 1: // section font = format.PlantFormat.FormatData.SectData.SectionHeader.Font; break; case 2: // step types int typindx = type - 20000; // what to do for other types rather than steps font = format.PlantFormat.FormatData.StepDataList[typindx].Font; break; } TextFont = font; return font; } #endregion #region DoListElements private int FindTokenChar(string txt, int startIndex) { // 'tokens' are for symbols and links (ro & transitions). symbols are represented by \u // and links are represented by \v \v0 bool done = false; while (!done) { int indx = txt.IndexOf('\\', startIndex); if (indx < 0) return indx; // see if symbol (but not underline) or another rtf command: has a 'u' // followed by a non-underline or single quote, and if so, return it. if (((txt[indx + 1] == 'u' && txt[indx + 2] != 'l')) || (txt[indx + 1] == '\'')) return indx; // see if link if (txt[indx + 1] == 'v') return indx; // Otherwise, get next index, must have been a slash or other rtf command. startIndex = indx + 1; } return -1; } private int DoTextElement(string text, int startIndex, int index) { displayTextElement vte = new displayTextElement(); vte.Type = E_TextElementType.Text; int len = (index == -1) ? text.Length - startIndex : index - startIndex; vte.Text = text.Substring(startIndex, len); DisplayTextElementList.Add(vte); return index+1; } private int DoLink(string text, int startIndex) { int retval = -1; int fnd = text.IndexOf("#Link:", startIndex); if (text.Substring(fnd + 6, 3) == "Ref") retval = DoRO(text, startIndex); else retval = DoTran(text, startIndex); return retval; } private int DoRO(string text, int index) { displayLinkElement vte = new displayLinkElement(); vte.Type = E_TextElementType.ReferencedObject; return DoLinkElements(text, index, vte); } private string FixTransition(string link, string text) { if (link.IndexOf("") != -1) return text; int transitionID = Convert.ToInt32(link.Split(" ".ToCharArray())[1]); // Find the transition if (_MyItemInfo.MyContent.ContentTransitionCount <= 0) return "*Resolved Transition Text*"; foreach (TransitionInfo ti in _MyItemInfo.MyContent.ContentTransitions) { if (ti.TransitionID == transitionID) { string path = ti.ResolvePathTo(_MyFormat, _MyItemInfo, ItemInfo.Get(ti.ToID), ti.RangeID==0?null:ItemInfo.Get(ti.RangeID)); return path; } } return text; } private int DoTran(string text,int index) { displayLinkElement vte = new displayLinkElement(); // determine if Range by checking for "R" after Transition (otherwise ":") int linkindx = text.IndexOf(@"#Link", index); vte.Type = (text[linkindx+16]=='R')?E_TextElementType.TransitionRange:E_TextElementType.Transition; return DoLinkElements(text, index, vte); } private int DoLinkElements(string text, int index, displayLinkElement vte) { // Find the 'end comment' for the int endLinkIndxV = text.IndexOf(@"\v0 ", linkIndx); if (endLinkIndxV == -1) endLinkIndxV = text.IndexOf(@"\v0", linkIndx); // at end of string int endLinkIndxE = text.IndexOf(@"[END>", linkIndx); int endLinkIndx = (endLinkIndxV < endLinkIndxE) ? endLinkIndxV : endLinkIndxE; vte.Link = text.Substring(linkIndx + 6, endLinkIndx - linkIndx - 6); // 6 for #Link: string tmptxt = null; if (vte.Type != E_TextElementType.ReferencedObject) { tmptxt = FixTransition(vte.Link, vte.Text); vte.Text = tmptxt; } // Now get the entire text & link. Account for various ending possibilities: // ends with '\v0\'; ends with '\v0 '; ends with '\v0' (end of string); // ends with '[END>' if two in a row - will have ", endLinkIndx + 3); // get past end of link int endComment = text.IndexOf(@"\v0", endToken); int rettoken = 0; int retlen = 4; if (endComment + 3 == text.Length) retlen = 3; else if (text[endComment + 3] == '\\') retlen = 3; vte.TextAndLink = text.Substring(index, endComment - index + retlen); rettoken = endComment + retlen; if (vte.Type != E_TextElementType.ReferencedObject) vte.TextAndLink = vte.TextAndLink = vte.TextAndLink.Replace("(Resolved Transition Text)", tmptxt); DisplayTextElementList.Add(vte); return rettoken; } private int DoSymbol(string text, int startIndex, int index) { displayTextElement vte = new displayTextElement(); vte.Type = E_TextElementType.Symbol; // symbols are the unicode/rtf command. A symbol can be represented by \'xy or // in the text from the database \uxyz?. If the \'xy is used the length of the // symbol number will always be two, otherwise find the index of the '?' to // find the end. int endindx = -1; if (text[index + 1] == '\'') endindx = index + 3; else endindx = text.IndexOf("?", index); vte.Text = text.Substring(index, endindx - index + 1); DisplayTextElementList.Add(vte); return endindx+1; } #endregion #region ReplaceWords private ReplaceStr _rs; //private string ReplaceIt(Match m) //{ // string s = m.ToString(); // string t = s.Replace(_rs.ReplaceWord, _rs.ReplaceWith); // return m.ToString().Replace(_rs.ReplaceWord, _rs.ReplaceWith); //} private string DoReplaceWords(string Text) { ReplaceStrList rsl = _MyFormat.PlantFormat.FormatData.SectData.ReplaceStrList; foreach (ReplaceStr rs in rsl) { if (_MyItemInfo.MyContent.Type < 20000) return Text; // for now only replace in steps. bool replaceit = false; // note that the order of this check is important. Check in this order... // background here if (_MyItemInfo.IsHigh && (rs.Flag & E_ReplaceFlags.High)>0) replaceit = true; else if ((_MyItemInfo.IsTable || _MyItemInfo.IsFigure) && (rs.Flag & E_ReplaceFlags.Table) > 0) replaceit = true; else if (_MyItemInfo.IsInRNO && (rs.Flag & E_ReplaceFlags.RNO) > 0) replaceit = true; else if (_MyItemInfo.IsCaution && (rs.Flag & E_ReplaceFlags.Caution) > 0) replaceit = true; else if (_MyItemInfo.IsNote && (rs.Flag & E_ReplaceFlags.Note) > 0) replaceit = true; else if (_MyItemInfo.IsInFirstLevelSubStep && (rs.Flag & E_ReplaceFlags.Substep) > 0) replaceit = true; else if (_MyItemInfo.IsAccPages & (rs.Flag & E_ReplaceFlags.Attach) > 0) replaceit = true; if (replaceit) { // CASEINSENS: Do ReplaceWords for all words that match, regardless of case, and replace // with the ReplaceWith string as is if ((rs.Flag & E_ReplaceFlags.CaseInsens) > 0) { string res = ""; string fortest = Text.ToUpper(); string pat = @"(?<=\W|^)" + rs.ReplaceWord.ToUpper() + @"(?=\W|$)"; int cpindx = 0; foreach (Match m in Regex.Matches(fortest, pat)) { res += Text.Substring(cpindx, m.Index-cpindx); cpindx += (m.Index - cpindx); res += rs.ReplaceWith; cpindx += rs.ReplaceWord.Length; } if (cpindx < Text.Length) res += Text.Substring(cpindx, Text.Length - cpindx); Text = res; } // CASEINSENSALL: Do ReplaceWords for all words that match the ReplaceWord, regardless of case else if ((rs.Flag & E_ReplaceFlags.CaseInsensAll) > 0) { // not in hlp } // CASEINSENSFIRST: Do ReplaceWords for all words that exactly match the ReplaceWord, // except the case where the first character may be different else if ((rs.Flag & E_ReplaceFlags.CaseInsensFirst) > 0) { // not in hlp } else { string pat = @"(?<=\W|^)" + rs.ReplaceWord + @"(?=\W|$)"; Text = Regex.Replace(Text, pat, rs.ReplaceWith); } } } return Text; } #endregion } #region displayTextElementClass public enum E_TextElementType : uint { Text = 0, Transition = 1, TransitionRange = 2, ReferencedObject = 3, Symbol = 4 }; public class displayTextElement { private E_TextElementType _Type; public E_TextElementType Type { get { return _Type; } set { _Type = value; } } private string _Text; public string Text { get { return _Text; } set { _Text = value; } } } public class displayLinkElement : displayTextElement { private string _Link; public string Link { get { return _Link; } set { _Link = value; } } private string _TextAndLink; public string TextAndLink { get { return _TextAndLink; } set { _TextAndLink = value; } } } #endregion }