using System; using System.Collections.Generic; using System.Text; using System.IO; using Csla; using Csla.Data; using System.Data; using System.Data.SqlClient; //----------------- using System.Drawing; using System.Text.RegularExpressions; using LBWordLibrary; using System.Drawing.Imaging; using Volian.Base.Library; using System.Diagnostics; namespace VEPROMS.CSLA.Library { public enum VolianStatusType { Initialize, Update, Complete } public delegate void VolianStatusChange(VolianStatusType type, int count, string text); public partial class Document { public string DocumentTitle { get { if (_LibTitle == "") return string.Format("Document {0}", _DocID); return _LibTitle; } } private static LBApplicationClass _MyApp = null; public static LBApplicationClass MyApp { get { if (_MyApp == null) _MyApp = new LBApplicationClass(); return _MyApp; } } public void UpdateDRoUsages(List roids) { _DocumentDROUsageCount = -1; if (DocumentDROUsages.Count > 0) { List delList = new List(); foreach (DocumentDROUsage myUsage in DocumentDROUsages) { string roidkey = string.Format("{0}:{1}", myUsage.RODbID, myUsage.ROID); if (roids.Contains(roidkey)) roids.Remove(roidkey);// If in both, nothing to do else delList.Add(myUsage); } foreach (DocumentDROUsage myUsage in delList) DocumentDROUsages.Remove(myUsage); // If only in old, remove it } foreach (string roidkey in roids) { string [] parts = roidkey.Split(":".ToCharArray()); DocumentDROUsages.Add(parts[1], RODb.GetJustRoDb(int.Parse(parts[0]))); } } private int _Unique = 0; private string Unique { get { string retval = ""; if (_Unique != 0) retval = "_" + _Unique.ToString(); _Unique++; return retval; } } public void StatusChanged(VolianStatusType type, int count, string text) { //if (Parent != null && Parent.Parent != null && Parent.Parent.Parent is DisplayTabControl) //{ // DisplayTabControl tc = Parent.Parent.Parent as DisplayTabControl; // tc.ONStatusChanged(this, new DisplayTabControlStatusEventArgs(type, count, text)); //} } public void RestoreWordDoc(ItemInfo myItemInfo) { DocumentAuditInfo savDocAuditInfo = null; using (DocumentAuditInfoList dail = DocumentAuditInfoList.Get(DocID)) { if (dail.Count > 0) { DocumentAuditInfo dai = dail[0]; foreach (DocumentAuditInfo tmpa in dail) { FileInfo tmpFile = new FileInfo(string.Format(@"{0}\tmp_{1}{2}{3}", VlnSettings.TemporaryFolder, DocID, Unique, tmpa.FileExtension)); while (tmpFile.Exists) { tmpFile = new FileInfo(string.Format(@"{0}\tmp_{1}{2}{3}", VlnSettings.TemporaryFolder, DocID, Unique, tmpa.FileExtension)); } FileStream fs = tmpFile.Create(); if (tmpa.DocContent != null) fs.Write(tmpa.DocContent, 0, tmpa.DocContent.Length); fs.Close(); LBDocumentClass myDoc = null; try { myDoc = MyApp.Documents.Open(tmpFile.FullName, false); savDocAuditInfo = tmpa; myDoc.Close(); break; } catch (Exception ex) { if (myDoc != null) myDoc.Close(); continue; // get next document audit item. } } } if (savDocAuditInfo != null) { FileExtension = savDocAuditInfo.FileExtension; DocContent = savDocAuditInfo.DocContent; DocAscii = savDocAuditInfo.DocAscii; Config = savDocAuditInfo.Config; UserID = savDocAuditInfo.UserID; DTS = savDocAuditInfo.DTS; Save(); List roids = new List(); DocumentInfo docinfo = DocumentInfo.Get(DocID); string pdfTmp = MSWordToPDF.ToPDFReplaceROs(docinfo, roids, myItemInfo, StatusChanged); FileInfo pdfFile = new FileInfo(pdfTmp); FileStream fs = pdfFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); Byte[] buf = new byte[pdfFile.Length]; fs.Read(buf, 0, buf.Length); fs.Close(); pdfFile.Delete(); Pdf.DeleteAll(DocID); // clear the PDF table for DocID first DocStyle myDocStyle = myItemInfo.ActiveSection.MyDocStyle; SectionConfig sc = myItemInfo.ActiveSection.MyConfig as SectionConfig; if (sc != null && sc.Section_WordMargin == "Y") { using (Pdf myPdf = Pdf.MakePdf(this, MSWordToPDF.DebugStatus, 0, 0, 0, 0, (double)myItemInfo.MSWordPageCount, buf)) { ;} } else { using (Pdf myPdf = Pdf.MakePdf(this, MSWordToPDF.DebugStatus, (int)myDocStyle.Layout.TopMargin, (int)myDocStyle.Layout.PageLength, (int)myDocStyle.Layout.LeftMargin, (int)myDocStyle.Layout.PageWidth, (double)myItemInfo.MSWordPageCount, buf)) { ;} } UpdateDRoUsages(roids); Save(); } } } /// /// FixString processes the string returned and changes any symbols (0xF0??) to normal characters /// /// /// //private static string FixString(string str) //{ // StringBuilder results = new StringBuilder(); // foreach (char c in str) // { // if ((c & 0xFF00) == 0xF000) // results.Append((char)(c & 0xFF)); // else // results.Append((char)(c)); // } // return results.ToString(); //} } public partial class DocumentInfo { public string DocumentTitle { get { if (_LibTitle == "") return string.Format("Document {0}", _DocID); return _LibTitle; } } public string LibraryDocumentUsage { get { StringBuilder sb = new StringBuilder(); string sep = "\r\nUsed In:\r\n "; if (DocumentEntries == null) sb.Append("None"); else { int limit = 20; foreach (EntryInfo myEntry in DocumentEntries) { foreach (ItemInfo myItem in myEntry.MyContent.ContentItems) { --limit; if (limit < 0) { sb.Append(sep + "..."); return sb.ToString(); } ItemInfo proc = myItem.MyProcedure; sb.Append(sep + proc.DisplayNumber + " - " + proc.DisplayText); sep = "\r\n "; } } } return sb.ToString(); } } public ItemInfoList LibraryDocumentUsageList { get { bool first = true; ItemInfoList iil = null; if (DocumentEntries == null) return null; foreach (EntryInfo myEntry in DocumentEntries) { foreach (ItemInfo myitem in myEntry.MyContent.ContentItems) { if (first) { iil = new ItemInfoList(myitem); first = false; } else iil.AddItem(myitem); } } return iil; } } #region DocumentConfig [NonSerialized] private DocumentConfig _DocumentConfig; public DocumentConfig DocumentConfig { get { return (_DocumentConfig != null ? _DocumentConfig : _DocumentConfig = new DocumentConfig(this)); } } public void RefreshConfig() { _DocumentConfig = null; } #endregion public static DocumentInfo GetByLibDocName(string libdoc, int versionID) { try { DocumentInfo tmp = DataPortal.Fetch(new LibDocCriteria(libdoc, versionID)); return tmp; } catch (Exception ex) { throw new DbCslaException("Error on DocumentInfo.GetByLibDocName", ex); } } [Serializable()] protected class LibDocCriteria { private string _LibDoc; public string LibDoc { get { return _LibDoc; } } private int _VersionID; public int VersionID { get { return _VersionID; } } public LibDocCriteria(string libdoc, int versionid) { _LibDoc = libdoc; _VersionID = versionid; } } private void DataPortal_Fetch(LibDocCriteria criteria) { if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] DocumentInfo.DataPortal_Fetch", GetHashCode()); try { using (SqlConnection cn = Database.VEPROMS_SqlConnection) { using (SqlCommand cm = cn.CreateCommand()) { cm.CommandType = CommandType.StoredProcedure; cm.CommandText = "getDocumentByLibDoc"; cm.Parameters.AddWithValue("@LibDoc", criteria.LibDoc); cm.Parameters.AddWithValue("@VersionID", criteria.VersionID); cm.CommandTimeout = Database.DefaultTimeout; using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader())) { if (!dr.Read()) { _ErrorMessage = "No Record Found"; return; } ReadData(dr); } } } } catch (Exception ex) { if (_MyLog.IsErrorEnabled) _MyLog.Error("DocumentInfo.DataPortal_Fetch", ex); throw new DbCslaException("DocumentInfo.DataPortal_Fetch", ex); } } } public partial class DocumentInfoList { public static DocumentInfoList GetLibraries(bool forceload) { try { if (!forceload && _DocumentInfoList != null) return _DocumentInfoList; DocumentInfoList tmp = DataPortal.Fetch(new LibraryCriteria(true)); DocumentInfo.AddList(tmp); tmp.AddEvents(); _DocumentInfoList = tmp; return tmp; } catch (Exception ex) { throw new DbCslaException("Error on DocumentInfoList.Get", ex); } } [Serializable()] protected class LibraryCriteria { private bool _IsLibrary; public bool IsLibrary { get { return _IsLibrary; } set { _IsLibrary = value; } } public LibraryCriteria(bool islibrary) { _IsLibrary = islibrary; } } private void DataPortal_Fetch(LibraryCriteria criteria) { this.RaiseListChangedEvents = false; if (_MyLog.IsDebugEnabled) _MyLog.DebugFormat("[{0}] DocumentInfoList.DataPortal_Fetch", GetHashCode()); try { using (SqlConnection cn = Database.VEPROMS_SqlConnection) { using (SqlCommand cm = cn.CreateCommand()) { cm.CommandType = CommandType.StoredProcedure; cm.CommandText = "getLibraryDocuments"; cm.CommandTimeout = Database.DefaultTimeout; using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader())) { IsReadOnly = false; while (dr.Read()) this.Add(new DocumentInfo(dr)); IsReadOnly = true; } } } } catch (Exception ex) { if (_MyLog.IsErrorEnabled) _MyLog.Error("DocumentInfoList.DataPortal_Fetch", ex); throw new DbCslaException("DocumentInfoList.DataPortal_Fetch", ex); } this.RaiseListChangedEvents = true; } } public class DSOFile : IDisposable { private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #region Fields private bool _IsDisposed; private DocumentInfo _MyDocument = null; private FileInfo _MyFile = null; private string _Extension = "DOC"; #endregion #region Properties public DocumentInfo MyDocument { get { return _MyDocument; } set { TryDelete(); _MyDocument = value; CreateFile(); } } public FileInfo MyFile { get { return _MyFile; } } public string Extension { get { return _Extension; } set { _Extension = value; } } #endregion #region Private Methods private void TryDelete() { if (_MyDocument == null) return; if (_MyFile == null) return; if (_MyFile.Exists) { try { _MyFile.Delete(); } catch (IOException ex) { // _MyLog.Error("TryDelete", ex); } finally { _MyFile = null; _MyDocument = null; } } } private bool _Created = false; private int _Unique = 0; private string Unique { get { string retval = ""; if (_Unique != 0) retval = "_" + _Unique.ToString(); _Unique++; return retval; } } private void CreateFile() { while (!_Created) CreateTemporaryFile(); } private void CreateTemporaryFile() { try { if (_MyDocument != null) { _MyFile = new FileInfo(string.Format(@"{0}\tmp_{1}{2}{3}", VlnSettings.TemporaryFolder, MyDocument.DocID, Unique, MyDocument.FileExtension)); while (_MyFile.Exists) { _MyFile = new FileInfo(string.Format(@"{0}\tmp_{1}{2}{3}", VlnSettings.TemporaryFolder, MyDocument.DocID, Unique, MyDocument.FileExtension)); } FileStream fs = _MyFile.Create(); if (MyDocument.DocContent != null) fs.Write(MyDocument.DocContent, 0, MyDocument.DocContent.Length); fs.Close(); _MyFile.CreationTimeUtc = _MyDocument.DTS; _MyFile.LastWriteTimeUtc = _MyDocument.DTS; _Created = true; } } catch (Exception ex) { _MyLog.Error("***** Could not create " + _MyFile.FullName, ex); Console.WriteLine(ex.Message); } } public string FullName { get { return _MyFile.FullName; } set { if (FullName != value) _MyFile = new FileInfo(value); } } public void SaveFile(float length, string ascii, ItemInfo myItemInfo, bool cvtLibDoc, VolianStatusChange statusChange) { // TODO: Add Try & Catch logic if (_MyDocument == null) return; Document doc = _MyDocument.Get(); FileStream fs = _MyFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); long savLen = _MyFile.Length; Byte[] buf = new byte[_MyFile.Length]; fs.Read(buf, 0, buf.Length); fs.Close(); // Handle if this is a libdoc & the user wanted to convert to a non-library document. if (cvtLibDoc) { // if just one usage (this one), then just convert this to a non-library document. If there is more // than one usage, make a copy so that the rest of the usages still point to the library document. if (doc.DocumentEntryCount == 1) doc.LibTitle = null; else { // make new document with 'no' libtitle. Then link this to the item/content via the entry. // the data gets set below. Document tdoc = Document.MakeDocument(null, null, null, null); _MyDocument = DocumentInfo.Get(doc.DocID); doc = tdoc; using (Entry ent = myItemInfo.MyContent.MyEntry.Get()) { ent.MyDocument = tdoc; ent.Save(); } } } doc.FileExtension = MyFile.Extension; doc.DocContent = buf; doc.DocAscii = ascii; //doc.UpdateDocAscii(_MyFile.FullName); DocumentConfig cfg = new DocumentConfig(doc); cfg.Edit_Initialized = true; doc.Config = cfg.ToString(); doc.UserID = Volian.Base.Library.VlnSettings.UserID; //doc.DTS = _MyFile.LastWriteTimeUtc; doc.DTS = DateTime.Now.ToUniversalTime(); doc = doc.Save(); List roids = new List(); string pdfTmp = MSWordToPDF.ToPDFReplaceROs(_MyDocument, roids, myItemInfo,statusChange); FileInfo pdfFile = new FileInfo(pdfTmp); fs = pdfFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); buf = new byte[pdfFile.Length]; fs.Read(buf, 0, buf.Length); fs.Close(); pdfFile.Delete(); Pdf.DeleteAll(doc.DocID); // clear the PDF table for DocID first DocStyle myDocStyle = myItemInfo.ActiveSection.MyDocStyle; SectionConfig sc = myItemInfo.ActiveSection.MyConfig as SectionConfig; if (sc != null && sc.Section_WordMargin == "Y") { using (Pdf myPdf = Pdf.MakePdf(doc, MSWordToPDF.DebugStatus, 0, 0, 0, 0, (double)myItemInfo.MSWordPageCount, buf)) { ;} } else { using (Pdf myPdf = Pdf.MakePdf(doc, MSWordToPDF.DebugStatus, (int)myDocStyle.Layout.TopMargin, (int)myDocStyle.Layout.PageLength, (int)myDocStyle.Layout.LeftMargin, (int)myDocStyle.Layout.PageWidth, (double)myItemInfo.MSWordPageCount, buf)) { ;} } doc.UpdateDRoUsages(roids); doc.Save(); if (savLen != _MyFile.Length) _MyLog.ErrorFormat("DSO FRAMER: File size changed during Save for Word Document, beginSize = {0}, endSize = {1}", savLen, _MyFile.Length); } #endregion #region Constructors public DSOFile(DocumentInfo myDocument) { MyDocument = myDocument; } #endregion #region Destructor ~DSOFile() { Dispose(false); } public void Dispose() { Dispose(false); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (!_IsDisposed) { _IsDisposed = true; TryDelete(); } } #endregion } public static class MSWordToPDF { private static bool _CloseWordWhenDone = true; public static bool CloseWordWhenDone { get { return MSWordToPDF._CloseWordWhenDone; } set { MSWordToPDF._CloseWordWhenDone = value; } } private static LBApplicationClass _MyApp = null; public static LBApplicationClass MyApp { get { if (_MyApp == null) _MyApp = new LBApplicationClass(); return _MyApp; } } private static int _DebugStatus = 0; public static int DebugStatus { get { return MSWordToPDF._DebugStatus; } set { MSWordToPDF._DebugStatus = value; } } private static System.Drawing.Color _OverrideColor = System.Drawing.Color.Transparent; public static System.Drawing.Color OverrideColor { get { return MSWordToPDF._OverrideColor; } set { MSWordToPDF._OverrideColor = value; } } private static System.Windows.Forms.Form _FormForPlotGraphics=null; public static System.Windows.Forms.Form FormForPlotGraphics { get { return MSWordToPDF._FormForPlotGraphics; } set { MSWordToPDF._FormForPlotGraphics = value; } } private static SectionInfo _MySection; public static string GetDocPdf(SectionInfo sect, Color overrideColor) { _MySection = sect; DocumentInfo mydoc = sect.MyContent.MyEntry.MyDocument; UpdateDocPdf(mydoc, overrideColor,sect); string fileName = GetFileName(sect); FileInfo fi = new FileInfo(fileName); FileStream fs = fi.Create(); PdfInfo myPdf = PdfInfo.Get(sect); if (myPdf != null && myPdf.DocPdf != null) fs.Write(myPdf.DocPdf, 0, myPdf.DocPdf.Length); fs.Close(); return fileName; } public static bool UpdateDocPdf(DocumentInfo mydoc, Color overrideColor, ItemInfo sect) { MSWordToPDF.OverrideColor = overrideColor; PdfInfo myPdf = PdfInfo.Get(sect); return true; } public static bool SetDocPdf(DocumentInfo docInfo, ItemInfo sect) { string pdfTmp = null; List roids = new List(); try { pdfTmp = MSWordToPDF.ToPDFReplaceROs(docInfo,roids,sect,null); } catch (Exception ex) { return false; } if (pdfTmp == null) return false; FileInfo pdfFile = new FileInfo(pdfTmp); FileStream fs = pdfFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); Byte[] buf = new byte[pdfFile.Length]; fs.Read(buf, 0, buf.Length); fs.Close(); pdfFile.Delete(); using (Document doc = docInfo.Get()) { DocStyle myDocStyle = sect.ActiveSection.MyDocStyle; SectionConfig sc = sect.ActiveSection.MyConfig as SectionConfig; int ss = sect.MyDocVersion.DocVersionConfig.SelectedSlave; if (sc != null && sc.Section_WordMargin == "Y") { using (Pdf myPdf = Pdf.MakePdf(doc, ss*10 + MSWordToPDF.DebugStatus, 0, 0, 0, 0, (double)sect.MSWordPageCount, buf)) { ;} } else { using (Pdf myPdf1 = Pdf.MakePdf(doc, ss*10 + MSWordToPDF.DebugStatus, (int)myDocStyle.Layout.TopMargin, (int)myDocStyle.Layout.PageLength, (int)myDocStyle.Layout.LeftMargin, (int)myDocStyle.Layout.PageWidth, (double)sect.MSWordPageCount, buf)) { ;} } doc.UpdateDRoUsages(roids); doc.Save(); } docInfo.RefreshConfig(); return true; } public static string ToPDFReplaceROs(DocumentInfo doc, List roids, ItemInfo sect, VolianStatusChange statusChange) { //ItemInfo sect = doc.DocumentEntries[0].MyContent.ContentItems[0]; return ToPDFReplaceROs(sect, false, roids, statusChange); } private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public static string ToPDFReplaceROs(ItemInfo sect, bool openPdf, List roids, VolianStatusChange statusChange) //, System.Drawing.Color overrideColor, System.Windows.Forms.Form myForm) { string fileName = GetFileName(sect); // TODO: do we want to cache the word pdfs //if (System.IO.File.Exists(@"C:\Temp\" + fileName + ".pdf")) // return @"C:\Temp\" + fileName + ".pdf"; //int docStyleIndex = ((int)sect.MyContent.Type) % 10000; //DocStyle myDocStyle = sect.ActiveFormat.PlantFormat.DocStyles.DocStyleList[docStyleIndex]; DocStyle myDocStyle = sect.MyDocStyle; //PageStyle myPageStyle = myDocStyle.pagestyle; ProcedureInfo proc = sect.MyProcedure; DocVersionInfo dvi = proc.ActiveParent as DocVersionInfo; bool hasRos = false; ROFstInfo rofst = null; ROFSTLookup lookup = null; string igPrefix = null; string spPrefix = null; if (dvi.DocVersionAssociationCount > 0) { hasRos = true; rofst = dvi.DocVersionAssociations[0].MyROFst; lookup = rofst.GetROFSTLookup(dvi); igPrefix = dvi.DocVersionConfig.RODefaults_graphicsprefix; spPrefix = dvi.DocVersionConfig.RODefaults_setpointprefix; } // string AccPageID = string.Format("<{0}-{1}>", accPrefix, roch.appid); using (DSOFile myFile = new DSOFile(sect.MyContent.MyEntry.MyDocument)) { // Increase the priority of the Word Process so that the pdf creation happens quickly Process[] myProcessess = Process.GetProcessesByName("winword"); foreach (Process myProcess in myProcessess) { try { if (myProcess.PriorityClass != ProcessPriorityClass.High && myProcess.MainWindowTitle == "") myProcess.PriorityClass = ProcessPriorityClass.High; } catch (Exception ex) { while (ex != null) { Console.WriteLine("{0} - {1}", ex.GetType().Name, ex.Message); ex = ex.InnerException; } } } LBDocumentClass myDoc = MyApp.Documents.Open(myFile.FullName, false); try { SectionConfig sc = sect.ActiveSection.MyConfig as SectionConfig; if (sc == null || sc.Section_WordMargin == "N") { AdjustMargins(myDocStyle, myDoc, true); } } catch (Exception ex) { _MyLog.Error("Could not Adjust Margins", ex); } LBSelection selxy = hasRos ? FindXyPlot() : null; string pngFile = VlnSettings.TemporaryFolder + @"\XYPlot1.png"; //@"C:\Temp\XYPlot1.png"; if (File.Exists(pngFile)) File.Delete(pngFile); int filecount = 1; while (selxy != null) { string xyplot = selxy.Text; xyplot = xyplot.Replace("`", "\xB0"); // The 16bit code must have kept the carriage returns in the word doc, if there // are carriage returns in the plot language. Count number of carriage return/newlines // so that they can be added back. int cnt = 0; int indxCr = xyplot.IndexOf("\r"); while (indxCr > 0) { cnt++; indxCr = xyplot.IndexOf("\r", indxCr + 1); } // Setting the selected text to "" actually sets it to "\r", thus cnt-- (subtract one // from cnt since there's already a return in the string. cnt--; float x = (float)selxy.get_Information(LBWdInformation.wdHorizontalPositionRelativeToPage); float y = (float)selxy.get_Information(LBWdInformation.wdVerticalPositionRelativeToPage); LBRange myRange = selxy.Paragraphs.First.Range; float yTop = (float)myRange.get_Information(LBWdInformation.wdVerticalPositionRelativeToPage); float yTop1 = (float)myRange.get_Information(LBWdInformation.wdVerticalPositionRelativeToTextBoundary); // some data had regular text embedded in the xyplot definition. If so, the plain text must // be left in the file. Otherwise, we can replace with empty text. string resXyPlot = xyplot; string txt = FindEmbeddedText(selxy.Text, ref resXyPlot); if (txt != null) { selxy.Text = txt; xyplot = resXyPlot.Replace(">\r>", ">>\r"); } else { selxy.Text = ""; if (cnt > 0) for (int icnt = 0; icnt < cnt; icnt++) selxy.Text = selxy.Text + "\r"; } pngFile = VlnSettings.TemporaryFolder + @"\XYPlot" + filecount.ToString() + @".png"; //@"C:\Temp\XYPlot1.png"; //FileInfo fi = new FileInfo(pngFile); //_MyLog.WarnFormat("PNG Name = {0}, size = {1}", fi.Name, fi.Length); filecount++; RectangleF plotRect = CreatePlot(pngFile, xyplot, 600F, FormForPlotGraphics); float xAdjust = (float)-sect.MyDocStyle.Layout.LeftMargin; float yAdjust = selxy.Font.Size; LBShape shape = myDoc.Shapes.AddPicture(pngFile, x + xAdjust + plotRect.X, yAdjust + y - yTop + plotRect.Y, selxy.Range); File.Delete(pngFile); shape.LockAspectRatio = LBMsoTriState.msoTrue; shape.Width = plotRect.Width; selxy.WholeStory(); selxy = FindXyPlot(); } LBSelection sel = MyApp.Selection; sel.WholeStory(); if (statusChange != null) statusChange(VolianStatusType.Initialize, sel.End, "Refreshing ROs"); sel = hasRos ? FindRO() : null; int roCount = 0; // force Print of MS Word Attachment to Final without revisions and comments myDoc.ActiveWindow.View.ShowRevisionsAndComments = false; myDoc.ActiveWindow.View.RevisionsView = LBWdRevisionsView.wdRevisionsViewFinal; while (sel != null) { if (statusChange != null) statusChange(VolianStatusType.Update, sel.Start, string.Format("{0} ROs Refreshed", ++roCount)); string val = lookup.GetROValueByAccPagID(sel.Text, spPrefix, igPrefix); int? type = lookup.GetROTypeByAccPagID(sel.Text, spPrefix, igPrefix); // if type is null, then set type to zero so that InsertROValue will put in "RO Not Found" for the value if (type == null) type = 0; // If multiple return values includes X-Y Plot, check to see if it is an X-Y Plot if (val == null) { if(sel.Text.ToUpper() == "") val =lookup.MyDocVersionInfo.DocVersionConfig.Unit_Text; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Unit_Number; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Unit_Name; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Unit_ID; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Other_Unit_Text; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Other_Unit_Number; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Other_Unit_Name; else if (sel.Text.ToUpper() == "") val = lookup.MyDocVersionInfo.DocVersionConfig.Other_Unit_ID; //val = "",MyDocVersion.DocVersionConfig.Unit_ID); //text = text.Replace(@"", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_ProcedureSetID); //text = text.Replace("", _MyItemInfo.MyDocVersion.DocVersionConfig.Unit_Number); } if ((type & 4) == 4 && val.StartsWith("< 0) && (idx < sel.Text.Length + 1)) { idx = sel.Text.IndexOf("\r", idx + 1); y += (float)sel.ParagraphFormat.LineSpacing; // get_Information(LBWdLineSpacing.wdLineSpaceSingle); } //LBInlineShape shape = sel.InlineShapes.AddPicture(pngFile); LBRange myRange = sel.Paragraphs.First.Range; float yTop = (float)myRange.get_Information(LBWdInformation.wdVerticalPositionRelativeToPage); float yTop1 = (float)myRange.get_Information(LBWdInformation.wdVerticalPositionRelativeToTextBoundary); float xAdjust = (float)-sect.MyDocStyle.Layout.LeftMargin; float yAdjust = sel.Font.Size; // The following two lines made the xyplot location for WCN2 match the 16bit output. However, how the // xTweak value is determined is phantom of Rich's mind. Word document location of the RO token // will be modified in data before delivery so that this xTweak is not needed. //float xTweak = -(30 + xAdjust) / 3; // Used to align plots for WCN2. //LBShape shape = myDoc.Shapes.AddPicture(pngFile, x + xAdjust + plotRect.X + xTweak, yAdjust + y - yTop + plotRect.Y, sel.Range); LBShape shape = myDoc.Shapes.AddPicture(pngFile, x + xAdjust + plotRect.X, yAdjust + y - yTop + plotRect.Y, sel.Range); File.Delete(pngFile); shape.LockAspectRatio = LBMsoTriState.msoTrue; //shape.Width = .89F * shape.Width; //shape.Width = float.Parse(tbAdjust.Text) * shape.Width; shape.Width = plotRect.Width; //shape.Height = .89F * shape.Height; sel.WholeStory(); // TODO: Do we want to color code ROs //sel.Range.Font.Color = LBWdColor.wdColorRed; //shape.Width = width; //shape.Height = height; //imageROTokenReplaced = true; } catch (Exception ex) { // something is wrong with the X/Y plot RO. // print out the un-processed X/Y plot RO value sel.Text = val; //return null; } } else { if (val != null) val = val.Replace("`", "\xB0"); //AddInfo("\tRO Found {0} = '{1}'", sel.Text, val); // if val is null, then InsertROValue will put in "RO Not Found" for the value InsertROValue(sel, val, sect.ActiveFormat.PlantFormat.FormatData.ROData.UpRoIfPrevUpper); } sel = FindRO(); } if (statusChange != null) statusChange(VolianStatusType.Update, 0, "Creating PDF"); sel = MyApp.Selection; sel.WholeStory(); //sel.Range.Font.Color = (LBWdColor)WordColor(PrintOverride.OverrideTextColor(System.Drawing.Color.Black)); sel.Range.Font.Color = (LBWdColor)WordColor(OverrideColor == System.Drawing.Color.Transparent ? System.Drawing.Color.Black : OverrideColor); sect.MSWordPageCount = myDoc.Length; fileName = CreatePDF(fileName, openPdf,MSWordToPDF.DebugStatus); CloseDocument(); if (CloseWordWhenDone) { CloseAppAfterWait(); } if (statusChange != null) statusChange(VolianStatusType.Complete, 0, ""); return fileName; } } private static void CloseDocument() { int attempts = 0; while (++attempts < 11) { if (TryToClose(attempts)) return; WaitMS(1000); } } private static bool TryToClose(int attempts) { try { MyApp.ActiveDocument.Close(false); return true; } catch (Exception ex) { _MyLog.WarnFormat("{0} - {1}, Attempt {2}", ex.GetType().Name, ex.Message, attempts); if (attempts >= 10) _MyLog.Error("Failed to close 10 times.", ex); return false; } } private static string FindEmbeddedText(string p, ref string resXyPlot) { StringBuilder sb = new StringBuilder(); // contains embedded text StringBuilder xy = new StringBuilder(); // contains xyplot without embedded text. string origXy = p; bool findEmbeddedText = false; // get past opening command: int indxCmd = p.IndexOf("<"); indxCmd = p.IndexOf("<", indxCmd + 1); xy.Append(p.Substring(0, indxCmd)); // While there are xyplot commands, check for beginning/ending. // Any text not in a command, save. while (indxCmd > 0) { // find end of command. Look for another beginning of command, newline, // regular text, or end of graph and handle each of these cases. int indxClose = GetNonStringCmdClose(p, indxCmd + 1); // p.IndexOf(">", indxCmd + 1); int nxtIndxCmd = p.IndexOf("<", indxCmd + 1); xy.Append(p.Substring(indxCmd, indxClose - indxCmd+1)); xy.Append("\r"); // the xyplot code assumes a return exists. // get substrings between end index & start of next and if any // non white space text, add it to return string and flag that we have // embedded text. If there's a newline and just other white space put a // newline in return string. if (nxtIndxCmd > 0) { string mydebug = p.Substring(indxClose + 1); for (int i = indxClose + 1; i < nxtIndxCmd; i++) { if (!System.Char.IsWhiteSpace(p[i])) { sb.Append(p[i]); findEmbeddedText = true; } if (p[i] == '\r' || p[i] == ' ') sb.Append(p[i]); } } indxCmd = nxtIndxCmd; } xy.Append(">"); if (findEmbeddedText) { resXyPlot = xy.ToString(); return sb.ToString(); } resXyPlot = origXy; return null; } private static int GetNonStringCmdClose(string p, int indxCmd) { int indxClose = p.IndexOf(">", indxCmd); if (indxClose >= 0) { // if there are any quotes between the open of command and close, // need to see if the close command is quoted. if (p.IndexOf('"', indxCmd, indxClose - indxCmd) > -1) { // see how many quotes between open/close command, if // an odd number, the close command char '>' is in quotes. int countQuotes = 0; for (int i = indxCmd; i < indxClose; i++) if (p[i] == '"') countQuotes++; if ((countQuotes % 2) != 0) { // find quote after close, and then get next close. int closeQuote = p.IndexOf('"', indxClose); if (closeQuote < 0) return -1; // this is error, so return end not found. return p.IndexOf(">", closeQuote + 1); } } } return indxClose; } public static void AddPrecedingText(LBSelection sel, string val) { if (val.IndexOf("_") == -1) // Is some of the text underlined? { sel.Text = val; // nothing is underlined, use text as is return; } // Back in the DOS days, an underbar was used to toggle underlining on/off // Spit the val text on the underbar characters string[] parts = val.Split("_".ToCharArray()); foreach (string part in parts) { // If there is a carrage return, and underline is turned on, then turn off the underline if (sel.Font.Underline != LBWdUnderline.wdUnderlineNone && part.Contains("\r")) { int idx = part.IndexOf("\r"); string part1 = part.Substring(0, idx); string part2 = part.Substring(idx); sel.TypeText(part1); sel.Font.Underline = LBWdUnderline.wdUnderlineNone; sel.TypeText(part2); } else // put out each part of the split text and toggle the underline on/off { // Farley had a case where the underlining of text with spaces at end of line was // not underlining the spaces. To fix this, test for spaces at the end of text // and ireplace last space with a hard space. Note that the underlying issue // existed in MS Word, so this is a work around from our code to make MS Word work. // The problem was in Farley's FNP-1-ECP-3.1, Table 1 - 'ro': W.4T. if (part.EndsWith(" ")) { sel.TypeText(part.Substring(0,part.Length-1)); sel.InsertSymbol(160); } else sel.TypeText(part); if (sel.Font.Underline == LBWdUnderline.wdUnderlineNone) sel.Font.Underline = LBWdUnderline.wdUnderlineSingle; else sel.Font.Underline = LBWdUnderline.wdUnderlineNone; } } // We are done processing the text in val, if underline is on, turn it off if (sel.Font.Underline != LBWdUnderline.wdUnderlineNone) sel.Font.Underline = LBWdUnderline.wdUnderlineNone; } public static void AdjustMargins(DocStyle myDocStyle, LBDocumentClass myDoc, bool printingMode) { float newTop = (float)myDocStyle.Layout.TopMargin; float newLeft = (float)myDocStyle.Layout.LeftMargin; float newLength = (float)myDocStyle.Layout.PageLength; float newWidth = (float)myDocStyle.Layout.PageWidth; float oldTop = myDoc.PageSetup.TopMargin; float oldLeft = myDoc.PageSetup.LeftMargin; float oldBottom = myDoc.PageSetup.BottomMargin; float oldRight = myDoc.PageSetup.RightMargin; float oldHeight = myDoc.PageSetup.PageHeight; float oldWidth = myDoc.PageSetup.PageWidth; // in the following line, the 2 accounts for a difference between how word treats margin versus // ours, we are not exactly sure why. float newRight = Math.Max(0, oldWidth - (newWidth + 2)); float newBottom = Math.Max(0, oldHeight - (newLength + newTop + 1)); //Console.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}", newTop, newLeft, newLength, newWidth, oldTop, oldLeft, oldBottom, oldRight,oldHeight,oldWidth); if (printingMode) { if (myDoc.PageSetup.BottomMargin != 9999999) { // the + 1 in the next line allows for rounding. if ((newWidth > (8.5f * 72)) && newWidth > newLength) if(myDoc.PageSetup.Orientation != LBWdOrientation.wdOrientLandscape) myDoc.PageSetup.Orientation = LBWdOrientation.wdOrientLandscape; myDoc.PageSetup.BottomMargin = newBottom; myDoc.PageSetup.RightMargin = newRight; myDoc.PageSetup.LeftMargin = newLeft; myDoc.PageSetup.TopMargin = newTop; } else { try { // the + 1 in the next line allows for rounding. myDoc.PageSetup.BottomMargin = newBottom; myDoc.PageSetup.RightMargin = newRight; myDoc.PageSetup.LeftMargin = newLeft; myDoc.PageSetup.TopMargin = newTop; } catch (Exception ex) { if (_MySection != null) { _MyLog.ErrorFormat("<<< ERROR >>> MSWord could not set margins\r\n==>'MSWord could not set margins',{0},'{1}','{2}'" , _MySection.ItemID, _MySection.MyDocVersion.MyFolder.Name, _MySection.ShortPath); } else _MyLog.Error("Could not set margins", ex); } } } else { myDoc.PageSetup.TopMargin = 0; myDoc.PageSetup.LeftMargin = 0; myDoc.PageSetup.RightMargin = (8.5F * 72) - newWidth + newLeft; // For OHLP, docstyle (ohlpdoc.in) in 16-bit for "Cover Page", pagelen seems to be incorrect. It would // put out text on a second page. The following code is to catch this condition and reset the bottom margin. // 11 * 72 -> 11 inches converted to points. newLength is printable part so BottomMargin is unprintable part if (newTop + 36 > ((11 * 72) - newLength)) // 36 is 1/2 inch myDoc.PageSetup.BottomMargin = newTop + 36; // makes an 1/2 inch bottom margin else myDoc.PageSetup.BottomMargin = (11 * 72) - newLength; } } public static void CloseApp() { //WaitMS(900);// This was added because MSWord will sometimes get the error below // Microsoft Office Word has stopped working // It appears that this is caused by quiting the MS Word application // to soon after closing the document or doing an export. MyApp.Quit(false); _MyApp = null; } /// /// This closes the MS Word Application, but, delays for about 1 second. /// It appears that closing MSWord to quickly causes a: /// "Microsoft Office Word has stopped working" error. /// public static void CloseAppAfterWait() { System.Windows.Forms.Application.DoEvents(); new CloseWordApp(_MyApp, 1000); _MyApp = null; } private class CloseWordApp:System.Windows.Forms.Timer { LBApplicationClass _MyApp; public LBApplicationClass MyApp { get { return _MyApp; } set { _MyApp = value; } } public CloseWordApp(LBApplicationClass myApp, int interval) { MyApp = myApp; Interval = interval; Tick += new EventHandler(CloseWordApp_Tick); Enabled = true; } void CloseWordApp_Tick(object sender, EventArgs e) { Enabled = false; MyApp.Quit(false); Dispose(); } } private static void WaitMS(int n) { DateTime dtw = DateTime.Now.AddMilliseconds(n); while (DateTime.Now < dtw) { System.Windows.Forms.Application.DoEvents(); } } private static int WordColor(System.Drawing.Color color) { System.Drawing.Color c1 = System.Drawing.Color.FromArgb(0, color.B, color.G, color.R); return c1.ToArgb(); } private static string GetFileName(ItemInfo sect) { string fileName = VlnSettings.TemporaryFolder + @"\Doc " + sect.MyContent.MyEntry.DocID.ToString(); // +" " + (sect.DisplayNumber == "" ? sect.DisplayText : sect.DisplayNumber); return fileName; } private static RectangleF CreatePlot(string pngFile, string xyPlot, float resolution, System.Windows.Forms.Form myForm) { RectangleF retval = new RectangleF(0, 0, 0, 0); //Form frm = Application.OpenForms[0]; System.Windows.Forms.Form frm = myForm; Graphics grfx = frm.CreateGraphics(); string emfFile = pngFile.Replace(".png", ".emf"); Metafile mf = new Metafile(emfFile, grfx.GetHdc()); grfx.Dispose(); grfx = Graphics.FromImage(mf); float dpi = grfx.DpiX; //grfx.ScaleTransform(resolution / grfx.DpiX, (resolution +1F) / grfx.DpiY); grfx.ScaleTransform(resolution / grfx.DpiX, resolution / grfx.DpiY); grfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; grfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; grfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; grfx.Clear(MSWordToPDF.DebugStatus==1 ? System.Drawing.Color.Transparent : System.Drawing.Color.White); //grfx.Clear(System.Drawing.Color.SlateGray); XYPlots.XYPlot.BlackColor = MSWordToPDF.OverrideColor == Color.Red ? Color.Red : Color.Black; XYPlots.XYPlot myPlot = new XYPlots.XYPlot(xyPlot); myPlot.SetMargins(0, 0, 0, 0); VG.IVGOutput vgOut = new VG.VGOut_Graphics(grfx); vgOut.DebugStatus = MSWordToPDF.DebugStatus; myPlot.Process(vgOut); grfx.Dispose(); GraphicsUnit gu = new GraphicsUnit(); retval = mf.GetBounds(ref gu); retval.Width *= dpi / resolution; retval.Height *= dpi / resolution; retval.X *= dpi / resolution; retval.Y *= dpi / resolution; //retval.X = myPlot.Width-retval.Width; //AddInfo("{0},{1},{2},{3},{4},{5}", myPlot.Width, myPlot.Height, retval.Width, retval.Height,retval.X,retval.Y); //Console.Write("{0},{1},{2},{3}", myPlot.Width, myPlot.Height, retval.Width, retval.Height); mf.Save(pngFile, ImageFormat.Png); //Console.WriteLine("'pngfile','{0}'", pngFile); mf.Dispose(); FileInfo myFile = new System.IO.FileInfo(emfFile); myFile.Delete(); return retval; } private static void InsertROValue(LBSelection sel, string roValue, bool upRoIfPrevUpper) { if (roValue == null) { sel.Text = "RO Not Found"; sel.Font.Color = LBWdColor.wdColorRed; } else { if (upRoIfPrevUpper && sel.LastWasUpper) roValue = roValue.ToUpper(); // Convert fortran formatted numbers to scientific notation. //string tmp = DisplayRO.ConvertFortranFormatToScienctificNotation(roValue); string tmp = ROFSTLookup.ConvertFortranFormatToScienctificNotation(roValue); // Only in Word sections, convert the # to superscripts and ~ to subscrtipts tmp = Regex.Replace(tmp, "[#](.*?)[#]", "\\up2 $1\\up0 ");// DOS Superscript tmp = Regex.Replace(tmp, "[~](.*?)[~]", "\\dn2 $1\\up0 ");// DOS Subscript tmp = tmp.Replace(@"\u160?", "\xA0"); tmp = tmp.Replace(@"\U160?", "\xA0"); tmp = tmp.Replace(@"[xB3]", "\xB3"); tmp = tmp.Replace(@"\U8209?", "-"); // fixes negative value in scienctific notation tmp = tmp.Replace(@"\u8209?", "-"); // Look for superscript or subscript and insert the appropriate commands Match roMatch = Regex.Match(tmp, @"(.*?)\\(up2|dn2) (.*?)\\(up0|dn0) "); if (roMatch.Groups.Count == 5)// Superscript or subscript found { sel.Font.Color = LBWdColor.wdColorRed; while (roMatch.Groups.Count == 5) { sel.TypeText(roMatch.Groups[1].Value); // output the text preceeding the super or sub command sel.Font.Position = roMatch.Groups[2].Value == "up2" ? 2 : -2; // Shift the vertical position for super or sub sel.TypeText(roMatch.Groups[3].Value); // output the superscript or subscript sel.Font.Position = 0; // restore the vertical position tmp = tmp.Substring(roMatch.Length); // remove the processed text roMatch = Regex.Match(tmp, @"(.*?)\\(up2|dn2) (.*?)\\(up0|dn0) "); // check to see if the text contain another super or sub } if (tmp != "")// Add any remaining text sel.TypeText(tmp); sel.Font.Color = LBWdColor.wdColorAutomatic; } else // if no superscripts or subscripts just output the text { roValue = roValue.Replace(@"\u160?", "\xA0"); roValue = roValue.Replace(@"\U160?", "\xA0"); roValue = roValue.Replace(@"[xB3]", "\xB3"); roValue = roValue.Replace(@"[XB3]", "\xB3"); sel.Text = roValue; // look for toggling of '_' to turn underlining on/off: AddPrecedingText(sel, roValue); // parse underlining sel.Font.Color = LBWdColor.wdColorRed; } } } private static LBSelection FindXyPlot() { LBSelection sel = MyApp.Selection; LBFind find = sel.Find; find.ClearFormatting(); // Search string format - this is MSWord wildcard format // If you do a search in MSWord, make sure wildcard box is checked and then press the // Special button to see the definitions of the various wildcards // [<] - Less-Than Character // [!<> ]@ - 1 or more characters not including Less-Than, Greater-Than or Space // - Dash // [!<> ]@ - 1 or more characters not including Less-Than, Greater-Than or Space // [>] - Greater-Than Character find.Text = "[<][<]*[>][>]"; //find.Wrap = LBWdFindWrap.wdFindStop; find.Wrap = LBWdFindWrap.wdFindContinue; find.MatchCase = false; find.MatchWholeWord = false; find.MatchWildcards = true; find.MatchSoundsLike = false; find.MatchAllWordForms = false; if (find.Execute()) return sel; return null; } private static LBSelection FindRO() { int firstStart = 0; bool executeResult = false; LBSelection sel = null; while (!executeResult) { sel = MyApp.Selection; LBFind find = sel.Find; find.ClearFormatting(); // Search string format - this is MSWord wildcard format // If you do a search in MSWord, make sure wildcard box is checked and then press the // Special button to see the definitions of the various wildcards // [<] - Less-Than Character // [!<> ]@ - 1 or more characters not including Less-Than, Greater-Than or Space // - Dash // [!<>]@ - 1 or more characters not including Less-Than, Greater-Than. // a space be included as part of the accessory page id (Callaway, EOP Addendum 37) // [>] - Greater-Than Character find.Text = "[<][!<> ]@-[!<>]@[>]"; find.Wrap = LBWdFindWrap.wdFindContinue; find.MatchCase = false; find.MatchWholeWord = false; find.MatchWildcards = true; find.MatchSoundsLike = false; find.MatchAllWordForms = false; executeResult = find.Execute(); if (!executeResult) return null; // MS Word found 'invalid' ro when text had "[335.0