using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Text.RegularExpressions; 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; namespace Volian.Print.Library { public partial class vlnParagraphs : List { private vlnParagraph _Parent; public vlnParagraph Parent { get { return _Parent; } set { _Parent = value; } } public vlnParagraphs(vlnParagraph parent) { _Parent = parent; } public float Add(PdfContentByte cb, ItemInfoList itemInfoList, float xoff, float yoff, float yoffRight, int rnoLevel, int maxRNO, FormatInfo formatInfo) { int? bxIndex = null; vlnBox box = null; float yTop = yoff; foreach (ItemInfo childItemInfo in itemInfoList) { int? bxIndx = childItemInfo.FormatStepData.StepLayoutData.STBoxindex; if (bxIndex != bxIndx || childItemInfo.FormatStepData.BoxIt) { if (childItemInfo.FormatStepData.BoxIt) // this is a boxed HLS { box = new vlnBox(); box.MyBox = new Box(); box.DefBox = vlnBox.BoxThin; StepSectionLayoutData ssld = formatInfo.MyStepSectionLayoutData; int colR = int.Parse(formatInfo.MyStepSectionLayoutData.ColRTable.Split(",".ToCharArray())[childItemInfo.ColumnMode]); int widS = vlnPrintObject.ToInt(formatInfo.MyStepSectionLayoutData.WidSTablePrint, maxRNO); box.DefEnd = (float)(ssld.ColS + colR + widS + (60/4.8)); box.YOffset = yoff - .75F * vlnPrintObject.SixLinesPerInch; } else if (bxIndex == null) // First boxed step { box = new vlnBox(); box.MyBox = formatInfo.PlantFormat.FormatData.BoxList[(int)bxIndx]; box.YOffset = yoff; yoff += 2 * vlnPrintObject.SixLinesPerInch; } else // Change Box Style { if (box != null) box.Height = yoff - box.YOffset; // new height, with children box = new vlnBox(); box.MyBox = formatInfo.PlantFormat.FormatData.BoxList[(int)bxIndx]; box.YOffset = yoff; yoff += 2 * vlnPrintObject.SixLinesPerInch; } bxIndex = bxIndx; } if (childItemInfo is SectionInfo) formatInfo = (childItemInfo as SectionInfo).LocalFormat ?? formatInfo; if (rnoLevel < maxRNO && childItemInfo.RNOs != null) yoff = Math.Max(yoff, yoffRight); vlnParagraph para = new vlnParagraph(Parent, cb, childItemInfo, xoff, yoff, rnoLevel, maxRNO, formatInfo); if (box != null && box.MyParent == null) { box.MyParent = para; para.PartsContainer.Add(box); } Add(para); // para.YBottomMost will have y for bottom of any substeps that are also enclosed in the box. yoff = para.YBottomMost; if (childItemInfo.FormatStepData.BoxIt) { box.Height = yoff - box.YOffset - (1.1F * vlnPrintObject.SixLinesPerInch); box = null; // if doing boxed steps, only do single sibling at a time. } } if (box != null) { if (box != null) box.Height = yoff - box.YOffset; // new height, with children yoff += 2 * vlnPrintObject.SixLinesPerInch; } return yoff; } public float ToPdf(PdfContentByte cb, float yPageStart, float yTopMargin, float yBottomMargin) { foreach (vlnParagraph child in this) { yPageStart = child.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); } return yPageStart; } } public partial class vlnParagraph : vlnPrintObject { /// /// This variable is used to match 16 bit pagaination /// private bool _Match16BitPagination = false; public float ParagraphToPdf(PdfContentByte cb, float yPageStart, float yTopMargin, float yBottomMargin) { if (Processed) return yPageStart; Processed = true; if (_PartsAbove != null && _PartsAbove.Count > 0) yPageStart = PartsAbove.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); float yLocation = CalculateYOffset(yPageStart, yTopMargin); if (MyItemInfo.HasChangeBar()) MyPageHelper.AddChangeBar(DoChangeBar(cb, MyItemInfo, MyPageHelper, XOffset, yLocation, MyPageHelper.MaxRNO, MyItemInfo.ActiveFormat), cbMess); float retval = yLocation; if (MyItemInfo.IsFigure) { yLocation -= (SixLinesPerInch * MyPageHelper.YMultiplier); if (ImageText != null) retval = DrawFigure(cb, yBottomMargin, yLocation); else retval = DrawText(cb, ref yPageStart, yTopMargin, yBottomMargin, ref yLocation); } else if (!MyItemInfo.IsStepSection) // Don't ouput the Step Section title { retval = DrawText(cb, ref yPageStart, yTopMargin, yBottomMargin, ref yLocation); if (MyItemInfo.IsHigh) { MyPageHelper.VlnDestinations.Add(MyItemInfo.MyTab.CleanText + " " + MyItemInfo.DisplayText, new PdfDestination(PdfDestination.FITBH,yLocation+YVeryTop-YTopMost+SixLinesPerInch)); } } //Height = yLocation - retval; if (_PartsLeft != null && _PartsLeft.Count > 0) yPageStart = PartsLeft.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); if (_PartsRight != null && _PartsRight.Count > 0) yPageStart = PartsRight.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); if (_PartsBelow != null && _PartsBelow.Count > 0) yPageStart = PartsBelow.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); if (_PartsContainer != null && _PartsContainer.Count > 0) yPageStart = PartsContainer.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); return yPageStart; } private float DrawText(PdfContentByte cb, ref float yPageStart, float yTopMargin, float yBottomMargin, ref float yLocation) { if (_TextDebug) Console.WriteLine("{0},{1},'{2}','<>'", MyItemInfo.ItemID, MyItemInfo.DBSequence, FormattedText); //Console.WriteLine("{0},{1},'{2}','<>'", MyItemInfo.ItemID, MyItemInfo.DBSequence, IParagraph.Content); float retval = yLocation; if (MyItemInfo.FormatStepData.CenterOneLineOnly && MyItemInfo.MyPrevious == null && MyItemInfo.NextItem == null && Height<(1.01F*IParagraph.Leading)) IParagraph.Alignment = Element.ALIGN_CENTER; retval = Rtf2Pdf.TextAt(cb, IParagraph, XOffset, yLocation, Width, 100, DebugText, yBottomMargin); if (retval == 0) // problem occurred - paragraph was not able to be printed on page { // pagination logic needs to be fixed. cb.PdfDocument.NewPage(); yPageStart = yTopMargin + YVeryTop; yLocation = yPageStart - YOffset; //MyItemInfo.ItemID, YSize, yPageSize, yLocation if(_PaginationDebug) Console.WriteLine("-1,'Yes','Forced Pagination',{0},{1},,{3},{4}", MyItemInfo.ItemID, YSize, 0, yLocation, MyItemInfo.DBSequence); retval = Rtf2Pdf.TextAt(cb, IParagraph, XOffset, yLocation, Width, 100, DebugText, yBottomMargin); } return retval; } private static List myAttributes =new List(); private static void AddAttribute(string attr) { if (myAttributes.Contains(attr)) return; //Console.WriteLine("Attribute = \"{0}\"", attr); myAttributes.Add(attr); } private void CheckAttributes(System.Collections.Hashtable attributes) { foreach (string attr in attributes.Keys) { AddAttribute(attr); } } private string FormattedText { get { bool subscript = false; //if (_MyItemInfo.ItemID == 467) // Console.Write(""); StringBuilder sb = new StringBuilder(); //if (IParagraph.Chunks.Count > 1) // Console.WriteLine("{0} Chunks", IParagraph.Chunks.Count); foreach (Chunk chk in IParagraph.Chunks) { string prefix = ""; string suffix = ""; CheckAttributes(chk.Attributes); if (chk.Font.BaseFont != null && chk.Font.BaseFont.PostscriptFontName.ToUpper().Contains("BOLD")) { prefix += "\xD5"; suffix = "\xD6" + suffix; } if (chk.Attributes.ContainsKey("SUBSUPSCRIPT")) { float sup = (float)(chk.Attributes["SUBSUPSCRIPT"]); if (sup > 0) { prefix += "\xA6"; suffix = "\xD1" + suffix; } else if (sup < 0) { prefix += "\xD1"; suffix = "\xA6" + suffix; } } if (chk.Attributes.ContainsKey("UNDERLINE")) { prefix += "\x16"; suffix = "\x16" + suffix; ; } sb.Append(prefix + chk.Content + suffix); } string retval = sb.ToString(); retval = retval.Replace("\xD1\xA6", "");// Remove Multiple Superscript commands in a row retval = retval.Replace("\xA6\xD1", "");// Remove Multiple Superscript commands in a row retval = retval.Replace("\xD6\xD5", ""); retval = retval.Replace("\xD6\x16\xD5", "\x16"); return retval; } } private bool _PaginationDebug = false; private bool _TextDebug = true; // false; private float DrawFigure(PdfContentByte cb, float yBottomMargin, float yLocation) { float retval = yLocation; if (ImageText != null) { string[] vals = ImageText.Split("\n".ToCharArray()); ProcedureInfo proc = MyItemInfo.MyProcedure; DocVersionInfo dvi = proc.ActiveParent as DocVersionInfo; ROFstInfo rofst = dvi.DocVersionAssociations[0].MyROFst; ROImageInfo roImage = ROImageInfo.GetByROFstID_FileName(rofst.ROFstID, vals[0]); if (roImage != null) { iTextSharp.text.Image it_image = iTextSharp.text.Image.GetInstance(roImage.Content); retval = Rtf2Pdf.FigureAt(cb, it_image, XOffset + _CharsToTwips, yLocation, Width * MyPageHelper.YMultiplier, Height * MyPageHelper.YMultiplier, DebugText, yBottomMargin, !MyItemInfo.FormatStepData.Type.Contains("Borderless")); } } return retval; } private string DebugText { get { return string.Format("DebugID = {0}, ID={1} Type={2} TypeName='{3}' StepLevel={4} DBSequence={5}", DebugId, MyItemInfo.ItemID, MyItemInfo.FormatStepType, MyItemInfo.FormatStepData.Type, MyItemInfo.StepLevel, MyItemInfo.DBSequence); } } public override float ToPdf(PdfContentByte cb, float yPageStart, float yTopMargin, float yBottomMargin) { float yLocation = yPageStart - YTopMost; int paginate = Paginate(yLocation, yTopMargin, yBottomMargin); switch (paginate) { case 1: // Break on High Level Step OutputOtherPageSteps(cb, YTopMost, yPageStart, yTopMargin, yBottomMargin); cb.PdfDocument.NewPage(); yPageStart = yTopMargin + YTopMost; MyPageHelper.YMultiplier = 1; break; case 2: // Break within a Step OutputOtherPageSteps(cb, YTopMost, yPageStart, yTopMargin, yBottomMargin); DocStyle docstyle = MyItemInfo.MyDocStyle; string myMsg = docstyle.Continue.Bottom.Message; if (myMsg.IndexOf(@"%d") > -1) myMsg = myMsg.Replace(@"%d", MyItemInfo.MyHLS.MyTab.CleanText.Trim()); float msg_yLocation = 0; switch (docstyle.Continue.Bottom.Location) { case E_ContBottomLoc.EndOfText: // place continue string at end of text case E_ContBottomLoc.BtwnTextAndBottom: // place continue string between end of text & bottom of page Console.WriteLine("Not done yet"); break; case E_ContBottomLoc.BottomOfPage: // place continue message at bottom of page msg_yLocation = yBottomMargin + 2 * SixLinesPerInch; // 2 lines above bottom margin break; } MyPageHelper.BottomMessage = new vlnText(cb, this, myMsg, myMsg, docstyle.Layout.LeftMargin + XOffsetBox + docstyle.Continue.Bottom.Margin ?? 0, msg_yLocation, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font); cb.PdfDocument.NewPage(); // If there is a box, adjust the yTopMost to include it. // TODO: Why doesn't YTopMost account for the box? float yTopMost = YTopMost; //if (YVeryTop < yTopMost) Console.WriteLine("{0},{1},{2}", MyItemInfo.DBSequence, yTopMost, YVeryTop); yTopMost = Math.Min(yTopMost,YVeryTop); yPageStart = yTopMargin + yTopMost - 2 * SixLinesPerInch; myMsg = docstyle.Continue.Top.Message; if (myMsg.IndexOf(@"%d") > -1) myMsg = myMsg.Replace(@"%d", MyItemInfo.MyHLS.MyTab.CleanText.Trim()); MyPageHelper.TopMessage = new vlnText(cb, this, myMsg, myMsg, docstyle.Layout.LeftMargin + XOffsetBox + docstyle.Continue.Top.Margin ?? 0, yTopMargin + 0.1F, MyItemInfo.ActiveFormat.PlantFormat.FormatData.Font); MyPageHelper.YMultiplier = 1; break; case 3: // Break on High Level Step (SevenLinesPerInch) OutputOtherPageSteps(cb, YTopMost, yPageStart, yTopMargin, yBottomMargin); cb.PdfDocument.NewPage(); yPageStart = yTopMargin + YTopMost; MyPageHelper.YMultiplier = _SevenLinesPerInch / SixLinesPerInch; break; } yPageStart = ChildrenAbove.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); yPageStart = ChildrenLeft.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); yPageStart = ParagraphToPdf(cb, yPageStart, yTopMargin, yBottomMargin); yPageStart = ChildrenRight.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); yPageStart = ChildrenBelow.ToPdf(cb, yPageStart, yTopMargin, yBottomMargin); if (MyItemInfo.IsHigh && MyItemInfo.NextItem == null) // last hls, add the 'end' message, if there is one { DocStyle docstyle = MyItemInfo.MyDocStyle; string myMsg = (docstyle.End == null) ? null : docstyle.End.Message; if (myMsg != null) { float msg_yLocation = yBottomMargin + SixLinesPerInch; // use the 'flag' to position the message. Just implementing OHLP if (docstyle.End.Flag >= 2) { msg_yLocation = yTopMargin - (float)(docstyle.End.Flag * SixLinesPerInch); } // center it. Just implementing OHLP float wtpm = (float)docstyle.Layout.PageWidth - (float)docstyle.Layout.LeftMargin; float centerpos = XOffsetBox + (float)docstyle.Layout.LeftMargin + (wtpm - (myMsg.Length * vlnPrintObject._CharsToTwips)) / 2; MyPageHelper.BottomMessage = new vlnText(cb, this, myMsg, myMsg, centerpos, msg_yLocation, docstyle.End.Font); } } return yPageStart; } private void OutputOtherPageSteps(PdfContentByte cb, float YTopMost, float yPageStart, float yTopMargin, float yBottomMargin) { // Find any items remaining in MyPageHelper.MyParagraphs that should be printed on this page. vlnParagraphs process = new vlnParagraphs(null); foreach (vlnParagraph vPara in MyPageHelper.MyParagraphs.Values) { //if (!vPara.Processed && ((vPara.YOffset + vPara.Height) < YTopMost)) if (!vPara.Processed && ((vPara.YOffset) < YTopMost)) process.Add(vPara); } foreach (vlnParagraph vPara in process) { vPara.ParagraphToPdf(cb, yPageStart, yTopMargin, yBottomMargin); } } private void WalkStepLevel(float yTopMost) { foreach (vlnParagraph child in ChildrenAbove) child.WalkStepLevel(yTopMost); foreach (vlnParagraph child in ChildrenLeft) child.WalkStepLevel(yTopMost); ShowStepLevel(yTopMost); foreach (vlnParagraph child in ChildrenRight) child.WalkStepLevel(yTopMost); foreach (vlnParagraph child in ChildrenBelow) child.WalkStepLevel(yTopMost); } private void ShowStepLevel(float yTopMost) { ItemInfo item = MyItemInfo; ItemInfo parent = item.ActiveParent as ItemInfo; //if (para.MyItemInfo.ItemID == 205) // Console.Write(""); if (_PaginationDebug) { Console.WriteLine("'StepLevel',{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}", YVeryTop - yTopMost, YSize, YBottomMost - yTopMost, item.ItemID, item.DBSequence, item.StepLevel, item.MyContent.Type % 10000, parent.MyContent.Type % 10000, item.HasCautionOrNote ? 1 : 0, parent.Cautions == null ? 0 : 1); } } private float _YVeryTop = -1; public float YVeryTop { get { if (_YVeryTop == -1) { _YVeryTop = YTop; _YVeryTop = VeryTop(PartsAbove,_YVeryTop); _YVeryTop = VeryTop(PartsContainer,_YVeryTop); } return _YVeryTop; } } private float VeryTop(vlnPrintObjects parts, float yVeryTop) { if (parts != null) foreach (vlnPrintObject part in parts) if (part.YOffset < yVeryTop) yVeryTop = part.YOffset; return yVeryTop; } private int Paginate(float yLocation, float yTopMargin, float yBottomMargin) { float yPageSize = yTopMargin - yBottomMargin; float yWithinMargins = CalculateYLocation(yLocation, yTopMargin) - yBottomMargin - SixLinesPerInch; // if step is breaking over a number of pages, determine if the current step is the // location of a pagebreak. if (MyPageHelper.ParaBreaks.Count > 0) { if (this == MyPageHelper.ParaBreaks[0] || this.YTopMost > MyPageHelper.ParaBreaks[0].YTopMost) { MyPageHelper.ParaBreaks.RemoveAt(0); //Console.WriteLine("'PageBreak',6,'Yes','Page Break within Step',{0},{1},{2},{3}, {4},'{5}'", MyItemInfo.ItemID, YSize, 0, 0, 0, MyItemInfo.ShortPath); //Console.WriteLine("Prev = {0}", MyItemInfo.MyPrevious==null ? "''" : MyItemInfo.DBSequence); ShowPageBreak(100,"Page Break within Step","Yes",YSize, yPageSize, yWithinMargins); return 2; // break on this item within a step } return 0; // this is not an item with a break } if (MyItemInfo.IsStepSection) return 0; // Don't Paginate on a Step Section if (!MyItemInfo.IsHigh) return 0; // Don't Paginate on a Substep level bool ManualPageBreak = (MyItemInfo.MyConfig as StepConfig).Step_ManualPagebreak; float mySize = YSize * MyPageHelper.YMultiplier; if (_Match16BitPagination) mySize = YSize; float ySize7LPI = YSize + SixLinesPerInch; if (_Match16BitPagination) ySize7LPI += SixLinesPerInch; string firstStep = "No"; if (MyItemInfo.IsHigh && MyItemInfo.MyPrevious == null) firstStep = "Yes"; if (!ManualPageBreak && mySize <= yWithinMargins) // Don't Paginate if there is enough room, will fit on page { //Console.WriteLine("'PageBreak',1,'No','HLS will fit on page',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); ShowPageBreak(-1, "HLS will fit on page", firstStep, YSize, yPageSize, yWithinMargins); return 0; } // !MyItemInfo.IsHigh - if (MyItemInfo.IsRNOPart && MyParent.XOffset < XOffset) return 0; // Don't paginate on an RNO to the right if (YSize < yPageSize) // if the entire step can fit on one page, do a page break { //Console.WriteLine("'PageBreak',2,'Yes','HLS will fit on 1 Page',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); ShowPageBreak(5, "HLS will fit on 1 Page at 6 LPI", "Yes", YSize, yPageSize, yWithinMargins); return 1; } else if (MyItemInfo.ActiveFormat.MyStepSectionLayoutData.CompressSteps && (ySize7LPI) < (yPageSize * SixLinesPerInch / _SevenLinesPerInch)) { //Console.WriteLine("'PageBreak',3,'Yes','HLS will fit on 1 Page at 7 LPI',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); ShowPageBreak(7, "HLS will fit on 1 Page at 7 LPI", "Yes", YSize, yPageSize, yWithinMargins); //Console.WriteLine("'7LPI',{0},{1}", MyItemInfo.DBSequence, YSize); return 3; // High Level Step can fit at SevenLinesPerInch } else // The entire step cannot fit on a blank page. { // if there is more than half a page left, then start to print on the current page float myFirstPieceSize = GetFirstPieceSize(); //Case 0 if (_Match16BitPagination) myFirstPieceSize += 2 * SixLinesPerInch; // TODO: Put this line back to case 0, i.e. previous line. This fixes a 16-bit vs 32-bit pagination diff in EO30 Step 20. //float myFirstPieceSize = GetFirstPieceSize() + 2 * SixLinesPerInch; //Case 10 - this is to match 16bit if (!ManualPageBreak && MyItemInfo.ActiveFormat.MyStepSectionLayoutData.SpecialPageBreakFlag && yWithinMargins > yPageSize / 2 && myFirstPieceSize < yWithinMargins ) { //Console.WriteLine("'PageBreak',4,'No','HLS will have to split anyway',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); ShowPageBreak(-4, "HLS will have to split anyway", firstStep , YSize, yPageSize, yWithinMargins); //BuildPageBreakList(yWithinMargins+SixLinesPerInch,yPageSize-2*SixLinesPerInch); // Determine items where page break(s) occur BuildPageBreakList(yWithinMargins + SixLinesPerInch, yPageSize); // Case 5 - Determine items where page break(s) occur return 0; // Stay on this page } // Less than half a page left, start printing on a new page. //Console.WriteLine("'PageBreak',5,'Yes','HLS will have to split',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); ShowPageBreak(5, "HLS will have to split", "Yes", YSize, yPageSize, yWithinMargins); // Determine items where page break(s) occur //BuildPageBreakList(yPageSize, yPageSize - 2 * SixLinesPerInch); // Case Base BuildPageBreakList(yPageSize, yPageSize); // Case 1 :Works for ES05 Step 15 SubStep 7 return 1; // Paginate on High Level Steps } //if (yWithinMargins > yPageSize / 2) //{ // Console.WriteLine("'PageBreak',4,'No','Not Half way down the page',{0},{1},{2}, {3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); // return 0; // More than half way down the page //} //if (ChildrenBelow.Count > 0 && ChildrenBelow[0].YSize < yWithinMargins) // return 0; //Console.WriteLine("'PageBreak',5,'Yes','At least half the page is filled',{0},{1},{2},{3}, {4},'{5}'", MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.ShortPath); //return 2; throw new Exception("PageBreak Logic Missing, vlnParagraph.cs"); } /// /// This gets the height of the step with it's Caution's, Notes and potentially any First Substeps /// /// private float GetFirstPieceSize() { vlnParagraph paraLast = GetFirstPieceLastPart(); float retval = (paraLast.YBottom) - YTopMost; //Console.WriteLine(MyItemInfo.DBSequence); return retval; } public override float YBottom { get { float bottom = YOffset + Height; if (PartsBelow != null) { foreach (vlnPrintObject part in PartsBelow) { float partBottom = part.YBottom; bottom = Math.Max(partBottom, bottom); } } return bottom; } } private vlnParagraph GetFirstPieceLastPart() { vlnParagraph para = this; if (!MyItemInfo.ActiveFormat.MyStepSectionLayoutData.PaginateOnFirstSubstep && ChildrenBelow != null && ChildrenBelow.Count > 0) { para = ChildrenBelow[0].GetFirstPieceLastPart(); } if (ChildrenRight != null && ChildrenRight.Count > 0) { foreach(vlnParagraph paraRight in ChildrenRight) { vlnParagraph paraRightLast = paraRight.GetFirstPieceLastPart(); if (paraRightLast.YBottom > para.YBottom) para = paraRightLast; } } return para; } private void ShowPageBreak(int instance, string message, string breakOrNot, float YSize, float yPageSize, float yWithinMargins) { if(_PaginationDebug) if (breakOrNot == "Yes") Console.WriteLine("{0}", MyItemInfo.DBSequence); //,instance); // Console.WriteLine("{0},{1}", MyItemInfo.DBSequence, IsFirstSubStep(MyItemInfo)); //,instance); // Console.WriteLine("{0},'{1}','{2}',{3},{4},{5},{6},{7},'{8}'", instance, message, breakOrNot, // MyItemInfo.ItemID, YSize, yPageSize, yWithinMargins, (int)(100 * yWithinMargins / yPageSize), MyItemInfo.DBSequence); } private void BuildPageBreakList(float ySpaceOnCurPage, float yPageSize) { ParagraphLocations myLocations = new ParagraphLocations(); BuildLocationList(YTopMost, myLocations); StepLevelList myList = myLocations.BuildStepLevelList(); // Find Break Locations in the list based upon StepLevel and yLocation float yTop = 0; float yLowerLimit = (yPageSize - 2 * SixLinesPerInch) / 2; float yStart = Math.Max(0,(yPageSize - 2 * SixLinesPerInch) - ySpaceOnCurPage); //Console.WriteLine("'yStart',{0},{1}", MyItemInfo.DBSequence, yStart); // The following three lines make page breaking match 16-bit: if (_Match16BitPagination) { yLowerLimit = yStart - SixLinesPerInch + ySpaceOnCurPage / 2; if ((yStart + MyItemInfo.MyDocStyle.Layout.TopRow + 2 * SixLinesPerInch) > ((MyItemInfo.MyDocStyle.Layout.TopRow + yPageSize - 2 * SixLinesPerInch) / 2)) yLowerLimit = yStart + 2 * SixLinesPerInch; } // Make sure that the FirstPiece (Caution Note HLS and First Substeps) fit float myFirstPieceSize = GetFirstPieceSize(); //Case 0 if (myFirstPieceSize < ySpaceOnCurPage) yLowerLimit = Math.Max(myFirstPieceSize + yStart, yLowerLimit); while ((YSize - yTop) >= ySpaceOnCurPage) { vlnParagraph paraBreak = FindPageBreak(yStart, ySpaceOnCurPage, yLowerLimit, myList); // yTopNew is y Location of this page break. YTopMost is top of HLS, including any Cautions/Notes/Boxes/etc float yTopNew = paraBreak.YVeryTop - YTopMost; RemoveProcessedParagraphs(myList, yTopNew-yTop); yTop = yTopNew; MyPageHelper.ParaBreaks.Add(paraBreak); ySpaceOnCurPage = yPageSize - 2 * SixLinesPerInch; // Allow for continue message and blank line. yLowerLimit = ySpaceOnCurPage / 2; if(_Match16BitPagination)yLowerLimit -= 1.5F * SixLinesPerInch; // 276 for HLP yStart = 0; } } /// /// Find items from previous page (yLocation less than yTop) and remove them from the list. /// yTop is the new starting location on the next page for this step. /// /// /// private void RemoveProcessedParagraphs(StepLevelList myList, float yTop) { // the two CleanUpLists are used to remove items from // the original list because list items cannot be removed in a // 'foreach'. List CleanupListStepLevel = new List(); foreach(int stepLevel in myList.Keys) { List CleanupListYLocation = new List(); SortedList AdjustYLocation = new SortedList(); foreach (float yLocation in myList[stepLevel].Keys) { if (-yLocation <= yTop) CleanupListYLocation.Add(yLocation); else AdjustYLocation.Add(-yLocation, yLocation); // order in ascending order } //if (stepLevel == 3) Console.WriteLine("here"); foreach (float yLocation in CleanupListYLocation) myList[stepLevel].Remove(yLocation); foreach (float yLocation in AdjustYLocation.Keys) { vlnParagraph para = myList[stepLevel][-yLocation]; myList[stepLevel].Remove(-yLocation); // shift yLocation by yTop to work with items whose locations // are defined from the top of the new page rather than // from the beginning of the step. // Note that yLocation is negative to have items in descending // order so that adding yTop decrements their values. myList[stepLevel].Add(yTop-yLocation, para); } if (myList[stepLevel].Count == 0) CleanupListStepLevel.Add(stepLevel); } foreach (int stepLevel in CleanupListStepLevel) myList.Remove(stepLevel); } /// /// Finds the highest StepLevel (lowest StepLevel number, 0 = HLS, 1 = first substep) that /// fills the page sufficiently (more than half-full) /// /// /// /// /// private static vlnParagraph FindPageBreak(float yStart, float yUpperLimit, float yLowerLimit, StepLevelList myList) { foreach (int stepLevel in myList.Keys) // loop thru StepLevels, starting with lowest. { foreach (float yLocation in myList[stepLevel].Keys) // loop thru yLocation { // The top of this step will fit onto page (-yLocation < yWithinMargins) if (-yLocation < yUpperLimit) //if (-yLocation < yWithinMargins && myList[stepLevel][yLocation].MyItemInfo.MyPrevious != null) { //ItemInfo prev = myList[stepLevel][yLocation].MyItemInfo.MyPrevious; //if (myList[stepLevel][yLocation].MyItemInfo.ItemID == 5609) Console.WriteLine("aer"); //if (myList[stepLevel][yLocation].MyItemInfo.ItemID == 4312) Console.WriteLine("rno"); // The top of this step is more than 1/2 way down the page if ((-yLocation + yStart) >= yLowerLimit) { return myList[stepLevel][yLocation]; } // if is a caution or note & parent is a substep and entire substep doesn't fit, break. if ((myList[stepLevel][yLocation].MyItemInfo.IsNote || myList[stepLevel][yLocation].MyItemInfo.IsCaution) && !myList[stepLevel][yLocation].MyParent.MyItemInfo.IsHigh && myList[stepLevel][yLocation].MyParent.YSize > (yUpperLimit + yLocation)) { return myList[stepLevel][yLocation]; } } } } return null; } /// /// Builds a list of paragraphs by StepLevel and yLocation in descending order. /// /// /// private void BuildLocationList(float yTopMost, ParagraphLocations myLocations) { foreach (vlnParagraph child in ChildrenAbove) child.BuildLocationList(yTopMost, myLocations); foreach (vlnParagraph child in ChildrenLeft) child.BuildLocationList(yTopMost, myLocations); // Add a list entry consisting of StepLevel, yoffset from the beginning of this step, paragraph itself myLocations.Add(this, yTopMost); foreach (vlnParagraph child in ChildrenRight) child.BuildLocationList(yTopMost, myLocations); foreach (vlnParagraph child in ChildrenBelow) child.BuildLocationList(yTopMost, myLocations); } private int COL_WID_ADJ = 6; // adjusts for incorrect use of WidSTable when breaking a line (it breaks 6 chars too short) public vlnParagraph(vlnParagraph parent, PdfContentByte cb, ItemInfo itemInfo, float xoff, float yoff, int rnoLevel, int maxRNO, FormatInfo formatInfo) { //int[] problemIDs = { 889 }; //List lProblemIDs = new List(problemIDs); //if (lProblemIDs.Contains(itemInfo.ItemID)) // Console.WriteLine("Found Item {0}", itemInfo.ItemID); MyParent = parent; // The following code determines the last paragraph for an RNO // MyTopRNO finds the Top paragraph for an RNO if (itemInfo.IsInRNO) { if (rnoLevel <= maxRNO && itemInfo.IsRNOPart) // Not top level RNO MyTopRNO = this; else MyTopRNO = MyParent.MyTopRNO; if(MyTopRNO != null) MyTopRNO.LastRNO = this; } MyContentByte = cb; MyPageHelper.MyParagraphs.Add(itemInfo.ItemID, this); MyItemInfo = itemInfo; XOffset = xoff; YTopMost = YOffset = yoff; vlnTab mytab = null; if (itemInfo.MyTab != null && itemInfo.MyTab.Text != null && itemInfo.MyTab.Text != "") { mytab = new vlnTab(cb, this, itemInfo.MyTab.Text, itemInfo.MyTab.CleanText, XOffset, yoff, itemInfo.MyTab.MyFont); PartsLeft.Add(mytab); } AdjustWidth(itemInfo, maxRNO, formatInfo, mytab); AdjustXOffsetForTab(itemInfo, maxRNO, formatInfo, mytab); if (itemInfo.Cautions != null) { //yoff += 2 * _SixLinesPerInch; yoff = ChildrenAbove.Add(cb, itemInfo.Cautions, xoff, yoff, yoff, rnoLevel, maxRNO, formatInfo); //yoff += 2 * _SixLinesPerInch; } if (itemInfo.Notes != null) { //yoff += 2 * _SixLinesPerInch; yoff = ChildrenAbove.Add(cb, itemInfo.Notes, xoff, yoff, yoff, rnoLevel, maxRNO, formatInfo); //yoff += 2 * _SixLinesPerInch; } YTop = yoff; if (itemInfo.MyHeader != null && itemInfo.MyHeader.Text != null) yoff += SetHeader(this, cb, itemInfo, formatInfo); YOffset = yoff; AddMacros(itemInfo, mytab); if (mytab != null) mytab.YOffset = yoff; if (itemInfo.IsFigure) // if a figure we've got to determine the size: { if (itemInfo.MyContent.Text != null) { ProcedureInfo proc = itemInfo.MyProcedure; DocVersionInfo dvi = proc.ActiveParent as DocVersionInfo; ROFstInfo rofst = dvi.DocVersionAssociations[0].MyROFst; ROFSTLookup lookup = rofst.ROFSTLookup; string linkInfoText = itemInfo.MyContent.Text.Replace(@"\v ", ""); Match m = Regex.Match(linkInfoText, @"(.*)[#]Link:([A-Za-z]*):(.*)"); string[] subs = m.Groups[3].Value.Split(" ".ToCharArray()); string roid = subs[1]; string val = lookup.GetRoValue(subs[1]); if (val == null) val = lookup.GetRoValue(subs[1].Substring(0, 12)); if (val != null) { string[] vals = val.Split("\n".ToCharArray()); Width = Int32.Parse(vals[3], System.Globalization.NumberStyles.AllowHexSpecifier) * _CharsToTwips; int lines = Int32.Parse(vals[2], System.Globalization.NumberStyles.AllowHexSpecifier); Height = lines * SixLinesPerInch; yoff += (Height + (2 * SixLinesPerInch)); string erMsg = null; try { ROImageInfo roImage = ROImageInfo.GetByROFstID_FileName(rofst.ROFstID, vals[0]); if (roImage != null) ImageText = val; else erMsg = string.Format("Image {0} does not exist.", vals[0]); } catch (Exception ex) { erMsg = string.Format("Image {0} does not exist, error = {1}.", vals[0], ex.Message); } if (erMsg != null) Rtf = GetRtf(erMsg, itemInfo.ActiveFormat.PlantFormat.FormatData.Font); } CalculateXOffset(itemInfo, maxRNO, formatInfo); } } else { Rtf = GetRtf(itemInfo); if (itemInfo.IsTablePart) { Width = GetTableWidth(cb, IParagraph); CalculateXOffset(itemInfo, maxRNO, formatInfo); } if (!itemInfo.IsStepSection) // Don't add any lines for the Section Title { yoff += Height; yoff += AdjustForBlankLines(); } } float yOffRight = yoff; float RnoOffset = ToInt(formatInfo.MyStepSectionLayoutData.ColRTable, maxRNO); if (rnoLevel < maxRNO && itemInfo.RNOs != null) yOffRight = ChildrenRight.Add(cb, itemInfo.RNOs, XOffset + RnoOffset, YTop, YTop, rnoLevel + 1, maxRNO, formatInfo); // Need code to determine if the table will overlap the Right Column if it does then // use YOffRight rather than yoff if (itemInfo.Tables != null) yoff = ChildrenBelow.Add(cb, itemInfo.Tables, XOffset, yoff, yOffRight, rnoLevel, maxRNO, formatInfo); if (itemInfo.Steps != null) yoff = ChildrenBelow.Add(cb, itemInfo.Steps, XOffset, yoff, yOffRight, rnoLevel, maxRNO, formatInfo); if (itemInfo.Sections != null) yoff = ChildrenBelow.Add(cb, itemInfo.Sections, xoff, yoff, yoff, rnoLevel, maxRNO, formatInfo); if (itemInfo.Procedures != null) yoff = ChildrenBelow.Add(cb, itemInfo.Procedures, xoff, yoff, yoff, rnoLevel, maxRNO, formatInfo); if (rnoLevel >= maxRNO && itemInfo.RNOs != null) yoff = ChildrenBelow.Add(cb, itemInfo.RNOs, XOffset, yoff, yoff, rnoLevel + 1, maxRNO, formatInfo); yoff = Math.Max(yoff, yOffRight); // TODO - use RNOSepAfterAER flag too: string tmpRnoSepStr = formatInfo.MyStepSectionPrintData.RNOSepString; if (rnoLevel < maxRNO && itemInfo.RNOs != null && tmpRnoSepStr != null) { float xsep = MyHighLevelParagraph.XOffset + RnoOffset; vlnRNOSeparator myRnoSep = new vlnRNOSeparator(this, cb, tmpRnoSepStr, xsep, yoff, formatInfo.PlantFormat.FormatData.Font); vlnParagraph rno = ChildrenRight[0]; // TODO: May need to handle more than one RNO column for RNO Separator rno.LastRNO.PartsBelow.Add(myRnoSep); yoff += myRnoSep.Height + SixLinesPerInch; } YBottomMost = yoff; } private void CalculateXOffset(ItemInfo itemInfo, int maxRNO, FormatInfo formatInfo) { bool aerFigure = itemInfo.FormatStepData.Type.Contains("AER"); vlnParagraph hls1 = MyParent; while (hls1.MyParent != null && !hls1.MyItemInfo.IsHigh) hls1 = hls1.MyParent; XOffset = hls1.XOffset + hls1.Width / 2 - Width / 2; // xoffset if AER column if (!aerFigure) { // adjust for RNO int colR = int.Parse(formatInfo.MyStepSectionLayoutData.ColRTable.Split(",".ToCharArray())[itemInfo.ColumnMode]); XOffset += (colR * maxRNO) / 2; XOffset -= (hls1.XOffset - (float)itemInfo.MyDocStyle.Layout.LeftMargin) / 2; } if (XOffset < (float)itemInfo.MyDocStyle.Layout.LeftMargin) XOffsetBox = (float)itemInfo.MyDocStyle.Layout.LeftMargin; } private float AdjustForBlankLines() { int everyNLines = MyItemInfo.FormatStepData == null ? 1 : MyItemInfo.FormatStepData.StepLayoutData.EveryNLines ?? 1; if (MyItemInfo.Ordinal % everyNLines == 0 || MyItemInfo.NextItem == null) return SixLinesPerInch; return 0; } private void AddMacros(ItemInfo itemInfo, vlnTab mytab) { float y = YOffset; float x = mytab == null ? XOffset : mytab.XOffset + mytab.TabOffset; List myMacros = itemInfo.MyMacros; if (myMacros != null) { foreach (Macro myMacro in myMacros) { PartsLeft.Add(new vlnMacro(x, y, myMacro.MacroDef)); } } } // HLP Change bar flags in format file: // Locations: With Text, Outside Box, AER on Left RNO on Right, To The Left of Text // Text: Date & Change ID, Revision Number, Change ID, None, Custom (use input data) // Flag AERChgBarMsgRNOChgBarNoMsg and AERMsgRNONoMsg are NOT Used in 16-bit. private string cbMess = null; private vlnChangeBar DoChangeBar(PdfContentByte cb, ItemInfo itemInfo, VlnSvgPageHelper myPageHelper, float xoff, float yoff, int maxRNO, FormatInfo formatInfo) //, vlnChangeBar myCB) { // find column for the change bar based on format flags - this is code from 16-bit // if AbsoluteFixedChangeColumn // if FixedAERChangeColumn // if col>ColsS+ColR+COL_WID+ADJ // FixedChangeColumn // else // AERLeftChangeBarLocation() // else // FixedChangeColumn // else // ChangeBarLocation() ChangeBarData cbd = formatInfo.PlantFormat.FormatData.ProcData.ChangeBarData; int cols = formatInfo.MyStepSectionLayoutData.ColS ?? 0; int colr = ToInt(formatInfo.MyStepSectionLayoutData.ColRTable, maxRNO); float col = (cbd.AbsoluteFixedChangeColumn) ? ((cbd.FixedAERChangeColumn ?? 0) > 0) ? (xoff > (cols + colr + COL_WID_ADJ)) ? cbd.FixedChangeColumn ?? 0 : AERLeftChangeBarLocation(formatInfo) : cbd.FixedChangeColumn ?? 0 : ChangeBarLocation(xoff, this, formatInfo, maxRNO); if (myPageHelper.ChangeBarDefinition.MyChangeBarText == PrintChangeBarText.ChgID) cbMess = itemInfo.UserID; else if (myPageHelper.ChangeBarDefinition.MyChangeBarText == PrintChangeBarText.DateChgID) { string fmtDate = itemInfo.DTS.ToShortDateString(); if (fmtDate.Length != 10) // need to add zeros { if (fmtDate.IndexOf("/") == 1) fmtDate = "0" + fmtDate; if (fmtDate.IndexOf("/", 3) == 1) fmtDate = fmtDate.Substring(0, 3) + "0" + fmtDate.Substring(3, fmtDate.Length - 3); } cbMess = itemInfo.UserID + @"\n" + fmtDate; } else if (myPageHelper.ChangeBarDefinition.MyChangeBarText == PrintChangeBarText.RevNum) cbMess = myPageHelper.Rev; else if (myPageHelper.ChangeBarDefinition.MyChangeBarText == PrintChangeBarText.UserDef) cbMess = myPageHelper.ChangeBarDefinition.MyChangeBarMessage; int msgAlign = Element.ALIGN_LEFT; if (myPageHelper.ChangeBarDefinition.MyChangeBarLoc == PrintChangeBarLoc.LeftOfText || (myPageHelper.ChangeBarDefinition.MyChangeBarLoc == PrintChangeBarLoc.AERleftRNOright && !itemInfo.IsInRNO)) msgAlign = Element.ALIGN_RIGHT; return new vlnChangeBar(cb, this, (float)itemInfo.MyDocStyle.Layout.LeftMargin + (col * _CharsToTwips), yoff, msgAlign); } private int ChangeBarLocation(float c, vlnParagraph paragraph, FormatInfo formatInfo, int maxRNO) { int fixedChgCol = formatInfo.PlantFormat.FormatData.ProcData.ChangeBarData.FixedChangeColumn ?? 0; int cols = formatInfo.MyStepSectionLayoutData.ColS ?? 0; int colr = ToInt(formatInfo.MyStepSectionLayoutData.ColRTable, maxRNO); if (fixedChgCol < -10 || fixedChgCol >= 0) return ((fixedChgCol > 0) ? fixedChgCol : (fixedChgCol == 0) ? (int)c + 1 : (c > cols + colr + COL_WID_ADJ) ? -fixedChgCol : AERLeftChangeBarLocation(formatInfo)); else return (fixedChgCol + (((c < cols + Width + colr) || TableTest() || MyItemInfo.IsCaution || MyItemInfo.IsNote) ? 0 : cols + colr)); // || (GetColumnMode() == 0)) ? 0 : cols + colr)); /* Change bars to left of text -- ColS+WidS+ColR is the end of RNO col*/ } /* ** Centered tables whose width exceeds the end of the RNO column should ** still have their change bars printed on the left. This procedure checks ** to make sure the step is a table and that it is not an RNO. */ private bool TableTest() { return false; //return ((s->Type == TABLE || s->Type == BORDERLESSTABLE) && //!(strchr((char *)&s->dbseq[2],RNO_MARKER))); } private float GetBottomYoff(float bottomY) { foreach (vlnParagraph child in ChildrenBelow) { if (child.YOffset > bottomY) bottomY = child.YOffset; bottomY = child.GetBottomYoff(bottomY); } return bottomY; } private int AERLeftChangeBarLocation(FormatInfo formatInfo) { // use -5 default unless it is format specified int fixedAERChgCol = formatInfo.PlantFormat.FormatData.ProcData.ChangeBarData.FixedAERChangeColumn ?? 0; return (fixedAERChgCol != 0) ? (fixedAERChgCol > 100) ? (fixedAERChgCol % 100) : -fixedAERChgCol : -5; } private StringBuilder _RtfSB = null; // return rtf and use for tab and other text public string GetRtf(ItemInfo itemInfo) { _RtfSB = new StringBuilder(); DisplayText vlntxt = new DisplayText(itemInfo, E_EditPrintMode.Print, E_ViewMode.View, true, E_FieldToEdit.StepText, false); _RtfSB.Append(AddFontTable(vlntxt.TextFont.WindowsFont)); _RtfSB.Append(vlntxt.StartText); _RtfSB.Append("}"); return _RtfSB.ToString(); } private float _XOffsetBox = -24; public float XOffsetBox { get { return _XOffsetBox; } set { _XOffsetBox = value; } } private float SetHeader(vlnParagraph para, PdfContentByte cb, ItemInfo itemInfo, FormatInfo formatInfo) { float xoff = (float)itemInfo.MyDocStyle.Layout.LeftMargin; float hdrWidth = (itemInfo.MyHeader.CleanText == null) ? 0 : itemInfo.MyHeader.CleanText.Length * _CharsToTwips; // convert to twips int typ = ((int)itemInfo.MyContent.Type) % 10000; int? bxIndx = formatInfo.PlantFormat.FormatData.StepDataList[typ].StepLayoutData.STBoxindex; if (itemInfo.MyHeader.Justify == System.Drawing.ContentAlignment.MiddleCenter) { if (bxIndx != null) { Box bx = formatInfo.PlantFormat.FormatData.BoxList[(int)bxIndx]; if (bx.TabPos > 0) xoff += (float)bx.TabPos; // xoff starts as left margin else { xoff += (float)((bx.TxtStart + XOffsetBox + (bx.TxtWidth / 2)) - (hdrWidth / 2)); // xoff starts as left margin } } else if (formatInfo.MyStepSectionLayoutData.Separator.Location > 0) { // if there is a separator location, use it - 16bit code used the separator location as a divisor: xoff = XOffset + AdjustToCharPosition((float)((para.Width - hdrWidth) / formatInfo.MyStepSectionLayoutData.Separator.Location)); } else xoff = XOffset + (para.Width / 2) + (hdrWidth / 2); // XOffset has left margin included } else xoff = XOffset; // XOffset has left margin included vlnHeader myHeader = new vlnHeader(this, cb, itemInfo.MyHeader.Text, itemInfo.MyHeader.CleanText.TrimStart(" ".ToCharArray()), xoff, YOffset, itemInfo.MyHeader.MyFont); PartsAbove.Add(myHeader); return myHeader.Height + SixLinesPerInch; } private bool _Processed = false; public bool Processed { get { return _Processed; } set { _Processed = value; } } private vlnParagraph _LastRNO; public vlnParagraph LastRNO { get { return _LastRNO; } set { _LastRNO = value; } } private vlnParagraph _MyTopRNO; public vlnParagraph MyTopRNO { get { return _MyTopRNO; } set { _MyTopRNO = value; } } private static string _Prefix = ""; public static string Prefix { get { return vlnParagraph._Prefix; } set { vlnParagraph._Prefix = value; } } protected float _YBottomMost; // Bottom of the paragraph including the children public float YBottomMost { get { return _YBottomMost; } set { _YBottomMost = value; } } protected float _YTopMost; // Top of the paragraph including the children public float YTopMost { get { return _YTopMost; } set { _YTopMost = value; } } protected float _YTop; // Top of the paragraph including parts public float YTop { get { return _YTop; } set { vlnParagraph vp = this as vlnParagraph; //if (vp != null && vp.MyItemInfo != null && vp.MyItemInfo.ItemID == 55) // Console.WriteLine("here"); _YTop = value; } } public float YSize // How big this paragraph is with all of its children { get { return _YBottomMost - _YTopMost; } } private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { return _MyItemInfo; } set { _MyItemInfo = value; } } private vlnParagraph _MyHighLevelParagraph; public vlnParagraph MyHighLevelParagraph { get { if (_MyHighLevelParagraph == null) { _MyHighLevelParagraph = GetHighLevelParagraph(); } return _MyHighLevelParagraph; } } private vlnParagraph GetHighLevelParagraph() { if (MyItemInfo.IsHigh) return this; return MyParent.GetHighLevelParagraph(); } // Tab, Separator, ChangeBar, Box, Circle, Checkoff private vlnPrintObjects _PartsAbove; public vlnPrintObjects PartsAbove { get { if (_PartsAbove == null) _PartsAbove = new vlnPrintObjects(); return _PartsAbove; } } private vlnPrintObjects _PartsBelow; public vlnPrintObjects PartsBelow { get { if (_PartsBelow == null) _PartsBelow = new vlnPrintObjects(); return _PartsBelow; } } private vlnPrintObjects _PartsRight; public vlnPrintObjects PartsRight { get { if (_PartsRight == null) _PartsRight = new vlnPrintObjects(); return _PartsRight; } } private vlnPrintObjects _PartsLeft; public vlnPrintObjects PartsLeft { get { if (_PartsLeft == null) _PartsLeft = new vlnPrintObjects(); return _PartsLeft; } } private vlnPrintObjects _PartsContainer; public vlnPrintObjects PartsContainer { get { if (_PartsContainer == null) _PartsContainer = new vlnPrintObjects(); return _PartsContainer; } } private vlnParagraphs _ChildrenAbove; public vlnParagraphs ChildrenAbove { get { if (_ChildrenAbove == null) _ChildrenAbove = new vlnParagraphs(this); return _ChildrenAbove; } } private vlnParagraphs _ChildrenBelow; public vlnParagraphs ChildrenBelow { get { if (_ChildrenBelow == null) _ChildrenBelow = new vlnParagraphs(this); return _ChildrenBelow; } } private vlnParagraphs _ChildrenRight; public vlnParagraphs ChildrenRight { get { if (_ChildrenRight == null) _ChildrenRight = new vlnParagraphs(this); return _ChildrenRight; } } private vlnParagraphs _ChildrenLeft; public vlnParagraphs ChildrenLeft { get { if (_ChildrenLeft == null) _ChildrenLeft = new vlnParagraphs(this); return _ChildrenLeft; } } public void AdjustXOffsetForTab(ItemInfo itemInfo, int maxRNO, FormatInfo formatInfo, vlnTab myTab) { float tabWidth = (myTab == null) ? 0 : myTab.Width; int typ = ((int)itemInfo.MyContent.Type) % 10000; int? bxIndx = formatInfo.PlantFormat.FormatData.StepDataList[typ].StepLayoutData.STBoxindex; if (bxIndx != null) { Box bx = formatInfo.PlantFormat.FormatData.BoxList[(int)bxIndx]; //XOffset += (float)bx.TxtStart + tabWidth + XOffsetBox; XOffset = (float)itemInfo.MyDocStyle.Layout.LeftMargin + (float)bx.TxtStart + tabWidth + XOffsetBox; if (myTab != null) myTab.XOffset = XOffset - tabWidth; } else if (itemInfo.IsHigh) { XOffset += tabWidth - myTab.TabAlign; if (myTab != null) myTab.XOffset += tabWidth - myTab.TabAlign; } else if (itemInfo.IsRNOPart && !((ItemInfo)itemInfo.ActiveParent).IsHigh) { // don't adjust for rno } else if (MyParent != null) { XOffset += tabWidth - (myTab == null ? 0 : myTab.TabAlign); if (myTab != null) myTab.XOffset += tabWidth - myTab.TabAlign; } } public void AdjustWidth(ItemInfo itemInfo, int maxRNO, FormatInfo formatInfo, vlnTab myTab) { float tabWidth = (myTab == null) ? 0 : myTab.Width; int typ = ((int)itemInfo.MyContent.Type) % 10000; int? bxIndx = formatInfo.PlantFormat.FormatData.StepDataList[typ].StepLayoutData.STBoxindex; if (bxIndx != null) { Box bx = formatInfo.PlantFormat.FormatData.BoxList[(int)bxIndx]; Width = _WidthAdjustBox + (float)bx.TxtWidth - tabWidth; } else if (itemInfo.IsHigh) { Width = _WidthAdjust + ToInt(formatInfo.MyStepSectionLayoutData.WidSTablePrint, maxRNO); } else if (MyParent == null) { // 72 points / inch - 7 inches (about width of page) Width = 72 * 7; } else if (itemInfo.IsRNOPart && !((ItemInfo)itemInfo.ActiveParent).IsHigh) { Width = MyParent.Width; } else if (itemInfo.IsTablePart) { Width = 72 * 7; // TODO: Need to determine the Width of the Table based upon the contents } else { Width = MyParent.Width - tabWidth + (myTab == null ? 0 : myTab.TabAlign); } } } /// /// First order by stepLevel, then within a stepLevel, order by descending yLocation on page. /// Want to find maximum y value that fits on page, i.e. put the most on page that can /// fit which is defined by the largest yLocation /// public class StepLevelList : SortedDictionary> { public StepLevelList() : base() { } public void Add(int stepLevel, float yLocation, vlnParagraph para) { if (stepLevel == 0) return; if (!this.ContainsKey(stepLevel)) this.Add(stepLevel, new SortedDictionary()); // using a negative for yLocation so that its in descending order: if (!this[stepLevel].ContainsKey(-yLocation)) this[stepLevel].Add(-yLocation, para); } } public class ParagraphLocations : List { public ParagraphLocations() : base() { } public void Add(vlnParagraph myParagraph, float yTopMost) { ParagraphLocation foundOverlap = FindOverlap(myParagraph); if (foundOverlap == null) { this.Add(new ParagraphLocation(yTopMost,myParagraph)); return; } ParagraphLocation doubleOverlap = FindOverlap(foundOverlap); while (doubleOverlap != null) { doubleOverlap.Merge(foundOverlap); this.Remove(foundOverlap); foundOverlap = doubleOverlap; doubleOverlap = FindOverlap(foundOverlap); } } private ParagraphLocation FindOverlap(vlnParagraph myParagraph) { foreach (ParagraphLocation paraLoc in this) if (paraLoc.Overlap(myParagraph)) return paraLoc; return null; } private ParagraphLocation FindOverlap(ParagraphLocation myParaLoc) { foreach (ParagraphLocation paraLoc in this) if (paraLoc != myParaLoc && paraLoc.Overlap(myParaLoc)) return paraLoc; return null; } internal StepLevelList BuildStepLevelList() { StepLevelList myList = new StepLevelList(); foreach (ParagraphLocation paraLoc in this) myList.Add(paraLoc.StepLevel, paraLoc.YTop, paraLoc.MyParagraph); return myList; } } public class ParagraphLocation { private float _YTop; public float YTop { get { return _YTop; } set { _YTop = value; } } private float _YBottom; public float YBottom { get { return _YBottom; } set { _YBottom = value; } } private int _StepLevel; public int StepLevel { get { return _StepLevel; } set { _StepLevel = value; } } private vlnParagraph _MyParagraph; public vlnParagraph MyParagraph { get { return _MyParagraph; } set { _MyParagraph = value; } } public ParagraphLocation(float yTopMost,vlnParagraph myParagraph) { MyParagraph =myParagraph; YTop = myParagraph.YVeryTop - yTopMost; YBottom = myParagraph.YBottom - yTopMost; StepLevel = myParagraph.MyItemInfo.StepLevel; } public bool Overlap(vlnParagraph otherParagraph) { if (Between(otherParagraph.YTop, YTop, YBottom)) return true; if (Between(otherParagraph.YBottom, YTop, YBottom)) return true; if(Between(YTop,otherParagraph.YVeryTop,otherParagraph.YBottom)) return true; if(Between(YBottom,otherParagraph.YVeryTop,otherParagraph.YBottom)) return true; return false; } public static bool Between(float x, float lower, float higher) { return x >= lower && x <= higher; } public bool Overlap(ParagraphLocation otherParagraphLocation) { if (Between(otherParagraphLocation.YTop, YTop, YBottom)) return true; // The top is within the other if (Between(otherParagraphLocation.YBottom, YTop, YBottom)) return true; // The bottom is within the other if(Between(YTop,otherParagraphLocation.YTop,otherParagraphLocation.YBottom)) return true; // the other top is within this one if(Between(YBottom,otherParagraphLocation.YTop,otherParagraphLocation.YBottom)) return true;// I believe this is unnecessary return false; } public void Merge(vlnParagraph otherParagraph) { if (StepLevel < otherParagraph.MyItemInfo.StepLevel) MyParagraph = otherParagraph; YTop = Math.Min(YTop, otherParagraph.YVeryTop); YBottom = Math.Max(YBottom, otherParagraph.YBottom); StepLevel = Math.Max(StepLevel, otherParagraph.MyItemInfo.StepLevel); } public void Merge(ParagraphLocation otherParagraphLocation) { if (StepLevel < otherParagraphLocation.StepLevel) MyParagraph = otherParagraphLocation.MyParagraph; YTop = Math.Min(YTop, otherParagraphLocation.YTop); YBottom = Math.Max(YBottom, otherParagraphLocation.YBottom); StepLevel = Math.Max(StepLevel, otherParagraphLocation.StepLevel); } } }