570 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			570 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Text;
 | |
| using System.Drawing;
 | |
| using iTextSharp.text.pdf;
 | |
| using iTextSharp.text;
 | |
| using Itenso.Rtf;
 | |
| using Itenso.Rtf.Parser;
 | |
| using Itenso.Rtf.Interpreter;
 | |
| using Itenso.Rtf.Support;
 | |
| using Volian.Controls.Library;
 | |
| using VEPROMS.CSLA.Library;
 | |
| using Volian.Base.Library;
 | |
| using System.Text.RegularExpressions;
 | |
| 
 | |
| namespace Volian.Print.Library
 | |
| {
 | |
| 	public abstract partial class vlnPrintObject
 | |
| 	{
 | |
| 		// Used for debugging:
 | |
| 		private static int _UniqueDebugId = 0;
 | |
| 		public static int UniqueDebugId
 | |
| 		{
 | |
| 			get { return _UniqueDebugId++; }
 | |
| 			set { _UniqueDebugId = value; }
 | |
| 		}
 | |
| 		private int _DebugId = UniqueDebugId;
 | |
| 		public int DebugId
 | |
| 		{
 | |
| 			get { return _DebugId; }
 | |
| 			set { _DebugId = value; }
 | |
| 		}
 | |
| 
 | |
| 		protected static float _WidthAdjust = 1;  // 1 Point - adjusted to match 16-bit line wrapping. For editting it's 3.
 | |
| 		protected static float _WidthAdjustBox = 6;
 | |
| 		private static float _SixLinesPerInch = 12;   // twips
 | |
| 		public static float SixLinesPerInch
 | |
| 		{
 | |
| 			get { return vlnPrintObject._SixLinesPerInch; }
 | |
| 			set { vlnPrintObject._SixLinesPerInch = value; }
 | |
| 		}
 | |
| 		protected static float _SevenLinesPerInch = 10.1F;//72F / 7F;
 | |
| 
 | |
| 		protected float _XOffset;
 | |
| 		public float XOffset
 | |
| 		{
 | |
| 			get { return _XOffset; }
 | |
| 			set {_XOffset = value; }
 | |
| 		}
 | |
| 		protected float _YOffset;
 | |
| 		public float YOffset
 | |
| 		{
 | |
| 			get { return _YOffset; }
 | |
| 			set 
 | |
| 			{
 | |
| 				_YOffset = value; 
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		protected vlnParagraph _MyParent;
 | |
| 		public vlnParagraph MyParent
 | |
| 		{
 | |
| 			get { return _MyParent; }
 | |
| 			set 
 | |
| 			{
 | |
| 				_MyParent = value;
 | |
| 				if (_MyParent != null)
 | |
| 				{
 | |
| 
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		private bool _HasIndent = false;
 | |
| 		public bool HasIndent
 | |
| 		{
 | |
| 			get { return _HasIndent; }
 | |
| 			set { _HasIndent = value; }
 | |
| 		}
 | |
| 		private bool _IsCompressed = false;
 | |
| 		public bool IsCompressed
 | |
| 		{
 | |
| 			get { return _IsCompressed; }
 | |
| 			set { _IsCompressed = value; }
 | |
| 		}
 | |
| 		private string _ImageText;  // ro definition, value part of #Link in case of image/figure
 | |
| 		public string ImageText
 | |
| 		{
 | |
| 			get { return _ImageText; }
 | |
| 			set { _ImageText = value; }
 | |
| 		}
 | |
| 		protected string _Rtf;   // may become iTextSharp paragraph
 | |
| 		public virtual string Rtf
 | |
| 		{
 | |
| 			get { return _Rtf; }
 | |
| 			set {	_Rtf = value; }
 | |
| 		}
 | |
| 		public class VlnSplitCharacter : ISplitCharacter
 | |
| 		{
 | |
| 			public bool IsSplitCharacter(int start, int current, int end, char[] cc, PdfChunk[] ck)
 | |
| 			{
 | |
| 				return (cc[current] == ' ');
 | |
| 			}
 | |
| 			public bool IsSplitCharacter(char c)
 | |
| 			{
 | |
| 				return (c == ' ');
 | |
| 			}
 | |
| 		}
 | |
| 		public static VlnSplitCharacter mySplitter = new VlnSplitCharacter();
 | |
| 		// B2018-034 Attributes were being lost when the IsCompressed flag was true.  
 | |
| 		// The following variable was changed to a public so that it could be used
 | |
| 		// for setting PDF Links without creating IParagraph when IsCompressed was true.
 | |
| 		public iTextSharp.text.Paragraph _IParagraph;
 | |
| 		public iTextSharp.text.Paragraph IParagraph
 | |
| 		{
 | |
| 			get 
 | |
| 			{
 | |
| 				// If the paragraph iscompressed, it may have been created as not compressed since compression
 | |
| 				// is not set when paragraph is initially created, it is set during pagination tests.
 | |
| 				//if (_IParagraph == null || IsCompressed)
 | |
| 				if (Rtf != null && (_IParagraph == null || IsCompressed)) 
 | |
| 				{
 | |
| 					int profileDepth = ProfileTimer.Push(">>>> VlnPrintObject.IParagraph");
 | |
| 					string myRtf = Rtf;
 | |
| 					// Add a printable character (hard space) between multiple newlines
 | |
| 					// this asssures that the blank line will be printed
 | |
| 					if (myRtf.Contains(@"\line \line "))
 | |
| 					myRtf=	 myRtf.Replace(@"\line \line ", @"\line \u160? \line ");
 | |
| 					if (myRtf.Contains(@"\pard\line  "))  // Bug fix:  B2016-145 for VC.Summer End Message
 | |
| 						myRtf = myRtf.Replace(@"\pard\line  ", @"\par  ");
 | |
| 					// B2018-034 Attributes were being lost when the IsCompressed flag was true.  
 | |
| 					// CopyAttributesToNewIParagraph retains any attribute which have been set
 | |
| 					Paragraph oldParagraph = _IParagraph;
 | |
| 					_IParagraph = RtfToParagraph(myRtf, HasIndent, MyPageHelper.MyPromsPrinter.SaveLinks);
 | |
| 					// B2018-034 Attributes were being lost when the IsCompressed flag was true.  
 | |
| 					// CopyAttributesToNewIParagraph retains any attribute which have been set
 | |
| 					CopyAttributesToNewIParagraph(oldParagraph, _IParagraph);
 | |
| 					ProfileTimer.Pop(profileDepth);
 | |
| 				}
 | |
| 				return _IParagraph; 
 | |
| 			}
 | |
| 			set { _IParagraph = value; }
 | |
| 		}
 | |
| 		// B2018-034 Attributes were being lost when the IsCompressed flag was true.  
 | |
| 		// CopyAttributesToNewIParagraph retains any attribute which have been set
 | |
| 		private void CopyAttributesToNewIParagraph(Paragraph oldParagraph, Paragraph newParagraph)
 | |
| 		{
 | |
| 			if (oldParagraph == null) return;
 | |
| 			if (oldParagraph.Chunks.Count != newParagraph.Chunks.Count) return;
 | |
| 			for (int i = 0; i < oldParagraph.Chunks.Count; i++)
 | |
| 			{
 | |
| 				System.Collections.Hashtable oldTable = (oldParagraph.Chunks[i] as Chunk).Attributes;
 | |
| 				System.Collections.Hashtable newTable = (newParagraph.Chunks[i] as Chunk).Attributes;
 | |
| 				if (oldTable.Count == newTable.Count) return;
 | |
| 				foreach (System.Collections.DictionaryEntry de in oldTable)
 | |
| 					if (!newTable.ContainsKey(de.Key))
 | |
| 						newTable.Add(de.Key, de.Value);
 | |
| 			}
 | |
| 		}
 | |
| 		private float _Width;
 | |
| 		public float Width
 | |
| 		{
 | |
| 			get { return _Width; }
 | |
| 			set
 | |
| 			{
 | |
| 				// Debug B2018-146 - Check to see what is setting the width
 | |
| 				//if (this is vlnParagraph && (this as vlnParagraph).MyItemInfo.InList(1986333, 1986334, 1986335))
 | |
| 				//	Console.WriteLine("here");
 | |
| 				//if (this is vlnParagraph)
 | |
| 					//if ((this as vlnParagraph).MyItemInfo.InList(1986333))
 | |
| 						//Console.WriteLine("{0} Width {1} Right {2} Right Margin {3}", (this as vlnParagraph).MyItemInfo.ItemID, value,
 | |
| 							//value + this.XOffset, (this as vlnParagraph).MyItemInfo.MyDocStyle.Layout.PageWidth -
 | |
| 							//(this as vlnParagraph).MyItemInfo.MyDocStyle.Layout.LeftMargin);
 | |
| 				_Width = value;
 | |
| 			}
 | |
| 		}
 | |
| 		protected float _Height;
 | |
| 		public virtual float Height
 | |
| 		{
 | |
| 			get 
 | |
| 			{
 | |
| 				int profileDepth = ProfileTimer.Push(">>>> vlnPrintObject.Height");
 | |
| 				if (_Height == 0)
 | |
| 					_Height = GetParagraphHeight(MyContentByte, IParagraph, string.Empty, Width);
 | |
| 				ProfileTimer.Pop(profileDepth);
 | |
| 				return _Height; 
 | |
| 			}
 | |
| 			set { _Height = value; }
 | |
| 		}
 | |
| 		public float GetParagraphHeight(PdfContentByte cb, Paragraph iParagraph, string suffix, float width)
 | |
| 		{
 | |
| 			return GetParagraphHeight(cb, iParagraph, suffix, width, true);
 | |
| 		}
 | |
| 		public float GetParagraphHeight(PdfContentByte cb, Paragraph iParagraph, string suffix, float width, bool throwException)
 | |
| 		{
 | |
| 			float heightAll = GetHeight(cb, iParagraph, suffix, width, throwException);
 | |
| 			return heightAll;
 | |
| 		}
 | |
| 		private static void RestoreLastCharacter(Paragraph iParagraph, Chunk chk)
 | |
| 		{
 | |
| 			iParagraph.RemoveAt(iParagraph.Count - 1);
 | |
| 			iParagraph.Add(chk);
 | |
| 		}
 | |
| 		private static Chunk RemoveLastCharacter(Paragraph iParagraph)
 | |
| 		{
 | |
| 			if (iParagraph.Count == 0)
 | |
| 				return null;
 | |
| 			object obj = iParagraph[iParagraph.Count-1];
 | |
| 			Chunk chk = obj as Chunk;
 | |
| 			if (chk == null)
 | |
| 				return null;
 | |
| 			string s = chk.Content;
 | |
| 			if (s.Length > 1 || iParagraph.Count > 1) // don't remove last character if it's the only one
 | |
| 			{
 | |
| 				iParagraph.RemoveAt(iParagraph.Count - 1);
 | |
| 				if (s.Length > 0)
 | |
| 				{
 | |
| 					if (s == "\xA0") // If this is a space at the end put it back
 | |
| 					{
 | |
| 						iParagraph.Add(chk);
 | |
| 						return null;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 				s = s.Substring(0, s.Length - 1);
 | |
| 				iParagraph.Add(new Chunk(s, chk.Font));
 | |
| 			}
 | |
| 				}
 | |
| 			}
 | |
| 			return chk;
 | |
| 		}
 | |
| 		public static float GetHeight(PdfContentByte cb, Paragraph iParagraph, string suffix, float width, bool throwException)
 | |
| 		{
 | |
| 			ColumnText myColumnText = new ColumnText(cb);
 | |
| 			float pgHeight = cb.PdfDocument.PageSize.Height; // C2020-002 paper size is now set in the format files
 | |
| 			myColumnText.SetSimpleColumn(0, pgHeight, width, 0); // Bottom margin
 | |
| 			if (suffix != string.Empty)
 | |
| 			{
 | |
| 				Chunk chk = iParagraph.Chunks[0] as Chunk;
 | |
| 				iParagraph.Add(new Chunk(suffix, chk.Font));
 | |
| 				myColumnText.AddText(iParagraph);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				myColumnText.AddElement(iParagraph);
 | |
| 			}
 | |
| 			//myColumnText.UseAscender = true;// Adjusts to the top of the text box.
 | |
| 			int status = myColumnText.Go(true); // Check to see if it will fit on the page.
 | |
| 			if (ColumnText.HasMoreText(status) && throwException)
 | |
| 			{
 | |
| 				// B2016-142:  If the paragraph won't fit on page and indenting is on, remove
 | |
| 				// indenting & try again:
 | |
| 				if (iParagraph.FirstLineIndent < 0)
 | |
| 				{
 | |
| 					iParagraph.FirstLineIndent = 0;
 | |
| 					iParagraph.IndentationLeft = 0;
 | |
| 					return GetHeight(cb, iParagraph, suffix, width, throwException);
 | |
| 				}
 | |
| 				//throw (new Exception("Paragraph longer than a page"));
 | |
| 				Console.WriteLine("Paragraph longer than a page");
 | |
| 			}
 | |
| 			return pgHeight - myColumnText.YLine; // This gives the height of the Paragraph // C2020-002 paper size is now set in the format files
 | |
| 		}
 | |
| 		public float GetTableWidth(PdfContentByte cb, Paragraph iParagraph, float? maxWidth)
 | |
| 		{
 | |
| 			int iWidth = (int)(maxWidth ?? 72 * 8.5F);
 | |
| 			float h = GetParagraphHeight(cb, iParagraph, string.Empty, iWidth);
 | |
| 			int iWidthMax = iWidth;		// maximum width in Characters
 | |
| 			int iDelta = iWidth / 2;
 | |
| 			iWidth = iWidth / 2;
 | |
| 			while (iDelta > 0)
 | |
| 			{
 | |
| 				float h2 = GetParagraphHeight(cb, iParagraph, string.Empty, iWidth,false);
 | |
| 				iDelta = iDelta / 2;
 | |
| 				if (h2 == h) iWidthMax = iWidth;
 | |
| 				iWidth +=  (h2>h ? 1: -1) * iDelta;
 | |
| 			}
 | |
| 			return (float) iWidthMax;
 | |
| 		}
 | |
| 		private PdfContentByte _MyContentByte;
 | |
| 		public PdfContentByte MyContentByte
 | |
| 		{
 | |
| 			get { return _MyContentByte; }
 | |
| 			set { _MyContentByte = value; }
 | |
| 		}
 | |
| 		private VlnSvgPageHelper _MyPageHelper;
 | |
| 		public VlnSvgPageHelper MyPageHelper
 | |
| 		{
 | |
| 			get 
 | |
| 			{
 | |
| 				if(_MyPageHelper == null)
 | |
| 					_MyPageHelper = MyContentByte.PdfWriter.PageEvent as VlnSvgPageHelper;
 | |
| 				return _MyPageHelper; 
 | |
| 			}
 | |
| 			set { _MyPageHelper = value; }
 | |
| 		}
 | |
| 		public vlnPrintObject()
 | |
| 		{
 | |
| 		}
 | |
| 		/// <summary>
 | |
| 		/// No conversion necessary: twips -> twips
 | |
| 		/// </summary>
 | |
| 		/// <param name="value"></param>
 | |
| 		/// <returns></returns>
 | |
| 		public static int ToInt(int value)
 | |
| 		{
 | |
| 			return value;
 | |
| 		}
 | |
| 		/// <summary>
 | |
| 		/// No conversion necessary: int? twips -> int twips
 | |
| 		/// </summary>
 | |
| 		/// <param name="value"></param>
 | |
| 		/// <returns></returns>
 | |
| 		public static int ToInt(int? value)
 | |
| 		{
 | |
| 			return ToInt((int)value);
 | |
| 		}
 | |
| 		/// <summary>
 | |
| 		/// No conversion necessary: string twips -> int twips
 | |
| 		/// </summary>
 | |
| 		/// <param name="value"></param>
 | |
| 		/// <returns></returns>
 | |
| 		public static int ToInt(string value)
 | |
| 		{
 | |
| 			return ToInt((int)Convert.ToSingle(value));
 | |
| 		}
 | |
| 		/// <summary>
 | |
| 		/// No conversion necessary: value from a list in a string, twips -> int twips
 | |
| 		/// </summary>
 | |
| 		/// <param name="value"></param>
 | |
| 		/// <returns></returns>
 | |
| 		public static int ToInt(string value, int i)
 | |
| 		{
 | |
| 			string s = (value.Contains(",")) ? value.Split(",".ToCharArray())[i] : value;
 | |
| 			return ToInt(s);
 | |
| 		}
 | |
| 		public static string GetRtf(string text, VE_Font vFont)
 | |
| 		{
 | |
| 			StringBuilder rtfSB = new StringBuilder();
 | |
| 			//DisplayText vlntxt = new DisplayText(text.TrimStart(" ".ToCharArray()), vFont, false);
 | |
| 			DisplayText vlntxt = new DisplayText(text, vFont, false);
 | |
| 			//rtfSB.Append(AddFontTable(vlntxt.TextFont.WindowsFont));
 | |
| 			//rtfSB.Append(AddFontTable(vFont.WindowsFont));
 | |
| 			rtfSB.Append(AddFontTable(vFont));
 | |
| 			rtfSB.Append(vlntxt.StartText);
 | |
| 			rtfSB.Append("}");
 | |
| 			return rtfSB.ToString();
 | |
| 		}
 | |
| 		public static string AddFontTable(VE_Font vfont)
 | |
| 		{
 | |
| 			System.Drawing.Font font = vfont.WindowsFont;
 | |
| 			StringBuilder rtfSB = new StringBuilder();
 | |
| 			StringBuilder sbbeg = new StringBuilder();
 | |
| 			StringBuilder sbend = new StringBuilder();
 | |
| 			if ((vfont.Style & E_Style.Bold) > 0)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\b");
 | |
| 				sbend.Append(@"\b0");
 | |
| 			}
 | |
| 			if ((vfont.Style & E_Style.Underline) > 0)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\ul");
 | |
| 				sbend.Insert(0, @"\ulnone");
 | |
| 			}
 | |
| 			if ((vfont.Style & E_Style.Italics) > 0)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\i");
 | |
| 				sbend.Insert(0, @"\i0");
 | |
| 			}
 | |
| 			rtfSB.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset2 " + font.FontFamily.Name + @";}"); //}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}}";
 | |
| 			if (!FontIsFixed(font))
 | |
|                 rtfSB.Append(@"{\f1\fnil\fcharset0 " + Volian.Base.Library.vlnFont.ProportionalSymbolFont + @";}}{\colortbl ;\red255\green0\blue0;}"); // C2017-036 get best available proportional font for symbols
 | |
| 			else
 | |
| 				rtfSB.Append(@"{\f1\fnil\fcharset0 VESymbFix;}}{\colortbl ;\red255\green0\blue0;}");
 | |
| 			rtfSB.Append("\r\n");
 | |
| 			// use styles to construct rtf commands to insert into next line (where \b, etc is)
 | |
| 			rtfSB.Append(@"\viewkind4\uc1\pard\sl-240\slmult0" + sbbeg.ToString() + @"\fs" + Convert.ToInt32(font.SizeInPoints * 2).ToString() + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}";
 | |
| 			return rtfSB.ToString();
 | |
| 		}
 | |
| 		public static string AddFontTable(System.Drawing.Font font)
 | |
| 		{
 | |
| 			StringBuilder rtfSB = new StringBuilder();
 | |
| 			StringBuilder sbbeg = new StringBuilder();
 | |
| 			StringBuilder sbend = new StringBuilder();
 | |
| 			if (font.Bold)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\b");
 | |
| 				sbend.Append(@"\b0");
 | |
| 			}
 | |
| 			if (font.Underline)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\ul");
 | |
| 				sbend.Insert(0, @"\ulnone");
 | |
| 			}
 | |
| 			if (font.Italic)
 | |
| 			{
 | |
| 				sbbeg.Append(@"\i");
 | |
| 				sbend.Insert(0, @"\i0");
 | |
| 			}
 | |
| 			rtfSB.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset2 " + font.FontFamily.Name + @";}"); //}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}}";
 | |
| 			if (!FontIsFixed(font))
 | |
|                 rtfSB.Append(@"{\f1\fnil\fcharset0 " + Volian.Base.Library.vlnFont.ProportionalSymbolFont + @";}}{\colortbl ;\red255\green0\blue0;}"); // C2017-036 get best available proportional font for symbols
 | |
| 			else
 | |
| 				rtfSB.Append(@"{\f1\fnil\fcharset0 VESymbFix;}}{\colortbl ;\red255\green0\blue0;}");
 | |
| 			rtfSB.Append("\r\n");
 | |
| 			// use styles to construct rtf commands to insert into next line (where \b, etc is)
 | |
| 			rtfSB.Append(@"\viewkind4\uc1\pard\sl-240\slmult0" + sbbeg.ToString() + @"\fs" + Convert.ToInt32(font.SizeInPoints * 2).ToString() + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}";
 | |
| 			return rtfSB.ToString();
 | |
| 		}
 | |
