From e36cc1847a466dd16b8f2030df60b2d26b080649 Mon Sep 17 00:00:00 2001 From: Kathy Date: Wed, 20 Jan 2016 16:52:55 +0000 Subject: [PATCH] Enhanced Document support - Moved from volian.controls.library (should be deleted from volian.controls.library ) Move from volian.controls.library (should be deleted from volian.controls.library ) --- .../Extension/DisplayText.cs | 2244 +++++++++++++++++ .../Extension/OutlineRTFTable.cs | 306 +++ 2 files changed, 2550 insertions(+) create mode 100644 PROMS/VEPROMS.CSLA.Library/Extension/DisplayText.cs create mode 100644 PROMS/VEPROMS.CSLA.Library/Extension/OutlineRTFTable.cs diff --git a/PROMS/VEPROMS.CSLA.Library/Extension/DisplayText.cs b/PROMS/VEPROMS.CSLA.Library/Extension/DisplayText.cs new file mode 100644 index 00000000..bb63c755 --- /dev/null +++ b/PROMS/VEPROMS.CSLA.Library/Extension/DisplayText.cs @@ -0,0 +1,2244 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Text.RegularExpressions; +using System.Drawing; +using Volian.Base.Library; + +// This was moved from volian.controls.library +namespace VEPROMS.CSLA.Library +{ + public enum E_FieldToEdit { StepText, Text, Number, PSI }; + public class DisplayText + { + private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + #region Properties + private E_FieldToEdit _FieldToEdit; + public E_FieldToEdit FieldToEdit + { + get { return _FieldToEdit; } + set { _FieldToEdit = value; } + } + private ItemInfo _MyItemInfo; + private string InfoText + { + get + { + switch (FieldToEdit) + { + case E_FieldToEdit.StepText: + case E_FieldToEdit.Text: + return _MyItemInfo.MyContent.Text; + break; + case E_FieldToEdit.Number: + return _MyItemInfo.MyContent.Number; + break; + } + return string.Empty; + } + } + private Item _MyItem; + private string EditText + { + get + { + switch (FieldToEdit) + { + case E_FieldToEdit.StepText: + case E_FieldToEdit.Text: + return _MyItem.MyContent.Text; + break; + case E_FieldToEdit.Number: + return _MyItem.MyContent.Number; + break; + } + return string.Empty; + } + set + { + switch (FieldToEdit) + { + case E_FieldToEdit.StepText: + case E_FieldToEdit.Text: + _MyItem.MyContent.Text = value; + _MyItem.MyContent.UserID = Volian.Base.Library.VlnSettings.UserID; + _MyItem.MyContent.DTS = DateTime.Now; + break; + case E_FieldToEdit.Number: + _MyItem.MyContent.Number = value; + _MyItem.MyContent.UserID = Volian.Base.Library.VlnSettings.UserID; + _MyItem.MyContent.DTS = DateTime.Now; + break; + default: + break; + } + } + } + // 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; } + } + private bool PrintingSmartTemplate = false; + public string StartText; + public string OriginalText; // compare for save to see if change for links. + 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. + /// E_FieldToEdit fieldToEdit - identifies the field to edit (number or text) + /// bool colorLinks - whether to add color to links + /// + public DisplayText(ItemInfo itemInfo, E_EditPrintMode epMode, E_ViewMode vwMode, bool noEdit,E_FieldToEdit fieldToEdit, bool colorLinks, string prefix, string suffix) + { + int profileDepth = ProfileTimer.Push(">>>> DisplayText"); + _FieldToEdit = fieldToEdit; + _MyItemInfo = itemInfo; + OriginalText = InfoText; + if (OriginalText.Contains("Prerequisite") && epMode == E_EditPrintMode.Print) + OriginalText = Regex.Replace(OriginalText, @"\\{Prerequisite Step: .*?\\}", ""); + TextFont = itemInfo.GetItemFont();//GetItemFont(); + // if in print mode, and this is the HLS of a smart template (checklist formats) see if the hls + // splits across 2 lines. + if (itemInfo.IsStep && itemInfo.FormatStepData.UseSmartTemplate && epMode == E_EditPrintMode.Print) + { + int hlslen = (int)(itemInfo.FormatStepData.StepPrintData.HLSLength ?? 66); + List titleLines = Volian.Base.Library.RtfTools.SplitText(OriginalText, hlslen); + if (titleLines.Count > 1) + { + string tmporig = titleLines[0]; + for (int ix = 1; ix < titleLines.Count; ix++) + tmporig = tmporig + @"\par " + titleLines[ix]; + OriginalText = tmporig; + } + } + string text = prefix + OriginalText + suffix; + _MyFormat = itemInfo.ActiveFormat; + + bool tableShouldBeOutlined = false; //(epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit) && + //(_FieldToEdit == E_FieldToEdit.StepText || _FieldToEdit == E_FieldToEdit.Text) && + //(!itemInfo.IsSection && !itemInfo.IsProcedure) && (itemInfo.IsTable || itemInfo.IsFigure); + bool wordsShouldBeReplaced = epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit; + if (_MyFormat == null) + Console.WriteLine(this._MyItemInfo.MyItemInfoUnique); + bool numbersShouldBeFormated = (!_MyFormat.PlantFormat.FormatData.SectData.StepSectionData.FortranFormatNumbers && (epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit)); + int typ = ((int)itemInfo.MyContent.Type) % 10000; + bool tableHasBorder = tableShouldBeOutlined ? itemInfo.ActiveFormat.PlantFormat.FormatData.StepDataList[typ].Type.IndexOf(@"Borderless") < 0 : false; + bool ROsShouldBeAdjusted = wordsShouldBeReplaced; // same logical value + bool underlineAfterDashSpace = (itemInfo.FormatStepData == null) ? false : itemInfo.FormatStepData.UnderlineAfterDashSpace; + if (epMode == E_EditPrintMode.Print && _MyItemInfo.IsStep) + { + if (_MyItemInfo.FormatStepData.UseSmartTemplate) + { + // Add 2 spaces before and 1 after if there is prefix so that wrapping in RTB accounts for vertical + // lines (the 2 spaces after the first "\par " command and 1 space before 2nd "\par"). Tried other + // combinations that did not work. + if (_MyItemInfo.FormatStepData.Prefix != null && _MyItemInfo.FormatStepData.Prefix != "") + text = !_MyItemInfo.FormatStepData.Font.FontIsProportional() ? ReplaceLinesWithUnicode(_MyItemInfo.FormatStepData.Prefix) + @"\par " + text + @"\par " : + @"\par " + text + @"\par "; + if (_MyItemInfo.FormatStepData.Suffix != null && _MyItemInfo.FormatStepData.Suffix != "") + text = text + (!_MyItemInfo.FormatStepData.Font.FontIsProportional() ? ReplaceLinesWithUnicode(_MyItemInfo.FormatStepData.Suffix) : + @"\par\par\par "); + } + } + // Replace Hard Hyphens with normal hyphen so the PDF search for hyphens will work properly + if (text.Contains(@"\u8209?") && epMode == E_EditPrintMode.Print) + { + // Handle RTF Tokens followed immediately by a hard hyphen + text =Regex.Replace(text, @"(?<=\\[^\\?' \r\n\t]+)\\u8209\?", " -"); + text = text.Replace(@"\u8209?", "-"); + } + _MyStaticItemInfo = _MyItemInfo; + text = CreateRtf(colorLinks, text, tableShouldBeOutlined, wordsShouldBeReplaced, numbersShouldBeFormated, tableHasBorder, ROsShouldBeAdjusted, underlineAfterDashSpace, epMode); + _MyStaticItemInfo = null; + StartText = text; + ProfileTimer.Pop(profileDepth); + } + private static ItemInfo _MyStaticItemInfo = null; // Used to report errors + private string ReplaceLinesWithUnicode(string text) + { + text = text.Replace("\x2500", @"\u9472?"); // Horizontal + text = text.Replace("\x2502", @"\u9474?"); // Vertical + text = text.Replace("\x2514", @"\u9492?"); // Bottom Left Corner + text = text.Replace("\x2518", @"\u9496?"); // Bottom Right Corner + text = text.Replace("\x2534", @"\u9524?"); // Bottom Tee + text = text.Replace("\x250c", @"\u9484?"); // Upper Left Corner + text = text.Replace("\x251c", @"\u9500?"); // Left Tee + text = text.Replace("\x2510", @"\u9488?"); // Upper Right Corner + text = text.Replace("\x252c", @"\u9516?"); // Top Tee + text = text.Replace("\x2524", @"\u9508?"); // Right Tee + text = text.Replace("\x253c", @"\u9532?"); // Plus + return text; + } + + public DisplayText(string text, VE_Font vFont, bool colorLinks) + { + TextFont = vFont; + StartText = CreateRtf(colorLinks, text, false, false, false, false, false, false, E_EditPrintMode.Edit); + } + public DisplayText(ItemInfo itemInfo, string text, bool colorLinks) + { + _FieldToEdit = E_FieldToEdit.Text; + _MyItemInfo = itemInfo; + OriginalText = text; + TextFont = itemInfo.GetItemFont(); + _MyFormat = itemInfo.ActiveFormat; + + bool wordsShouldBeReplaced = true; + bool numbersShouldBeFormated = !_MyFormat.PlantFormat.FormatData.SectData.StepSectionData.FortranFormatNumbers; + int typ = ((int)itemInfo.MyContent.Type) % 10000; + bool ROsShouldBeAdjusted = wordsShouldBeReplaced; // same logical value + bool underlineAfterDashSpace = (itemInfo.FormatStepData == null) ? false : itemInfo.FormatStepData.UnderlineAfterDashSpace; + + text = CreateRtf(colorLinks, text, false, wordsShouldBeReplaced, numbersShouldBeFormated, false, ROsShouldBeAdjusted, underlineAfterDashSpace,E_EditPrintMode.Edit); + StartText = text; + // Shearon Harris Tables are Bold + if (itemInfo.IsTable && (TextFont.Style & E_Style.Bold) == E_Style.Bold) + { + // Strip out Bold OFF commands + text = text.Replace(@"\b0 "," "); + text = text.Replace(@"\b0", ""); + // Insert a Bold ON command at the beginning of the printable text. + StartText = Regex.Replace(text, @"(\\viewkind.*?)(?= |\\u[0-9]+?|\\'[0-9A-F])", @"$1\b"); + } + } + private bool InLinkedText(string text, int idx) + { + MatchCollection mc = Regex.Matches(text, @"", RegexOptions.Singleline); + if (mc.Count == 0) return false; + foreach (Match m in mc) + if (m.Index < idx && m.Index + m.Length > idx) return true; + return (false); + } + private string CreateRtf(bool colorLinks, string text, bool tableShouldBeOutlined, bool wordsShouldBeReplaced, bool numbersShouldBeFormated, bool tableHasBorder, bool ROsShouldBeAdjusted, bool underlineAfterDashSpace, E_EditPrintMode epMode) + { + int profileDepth = ProfileTimer.Push(">>>> CreateRtf"); + // Adjust RO display + if (ROsShouldBeAdjusted) + { + try // Added try/catch because an unresolved RO Link was causing a failure. + { + text = DoROAdjustments(text); + } + catch (Exception ex) + { + if (_MyItemInfo != null) + { + _MyLog.ErrorFormat("<<< ERROR >>> Error doing DoROAdjustments\r\n==>'RO Adjustments Error',{0},'{1}','{2}','{3}'" + , _MyItemInfo.ItemID, _MyItemInfo.MyDocVersion.MyFolder.Name, _MyItemInfo.ShortPath, ex.Message); + } + else + _MyLog.Error("DisplayText.CreateRTF Error doing DoROAdjustments", ex); + + } + } + // 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. + // But don't do ReplaceWords if the TurnOffReplaceWords format flag is set + if (wordsShouldBeReplaced && !_MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.TurnOffReplaceWords) + { + int profileDepth1 = ProfileTimer.Push(">>>> DoReplaceWords2"); + text = DoReplaceWords2(text); + ProfileTimer.Pop(profileDepth1); + } + if (_MyItemInfo != null) + { + text = Regex.Replace(text, @"\", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Number, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)ID)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_ID, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)NAME)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Name, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)TEXT)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Text, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)NUMBER)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Number, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)OTHER ID)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Other_Unit_ID, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)OTHER NAME)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Other_Unit_Name, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)OTHER TEXT)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Other_Unit_Text, RegexOptions.IgnoreCase); + text = Regex.Replace(text, @"\<(U(-|\\u8209\?)OTHER NUMBER)\>", _MyItemInfo.MyDocVersion.DocVersionConfig.Other_Unit_Number, RegexOptions.IgnoreCase); + //text = DoSearchAndReplace(text, "", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_ID); + text = text.Replace(@"", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_ProcedureSetID); + //text = text.Replace("", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Number); + } + // Adjust RO display + if (ROsShouldBeAdjusted) + text = DoTransitionAdjustments(text, _MyItemInfo.ActiveFormat.PlantFormat.FormatData.TransData.BoldTransition || (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.TransData.BoldTransitionExceptHLS && !_MyItemInfo.IsHigh)); + // add colors around links: + if (colorLinks) + text = DoColorLinks(text); + //Console.WriteLine(text); + // adjust formatting of exponents + if (numbersShouldBeFormated) + text = DoFortranFormat(text); + // determine whether the table/figure should be outlined: + if (tableShouldBeOutlined) + { + OutlineRTFTable myTable = new OutlineRTFTable(text, tableHasBorder); + // if a table has internal line draw characters, we may have to do part of 'OutlineTable' + // to convert dashes and vertical bars to line draw characters. + if (tableHasBorder) myTable.OutlineTable(); + text = myTable.Lines.ToString(); + } + + // if we're working with a grid it won't go thru here. + if (!text.StartsWith(@"{\rtf")) + { + // 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", @"\line "); // replace a \r\n with a \line instead of a \par + //if (text.IndexOf(@"\line") > -1) + // MessageBox.Show("Found rtf line"); + //text = text.Replace(@"\line", @"\par"); // we don't want to replace the \line part of bug fix B2015-140 + + // Now put symbol (for fixed fonts) or unicode font (proportional) around symbols + // These fonts are VESymbFix & Arial Unicode MS respectively, and the font table + // is actually defined in the StepRTB code. + int indxsym = NextUnicode(text, 0);//text.IndexOf(@"\u"); + while (indxsym != -1) + { + int incrindx = 3; + if (text[indxsym + 2] != 'l') + { + text = text.Insert(indxsym, @"\f1 "); + int indxendsym = text.IndexOfAny(@"\ ?".ToCharArray(), indxsym + 5); + if (indxendsym == -1) // must be end of line: + text = text.Insert(text.Length - 1, @"\f0 "); + else + { + if (text[indxendsym] == '?') indxendsym++; + text = text.Insert(indxendsym, @"\f0 "); // TODO: do I need a space?? + } + incrindx = 5; + } + indxsym = NextUnicode(text, indxsym + incrindx);//text.IndexOf(@"\u", indxsym + incrindx); + } + } + if (underlineAfterDashSpace) + { + // Bug fix: B2015-110 - currently used in Byron and Braidwood formats + // for the screen we need to look for the unicode dash + // for printing we need to look for the keyboard dash character + MatchCollection mc = Regex.Matches(text,((epMode == E_EditPrintMode.Edit)? @"\\u8209\?\\f[0-9]+ " : "- ")); + if (mc.Count > 0) + { + Match m = mc[0]; + if (!InLinkedText(text, m.Index)) + { + string str1 = text.Substring(0, m.Index + m.Length); + string str2 = text.Substring(m.Index + m.Length); + string str3 = ""; + int iTerm = FindUnderlineTerminator(str2); + if (iTerm >= 0) + { + str3 = str2.Substring(iTerm); + str2 = str2.Substring(0, iTerm); + } + str2 = str2.Replace(@"\ulnone ", ""); + str2 = str2.Replace(@"\ulnone", ""); + str2 = str2.Replace(@"\ul ", ""); + str2 = str2.Replace(@"\ul", ""); + text = str1 + @"\ul " + str2 + @"\ulnone " + str3; + } + } + } + text = FixDiffUnitROReplaceWords(text); + ProfileTimer.Pop(profileDepth); + return text; + } + + private string FixDiffUnitROReplaceWords(string text) + { + if (_MyFormat == null) return text; + ReplaceStrList rsl = _MyFormat.PlantFormat.FormatData.SectData.ReplaceStrList; + + // The only way to get an 'empty' list is to have one 'dummy' replacestr, i.e. that has ReplaceWord as an empty string. If the + // ReplaceStrData xml node is empty, it does the inheritance and gets the 'base' format's list. + if (rsl.Count == 1 && (rsl[0].ReplaceWord == null || rsl[0].ReplaceWord == "")) return text; + // Loop through text looking for words to be replaced + List partialReplaceList = new List(); + foreach (ReplaceStr rs in rsl) + { + if (rs.ReplaceWord.Contains("{RO}")) + { + //if (_MyItemInfo.InList(34770,34771,34782,34882,34886,34916,34891,35121,36361)) + // Console.WriteLine("FixDiffUnitROReplaceWords jcb"); + string oldvalue = text; + string replaceWord = rs.ReplaceWord; + string replaceWord2 = Regex.Replace( replaceWord,@"(\{RO\})([0-9,]+)(\{RO\})",@"\\v 0) + { + Match mm = Regex.Match(text, replaceWord2, RegexOptions.IgnoreCase); + return matches[0]; + } + return null; + } + private int FindUnderlineTerminator(string text) + { + int idx = -1; + UnderlineTerminateList utl = _MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.UnderlineTerminateList; + foreach (UnderlineTerminate ut in utl) + { + MatchCollection mc = Regex.Matches(text, "(? 0) + { + Match m = mc[mc.Count - 1]; + if (idx < 0 || idx > m.Index) + idx = m.Index; + } + } + return idx; + } + private string DoSearchAndReplace(string text, string find, string replace) + { + return text.Replace(find, replace); + } + private static string DoColorLinks(string text) + { + string origtext = text; + text = Regex.Replace(text, @"( -1) + { + text = text.Insert(indxend, @"\cf0"); + indxcf = text.IndexOf(@"\v0\cf1", indxend); + } + else + { + indxcf = -1; + _MyLog.WarnFormat("DisplayText.DoColorLinks Failed\r\norgitext:'{0}'\r\ntext'{1}'", origtext, text); + } + } + } + catch (Exception ex) + { + _MyLog.WarnFormat("DisplayText.DoColorLinks Failed\r\norgitext:'{0}'\r\ntext'{1}'", origtext, text); + } + return text; + } + private int NextUnicode(string text, int offset) + { + // Skip Hard Spaces + Match m = Regex.Match(text.Substring(offset), @"\\u[0-9a-fA-F]"); + while(m.Success && text.Substring(offset+m.Index).StartsWith(@"\u160")) + { + offset += m.Index + 5; + m = Regex.Match(text.Substring(offset), @"\\u[0-9a-fA-F]"); + } + if (m.Success) + return m.Index + offset; + return -1; + } + private string DoROAdjustments(string text) + { + Regex regRefObj = new Regex(@"\#Link\:ReferencedObject:([0-9]*|) ([0-9a-zA-Z]*) ([0-9]*)", RegexOptions.Singleline); + string strippedText = StaticStripRtfCommands(text); + // (\\[^v \\]+)* --> look for any rtf commands (first part of lookFor) + // \\v0 --> end of comment + // (\\[^v \\]+)* --> more rtf commands ended by a space + // (.*?) --> smallest anything to that matches this based on what's next + // (\\[^v' \\]+)* --> look for rtf commands but exclude \' before the \v + // \\v(\\[^v \\]+)* --> look for rtf commands after the \v + // if it turns out that if ro's have any embedded unicode characters this needs expanded, such as /u8209? (hard hyphen) + string lookFor = string.Format(@""); + MatchCollection matches = Regex.Matches(text, lookFor); + string prevValue = null; + for (int i = matches.Count - 1; i >= 0; i--) + { + Match m = matches[i]; + if (m != null && m.Groups.Count > 7 && m.Groups[7].ToString() == "ReferencedObject") + { + // if previous processed (next ro) was found, then see if it has an 'and' between it and the previous + //if (prevValue != null) + //{ + // int endIndx = m.Index + m.Length; + // string tr = text.Substring(endIndx).Replace(@"\v0","").TrimStart(); + // if (!tr.ToUpper().StartsWith("AND")) prevValue = null; + //} + int myIndex = m.Groups[4].Index; + int myLength = m.Groups[4].Length; + if (m.Groups[3].Value != " ") + { + myIndex = m.Groups[3].Index; + myLength += m.Groups[3].Length; + } + string gg = text.Substring(myIndex, myLength); + //System.Text.RegularExpressions.Group g = m.Groups[3]; + string beforeRO = StaticStripRtfCommands(text.Substring(0, myIndex)); + string afterRO = StaticStripRtfCommands(text.Substring(myIndex + myLength)); + Match myMatch = regRefObj.Match(m.ToString()); + if(m.ToString().ToUpper().Contains("")) + _MyLog.WarnFormat("Unprocessed RO in {0},({1})",_MyItemInfo.ShortPath,gg); + int dbid = System.Convert.ToInt32(myMatch.Groups[2].Value.Substring(0, 4), 16); + int rodbid = int.Parse(myMatch.Groups[3].Value); + ROFstInfo myROFst = _MyItemInfo.MyDocVersion.GetROFst(rodbid); + bool isSetpoint=myROFst.IsSetpointDB(dbid, _MyItemInfo.MyDocVersion); + string newvalue1 = DoROFormatFlags(gg, beforeRO, afterRO, isSetpoint); + string newvalue = RemoveMultipleUnits(prevValue, newvalue1); + if (!_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.AllUnits) prevValue = newvalue1; + newvalue = DoROReplaceWords(_MyFormat.PlantFormat.FormatData.SectData.ReplaceStrList, newvalue, _MyItemInfo.IsHigh); + if (isSetpoint) newvalue = ReplaceSpaceWithHardspace(newvalue); + if (gg != newvalue) + text = text.Substring(0, myIndex) + newvalue + text.Substring(myIndex + myLength); + } + } + return text; + } + private string DoROReplaceWords(ReplaceStrList replaceStrList, string oldvalue, bool isHigh) + { + int profileDepth = ProfileTimer.Push(">>>> DoROReplaceWords"); + string newvalue = oldvalue; + foreach (ReplaceStr rs in replaceStrList) + { + if (((rs.Flag & E_ReplaceFlags.Setpoint) > 0) || (isHigh && (rs.Flag & E_ReplaceFlags.HLSSetpnt) > 0)) + { + try + { + // Use regular expression to assure that the ReplaceWord is not part of another word + // For VEPROMS_CAL E-0 Step 23 (Reset SI) the word "after" was being changed to "aFTer" + newvalue = Regex.Replace(newvalue, @"(?<=\W|^)" + rs.ReplaceWord + @"(?=\W|$)", rs.ReplaceWith); + //newvalue = newvalue.Replace(rs.ReplaceWord, rs.ReplaceWith); + } + catch (Exception ex) + { + _MyLog.Warn("Problem with regular expression", ex); + } + } + } + //if (oldvalue != newvalue) + // Console.WriteLine("\"{0}\"\r\n\"{1}\"",oldvalue,newvalue); + ProfileTimer.Pop(profileDepth); + return newvalue; + } + // Replace spaces with hardspaces, but DO NOT replace the end of an Rtf Command with a hardspace + private string ReplaceSpaceWithHardspace(string newvalue) + { + string oldvalue = newvalue; + int spindx = newvalue.IndexOf(" "); + int lstindx = -1; + while (spindx >= 0) + { + if (!EndsRtfCommand(newvalue, spindx, lstindx)) + { + newvalue = newvalue.Remove(spindx, 1); + newvalue = newvalue.Insert(spindx, @"\u160?"); + } + lstindx = spindx; + spindx = (spindx + 1 >= newvalue.Length)?spindx = -1: newvalue.IndexOf(" ", spindx+1); + } + return newvalue; + } + + private bool EndsRtfCommand(string str, int spindx, int previndx) + { + // get text from last space to current, or from beginning of string to current: + int start = previndx < 0 ? 0 : previndx+1; + string substring = str.Substring(start, spindx-start); + if (substring.Contains(@"\")) + { + // is space ending an rtf command. + int startCmd = substring.LastIndexOf(@"\"); + string Cmd = substring.Substring(startCmd); + char tst = Cmd[1]; + // consider rtf commands up/dn/b/ul/i + if (tst == 'u' || tst == 'd' || tst == 'b' || tst == 'u' || tst == 'i') return true; + } + return false; + } + private string DoTransitionAdjustments(string text, bool boldTran) + { + int profileDepth = ProfileTimer.Push(">>>> DoTransitionAdjustments"); + bool undtran = _MyItemInfo.ActiveFormat.PlantFormat.FormatData.TransData.Underline; + string strippedText = StaticStripRtfCommands(text); + string lookFor = string.Format(@""); + MatchCollection matches = Regex.Matches(text, lookFor); + if (matches.Count == 0) + { + ProfileTimer.Pop(profileDepth); + return text; + } + string retstr = text; + for (int i = matches.Count - 1; i >= 0; i--) + { + Match m = matches[i]; + // if this transition text already has a hard space, don't add another. + if (m.Groups[4].Value.Contains("\xA0")) continue; + // if the transition text does not start with a digit, don't add the hardspace. + //if (!Char.IsDigit(m.Groups[3].Value[0])) continue; + if (m != null && m.Groups.Count > 8 && m.Groups[7].ToString().StartsWith("Transition")) + { + if (m.Groups[8].Value != "") // && StepTransition(int.Parse(m.Groups[7].Value))) + { + int myIndex = m.Groups[4].Index; + int myLength = m.Groups[4].Length; + if (m.Groups[3].Value != " ") + { + myIndex = m.Groups[3].Index; + myLength += m.Groups[3].Length; + } + string newvalue = text.Substring(myIndex, myLength); + //System.Text.RegularExpressions.Group g = m.Groups[3]; + string beforeTran = retstr.Substring(0, myIndex); + string afterTran = retstr.Substring(myIndex + myLength); + + // if replacing text in the 'beforeTran' string, then do it here, + // i.e. there is a format flag 'BeforeTrans' that bolds text before the transition + // (in wst formats). + beforeTran = DoBeforeTransFlagSupport(beforeTran, _MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.ReplaceStrList); + //string newvalue = g.ToString(); + // if this is a 'step transition' type, i.e. includes a step number, in addition to other replacements, + // we want to change a space to a hardspace. + if (StepTransition(int.Parse(m.Groups[8].Value))) + { + int indexLastSpace = newvalue.LastIndexOf(' '); + if (indexLastSpace >= 0) + // Use a "\x1" as a token to replace later. Insert the unicode char, whose length is + // more than 1 character was throwing of the regexp Matches index, so that the resulting + // string may have been incorrect. + retstr = beforeTran + (boldTran ? @"\b " : null) + (undtran ? @"\ul " : null) + newvalue.Substring(0, indexLastSpace) + "\x1" + newvalue.Substring(indexLastSpace + 1) + (undtran ? @"\ulnone " : null) + (boldTran ? @"\b0" : null) + afterTran; + else + if (beforeTran.EndsWith(" ")) + retstr = ReplaceLastSpaceWithHardSpace(beforeTran) + (boldTran ? @"\b " : null) + (undtran ? @"\ul " : null) + newvalue + (undtran? @"\ulnone ":null) + (boldTran ? @"\b0" : null) + afterTran; + else + Console.Write("");// Don't know where to put the Hard Space + } + else if (boldTran) + { + retstr = beforeTran + @"\b " + newvalue + @"\b0" + afterTran; + } + } + } + } + ProfileTimer.Pop(profileDepth); + return retstr.Replace("\x1", @"\u160?"); + } + + private string DoBeforeTransFlagSupport(string beforeTran, ReplaceStrList replaceStrList) + { + foreach (ReplaceStr repstr in replaceStrList) + { + if ((repstr.Flag & E_ReplaceFlags.BeforeTrans) > 0) + { + // the beforeTran string ends with the string that starts the transition comment, i.e. + // '\\v -1) + { + string findit = beforeTran.Substring(0, beforeTran.LastIndexOf(@"\v 0 && str[ind - 1] != ' ') + { + if (ind > 5 && str.Substring(0, ind).EndsWith(@"\u160?") || str.Substring(0, ind).ToLower().EndsWith(@"\'a0")) + return str;//Already has a Hard Space + ind = str.LastIndexOf(@"\", ind - 1); + } + // If the previous character is a comma or a space then don't add a Hard Space + if (ind > 1 && (str[ind - 2] == ',' || str[ind - 2] == ' ')) return str; + if (ind <= 0) return str; + + // replace with a 'token' "\x1" instead of a hardspace unicode char. When using a hardspace unicode + // char the string length/contents was thrown off so that the calling method's processing was off + // in terms of regexp matches in string. + return str.Substring(0, ind - 1) + "\x1" + str.Substring(ind); + } + private bool StepTransition(int TransId) + { + if (_MyItemInfo == null) return false; + _MyItemInfo.MyContent.RefreshContentTransitions(); + foreach (TransitionInfo trans in _MyItemInfo.MyContent.ContentTransitions) + if (trans.TransitionID == TransId) + return trans.MyItemToID.IsStep; + return false; + } + private string DoFortranFormat(string text) + { + if (text.IndexOf(@".E") < 0) return text; + // Look for text as n.Ey, where n can be null or a number, and y can be + // positive or negative. This translates into nx10x10y where y is + // superscripted. For example, .E3 -> 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\up2 {1}\up0 ", fnum, supnum); + retstr = retstr.Replace(m.Value, newstr); + } + return retstr; + } + #endregion + #region SaveData + public bool Save(RichTextBox rtb) + { + string rtbString = RtfToDbText(rtb.Rtf).Replace("", "\\\\"); + return Save(rtbString); + } + public bool Save(string modtext) + { + //int savSelStart = rtb.SelectionStart; + try + { + //FormatInfo formatInfo = _MyItemInfo.ActiveFormat; + using (_MyItem = _MyItemInfo.Get()) + { + // The following was added to support transitions to un-numbered steps + if (_MyItemInfo.NewTransToUnNumberedItem && modtext.Contains("")) //rtb.Text.Contains("")) + { + ItemAnnotation ia = _MyItem.ItemAnnotations.Add(AnnotationType.GetByName("Verification Required")); + ia.SearchText = "Transition to Un-Numbered Step"; + _MyItemInfo.NewTransToUnNumberedItem = false; + } + // 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 != EditText) + { + Console.WriteLine("Save Failed because text changed outside of this edit session."); + return false; + } + //string modtext = RtfToDbText(rtb.Rtf).Replace("", "\\\\"); + + // 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(modtext); + // Compare ro/transition lists and delete or add any to the item for any ros/transitions that have been + // added/deleted or modified. + ProcessRoTranChanges(_MyItem, origList); + EditText = DteToString(); + // if new transitions/ros, we need to 'fix' the string in the embedded link to contain the + // transition or usage record. + Dictionary ctReplacements = BuildCtReplacements(_MyItem.MyContent.ContentTransitions); + Dictionary roUsgReplacements = BuildRoUsgReplacements(_MyItem.MyContent.ContentRoUsages); + _MyItem.DTS = DateTime.Now; + _MyItem.UserID = Volian.Base.Library.VlnSettings.UserID; + // Do the Save once rather than multiple times + _MyItem.Save(); + if (ctReplacements.Count > 0) + { + EditText = FixCtReplacements(EditText, ctReplacements); + // Replace Transition Text + foreach (ContentTransition ct in ctReplacements.Values) + using (TransitionInfo tran = TransitionInfo.Get(ct.TransitionID)) + _MyItem.MyContent.FixTransitionText(tran); + _MyItem.Save(); + } + if (roUsgReplacements.Count > 0) + { + EditText = FixRoUsgReplacements(EditText, roUsgReplacements); + _MyItem.Save(); + } + modtext = EditText; + } + else + { + EditText = modtext; + foreach (Csla.Validation.BrokenRule br in _MyItem.MyContent.BrokenRulesCollection) + { + Console.WriteLine("{0} - {1}", br.Property, br.Description); + } + // Don't update the DTS or User for Text Changes + //_MyItem.DTS = DateTime.Now; + //_MyItem.UserID = Volian.Base.Library.VlnSettings.UserID; + _MyItem.Save(); + } + _MyItem = null; + OriginalText = modtext; + } + if (!_MyItemInfo.IsStep) + { + _MyItemInfo.UpdateTransitionText(); + _MyItemInfo.UpdateROText(); + } + } + catch (Exception ex) + { + Console.WriteLine("DisplayText Save Failed with error: {0} - {1}\r\n{2}", ex.GetType().Name, ex.Message, ex.StackTrace); + return false; + } + //rtb.SelectionStart = savSelStart; + 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.GetJustRoDb(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[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; + 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 (dte.Type == E_TextElementType.Transition) + ct.IsRange = 0; + else if (tr1 != tr2) + ct.IsRange = 1; + else + ct.IsRange = 2; + l_dte.Link = l_dte.Link.Replace("", string.Format("", ct.TransitionID)); + l_dte.TextAndLink = l_dte.TextAndLink.Replace("", string.Format("", ct.TransitionID)); + if (dispose2) itm2.Dispose(); + if (dispose1) itm1.Dispose(); + } + } + } + } + } + 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 = text; + + int startIndex = 0; + int index = -1; + noExtraRtfStr = noExtraRtfStr.Replace(@"><", @">\v0 \v <"); + 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?"); + noExtraRtfStr = noExtraRtfStr.Replace(@"\'a0", @"\u160?"); + + // Check for two links in a row & if found, add separating rtf comment + // commands (these get removed in the richtextbox: + // RHM 20100303 Not sure why this is here. The RichTextBox will always remove it. + //noExtraRtfStr = noExtraRtfStr.Replace(@"[END>\v0 \v -1) noExtraRtfStr = noExtraRtfStr.Replace(@"\'05", "\x05"); + + return noExtraRtfStr; + } + public static string StaticReplaceRTFClause(Match m) + { + try + { + string token = m.Groups[1].Value; + switch (token[1]) + { + case '\\': + return token; + case 'u': + if (Regex.IsMatch(token, @"^\\u[0-9]+$")) + return token; // Special Charcaters + if (Regex.IsMatch(token, @"^\\ulnone ?$")) + return token; + if (Regex.IsMatch(token, @"^\\ul.*$")) + return token; // Underline + if (Regex.IsMatch(token, @"^\\up[0-9] ?$")) + return token; // shift up (superscript) + break; + case 'd': + if (Regex.IsMatch(token, @"^\\dn[0-9] ?$")) + return token; // shift down (subscript) + break; + case '\'': // Special Character + return token; + case 'b': // Bold + return token; + case 'i': // Italics + return token; + case '{': // look for escape for curly braces: + return token; + case '}': + return token; + case 'v': // save link hidden info + if (token == "\\viewkind4 ") break; + if (Regex.IsMatch(token, @"^\\v0? ?$")) + return token; // comment part of link + // If possible show what procedure was being processed. + if(_MyStaticItemInfo == null) + _MyLog.WarnFormat("<<>>\r\n==> Token including Comment not processed '{0}'", token); + else + _MyLog.WarnFormat("<<>>\r\n==> Token including Comment not processed '{0}' in {1},[{2}]", token, _MyStaticItemInfo.ShortPath, _MyStaticItemInfo.ItemID); + break; + case 'l': + if (Regex.IsMatch(token, @"^\\line ?$")) return token; + if (Regex.IsMatch(token, @"^\\li[-0-9]+ ?$")) return token; // line indent + break; + case 'f': + if (Regex.IsMatch(token, @"^\\fi[-0-9]+ ?$")) return token; // first line indent + break; + case 'p': + if (Regex.IsMatch(token, @"^\\par ?$")) return "\r\n"; + //if (token == @"\protect") + // return token; + //if (token == @"\protect0") + // return token; + //if (token.Length >= 6 && token.Substring(0, 6) == "\\par\r\n") return token.Replace("\r\n", " "); + break; + //case 'f': // handle fonts separately because they may or may not have a space after them + // if (token[2] >= '0' && token[2] <= '9') return token; + // break; + } + } + catch (Exception ex) + { + Console.WriteLine("StaticReplaceRTFClause {0} - {1}", ex.GetType().Name, ex.Message); + } + return "";//Strip All + } + private static Regex reg1 = new Regex(@"\\par\r\n(?!\\)"); + private static Regex reg2 = new Regex(@"[\r\n]", RegexOptions.Singleline); // Strip Carriage Returns and Newlines + private static Regex reg3 = new Regex(@"^\{(.*)\}$", RegexOptions.Singleline); // Strip Opening and Closing Braces + private static Regex reg4 = new Regex(@"\{[^{]*?\}", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces + private static Regex reg5 = new Regex(@"\{[^{]*?\}", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces + private static Regex reg6 = new Regex(@"(\\[^' \\?\r\n\t]+)(?=\\)"); // add space after token if followed by token + private static Regex reg7 = new Regex(@"(\\[^' \\?\r\n\t]+ )"); // take backslash xyz and evaluates them + private static Regex reg8 = new Regex(@"(\\[^' \\?\r\n\t]+) (?=\\)"); // remove space between tokens + private static Regex reg9 = new Regex(@"(\\[^' \\?\r\n\t]+) (?=\r\n)"); // remove space before /r/n + + public 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 = reg1.Replace(retval, "\\par "); + retval = retval.Replace("\\v0\r\n", "\\v0 "); // Replace Carriage Return and Newline after comment + retval = reg2.Replace(retval, ""); // Strip Carriage Returns and Newlines + retval = reg3.Replace(retval, "$1"); // Strip Opening and Closing Braces + retval = reg4.Replace(retval, ""); // Strip Clauses - remove anything from curly braces + retval = reg5.Replace(retval, ""); // Strip Clauses - remove anything from curly braces + retval = reg6.Replace(retval, "$1 "); // add space after token if followed by token + retval = reg7.Replace(retval, new MatchEvaluator(StaticReplaceRTFClause)); // take backslash xyz and evaluates them + retval = reg8.Replace(retval, "$1"); // remove space between tokens + retval = reg9.Replace(retval, "$1"); // remove space before /r/n + + //retval = Regex.Replace(retval, @"\\par\r\n(?!\\)", "\\par "); + //retval = retval.Replace("\\v0\r\n", "\\v0 "); // Replace Carriage Return and Newline after comment + //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, @"(\\[^' \\?\r\n\t]+)(?=\\)", "$1 "); // add space after token if followed by token + //retval = Regex.Replace(retval, @"(\\[^' \\?\r\n\t]+ )", new MatchEvaluator(StaticReplaceRTFClause)); // take backslash xyz and evaluates them + //retval = Regex.Replace(retval, @"(\\[^' \\?\r\n\t]+) (?=\\)", "$1"); // remove space between tokens + //retval = Regex.Replace(retval, @"(\\[^' \\?\r\n\t]+) (?=\r\n)", "$1"); // remove space before /r/n + + // remove \r\n at end of string if the string has 2 or more characters + if (retval.EndsWith("\r\n")) retval = retval.Remove(retval.Length - 2, 2); + if (retval.Length == 0) return ""; + if (retval.EndsWith(@"\v")) retval = retval.Remove(retval.Length - 2, 2); + retval = _MyItemInfo.RemoveRtfStyles(retval); // RemoveRtfStyles(retval); + retval = retval.Replace(@" (![", @"\{"); + retval = retval.Replace(@" (!]", @"\}"); + retval = retval.TrimEnd(' '); + return retval; + } + + private static Regex sreg1 = new Regex(@"\\par\r\n(?!\\)"); + private static Regex sreg2 = new Regex(@"[\r\n]", RegexOptions.Singleline); // Strip Carriage Returns and Newlines + private static Regex sreg3 = new Regex(@"^\{(.*)\}$", RegexOptions.Singleline); // Strip Opening and Closing Braces + private static Regex sreg4 = new Regex(@"\{[^{]*?\}", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces + private static Regex sreg5 = new Regex(@"\{[^{]*?\}", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces + private static Regex sreg6 = new Regex(@"(\\[^' \\?\r\n\t]+)(?=\\)"); // add space after token if followed by token + private static Regex sreg7 = new Regex(@"(\\[^ \\?\r\n\t]+ )"); // take backslash xyz and evaluates them + private static Regex sreg8 = new Regex(@"(\\[^ \\?\r\n\t]+) (?=\\)"); // remove space between tokens + private static Regex sreg9 = new Regex(@"(\\[^ \\?\r\n\t]+) (?=\r\n)"); // remove space before /r/n + + // This is used in the DataLoader + public static string StaticStripRtfCommands(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(@"\}", @" (!]"); + + // 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? + retval = retval.Replace(@"\~", @"\u160?"); + + // 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 = sreg1.Replace(retval, "\\par "); + + + retval = retval.Replace("\\v0\r\n", "\\v0 "); // Replace Carriage Return and Newline after comment + retval = sreg2.Replace(retval, ""); // Strip Carriage Returns and Newlines + retval = sreg3.Replace(retval, "$1"); // Strip Opening and Closing Braces + retval = sreg4.Replace(retval, ""); // Strip Clauses - remove anything from curly braces + retval = sreg5.Replace(retval, ""); // Strip Clauses - remove anything from curly braces + retval = sreg6.Replace(retval, "$1 "); // add space after token if followed by token + retval = sreg7.Replace(retval, new MatchEvaluator(StaticReplaceRTFClause)); // take backslash xyz and evaluates them + retval = sreg8.Replace(retval, "$1"); // remove space between tokens + retval = sreg9.Replace(retval, "$1"); // remove space before /r/n + + //retval = Regex.Replace(retval, @"\\par\r\n(?!\\)", "\\par "); + ////retval = Regex.Replace(retval, @"\\par\r\n(?=\\)", "\\par"); + + //retval = retval.Replace("\\v0\r\n", "\\v0 "); // Replace Carriage Return and Newline after comment + //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, @"(\\[^ \\?\r\n\t]+)\\f[0-9] ", "$1 "); // remove font command - if next to another command, keep other command and space + //// OLD: The following two lines are replaced by the more generic replace above. + ////retval = Regex.Replace(retval, @"\\v\\f[0-9] ", "\\v "); // remove font command - if next to Comment keep space + ////retval = Regex.Replace(retval, @"\\line\\f[0-9] ", "\\line "); // remove font command - if next to Line keep space + ////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, @"\\par ", "\r\n"); + //retval = Regex.Replace(retval, @"(\\[^' \\?\r\n\t]+)(?=\\)", "$1 "); // add space after token if followed by token + ////retval = Regex.Replace(retval, @"(\\[^ \\?\r\n\t]+)(\\)", "$1 $2"); // take backslash xyz and evaluates them + //retval = Regex.Replace(retval, @"(\\[^ \\?\r\n\t]+ )", new MatchEvaluator(StaticReplaceRTFClause)); // take backslash xyz and evaluates them + //retval = Regex.Replace(retval, @"(\\[^ \\?\r\n\t]+) (?=\\)", "$1"); // remove space between tokens + //retval = Regex.Replace(retval, @"(\\[^ \\?\r\n\t]+) (?=\r\n)", "$1"); // remove space before /r/n + + // 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 at end of string if the string has 2 or more characters + if (retval.Length > 1 && retval.Substring(retval.Length - 2, 2) == "\r\n") retval = retval.Remove(retval.Length - 2, 2); + // remove \par at end of string if the string has 4 or more characters + //if (retval.Length > 3 && retval.Substring(retval.Length - 4, 4) == @"\par") retval = retval.Remove(retval.Length - 4, 4); + // remove a space following \r\n + //retval = Regex.Replace(retval, "\r\n ", "\r\n"); + ////if there are still spaces following \r\n, then probable in a table - we need to put the space back + //retval = Regex.Replace(retval, "\r\n ", "\r\n "); + + if (retval.Length == 0) return ""; + if (retval.Length > 1 && retval.Substring(retval.Length - 2, 2) == @"\v") retval = retval.Remove(retval.Length - 2, 2); + //retval = RemoveRtfStyles(retval); + //if (itmInfo != null) + // retval = StaticRemoveRtfStyles(retval, itmInfo); + + retval = retval.Replace(@" (![", @"\{"); + retval = retval.Replace(@" (!]", @"\}"); + retval = retval.TrimEnd(' '); + + // the indent character was translated in the richtextbox, change it back: + if (retval.IndexOf(@"\'05") > -1) retval = retval.Replace(@"\'05", "\x05"); + 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 + 2] !='p')) || (txt[indx + 1] == '\'')) return indx; + // see if link + if (txt[indx + 1] == 'v') return indx; //TODO - should have ") != -1) return text; + int transitionID = Convert.ToInt32(link.Split(" ".ToCharArray())[1]); + // Find the transition + if (_MyItemInfo.MyContent.ContentTransitionCount <= 0) + { + // TODO: RHM 20100310 + _MyItemInfo.MyContent.RefreshContentTransitions(); + 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, ti.TranType, ti.MyItemToID, ti.MyItemRangeID); + 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 GetLastLower(string stepText) + //{ + // // TO DO: need to check AlwaysUpperCase format setting - this was not yet converted as of 17Jun2010 + // // if (AlwaysUpperCase[steptype]) return (stepText.Length-1); + + // int idx = stepText.Length - 1; + // while (idx >= 0 && !(char.IsLower(stepText[idx]) && stepText[idx] != 's')) idx--; + // if (idx < 0) idx = stepText.Length - 1; // entire string is uppercased set return value to end of string + // return idx; + //} + + //private bool IsSpaceOrHardSpace(char ch) + //{ + // string spaces = @" \u160?"; + // return (spaces.IndexOf(ch) >= 0); + //} + private string DoROFormatFlags(string roText, string beforeRO, string afterRO, bool isSetpoint) + { + string rtnstr = roText; + // The RO text is being changed to match it's context. Since it is changed in reverse order, the text before the RO + // should ignore other RO text. + beforeRO = Regex.Replace(beforeRO, @"\", ""); // Remove any RO Values. + beforeRO = Regex.Replace(beforeRO, @"(\\[^v \\]+)*\\v(\\[^v \\]+)* .*?\\v0(\\[^v \\]+)*( |$)", ""); // Remove Comments + string allUnitAfterRo = afterRO; + afterRO = Regex.Replace(afterRO, @"(\\[^v \\]+)*\\v(\\[^v \\]+)* .*?\\v0(\\[^v \\]+)*( |$)", ""); // Remove Comments + + // Underline all ROs, values and Units + if (isSetpoint && _MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.UnderlineRo) + { + // TO DO: Need to check if step text is already underlined + if ((_MyItemInfo.FormatStepData.Font.Style & E_Style.Underline) == 0) + rtnstr = @"\ul " + rtnstr + @"\ulnone "; + } + + // UpcaseAllRoUnits - Uppercases ALL ROs units everywhere. + if (isSetpoint && _MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.UpcaseAllRoUnits) + return UpperCaseUnits(rtnstr); + + //Forces the units for a RO to be uppercased for high level steps + if (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.CapHighRo &&_MyItemInfo.IsHigh) + return UpperCaseUnits(rtnstr); + + // Caps ROs anywhere if no lower case text follows + // and an upper case letter immediately precedes the RO. + + if (isSetpoint && _MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.CapSPIfLastLower && + !Regex.IsMatch(afterRO, @".*(? 0 && !IsSpaceOrHardSpace(stepText[indx])) indx--; // find character before RO + //while (indx2 <= stepText.Length && !IsSpaceOrHardSpace(stepText[indx2])) indx2++; // find character after RO + + //if (indx >= 0 && char.IsUpper(stepText[indx]) && indx2 > GetLastLower(stepText)) + // doUpCase = true; + return UpperCaseUnits(rtnstr); + } + + // If a RO follows a "- " then it will be uppercased + if (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.UpRoAftrDash && Regex.IsMatch(beforeRO, @".*\\u8209\?( |\\u160\?)")) + { + //int indx = startLinkText - 1; + //while (indx > 0 && !IsSpaceOrHardSpace(stepText[indx])) indx--; // find character before RO + //string prefix = indx >= 7?stepText.Substring(indx-7,8):""; + //doUpCase = (prefix == @"\u8209? "); // Dash character before RO + return UpperCaseUnits(rtnstr); + } + // For Wolf Creek, the "- " should be right before the link. This ro format flag was introduced + // for Wolf Creek only because a problem was found with some of their data that was incorrectly + // processed through the 'UpRoAftrDash' flag. That flag was more general, i.e. upper cased units + // if there was a dash and then a space or hard space anywhere before the RO text. The original + // 16bit flag was more specific. Other plants that were released had the UpRoAftrDash, but + // we didn't want to change their formats since they had gone through testing. + if (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.UpRoImmAftrDashSpace && Regex.IsMatch(beforeRO, @".*\\u8209\?( )")) + return UpperCaseUnits(rtnstr); + + // Uppercase the RO Unit if the previous letter is uppercase + if (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.UpRoIfPrevUpper && char.IsUpper(LastAlpha(beforeRO))) + { + //doUpCase = (char.IsUpper(stepText[startLinkText - 1])); + return UpperCaseUnits(rtnstr); + + } + + //CapFirstLetterInHighRO - Cap only the first letters of the units in a high level RO + // note: used in FLP (Turkey Point) format + if (_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.CapFirstLetterInHighRO && _MyItemInfo.IsHigh) + { + int idx = 0; + string tstr = ""; + while (idx < rtnstr.Length && !char.IsLetter(rtnstr[idx])) tstr += rtnstr[idx++].ToString(); + if (idx < rtnstr.Length) + { + tstr += char.ToUpper(rtnstr[idx]).ToString(); + if (idx + 1 < rtnstr.Length) + tstr += rtnstr.Substring(idx + 1); + } + rtnstr = tstr; + } + + return rtnstr; + } + + private string RemoveMultipleUnits(string prevValue, string rtnstr) + { + //In a sequence of RO values, the unit appears with every value + //(e.g., "25 gpm and 30 gpm" vs. "25 and 30 gpm") + if (!_MyItemInfo.ActiveFormat.PlantFormat.FormatData.ROData.AllUnits && prevValue != null) + { + string units = null; + //Match m = Regex.Match(prevValue, "[^0-9]"); + int ind = prevValue.LastIndexOfAny("0123456789".ToCharArray()); + if (ind>=0) + { + string mynum = prevValue.Substring(0, ind+1); + // Handle Hex characters which are part of the Units such as the degree character + if (Regex.IsMatch(mynum, @".*\\'[A-Fa-f0-9]{2,2}$")) + ind -= 4; + units = prevValue.Substring(ind+1); + if (rtnstr.EndsWith(units) && units != "")// Don't do this if there are no units + { + rtnstr = rtnstr.Replace(units, ""); + } + } + } + return rtnstr; + } + /// + /// Uppercase alphabetical strings excluding any RTF token + /// + /// + /// + private string MatchEvaluatorUppercaseROUnits(Match match) + { + if (match.Value[0] == '\\') // If the previous character is a backslash then this is an RTF token + return match.Value; + return match.Value.ToUpper(); + } + Regex _RegExUppercaseROUnits = new Regex("(^|[^a-zA-Z])[a-zA-Z]+"); + private string UpperCaseUnits(string rtnstr) + { + // Uppercase Units + rtnstr = _RegExUppercaseROUnits.Replace(rtnstr, new MatchEvaluator(MatchEvaluatorUppercaseROUnits)); + // After converting the value to uppercase, change X10 to x10 to handle Fortran Formatted numbers + return rtnstr.Replace("X10", "x10"); + } + + // Find the last Alphabetical character + private char LastAlpha(string beforeRO) + { + Match m = Regex.Match(beforeRO, ".*([a-zA-Z])[^a-zA-Z]*"); + if (m.Success) return m.Groups[1].ToString()[0]; + return '\0'; + } + + private int DoLinkElements(string text, int index, displayLinkElement vte) + { + // Find the 'end comment' for this 0 && (endTextIndx < 0 || endTextIndx > endTextIndx2)) + endTextIndx = endTextIndx2; + vte.Text = text.Substring(endStartTknIndx + startAdj, endTextIndx - endStartTknIndx - startAdj); // 4 for \v0 + + // Now get the link part. It can be terminated by a '\v0' or an [END> + 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; + } + //else + //{ + // tmptxt = DoROFormatFlags(vte.Text, text, index, endLinkIndx); + // 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) + { + if (vte.TextAndLink.Contains("(Resolved Transition Text)")) + vte.TextAndLink = vte.TextAndLink.Replace("(Resolved Transition Text)", tmptxt); + else + if (vte.Text != tmptxt) + vte.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 + #region commented out + //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; + + // if (_MyItemInfo.ItemID == 2557) Console.WriteLine("here"); + // // 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.IsStepPart && (rs.Flag & E_ReplaceFlags.Substep) > 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|$)"; + // //// jsj 07Jun2010 HardSpaces defeat replaceword logic + // //string pat = @"(?<=\W|^)(? 0) + // { + // // only in Maine Yankee - we don't need to do this one. + // } + // // 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) + // { + // // only used in V.C. Summer - we don't need to do this either. + // } + // else + // { + // // If there are Regex Control Characters '\[]()' prefix them with backslash + // string replaceWord = Regex.Replace(rs.ReplaceWord, @"[[\]\\()]", @"\$0"); + // //string pat = @"(?<=\W|^)" + replaceWord + @"(?=\W|$)"; + // // jsj 07Jun2010 HardSpaces defeat replaceword logic + // //string pat = @"(?<=\W|^)(? 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.IsStepPart && (rs.Flag & E_ReplaceFlags.Substep) > 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 + // RegexOptions myOptions = (rs.Flag & E_ReplaceFlags.CaseInsens) == E_ReplaceFlags.CaseInsens ? RegexOptions.IgnoreCase : RegexOptions.None; + // string replaceWord = Regex.Replace(rs.ReplaceWord, @"[[\]\\()]", @"\$0"); + // string pat = @"(?<=\W|^)(? dicReplaceRegex = new Dictionary(); + private static bool? _ProcessReplaceWords; + public static bool ProcessReplaceWords + { + get + { + if (_ProcessReplaceWords == null) + { + string[] parameters = System.Environment.CommandLine.Split(" ".ToCharArray()); + _ProcessReplaceWords = true; + foreach (string parameter in parameters) + { + if (parameter.ToUpper() == "/NRW") + _ProcessReplaceWords = false; + } + } + return (bool) _ProcessReplaceWords; + } + } + private string DoReplaceWords2(string Text) + { + if(!ProcessReplaceWords) return Text; + if (_MyItemInfo.MyContent.Type < 20000) return Text; // for now only replace in steps. + FoundMatches myMatches = new FoundMatches(Text,_MyItemInfo.FormatStepData.Font,_MyItemInfo); + // Exclude Link Text from Replace Word process + myMatches.AddLink(regFindLink, _MyFormat.PlantFormat.FormatData.SectData.ReplaceWordsInROs, _MyItemInfo.MyProcedure.MyDocVersion); + ReplaceStrList rsl = _MyFormat.PlantFormat.FormatData.SectData.ReplaceStrList; + + // ReplaceStrData xml node is empty, it does the inheritance and gets the 'base' format's list. + if (rsl.Count==1 && (rsl[0].ReplaceWord == null || rsl[0].ReplaceWord == "")) return Text; + // Loop through text looking for words to be replaced + Dictionary partialReplaceList = new Dictionary(); + Dictionary shouldReplace = new Dictionary(); + //int profileDepth = ProfileTimer.Push(">>>> DoReplaceWords2.ForLoop"); + foreach (ReplaceStr rs in rsl) + { + bool dopartial = (rs.Flag & E_ReplaceFlags.Partials) == E_ReplaceFlags.Partials; + // note that the order of this check is important. Check in this order... + // background here + if (!shouldReplace.ContainsKey(rs.Flag)) + { + //int profileDepth2 = ProfileTimer.Push(">>>> Before ShouldReplaceIt"); + shouldReplace.Add(rs.Flag, ShouldReplaceIt(rs.Flag)); + //ProfileTimer.Pop(profileDepth2); + } + bool replaceit = shouldReplace[rs.Flag]; + + if (replaceit) + { + if (!dicReplaceRegex.ContainsKey(rs)) + { + RegexOptions myOptions = (rs.Flag & E_ReplaceFlags.CaseInsens) == E_ReplaceFlags.CaseInsens ? RegexOptions.IgnoreCase : RegexOptions.None; + if (dopartial) + { + dicReplaceRegex.Add(rs, new Regex(rs.ReplaceWord, myOptions)); + } + else + { + //int profileDepth3 = ProfileTimer.Push(">>>> DoReplaceWords2.BuildMatch"); + // CASEINSENS: Do ReplaceWords for all words that match, regardless of case, and replace with the ReplaceWith string as is + //RegexOptions myOptions = (rs.Flag & E_ReplaceFlags.CaseInsens) == E_ReplaceFlags.CaseInsens ? RegexOptions.IgnoreCase & RegexOptions.Singleline : RegexOptions.None & RegexOptions.Singleline; + string replaceWord = Regex.Replace(rs.ReplaceWord, @"[[\]\\()]", @"\$0"); + // if first or last character in replaceword is a non-word character, for example, ',', ')', or '.', + // don't use the \W, i.e. don't bother to look for a non-word character. + string wordMatchBeg = Regex.IsMatch(replaceWord.Substring(0, 1), @"\W") ? "" : @"(?<=\W|^)"; + string wordMatchEnd = Regex.IsMatch(replaceWord.Substring(replaceWord.Length - 1, 1), @"\W") ? "" : @"(?=\W|$)"; + string pat = wordMatchBeg + @"(?>>> DoReplaceWords2.Partial"); + if (!dopartial) myMatches.Add(dicReplaceRegex[rs], rs); + else partialReplaceList.Add(rs, dicReplaceRegex[rs]); + //ProfileTimer.Pop(profileDepth4); + } + catch (Exception ex) + { + Console.WriteLine("{0},'{1}',{2},'{3}'", _MyItemInfo.ActiveFormat.Name, rs.ReplaceWord, ex.GetType().Name, ex.Message); + } + dopartial = false; + } + } + //ProfileTimer.Pop(profileDepth); + //int profileDepth5 = ProfileTimer.Push(">>>> DoReplaceWords2.ReplaceMatches"); + Text = myMatches.ReplaceMatches(); + //ProfileTimer.Pop(profileDepth5); + Text = Text.Replace(@"\xA0", @"\u160?"); //replace hard space + try + { + foreach (ReplaceStr prs in partialReplaceList.Keys) + Text = partialReplaceList[prs].Replace(Text, prs.ReplaceWith); + } + catch (Exception ex) // Don't crash on a format issue. + { + _MyLog.WarnFormat("{0} - {1}", ex.GetType().Name, ex.Message); + } + return Text; + } + private bool ShouldReplaceIt(E_ReplaceFlags? myFlag) + { + bool replaceit= false; + if (_MyItemInfo.IsHigh && (myFlag & E_ReplaceFlags.High) > 0) + { + replaceit = true; + } + else if ((_MyItemInfo.IsTable || _MyItemInfo.IsFigure) && (myFlag & E_ReplaceFlags.Table) > 0) + { + replaceit = true; + } + else if (_MyItemInfo.IsInRNO && (myFlag & E_ReplaceFlags.RNO) > 0) + { + replaceit = true; + } + else if (_MyItemInfo.IsCaution && (myFlag & E_ReplaceFlags.Caution) > 0) + { + replaceit = true; + } + else if (_MyItemInfo.IsNote && (myFlag & E_ReplaceFlags.Note) > 0) + { + replaceit = true; + } + else if (_MyItemInfo.IsStepPart && !_MyItemInfo.IsHigh && (myFlag & E_ReplaceFlags.Substep) > 0) + { + replaceit = true; + } + //else if (_MyItemInfo.IsInFirstLevelSubStep && (rs.Flag & E_ReplaceFlags.Substep) > 0) replaceit = true; + else if (_MyItemInfo.IsAccPages & (myFlag & E_ReplaceFlags.Attach) > 0) + { + replaceit = true; + } + return replaceit; + } + #region notused + static Regex regFindLink = new Regex(@"\", RegexOptions.Singleline); + private string ReplaceWord(string text, string replace, string with, RegexOptions regexOptions) + { + MatchCollection myMatches = Regex.Matches(text, replace, regexOptions); + MatchCollection myLinks = regFindLink.Matches(text); + for (int i = myMatches.Count - 1; i >= 0; i--) + { + Match myMatch = myMatches[i]; + if (!PartOfLinkText(myMatch, myLinks)) + text = text.Substring(0, myMatch.Index) + with + text.Substring(myMatch.Index + myMatch.Length); + } + return text; + } + + private bool PartOfLinkText(Match myMatch, MatchCollection myLinks) + { + foreach (Match myLink in myLinks) + if (myMatch.Index > myLink.Index && myMatch.Index < (myLink.Index + myLink.Length)) + return true; + return false; + } + #endregion + #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; } + } + protected string _Text; + virtual 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; } + } + /// + /// Text - this should parse the text and return the results + /// + override public string Text + { + get + { + if (_TextAndLink != null) + { + Match m = Regex.Match(_TextAndLink, @"", RegexOptions.Singleline); + if(m.Groups[3].Value == " ") + return m.Groups[4].Value; + return m.Groups[3].Value + m.Groups[4].Value; + } + return _Text; + } + set + { + if (_TextAndLink != null) + { + Match m = Regex.Match(_TextAndLink, @"", RegexOptions.Singleline); + int myIndex = m.Groups[4].Index; + int myLength = m.Groups[4].Length; + if (m.Groups[3].Value != " ") + { + myIndex = m.Groups[3].Index; + myLength += m.Groups[3].Length; + } + string gg = _TextAndLink.Substring(myIndex, myLength); + string newvalue = value.Replace("{", @"\{").Replace("}", @"\}"); + _TextAndLink = _TextAndLink.Substring(0, myIndex) + newvalue + _TextAndLink.Substring(myIndex + myLength); + } + _Text = value; + } + } + } + #endregion + public class FoundMatches : SortedList + { + private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private string _Text; + private VE_Font _Font; + private ItemInfo _MyItemInfo; + public FoundMatches(string text, VE_Font font, ItemInfo myItemInfo) + : base() + { + _Text = text; + _Font = font; + _MyItemInfo = myItemInfo; + } + public void Add(Regex myRegEx, ReplaceStr myWord) + { + MatchCollection myMatches = myRegEx.Matches(_Text); + foreach (Match myMatch in myMatches) + Add(myMatch, myWord); + } + public void AddLink(Regex myRegEx, bool replaceWordsInROs, DocVersionInfo myDocVersion) + { + MatchCollection myMatches = myRegEx.Matches(_Text); + foreach (Match myMatch in myMatches) + { + if (!replaceWordsInROs || IsTransition(myMatch.Value) || IsSetpointRO(myMatch.Value, myDocVersion)) + Add(myMatch, null);// Exclude from Replace Words + } + } + private bool IsTransition(string link) + { + return link.Contains("#Link:Transition"); + } + private static Regex regRefObj = new Regex(@"\#Link\:ReferencedObject:([0-9]*) ([0-9a-zA-Z]*) ([0-9]*)", RegexOptions.Singleline); + private static bool IsSetpointRO(string link, DocVersionInfo myDocVersion) + { + Match myMatch = regRefObj.Match(link); + if (myMatch.Success) + { + int dbid = System.Convert.ToInt32(myMatch.Groups[2].Value.Substring(0, 4), 16); + int rodbid = int.Parse(myMatch.Groups[3].Value); + ROFstInfo myROFst = myDocVersion.GetROFst(rodbid); + return myROFst.IsSetpointDB(dbid, myDocVersion); + } + return false; + } + public void Add(Match myMatch, ReplaceStr myWord) + { + // If one already exists for this location, then don't add another. + if (ContainsKey(myMatch.Index)) return; + // Start by Adding it. + base.Add(myMatch.Index, new FoundMatch(myMatch, myWord)); + // Now see what I can do with it. + int index = this.IndexOfKey(myMatch.Index); + if (index > 0) // If this match is contained within the previous match remove it + { + FoundMatch previousMatch = Values[index - 1]; + if (previousMatch.MyMatch.Index + previousMatch.MyMatch.Length > myMatch.Index) + Remove(myMatch.Index); + } // If the next match is contained within this match, remove the next match + while (index < Count - 1 && Values[index + 1].MyMatch.Index < (myMatch.Index + myMatch.Length)) + Remove(Values[index + 1].MyMatch.Index); + } + public bool StartsWith(string text, int index, params string[] examples) + { + foreach (string str in examples) + if (str.Length == index && str == text.Substring(0, str.Length)) return true; + return false; + } + public string ReplaceMatches() + { + int offset = 0; + string text = _Text; + foreach (FoundMatch foundMatch in Values) + { + if (foundMatch.MyWord != null) + { + if (VerifyNoHardSpace(text, foundMatch, offset) && VerifyNoLink(text, foundMatch, offset)) + { + //if(offset != 0 || foundMatch.MyMatch.Index != 0 || !foundMatch.MyWord.ReplaceWith.StartsWith(@"{\par}")) + //{ + if (((foundMatch.MyWord.Flag & E_ReplaceFlags.DiffUnit) == 0) || DiffUnit(foundMatch.MyWord.ReplaceWord,_MyItemInfo,"UNIT ")) + { + string with = foundMatch.MyWord.ReplaceWith; + if (offset == 0 && with.StartsWith(@"{\par}")) + if(StartsWith(text,foundMatch.MyMatch.Index,"",@"\ul ",@"\b ",@"* ",@"* \ul ",@"* \b ",@"*",@"*\ul ",@"*\b ")) + with = with.Replace(@"{\par}", ""); + bool IsBold = ((_Font.Style & E_Style.Bold) == E_Style.Bold) || + (_MyItemInfo.FormatStepData != null && _MyItemInfo.FormatStepData.BoldHighLevel && _MyItemInfo.IsRNOPart && _MyItemInfo.MyParent.IsHigh ); + if (IsBold && with.Contains(@"\b ")) + { + with = with.Replace(@"\b ",""); + with = with.Replace(@"\b0 ",""); + } + bool IsUnderline = (((_Font.Style & E_Style.Underline) == E_Style.Underline) && with.Contains(@"\ul ")); + // handle where replace words replaces a string with 'underline on'string'underline off', for example Point Beach + // had replaced OR's turning underline off in the middle of a transition, "EOP-0 UNIT 1, RACTORE TRIP OR SAFETY INJECTION". + if (!IsUnderline) + { + int repidxulnone = text.LastIndexOf(@"\ulnone", foundMatch.MyMatch.Index + offset); + int repidxst = text.LastIndexOf(@"\ul", foundMatch.MyMatch.Index + offset); + if (repidxulnone > 0) + { + repidxst = text.Substring(repidxulnone + 7, foundMatch.MyMatch.Index + offset - (repidxulnone + 7)).LastIndexOf(@"\ul"); + if (repidxst >= 0) + repidxst += (repidxulnone + 7); + } + if (repidxst >= 0) IsUnderline = true; + } + if (IsUnderline) + { + with = with.Replace(@"\ul ", ""); + with = with.Replace(@"\ulnone ", ""); + } + string preceedingText = text.Substring(0, offset + foundMatch.MyMatch.Index); + int ndxBold = preceedingText.LastIndexOf(@"\b"); + if (ndxBold > -1 && preceedingText.Length>( ndxBold + 2) && preceedingText[ndxBold + 2] != '0' && with.Contains(@"\b ")) + { + with = with.Replace(@"\b ",""); + with = with.Replace(@"\b0 ",""); + } + int ndxULine = preceedingText.LastIndexOf(@"\ul"); + if (ndxULine > -1 && preceedingText[ndxULine + 3] != 'n' && with.Contains(@"\ul ")) + { + with = with.Replace(@"\ul ", ""); + with = with.Replace(@"\ulnone ", ""); + } + + text = text.Substring(0, offset + foundMatch.MyMatch.Index) + with + text.Substring(offset + foundMatch.MyMatch.Index + foundMatch.MyMatch.Length); + //offset += foundMatch.MyWord.ReplaceWith.Length - foundMatch.MyMatch.Length; + offset += with.Length - foundMatch.MyMatch.Length; + } + } + } + } + return text; + } + private bool VerifyNoLink(string text, FoundMatch fndMatch, int offset) + { + if (text.Substring(offset + fndMatch.MyMatch.Index, fndMatch.MyMatch.Length) == "START") + if (fndMatch.MyMatch.Index > 0 && offset + fndMatch.MyMatch.Index + fndMatch.MyMatch.Length < text.Length && + text.Substring(offset + fndMatch.MyMatch.Index - 1, fndMatch.MyMatch.Length + 2) == " + { + public static Regex _RegReplaceLine = new Regex(@"\\line((\\[^ \[\]\\\(\)]*) )"); + public RtfLines(string text) + { + // replace RTF \line with crlf + string txt = _RegReplaceLine.Replace(text, "$1\r\n"); + // split text into lines + string[] breaks = { "\r\n" }; + string[] lines = txt.Split(breaks, StringSplitOptions.None); + //string lastLine = lines[lines.Length - 1]; + foreach (string line in lines) + Add(new RtfLine(line.Replace("\\bullet","*"))); + } + public int MaximumWidth + { + get + { + int retval = 0; + foreach (RtfLine myLine in this) + if (myLine.MaximumWidth > retval) retval = myLine.MaximumWidth; + return retval; + } + } + public void Pad(int maxWidth, string edge) + { + foreach (RtfLine myLine in this) + myLine.Pad(maxWidth, edge); + + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + string sep = ""; + foreach (RtfLine myLine in this) + { + sb.Append(sep + myLine.ToString()); + sep = "\r\n"; + } + return sb.ToString(); + } + private static Regex _RegRightCheck = new Regex(@"-|\\u9472?|\\u8209\?"); + private static Regex _RegAboveCheck = new Regex(@"\||\\u9474\?|\\u9492\?|\\u9516\?|\\u9532\?|\\u9500\?|\\u9484\?|\\u9524\?|\\u9488\?|\\u9508\?"); + private static Regex _RegLeftCheck = new Regex(@"-|\\u9472\?|\\u9508\?|\\u9516\?|\\u9500\?|\\u9532\?|\\u9484\?|\\u9488\?|\\u9492\?|\\u8209\?"); + private static Regex _RegBelowCheck = new Regex(@"\||\\u9474\?"); + + private static Regex _RegRightCheck1 = new Regex(@"\\u9474\?"); + private static Regex _RegAboveCheck1 = new Regex(@"\\u9472\?|\\u8209\?"); + private static Regex _RegLeftCheck1 = new Regex(@"\\u9474\?"); + private static Regex _RegBelowCheck1 = new Regex(@"\\u9472\?|\\u8209\?"); + + private static Regex _RegHorizontalCheck = new Regex(@"-|\\u9472\?|\\u8209\?"); + private static Regex _RegVerticalCheck = new Regex(@"\||\\u9474\?"); + 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' + }; + internal void ReplaceLines(bool withBorder) + { + int maxWidth = this[0].Count; + for (int row = 1; row < Count - 1; row++) + { + RtfLine lineAbove = this[row - 1]; + RtfLine line = this[row]; + RtfLine lineBelow = this[row + 1]; + for (int col = 1; col < maxWidth - 1; col++) + { + RtfPiece curPiece = line[col]; + string current = curPiece.Text; + bool horizontal = _RegHorizontalCheck.IsMatch(current); // Horizontal + bool vertical = _RegVerticalCheck.IsMatch(current); // Vertical + if (horizontal || vertical) + { + int index = _RegRightCheck.IsMatch(line[col + 1].Text) || + (horizontal && _RegRightCheck1.IsMatch(line[col + 1].Text)) ? 1 : 0; // Right + index += _RegAboveCheck.IsMatch(lineAbove[col].Text) || + (vertical && _RegAboveCheck1.IsMatch(lineAbove[col].Text)) ? 2 : 0; // Above + index += _RegLeftCheck.IsMatch(line[col - 1].Text) || + (horizontal && _RegLeftCheck1.IsMatch(line[col - 1].Text)) ? 4 : 0; // Left + index += _RegBelowCheck.IsMatch(lineBelow[col].Text) || + (vertical && _RegBelowCheck1.IsMatch(lineBelow[col].Text)) ? 8 : 0; // Below + if (index > 0) + { + curPiece.Text = TableCharsU[index]; + // this connects the lines to the border, so only do it if there is a border + if (withBorder) + { + if (vertical && row == 1) lineAbove[col].Text = TableCharsU[13]; // Upper Tee + if (vertical && row == Count - 2) lineBelow[col].Text = TableCharsU[7]; // Lower Tee + if (horizontal && col == 1) line[col - 1].Text = TableCharsU[11];// Left Tee + if (horizontal && col == maxWidth - 2) line[col + 1].Text = TableCharsU[14];// Right Tee + } + } + } + } + } + } + private void ListItems(string loc, string str) + { + StringBuilder sb = new StringBuilder(string.Format("{0} = @\"", loc)); + string sep = ""; + foreach (char c in str) + { + if (c < 127) + sb.Append(sep + c.ToString()); + else + sb.Append(sep + string.Format("\\u{0}?", (int)c)); + sep = "|"; + } + Console.WriteLine(sb.ToString()); + } + } + public class RtfLine : List + { + private static Regex _RegRtfText = new Regex(@"((\\[^'u ]*|\\up[0-9]|\\ul|\\ulnone)+( |$|(?=\\['u])))?(|\\'[0-9a-fA-F]{2}|\\u[0-9]*\?|[^\\]{1}|$|)"); + public RtfLine(string text) + { + MatchCollection matches = _RegRtfText.Matches(text); + int nextIndex = 0; + foreach (Match match in matches) + { + if (nextIndex != match.Index) // This should never happen + { + throw new Exception(string.Format("\"RtfPiece Missing Content\",{0},{1},\"{2}\",\"{3}\",\"{4}\"", nextIndex, match.Index, text.Substring(nextIndex, match.Index - nextIndex), match.Groups[2].Value, match.Groups[4].Value)); + //Console.WriteLine("\"RtfPiece Missing Content\",{0},{1},\"{2}\",\"{3}\",\"{4}\"", nextIndex, match.Index, text.Substring(nextIndex, match.Index - nextIndex), match.Groups[2].Value, match.Groups[4].Value); + //Console.WriteLine(text.Substring(nextIndex)); + } + nextIndex = match.Index + match.Length; + string rtfPart = match.Groups[1].ToString(); + if (match.Groups[1].ToString().TrimEnd(" ".ToCharArray()).Length + match.Groups[4].ToString().Length > 0) + this.Add(new RtfPiece(match.Groups[1].ToString().TrimEnd(" ".ToCharArray()), match.Groups[4].ToString())); + //if (match.Groups[1].ToString().Length + match.Groups[4].ToString().Length > 0) + // this.Add(new RtfPiece(match.Groups[1].ToString(), match.Groups[4].ToString())); + } + } + public RtfLine(int width, string left, string fill, string right) + { + Add(new RtfPiece("", left)); + for (int i = 0; i < width; i++) this.Add(new RtfPiece("", fill)); // Pad + Add(new RtfPiece("", right)); + } + public int MaximumWidth + { + get + { + int retval = 0; + foreach (RtfPiece myPiece in this) + retval += myPiece.MaximumWidth; + return retval; + } + } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + foreach (RtfPiece myPiece in this) + sb.Append(myPiece.ToString()); + return sb.ToString(); + } + internal void Pad(int maxWidth, string edge) + { + int pad = maxWidth - MaximumWidth; + this.Insert(0, new RtfPiece("", edge)); // Left Edge + for (int i = 0; i < pad; i++) this.Add(new RtfPiece("", " ")); // Pad + this.Add(new RtfPiece("", edge)); // Right Edge + } + public new RtfPiece this[int index] + { + get + { + int j = 0; + foreach (RtfPiece myPiece in this) + { + if (myPiece.Text != "") + { + if (j == index) return myPiece; + j++; + } + } + return null; + } + } + } + public class RtfPiece + { + private string _Rtf; + public string Rtf + { + get { return _Rtf; } + set { _Rtf = value; } + } + private string _Text = ""; + public string Text + { + get { return _Text; } + set { _Text = value; } + } + public int TextLength + { + get { return Text.Length; } + } + public int MaximumWidth + { + get { return Text == "" ? 0 : 1; } + } + private static Regex _RegStartLink = new Regex(@""); + public RtfPiece(string rtf, string text) + { + _Rtf = rtf; + if (_RegStartLink.IsMatch(text) || _RegEndLink.IsMatch(text)) + _Rtf += (rtf == "" ? "" : " ") + text; + else + { + _Rtf += rtf == "" ? "" : " "; + _Text = text; + } + } + public override string ToString() + { + return _Rtf + _Text; + //string retval = _RegUnicode.Replace(_Text, new MatchEvaluator(RtfUnicodeCharacter)); + //retval = _RegHex.Replace(retval, new MatchEvaluator(RtfHexCharacter)); + //return retval; + } + //private static Regex _RegUnicode = new Regex(@"\\u([0-9ABCDEF]*)\?"); + //internal static string RtfUnicodeCharacter(Match myMatch) + //{ + // string hexStr = myMatch.Groups[1].ToString(); + // int i = int.Parse(hexStr); + // Char schar = Convert.ToChar(i); + // return schar.ToString(); + //} + //private static Regex _RegHex = new Regex(@"\\'([0-9A-Fa-f]{2})"); + //internal static string RtfHexCharacter(Match myMatch) + //{ + // string hexStr = myMatch.Groups[1].ToString(); + // int i = int.Parse(hexStr, System.Globalization.NumberStyles.HexNumber); + // Char schar = Convert.ToChar(i); + // return schar.ToString(); + //} + } +}