using System; using System.Collections.Generic; using System.Text; using VEPROMS.CSLA.Library; using iTextSharp.text.pdf; using iTextSharp.text; using System.IO; using System.Text.RegularExpressions; using System.Collections; namespace Volian.Print.Library { // B2022-026 New code for RO Memory reduction - now use SQL tables instead of building dictionarys to get RO values public class PDFReport { #region Enums public enum ReportType { SearchResults = 0, LibraryDocUsage = 1, ReferencedObjectsUsage = 2, TransitionUsage = 3, ReferencedObjectSummary = 4, ReferencedObjectComplete = 5 } #endregion #region Fields private PdfWriter _MyPdfWriter; private ICollection _ResultList; private string _FileName; private string _ReportTitle; private string _TypesSelected; private bool _ShowAnnotations = true; private string _SearchString; private string _SortedBy; // C2019-013 pass in sorting information private DocumentInfoList _LibDocList; private int _ReportType = 0; private string _ByLine; private bool _SortUsageByProcedure = false; private string _RODataFile = string.Empty; private List _ROList; private ROFSTLookup _ROFSTLookup; private bool _IncludeMissingROs = false; private bool _ConvertCaretToDelta = true; private bool _IncludeEmptyROFields = false; private string _PaperSize = "Letter"; // C2020-002 paper size is now set in the format files private string _RegexSearchString = null; private ArrayList ProcSetList; #endregion #region Properties public ICollection ResultList { get { return _ResultList; } set { _ResultList = value; } } public string FileName { get { return _FileName; } set { _FileName = value; } } public string ReportTitle { get { return _ReportTitle; } set { _ReportTitle = value; } } public string TypesSelected { get { return _TypesSelected; } set { _TypesSelected = value; } } public bool ShowAnnotations { get { return _ShowAnnotations; } set { _ShowAnnotations = value; } } public string SearchString { get { return _SearchString; } set { _SearchString = VEPROMS.CSLA.Library.ItemInfo.ConvertToDisplayText(value); } } public string SortedBy { get { return _SortedBy; } set { _SortedBy = value; } } public DocumentInfoList LibDocList { get { return _LibDocList; } set { _LibDocList = value; } } private string RegexSearchString { get { if (_RegexSearchString == null) { _RegexSearchString = _SearchString; // Make it match the smallest matching string _RegexSearchString = _RegexSearchString.Replace("*", ".*?"); // If search string starts with a wildcard use the beginning of line token (^) if (_RegexSearchString.StartsWith(".*?")) { _RegexSearchString = "^" + _RegexSearchString; } // If search string ends with a wildcard use the end of line token ($) if (_RegexSearchString.EndsWith(".*?")) { _RegexSearchString = _RegexSearchString + "$"; } _RegexSearchString = _RegexSearchString.Replace("[", @"\["); _RegexSearchString = _RegexSearchString.Replace("]", @"\]"); _RegexSearchString = _RegexSearchString.Replace("(", @"\("); _RegexSearchString = _RegexSearchString.Replace(")", @"\)"); } return _RegexSearchString; } } #endregion #region Constructors /// /// Search Results Report /// /// /// /// /// /// /// public PDFReport(string reportTitle, string typesSelected, ICollection resultList, string fileName, string paperSize, string sortedBy) { _ResultList = resultList; _FileName = fileName; _ReportTitle = VEPROMS.CSLA.Library.ItemInfo.ConvertToDisplayText(reportTitle); _TypesSelected = VEPROMS.CSLA.Library.ItemInfo.ConvertToDisplayText(typesSelected); _ReportType = (int)ReportType.SearchResults; _ByLine = "PROMS Search Results"; _PaperSize = paperSize; _SortedBy = sortedBy; // C2019--13 pass in sorted by information } /// /// Library Document Report /// /// /// /// /// public PDFReport(string reportTitle, DocumentInfoList libDocList, string fileName, string paperSize) { _LibDocList = libDocList; _FileName = fileName; _ReportTitle = VEPROMS.CSLA.Library.ItemInfo.ConvertToDisplayText(reportTitle); _ReportType = (int)ReportType.LibraryDocUsage; _ByLine = "Generated By PROMS"; _PaperSize = paperSize; } /// /// RO Usage /// /// /// /// /// /// /// public PDFReport(string reportTitle, ICollection resultList, string fileName, bool sortUsageByProcedure, bool includeMissingROs, string paperSize) { _ResultList = resultList; _FileName = fileName; _ReportTitle = VEPROMS.CSLA.Library.ItemInfo.ConvertToDisplayText(reportTitle); _ReportType = (int)ReportType.ReferencedObjectsUsage; _ByLine = "Generated By PROMS"; _SortUsageByProcedure = sortUsageByProcedure; _IncludeMissingROs = includeMissingROs; _PaperSize = paperSize; } /// /// RO Complete RO Report /// /// /// /// /// /// /// /// /// public PDFReport(string reportTitle, string roDataFile, string outfile, ROFSTLookup fstlookup, bool completeReport, bool convertCaretToDelta, bool includeEmptyROFields, string paperSize) { _FileName = outfile; _ReportTitle = reportTitle; _ReportType = (int)ReportType.ReferencedObjectComplete; _ByLine = "Complete Referenced Objects Report"; _RODataFile = roDataFile; _ConvertCaretToDelta = convertCaretToDelta; _ROFSTLookup = fstlookup; _IncludeEmptyROFields = includeEmptyROFields; _PaperSize = paperSize; } /// /// RO Summary Report /// /// /// /// /// /// public PDFReport(string reportTitle, string outfile, ROFSTLookup fstlookup, List roList, string paperSize) { _FileName = outfile; _ReportTitle = reportTitle; _ReportType = (int)ReportType.ReferencedObjectSummary; _ByLine = "RO Summary Report"; _ROFSTLookup = fstlookup; _ROList = roList; _PaperSize = paperSize; } #endregion #region Public Methods public void AddMainRODatabaseTitle(PdfPTable datatable, int dbTitleIndex, Font f2, Color bgColor) { string dbTitle = _ROFSTLookup.GetRODatabaseTitle(dbTitleIndex); PdfPCell cell = new PdfPCell(new Phrase(dbTitle, f2)); cell.BorderColor = Color.WHITE; cell.Colspan = 2; cell.BackgroundColor = bgColor; datatable.AddCell(cell); } public void AddMainPathGroup(PdfPTable datatable, string dvPath, int splitLevel, Font f2, Color bgColor, int colSpan) { int level = 0; StringBuilder sb = new StringBuilder(); string[] NewPath = dvPath.Split("\x7".ToCharArray()); string sep = string.Empty; int n = NewPath.Length; for (int j = 1; j < n && j < splitLevel; j++) { sb.Append(sep + "".PadLeft(2 * level) + NewPath[j].Replace("\x11", " ")).Replace(@"\u8209?", "-").Replace(@"\u9586?", @"\"); sep = "\r\n"; level++; } if (sb.Length > 0) { PdfPCell cell = new PdfPCell(new Phrase(sb.ToString(), f2)); cell.Colspan = colSpan; cell.BackgroundColor = bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } } public void AddSubPathGroup(PdfPTable datatable, string oldDVPath, string dvPath, int splitLevel, Font f2, Color bgColor, int colSpan) { int level = 0; StringBuilder sb = new StringBuilder(); string[] NewPath = dvPath.Split("\x7".ToCharArray()); string[] OldPath = oldDVPath.Split("\x7".ToCharArray()); string sep = string.Empty; int n = NewPath.Length - 1; for (int i = 0; i < n; i++) { if (OldPath[i] != NewPath[i]) { splitLevel = Math.Max(splitLevel, i); break; } } if (splitLevel < n) { for (int j = splitLevel; j < n; j++) { sb.Append(sep + "".PadLeft(2 * level) + NewPath[j].Replace("\x11", " ")).Replace(@"\u8209?", "-").Replace(@"\u9586?", @"\"); sep = "\r\n"; level++; } if (sb.Length > 0) { PdfPCell cell = new PdfPCell(new Phrase(sb.ToString(), f2)); cell.Colspan = colSpan; cell.BackgroundColor = bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } } } public void Build() { iTextSharp.text.Document document = new iTextSharp.text.Document(PDFPageSize.UsePaperSize(_PaperSize), 36, 36, 36, 36); // C2020-002 paper size is now set in the format files if (!CreateResultsPDF(document, _ReportType)) return; try { switch (_ReportType) // set in the PDFReport constructor { case (int)ReportType.SearchResults: BuildSearchResultsTable(document); break; case (int)ReportType.LibraryDocUsage: BuildLibDocUsageReport(document); break; case (int)ReportType.ReferencedObjectsUsage: if (_SortUsageByProcedure) BuildROUsageTableByProcedure(document); else BuildROUsageTableByRO(document); break; case (int)ReportType.ReferencedObjectComplete: BuildCompleteROReport(document); break; case (int)ReportType.ReferencedObjectSummary: BuildROSummaryReport(document); break; } } catch (Exception ex) { StringBuilder msg = new StringBuilder(); document.Add(new Paragraph("Error:")); while (ex != null) { document.Add(new Paragraph(ex.GetType().Name)); document.Add(new Paragraph(ex.Message)); ex = ex.InnerException; } } finally { if (document.IsOpen()) { //document.Add(new Phrase("End of Search Results",FontFactory.GetFont("Arial",4))); // B2019-089 commented out - used for debug document.Add(new Phrase(" ", FontFactory.GetFont("Arial", 4))); // B2019-089 - assure output has at least a blank space to prevent error on close document.Close(); System.Diagnostics.Process.Start(_FileName); } } } #endregion #region Private Methods private string AddGroup(PdfPTable datatable, string dvPath, string lastDvPath, Font f2, bool StripLast, Color bgColor, bool skipFirst) { int level = 0; string retval = string.Empty; StringBuilder sb = new StringBuilder(); string ttt = dvPath.Replace("\x11", " "); string[] OldPath = lastDvPath.Split("\x7".ToCharArray()); string[] NewPath = dvPath.Split("\x7".ToCharArray()); string sep = string.Empty; bool foundMisMatch = false; // n-1 Exclude the "Working Draft" entry from the list int n = NewPath.Length - 1; int jstart = (skipFirst) ? 1 : 0; if (StripLast) { retval = NewPath[--n]; if (retval.Contains("\x11")) { retval = retval.Substring(0, retval.IndexOf("\x11")); // this is the step number } } if (n == 0) { // B2020-006: 'clean-up' the output string by making string replaces as in 'else' below. sb.Append(dvPath.Replace("\x11", " ").Replace(@"\u8209?", "-").Replace(@"\u160?", " ").Replace(@"\u9586?", @"\")); } else { for (int j = jstart; j < n; j++) { if (!string.IsNullOrEmpty(NewPath[j]) && (foundMisMatch || OldPath.Length < j + 1 || NewPath[j] != OldPath[j])) { // B2020-006: Add hard space '\u160?' sb.Append(sep + "".PadLeft(2 * level) + NewPath[j].Replace("\x11", " ")).Replace(@"\u8209?", "-").Replace(@"\u160?", " ").Replace(@"\u9586?", @"\"); sep = "\r\n"; foundMisMatch = true; } level++; } } if (sb.Length > 0) { PdfPCell cell = new PdfPCell(new Phrase(sb.ToString(), f2)); cell.Colspan = 2; cell.BackgroundColor = bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } return retval; } private string AddGroupLibDoc(PdfPTable datatable, string dvPath, string lastDvPath, Font f2, bool StripLast, Color bgColor, bool skipFirst) { int level = 0; string retval = string.Empty; StringBuilder sb = new StringBuilder(); string ttt = dvPath.Replace("\x11", " "); string[] OldPath = lastDvPath.Split("\x7".ToCharArray()); string[] NewPath = dvPath.Split("\x7".ToCharArray()); string sep = string.Empty; bool foundMisMatch = false; int n = NewPath.Length - 1; int jstart = (skipFirst) ? 1 : 0; if (StripLast) { retval = NewPath[--n]; if (retval.Contains("\x11")) { retval = retval.Substring(0, retval.IndexOf("\x11")); // this is the step number } } //If no colons output the entire text if (n == 0) { sb.Append(dvPath); } else { for (int j = jstart; j < n; j++) { if (!string.IsNullOrEmpty(NewPath[j]) && (foundMisMatch || OldPath.Length < j + 1 || NewPath[j] != OldPath[j])) { sb.Append(sep + "".PadLeft(2 * level) + NewPath[j].Replace("\x11", " ")).Replace(@"\u8209?", "-").Replace(@"\u9586?", @"\"); sep = "\r\n"; foundMisMatch = true; } level++; } } if (sb.Length > 0) { PdfPCell cell = new PdfPCell(new Phrase(sb.ToString(), f2)); cell.Colspan = 2; cell.BackgroundColor = bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } return retval; } private void AddProcedureSectionGroup(PdfPTable datatable, string curProc, string lastProc, string curSect, string lastSect, Font f2, Color bgColor) { string headerText = string.Empty; if (curProc != lastProc) headerText = curProc + "\r\n"; if (curSect != lastSect) headerText += " " + curSect; if (headerText.Length > 0) { headerText = headerText.Replace(@"\u8209?", "-");// repace unicode with dash char headerText = headerText.Replace(@"\u160?", " "); // replace Hard Space with normal Space headerText = headerText.Replace(@"\u9586?", @"\"); // replace backslash symbol with a backslash PdfPCell cell = new PdfPCell(new Phrase(headerText, f2)); cell.Colspan = 2; cell.BackgroundColor = bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } } private string GetCurProcNum(string path) { string[] NewPath = path.Split("\x7".ToCharArray()); string pnumtitle = NewPath[1]; pnumtitle = pnumtitle.Replace('\x11', ' '); return pnumtitle; } private string GetCurSectionNumTitle(ItemInfo itm) { string rtnstr = string.Empty; if (itm.ActiveSection != null) { rtnstr = itm.ActiveSection.DisplayNumber; if (rtnstr.Length > 0) rtnstr += " "; rtnstr += itm.ActiveSection.DisplayText; } return rtnstr; // string containing section and subsection number/titles } private int FindSpitLevel() { int level = 0; bool foundMisMatch = false; string lastPath = string.Empty; foreach (string p in ProcSetList) { string[] NewPath = p.Split("\x7".ToCharArray()); if (lastPath != string.Empty) { string[] OldPath = lastPath.Split("\x7".ToCharArray()); int n = NewPath.Length; int lvl = 0; foundMisMatch = false; for (int j = 0; j < n && !foundMisMatch; j++) { if (NewPath[j] != string.Empty && (OldPath.Length < j + 1 || NewPath[j] != OldPath[j])) { foundMisMatch = true; } lvl++; } if (level == 0) level = lvl; if (foundMisMatch) level = Math.Min(level, lvl); } lastPath = p; if (ProcSetList.Count == 1) { level = NewPath.Length - 1; } } return level; } /// /// Attempt to open a file for the PDF output. /// If the file cannot be opened because it is in use, try adding a suffix /// If the file cannot be opened for some other reason, display an error message /// /// /// private bool CreateResultsPDF(iTextSharp.text.Document document, int typ) { int topMargin = 36; switch (typ) { case (int)ReportType.LibraryDocUsage: topMargin = 80; // Add some space for the Report Header for the Library Document Report break; } bool result = false; string suffix = string.Empty; int i = 0; // Try to open a file for creating the PDF. while (result == false) { string fileName = _FileName.ToLower().Replace(".pdf", suffix + ".pdf"); try { _MyPdfWriter = PdfWriter.GetInstance(document, new FileStream(fileName, FileMode.Create)); _MyPdfWriter.PageEvent = new MyPageHelper(_ByLine); // JSJ - 7/8/2011 document.SetMargins(36, 36, topMargin, 36); document.Open(); _FileName = fileName; result = true; } catch (System.IO.IOException exIO) { if (exIO.Message.Contains("because it is being used by another process")) { suffix = string.Format("_{0}", ++i);// If this file is in use, increment the suffix and try again } else // If some other error, display a message and don't print the results { ShowException(exIO); return false; } } catch (Exception ex) { ShowException(ex); return false; // Could not open the output file } } return true; } /// /// Use Cells within Cells to see if I can limit the way Cells break from Page to Page /// /// private void BuildSearchResultsTable(iTextSharp.text.Document document) { float[] headerwidths = { 20, 80 }; PdfPTable datatable = new PdfPTable(1); PdfPTable colHeader = new PdfPTable(headerwidths); //datatable.FooterRows = 1; datatable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; datatable.LockedWidth = true; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f1 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); iTextSharp.text.Font f3 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 12, 0, Color.BLACK); PdfPCell cell = new PdfPCell(new Phrase(ReportTitle, f1)); cell.HorizontalAlignment = Element.ALIGN_CENTER; cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); // light cyan datatable.AddCell(cell); // C2019-013 add sorted by information if sorting is used cell = new PdfPCell(new Phrase(TypesSelected + ((SortedBy.Length > 0) ? string.Format("\n{0}", SortedBy) : string.Empty), f3)); cell.HorizontalAlignment = Element.ALIGN_LEFT; cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); // light cyan datatable.AddCell(cell); BuildSearchResultsProcSetList(); datatable.HeaderRows = 4 + (ProcSetList.Count == 1 ? 1 : 0); int splitAt = FindSpitLevel(); // find the split level of the common path - for all procedure sets that use these library documents Color subHeaderColor = new Color(0xD0, 0xF0, 0xF0); // new Color(0xD0, 0xF0, 0xD0); datatable.DefaultCell.Padding = 0; // this removes a white space after the header was set to 4; datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER; AddCell(colHeader, "Step", f2, subHeaderColor); AddCell(colHeader, "Text", f2, subHeaderColor); datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT; string lastPath = string.Empty; Color AnnoColor = new Color(0xFF, 0xFF, 0xC0); // yellow Color TextColor = Color.WHITE; Color WordSectColor = new Color(0xE8, 0xE8, 0xE8);// light grey Color StepSectColor = new Color(0xE7, 0xFF, 0xE7); // lighter green PdfPTable subTable = new PdfPTable(headerwidths); string lastProcNum = string.Empty; string lastDVPath = string.Empty; string lastSectNumAndTitle = string.Empty; List processedItems = new List(); foreach (ItemInfo item in _ResultList) { if (!processedItems.Contains(item.ItemID)) { processedItems.Add(item.ItemID); if (lastDVPath != item.SearchDVPath) { datatable.AddCell(subTable); subTable = new PdfPTable(headerwidths); AddMainPathGroup(datatable, item.SearchDVPath, splitAt, f2, new Color(0xB0, 0xF0, 0xF0), 0);// little brighter cyan datatable.AddCell(colHeader); lastProcNum = string.Empty; lastSectNumAndTitle = string.Empty; // C2020-019 reset we are processing a different procedure set } lastDVPath = item.SearchDVPath; string curProcNum = GetCurProcNum(item.SearchPath); if (subTable.Rows.Count > 0) // prevent first page from being blank { datatable.AddCell(subTable); subTable = new PdfPTable(headerwidths); } if (curProcNum != lastProcNum) { lastSectNumAndTitle = string.Empty; // C2020-019 reset we are processing a different procedure } lastProcNum = curProcNum; // B2020-006: When doing a section, don't remove the last item or the procedure title won't print (if section is only item found w/ search string) string stepPath = AddGroup(subTable, item.SearchPath ?? item.ShortPath, lastPath, f2, item.IsSection ? false : true, new Color(0xC0, 0xFF, 0xC0), true); // light green for procedure number and title // C2020-019 add section number and title if is different from last item and it is not a Word Section (item will be a section if search item was found in a Word section) string curSectNumTitle = GetCurSectionNumTitle(item); if (curSectNumTitle != string.Empty && curSectNumTitle != lastSectNumAndTitle && !item.IsSection) { AddColSpanCell(subTable, curSectNumTitle, f2, StepSectColor, 2, 0); lastSectNumAndTitle = curSectNumTitle; } lastPath = item.SearchPath ?? item.ShortPath; stepPath = BuildStepTab(item); AddCell(subTable, stepPath, f2, (item.IsSection ? WordSectColor : TextColor)); AddCell(subTable, item.DisplayText, f2, (item.IsSection ? WordSectColor : TextColor)); if (ShowAnnotations && item.ItemAnnotationCount > 0) { foreach (AnnotationInfo ai in item.ItemAnnotations) { AddCell(subTable, ai.MyAnnotationType.Name, f2, AnnoColor); AddCell(subTable, ai.SearchText, f2, AnnoColor); } } } } datatable.AddCell(subTable); document.Add(datatable); } private void AddCell(PdfPTable datatable, string str, iTextSharp.text.Font fnt, Color bgColor) { iTextSharp.text.Font fntBold = new Font(fnt.BaseFont, fnt.Size, Font.BOLD, Color.RED); Phrase p = BuildPhrase2(str, fnt, fntBold); PdfPCell cell = new PdfPCell(p); cell.PaddingBottom = 4; cell.BackgroundColor = bgColor; datatable.AddCell(cell); } private void AddColSpanCell(PdfPTable datatable, string str, iTextSharp.text.Font fnt, Color bgColor, int span, int txtAlign) { iTextSharp.text.Font fntBold = new Font(fnt.BaseFont, fnt.Size, Font.BOLD, Color.RED); Phrase p = BuildPhrase2(str, fnt, fntBold); PdfPCell cell = new PdfPCell(p); cell.PaddingBottom = 4; cell.BackgroundColor = bgColor; cell.Colspan = span; cell.HorizontalAlignment = txtAlign; datatable.AddCell(cell); } private Phrase BuildPhrase(string str, Font fnt, Font fntBold) { Phrase p = new Phrase(); if (_SearchString != null) { while (str.ToLower().Contains(_SearchString.ToLower())) { int iStart = str.ToLower().IndexOf(_SearchString.ToLower()); if (iStart > 0) { p.Add(new Phrase(str.Substring(0, iStart), fnt)); } Phrase p2 = new Phrase(str.Substring(iStart, _SearchString.Length), fntBold); p.Add(p2); str = str.Substring(iStart + _SearchString.Length); } } if (str.Length > 0) p.Add(new Phrase(str, fnt)); return p; } private Phrase BuildPhrase2(string str, Font fnt, Font fntBold) { Phrase p = new Phrase(); int lastIndex = 0; if ((_SearchString ?? string.Empty) != string.Empty) { Regex reg = new Regex(RegexSearchString, RegexOptions.Multiline | RegexOptions.IgnoreCase); foreach (Match m in reg.Matches(str)) { if (m.Index > 0) p.Add(new Phrase(str.Substring(lastIndex, m.Index - lastIndex), fnt)); Chunk chk = new Chunk(m.Value, fnt); chk.SetBackground(Color.YELLOW); p.Add(chk); lastIndex = m.Index + m.Length; } } p.Add(new Phrase(str.Substring(lastIndex), fnt)); return p; } private void BuildLibDocUsageReport(iTextSharp.text.Document document) { // Adjusted from 20,80 to 25,75 to account for long Procedure Numbers float[] headerwidths = { 25, 75 }; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); BuildLibDocProcSetList(); int splitAt = FindSpitLevel() - 1; // find the split level of the common path - for all procedure sets that use these library documents string lastDvPath = string.Empty; Color AnnoBackgroundColor = new Color(0xFF, 0xFF, 0xC0); Color TextBackgroundColor = Color.WHITE; Color NotUsedBackgroundColor = Color.WHITE; MyPageHelper pghlp = _MyPdfWriter.PageEvent as MyPageHelper; pghlp.HeaderTable = LibDocTable(document, headerwidths, f2, null); foreach (DocumentInfo di in _LibDocList) { PdfPTable subtable; subtable = BuildSubTable(document, headerwidths); AddGroupLibDoc(subtable, di.DocumentTitle, string.Empty, f2, false, new Color(0xC0, 0xFF, 0xC0), false); // Library Document Title if (di.DocumentConfig.LibDoc_Comment != null && di.DocumentConfig.LibDoc_Comment.Length > 0) { AddCell(subtable, "Comment", f2, AnnoBackgroundColor); AddCell(subtable, di.DocumentConfig.LibDoc_Comment, f2, AnnoBackgroundColor); // lib doc comment } if (di.DocumentEntries == null || di.DocumentEntries.Count == 0) { AddGroupLibDoc(subtable, "* No References To This Library Document *", string.Empty, f2, false, TextBackgroundColor, false); // Library Document Title } else { subtable.HeaderRows = 2; System.Collections.ArrayList LibDocUsageList = GetSortedItemInfoList(di.LibraryDocumentUsageList); lastDvPath = string.Empty; foreach (ItemInfo item in LibDocUsageList)//di.LibraryDocumentUsageList) { if (item.SearchDVPath != lastDvPath) { if (lastDvPath != string.Empty) { document.Add(subtable); subtable = BuildSubTable(document, headerwidths); subtable.HeaderRows = 2; AddGroupLibDoc(subtable, di.DocumentTitle, string.Empty, f2, false, new Color(0xC0, 0xFF, 0xC0), false); // Library Document Title } AddSubPathGroup(subtable, lastDvPath, item.SearchDVPath, splitAt, f2, Color.LIGHT_GRAY, 2);//new Color(0xC0, 0xFF, 0xC0)); } lastDvPath = item.SearchDVPath; string ProcNumber = item.MyProcedure.ProcedureConfig.Number; ProcNumber = ProcNumber.Replace(@"\u8209?", "-"); // repace unicode with dash char ProcNumber = ProcNumber.Replace(@"\u160?", " "); // replace Hard Space with normal Space ProcNumber = ProcNumber.Replace(@"\u9586?", @"\"); // replace backslash symbol with a backslash AddCell(subtable, ProcNumber, f2, TextBackgroundColor); AddCell(subtable, item.DisplayNumber + " - " + item.DisplayText, f2, TextBackgroundColor); } } document.Add(subtable); } } private PdfPTable LibDocTable(iTextSharp.text.Document document, float[] headerwidths, iTextSharp.text.Font f2, DocumentInfo di) { PdfPTable datatable = new PdfPTable(1);// (headerwidths); PdfPTable colheader = new PdfPTable(headerwidths); datatable.HeaderRows = 2; datatable.KeepTogether = false; datatable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; datatable.LockedWidth = true; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f1 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); iTextSharp.text.Font f3 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 12, 0, Color.BLACK); PdfPCell cell = new PdfPCell(new Phrase(ReportTitle, f1)); cell.HorizontalAlignment = Element.ALIGN_CENTER; //cell.Colspan = 2; cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); datatable.AddCell(cell); Color subHeaderColor = new Color(0xD0, 0xF0, 0xD0); datatable.DefaultCell.Padding = 4; datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER; AddCell(colheader, "Procedure", f2, subHeaderColor); AddCell(colheader, "Section", f2, subHeaderColor); datatable.AddCell(colheader); datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT; return datatable; } private void AddROUsages(ItemInfo item, Dictionary> roUse) { if (item != null && !string.IsNullOrEmpty(item.FoundROID)) { string roid = item.FoundROID; if (roUse.ContainsKey(roid)) { ((List)roUse[roid]).Add(item); } else { List itmIfoLst = new List(); itmIfoLst.Add(item); roUse.Add(roid, itmIfoLst); } } } private void PutROusageForProcedure(PdfPTable curTable, Dictionary> rosused, float[] headerwidths) { //if (rosused.Count == 0) return; // nothing to process // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); foreach (string roKey in rosused.Keys) { PdfPTable rotable = new PdfPTable(headerwidths); string rotitle = string.Empty; foreach (ItemInfo itm in rosused[roKey]) { if (string.IsNullOrEmpty(rotitle)) { rotitle = GetROTitleAndGroup(roKey, itm); if (!string.IsNullOrEmpty(rotitle)) { PdfPCell ROTitleCell = new PdfPCell(new Phrase(rotitle, f2)); ROTitleCell.Colspan = 2; ROTitleCell.HorizontalAlignment = Element.ALIGN_LEFT; if (rotitle.StartsWith("Missing RO")) { ROTitleCell.BackgroundColor = Color.PINK; } else { ROTitleCell.BackgroundColor = new Color(0xDC, 0xE7, 0xC9); //new Color(0xD0, 0xF0, 0xD0);//ligt green //new Color(0xC8, 0xC8, 0x91);//(0xAF, 0xD8, 0xD8);//(0xF5, 0xE4, 0xA0); } rotable.AddCell(ROTitleCell); // put RO value and description } } string stepnum = string.Empty; string sectitle = (itm.ActiveSection != null) ? itm.ActiveSection.DisplayText : string.Empty; if (itm.IsSection) { stepnum = (itm.ActiveSection != null) ? itm.ActiveSection.DisplayNumber : string.Empty; } else { stepnum = BuildStepTab(itm); } AddCell(rotable, stepnum, f2, Color.WHITE); AddCell(rotable, itm.DisplayText, f2, Color.WHITE); } curTable.AddCell(rotable); } } private void BuildROUsageTableByProcedure(iTextSharp.text.Document document) { Dictionary> roUse = new Dictionary>(); float[] headerwidths = { 20, 80 }; PdfPTable datatable = new PdfPTable(1); PdfPTable colHeader = new PdfPTable(headerwidths); //datatable.FooterRows = 1; datatable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; datatable.LockedWidth = true; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f1 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); iTextSharp.text.Font f3 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 12, 0, Color.BLACK); PdfPCell cell = new PdfPCell(new Phrase(ReportTitle, f1)); cell.HorizontalAlignment = Element.ALIGN_CENTER; //cell.Colspan = 2; cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); // light blue datatable.AddCell(cell); BuildSearchResultsProcSetList(); datatable.HeaderRows = 2;//3 + (ProcSetList.Count == 1 ? 1 : 0); int splitAt = FindSpitLevel(); // find the split level of the common path Color subHeaderColor = new Color(0xD0, 0xF0, 0xF0); // light blue //new Color(0xD0, 0xF0, 0xD0);//ligt green datatable.DefaultCell.Padding = 4; datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER; // This puts "Step" and "Text" column headers at the bottom of the page AddCell(colHeader, "Step", f2, subHeaderColor); AddCell(colHeader, "Text", f2, subHeaderColor); datatable.AddCell(colHeader); datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT; Color AnnoColor = new Color(0xFF, 0xFF, 0xC0); Color TextColor = Color.WHITE; Color SectColor = new Color(0xE0, 0xFF, 0xE0);//new Color(0xC0, 0xFF, 0xC0);//Color.LIGHT_GRAY; PdfPTable subTable = new PdfPTable(headerwidths); datatable.AddCell(subTable); string lastProcNum = string.Empty; string lastSection = string.Empty; //CSM B2021-043 Step numbering is out of order in RO usage report if RO values exist on steps 10 or higher. //setting this to something other than empty - otherwise will not print first initial header string lastDVPath = "start"; if (_ResultList.Count > 0) { foreach (ItemInfo item in _ResultList) { bool differentProcSet = false; bool differentRO = false; // Check Doc Version path // if more than one procedure set is in the report data, then // we will output the procedure set title inside the grouping of each RO // otherwise, if we are reporting on only one procedure set, print the // procedure set title at the top of the report (once). if (lastDVPath != "" && lastDVPath != item.SearchDVPath) { //CSM B2021-043 Step numbering is out of order in RO usage report if RO values exist on steps 10 or higher. //was placing last item from the precious section in the new section //place it before starting the new section and then clear items PutROusageForProcedure(datatable, roUse, headerwidths); roUse.Clear(); subTable = new PdfPTable(headerwidths); AddMainPathGroup(datatable, item.SearchDVPath, splitAt, f2, Color.LIGHT_GRAY, 0); lastProcNum = string.Empty; lastSection = string.Empty; } lastDVPath = item.SearchDVPath; //check for different procedure number string curProcNum = GetCurProcNum(item.SearchPath); string curSection = GetCurSectionNumTitle(item); if (!string.IsNullOrEmpty(lastProcNum) && (curProcNum != lastProcNum)) { if (roUse.Count > 0) { PutROusageForProcedure(datatable, roUse, headerwidths); roUse.Clear(); } lastSection = string.Empty; } if (!string.IsNullOrEmpty(lastSection) && (curSection != lastSection)) { if (roUse.Count > 0) { PutROusageForProcedure(datatable, roUse, headerwidths); roUse.Clear(); } } AddROUsages(item, roUse); // add the used ro to the list for this procedure AddProcedureSectionGroup(datatable, curProcNum, lastProcNum, curSection, lastSection, f2, new Color(0xC0, 0xFF, 0xC0)); lastProcNum = curProcNum; lastSection = curSection; } } else { // B2022-093 put out a message if no RO Usages were found cell = new PdfPCell(new Phrase("No RO Usage Information Found", f3)); cell.HorizontalAlignment = Element.ALIGN_LEFT; //cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); // light blue datatable.AddCell(cell); } PutROusageForProcedure(datatable, roUse, headerwidths); document.Add(datatable); } private void AddProcROUse(ItemInfo item, Dictionary> procRoUse) { string dictKey = GetCurProcNum(item.SearchPath) + " " + GetCurSectionNumTitle(item); if (!string.IsNullOrEmpty(dictKey)) { if (procRoUse.ContainsKey(dictKey)) { ((List)procRoUse[dictKey]).Add(item); } else { List itmIfoLst = new List(); itmIfoLst.Add(item); procRoUse.Add(dictKey, itmIfoLst); } } } private void PutStepListForProcedure(PdfPTable rotable, Dictionary sortedStepList) { // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); foreach (ItemInfo itm in sortedStepList.Values) { string stepnum = (itm.IsSection && itm.ActiveSection != null) ? itm.ActiveSection.DisplayNumber : stepnum = BuildStepTab(itm);// C2018-003 fixed use of getting the active section AddCell(rotable, stepnum, f2, Color.WHITE); AddCell(rotable, itm.DisplayText, f2, Color.WHITE); } sortedStepList.Clear(); } private void PutROusageForROID(PdfPTable curTable, Dictionary> procRoUse, float[] headerwidths, int splitAt, bool moreThanOneProcSet) { // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); Dictionary sortedStepList = new Dictionary(); string lastProcKey = string.Empty; string lastProcNumTitle = string.Empty; string lastDVPath = string.Empty; string curProcNumTitle = string.Empty; foreach (string procKey in procRoUse.Keys) { PdfPTable rotable = new PdfPTable(headerwidths); foreach (ItemInfo itm in procRoUse[procKey]) { bool didProcSetTitle = false; // Check Doc Version path // where we are reporting on more than one procedure set // output the procedure set title within the RO value grouping on the report if (moreThanOneProcSet && lastDVPath != itm.SearchDVPath) { AddMainPathGroup(curTable, itm.SearchDVPath, splitAt, f2, Color.LIGHT_GRAY, 0); didProcSetTitle = true; } else { didProcSetTitle = false; } lastDVPath = itm.SearchDVPath; if (didProcSetTitle || procKey != lastProcKey) { if (sortedStepList.Count > 0) { PutStepListForProcedure(rotable, sortedStepList); } string procNumTitleSect = string.Empty; curProcNumTitle = GetCurProcNum(itm.SearchPath); if (lastProcNumTitle == string.Empty || lastProcNumTitle != curProcNumTitle) { procNumTitleSect = curProcNumTitle + "\r\n"; lastProcNumTitle = curProcNumTitle; } procNumTitleSect += " " + GetCurSectionNumTitle(itm); procNumTitleSect = procNumTitleSect.Replace(@"\u8209?", "-"); // repace unicode with dash char procNumTitleSect = procNumTitleSect.Replace(@"\u160?", " "); // replace Hard Space with normal Space procNumTitleSect = procNumTitleSect.Replace(@"\u9586?", @"\"); // replace backslash symbol with a backslash PdfPCell ProcTitleCell = new PdfPCell(new Phrase(procNumTitleSect, f2)); ProcTitleCell.Colspan = 2; ProcTitleCell.HorizontalAlignment = Element.ALIGN_LEFT; ProcTitleCell.BackgroundColor = new Color(0xDC, 0xE7, 0xC9); //new Color(0xD0, 0xF0, 0xD0);//ligt green //new Color(0xC8, 0xC8, 0x91);//(0xAF, 0xD8, 0xD8);//(0xF5, 0xE4, 0xA0); rotable.AddCell(ProcTitleCell); // put RO value and description lastProcKey = procKey; } string stepnum = (itm.IsSection && itm.ActiveSection != null) ? itm.ActiveSection.DisplayNumber : BuildStepTab(itm);// C2018-003 fixed use of getting the active section string itemkey = stepnum + " " + itm.ItemID.ToString(); // add ItemId to stepnum, sometimes we have idential stepnum text for different steps (ex: blank section numbers) if (!sortedStepList.ContainsKey(itemkey)) { sortedStepList.Add(itemkey, itm); } } if (sortedStepList.Count > 0) { PutStepListForProcedure(rotable, sortedStepList); } curTable.AddCell(rotable); } } private string GetROTitleAndGroup(string roid, ItemInfo itm) { string rotitle = string.Empty; ROFSTLookup myrofstlookup = (itm == null) ? _ROFSTLookup : itm.MyDocVersion.DocVersionAssociations[0].MyROFst.GetROFSTLookup(itm.MyDocVersion); List roTitleList = myrofstlookup.GetROTitleAndGroupPath(roid, _IncludeMissingROs, _ConvertCaretToDelta); if (roTitleList != null && roTitleList.Count > 0) { for (int cnt = 0; cnt < roTitleList.Count; cnt++) { if (cnt == roTitleList.Count - 1) // Last roTitle in list, don't add a NewLine character after the value rotitle += roTitleList[cnt]; else rotitle += roTitleList[cnt] + "\n "; } } return rotitle; } private void AddROHeaderGroup(PdfPTable datatable, string curROID, ItemInfo itm, Font f2, Color bgColor) { string headerText = GetROTitleAndGroup(curROID, itm); if (!string.IsNullOrEmpty(headerText) && headerText.Length > 0) { PdfPCell cell = new PdfPCell(new Phrase(headerText, f2)); cell.Colspan = 2; cell.BackgroundColor = (headerText.StartsWith("Missing RO")) ? Color.PINK : bgColor; cell.BorderWidthTop = 1; datatable.AddCell(cell); } } private void BuildROUsageTableByRO(iTextSharp.text.Document document) { Dictionary> procRoUse = new Dictionary>(); float[] headerwidths = { 20, 80 }; PdfPTable datatable = new PdfPTable(1); PdfPTable colHeader = new PdfPTable(headerwidths); //datatable.FooterRows = 1; datatable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; datatable.LockedWidth = true; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f1 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); iTextSharp.text.Font f3 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 12, 0, Color.BLACK); PdfPCell cell = new PdfPCell(new Phrase(ReportTitle, f1)); cell.HorizontalAlignment = Element.ALIGN_CENTER; cell.BackgroundColor = new Color(0xD0, 0xF0, 0xF0); // light blue datatable.AddCell(cell); BuildSearchResultsProcSetList(); datatable.HeaderRows = 2;//3 + (ProcSetList.Count == 1 ? 1 : 0); int splitAt = FindSpitLevel(); // find the split level of the common path Color subHeaderColor = new Color(0xD0, 0xF0, 0xF0); // light blue //new Color(0xD0, 0xF0, 0xD0);//ligt green datatable.DefaultCell.Padding = 4; datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER; // This puts "Step" and "Text" column headers at the bottom of the page AddCell(colHeader, "Step", f2, subHeaderColor); AddCell(colHeader, "Text", f2, subHeaderColor); datatable.AddCell(colHeader); datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT; Color AnnoColor = new Color(0xFF, 0xFF, 0xC0); Color TextColor = Color.WHITE; Color SectColor = new Color(0xE0, 0xFF, 0xE0);//new Color(0xC0, 0xFF, 0xC0);//Color.LIGHT_GRAY; PdfPTable subTable = new PdfPTable(headerwidths); datatable.AddCell(subTable); string lastDVPath = string.Empty; string lastROID = string.Empty; bool moreThanOneProcSet = false; bool printedSetTitle = false; bool printedROHeader = false; ItemInfo lastItem = null; if (_ResultList.Count == 0) { PdfPCell cell2 = new PdfPCell(new Phrase("Selected RO is not used", f2)); cell2.Colspan = 0; cell2.BorderWidthTop = 1; datatable.AddCell(cell2); document.Add(datatable); return; } foreach (ItemInfo item in _ResultList) { bool differentProcSet = false; bool differentRO = false; // Check Doc Version path // if more than one procedure set is in the report data, then // we will output the procedure set title inside the grouping of each RO // otherwise, if we are reporting on only one procedure set, print the // procedure set title at the top of the report (once). if (!string.IsNullOrEmpty(lastDVPath) && lastDVPath != item.SearchDVPath) { moreThanOneProcSet = true; differentProcSet = true; } lastDVPath = item.SearchDVPath; // Check for different ROID string curROID = item.FoundROID; differentRO = (!string.IsNullOrEmpty(lastROID) && !string.IsNullOrEmpty(curROID) && curROID.Substring(0, 12) != lastROID.Substring(0, 12)); if (procRoUse.Count > 0 && (differentProcSet || differentRO)) { if (!moreThanOneProcSet && !printedSetTitle) { AddMainPathGroup(datatable, lastDVPath, splitAt, f2, Color.LIGHT_GRAY, 0); printedSetTitle = true; } if (!printedROHeader) { AddROHeaderGroup(datatable, lastROID, lastItem, f2, new Color(0xC0, 0xFF, 0xC0)); printedROHeader = true; } PutROusageForROID(datatable, procRoUse, headerwidths, splitAt, moreThanOneProcSet); procRoUse.Clear(); differentProcSet = false; } if (differentRO) { printedROHeader = false; } AddProcROUse(item, procRoUse); lastROID = curROID; lastItem = item; } if (!moreThanOneProcSet && !printedSetTitle) AddMainPathGroup(datatable, lastDVPath, splitAt, f2, Color.LIGHT_GRAY, 0); if (!printedROHeader) AddROHeaderGroup(datatable, lastROID, lastItem, f2, new Color(0xC0, 0xFF, 0xC0)); PutROusageForROID(datatable, procRoUse, headerwidths, splitAt, moreThanOneProcSet); document.Add(datatable); } private void BuildSearchResultsProcSetList() { ProcSetList = new System.Collections.ArrayList(); foreach (ItemInfo item in _ResultList) { if (!ProcSetList.Contains(item.SearchDVPath)) ProcSetList.Add(item.SearchDVPath); } } private void BuildLibDocProcSetList() { ProcSetList = new System.Collections.ArrayList(); foreach (DocumentInfo di in _LibDocList) { if (di.LibraryDocumentUsageList != null && di.LibraryDocumentUsageList.Count > 0) foreach (ItemInfo item in di.LibraryDocumentUsageList) { if (!ProcSetList.Contains(item.SearchDVPath)) ProcSetList.Add(item.SearchDVPath); } } } private ArrayList GetSortedItemInfoList(ItemInfoList orgIFL) { System.Collections.ArrayList libDocProcSetList = new System.Collections.ArrayList(); System.Collections.ArrayList rtnIFL = new System.Collections.ArrayList(); foreach (ItemInfo item in orgIFL) { if (!libDocProcSetList.Contains(item.SearchDVPath)) libDocProcSetList.Add(item.SearchDVPath); } foreach (string pset in libDocProcSetList) { foreach (ItemInfo item in orgIFL) { if (item.SearchDVPath.Equals(pset)) rtnIFL.Add(item); } } return rtnIFL; } private void BuildCompleteROReport(iTextSharp.text.Document document) { CompleteROReport compRORpt = new CompleteROReport(_MyPdfWriter, document, _RODataFile, _ConvertCaretToDelta, _IncludeEmptyROFields); compRORpt.F10 = pdf.GetFont("Courier New", 10, 0, Color.BLACK); compRORpt.F10Bold = pdf.GetFont("Courier New", 10, 1, Color.BLACK); compRORpt.F12 = pdf.GetFont("Courier New", 12, 0, Color.BLACK); compRORpt.F12Bold = pdf.GetFont("Courier New", 12, 1, Color.BLACK); // C2017-036 Get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 compRORpt.F14 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); //B2022 - 083: Support Conditional RO Values compRORpt.ROFstID = _ROFSTLookup.RofstID; compRORpt.Run(); } private string GetROTitleAndGroupsForSummary(List roTitleList, List prevROTitleList) { string rotitle = string.Empty; string indent = string.Empty; for (int icnt = 0; icnt < roTitleList.Count; icnt++) { indent += " "; if (icnt == roTitleList.Count - 1) { rotitle += indent + roTitleList[icnt]; // this should be the ro description break; //break out of for loop } if (prevROTitleList == null || (icnt < roTitleList.Count && icnt < prevROTitleList.Count && prevROTitleList[icnt] != roTitleList[icnt])) { if (rotitle == string.Empty && prevROTitleList != null) rotitle = "\n"; rotitle += indent + roTitleList[icnt] + "\n"; } } return rotitle; } private List AddROHeaderGroupForSummary(PdfPTable datatable, string curROID, List prevROTitleList, Font f2, Color bgColor) { List roTitleList = _ROFSTLookup.GetROTitleAndGroupPath(curROID, _IncludeMissingROs, _ConvertCaretToDelta); string headerText = GetROTitleAndGroupsForSummary(roTitleList, prevROTitleList); if (headerText.Length > 0) { Paragraph pgh = new Paragraph(headerText, f2); PdfPCell cell = new PdfPCell(pgh); cell.FollowingIndent = 72; cell.Colspan = 2; cell.BorderColor = Color.WHITE; cell.BackgroundColor = Color.WHITE; cell.BorderWidthTop = 1; datatable.AddCell(cell); } return roTitleList; } private void BuildROSummaryReport(iTextSharp.text.Document document) { float[] headerwidths = { 10, 20, 80 }; PdfPTable datatable = new PdfPTable(1); datatable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; datatable.LockedWidth = true; // C2017-036 get best available proportional font for symbols that looks close to Arial // Note that Microsoft no longer supplies Arial Unicode MS as of Word16 iTextSharp.text.Font f1 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 14, 1, Color.BLACK); iTextSharp.text.Font f2 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 10, 0, Color.BLACK); iTextSharp.text.Font f3 = pdf.GetFont(Volian.Base.Library.vlnFont.ReportsFont, 12, 1, Color.BLACK); PdfPCell cell = new PdfPCell(new Phrase(ReportTitle, f1)); cell.HorizontalAlignment = Element.ALIGN_CENTER; //cell.Colspan = 2; cell.BackgroundColor = Color.WHITE;//new Color(0xD0, 0xF0, 0xF0); // light blue cell.BorderColor = Color.WHITE; datatable.AddCell(cell); string roFSTDateTime = "RO.FST Last Created: " + _ROFSTLookup.GetRoFSTdts().ToLongDateString() + " @ " + _ROFSTLookup.GetRoFSTdts().ToShortTimeString() + "\n "; cell = new PdfPCell(new Phrase(roFSTDateTime, f2)); cell.BorderColor = Color.WHITE; datatable.AddCell(cell); datatable.HeaderRows = 2;//3 + (ProcSetList.Count == 1 ? 1 : 0); datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_LEFT; string lastROID = string.Empty; List prevROTitleList = null; int lastDBindex = -1; foreach (string curROID in _ROList) { string[] tmp = curROID.TrimEnd(',').Split(':'); //curROID.Split(':');// this is the RO FST id number (for plants with multiple RO FSTs) string rolst = (tmp.Length == 2) ? tmp[1] : tmp[0]; string[] roIdslst = rolst.Split(','); foreach (string cROID in roIdslst) { if (string.IsNullOrEmpty(cROID)) break; if (cROID.Length == 4) ProcessROdb(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cROID); else ProcessROID(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cROID); } } document.Add(datatable); } private void ProcessROdb(PdfPTable datatable, iTextSharp.text.Font f2, iTextSharp.text.Font f3, ref PdfPCell cell, ref string lastROID, ref List prevROTitleList, ref int lastDBindex, string cROID) { ROFSTLookup.rodbi roDBI = _ROFSTLookup.GetRODatabase(cROID, true, true); if (roDBI.children != null && roDBI.children.Length > 0) { for (int i = 0; i < roDBI.children.Length; i++) { ProcessROChild(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, roDBI.children[i]); } } else { ProcessROID(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cROID); cell = new PdfPCell(new Phrase(" ", f2)); cell.BorderColor = Color.WHITE; datatable.AddCell(cell); cell = new PdfPCell(new Phrase("-- No Information Entered --", f2)); cell.BorderColor = Color.WHITE; datatable.AddCell(cell); } } private void ProcessROChild(PdfPTable datatable, iTextSharp.text.Font f2, iTextSharp.text.Font f3, ref PdfPCell cell, ref string lastROID, ref List prevROTitleList, ref int lastDBindex, ROFSTLookup.rochild cld) { if (cld.children == null || cld.children.Length <= 0) // leaf node { ProcessROID(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cld.roid); } else if (cld.children[0].ParentID == 0) // multiple return value { ProcessROID(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cld.roid); } else { for (int i = 0; i < cld.children.Length; i++) { ProcessROChild(datatable, f2, f3, ref cell, ref lastROID, ref prevROTitleList, ref lastDBindex, cld.children[i]); } } } private void ProcessROID(PdfPTable datatable, iTextSharp.text.Font f2, iTextSharp.text.Font f3, ref PdfPCell cell, ref string lastROID, ref List prevROTitleList, ref int lastDBindex, string cROID) { int curDBindex = _ROFSTLookup.GetRODatabaseTitleIndex(cROID); if (lastDBindex == -1 || curDBindex != lastDBindex) { if (prevROTitleList != null) { // add blank line to separate groups on the report cell = new PdfPCell(new Phrase(" ", f2)); cell.BorderColor = Color.WHITE; datatable.AddCell(cell); } AddMainRODatabaseTitle(datatable, curDBindex, f3, Color.WHITE); lastDBindex = curDBindex; } if (string.IsNullOrEmpty(lastROID) || cROID != lastROID) prevROTitleList = AddROHeaderGroupForSummary(datatable, cROID, prevROTitleList, f2, new Color(0xC0, 0xFF, 0xC0)); lastROID = cROID; } #endregion #region Private Static Methods private static PdfPTable BuildSubTable(iTextSharp.text.Document document, float[] headerwidths) { PdfPTable subtable = new PdfPTable(headerwidths); subtable.HeaderRows = 1; subtable.KeepTogether = true; subtable.TotalWidth = document.PageSize.Width - document.LeftMargin - document.RightMargin; subtable.LockedWidth = true; subtable.DefaultCell.Padding = 4; return subtable; } private static void ShowException(Exception ex) { Console.WriteLine("{0} - {1}", ex.GetType().Name, ex.Message); StringBuilder msg = new StringBuilder(); string sep = string.Empty; string indent = string.Empty; while (ex != null) { msg.Append(string.Format("{0}{1}{2}:\r\n{1}{3}", sep, indent, ex.GetType().Name, ex.Message)); ex = ex.InnerException; sep = "\r\n"; indent += " "; } System.Windows.Forms.MessageBox.Show(msg.ToString(), "Error during PDF creation for search:", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation); } private static string BuildStepTab(ItemInfo item) { if (item == null) return string.Empty; string sret = string.Empty; switch (item.MyContent.Type / 10000) { case 0: //procedure sret = ProcedureInfo.Get(item.ItemID).MyTab.CleanText; break; case 1: // section sret = SectionInfo.Get(item.ItemID).MyTab.CleanText; break; case 2: // step ItemInfo pitem = item; bool hasDelim = item.ActiveFormat.PlantFormat.FormatData.TransData.StepSubstepDelimeter != null; List DelimList = null; DelimList = new List(); if (!hasDelim) { SeqTabFmtList seqtabs = item.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.SeqTabFmtList; foreach (SeqTabFmt seqtab in seqtabs) { string delim = seqtab.PrintTabFormat.Replace("{seq}", string.Empty); if (!DelimList.Contains(delim)) { DelimList.Add(delim.Trim()); } } } else { string stpdelms = item.ActiveFormat.PlantFormat.FormatData.TransData.StepSubstepDelimeter; foreach (char c in stpdelms) { if (!DelimList.Contains(c.ToString())) { DelimList.Add(c.ToString()); } } } // B2016-160 Support transitions to sections while (!pitem.IsSection && !pitem.IsHigh) { StepInfo stpinfo = StepInfo.Get(pitem.ItemID); string thisTab = stpinfo.MyTab.CleanText; if (IncludesParentToHLS(stpinfo)) { if (!thisTab.Contains("\u25CF")) //Remove Bullet { return thisTab; } else { thisTab = null; } } string typeName = stpinfo.FormatStepData.StepEditData.TypeMenu.MenuItem;//stpinfo.FormatStepData.ToString(); // remove delimiters of '.' and ')' in tab. if (!string.IsNullOrEmpty(thisTab)) { // get list of delimiters to remove from the format: foreach (string rmvDelim in DelimList) { thisTab = thisTab.Replace(rmvDelim, string.Empty); } } if (!string.IsNullOrEmpty(thisTab)) { thisTab = thisTab.Trim(); } // if the tab is null or // if the the tab is not a letter or number OR // the tab is an AND or OR type and is the letter "o" // then reset the tab an empty string so that the type name along with the count of that type // (ex. "AND 2", "OR 3") if (string.IsNullOrEmpty(thisTab) || (thisTab != string.Empty && (!(char.IsLetterOrDigit(thisTab[0])) || ((pitem.IsAnd || pitem.IsOr || pitem.IsCaution || pitem.IsNote) && thisTab.Contains("o"))))) { thisTab = string.Empty; } if (pitem.IsRNOPart) { if (string.IsNullOrEmpty(thisTab)) { sret = "RNO." + sret; //"RNO." + sret; } else { thisTab = thisTab.Trim(" ".ToCharArray()); if (!thisTab.EndsWith(".") && !thisTab.EndsWith(")")) { thisTab = thisTab + "."; } sret = "RNO." + thisTab + sret; //"RNO." + thisTab + sret; } } else if (pitem.IsCaution || pitem.IsNote) { // add the Caution or Note count to the tab (ex "Caution 1", "Note 2") if (string.IsNullOrEmpty(thisTab)) { sret = "{" + typeName + " " + pitem.Ordinal.ToString() + "}"; } else { thisTab = thisTab.Trim(" ".ToCharArray()); sret = thisTab + " " + pitem.Ordinal.ToString() + sret; } } else { if (!string.IsNullOrEmpty(thisTab)) { thisTab = thisTab.Trim(" ".ToCharArray()); if (!thisTab.EndsWith(".") && !thisTab.EndsWith(")")) { thisTab = thisTab + "."; } } else { thisTab = "{" + typeName + " " + pitem.Ordinal.ToString() + "}."; } sret = thisTab + sret; } pitem = pitem.ActiveParent as ItemInfo; if (pitem == null) break; } // add hls tab if it's not already in the tab. if (pitem.IsHigh) { StepInfo stpinfo = StepInfo.Get(pitem.ItemID); string hlsTab = stpinfo.MyTab.CleanTextNoSymbols; //StepInfo.Get(pitem.ItemID).MyTab.CleanTextNoSymbols; string typeName = stpinfo.FormatStepData.StepEditData.TypeMenu.MenuItem;//stpinfo.FormatStepData.GetPDDisplayName(); //.ToString(); // C2020-043: don't remove delimiters on tabs if this step's tab has the parent tab included. bool hasParent = false; if (IncludesParentToHLS(stpinfo) && !hlsTab.Contains("\u25CF")) { hlsTab = hlsTab.Trim(" ".ToCharArray()).TrimEnd(".".ToCharArray()); hasParent = true; } if (string.IsNullOrEmpty(hlsTab)) { hlsTab = "{" + typeName + " " + pitem.Ordinal.ToString() + "}."; } else if (!hasParent && !sret.StartsWith(hlsTab.Trim(" ".ToCharArray()))) { foreach (string rmvDelim in DelimList) { hlsTab = hlsTab.Replace(rmvDelim, string.Empty); } hlsTab = hlsTab.Trim(" ".ToCharArray()); if (!hlsTab.EndsWith(".") && !hlsTab.EndsWith(")")) { hlsTab = hlsTab + "."; } } sret = hlsTab + sret; } break; } return sret.Trim(" .)".ToCharArray()); } private static bool IncludesParentToHLS(StepInfo stpinfo) { if (stpinfo.IsHigh) return true; StepInfo parent = StepInfo.Get((stpinfo.ActiveParent as ItemInfo).ItemID); if (stpinfo.MyTab.CleanText.StartsWith(parent.MyTab.CleanText.Trim()) && stpinfo.MyTab.CleanText.Length > parent.MyTab.CleanText.Length) { return IncludesParentToHLS(parent); } return false; } #endregion } public class MyPageHelper : PdfPageEventHelper { #region Fields private PdfPTable _HeaderTable = null; protected PdfTemplate total; protected BaseFont helv; private int ptSize = 10; // text point size of page number and page total string _ByLine = "PROMS"; #endregion #region Properties public PdfPTable HeaderTable { get { return _HeaderTable; } set { _HeaderTable = value; } } #endregion #region Constructors public MyPageHelper(string byLine) { _ByLine = byLine; } #endregion #region Public Methods public override void OnOpenDocument(PdfWriter writer, iTextSharp.text.Document document) { total = writer.DirectContent.CreateTemplate(100, 100); total.BoundingBox = new Rectangle(-20, -20, 100, 100); helv = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED); } public override void OnEndPage(PdfWriter writer, iTextSharp.text.Document document) { PdfContentByte cb = writer.DirectContent; cb.SaveState(); if (HeaderTable != null) HeaderTable.WriteSelectedRows(0, 2, 36, document.Top + 44, cb); String text = "Page " + writer.PageNumber + " of "; float textBase = document.Bottom - 19;//20; cb.BeginText(); cb.SetFontAndSize(helv, ptSize); float posCenter = document.Left + ((document.Right - document.Left) / 2) - (helv.GetWidthPoint(text + "XX", ptSize) / 2); cb.SetTextMatrix(posCenter, textBase); cb.ShowText(text); cb.EndText(); cb.AddTemplate(total, posCenter + helv.GetWidthPoint(text, ptSize), textBase); cb.RestoreState(); AddVolianFooter(writer, document); AddDateFooter(writer, document); } public override void OnCloseDocument(PdfWriter writer, iTextSharp.text.Document document) { total.BeginText(); total.SetFontAndSize(helv, ptSize); total.SetTextMatrix(0, 0); total.ShowText((writer.PageNumber - 1).ToString()); total.EndText(); base.OnCloseDocument(writer, document); } #endregion #region Private Methods private void AddVolianFooter(PdfWriter writer, iTextSharp.text.Document document) { PdfContentByte cb = writer.DirectContent; cb.SaveState(); String text = _ByLine;//"PROMS Search Results"; float textBase = document.Bottom - 19;//20; float textSize = helv.GetWidthPoint(text, ptSize); cb.BeginText(); cb.SetFontAndSize(helv, ptSize); cb.SetTextMatrix(document.Left, textBase); cb.ShowText(text); cb.EndText(); cb.RestoreState(); } private void AddDateFooter(PdfWriter writer, iTextSharp.text.Document document) { PdfContentByte cb = writer.DirectContent; cb.SaveState(); String text = DateTime.Today.ToShortDateString(); float textBase = document.Bottom - 19;//20; float textSize = helv.GetWidthPoint(text, ptSize); float posRight = document.Right - helv.GetWidthPoint(text, ptSize); cb.BeginText(); cb.SetFontAndSize(helv, ptSize); cb.SetTextMatrix(posRight, textBase); cb.ShowText(text); cb.EndText(); cb.RestoreState(); } #endregion } }