| 		private static bool FontIsFixed(System.Drawing.Font font)
 | |
| 		{
 | |
| 			iTextSharp.text.Font iFont = Volian.Svg.Library.VolianPdf.GetFont(font);
 | |
| 			float fW = iFont.BaseFont.GetWidthPointKerned("W", 12);
 | |
| 			float fE = iFont.BaseFont.GetWidthPointKerned("!", 12);
 | |
| 			return fW == fE;
 | |
| 		}
 | |
| 		public static iTextSharp.text.Paragraph RtfToParagraph(string rtf)
 | |
| 		{
 | |
| 			return RtfToParagraph(rtf, false, false);
 | |
| 		}
 | |
| 		public static iTextSharp.text.Paragraph RtfToParagraph(string rtf, bool hasIndent, bool doPdfLinks)
 | |
| 		{
 | |
| 			if (hasIndent)
 | |
| 			{
 | |
| 				hasIndent = rtf.Contains("\x05");
 | |
| 				if (hasIndent && rtf.Contains(@"\par \par")) rtf = rtf.Replace(@"\par \par", @"\par \u160? \par");
 | |
| 				if (hasIndent && rtf.Contains(@"\par\par")) rtf = rtf.Replace(@"\par\par", @"\par \u160? \par");
 | |
| 			}
 | |
| 
 | |
| 			IRtfDocument rtfDoc = RtfInterpreterTool.BuildDoc(rtf);
 | |
| 			Rtf2iTextSharp rtf2IText = new Rtf2iTextSharp(rtfDoc);
 | |
| 			rtf2IText.DoPdfLinks = doPdfLinks;
 | |
| 			rtf2IText.HasIndent = hasIndent;
 | |
| 			iTextSharp.text.Paragraph para = rtf2IText.Convert();
 | |
| 			para.SetLeading(_SixLinesPerInch, 0);
 | |
| 			if (rtf.Contains("\x05"))   // note that this is for existing customer data as of August 2015.
 | |
| 			{
 | |
| 				// if there is a hanging indent, the iTextSharp paragraph properties must be set
 | |
| 				// to print the indent.  Replace the indent 'token' with a non-used symbol, this will
 | |
| 				// create a chunk with that symbol.  Then loop through all of the chunks until we find
 | |
| 				// this symbol, adding up the widths to that point.  This width is the value that
 | |
| 				// needs to be used to set the indent.
 | |
| 				// Notes:
 | |
| 				//	A hard return will reset the chkW (indent width) back to zero.
 | |
| 				//  We jump out of the processing loop after the first indent token is found and ignor any other ones
 | |
| 				float chkW = CalculateHangingIndent(rtf);
 | |
| 				para.IndentationLeft = chkW;
 | |
| 				para.FirstLineIndent = -chkW;
 | |
| 			}
 | |
| 			Match match = Regex.Match(rtf, @"\\fi([-0-9]*) ?\\li([0-9]*)");
 | |
| 			if (match.Success)
 | |
| 			{
 | |
| 				float fi = float.Parse(FixNumber(match.Groups[1].Value)) / 20;
 | |
| 				float li = float.Parse(FixNumber(match.Groups[2].Value)) / 20;
 | |
| 				// if there is a hanging indent, the iTextSharp paragraph properties must be set
 | |
| 				// to print the indent. 
 | |
| 				para.IndentationLeft = li;
 | |
| 				para.FirstLineIndent = fi;
 | |
| 			}
 | |
| 			// Change the chunks to only split on spaces rather than spaces and hyphens
 | |
| 			foreach (object obj in para)//Fix the code to check for chunks before assuming chunks
 | |
| 			{
 | |
| 				Chunk chk = obj as Chunk;
 | |
| 				if (chk != null && (chk.Attributes==null || !chk.Attributes.ContainsKey("NoSplit")))
 | |
| 				{
 | |
| 					if (chk.Attributes == null) chk.Attributes = new System.Collections.Hashtable();
 | |
| 					chk.SetSplitCharacter(mySplitter);
 | |
| 					chk.Attributes.Add("NoSplit", false);
 | |
| 				}
 | |
| 			}
 | |
| 			return para;
 | |
| 		}
 | |
