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