using System; using System.Collections.Generic; using System.Text; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.factories; using Volian.Svg.Library; using System.Text.RegularExpressions; using System.Xml; using VEPROMS.CSLA.Library; using Volian.Base.Library; namespace Volian.Print.Library { public partial class VlnSvgPageHelper:SvgPageHelper { private float _TableAdjustment = 0;// RHM20150525 - Table Scrunch public float TableAdjustment { get { return _TableAdjustment; } set { _TableAdjustment = value; } } private vlnParagraph _AdjustedTable; // B2020-059 - save info of table that was compressed (set in vlnParagraph.cs DrawGrid() and used in RTF2PDF.cs TextAt()) public vlnParagraph AdjustedTable { get { return _AdjustedTable; } set { _AdjustedTable = value; } } private float _AdjustedTableYtop; public float AdjustedTableYtop // B2020-059 - save the Ytop of the compressed table (set in vlnParagraph.cs DrawGrid() and used in RTF2PDF.cs TextAt()) { get { return _AdjustedTableYtop; } set { _AdjustedTableYtop = value; } } private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private pkParagraphs _MyPlacekeepers = new pkParagraphs(); public pkParagraphs MyPlacekeepers { get { return _MyPlacekeepers; } } private pkParagraphs _MyContActSteps = new pkParagraphs(); public pkParagraphs MyContActSteps { get { return _MyContActSteps; } } private float? _BottomContent = null;// RHM20150525 - Table Scrunch public float? BottomContent { get { return _BottomContent; } set { if(value == null || _BottomContent == null || _BottomContent > value) _BottomContent = value; } } private PageBookmarks _PageBookmarks = new PageBookmarks(); public PageBookmarks PageBookmarks { get { return _PageBookmarks; } set { _PageBookmarks = value; } } private List _MyPdfOutlines = new List(); public List MyPdfOutlines { get { return _MyPdfOutlines; } } private ChkListBoxesHelper _CheckListBoxes = null; private ChkListBoxesHelper CheckListBoxes { get { return _CheckListBoxes; } set { _CheckListBoxes = value; } } private vlnText _TopMessage; public vlnText TopMessage { get { return _TopMessage; } set { _TopMessage = value; } } private List _TopMessageRs=new List(); // Added if there are 2 messages, in AER AND RNO (for BGE) public List TopMessageRs { get { return _TopMessageRs; } set { _TopMessageRs = value; } } private List _TopMessageSub1s=new List(); // BGE Alarms: in CONDITION/RESPONSE if break within substep public List TopMessageSub1s { get { return _TopMessageSub1s; } set { _TopMessageSub1s = value; } } private List _TopMessageSub2s=new List(); // BGE Alarms: in CONDITION/RESPONSE if break within substep public List TopMessageSub2s { get { return _TopMessageSub2s; } set { _TopMessageSub2s = value; } } private List _BottomMessage = new List(); // B2017-203) any continuous sections with end messages may have more than 1 message on a page public List BottomMessage { get { return _BottomMessage; } set { _BottomMessage = value; } } private vlnText _BottomMessageR; // Added if there are 2 messages, in AER AND RNO (for BGE) public vlnText BottomMessageR { get { return _BottomMessageR; } set { _BottomMessageR = value; } } private vlnText _BottomMessageA; // Added if there are 3 messages, at bottom AND in AER AND RNO (for BGEALARMS) public vlnText BottomMessageA { get { return _BottomMessageA; } set { _BottomMessageA = value; } } private Dictionary> _NotesToFootNotesHLS = new Dictionary>(); public Dictionary> NotesToFootNotesHLS { get { return _NotesToFootNotesHLS; } set { _NotesToFootNotesHLS = value; } } private List _NotesToFootNotes = new List(); public List NotesToFootNotes { get { return _NotesToFootNotes; } set { _NotesToFootNotes = value; } } private float _NotesToFootNotesYoffset = 0; public float NotesToFootNotesYoffset { get { return _NotesToFootNotesYoffset; } set { _NotesToFootNotesYoffset = value; } } Dictionary _MyParagraphs = new Dictionary(); public Dictionary MyParagraphs { get { return _MyParagraphs; } set { _MyParagraphs = value; } } float _YMultiplier = 1; public float YMultiplier { get { return _YMultiplier; } set { _YMultiplier = value; } } float _PhoneListHeight = 0; public float PhoneListHeight { get { return _PhoneListHeight; } set { _PhoneListHeight = value; } } private float _AlarmYoffStart = 0; public float AlarmYoffStart { get { return _AlarmYoffStart; } set { _AlarmYoffStart = value; } } private float _AlarmYoffEnd = 0; public float AlarmYoffEnd { get { return _AlarmYoffEnd; } set { _AlarmYoffEnd = value; } } private float _SectionSepLineYoffStart = 0; public float SectionSepLineYoffStart { get { return _SectionSepLineYoffStart; } set { _SectionSepLineYoffStart = value; } } private PdfWriter _MyPdfWriter; public PdfWriter MyPdfWriter { get { return _MyPdfWriter; } set { MyPageCounts = new PageCounts(); MyTOCPageCounts = new PageCounts(); MyTOCPageNums = new Dictionary(); _MyPdfWriter = value; } } private PdfContentByte _MyPdfContentByte; public PdfContentByte MyPdfContentByte { get { return _MyPdfContentByte; } set { _MyPdfContentByte = value; } } private int _FinalMessageSectionID; public int FinalMessageSectionID { get { return _FinalMessageSectionID; } set { _FinalMessageSectionID = value; } } private bool _DidFirstPageDocStyle = false; public bool DidFirstPageDocStyle { get { return _DidFirstPageDocStyle; } set { _DidFirstPageDocStyle = value; } } public override void OnCloseDocument(PdfWriter writer, iTextSharp.text.Document document) { AddBookmarks(writer); MyPageCounts.DrawTemplates(); } private bool _OnBlankPage = false; public bool OnBlankPage // used while inserting a blank page when printing a procedure with duplex foldouts { get { return _OnBlankPage; } set { _OnBlankPage = value; } } // when false, no page has been printed yet (for determining whether a blank page before print // needs done if first section has foldouts) private bool _PrintedAPage = false; public bool PrintedAPage { get { return _PrintedAPage; } set { _PrintedAPage = value; } } // the following two variables are used to handle the 'PSOnlyFirst' page list Justify flag. // PSOnlyFirst signals that the pagelist token should only be processed for the first page of // the section. It gets set when this token is processed, so that any remaining pages will // not get the token. It's value is derived by taking the different the location of this token // & the location of the previous token, so that this amount can be used to move the text up // on the 'not first' pages of the section. It's used as an adjustment on the topmargin. // This is used in FNP formats. private int _sectLevelNumTtlDiff = 0; private int _PrintedSectionPage = 0; public int PrintedSectionPage { get { return _PrintedSectionPage; } set { _PrintedSectionPage = value; } } private static int _CountInApplProcs; // B2021-127: BNPPalr - Auto set of serial # public static int CountInApplProcs { get { return _CountInApplProcs; } set { _CountInApplProcs = value; } } //private bool _AddBlankPagesForDuplexPrinting = false; //public bool AddBlankPagesForDuplexPrinting // Tells us if a the option to add a blank page is turn on (for procedures with duplex foldouts) //{ // get { return _AddBlankPagesForDuplexPrinting; } // set { _AddBlankPagesForDuplexPrinting = value; } //} private int _prevSectId = 0; public override void OnEndPage(PdfWriter writer, iTextSharp.text.Document document) { TableAdjustment = 0;// RHM20150525 - Table Scrunch //string path = Volian.Base.Library.vlnStackTrace.StackToStringLocal(3, 1); //Console.WriteLine("End {0}",path); int profileDepth = ProfileTimer.Push(">>>> OnEndPage"); InitialsPrinted = false; MyPromsPrinter.OnStatusChanged(string.Format("Page {0}", CurrentPageNumber+1)); // B2019-152: Landscape page merged page numbers if (this.MySection != null && MySection.MyDocStyle.LandscapePageList) PromsPrinter.AddMergedLandscapePage(this, MyPromsPrinter.PDFFile); bool onBlankPage = OnBlankPage; if (OnBlankPage) { OnBlankPage = false; } else if (!OnFoldoutPage) { if (DidFirstPageDocStyle) SetDocStyleAndValues(); AddBookmarks(writer); MyPageCounts.CanIncrement = true; base.OnEndPage(writer, document); DrawFootnotes(writer.DirectContent); DrawChangeBars(writer.DirectContent); DrawMessages(writer.DirectContent); if (!CreatingFoldoutPage && !CreatingSupInfoPage) { DrawRuler(writer.DirectContent); float x = MySection == null ? 555 : (float)MySection.MyDocStyle.Layout.PageWidth; DrawBottomRuler(writer.DirectContent, x / 2 - 144); //aer column DrawBottomRuler(writer.DirectContent, x - 144); //rno column } } else { E_NumberingSequence numseq = MySection.MyDocStyle.NumberingSequence??0; // if a foldout is only printing within its section, don't do increments on pagecounts: if (numseq==E_NumberingSequence.WithinEachSection) MyPageCounts.CanIncrement = false; else MyPageCounts.CanIncrement = true; base.OnEndPage(writer, document); if (!CreatingFoldoutPage && !CreatingSupInfoPage) DrawRuler(writer.DirectContent); } // added the check for onBlankPage and Foldouts to fix bug found in V.C. Summer auto table of contents - 03/08/2016 //C2019-042 Section_IsFoldout checks Section Number, Section Title, and use of check box if (!onBlankPage && (MySection.MyDocStyle.StructureStyle.Style==null || (MySection.MyDocStyle.StructureStyle.Style & E_DocStructStyle.DontCountInTabOfCont) == 0) && !(MySection.ActiveFormat.PlantFormat.FormatData.PrintData.SectionLevelFoldouts && (MySection.MyConfig as SectionConfig).Section_IsFoldout == "Y")) CurrentTOCPageNumber++; if (MySection.ActiveFormat.PlantFormat.FormatData.SectData.PrintPhoneList) { SectionConfig sc = MySection.MyConfig as SectionConfig; if (sc.Section_PhoneList != null && sc.Section_PhoneList == "Y") { // yoffset the footer length + the size of the phone list: float yoff = (float)MySection.MyDocStyle.Layout.FooterLength + PhoneListHeight + 12; // 12 is an extra line for the horizontal. DocVersionConfig dvc = MySection.MyDocVersion.MyConfig as DocVersionConfig; if (dvc != null) DrawPhoneList(writer.DirectContent, (float)MySection.MyDocStyle.Layout.LeftMargin, (float)MySection.MyDocStyle.Layout.PageWidth, yoff, dvc.Print_PhoneList); } } if (MySection.MyDocStyle.CenterLineX != null && !onBlankPage) { if ((MySection.MyDocStyle.StructureStyle.Style & E_DocStructStyle.DoubleBoxHLS) == E_DocStructStyle.DoubleBoxHLS) DrawHorizontal(writer.DirectContent, (float)MySection.MyDocStyle.Layout.LeftMargin, (float)MySection.MyDocStyle.Layout.PageWidth, (float)MySection.MyDocStyle.CenterLineYTop); //if (MySection.ColumnMode > 0 && onBlankPage == false) if (MySection.ColumnMode > 0 || MySection.ActiveFormat.PlantFormat.FormatData.PrintData.WCNTraining) { DrawCenterLine(writer.DirectContent, MySection.MyDocStyle.Layout.LeftMargin + MySection.MyDocStyle.CenterLineX ?? 0, MySection.MyDocStyle.CenterLineYTop ?? 0, MySection.MyDocStyle.CenterLineYBottom ?? 0); if (MySection.ActiveFormat.PlantFormat.FormatData.PrintData.WCNTraining) { // only draw the line if this is a new section. if (MySection.ItemID != _prevSectId) DrawHorizontal(writer.DirectContent, (float)(MySection.ActiveFormat.PlantFormat.FormatData.SectData.SectionHeaderSeparatorLine.XStartPos ?? 0), (float)(MySection.ActiveFormat.PlantFormat.FormatData.SectData.SectionHeaderSeparatorLine.Length ?? 0), SectionSepLineYoffStart); _prevSectId = MySection.ItemID; } } } if (MySection.ActiveFormat.PlantFormat.FormatData.PrintData.SpecialCaseCalvertAlarm) { float left = (float)MySection.MyDocStyle.Layout.LeftMargin + 4.40f - 6; // used 4.40 -6 to line up with the macro & not touch two digit sub-step tabs. float right = (float)MySection.MyDocStyle.Layout.PageWidth - .76f; // used -.76 to make bge alarm lines closest to lining up with macro if (AlarmYoffStart > 0) { // draw vertical - either to the alarmyoffend or bottom of page if (AlarmYoffEnd > 0) // ends on this page. { DrawVertical(writer.DirectContent, left, AlarmYoffStart, AlarmYoffEnd); DrawVertical(writer.DirectContent, right, AlarmYoffStart, AlarmYoffEnd); DrawVertical(writer.DirectContent, (right + left) / 2, AlarmYoffStart, AlarmYoffEnd); DrawHorizontal(writer.DirectContent, left, right, AlarmYoffEnd); AlarmYoffStart = 0; AlarmYoffEnd = 0; } else { float yBottom = (float)(writer.DirectContent.PdfWriter.PageSize.Height - ((float)MySection.MyDocStyle.Layout.TopMargin + (float)MySection.MyDocStyle.Layout.PageLength)); DrawVertical(writer.DirectContent, left, AlarmYoffStart, yBottom); DrawVertical(writer.DirectContent, right, AlarmYoffStart, yBottom); DrawVertical(writer.DirectContent, (right + left) / 2, AlarmYoffStart, yBottom); DrawHorizontal(writer.DirectContent, left, right, yBottom); AlarmYoffStart = (float)writer.DirectContent.PdfWriter.PageSize.Height - (float)MySection.MyDocStyle.Layout.TopMargin; } } } PageListTopCheckOffHeader = null; PageListLastCheckOffHeader = null; BottomContent = null; YMultiplier = 1; PrintedAPage = true; ProfileTimer.Pop(profileDepth); } private void DrawBottomRuler(PdfContentByte cb, float x) { VlnSvgPageHelper myPageHelper = cb.PdfWriter.PageEvent as VlnSvgPageHelper; if (myPageHelper.DebugLayer != null) { cb.BeginLayer(myPageHelper.DebugLayer); cb.SaveState(); cb.SetLineWidth(.1F); cb.SetColorStroke(new Color(System.Drawing.Color.Plum)); float height = 350; float yTop = 350; float yBottom = yTop - height; cb.MoveTo(x, yTop); cb.LineTo(x, yBottom); if (myPageHelper.BottomContent != null) { cb.MoveTo(0, (float)myPageHelper.BottomContent); cb.LineTo(PDFPageSize.PaperSizePoints(MySection.ActiveFormat.PlantFormat.FormatData.PDFPageSize.PaperSize), (float)myPageHelper.BottomContent); // C2020-002 paper size is now set in the format files } int i = 0; for (float y = yBottom; y <= yTop; y += 12) { float w = 10; if (i % 6 == 0) w = 30; else if (i % 3 == 0) w = 20; cb.SetLineWidth(w / 30); i++; cb.MoveTo(x + w, y); cb.LineTo(x, y); cb.Stroke(); } for (float y = yBottom; y <= yTop; y += 10) { float w = 10; if (i % 10 == 0) w = 30; else if (i % 5 == 0) w = 20; cb.SetLineWidth(w / 30); i++; cb.MoveTo(x - w, y); cb.LineTo(x, y); cb.Stroke(); } i = 0; cb.Stroke(); cb.RestoreState(); cb.EndLayer(); } } private void DrawVertical(PdfContentByte cb, float x, float top, float bottom) { cb.SaveState(); if (PageListLayer != null) cb.BeginLayer(PageListLayer); cb.SetColorStroke(new Color(PrintOverride.SvgColor)); cb.SetLineWidth(1.05f); // Tweak the line width to match vlnmacro //cb.SetColorStroke(lineColor); cb.MoveTo(x, top); cb.LineTo(x, bottom); cb.Stroke(); if (PageListLayer != null) cb.EndLayer(); cb.RestoreState(); } private void DrawPhoneList(PdfContentByte pdfContentByte, float leftMargin, float pageWidth, float yOff, string plist) { // draw the line above the phone list: yOff = yOff + 4; // move up 1/2 line: DrawHorizontal(pdfContentByte, leftMargin, pageWidth, yOff); pdfContentByte.SaveState(); if (PageListLayer != null) pdfContentByte.BeginLayer(PageListLayer); pdfContentByte.SetColorStroke(new Color(PrintOverride.SvgColor)); // for each line, break it into phone items for printing. Note that 16bit code also supported // a tabbing line - BGE wasn't using this in data at time of development. The following code may // need expanded to support the tabbing/column definitions if this is found in data. float lyoff = yOff - 4; plist = plist.Replace("\r", ""); string[] lines = plist.Split("\n".ToCharArray()); DocStyle docstyle = MySection.MyDocStyle; try { foreach (string clinex in lines) { string cline = clinex.TrimEnd(); if (cline != "") { // xoff handles the columns. The separator between phone items is a double space. A phone // item may have a single space within it (this comes from 16bit implementation) float xoff = (float)docstyle.Layout.LeftMargin; int stLineindx = 0; int endLineindx = cline.IndexOf(" "); bool endOfLine = false; while (!endOfLine) { if (endLineindx - stLineindx > 0) { string phone = cline.Substring(stLineindx, endLineindx - stLineindx); float tmp = 0; vlnText vt = new vlnText(pdfContentByte, null, phone, phone, xoff, lyoff, MySection.ActiveFormat.PlantFormat.FormatData.Font); vt.ToPdf(pdfContentByte, 0, ref tmp, ref tmp); xoff += 132; // columns in 16bit were a little more than 1 3/4 inches. stLineindx = endLineindx; if (stLineindx >= cline.Length) break; while (cline[stLineindx] == ' ' && stLineindx < cline.Length) stLineindx++; if (stLineindx >= cline.Length - 1) endOfLine = true; else { endLineindx = cline.IndexOf(" ", stLineindx); if (endLineindx == -1) endLineindx = cline.Length; } } else endOfLine = true; } lyoff = lyoff - vlnPrintObject.SixLinesPerInch; } } } catch (Exception ex) { _MyLog.Error("Error processing phone list.", ex); } if (PageListLayer != null) pdfContentByte.EndLayer(); pdfContentByte.RestoreState(); } private void DrawHorizontal(PdfContentByte cb, float left, float right, float yoff) { // if there are gaps, check to be sure top isn't a double line box. If it's a box, don't draw the top line. if (MyGaps != null && MyGaps.Count > 0 && MyGaps[0].YTop == (float)MySection.MyDocStyle.CenterLineYTop) return; cb.SaveState(); if (PageListLayer != null) cb.BeginLayer(PageListLayer); cb.SetColorStroke(new Color(PrintOverride.SvgColor)); if (MySection.MyDocStyle.CLineWidth != null && MySection.MyDocStyle.CLineWidth != 0) cb.SetLineWidth((float)MySection.MyDocStyle.CLineWidth); //cb.SetColorStroke(lineColor); // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine("HorzLn X1={0} Y={1} X2={2}", left, yoff, right); cb.MoveTo(left, yoff); cb.LineTo(right, yoff); cb.Stroke(); if (PageListLayer != null) cb.EndLayer(); cb.RestoreState(); } private Gaps _MyGaps; public Gaps MyGaps { get { if (_MyGaps == null) _MyGaps = new Gaps(); return _MyGaps; } } public void AddGap(float top, float bottom, float left, float right) { float center = MySection.MyDocStyle.Layout.LeftMargin + MySection.MyDocStyle.CenterLineX ?? 0; if(center == 0) return; if (center > right || center < left) return; MyGaps.Add(top, bottom); } private void DrawCenterLine(PdfContentByte cb, float xLoc, float yTop, float yBottom) { //iTextSharp.text.Color lineColor = new iTextSharp.text.Color(PrintOverride.OverrideTextColor(System.Drawing.Color.DarkOrange)); cb.SaveState(); if (PageListLayer != null) cb.BeginLayer(PageListLayer); float lwidth = MySection.MyDocStyle.CLineWidth ?? .95f; cb.SetLineWidth(lwidth); cb.SetColorStroke(new Color(PrintOverride.SvgColor)); //cb.SetColorStroke(lineColor); cb.MoveTo(xLoc, yTop); float ylast = yTop; if (_MyGaps != null) { foreach (Gap gap in MyGaps) { // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine("CntrLn X={0} Top={1} Btm={2}", xLoc, ylast, gap.YTop - (gap.YTop - gap.YBottom) * YMultiplier); cb.LineTo(xLoc, gap.YTop); cb.MoveTo(xLoc, gap.YTop - (gap.YTop - gap.YBottom) * YMultiplier); ylast = gap.YTop - (gap.YTop - gap.YBottom) * YMultiplier; } _MyGaps = null; } // put in for V.C. Summer // the end message for EOP procedure 15.2 was at the very bottom of the page. // the remaining center line was drawn past the page boarder. there was no need // to print it for cases like that if (ylast > yBottom) { // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine("CntrLn X={0} Top={1} Btm={2}", xLoc, ylast, yBottom); cb.LineTo(xLoc, yBottom); } cb.Stroke(); if (PageListLayer != null) cb.EndLayer(); cb.RestoreState(); } private bool SetDocStyleAndValues() { // if this document style has another style that is for pages other than first, we need to // reset the document style off of this section AND reset docstyle values used // AND reset the 'svg' data. bool forceLoadSvg = false; if ((MySection.MyDocStyle.StructureStyle.Where & E_DocStyleUse.UseOnFirstPage) > 0) { //Console.WriteLine("{0} ResetDocStyleAndValues", MySection.MyDocStyle.Name); ItemInfo ii = (ItemInfo) MySection; int indx = (int)MySection.MyDocStyle.IndexOtherThanFirstPage; foreach (DocStyle ds in ii.ActiveFormat.PlantFormat.DocStyles.DocStyleList) { if (ds.Index == indx) { MySection.MyDocStyle = ds; forceLoadSvg = true; break; } } } return forceLoadSvg; } public void ResetSvg() { Volian.Svg.Library.Svg sectSvg = BuildSvg(_MySection, true); if (sectSvg != null) MySvg = sectSvg; } private float? _YTopMargin = null; public float? YTopMargin { get { return _YTopMargin - _AdjustTopMarginForMultiLinePageListItems; } set { _YTopMargin = value; } } private void DrawRuler(PdfContentByte cb) { if (DebugLayer == null) return; Layout layout = MySection.MyDocStyle.Layout; cb.SaveState(); cb.BeginLayer(DebugLayer); float x = (cb.PdfWriter.PageSize.Left + cb.PdfWriter.PageSize.Right) / 2; cb.SetLineWidth(.1F); cb.SetColorStroke(new Color(System.Drawing.Color.CornflowerBlue)); float yTop = (float)(cb.PdfWriter.PageSize.Height - layout.TopMargin); //Console.WriteLine("Page,yTop,yTopMargin {0},{1},{2}", cb.PdfDocument.PageNumber, yTop, YTopMargin); if(YTopMargin != null) yTop = (float)YTopMargin; float yBottom = (float)(cb.PdfWriter.PageSize.Height - (layout.TopMargin + layout.PageLength)); //Console.WriteLine("'{0}',{1},{2}", MySection.MyDocStyle.Name, yTop, yBottom); cb.MoveTo(x, yTop); cb.LineTo(x, yBottom); int i = 0; for (float y = yTop; y >= yBottom; y -= 12) { float w = 10; if (Volian.Base.Library.VlnSettings.GetCommandFlag("InchRuler")) { if (i % 6 == 0) w = 30; else if (i % 3 == 0) w = 20; } else { if (i % 10 == 0) w = 30; else if (i % 5 == 0) w = 20; } cb.SetLineWidth(w / 30); i++; cb.MoveTo(x - w, y); cb.LineTo(x, y); cb.Stroke(); } i = 0; for (float y = yTop; y >= yBottom; y -= 10.1F) { float w = 10; if (Volian.Base.Library.VlnSettings.GetCommandFlag("InchRuler")) { if (i % 7 == 0) w = 30; //else if (i % 5 == 0) w = 20; } else { if (i % 10 == 0) w = 30; else if (i % 5 == 0) w = 20; } cb.SetLineWidth(w / 30); i++; cb.MoveTo(x + w, y-1); cb.LineTo(x, y-1); cb.Stroke(); } cb.SetLineWidth(.1F); cb.Rectangle((float)layout.LeftMargin, yTop, (float)layout.PageWidth - (float)layout.LeftMargin, yBottom - yTop); float yFooter = yBottom+(float)layout.FooterLength; cb.MoveTo((float)layout.LeftMargin,yFooter); cb.LineTo((float)layout.PageWidth, yFooter); float yRuler = 612; cb.MoveTo(0, yRuler); cb.LineTo(612, yRuler); for (float x1 = 0; x1 < 612; x1 += 6) // tic marks every 1/12 inch { if (x1 % 72 == 0) { cb.MoveTo(x1, yRuler-20); cb.LineTo(x1, yRuler+20); } else if (x1 % 36 == 0) { cb.MoveTo(x1, yRuler-10); cb.LineTo(x1, yRuler+10); } else { cb.MoveTo(x1, yRuler-5); cb.LineTo(x1, yRuler); } } for (float x1 = 0; x1 < 612; x1 += 7.2f) // tic marks every 1/10 inch { if (x1 % 72 == 0) { cb.MoveTo(x1, yRuler); cb.LineTo(x1, yRuler + 20); } else if (x1 % 36 == 0) { cb.MoveTo(x1, yRuler); cb.LineTo(x1, yRuler + 10); } else { cb.MoveTo(x1, yRuler); cb.LineTo(x1, yRuler + 5); } } //cb.MoveTo(122.4F, 0); //WCN2 HLS //cb.LineTo(122.4F, cb.PdfWriter.PageSize.Height); //cb.MoveTo(78, 0); // HLP HLS //cb.LineTo(78, cb.PdfWriter.PageSize.Height); //cb.MoveTo(441, 0); // HLP cover page date //cb.LineTo(441, cb.PdfWriter.PageSize.Height); //cb.MoveTo(71.4F, 0); // WCN Purpose page, Revision: {REV} //cb.LineTo(71.4F, cb.PdfWriter.PageSize.Height); cb.Stroke(); cb.EndLayer(); cb.RestoreState(); } private void AddBookmarks(PdfWriter writer) { foreach (PageBookmark pb in PageBookmarks) { int lev = pb.Level; if (MyPdfOutlines.Count < lev || lev==0) { PdfDestination dest = new PdfDestination(PdfDestination.FIT); PdfOutline pdo = new PdfOutline(writer.DirectContent.RootOutline, dest, pb.Title, false); if (MyPdfOutlines.Count == lev) MyPdfOutlines.Add(pdo); else MyPdfOutlines[lev] = pdo; } else { PdfDestination dest =pb.PdfDestination; if(dest==null) dest = new PdfDestination(PdfDestination.FIT); PdfOutline pdo = new PdfOutline(MyPdfOutlines[lev-1], dest,Regex.Replace(pb.Title, @"\\{Prerequisite Step: .*?\\}", ""), false); if (MyPdfOutlines.Count == lev) MyPdfOutlines.Add(pdo); else MyPdfOutlines[lev] = pdo; } } PageBookmarks.Clear(); } private void DrawFootnotes(PdfContentByte cb) { float tmp = 0; if (NotesToFootNotes != null && NotesToFootNotes.Count > 0) { float _PointsPerPage = (float)PDFPageSize.PaperSizePoints(MySection.ActiveFormat.PlantFormat.FormatData.PDFPageSize.PaperSize); // C2020-002 paper size is now set in the format files float yTopMargin = _PointsPerPage - (float)MySection.MyDocStyle.Layout.TopMargin; float myYOff = NotesToFootNotesYoffset; foreach (vlnParagraph ntfn in NotesToFootNotes) { // subtract from yTopMargin to take the location from the 'roll of paper' // to the physical page location. ntfn.YOffset = yTopMargin - myYOff; ntfn.YTopMost = yTopMargin - myYOff; ntfn.Processed = false; // process from here // Only use ParagraphToPdf for printing of a single step. // This is assuming that footnotes do not have child steps. ntfn.ParagraphToPdf(cb, yTopMargin, yTopMargin, tmp); //ntfn.ToPdf(cb, yTopMargin, ref yTopMargin, ref tmp); myYOff -= (ntfn.Height); // - vlnPrintObject.SixLinesPerInch); } NotesToFootNotes = null; } } private void DrawMessages(PdfContentByte cb) { float tmp = 0; if (TopMessage != null) { TopMessage.ToPdf(cb, 0, ref tmp, ref tmp); TopMessage = null; // Only output it once. } if (TopMessageRs != null && TopMessageRs.Count > 0) { foreach (vlnText vt in TopMessageRs) { vt.ToPdf(cb, 0, ref tmp, ref tmp); } TopMessageRs = null; // Only output it once. } if (TopMessageSub1s != null) { foreach (vlnText vts1 in TopMessageSub1s) { vts1.YOffset = AlarmYoffStart - 3 * vlnPrintObject.SixLinesPerInch; vts1.ToPdf(cb, 0, ref tmp, ref tmp); } TopMessageSub1s = null; // Only output it once. } if (TopMessageSub2s != null) { foreach (vlnText vts2 in TopMessageSub2s) { vts2.YOffset = AlarmYoffStart - 3 * vlnPrintObject.SixLinesPerInch; vts2.ToPdf(cb, 0, ref tmp, ref tmp); } TopMessageSub2s = null; // Only output it once. } if (BottomMessage != null && BottomMessage.Count != 0) { foreach (vlnText vts3 in BottomMessage) { vts3.ToPdf(cb, 0, ref tmp, ref tmp); } BottomMessage.Clear(); // Only output it once. } if (BottomMessageR != null) { BottomMessageR.ToPdf(cb, 0, ref tmp, ref tmp); BottomMessageR = null; // Only output it once. } if (BottomMessageA != null) { BottomMessageA.ToPdf(cb, 0, ref tmp, ref tmp); BottomMessageA = null; // Only output it once. } } public void DrawBottomMessage(PdfContentByte cb) { float tmp = 0; if (BottomMessage != null && BottomMessage.Count != 0) { foreach (vlnText vts in BottomMessage) { vts.ToPdf(cb, 0, ref tmp, ref tmp); } BottomMessage.Clear(); // Only output it once. } } private void DrawChangeBars(PdfContentByte cb) { float tmp = 0; // B2022-060 Prairie Island Alarms, change bars on second page of Alarm Point would sometimes be printed to far down the page // The TopMargin setting of the first page is different than the second page and needed to be passed in to ToPDF for change bars float topMargin = (float)MySection.MyDocStyle.Layout.TopMargin; foreach (vlnChangeBar vcb in MyChangeBars) { // TODO: Pass in zeroes because topdf is inherited. vcb.ToPdf(cb, topMargin, ref tmp, ref tmp); } _MyChangeBars = new List(); } #region SectionLevelData private ChangeBarDefinition _ChangeBarDefinition; public ChangeBarDefinition ChangeBarDefinition { get { return _ChangeBarDefinition; } set { _ChangeBarDefinition = value; } } #endregion private PdfLayer _TextLayer; public PdfLayer TextLayer { get { return _TextLayer; } set { _TextLayer = value; } } private PdfLayer _DebugLayer; public PdfLayer DebugLayer { get { return _DebugLayer; } set { _DebugLayer = value; } } private VEPROMS.CSLA.Library.SectionInfo _MySection; public VEPROMS.CSLA.Library.SectionInfo MySection { get { return _MySection; } set { _MySection = value; MySectionTitle = ((_MySection.DisplayNumber ?? "")=="" ? "" : _MySection.DisplayNumber + " - ") + _MySection.DisplayText; bool forceLoadSvg = false; if (value.SectionConfig.Section_Pagination == SectionConfig.SectionPagination.Separate && value.MyDocStyle.ResetFirstPageOnSection) DidFirstPageDocStyle = false; if (DidFirstPageDocStyle) forceLoadSvg = SetDocStyleAndValues(); // this method also gets the SVG (the 'else' part of this) Volian.Svg.Library.Svg sectSvg = BuildSvg(_MySection, forceLoadSvg); if (sectSvg != null) MySvg = sectSvg; _YTopMargin = null; } } private string _MySectionTitle; public string MySectionTitle { get { return _MySectionTitle; } set { _MySectionTitle = value; } } private int _MaxRNO; public int MaxRNO { get { return _MySection.ColumnMode; } } private int _CurrentPageOf = 0; public int CurrentPageOf { get { return _CurrentPageOf; } set { _CurrentPageOf = value; } } private string _Rev = string.Empty; public string Rev { get { return _Rev; } set { _Rev = value; } } private string _RevDate = string.Empty; public string RevDate { get { return _RevDate; } set { _RevDate = value; } } private bool _DoFloatingFoldout = true; public bool DoFloatingFoldout { get { return _DoFloatingFoldout; } set { _DoFloatingFoldout = value; } } private List _MyChangeBars = new List(); public List MyChangeBars { get { return _MyChangeBars; } set { _MyChangeBars = value; } } public void AddChangeBar(vlnChangeBar vcb, string cbmess) { if (vcb == null) return; vlnChangeBar prevCB = null; foreach (vlnChangeBar cb in MyChangeBars) { // only look at changebars in same column if (cb.XOffset == vcb.XOffset) { // if the two change bars end at same location, set prevCB which will // adjust the length (top position) of the change bar. This condition // also flags that the change bar texts overlap. if (cb.YChangeBarBottom == vcb.YChangeBarBottom) prevCB = cb; // continuous case, if changes bars overlap, adjust size and don't add new one to // the MyChangeBars list. if (MySection.ActiveFormat.PlantFormat.FormatData.ProcData.ChangeBarData.ContinuousChangeBars || MySection.ActiveFormat.PlantFormat.FormatData.ProcData.ChangeBarData.ChangeIds) { if (OverlapOrSpan(cb, vcb)) { if (prevCB == null) prevCB = cb; else if (prevCB.YChangeBarBottom > cb.YChangeBarBottom) prevCB = cb; cb.BottomIsTable = (vcb.MyParent.MyItemInfo.IsTable); } } } } // if this and the prevCB overlap, adjust yoffset/height/ybottom in the prevCB so that both change bars are // included in this Dictionary item. A new vlnChangeBar is not added to the MyChangeBars list, the current // one that overlaps with the new is adjusted. if (prevCB != null) { // Bottom for both change bars is same, adjust top (YOffset) and height. if (prevCB.YChangeBarBottom == vcb.YChangeBarBottom) { prevCB.YOffset = Math.Max(prevCB.YOffset, vcb.YOffset); float yChangeBarBottomExtend = prevCB.YChangeBarBottomExtend; prevCB.Height = Math.Max(prevCB.Height, vcb.Height); prevCB.YExtendLine = prevCB.YChangeBarBottom - Math.Min(yChangeBarBottomExtend, vcb.YChangeBarBottomExtend); //Math.Max(prevCB.YExtendLine, vcb.YExtendLine); // if a change bar message at this ychangebarbottom exists, see which message is used if (cbmess != null && prevCB.Messages.ContainsKey(prevCB.YChangeBarBottom)) UpdateCbMessage(cbmess, prevCB, vcb.XOffset); return; } // Bottom locations are not the same, but another change bar is not added, i.e. the // length of the line is adjusted. prevCB.YOffset = Math.Max(prevCB.YOffset, vcb.YOffset); float yChangeBarBottomExtend1 = prevCB.YChangeBarBottomExtend; prevCB.YChangeBarBottom = Math.Min(prevCB.YChangeBarBottom, vcb.YChangeBarBottom); prevCB.YExtendLine = prevCB.YChangeBarBottom - Math.Min(yChangeBarBottomExtend1, vcb.YChangeBarBottomExtend); //Math.Max(prevCB.YExtendLine, vcb.YExtendLine); // Two messages at this location, determine which one to use if (cbmess != null && prevCB.Messages.ContainsKey(prevCB.YChangeBarBottom)) UpdateCbMessage(cbmess, prevCB, vcb.XOffset); // no message at this location, just add it. else if (cbmess != null) prevCB.Messages.Add(vcb.YChangeBarBottom, new vlnChangeBarMessage(vcb.MyParent.XOffset, cbmess)); return; } // There was no overlap, add a message if it exists, and then add the change bar to the MyChangeBars list. if (cbmess != null) vcb.Messages.Add(vcb.YChangeBarBottom, new vlnChangeBarMessage(vcb.MyParent.XOffset, cbmess)); MyChangeBars.Add(vcb); } private static void UpdateCbMessage(string cbmess, vlnChangeBar prevCB, float xoff) { // If there are two messages at the same location, for example an AER change bar & and RNO // change bar, and the messages have different text, see which change bar message should be // added, i.e. use the one in 'rno', the greatest x value. vlnChangeBarMessage tmp = prevCB.Messages[prevCB.YChangeBarBottom]; if (cbmess != tmp.Message) { if (xoff > tmp.ParentX) { prevCB.Messages.Remove(prevCB.YChangeBarBottom); prevCB.Messages.Add(prevCB.YChangeBarBottom, new vlnChangeBarMessage(xoff, cbmess)); } } } private bool OverlapOrSpan(vlnChangeBar cb, vlnChangeBar vcb) { float tolerance = vlnPrintObject.SixLinesPerInch; if (cb.MyParent.MyItemInfo.ActiveFormat.PlantFormat.FormatData.PrintData.SpecialCaseCalvertAlarm && (vcb.MyParent.MyItemInfo.IsTable || cb.MyParent.MyItemInfo.IsTable || cb.BottomIsTable)) tolerance *= 1.5f; bool bothFootnotes = cb.MyParent.MyItemInfo.IsFootnote && vcb.MyParent.MyItemInfo.IsFootnote; if (!bothFootnotes && cb.MyParent.MyItemInfo.MyHLS != null && vcb.MyParent.MyItemInfo.MyHLS != null && cb.MyParent.MyItemInfo.MyHLS.ItemID != vcb.MyParent.MyItemInfo.MyHLS.ItemID) return false; // cb.Yoffset is within range of vcb: if (cb.YOffset <= vcb.YOffset && cb.YOffset >= (vcb.YChangeBarBottomExtend - tolerance)) return true; // cb.YChangeBarBottom is within range of vcb: if ((cb.YChangeBarBottomExtend - tolerance) <= vcb.YOffset && cb.YChangeBarBottomExtend >= (vcb.YChangeBarBottomExtend - tolerance)) return true; // vcb.Yoffset is within range of cb: if (vcb.YOffset <= cb.YOffset && vcb.YOffset >= (cb.YChangeBarBottomExtend - tolerance)) return true; // vcb.YChangeBarBottom is within range of cb: if ((vcb.YChangeBarBottomExtend - tolerance) <= cb.YOffset && vcb.YChangeBarBottomExtend >= (cb.YChangeBarBottomExtend - tolerance)) return true; return false; } private PromsPrinter _MyPromsPrinter; public PromsPrinter MyPromsPrinter { get { return _MyPromsPrinter; } set { _MyPromsPrinter = value; } } private int _MyRomanPage = 1; public VlnSvgPageHelper(VEPROMS.CSLA.Library.SectionInfo mySection, PromsPrinter myPromsPrinter, string hlsText, int hlsItemId) : base() { HLSText = hlsText; HasHLSTextId = hlsItemId; MyPromsPrinter = myPromsPrinter; MySection = mySection; } private Volian.Svg.Library.Svg BuildSvg(VEPROMS.CSLA.Library.SectionInfo mySection, bool forceLoad) { // if mysection uses continuous pagination, and the previous section uses the same format, // and the docstyle is set to use on first page only, // then set section to use the Use On Rest of Pages //SectionConfig.SectionPagination sPag = SectionConfig.SectionPagination.Separate; //if (mySection.IsStepSection && mySection.MyPrevious != null && mySection.MyPrevious.IsStepSection) //{ // SectionConfig sc = mySection.MyConfig as SectionConfig; // sPag = sc.Section_Pagination; // if (sPag == SectionConfig.SectionPagination.Continuous) // { // if (MySection.MyDocStyle.StructureStyle.Where == E_DocStyleUse.UseOnFirstPage) // MySection.DidFirstPageDocStyle = true; // } //} VEPROMS.CSLA.Library.FormatInfo activeFormat = mySection.ActiveFormat; VEPROMS.CSLA.Library.DocStyle docStyle = mySection.MyDocStyle; Volian.Svg.Library.Svg mySvg = null; // the following line fills in the svg/svggroup/svgparts for all that is defined in the genmac definition (svg for plant) mySvg = SvgSerializer.StringDeserialize(BuildMyText(activeFormat)); mySvg.ViewBox.Height = 1100; mySvg.ViewBox.Width = 850; mySvg.Height = new SvgMeasurement(11, E_MeasurementUnits.IN); mySvg.Width = new SvgMeasurement(8.5F, E_MeasurementUnits.IN); mySvg.LeftMargin = (float)docStyle.Layout.LeftMargin; mySvg.TopMargin = 9.6F; VEPROMS.CSLA.Library.PageStyle pageStyle = docStyle.pagestyle; HasInitials = false; PIInitials = null; AddPageListItems(mySvg, pageStyle, mySection, forceLoad); mySvg.ProcessText += new SvgProcessTextEvent(mySvg_ProcessText); // if this section had a previous section and this is continuous, don't generate the svg for // it, we'll use the previous section. The only thing we need to do is to process through the // pagelist items in case there are some section items, for example the checkoff header needs // to be processed for each section whether or not it is continuous. SectionConfig.SectionPagination sPag = SectionConfig.SectionPagination.Separate; //C2019-042 Section_IsFoldout checks Section Number, Section Title, and use of check box if ((mySection.MyConfig as SectionConfig).Section_IsFoldout != "Y" && mySection.IsStepSection && mySection.MyPrevious != null && mySection.MyPrevious.IsStepSection) { SectionConfig sc = mySection.MyConfig as SectionConfig; sPag = sc.Section_Pagination; } //if (sPag == SectionConfig.SectionPagination.Continuous && !mySection.DidFirstPageDocStyle) return null; if (forceLoad) return mySvg; if (sPag == SectionConfig.SectionPagination.Continuous) return null; return mySvg; } public PageCounts MyPageCounts = null; public PageCounts MyTOCPageCounts = null; public Dictionary MyTOCPageNums = null; private static Regex regexFindToken = new Regex("{[^{}]*}"); private static Regex regexFindSubToken = new Regex(@"\[[^{}]*\]"); private string mySvg_ProcessText(object sender, SvgProcessTextArgs args) { if (args.MyText == null) return string.Empty; // Needed for empty genmac text (was space in 16bit files) if (!args.MyText.Contains("{")) return args.MyText; /* * Check if tokens for handling page counts ({PAGE} {OF} etc). if so, do templates. */ if (args.MyText.Contains("{METACURPAGE}") || args.MyText.Contains("{METATOTPAGE}")) { ItemInfo top = MySection; while (top.MyParent != null && !top.MyParent.IsProcedure) { top = top.MyParent; } string key = "DocCurPage." + top.ItemID; string txt = args.MyText.Replace("{METACURPAGE}", "{PAGE}").Replace("{METATOTPAGE}", "{OF}"); MyPdfContentByte.AddTemplate(MyPageCounts.AddToTemplateList(key, MyPdfWriter, txt, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor), args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); return string.Empty; } if (args.MyText.Contains("{DOCCURPAGE}") || args.MyText.Contains("{DOCTOTPAGE}")) { string key = "DocCurPage." + MySection.ItemID; string txt = args.MyText.Replace("{DOCCURPAGE}", "{PAGE}").Replace("{DOCTOTPAGE}", "{OF}"); MyPdfContentByte.AddTemplate(MyPageCounts.AddToTemplateList(key, MyPdfWriter, txt, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor), args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); return string.Empty; } //if (args.MyText.Contains("{ROMANPAGE}")) //{ // //return args.MyText.Replace("{ROMANPAGE}", ItemInfo.RomanNumbering(_MyRomanPage++).ToLower()); // string key = "RomanPage." + MySection.ItemID; // string txt = args.MyText; // MyPdfContentByte.AddTemplate(MyPageCounts.AddToTemplateList(key, MyPdfWriter, txt, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor), args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); // return string.Empty; //} if (args.MyText.Contains("{SECONDARYPAGE}") || args.MyText.Contains("{SECONDARYOF}")) { string key = "SecondaryPage." + MySection.DisplayNumber; string txt = args.MyText.Replace("{SECONDARYPAGE}", "{PAGE}").Replace("{SECONDARYOF}", "{OF}"); MyPdfContentByte.AddTemplate(MyPageCounts.AddToTemplateList(key, MyPdfWriter, txt, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor), args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); return string.Empty; } //string tocKey = "TOC" + MySection.ItemID.ToString(); if (args.MyText.Contains("{PAGE}") || args.MyText.Contains("{OF}")) { #region numberingseq /* public enum E_NumberingSequence : uint { NoPageNum = 0, WithSteps = 1, Add to original steps section page count. WithinEachDocStyle = 2, WithinEachSection = 3, WithinEachDocStyle1 = 4, GroupedByPagination = 5, GroupedByLevel = 6, WithStepsAndSecondaryPageNumber = 7, WithStepsAndSecondaryPageNumberGroupedByLevel = 8, Like6_ButDoesntNeedSubsection = 9, Like6_ButDoesntNeedSubsection1 = 10 }; */ #endregion // default for the key is to make it NumberingSequence. Then handle // specific cases. string key = ((int)MySection.MyDocStyle.NumberingSequence).ToString(); E_NumberingSequence numseq = MySection.MyDocStyle.NumberingSequence??0; //Console.WriteLine("\"{0}\"\t\"{1}\"\t{2}", MySection.DisplayNumber, MySection.DisplayText, numseq); switch (numseq) { case E_NumberingSequence.GroupedByPagination: key = ((int)E_NumberingSequence.WithSteps).ToString(); break; case E_NumberingSequence.WithSteps: // Number with 'originalstepsection' ProcedureInfo pc = MySection.MyProcedure; int sectid = 0; foreach (SectionInfo si in pc.Sections) { SectionConfig sc = si.MyConfig as SectionConfig; if (sc.Section_OriginalSteps == "Y") { sectid = si.ItemID; break; } } if (sectid != 0) key = (int)E_NumberingSequence.WithinEachSection + "." + sectid; break; case E_NumberingSequence.WithinEachDocStyle: key = key + "." + MySection.ActiveFormat.FormatID + "." + MySection.MyDocStyle.Index; break; //case E_NumberingSequence.WithinEachDocStyle1: // key = key + "." + MySection.DisplayNumber; // break; case E_NumberingSequence.WithinEachSection: key = key + "." + MySection.ItemID; break; case E_NumberingSequence.WithinEachSectionNumber: key = key + "." + ( MySection.DisplayNumber == "" ? (MySection.ActiveParent as ItemInfo).DisplayNumber : MySection.DisplayNumber); break; case E_NumberingSequence.GroupedByLevel: case E_NumberingSequence.Like6_ButDoesntNeedSubsection: if (MySection.MyParent.IsSection) key = key + "." + MySection.MyParent.ItemID; else key = key + "." + MySection.ItemID; break; case E_NumberingSequence.WithStepsAndSecondaryPageNumber: // For this one, we'll do two keys and templates. One will go with the main steps // section and one will be for this secondary section. ProcedureInfo pc1 = MySection.MyProcedure; int psectid = 0; foreach (SectionInfo si in pc1.Sections) { SectionConfig sc = si.MyConfig as SectionConfig; if (sc.Section_OriginalSteps == "Y") { psectid = si.ItemID; break; } } if (psectid != 0) { key = (int)E_NumberingSequence.WithinEachSection + "." + psectid; PdfTemplate tmp1 = MyPageCounts.AddToTemplateList(key, MyPdfWriter, args.MyText, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor); } break; } PdfTemplate tmp = MyPageCounts.AddToTemplateList(key, MyPdfWriter, args.MyText, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor); // Proms page numbering designed requires a "{PAGE}" token to increment the page counter. So the easiest way // to do that was to add a "{PAGE}" token to every page that is flagged as not to be printed. if (!args.MyText.StartsWith("Non-printing ")) MyPdfContentByte.AddTemplate(tmp, args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); return string.Empty; } if (args.MyText.Contains("{FINALPAGE}")) { if (MySection.ItemID == FinalMessageSectionID) { string key = "FinalPage"; MyPdfContentByte.AddTemplate(MyPageCounts.AddToTemplateList(key, MyPdfWriter, args.MyText, MySection.MyDocStyle.Final.Message, args.MySvgText.Font, args.MySvgText.Align, args.MySvgText.FillColor), args.MySvgScale.X(args.MySvgText.X), args.MySvgScale.Y(MyPdfContentByte, args.MySvgText.Y)); } return string.Empty; } return regexFindToken.Replace(args.MyText, new MatchEvaluator(ReplacePageListToken)); } private string BuildMyText(VEPROMS.CSLA.Library.FormatInfo activeFormat) { string sGenMac = activeFormat.GenMac; FormatInfo fibase = activeFormat; // If this format has checkoffs (go through docstyles to see if any sections 'usecheckoffs'), then see if the ucf checkoffs are // defined in the format's genmac: string sGenMacBase = null; foreach (DocStyle ds in activeFormat.PlantFormat.DocStyles.DocStyleList) { if (ds.Inactive == false && ds.UseCheckOffs && !sGenMac.ToUpper().Contains("C100")) { while (fibase.FormatID != fibase.ParentID) fibase = fibase.MyParent; sGenMacBase = fibase.GenMac; if (sGenMacBase != null && sGenMacBase != "") { XmlDocument xDocGenMacBase = new XmlDocument(); xDocGenMacBase.LoadXml(sGenMacBase); sGenMacBase = xDocGenMacBase.DocumentElement.InnerXml; sGenMacBase = sGenMacBase.Replace("xmlns=\"http://www.w3.org/2000/svg\"", ""); // replace fonts with hls fontname & size string bsfontfamily = activeFormat.PlantFormat.FormatData.StepDataList[0].Font.Family; string bsfontsize = activeFormat.PlantFormat.FormatData.StepDataList[0].Font.Size.ToString(); sGenMacBase = sGenMacBase.Replace("{family}", bsfontfamily); sGenMacBase = sGenMacBase.Replace("{size}", bsfontsize); break; } } } if (sGenMac == null || sGenMac == "") { // If subformat and does not have its own genmac, find an inherited genmac. FormatInfo tmpf = FormatInfo.Get(activeFormat.ParentID); while (tmpf.FormatID!=1 && (sGenMac==null||sGenMac=="")) { sGenMac = tmpf.GenMac; tmpf = FormatInfo.Get(tmpf.ParentID); } if (sGenMac == null || sGenMac == "") sGenMac = ""; } if (sGenMacBase != null && sGenMacBase != "") { sGenMac = sGenMac.Replace("", sGenMacBase + ""); } if (!sGenMac.Contains("xmlns")) sGenMac = sGenMac.Replace(".StringSerialize(mySvg); XmlDocument xDocPrintout = new XmlDocument(); xDocPrintout.LoadXml(str); XmlNode xn = xDocPrintout.DocumentElement.ChildNodes[0]; xn.AppendChild(xDocPrintout.ImportNode(xDocGenMac.DocumentElement, true)); return xDocPrintout.OuterXml; } private string FirstAndLast(string token) { // strip the curly braces and return the first and last character // For example Header1 becomes H1 and Box2 becomes B2 return token.Substring(1, 1) + token.Substring(token.Length - 2, 1); } private static Regex regexJustTokens = new Regex(@"^{([^{}]*}{)*[^{}]*}$"); // The following variables are used to keep track of whether a check off header should be printed // if the {CHKOFFHEADING} pagelist item is found. PageListTopCheckOffHeader is the text that // should be printed at the top of the page. PageListLastCheckOffHeader is the last header that was // printed (if a header is on the page, and another is to be printed, it doesn't get printed if it // is the same as the previous) and PageListCheckOffHeader is the page list item converted to a // SvgText - this stores X/Y location, etc. public string PageListTopCheckOffHeader = null; public string PageListLastCheckOffHeader = null; public SvgText PageListCheckOffHeader = null; public Dictionary PgLogicals; private void AddPageListItems(Volian.Svg.Library.Svg mySvg, VEPROMS.CSLA.Library.PageStyle pageStyle, VEPROMS.CSLA.Library.SectionInfo section, bool forceLoad) { SectionConfig sc = section.MyConfig as SectionConfig; // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine("SecNum=\"{0}\" SecTitle=\"{1}\" DocStyle=\"{2}\" Format=\"{3}\" ItemID={4}", section.DisplayNumber, section.DisplayText, section.MyDocStyle.Name, sc.FormatSelection, section.ItemID); Volian.Base.Library.BaselineMetaFile.WriteLine(" Pagination=\"{0}\" MSWordPgCnt={1} NumPages={2} WordMargin={3}", sc.Section_Pagination, section.MSWordPageCount, (string.IsNullOrEmpty(sc.Section_NumPages)) ? "0" : sc.Section_NumPages, (string.IsNullOrEmpty(sc.Section_WordMargin))?"N":sc.Section_WordMargin); if (PgLogicals == null) PgLogicals = new Dictionary(); else PgLogicals.Clear(); PageListCheckOffHeader = null; // If this is a continuous section, then the only pagelist items we want are section type since // we are still on the same page. - CHECK IF ON SAME PAGE!!!! SectionConfig.SectionPagination sPag = SectionConfig.SectionPagination.Separate; //C2019-042 Section_IsFoldout checks Section Number, Section Title, and use of check box if (section.IsStepSection && section.MyPrevious != null && section.MyPrevious.IsStepSection && (section.MyConfig as SectionConfig).Section_IsFoldout != "Y") { SectionConfig sc1 = section.MyConfig as SectionConfig; sPag = sc1.Section_Pagination; } SvgGroup svgGroup = new SvgGroup(); //int defPtPerRow = 72 / 6; //int curLPI = 6; // default //int prevLPI = 6; //float PrevRow = 0; //float rowAdj = 0; // = 18; bool usePSIvalue = false; // C2021-065 used with ROLkUpMatch pagelist flag (Barakah Alarms) string otherChildUnit = ""; // C2021-065 used when OTHER applicability information is used for the ROLookUp foreach (VEPROMS.CSLA.Library.PageItem pageItem in pageStyle.PageItems) { if (pageItem.Token == null) continue; // can be null if token is dependent on PSI lookup! DidHLSText = false; // reset to false for this group of tokens. //if (pageItem.Token.Contains("HLSTEXT")) // Console.WriteLine("{0} - PageList Token", pageItem.Token); // the pagelist 'justify="{PSNotFirst}"' flag only puts item out if not on first page of section, check for this if (((pageItem.Justify & VEPROMS.CSLA.Library.E_Justify.PSNotFirst) == VEPROMS.CSLA.Library.E_Justify.PSNotFirst) && PrintedSectionPage == 0) { PrintedSectionPage++; continue; } VE_Font useFontForCheckOffHeader = null; if (forceLoad || (sPag == SectionConfig.SectionPagination.Separate || ((sPag == SectionConfig.SectionPagination.Continuous || sPag ==0 )&& (pageItem.Row < 0)))) { //if (PrevRow > 0) //{ // //float pgRow = (float)(pageItem.Row + rowAdj); // if (curLPI != prevLPI) // { // int prow = (int)(PrevRow / defPtPerRow); // int nrows = ((int)(pageItem.Row / defPtPerRow)) - prow; // rowAdj += (float)Math.Abs(((nrows * (72 / curLPI)) - ((nrows * defPtPerRow) + rowAdj))); // //rowAdj += (float)(((pgRow - PrevRow) / (72 * prevLPI)) * (72 / curLPI)); // prevLPI = curLPI; // } //} // C2019-006 - Moved and modified the RO_Lookup() logic here, before we process the tokens in the page list // this allows us to use RO_Lookup() in a "PS=" conditional token (is usually a PSI check box) // A while loop was also added to the we can have more than one call to RO_Lookup() on a pagelist line // this logic was put in for Barakah Alarms // Note that each Alarm is defined as its own RO in the Referenced Object database, with multiple return values // to define the Window ID, Alarm, Source, Setpoint, etc. for example. string pltok = pageItem.Token; while (pltok.Contains("RO_Lookup(")) { int idxstart = pltok.IndexOf("RO_Lookup("); int idxend = pltok.Substring(idxstart).IndexOf(")"); string ROLookupstr = pltok.Substring(idxstart, idxend + 1); string parms = ROLookupstr.Substring(10, ROLookupstr.Length - 11); MatchCollection sm = regexFindToken.Matches(parms); foreach (Match m in sm) // resolve pagelist tokens that are parameters for ROLookup() { string tnk = m.Value; ProcessPaglistToken(section, svgGroup, pageItem, ref useFontForCheckOffHeader, ref parms, tnk); } string[] parts = parms.Split(",".ToCharArray());// split on comma // B2019-031 Support commas embedded in Alarm ID (Procedure Number) // B2019-075: Added the check for commas in the procedure number - this code was causing a bug in other alarms. if (parts.Length > 3 && MySection.MyProcedure.DisplayNumber.IndexOf(",") > 0)// If extra commas combine first part to account for it { int n = parts.Length - 3; string part0 = parts[0]; for (int i = 0; i < n; i++) // append parts based upon the number of parts (commas) part0 += "," + parts[i + 1]; parts[0] = part0; parts[1] = parts[n + 1];// Get the last 2 parts parts[2] = parts[n + 2]; } string ROLookupVal = ""; // parts[0] - the RO to look up - for Alarms, is usually the EOP number thus uses the "{EOPNUM}" token // parts[1] - Which of the multiple return value from the RO to return // parts[2] - the value to use if not found in ROs - usually defined in a PSI field for that Alarm procedure // C2021-065 Barakah Alarms - check if child RO alarm ID matches the resolved procedure number // if not, then use the values stored in the PSI instead of the value returned for ROLookup() // for all of the Alarm Point window items (ROLookup() items) in the pagelist for this section (BNPP Alarms format) // Note only one pagelist item has this flag and this special pagelist item needs to be listed before any other ROLoopUP items if (pageItem.ROLkUpMatch) // check for paglist flag { string rawPrcNum = section.MyProcedure.MyContent.Number; // C2021-065 see if we need to get the Other child info from ROLookUp if (rawPrcNum.ToUpper().StartsWith(" in its definiation (procedure property page) { string procnum = section.MyProcedure.DisplayNumber; // get the cooked (resolved) procedure number int idx = procnum.IndexOf('-'); otherChildUnit = procnum.Substring(0, idx); // we need to get RO info for the Other child applicability - this gets child's number } ROLookupVal = ROLookup(parts[0], parts[1], "",otherChildUnit); // will return empty string if alarm point is not found in RO database usePSIvalue = (ROLookupVal != section.MyProcedure.DisplayNumber); // use PSI value if child alarm ID not found or does not match resolved procedure number (alarm point) } // C2021-065 if usePSIvalue is true, then we know alarm point info is not in the RO database, so just use the default (PSI) value if (usePSIvalue) ROLookupVal = parts[2]; // C2021-065 use the value defined in the PSI else ROLookupVal = ROLookup(parts[0], parts[1], parts[2], otherChildUnit); // F2021-053: Do replace words for Page List items. This uses a DisplayText constructor that flags this case // and gets the resulting replaced words if (pageItem.RepWords) { DisplayText dt1 = new DisplayText(MyPromsPrinter.MyItem, ROLookupVal, false, true); ROLookupVal = dt1.StartText; } // replace the pagelist token with ROLookupVal pltok = pltok.Substring(0, idxstart) + ROLookupVal + ((idxstart + idxend < pltok.Length) ? pltok.Substring(idxstart + idxend + 1) : ""); } // C2021-065 (BNPP Alarms format) we are processing a paglist flag (ROLkUpMatch) to determine how to get Alarm Point information // Nothing else is on this page list item, so use "continue" to jump to the next pagelist item as nothing gets printed for this item if (pageItem.ROLkUpMatch) continue; MatchCollection matches = regexFindToken.Matches(pltok);//(pageItem.Token); if (matches.Count > 0) { string plstr = ""; // When a pagelist line (row) has more than one token that is resolved to text, each resolved token text was place on top // of each other. Use a temporary string (plstr) to process the pagelist tokens for each pagelist line (row) before adding // it to the svgGroup. plstr = pltok;//pageItem.Token; // F2017-046: Remove the '@@' characters that were getting printed on SAMG Sup Info facing pages for Calvert (BGESAM1 format). if (MyPromsPrinter.DoingFacingPage && plstr.Contains("@@")) plstr = plstr.Replace("@@", ""); foreach (Match match in matches) { string token = match.Value; //token = Regex.Replace(token, @"[\xB3-\xDF]", " "); // handle any conditional PS tokens if (token.Contains(@"PS=")) { ProcedureConfig procConfig = new ProcedureConfig(section.MyProcedure.MyContent.Config); if (procConfig != null) { int indx = token.IndexOf("="); int qindx = token.IndexOf("?", indx); string pstok = token.Substring(indx + 1, qindx - indx - 1); string val = procConfig.GetValue("PSI", pstok); int bindx = token.IndexOf("|", indx); if (val == "Y") { val = token.Substring(qindx + 1, bindx - qindx - 1); // F2017-036: see if there is a RelatedItem in this page item. RelatedItem allows for repositioning // this current item if both items are set to be printed from the Procedure Specific Information. If both are printed // the location of this item is defined in the RelatedItem xml. if (pageItem.RelatedItem.Token != null) { // see if the related item is on this page also, if so, use the new row/col/justify: string reltoken = pageItem.RelatedItem.Token; string relval = procConfig.GetValue("PSI", reltoken); if (relval == "Y") { //svgGroup.Add(PageItemToSvgText(pageItem.Token, (float)pageItem.RelatedItem.Row, (float)pageItem.RelatedItem.Col, pageItem.RelatedItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft, pageItem.Font, val, MySection)); svgGroup.Add(PageItemToSvgText(pltok, (float)pageItem.RelatedItem.Row, (float)pageItem.RelatedItem.Col, pageItem.RelatedItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft, pageItem.Font, val, MySection)); plstr = ""; // Clear it so it isn't put out twice (used below) } } } else { int eindx = token.IndexOf("}", bindx); val = token.Substring(bindx + 1, eindx - bindx - 1); } if (val != null && val != "" && !PgLogicals.ContainsKey(pstok)) PgLogicals.Add(pstok, val != null); //if (val == null || val == "") //val = " "; if (val == null) val = ""; plstr = plstr.Replace(token, val); // Get a list of Pagelist token that are inside the PS= conditional result // Paglist tokens inside a PS= conditional are surrounded by square brackets instead of curley // ex. [BOX3] instead of {BOX3} MatchCollection subMatches = regexFindSubToken.Matches(plstr); if (subMatches.Count > 0) { foreach (Match subMatch in subMatches) { string subToken = subMatch.Value; ProcessPaglistToken(section, svgGroup, pageItem, ref useFontForCheckOffHeader, ref plstr, subToken); } } } } else if (token.Contains(@"SI=")) // F2021-068 needed duplicate conditional logic from PSI (above) but make of folder (set) specific info { DocVersionConfig dvConfig = new DocVersionConfig(section.MyProcedure.MyDocVersion.Config); FolderConfig folderConfig = new FolderConfig(section.MyProcedure.MyDocVersion.MyFolder.Config); if (dvConfig != null || folderConfig != null) { int indx = token.IndexOf("="); int qindx = token.IndexOf("?", indx); string pstok = token.Substring(indx + 1, qindx - indx - 1); string val = DocVersionInfo.GetInheritedSIValue(section.MyProcedure, pstok); int bindx = token.IndexOf("|", indx); if (val == "Y") { val = token.Substring(qindx + 1, bindx - qindx - 1); // see if there is a RelatedItem in this page item. RelatedItem allows for repositioning // this current item if both items are set to be printed from the Procedure Specific Information. If both are printed // the location of this item is defined in the RelatedItem xml. if (pageItem.RelatedItem.Token != null) { // see if the related item is on this page also, if so, use the new row/col/justify: string reltoken = pageItem.RelatedItem.Token; string relval = DocVersionInfo.GetInheritedSIValue(section.MyProcedure, reltoken); if (relval == "Y") { svgGroup.Add(PageItemToSvgText(pltok, (float)pageItem.RelatedItem.Row, (float)pageItem.RelatedItem.Col, pageItem.RelatedItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft, pageItem.Font, val, MySection)); plstr = ""; // Clear it so it isn't put out twice (used below) } } } else { int eindx = token.IndexOf("}", bindx); val = token.Substring(bindx + 1, eindx - bindx - 1); } if (val != null && val != "" && !PgLogicals.ContainsKey(pstok)) PgLogicals.Add(pstok, val != null); //if (val == null || val == "") //val = " "; if (val == null) val = ""; plstr = plstr.Replace(token, val); // Get a list of Pagelist token that are inside the SI= conditional result // Paglist tokens inside a PS= conditional are surrounded by square brackets instead of curley // ex. [BOX3] instead of {BOX3} MatchCollection subMatches = regexFindSubToken.Matches(plstr); if (subMatches.Count > 0) { foreach (Match subMatch in subMatches) { string subToken = subMatch.Value; ProcessPaglistToken(section, svgGroup, pageItem, ref useFontForCheckOffHeader, ref plstr, subToken); } } } } else { if (!ProcessPaglistToken(section, svgGroup, pageItem, ref useFontForCheckOffHeader, ref plstr, token)) break; } } // end foreach matches if (plstr != "") { if (useFontForCheckOffHeader != null) svgGroup.Add(PageItemToSvgText(pageItem, plstr, useFontForCheckOffHeader, MySection)); else svgGroup.Add(PageItemToSvgText(pageItem, plstr, MySection)); } } else svgGroup.Add(PageItemToSvgText(pageItem, pltok, MySection)); } } // Proms page numbering designed requires a "{PAGE}" token to increment the page counter. So the easiest way // to do that was to add a "{PAGE}" token to every page that is flagged as not to be printed. if (sPag == SectionConfig.SectionPagination.Separate) { // follow through in fixing an Out of Window Handles bug, use new function to see if // we can retrieve the font from a dictionary instead a doing a New and using another // window handle B2017-117 //SvgText st = new SvgText(new System.Drawing.PointF(300, 300), "Non-printing {PAGE}", new System.Drawing.Font("Arial", 10), System.Drawing.Color.Black); SvgText st = new SvgText(new System.Drawing.PointF(300, 300), "Non-printing {PAGE}", VE_Font.GetWinSysFont("Arial", 10), System.Drawing.Color.Black); svgGroup.Add(st); } // C2018-004 create meta file for baseline compares if (svgGroup.Count > 0) mySvg.Add(svgGroup); else Volian.Base.Library.BaselineMetaFile.WriteLine("No Pagelist Information"); } private string ROLookup(string accpageid, string multiid, string deflt) { return ROLookup(accpageid, multiid, deflt, ""); } // C2021-065 pass in a override for the child unit - in this case the token is being used (Barakah Alarms) private string ROLookup(string accpageid, string multiid, string deflt, string overrideChild) { ROFSTLookup myLookup = MySection.MyDocVersion.DocVersionAssociations[0].MyROFst.GetROFSTLookup(MySection.MyDocVersion, overrideChild); string accpgid = accpageid; //accpgid = accpgid.Replace("-HIGH", "-HI").Replace("-LOW", "-LO").Replace("_HIGH", "-HI").Replace("_LOW", "-LO").Replace(@"\u8209?", "-"); string val = myLookup.GetROValueByAccPagID("<" + accpgid + "." + multiid + ">", MySection.MyDocVersion.DocVersionConfig.RODefaults_setpointprefix, MySection.MyDocVersion.DocVersionConfig.RODefaults_graphicsprefix); if (val == null) { accpgid = accpgid.Replace(@"\u8209?", "-"); val = myLookup.GetROValueByAccPagID("<" + accpgid + "." + multiid + ">", MySection.MyDocVersion.DocVersionConfig.RODefaults_setpointprefix, MySection.MyDocVersion.DocVersionConfig.RODefaults_graphicsprefix); } if (!deflt.StartsWith("[") && val != null && val.Trim().Length > 0) // don't return val if it's an empty or blank string - jsj 01-28-2019 { val = val.Replace("[xB3]", "\xB3"); val = val.Replace("[xB2]", "\xB2"); return val; } return deflt; } private bool _DidHLSText = false; public bool DidHLSText { get { return _DidHLSText; } set { _DidHLSText = value; } } private int _HasHLSTextId = 0; public int HasHLSTextId { get { return _HasHLSTextId; } set { _HasHLSTextId = value; } } private string _HLSText = ""; public string HLSText { get { return _HLSText; } set { if (_HLSText == "") _HLSText = value; } } private string _HLSTAB = ""; public string HLSTAB { get { return _HLSTAB; } set { _HLSTAB = value; } } private string _HLRNO = ""; public string HLRNO { get { return _HLRNO; } set { _HLRNO = value; } } private bool _OldTemplateContMsg = false; public bool OldTemplateContMsg { get { return _OldTemplateContMsg; } set { _OldTemplateContMsg = value; } } private float _AdjustTopMarginForMultiLinePageListItems = 0; public float AdjustTopMarginForMultiLinePageListItems { get { return _AdjustTopMarginForMultiLinePageListItems; } set { _AdjustTopMarginForMultiLinePageListItems = value; } } /// /// /// /// /// /// /// /// /// /// true - if token is resolved /// false - if entire text is processed /// private bool ProcessPaglistToken(VEPROMS.CSLA.Library.SectionInfo section, SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, ref VE_Font useFontForCheckOffHeader, ref string plstr, string token) { bool retval = true; //Console.WriteLine("{0} ProcessPagelistToken", token); // Paglist token inside a PS= conditional are surrounded by square brackets instead of curley // ex. [BOX3] instead of {BOX3}, thus the redunant looking cases switch (token) { case "{!atom}": // Add an Atom Figure to the SVG plstr = plstr.Replace(token, ""); AddImage(svgGroup, 160.5f, 170.5f, 288f, 323f, "atom.bmp"); break; case "{!cpllogo}": plstr = plstr.Replace(token, ""); AddImage(svgGroup, 10f, 10f, 78.7f, 29.8f, "cpllogo.bmp"); break; //case "{!domlogo}": // AddImage(svgGroup, 10f, 70f, 123f, 40.1f, "domlogo.bmp"); // break; //case "{!gpclogo}": // AddImage(svgGroup, 10f, 150f, 35.2f, 35.8f, "gpclogo.bmp"); // break; case "{HEADER1}": case "[HEADER1]": case "{HEADER2}": case "[HEADER2]": case "{HEADER3}": case "[HEADER3]": case "{HEADER4}": case "[HEADER4]": case "{HEADER5}": case "[HEADER5]": case "{BOX1}": case "[BOX1]": case "{BOX2}": case "[BOX2]": case "{BOX3}": case "[BOX3]": case "{BOX4}": case "[BOX4]": case "{BOX5}": case "[BOX5]": case "{BOX6}": case "[BOX6]": case "{BOX7}": case "[BOX7]": case "{BOX8}": case "[BOX8]": case "{BOX9}": case "[BOX9]": plstr = plstr.Replace(token, ""); svgGroup.Add(PageItemToSvgUse(pageItem, FirstAndLast(token))); break; case "{PMODEBOX}": // need to set either 1 or 2 depending on number of columns case "[PMODEBOX]": string box = "1"; if (_MySection.SectionConfig.Section_ColumnMode == SectionConfig.SectionColumnMode.Four) box = "4"; else if (_MySection.SectionConfig.Section_ColumnMode == SectionConfig.SectionColumnMode.Three) box = "3"; else if (_MySection.SectionConfig.Section_ColumnMode == SectionConfig.SectionColumnMode.Two) box = "2"; box = "{BOX" + box + "}"; plstr = plstr.Replace(token, ""); svgGroup.Add(PageItemToSvgUse(pageItem, FirstAndLast(box))); break; case "{DRAFTPAGE}": //if (!AllowedWatermarks.Contains("Draft")) AllowedWatermarks.Add("Draft"); -- B2018-124 not needed anymore plstr = plstr.Replace(token, "");// Remove token since it is handled now break; case "{REFERENCEPAGE}": //if (!AllowedWatermarks.Contains("Reference")) AllowedWatermarks.Add("Reference"); -- B2018-124 not needed anymore plstr = plstr.Replace(token, "");// Remove token since it is handled now break; case "{MASTERPAGE}": //if (!AllowedWatermarks.Contains("Master")) AllowedWatermarks.Add("Master"); -- B2018-124 not needed anymore plstr = plstr.Replace(token, "");// Remove token since it is handled now break; case "{SAMPLEPAGE}": //if (!AllowedWatermarks.Contains("Sample")) AllowedWatermarks.Add("Sample"); -- B2018-124 not needed anymore plstr = plstr.Replace(token, "");// Remove token since it is handled now break; //case "{INFORMATIONPAGE}": // if (!AllowedWatermarks.Contains("Information Only")) AllowedWatermarks.Add("Information Only"); -- B2018-124 not needed anymore // break; case "{PROCTITLE}": case "[PROCTITLE]": case "{PROCTITLE1}": case "[PROCTITLE1]": case "{PROCTITLE2}": case "[PROCTITLE2]": case "{PROCTITLE3}": case "[PROCTITLE3]": case "{COVERPROCTITLE}": case "[COVERPROCTITLE]": int tlen = (token.Contains("COVERPROCTITLE"))?(int)section.ActiveFormat.PlantFormat.FormatData.ProcData.CoverTitleLength : (int)section.ActiveFormat.PlantFormat.FormatData.ProcData.TitleLength; //float linelen = (int)section.ActiveFormat.PlantFormat.FormatData.ProcData.TitleLength * (float)pageItem.Font.CPI / 12; float linelen = tlen * (float)pageItem.Font.CPI / 12; string title = section.MyProcedure.MyContent.Text; if (title.Contains("") && !section.ActiveFormat.PlantFormat.FormatData.ProcData.PrintNoTitle) plstr = ""; else { if (section.ActiveFormat.PlantFormat.FormatData.ProcData.CapitalizeTitle) title = title.ToUpper(); // B2022-035: resolve unit specific designators if (title.ToUpper().Contains(@" 0) { if (unitnum1.Contains("#")) eopnum1 = unitnum1.Replace("#", eopnum1); if (unitnum1.Contains("!")) eopnum1 = unitnum1.Replace("!", unitname1); if (eopnum1 == string.Empty) eopnum1 = section.MyProcedure.MyContent.Number; } plstr = SplitEOPNumber(svgGroup, pageItem, eopnum1, token, plstr); break; case "{CM:(Cont)}": if (OldTemplateContMsg) plstr = plstr.Replace("{CM:(Cont)}", "(Cont)"); else plstr = plstr.Replace("{CM:(Cont)}", ""); break; case "{RF:REFERENCE}": // This token is used by IP2. In 16bit it is processed when the PO_DISTRIBUTEAPPROVED // purchase option is set and a file 'ref.dat' exists. Text from this file replaced // the token. It was decided by RHM/KBR on 10/7/14 that this would not be implemented // unless/until it is determined that it is used (no data that Volian currently has // contains this file). To implement it requires a config item off of the procedure level, // user interface support on the Procedure Properties dialog and print support. plstr = plstr.Replace("{RF:REFERENCE}", ""); break; case "{NULLDOCCURPAGE}": // This token is used by IP2. There was no support for it in 16bit and the 16bit to 32bit // output compared so it is just removed here so that a pagelist token error is not output // in error log. plstr = plstr.Replace("{NULLDOCCURPAGE}", ""); break; case "{PDFDate}": plstr = plstr.Replace("{PDFDate}", DateTime.Now.ToString("MM/dd/yyyy")); break; case "{PDFTime}": plstr = plstr.Replace("{PDFTime}", DateTime.Now.ToString("HH:mm:ss")); break; case "{EOPNUM}": case "[EOPNUM]": case "{PREDELIMEOPNUM}": case "[PREDELIMEOPNUM]": case "{EOPNUMROLU}": case "[EOPNUMROLU]": string eopnum = section.MyProcedure.MyContent.Number; string unitnum = MySection.MyDocVersion.DocVersionConfig.Unit_ProcedureNumber; string unitname = MySection.MyDocVersion.DocVersionConfig.Unit_Name; if (unitnum.Length > 0) { if (unitnum.Contains("#")) eopnum = unitnum.Replace("#", eopnum); if (unitnum.Contains("!")) eopnum = unitnum.Replace("!", unitname); if (eopnum == string.Empty) eopnum = section.MyProcedure.MyContent.Number; if (eopnum.ToUpper().Contains(@", , , , , , , , eopnum = Regex.Replace(eopnum, @"\", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)ID)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)NAME)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)TEXT)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)NUMBER)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); // B2021-148 remove space character after "OTHER" eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)OTHERID)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)OTHERNAME)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)OTHERTEXT)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); eopnum = Regex.Replace(eopnum, @"\<(U(-|\\u8209\?)OTHERNUMBER)\>(-|\\u8209\?)", "", RegexOptions.IgnoreCase); } else eopnum = section.MyProcedure.DisplayNumber;// B2021-066: found and fixed during proc pc/pc work } } // B2022-066 the "{PREDELIMEOPNUM}" token was not being processed because there was a space after the "{" if (token.Equals("{PREDELIMEOPNUM}")) { // only use up to the first non-alphanumeric character of the procedur number // Prairie Island (NSP) Alarms use this token int idx = 0; while (idx < eopnum.Length && char.IsLetterOrDigit(eopnum[idx])) idx++; if (idx < eopnum.Length) eopnum = eopnum.Substring(0, idx); } plstr = plstr.Replace(token, eopnum); //svgGroup.Add(PageItemToSvgText(pageItem, pageItem.Token.Replace(token, eopnum))); //svgGroup.Add(PageItemToSvgText(pageItem, pageItem.Token.Replace(token, section.MyProcedure.MyContent.Number))); break; case "{SECTIONLEVELTITLE}": case "[SECTIONLEVELTITLE]": case "{ATTACHTITLECONT}": case "[ATTACHTITLECONT]": // B2020-038: incorrect pagination: Note that if PSOnlyFirst is active and pagination is set to continuous, pagination may be incorrect in printed output (no code change-just info here in case happens again) bool printsectlevel = ((pageItem.Justify & VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) != VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) || (((pageItem.Justify & VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) == VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) && PrintedSectionPage==0); // if there is 'no title' for the section, only print it if a format flag says to print it. if (printsectlevel) { if (section.DisplayText.ToUpper().Contains("") && !section.ActiveFormat.PlantFormat.FormatData.ProcData.PrintNoTitle) printsectlevel = false; } if (MyPromsPrinter.DoingFacingPage) printsectlevel = false; // don't put out section title/number if doing SAMG facing pages if (printsectlevel) { string stitle = section.DisplayText; if (((section.MyDocStyle.StructureStyle.Style & E_DocStructStyle.DSS_PageListAddSectCont) == E_DocStructStyle.DSS_PageListAddSectCont) && token.Contains("ATTACHTITLECONT") && DidFirstPageDocStyle) { string myMsg = section.MyDocStyle.Continue.Top.Message; if (myMsg != null && myMsg != "")stitle = stitle + myMsg; } // B2021-119: large titles on Landscape Word Attachments are printing on 2 lines. int? stl = (int)section.ActiveFormat.PlantFormat.FormatData.SectData.SectionNumberAndTitleLength; if (section.MyDocStyle.LandscapePageList && section.ActiveFormat.PlantFormat.FormatData.SectData.SectNumAndTlLenLand != null) stl = section.ActiveFormat.PlantFormat.FormatData.SectData.SectNumAndTlLenLand; plstr = SplitTitle(svgGroup, pageItem, stitle, section.ActiveFormat.PlantFormat.FormatData.SectData.SectionTitleLength, token, plstr, stl); if ((pageItem.Justify & VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) == VEPROMS.CSLA.Library.E_Justify.PSOnlyFirst) // B2020-047 only set PrintedSectionPage if PSOnly is used PrintedSectionPage = (int)pageItem.Row - _sectLevelNumTtlDiff; } else plstr = plstr.Replace(token, ""); //svgGroup.Add(PageItemToSvgText(pageItem, section.DisplayText)); break; case "{METASECTIONTITLE}": // This will print the top level section title (versus level above current) case "[METASECTIONTITLE]": if (section.MyParent.IsSection) { // get top most section: ItemInfo top = section; while (top.MyParent != null && !top.MyParent.IsProcedure) { top = top.MyParent; } plstr = SplitTitle(svgGroup, pageItem, top.DisplayText, section.ActiveFormat.PlantFormat.FormatData.SectData.SectionTitleLength, token, plstr, section.ActiveFormat.PlantFormat.FormatData.SectData.SectionNumberAndTitleLength); } else plstr = plstr.Replace(token, ""); break; case "{SECTIONLEVELNUMBER}": case "[SECTIONLEVELNUMBER]": // don't put out section title/number if doing SAMG facing pages if (!MyPromsPrinter.DoingFacingPage) { plstr = plstr.Replace(token, section.DisplayNumber); _sectLevelNumTtlDiff = (int)pageItem.Row; } else plstr = plstr.Replace(token, ""); // B2020-040: pagelist was {SECTIONLEVELNUMBER}, {SECTIONLEVELTITLE} and if no SECTIONLEVELNUMBER exists, printed // text starts with a ', ' - remove it. if (plstr.StartsWith(", ") && plstr.IndexOf("{SECTIONLEVELTITLE}") == 2) plstr = plstr.Substring(2); // F2021-075 pagelist was {SECTIONLEVELNUMBER} - {SECTIONLEVELTITLE} and if no SECTIONLEVELNUMBER exists, printed // text starts with a ' - ' - remove it. else if (plstr.StartsWith(" - ") && plstr.IndexOf("{SECTIONLEVELTITLE}") == 3) plstr = plstr.Substring(3); //svgGroup.Add(PageItemToSvgText(pageItem, pageItem.Token.Replace(token, section.DisplayNumber))); break; case "{METASECTIONNUMBER}": // This will print the top level section number case "[METASECTIONNUMBER]": if (section.MyParent.IsSection) { // get top most section: ItemInfo top = section; while (top.MyParent != null && !top.MyParent.IsProcedure) { top = top.MyParent; } plstr = plstr.Replace(token, top.DisplayNumber); } else plstr = plstr.Replace(token, ""); break; case "{UNITTEXT}": case "[UNITTEXT]": plstr = plstr.Replace(token, MySection.MyDocVersion.DocVersionConfig.Unit_Text); //svgGroup.Add(PageItemToSvgText(pageItem, pageItem.Token.Replace(token, MySection.MyDocVersion.DocVersionConfig.Unit_Text))); break; case "{UNITNUMBER}": case "[UNITNUMBER]": string unbr = MySection.MyDocVersion.DocVersionConfig.Unit_Number; if (MySection.ActiveFormat.PlantFormat.FormatData.PrintData.PrintCommonForZeroUnit && unbr == "0") plstr = "COMMON"; // for Comanche Peak, replace "Unit 0" with "COMMON" else plstr = plstr.Replace(token, unbr); break; case "{VCBUNIT}": case "[VCBUNIT]": string unbr2 = MySection.MyDocVersion.DocVersionConfig.Unit_Number; if (unbr2 == "0") { if (MySection.MyProcedure.DisplayNumber.StartsWith("VCS") || MySection.MyProcedure.DisplayNumber.StartsWith("MD")) plstr = "NSBU"; else if (MySection.MyProcedure.DisplayNumber.StartsWith("VC2")) plstr = "Unit 2"; else if (MySection.MyProcedure.DisplayNumber.StartsWith("VC3")) plstr = "Unit 3"; else plstr = "Units 2 & 3"; // for VC Summer, replace "Unit 0" with "Units 2 & 3" } else plstr = plstr.Replace(token, unbr2); break; case "{ATTACHNUM}": case "[ATTACHNUM]": plstr = plstr.Replace(token, "1"); // used by SHESDD - but 16bit returns '1' unless has format flag 'MoveParensToToken' that was only in SCE (San Onofre) break; case "{ATTACHNUM1}": case "[ATTACHNUM1]": string numAtt = GetAttachNum1(); plstr = plstr.Replace(token, numAtt); // used by SHESDD - but 16bit returns '1' unless has format flag 'MoveParensToToken' that was only in SCE (San Onofre) break; case "{CHKOFFHEADING}": case "[CHKOFFHEADING]": // unfortunately, the font is not stored on the page list item if there is an active // check off header. It is stored with the checkoff data as defined by user selection // of the selected header (selection stored in section config). int sindx = section.CheckOffHeadingIndex(); VE_Font vf = sindx <= 0 ? pageItem.Font : section.ActiveFormat.PlantFormat.FormatData.ProcData.CheckOffData.CheckOffHeaderList[sindx].Font; useFontForCheckOffHeader = vf; PageListCheckOffHeader = PageItemToSvgText(pageItem, pageItem.Token, vf, section); break; case "{HLSTEXT}": DidHLSText = true; plstr = plstr.Replace(token, HLSText); break; case "{VALTYPE}": ItemInfo firstHigh = ValveGetFirstStep(section); if (firstHigh != null) { int typ = (int)firstHigh.MyContent.Type - 20000; switch (typ) { case 2: plstr = plstr.Replace(token, "VALVE"); break; case 9: plstr = plstr.Replace(token, "SWITCH"); break; case 3: plstr = plstr.Replace(token, "BREAKER"); break; default: plstr = plstr.Replace(token, ""); break; } } else plstr = plstr.Replace(token, ""); break; case "{STARTUP}": ItemInfo firstHighs = ValveGetFirstStep(section); if (firstHighs != null) { int typs = (int)firstHighs.MyContent.Type - 20000; switch (typs) { case 2: // the following test for OI-3A came from 16bit code: string num = section.MyProcedure.MyContent.Number.ToUpper().Replace(@"\U8209?", "-"); if (num.Equals("OI-3A")) plstr = plstr.Replace(token, " SDC/"); else plstr = plstr.Replace(token, "STARTUP/"); break; default: plstr = plstr.Replace(token, ""); break; } } else plstr = plstr.Replace(token, ""); break; case "{PROCDES}": ProcDescrList pdl = section.ActiveFormat.PlantFormat.FormatData.PrintData.ProcDescrList; if (pdl != null && pdl.Count > 0) { string procnum = section.MyProcedure.MyContent.Number.Replace(@"\u8209?", "-").Replace(@"\u9586?", @"\"); foreach (ProcDescr pd in pdl) { if (pd.MatchProcNumber != null) { string matchStr = (pd.MatchProcNumber.StartsWith("*}")) ? pd.MatchProcNumber.Substring(2) : pd.MatchProcNumber; if (procnum.Contains(matchStr)) { if (pd.ProcDescr1 == "{null}") // used to override fmt file inheritance & set null/empty string plstr = ""; else plstr = pd.ProcDescr1; break; } if (pd.MatchProcNumber == "@") { // 16bit code looked like it only checked for the first character, but this code looks at // all characters. It was not working correctly for BGE. Didn't want to change it for other // plants that have been delivered - so added special code for BGE. if (section.ActiveFormat.PlantFormat.FormatData.PrintData.SpecialCaseCalvert) { if (Regex.IsMatch(procnum.Substring(0,1),"[A-Za-z]")) plstr = pd.ProcDescr1; else plstr = ""; break; } if (Regex.IsMatch(procnum, "^[A-Za-z]+$")) plstr = pd.ProcDescr1; else plstr = ""; break; } } else plstr = "UNKNOWN"; } } break; case "{PROCDES2}": ProcDescrList pdl2 = section.ActiveFormat.PlantFormat.FormatData.PrintData.ProcDescrList; if (pdl2 != null && pdl2.Count > 0) { string procnum = section.MyProcedure.MyContent.Number.Replace(@"\u8209?", "-").Replace(@"\u9586?", @"\"); foreach (ProcDescr pd in pdl2) { if (pd.MatchProcNumber != null) { string matchStr = (pd.MatchProcNumber.StartsWith("*}")) ? pd.MatchProcNumber.Substring(2) : pd.MatchProcNumber; if (procnum.Contains(matchStr)) { plstr = pd.ProcDescr2; break; } if (pd.MatchProcNumber == "@") { if (Regex.IsMatch(procnum, "^[A-Za-z]+$")) plstr = pd.ProcDescr2; else plstr = ""; break; } } else plstr = "UNKNOWN"; } } break; case "{CURDATE}": DateTime thisDate1 = DateTime.Today; plstr = plstr.Replace(token, thisDate1.ToString("MMMM dd, yyyy")); break; case "{CURTIME}": DateTime thisDate2 = DateTime.Now; plstr = plstr.Replace(token, thisDate2.ToString("H:mm")); break; case "{HLRNO}": plstr = HLRNO==null?"":plstr.Replace(token, HLRNO); break; case "{HLSTAB}": plstr = plstr.Replace(token, HLSTAB); break; case "{UNITALPHA}": // copied from 16bit's pagelist.cs for BGE: string unitnm = MySection.MyDocVersion.DocVersionConfig.Print_UnitNumberForPageList; if (unitnm == "1") plstr = plstr.Replace(token, "ONE"); else if (unitnm == "2") plstr = plstr.Replace(token, "TWO"); else plstr = plstr.Replace(token, "ONE AND TWO"); break; case "{INITIALS}": // For Calvert: if this section has checkoffs turned on, put out this pagelist item: // Get SectionInfos to access specific section config items... //SectionInfo si = SectionInfo.Get(MySection.ItemID); //SectionInfo si = MySection.GetSectionInfo(); //SectionConfig sectCfg = si.MyConfig as SectionConfig; //int sc = sectCfg.Section_CheckoffListSelection; if (!MySection.HasInitials) { plstr = plstr.Replace(token, ""); //PIInitials = pageItem; } else { if (pageItem.Row == -MySection.MyDocStyle.Layout.TopMargin) { plstr = plstr.Replace(token, ""); PIInitials = pageItem; } else plstr = plstr.Replace(token, "INITIALS"); } break; case "{REVUNIT}": // copied from 16bit's pagelist.cs for BGE: string revUnit = null; string unitNum = MySection.MyDocVersion.DocVersionConfig.Print_UnitNumberForPageList; if (Rev != null && Rev != "") { revUnit = Rev; int indxs = Rev.IndexOf(MySection.ActiveFormat.PlantFormat.FormatData.PrintData.RevDateWithForwardSlash ? '\\' : '/'); if (indxs > 0) revUnit = Rev.Substring(0, indxs); } else revUnit = " "; if (unitNum == "2") revUnit += "/Unit 2"; else if (unitNum == "1") revUnit += "/Unit 1"; plstr = plstr.Replace(token, revUnit); break; case "[UNIT]": string un = MySection.MyDocVersion.DocVersionConfig.Print_UnitNumberForPageList; plstr = plstr.Replace(token, un); break; case "{MCRSERNUM}": // B2021-127: BNPPalr - Auto set of serial # int sernum = section.MyProcedure.Ordinal - VlnSvgPageHelper.CountInApplProcs; plstr = plstr.Replace(token, sernum.ToString()); break; default: if (token.Contains(@"SI-")) // procedure set specific information. (at folder or working draft levels) { DocVersionConfig dvConfig = new DocVersionConfig(section.MyProcedure.MyDocVersion.Config); FolderConfig folderConfig = new FolderConfig(section.MyProcedure.MyDocVersion.MyFolder.Config); if (dvConfig != null || folderConfig != null) { int indx = token.IndexOf("-"); int qindx = token.IndexOf("?", indx); string val = null; if (qindx == -1) { val = DocVersionInfo.GetInheritedSIValue(section.MyProcedure, token.Substring(4, token.Length - 5)); // C2021-051: Applicability tokens in Procedure Set and Folder Specific Information if (val.ToUpper().Contains("") || val.ToUpper().Contains("") || val.ToUpper().Contains("') if(val.ToUpper().Contains("") || val.ToUpper().Contains(" 0 || (pageItem.MaxWidthCurPage ?? 0) > 0) { int locwid = ((pageItem.MaxWidth??0)>0)?(int)pageItem.MaxWidth:(int)pageItem.MaxWidthCurPage; AdjustTopMarginForMultiLinePageListItems = SplitTextMaxWidth(svgGroup, pageItem, val, locwid, token, ref plstr); if ((pageItem.MaxWidthCurPage ?? 0) > 0) AdjustTopMarginForMultiLinePageListItems = 0; } else plstr = plstr.Replace(token, val); //svgGroup.Add(PageItemToSvgText(pageItem, plstr, MySection)); } else { string pstok = token.Substring(indx + 1, qindx - indx - 1); plstr = procConfig.GetValue("PSI", pstok); // the first part of the string between the ? and ' ' is the other logical // to see if it's on. If on, just use col and/or row as defined. Otherwise use // value between = and |. int sindx2 = token.IndexOf(" ", qindx); string logcheck = token.Substring(qindx + 1, sindx2 - qindx - 1); if (PgLogicals.ContainsKey(logcheck)) { int bindx = token.IndexOf("|", indx); string newval = token.Substring(sindx2 + 1, bindx - sindx2 - 1); float col = pageItem.Col ?? 0; if (newval.ToUpper().Contains("COL")) { col = System.Convert.ToInt32(newval.Substring(4)); } svgGroup.Add(PageItemToSvgText(pageItem.Token, pageItem.Row ?? 0, col, pageItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft, pageItem.Font, plstr, MySection)); plstr = ""; // clear so it doesn't get added twice, i.e. in the method that calls this. } } } } else { if (plstr != "") { svgGroup.Add(PageItemToSvgText(pageItem, plstr, MySection)); plstr = ""; } //svgGroup.Add(PageItemToSvgText(pageItem, pageItem.Token)); } //_MyLog.InfoFormat("Token not processed {0}", token); if (plstr == "") retval = false; break; } return retval; } // F2021-034: Resolve applicability unit tokens (not just '') private string ResolveUnitApp(DocVersionInfo dvi, string str) { if (dvi == null) return str; string tmp = str.ToUpper(); int sindx = tmp.IndexOf("", sindx + 1); string reptmp; while (sindx > -1 && eindx > -1) // B2022-007 added while loop to process more than one ") str = str.Replace(reptmp, dvi.DocVersionConfig.Unit_Number); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Unit_Text); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Unit_Number); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Unit_Name); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Unit_ID); // B2021-145: For applicability, the tree view & pdf file name are not getting resolved when using any of the ‘OTHER’ tokens else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Other_Unit_Text); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Other_Unit_Number); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Other_Unit_Name); else if (tmp == "") str = str.Replace(reptmp, dvi.DocVersionConfig.Other_Unit_ID); else str = str.Replace(reptmp, tmp.Replace("<", "*?").Replace(">", "?*")); tmp = str.ToUpper(); sindx = tmp.IndexOf("", sindx + 1); } return str; } // B2019-076: moved the following to DocVersionExt.cs to make it available to transitionext.cs code. //private string GetInheritedSIValue(ProcedureInfo pi, string fieldName) //{ // string val = null; // DocVersionConfig dvConfig = new DocVersionConfig(pi.MyDocVersion.Config); // if (dvConfig != null) // { // val = dvConfig.GetValue("SI", fieldName); // if (val != null && val != "") return val; // the value exists within the docversion level // } // FolderInfo fi = pi.MyDocVersion.MyFolder; // while (fi != null) // { // FolderConfig folderConfig = new FolderConfig(fi.Config); // if (folderConfig != null) // { // val = folderConfig.GetValue("SI", fieldName); // if (val != null && val != "") return val; // the value exists within this folder // } // fi = fi.ActiveParent as FolderInfo; // } // return val; //} private static ItemInfo ValveGetFirstStep(VEPROMS.CSLA.Library.SectionInfo section) { ItemInfo firstHigh = null; if (section.Steps == null || section.Steps.Count == 0) { // see if there is a 1st subsection with a step. The formats must match // if this is true, use that step. Otherwise just clear the token. if (section.Sections != null && section.Sections.Count > 0 && section.Sections[0].Steps != null || section.Sections[0].Steps.Count != 0) { if (section.ActiveFormat.FormatID == section.Sections[0].ActiveFormat.FormatID && section.MyContent.Type == section.Sections[0].MyContent.Type) firstHigh = section.Sections[0].Steps[0]; } } else firstHigh = section.Steps[0]; return firstHigh; } private string GetAttachNum1() { int cnt = 0; SectionInfo si = MySection; while (si != null) { if (si.MyContent.Type == MySection.MyContent.Type) cnt++; si = si.MyPrevious as SectionInfo; } return cnt.ToString(); } private static void AddImage(SvgGroup svgGroup, float x, float y, float w, float h, string figure) { svgGroup.Add(new SvgImage(new System.Drawing.PointF(x, y), new System.Drawing.SizeF(w, h), System.Windows.Forms.Application.StartupPath + @"\Resources\" + figure)); } private float SplitTextMaxWidth(SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, string title, int? len, string match, ref string plstr) { List titleLines = Volian.Base.Library.RtfTools.SplitText(title, (int)len); float yOffset = 0; int cnt = 0; foreach (string line in titleLines) { cnt++; if (cnt == 1 && yOffset == 0) plstr = plstr.Replace(match, line); else { if (cnt == 1) { plstr = plstr.Replace(match, line); // include preceeding text with the first line v.c. summer svgGroup.Add(PageItemToSvgText(pageItem, plstr, yOffset)); plstr = ""; } else svgGroup.Add(PageItemToSvgText(pageItem, line, yOffset)); plstr = plstr.Replace(match, ""); } yOffset += (float)((pageItem.Font.Size > 14) ? pageItem.Font.Size : 12); } return Math.Max(0, yOffset); } private string SplitTitle(SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, string title, int? len, string match, string plstr,int? numAndTitleLen) { bool includePrecedingText = false; if (match == "{PROCTITLE2}" || match == "[PROCTITLE2]") return plstr.Replace(match, ""); // F2017-013 - Ginna (RGESAM1) this handles when you have {SECTIONLEVELNUMBER} and {SECTIONLEVELTITLE} on the same line. // The section number was already replaced in plstr so when determining where to split the title, // include the section number (and anything before the title) in the calculation of where to split. // test for the ussage of the SectionNumberAndTitleLength (numAndTitleLen parameter) format variable (use a flag for this logic) // This logic does not handle any pagelist tokens following the section title. // "@@" acts like a hanging indent (Calvert) so don't include stuff before the title // For now, made this explicite with the use of SectionLevelTitle if ((numAndTitleLen != null && numAndTitleLen > 0) && !plstr.Contains("@@") && (plstr.IndexOf("{SECTIONLEVELTITLE}") > 0)) { int idx = plstr.IndexOf(match); title = plstr.Replace(match, title); // include everthing on this line for splitting plstr = plstr.Substring(idx); // since title include everthing before {SECTIONLEVELTITLE} plstr needs to be {SECTIONLEVELTITLE} and everything after it includePrecedingText = true; } // check to see if the title needs to wrap if ((len == null || len == 0 || ItemInfo.StripRtfFormatting(title).Length < len) && (!includePrecedingText || ItemInfo.StripRtfFormatting(title).Length < numAndTitleLen)) { // B2022-061: don't print '\line' as part of procedure title in pagelist items. if (match == "{PROCTITLE}") title = title.Replace("\\line ", ""); if (match == "{PROCTITLE2}" || match == "[PROCTITLE2]") return plstr.Replace(match, ""); // this would have been done in proctitle1 plstr = plstr.Replace(match, title).Replace("@@",""); //svgGroup.Add(PageItemToSvgText(pageItem, title)); return plstr; } // BGE has a '@@' in its section number/title pagelist item for eops. If the title goes onto two lines, // the '@@' marked the starting location for the title. Process this differently than other split titles: if (plstr.Contains("@@")) { DoSpecialSectNumTitle(svgGroup, pageItem, title, len, match, plstr); return ""; // all resolved pagelist items were already added to svgGroup for printing. } // Otherwise determine how many line to split the text into ListtitleLines = Volian.Base.Library.RtfTools.SplitText(title,(includePrecedingText)?(int)numAndTitleLen: (int)len); // Adjust y location based on which pagelist token & how many lines. Proctitle1 is adjusted if // there are more than 2 lines (proctitle1 should have it's own y location that is used if there are 1 or 2 lines.) float yOffset = (pageItem.Token.Contains("1") && titleLines.Count <= 2) ? 0 : (-6 * (titleLines.Count - 1)); // the following was added to support the vcb format proctitles that should always start on the line defined and // move down the page for additional lines (this was added to handle a 3 line title printing abouve the border) if (pageItem.Token.Contains("3")) yOffset = 0; int cnt = 0; // if the title broke into two lines & proctitle1 & proctitle2 are on the same line, handle that // and return the string: if (titleLines.Count == 2 && pageItem.Token.Contains("1") && pageItem.Token.Contains("2")) { plstr = plstr.Replace("{PROCTITLE1}", titleLines[0]); plstr = plstr.Replace("[PROCTITLE1]", titleLines[0]); plstr = plstr.Replace("{PROCTITLE2}", titleLines[1]); plstr = plstr.Replace("[PROCTITLE2]", titleLines[1]); return plstr; } foreach (string line in titleLines) { cnt++; if (cnt == 1 && yOffset == 0) // adj == 0 means we use PROCTITLE1/PROCTITLE2 pagelist tokens with 2 or less lines plstr = plstr.Replace(match, line); else { if (cnt == 1) { plstr = plstr.Replace(match, line); // include preceeding text with the first line v.c. summer svgGroup.Add(PageItemToSvgText(pageItem, plstr, yOffset)); plstr = ""; } else svgGroup.Add(PageItemToSvgText(pageItem, line, yOffset)); plstr = plstr.Replace(match, ""); } yOffset += (float)((pageItem.Font.Size > 14) ? pageItem.Font.Size : 12); } return plstr; } private PageItem _PIInitials = null; public PageItem PIInitials { get { return _PIInitials; } set { if (_PIInitials != null && value == null) _LastPIInitials = _PIInitials; _PIInitials = value; } } private PageItem _LastPIInitials = null; public PageItem LastPIInitials { get { return _LastPIInitials; } set { _LastPIInitials = value; } } private bool _HasInitials = false; public bool HasInitials { get { return _HasInitials; } set { _HasInitials = value; } } private bool _InitialsPrinted = false; public bool InitialsPrinted { get { return _InitialsPrinted; } set { _InitialsPrinted = value; } } public bool PrintInitials(PdfContentByte cb,float yLocation, float leftMargin) { if (InitialsPrinted) return false; InitialsPrinted = true; vlnParagraph.TextAt(cb,this, PIInitials ?? LastPIInitials, yLocation, leftMargin); return true; } private void DoSpecialSectNumTitle(SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, string title, int? len, string match, string plstr) { // first add anything up to the "@@" to the svgGroup: string befAts = plstr.Substring(0, plstr.IndexOf("@@")); svgGroup.Add(PageItemToSvgText(pageItem, befAts, 0)); // get the new xoffset. This will be the column value + the size of 'stuff' before the '@@' float xoff = (float)pageItem.Col; xoff += (befAts.Length * pageItem.Font.CharsToTwips); float yoff = (float)pageItem.Row; List titleLines = Volian.Base.Library.RtfTools.SplitText(title, (int)len); foreach (string line in titleLines) { svgGroup.Add(PageItemToSvgText(pageItem.Token, yoff, xoff, (E_Justify)pageItem.Justify, pageItem.Font, line, MySection)); yoff += (float)((pageItem.Font.Size > 14) ? pageItem.Font.Size : 12); } } private string SplitTitleAndUnit(SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, string title, int? len, string token, string plstr) { List titleLines = Volian.Base.Library.RtfTools.SplitText(title, (int)len); // Add a separate line with the Unit Number titleLines.Add("UNIT " + MySection.MyDocVersion.DocVersionConfig.Unit_Number); // Adjust y location based on which pagelist token & how many lines. float yOffset = (-6 * (titleLines.Count - 1)); foreach (string line in titleLines) { svgGroup.Add(PageItemToSvgText(pageItem, line, yOffset)); yOffset += (float)((pageItem.Font.Size > 14) ? pageItem.Font.Size : 12); } return plstr.Replace(token, ""); } private string SplitEOPNumber(SvgGroup svgGroup, PageItem pageItem, string eopnum, string token, string plstr) { string[] eopnums = eopnum.Split(" ".ToCharArray()); float yOffset = (-6 * (eopnums.Length - 1)); foreach (string line in eopnums) { svgGroup.Add(PageItemToSvgText(pageItem, line, yOffset)); yOffset += (float)((pageItem.Font.Size > 14) ? pageItem.Font.Size : 12); } return plstr.Replace(token, ""); } //private string symblsStr = "\u25CF\u0394"; // string of possible symbol character in a tab //// add symbol characters as needed //// "\u25CF" - solid bullet //// \x0394 - delta //private float GetTextWidth(VE_Font vefont, string txt, string symblFontName) //{ // System.Drawing.Font font = new System.Drawing.Font(vefont.Family, (float)vefont.Size, GetSysFontStyle(vefont)); // System.Drawing.Font symbFont = new System.Drawing.Font(symblFontName, (float)vefont.Size); // iTextSharp.text.Font iFont = Volian.Svg.Library.VolianPdf.GetFont(font); // iTextSharp.text.Font iSymblFont = Volian.Svg.Library.VolianPdf.GetFont(symbFont); // float w = 0; // foreach (char c in txt) // { // int idx = symblsStr.IndexOf(c); // if (idx >= 0) // symbol character - use symbol font to find its width // w += iSymblFont.BaseFont.GetWidthPointKerned(symblsStr[idx].ToString(), (float)vefont.Size); // else // w += iFont.BaseFont.GetWidthPointKerned(c.ToString(), (float)vefont.Size); // } // //float w = iFont.BaseFont.GetWidthPointKerned(Text.Replace("\u25CF","@"), (float)vefont.Size); // return w; //} private string SplitCoverTitle(SvgGroup svgGroup, VEPROMS.CSLA.Library.PageItem pageItem, string title, int? len, string match, string plstr) { if (len == null || ItemInfo.StripRtfFormatting(title).Length < len) { if (match == "{COVERTITLE2}" || match == "[COVERTITLE2]") return plstr; // this would have been done in COVERTITLE1 plstr = plstr.Replace(match, title); //svgGroup.Add(PageItemToSvgText(pageItem, title)); return plstr; } // Otherwise determine how many line to split the text into List titleLines = Volian.Base.Library.RtfTools.SplitText(title, (int)len); if (match == "{COVERTITLE1}" || match == "[COVERTITLE1]") { plstr = plstr.Replace(match, titleLines[0]); //svgGroup.Add(PageItemToSvgText(pageItem, titleLines[0])); return plstr; } // if the token was proctitle, dont' adjust. If the token was PROCTITLE1/2 then // move down 6. // int adj = pageItem.Token.Contains("1") || pageItem.Token.Contains("2") ? 0 : -6; int adj = (titleLines.Count > 2) ? -6 : 0; float yOffset = adj * (titleLines.Count - 2); int lnCnt = 0; foreach (string line in titleLines) { lnCnt++; if (lnCnt == 1) continue; plstr = plstr.Replace(match, line); svgGroup.Add(PageItemToSvgText(pageItem, plstr, yOffset)); plstr = ""; // clear it because it was added into the list in the line above this, i.e. don't duplicate yOffset += 12; } return plstr; } private int FindWidth(string title, int start, int len) { for (int ii = start + len; ii > start; ii--) { if (title[ii] == ' ') { while (title[ii] == ' ') ii--; if (ii > start) return 2 + ii - start; return len; } } return len; } private SvgPart PageItemToSvgUse(VEPROMS.CSLA.Library.PageItem pageItem, string templateName) { SvgUse svgUse = new SvgUse(); svgUse.UseID = templateName; svgUse.X = new SvgMeasurement((float)(pageItem.Col ?? 0), E_MeasurementUnits.PT); svgUse.Y = new SvgMeasurement((float)(pageItem.Row ?? 0), E_MeasurementUnits.PT); return svgUse; } private static SvgText PageItemToSvgText(VEPROMS.CSLA.Library.PageItem pageItem, string text, VE_Font font, SectionInfo mySection) { SvgText svgText = PageItemToSvgText(pageItem, text, mySection); svgText.Font = font.WindowsFont; return svgText; } private static SvgText PageItemToSvgText(VEPROMS.CSLA.Library.PageItem pageItem, string text, SectionInfo mySection) { SvgText svgText = new SvgText(); // F2021-053: Do replace words for Page List items. Send format items down to svgtext. SvgText.CompressSuper = mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSuper; SvgText.CompressSub = mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSub; SvgText.CompressPropSubSup = mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressPropSubSup; svgText.Text = text; VEPROMS.CSLA.Library.E_Justify justify = pageItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft; float colAdj16bit = 0; if ((justify & VEPROMS.CSLA.Library.E_Justify.PSLeft) == VEPROMS.CSLA.Library.E_Justify.PSLeft) svgText.Justify = SvgJustify.Left; else if ((justify & VEPROMS.CSLA.Library.E_Justify.PSRight) == VEPROMS.CSLA.Library.E_Justify.PSRight) svgText.Justify = SvgJustify.Right; else { svgText.Justify = SvgJustify.Center; if (((justify & VEPROMS.CSLA.Library.E_Justify.PSTrue) != VEPROMS.CSLA.Library.E_Justify.PSTrue) && !mySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.StepSectionLayoutData.PicaIgnoreFiveSixths) { // the default CPI for Proms is 12, in 16bit 12 is the default - if a font wasn't defined // or when doing a positioning calculation 12 was used. So we need to make an adjustment // to handle non-12 CPI (12CPI will just cancel out in the following calculation). // Take the difference between the width in Points of a character at 12CPI and a character // at the defined font's CPI. Multiply that times the length of title and divide by two // to find the half-way point. // if the PageItem's font CPI is null, then default to 12 CPI colAdj16bit = (1 + text.Length) * ((72 / (float)(pageItem.Font.CPI ?? 12)) - (72 / 12)) / 2; } } svgText.Font = pageItem.Font.WindowsFont; // F2021-070 & 066 - shrink font size of page list items if format has amount string tmpText = text; if (pageItem.FontShrinkAftLen != null && pageItem.FontShrinkAftLen > 0) svgText.FontSize = ShrinkIt(ref tmpText, svgText, (float)pageItem.FontShrinkAftLen, pageItem.FontTooSmallMsg); if (tmpText != text) svgText.Text = tmpText; float row = (float)pageItem.Row < 0 ? -(float)pageItem.Row : (float)pageItem.Row; if ((justify & VEPROMS.CSLA.Library.E_Justify.PSTop) == VEPROMS.CSLA.Library.E_Justify.PSTop) row -= ((72 / 6) / 2); float lcol = pageItem.Col ?? 0; // the column may need adjusted based on the document styles PageWidth. This was done in // the 16bit code and was needed here to get the printed output to match. if (pageItem.Font.FontIsProportional() && svgText.Justify == SvgJustify.Center) { int dotsPerChar = (int)(2400 / (mySection.MyDocStyle.Layout.PageWidth / 6)); lcol = (lcol * 25) / dotsPerChar; } svgText.X = new SvgMeasurement((float)lcol - colAdj16bit, E_MeasurementUnits.PT); svgText.Y = new SvgMeasurement(row, E_MeasurementUnits.PT); if (svgText.Font.Underline && svgText.Text.EndsWith(" ")) svgText.Text = svgText.Text.Substring(0, svgText.Text.Length - 1) + "\xA0";// replace last space with a hardspace // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine(" PL x {0} y {1} {2} {3} {4} \"{5}\"", svgText.X, svgText.Y, svgText.FontFamily, svgText.FontSize, svgText.SVGFontStyle, TextForBaseline.FixText(svgText.Text)); return svgText; } // F2021-070 & 066 - shrink font size of page list items if format has amount. ShrinkIt compares size (width) of text with input font and // will decrement font size by one until the text size is less than value from format file. // Additional work has been done for F2021-066 to allow for only shrinking to font size greater/equal to 8 and if it goes smaller than that // to put out a message. private static string ShrinkIt(ref string text, SvgText svgText, float fontShrinkAftLen, string reptext) { int tmpi = Convert.ToInt32(svgText.FontSize.Substring(0, svgText.FontSize.IndexOf("PT"))); string origFontSize = svgText.FontSize; using (var image = new System.Drawing.Bitmap(1, 1)) { using (var g = System.Drawing.Graphics.FromImage(image)) { try { // pageitem's font size did not have a 'set'. svgtext's fontsize is in format of 12PT, so get font size from that // and decrement until it is less than format value System.Drawing.SizeF mySize = g.MeasureString(text, svgText.Font); while (mySize.Width > fontShrinkAftLen && tmpi > 8) { tmpi = tmpi - 1; svgText.FontSize = tmpi.ToString() + "PT"; mySize = g.MeasureString(text, svgText.Font); } // Additional work for F2021-066: if font size goes less than or equal to 6, use original font size & if // there is a message in format file to use instead of text, then use it. if (tmpi == 8 && mySize.Width > fontShrinkAftLen) { if (reptext != null && reptext != "") text = reptext; else // As per PAL (11/15/21) have default message and highlight by italics (text was already bolded) { text = "Text Too Long To Fit"; svgText.SVGFontStyle = "italic"; } svgText.FontSize = origFontSize; } } catch // don't reset if error occurred. { } } } return svgText.FontSize; } private SvgPart PageItemToSvgText(VEPROMS.CSLA.Library.PageItem pageItem, string text, float yOffset) { SvgText svgText = new SvgText(); svgText.Text = text; VEPROMS.CSLA.Library.E_Justify justify = pageItem.Justify ?? VEPROMS.CSLA.Library.E_Justify.PSLeft; float colAdj16bit = 0; if ((justify & VEPROMS.CSLA.Library.E_Justify.PSLeft) == VEPROMS.CSLA.Library.E_Justify.PSLeft) svgText.Justify = SvgJustify.Left; else if ((justify & VEPROMS.CSLA.Library.E_Justify.PSRight) == VEPROMS.CSLA.Library.E_Justify.PSRight) svgText.Justify = SvgJustify.Right; else { svgText.Justify = SvgJustify.Center; if (((justify & VEPROMS.CSLA.Library.E_Justify.PSTrue) != VEPROMS.CSLA.Library.E_Justify.PSTrue) && !MySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.StepSectionLayoutData.PicaIgnoreFiveSixths) { // the default CPI for Proms is 12, in 16bit 12 is the default - if a font wasn't defined // or when doing a positioning calculation 12 was used. So we need to make an adjustment // to handle non-12 CPI (12CPI will just cancel out in the following calculation). // Take the difference between the width in Points of a character at 12CPI and a character // at the defined font's CPI. Multiply that times the length of title and divide by two // to find the half-way point. colAdj16bit = (1 + text.Length) * ((72 / (float)pageItem.Font.CPI) - (72 / 12)) / 2; } } float lcol = pageItem.Col ?? 0; // the column may need adjusted based on the document styles PageWidth. This was done in // the 16bit code and was needed here to get the printed output to match. if (pageItem.Font.FontIsProportional() && svgText.Justify == SvgJustify.Center) { int dotsPerChar = (int)(2400 / (MySection.MyDocStyle.Layout.PageWidth / 6)); lcol = (lcol * 25) / dotsPerChar; } svgText.Font = pageItem.Font.WindowsFont; svgText.X = new SvgMeasurement((float)lcol - colAdj16bit, E_MeasurementUnits.PT); // new SvgMeasurement((float)(pageItem.Col ?? 0), E_MeasurementUnits.PT); svgText.Y = new SvgMeasurement((float)(yOffset + pageItem.Row ?? 0), E_MeasurementUnits.PT); if (svgText.Font.Underline && svgText.Text.EndsWith(" ")) svgText.Text = svgText.Text.Substring(0, svgText.Text.Length - 1) + "\xA0";// replace last space with a hardspace // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine(" PL x {0} y {1} {2} {3} {4} \"{5}\"", svgText.X, svgText.Y, svgText.FontFamily, svgText.FontSize, svgText.SVGFontStyle, TextForBaseline.FixText(svgText.Text)); return svgText; } private SvgPart PageItemToSvgText(string token, float row, float col, E_Justify just, VE_Font font, string text, SectionInfo MySection) { SvgText svgText = new SvgText(); svgText.Text = text; VEPROMS.CSLA.Library.E_Justify justify = just; float colAdj16bit = 0; if ((justify & VEPROMS.CSLA.Library.E_Justify.PSLeft) == VEPROMS.CSLA.Library.E_Justify.PSLeft) svgText.Justify = SvgJustify.Left; else if ((justify & VEPROMS.CSLA.Library.E_Justify.PSRight) == VEPROMS.CSLA.Library.E_Justify.PSRight) svgText.Justify = SvgJustify.Right; else { svgText.Justify = SvgJustify.Center; if (((justify & VEPROMS.CSLA.Library.E_Justify.PSTrue) != VEPROMS.CSLA.Library.E_Justify.PSTrue) && !MySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.StepSectionLayoutData.PicaIgnoreFiveSixths) { // the default CPI for Proms is 12, in 16bit 12 is the default - if a font wasn't defined // or when doing a positioning calculation 12 was used. So we need to make an adjustment // to handle non-12 CPI (12CPI will just cancel out in the following calculation). // Take the difference between the width in Points of a character at 12CPI and a character // at the defined font's CPI. Multiply that times the length of title and divide by two // to find the half-way point. colAdj16bit = (1 + text.Length) * ((72 / (float)font.CPI) - (72 / 12)) / 2; } } float lcol = col; // the column may need adjusted based on the document styles PageWidth. This was done in // the 16bit code and was needed here to get the printed output to match. if (font.FontIsProportional() && svgText.Justify == SvgJustify.Center) { int dotsPerChar = (int)(2400 / (MySection.MyDocStyle.Layout.PageWidth / 6)); lcol = (lcol * 25) / dotsPerChar; } // F2021-053: Do replace words for Page List items. Send format items down to svgtext. SvgText.CompressSuper = MySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSuper; SvgText.CompressSub = MySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressHPSub; SvgText.CompressPropSubSup = MySection.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.CompressPropSubSup; svgText.Font = font.WindowsFont; svgText.X = new SvgMeasurement((float)lcol - colAdj16bit, E_MeasurementUnits.PT); // new SvgMeasurement((float)(pageItem.Col ?? 0), E_MeasurementUnits.PT); svgText.Y = new SvgMeasurement(row, E_MeasurementUnits.PT); if (svgText.Font.Underline && svgText.Text.EndsWith(" ")) svgText.Text = svgText.Text.Substring(0, svgText.Text.Length - 1) + "\xA0";// replace last space with a hardspace // C2018-004 create meta file for baseline compares Volian.Base.Library.BaselineMetaFile.WriteLine(" PL x {0} y {1} {2} {3} {4} \"{5}\"", svgText.X, svgText.Y, svgText.FontFamily, svgText.FontSize, svgText.SVGFontStyle, TextForBaseline.FixText(svgText.Text)); return svgText; } private static List _MissingTokens = new List(); protected override string ReplacePageListToken(Match match) { switch (match.Value) { case "{PAGE}": // Current Page Number return CurrentPageNumber.ToString(); case "{OF}": // Total Page Count for this section return CurrentPageOf.ToString(); case "{REV}": // Revision Number and/or Revision string. case "{REV2}": // The 16bit code has a revision number & then a revision date. This revision date // was actually either a date OR a string. The 32bit code no longer will call this // token or string RevDate. HLP procs & stpdif show the different types of data // that are used. // 16-bit had code to string preceeding blanks. if (Rev != null && Rev != "") Rev = Rev.TrimStart(" ".ToCharArray()); // Now check the format flags to determine if/how the Rev string should be parsed. if ((MySection.ActiveFormat.PlantFormat.FormatData.PrintData.DoRevDate && Rev.Contains("/")) || (MySection.ActiveFormat.PlantFormat.FormatData.PrintData.RevDateWithForwardSlash && Rev.Contains("\\"))) { int indx = Rev.IndexOf(MySection.ActiveFormat.PlantFormat.FormatData.PrintData.RevDateWithForwardSlash ? '\\' : '/'); if (match.Value == "{REV}") return Rev.Substring(0,indx); return Rev.Substring(indx+1); } if (match.Value == "{REV}")return Rev; return System.DateTime.Today.ToShortDateString(); case "{CHKOFFHEADING}": return PageListTopCheckOffHeader; case "{ROMANPAGE}": return ItemInfo.RomanNumbering(CurrentPageNumber).ToLower(); case "{SETREV}": return MySection.MyDocVersion.DocVersionConfig.ProcedureSetRev; case "{NULLDOCCURPAGE}": return ""; } if (!_MissingTokens.Contains(match.Value)) { _MissingTokens.Add(match.Value); _MyLog.InfoFormat("Unhandled token {0}", match.Value); } return ""; } } public class ChkListBoxesHelper : List { private float _yOffsetStart; private float _yOffsetEnd; public ChkListBoxesHelper() : base() { } public void Add(ItemInfo myHls, float yoffStart, float yoffend) { Add(new ChkListBoxHelper()); } public void Draw() { foreach (ChkListBoxHelper cb in this) { } } } public class ChkListBoxHelper { public ChkListBoxHelper() { } } public class PageBookmarks : List { public PageBookmarks() : base() { } public void Add(ItemInfo itemInfo, string title, PdfDestination pdfDestination) { foreach (PageBookmark pb in this) if (pb.Title == title) return; Add(new PageBookmark(itemInfo, title, pdfDestination)); } } public class PageBookmark { private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { return _MyItemInfo; } set { _MyItemInfo = value; } } private string _Title; public string Title { get { return _Title; } set { _Title = value; } } private PdfDestination _PdfDestination; public PdfDestination PdfDestination { get { return _PdfDestination; } set { _PdfDestination = value; } } public PageBookmark(ItemInfo itemInfo, string title, PdfDestination pdfDestination) { _MyItemInfo = itemInfo; _Title = title; _PdfDestination = pdfDestination; } internal bool IsTopLevel { get { ItemInfo parent = MyItemInfo.ActiveParent as ItemInfo; if (parent == null || parent.IsProcedure) return true; return false; } } internal int Level { get { int level = 0; ItemInfo parent = MyItemInfo.ActiveParent as ItemInfo; while (parent != null && !parent.IsProcedure) { level++; parent = parent.ActiveParent as ItemInfo; } return level; } } } public class ChangeBarDefinition // anything that is section level should go in here. { private PrintChangeBar _MyChangeBarType; public PrintChangeBar MyChangeBarType { get { return _MyChangeBarType; } set { _MyChangeBarType = value; } } private PrintChangeBarLoc _MyChangeBarLoc; public PrintChangeBarLoc MyChangeBarLoc { get { return _MyChangeBarLoc; } set { _MyChangeBarLoc = value; } } private PrintChangeBarText _MyChangeBarText; public PrintChangeBarText MyChangeBarText { get { return _MyChangeBarText; } set { _MyChangeBarText = value; } } private string _MyChangeBarMessage; // user defined change bar message from docconfig public string MyChangeBarMessage { get { return _MyChangeBarMessage; } set { _MyChangeBarMessage = value; } } private int _MyChangeBarColumn; // two dimensional array, if both on same side, values are = public int MyChangeBarColumn { get { return _MyChangeBarColumn; } set { _MyChangeBarColumn = value; } } /* * could have line thickness (set default from 16-bit), line color (set default as black), line style */ public ChangeBarDefinition() { } public ChangeBarDefinition(PrintChangeBar myCBT, PrintChangeBarLoc myCBL, PrintChangeBarText myCBTxt, string myCBMsg) { _MyChangeBarType = myCBT; _MyChangeBarLoc = myCBL; _MyChangeBarText = myCBTxt; } public ChangeBarDefinition(DocVersionConfig docverConfig, FormatInfo formatInfo) { // if there is not overridden data on the docversion, prompt user... ChangeBarData changeBarData = formatInfo.PlantFormat.FormatData.ProcData.ChangeBarData; if (docverConfig == null || docverConfig.Print_ChangeBar == PrintChangeBar.SelectBeforePrinting) { // use these for now, i.e. this is what user would have selected from dialog. _MyChangeBarType = PrintChangeBar.WithDefault; _MyChangeBarLoc = PrintChangeBarLoc.OutsideBox; _MyChangeBarText = PrintChangeBarText.None; } else { _MyChangeBarType = docverConfig.Print_ChangeBar; _MyChangeBarLoc = docverConfig.Print_ChangeBarLoc; _MyChangeBarText = docverConfig.Print_ChangeBarText; } if (_MyChangeBarType == PrintChangeBar.WithDefault) // get data from format { _MyChangeBarText = changeBarData.ChangeBarMessage == "ChgID" ? PrintChangeBarText.ChgID : changeBarData.ChangeBarMessage == "DateAndChgID" ? PrintChangeBarText.DateChgID : changeBarData.ChangeBarMessage == "None" ? PrintChangeBarText.None : changeBarData.ChangeBarMessage == "RevNum" ? PrintChangeBarText.RevNum : PrintChangeBarText.UserDef; } if (_MyChangeBarType != PrintChangeBar.Without) { // if the format has the absolutefixedchangecolumn format flag, then always use the fixedchangecolumn from the // format, otherwise, use the default column based on the selected location, stored in the base format. _MyChangeBarColumn = (changeBarData.AbsoluteFixedChangeColumn) ? (int)changeBarData.FixedChangeColumn : System.Convert.ToInt32(changeBarData.DefaultCBLoc.Split(",".ToCharArray())[(int)(_MyChangeBarLoc)]); if (_MyChangeBarText == PrintChangeBarText.UserDef) _MyChangeBarMessage = docverConfig.Print_UserCBMess1 + @"\n" + docverConfig.Print_UserCBMess2; } } } public class CheckOffHeaderHelper { private SvgText _SvgText; public SvgText SvgText { get { return _SvgText; } set { _SvgText = value; } } private VEPROMS.CSLA.Library.VE_Font _CheckOffHeaderFont; public VEPROMS.CSLA.Library.VE_Font CheckOffHeaderFont { get { return _CheckOffHeaderFont; } set { _CheckOffHeaderFont = value; } } public CheckOffHeaderHelper(SvgText stext, VEPROMS.CSLA.Library.VE_Font vf) { _SvgText = stext; _CheckOffHeaderFont = vf; } } public class Gap { private float _YTop; public float YTop { get { return _YTop; } set { _YTop = value; } } private float _YBottom; public float YBottom { get { return _YBottom; } set { _YBottom = value; } } public Gap(float yTop, float yBottom) { _YTop = yTop; _YBottom = yBottom; } } public class Gaps : List { public void Add(float yTop, float yBotttom) { this.Add(new Gap(yTop, yBotttom)); } } }