| 		private static string FixNumber(string num)
 | |
| 		{
 | |
| 			if (num == "") return ("0");
 | |
| 			return num;
 | |
| 		}
 | |
| 		public static float CalculateHangingIndent(string rtf)
 | |
| 		{
 | |
| 			float chkW=0;
 | |
| 			IRtfDocument rtfDoc2 = RtfInterpreterTool.BuildDoc(rtf.Replace("\x05", @"\f1 \u9999? \f0 "));
 | |
| 			Rtf2iTextSharp rtf2IText2 = new Rtf2iTextSharp(rtfDoc2);
 | |
| 			iTextSharp.text.Paragraph para2 = rtf2IText2.Convert();
 | |
| 			foreach (Chunk chk in para2.Chunks)
 | |
| 			{
 | |
| 				if (chk.Content[0] == 9999) break;
 | |
| 				if (chk.Content.Contains("\u270f"))
 | |
| 				{
 | |
| 					int i = chk.Content.IndexOf('\u270F');
 | |
| 					int n = chk.Content.Length;
 | |
| 					chkW += chk.GetWidthPoint() * i / (n - i);
 | |
| 					break;
 | |
| 				}
 | |
| 				if (chk.Content.Contains("\n")) chkW = 0; //hard return - reset chkW (indent start)
 | |
| 				chkW += chk.GetWidthPoint();
 | |
| 			}
 | |
| 			return chkW;
 | |
| 		}
 | |
