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 OriginalText; // compare for save to see if change. public string OriginalConfigText; private FormatInfo _MyFormat; #endregion #region Constructors /// /// DisplayText constructor: /// Creates a DisplayText object that converts the database text into a list of /// displayTextElement elements. /// 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. /// public DisplayText(ItemInfo itemInfo, E_EditPrintMode epMode, E_ViewMode vwMode) { _MyItemInfo = itemInfo; DisplayTextElementList = new List(); OriginalText = itemInfo.MyContent.Text; TextFont = GetItemFont(); string text = _MyItemInfo.MyContent.Text; // if in print mode or view mode, do replace words. Only if in edit mode are replace // words left as is. _MyFormat = itemInfo.ActiveFormat; if (epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View) text = DoReplaceWords(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?"); // replace the dash/hyphen or whatever you want to call it, with a hard hyphen. The 16-bit program // treated the dash/hyphen as such. Translate back on any data saves. text = text.Replace(@"-", @"\u8209?"); // displayTextElement List items are created for anything that is handled differently in RTB, i.e. // symbols, ros, trans, text. int startIndex = 0; int index = -1; while ((index = FindTokenChar(text, startIndex))>-1) { // Do any 'plain' text that preceeds the token. if (index > startIndex) DoTextElement(text, startIndex, index); // Now do any other types if (text[index] == '\x15') index = DoRO(text, index); else if (text[index] == '\x252C' || text[index]=='\x2566') index = DoTran(text, index); else index = DoSymbol(text, startIndex, index); startIndex = index; // +1; if (startIndex >= text.Length) break; } // Add any remaining text. if (startIndex < text.Length) DoTextElement(text, startIndex, index); } #endregion #region SaveData public bool Save(RichTextBox rtb) { try { List origList = GetLinkList(DisplayTextElementList); // massage string to store in DisplayTextElementList... RtfToDisplayTextElements(rtb); // take the list & convert to data in the format to save to the database. 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 if (vte.Type == E_TextElementType.ReferencedObject) sret.Append(ToData_RO((displayLinkElement)vte)); else if (vte.Type == E_TextElementType.Transition || vte.Type == E_TextElementType.TransitionRange) sret.Append(ToData_Trans((displayLinkElement)vte)); } string modtext = sret.ToString(); if (modtext != OriginalText) { Item itm = _MyItemInfo.Get(); // check for different text, i.e. text from this itm doesn't match // original text. if (OriginalText != itm.MyContent.Text) { Console.WriteLine("Save Failed because text changed outside of this edit session."); return false; } // 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 = modtext; itm.Save(); 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 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 "#Link:ReferencedObject:", i.e. index in link of 23 string srecid = odte.Link.Substring(23, sp-23); 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, ".*[#]Link:([A-Za-z]*):(.*)"); //_RoUsageid = m.Groups[2].Value; //_Roid = m.Groups[3].Value; string linkstr = m.Groups[2].Value; if (linkstr[0] == ' ') linkstr = linkstr.Substring(1, linkstr.Length - 1); int roidindx = linkstr.IndexOf(" ", 1)+1; string roid = linkstr.Substring(roidindx, linkstr.Length - roidindx); // TODO: KBR ROFST - need to add rodb ContentRoUsage cr = itm.MyContent.ContentRoUsages.Add(roid); //int rou //int trid = ct.TransitionID; 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, ".*[#]Link:([A-Za-z]*):(.*)"); string linkstr = m.Groups[2].Value; if (linkstr[0] == ' ') linkstr = linkstr.Substring(1, linkstr.Length - 1); int type = System.Convert.ToInt32(linkstr.Substring(0,1)); int trindx = linkstr.IndexOf(" ", 2); // start past the space after the type. int trindx2 = linkstr.IndexOf(" ", trindx + 1); if (trindx2 == -1) trindx2 = linkstr.Length - 1; int tr1 = System.Convert.ToInt32(linkstr.Substring(trindx + 1, trindx2 - trindx)); Item itm1 = Item.Get(tr1); int tr2 = 0; Item itm2 = null; if (dte.Type == E_TextElementType.TransitionRange) { tr2 = System.Convert.ToInt32(linkstr.Substring(trindx2,linkstr.Length-trindx2)); itm2 = Item.Get(tr2); } ContentTransition ct = itm.MyContent.ContentTransitions.Add(itm1, itm2); ct.TranType = type; int trid = 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(RichTextBox rtb) { // 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 = rtb.Rtf.Replace(@"\~", @"\u160?"); // GetFontTable returns a non-negative number font number in the // font table for the unicode font, if it is used (otherwise -1) //int unicodeFont = GetFontTable(rtb.Rtf); // strip off all rtf commands... noExtraRtfStr = StripRtfCommands(noExtraRtfStr); //Console.WriteLine("StripRtf: {0}", noExtraRtfStr); // Also, set back the hard dash to a regular dash... Do this after the removal // of other rtf commands though since the \u8209 was surrounded by font commands // that, without there removal first, was also removing the dash. Have it with // a space & without because if it is at the end, there will be no space (leave // it to rtf processing to make it more complicated) noExtraRtfStr = noExtraRtfStr.Replace(@"\u8209? ", @"-"); noExtraRtfStr = noExtraRtfStr.Replace(@"\u8209?", @"-"); DisplayTextElementList.Clear(); int startIndex = 0; int index = -1; while ((index = FindRtfChar(noExtraRtfStr, startIndex)) > -1) { int fndindx = -1; // Do any 'plain' text that preceeds the token. if (index > startIndex) index = SaveTextElement(noExtraRtfStr, startIndex, index); if ((fndindx = noExtraRtfStr.IndexOf(@"\protect",index)) == index) index = SaveLink(noExtraRtfStr, index); else index = SaveSymbolTE(noExtraRtfStr, index); startIndex = index + 1; if (startIndex >= noExtraRtfStr.Length) break; } // Add any remaining text. if (startIndex < noExtraRtfStr.Length) DoTextElement(noExtraRtfStr, startIndex, index); //Console.WriteLine(noExtraRtfStr); } private int SaveTextElement(string data, int startIndex, int index) { displayTextElement vte = new displayTextElement(); vte.Type = E_TextElementType.Text; int len = (index == -1) ? data.Length - startIndex : index - startIndex; vte.Text = data.Substring(startIndex, len); DisplayTextElementList.Add(vte); return index; } private int SaveSymbolTE(string data, int startIndex) { displayLinkElement vte = new displayLinkElement(); vte.Type = E_TextElementType.Symbol; // symbols are just the unicode/rtf command, no font associated with it // by the time it gets here... A symbol can be represented by \'xy or \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 (data[startIndex + 1] == '\'') endindx = startIndex + 3; else endindx = data.IndexOf("?", startIndex); if (endindx == -1) return startIndex; // not found - error vte.Text = data.Substring(startIndex, endindx - startIndex + 1); DisplayTextElementList.Add(vte); if (endindx+1 -1) { if (text[symindx2+2] == 'l') symindx2 = -1; // don't process underlines } if (prindx == -1 && symindx1 == -1 && symindx2 == -1) return -1; if (prindx == -1) prindx = text.Length + 1; if (symindx1 == -1) symindx1 = text.Length + 1; if (symindx2 == -1) symindx2 = text.Length + 1; // Which token has smallest number, to determine which item is next // in the string. If it is a symbol - see if it has a font specifier // first. int symindx = symindx1 < symindx2 ? symindx1 : symindx2; int smallest = (prindx < symindx ? prindx : symindx); return smallest; } private int GetFontTable(string rtf) { dicRtfFontTable = new Dictionary(); // return unicode (symbol) font number, if it exists, to expedite finding // the font for symbols. int unicodeFont = -1; int bindx = rtf.IndexOf(@"{\fonttbl"); if (bindx < -1) return -1; int eindx = rtf.IndexOf("}}", bindx); // get font table string and then do regular expressions to get font number // with font name. string tbl = rtf.Substring(bindx + 9, eindx - bindx - 8); tbl = tbl.Replace("{", "<"); tbl = tbl.Replace("}", ">"); string pat = @"(?:<\\f)([0-9]+)(?:[\S]+ )([\w ]+)"; StringBuilder sb = new StringBuilder(); foreach (Match m in Regex.Matches(tbl, pat)) { int num = Convert.ToInt32(m.Result("${1}")); string nam = m.Result("${2}"); dicRtfFontTable.Add(num, nam); if ((unicodeFont == -1) && (nam == "Arial Unicode MS")) unicodeFont = num; } return unicodeFont; } 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) { retval = Regex.Replace(retval, @"\\b0 ?", ""); retval = Regex.Replace(retval, @"\\b ?",""); } if ((TextFont.Style & E_Style.Underline) > 0) { retval = Regex.Replace(retval, @"\\ul0 ?", ""); 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 'v': // save link hidden info if (m.Value == @"\v") return m.Value; // part of link if (Regex.IsMatch(m.Value, @"\\v0")) return m.Value; // hidden info off break; case 'p': if (m.Value == @"\par") return "\r\n"; if (m.Value == @"\protect") return m.Value; if (m.Value == @"\protect0") return m.Value; break; } return "";//Strip All } private string StripRtfCommands(string rtf) { string retval = Regex.Replace(rtf, @"[\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, @"\\[^ \\?]+", new MatchEvaluator(ReplaceRTFClause)); // take backslash xyz and evaluates them // remove a space if there is one as the first character.. if (retval[0]==' ')retval = retval.Remove(0, 1); // remove \r\n at end of string - this was added with the \par at the end of string by the rtf box if (retval.Substring(retval.Length - 2, 2) == "\r\n") retval = retval.Remove(retval.Length - 2, 2); retval = RemoveRtfStyles(retval); return retval; } private string ToData_RO(displayLinkElement vte) { // get past the #Link:ReferencedObject part of the link. return String.Format("\x15ReferencedObject RO\\v0 {0}\\v #{1}\\v0", vte.Text, vte.Link.Substring(23, vte.Link.Length-23)); } private string ToData_Trans(displayLinkElement vte) { char trchar = vte.Type == E_TextElementType.Transition ? '\x252C' : '\x2566'; // depending on type, get past the #Link:Transition: or #Link:TransitionRange: part // of text. int indx = vte.Type == E_TextElementType.Transition ? 18 : 23; return String.Format("{0}\\v TRAN\\v0 {1}\\v {2}\\v0", trchar, vte.Text, vte.Link.Substring(indx, vte.Link.Length-indx)); } #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 ro, transitions and possible symbol char[] tok = { '\x15', '\x252C', '\x2566', '\\' }; bool done = false; // If there is only an rtf token from the indexed position on, don't return the // IndexOfAny index value, because it will by one character past the '\' and throw // of the return value of where in the string the text should be saved. For example // for the string '\b text \v somevalue \v0\b0', the first time through the while // loop has the index at the '\b' char of the b0. //int savstartIndex = startIndex; while (!done) { int indx = txt.IndexOfAny(tok, startIndex); if (indx < 0) return indx; if (txt[indx] != '\\') 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. // Otherwise, get next index, must have been a slash or other rtf command. if (((txt[indx + 1] == 'u' && txt[indx + 2] != 'l')) || (txt[indx + 1] == '\'')) return indx; 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 string CreateLink(E_TextElementType type, string linktxt) { string retlink = ""; if (type == E_TextElementType.ReferencedObject) retlink = "#Link:ReferencedObject:" + linktxt; else if (type == E_TextElementType.Transition) retlink = "#Link:Transition:" + linktxt; else retlink = "#Link:TransitionRange:" + linktxt; return retlink; } private int DoRO(string text, int index) { displayLinkElement vte = new displayLinkElement(); vte.Type = E_TextElementType.ReferencedObject; int iend = text.IndexOf(@"\v", index); vte.Text = text.Substring(index + 1, iend - index - 1); int istart = text.IndexOf("#", index); iend = text.IndexOf(@"\v0", istart); vte.Link = text.Substring(istart, iend - istart); DisplayTextElementList.Add(vte); return iend + 3; } private string FixTransition(string link, string text) { int transitionID = Convert.ToInt32(link.Split(" ".ToCharArray())[1]); // Find the transition foreach (TransitionInfo ti in _MyItemInfo.MyContent.ContentTransitions) { if (ti.TransitionID == transitionID) { //string path = ti.PathTo.Replace(" Section PROCEDURE STEPS ", ", "); //path = path.Replace(" Section PROCEDURE STEPS", ""); 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(); if (text[index]=='\x252C') vte.Type = E_TextElementType.Transition; else vte.Type = E_TextElementType.TransitionRange; // '\x2566'\ int iend = text.IndexOf(@"\v",index); vte.Text = text.Substring(index + 1, iend - index - 1); int istart = text.IndexOf("#", index); iend = text.IndexOf(@"\v0", istart); vte.Link = text.Substring(istart, iend-istart); vte.Text = FixTransition(vte.Link, vte.Text); // TODO: Transition text resolution? DisplayTextElementList.Add(vte); return iend + 3; } 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 the position just past the symbol. 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; } } } #endregion }