| 		public abstract float ToPdf(PdfContentByte cb, float yPageStart, ref float yTopMargin, ref float yBottomMargin);
 | |
| 		protected float CalculateYOffset(float yPageStart, float yTopMargin)
 | |
| 		{
 | |
| 			float yLocation = yPageStart - YOffset;
 | |
| 			if (MyPageHelper.YMultiplier != 1)
 | |
| 			{
 | |
| 				yLocation = -1 + yTopMargin - (yTopMargin - yLocation) * MyPageHelper.YMultiplier;
 | |
| 				if (Rtf != null)
 | |
| 					IParagraph.Leading = _SevenLinesPerInch;
 | |
| 			}
 | |
| 			return yLocation;
 | |
| 		}
 | |
| 		protected float CalculateYLocation(float yLocation, float yTopMargin)
 | |
| 		{
 | |
| 			if (MyPageHelper.YMultiplier != 1)
 | |
| 				yLocation = -1 + yTopMargin - (yTopMargin - yLocation) * MyPageHelper.YMultiplier;
 | |
| 			return yLocation;
 | |
| 		}
 | |
| 		public void DebugPdf(PdfContentByte cb, float left, float top)
 | |
| 		{
 | |
| 			VlnSvgPageHelper _MyPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper;
 | |
| 			PdfLayer debugLayer = _MyPageHelper == null ? null : _MyPageHelper.DebugLayer;
 | |
| 			if (debugLayer == null) return;
 | |
| 			cb.SaveState();
 | |
| 			cb.BeginLayer(debugLayer);
 | |
| 			ColumnText ct = new ColumnText(cb);
 | |
| 			ct.SetSimpleColumn(left, top, left+50, top - 50);
 | |
| 			iTextSharp.text.Font font = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 2);
 | |
| 			Chunk chk = new Chunk(DebugId.ToString(), font);
 | |
| 			Phrase ph = new Phrase(chk);
 | |
| 			ct.AddElement(ph);
 | |
| 			cb.SetColorFill(new iTextSharp.text.Color(PrintOverride.OverrideDebugColor(System.Drawing.Color.Gray)));
 | |
| 			ct.Go();
 | |
| 			cb.EndLayer();
 | |
| 			cb.RestoreState();
 | |
| 		}
 | |
| 		public virtual float YBottom
 | |
| 		{	get { return YOffset + Height;}	}
 | |
| 	}
 | |
| 	public partial class vlnPrintObjects : List<vlnPrintObject>
 | |
| 	{
 | |
| 		public float ToPdf(PdfContentByte cb, float yPageStart, ref float yTopMargin, ref float yBottomMargin)
 | |
| 		{
 | |
| 			foreach (vlnPrintObject part in this)
 | |
| 			{
 | |
| 				// F2018-013 Replace Symbols as necesasary on tabs (consistent bullets)
 | |
| 				if(part.Rtf != null) part.Rtf = vlnParagraph.FixRTFToPrint(part.MyParent.MyItemInfo, part.Rtf);
 | |
| 				yPageStart = part.ToPdf(cb, yPageStart, ref yTopMargin, ref yBottomMargin);
 | |
| 			}
 | |
| 			return yPageStart;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public enum PartLocation : int
 | |
| 	{
 | |
| 		None = 0,			// Non-printable
 | |
| 		Below = 1,			// RNO Separator
 | |
| 		Above = 2,			// Tab Headers, Separator?
 | |
| 		Right = 3,			// Change Bars
 | |
| 		Left = 4,			// Tabs, Checkoffs? (maybe part of tab)
 | |
| 		Container = 5		// Box
 | |
| 	};
 | |
| 	public enum ChildLocation : int
 | |
| 	{
 | |
| 		None = 0,
 | |
| 		Below = 1,
 | |
| 		Above = 2,
 | |
| 		Right = 3,			// RNO
 | |
| 		Left = 4
 | |
| 	}
 | |
| 	
 | |
| }
 |