using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Utils; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Sarand.Net.Standard.Proc.Excel { //======================================================================= public class SaMsSpreadsheet_OpenXml : SaMsSpreadsheet { //------------------------------------------------------------------- // Data members. private class WorkbookData { public SpreadsheetDocument Document { get; set; } public MemoryStream MemoryStream { get; set; } public WorkbookPart WorkbookPart { get { return Document.WorkbookPart; } } } private WorkbookData workbook; private class WorksheetData { public WorksheetData(uint worksheetPos, WorksheetPart worksheetPart, Sheet sheet) { WorksheetPos = worksheetPos; WorksheetPart = worksheetPart; Sheet = sheet; } public uint WorksheetPos { get; } public WorksheetPart WorksheetPart { get; } public Sheet Sheet { get; } public SheetData SheetData { get { return WorksheetPart.Worksheet.GetFirstChild(); } } // Active column. public uint ActiveColumnPos { get; private set; } public Column ActiveColumn { get; private set; } public void SetActiveColumn(uint activeColumnPos, Column activeColumn) { ActiveColumnPos = activeColumnPos; ActiveColumn = activeColumn; } public void ClearActiveColumn() { ActiveColumnPos = 0; ActiveColumn = null; } // Active row. public uint ActiveRowPos { get; private set; } public Row ActiveRow { get; private set; } public void SetActiveRow(uint activeRowPos, Row activeRow) { ActiveRowPos = activeRowPos; ActiveRow = activeRow; } public void ClearActiveRow() { ActiveRowPos = 0; ActiveRow = null; } } private WorksheetData worksheet; private uint activeWorksheetPos; //------------------------------------------------------------------- // Construction. public SaMsSpreadsheet_OpenXml() : base() { } protected override void Dispose(bool disposing) { if (disposing) { CloseWorkbook(); } base.Dispose(disposing); } //------------------------------------------------------------------- // Properties. private WorkbookPart WorkbookPart { get { return workbook.WorkbookPart; } } private Sheets Sheets { get { return WorkbookPart.Workbook.Sheets; } } //------------------------------------------------------------------- // W o r k b o o k //------------------------------------------------------------------- public override bool IsWorkbookValid() { return (workbook != null); } public override bool CreateWorkbook() { ClearErrorState(); CloseWorkbook(); try { workbook = new WorkbookData(); workbook.MemoryStream = new MemoryStream(); workbook.Document = SpreadsheetDocument.Create(workbook.MemoryStream, SpreadsheetDocumentType.Workbook); } catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); } return (workbook != null); } public override bool OpenWorkbook(String filePath) { ClearErrorState(); CloseWorkbook(); try { workbook = new WorkbookData(); workbook.Document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook); } catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); } return (workbook != null); } public override bool CleanseWorkbook() { throw new NotSupportedException(SysUtil.Fn); } public override bool SaveDocument(String filePath, int fileFormat, bool bAutomaticallyOverwrite) { ClearErrorState(); #pragma warning disable CS0219 // Variable is assigned but its value is never used SpreadsheetDocumentType documentType = SpreadsheetDocumentType.Workbook; #pragma warning restore CS0219 // Variable is assigned but its value is never used if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplate || fileFormat == (int)XlFileFormat.xlTemplate || fileFormat == (int)XlFileFormat.xlTemplate8) documentType = SpreadsheetDocumentType.Template; else if (fileFormat == (int)XlFileFormat.xlOpenXMLWorkbookMacroEnabled) documentType = SpreadsheetDocumentType.MacroEnabledWorkbook; else if (fileFormat == (int)XlFileFormat.xlOpenXMLTemplateMacroEnabled) documentType = SpreadsheetDocumentType.MacroEnabledTemplate; else if (fileFormat == (int)XlFileFormat.xlOpenXMLAddIn || fileFormat == (int)XlFileFormat.xlAddIn || fileFormat == (int)XlFileFormat.xlAddIn8 || fileFormat == (int)XlFileFormat.xlIntlAddIn) documentType = SpreadsheetDocumentType.AddIn; // ToDo Save OpenXML Excel document. return OK; } public override bool CloseWorkbook() { ClearErrorState(); CloseWorksheet(); try { if (workbook != null) { if (workbook.Document != null) workbook.Document.Dispose(); if (workbook.MemoryStream != null) workbook.MemoryStream.Dispose(); workbook = null; } } catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); } workbook = null; return OK; } /// Extract the document as a byte array. /// Document data as byte array. public override byte[] GetDocumentData() { throw new NotSupportedException(SysUtil.Fn); } // Default style. public override void ApplyDefaultStyle(SaMsExcelStyleAttr attr) { throw new NotSupportedException(SysUtil.Fn); } //------------------------------------------------------------------- // W o r k s h e e t s //------------------------------------------------------------------- public override uint WorksheetCount { get { uint worksheetCount = 0; foreach (Sheet sheet in Sheets) worksheetCount++; return worksheetCount; } } public override bool SetWorksheetCount(int worksheetCount) { ClearErrorState(); if (worksheetCount > 0 && worksheetCount < 11) { while (WorksheetCount < worksheetCount) AddWorksheet(""); while (WorksheetCount > worksheetCount) RemoveWorksheet(WorksheetCount); OpenWorksheet(1); } else SetErrorState("SetWorksheetCount - Requested number of worksheets (" + worksheetCount.ToString() + ") must be between 1 and 10"); return OK; } //------------------------------------------------------------------- public override List WorksheetNames { get { return new List(); } } //------------------------------------------------------------------- public override bool AddWorksheet(String sheetName) { ClearErrorState(); CloseWorksheet(); // Add a blank WorksheetPart. WorksheetPart worksheetPart = WorkbookPart.AddNewPart(); worksheetPart.Worksheet = new Worksheet(new SheetData()); // Get a unique ID for the new worksheet. Sheets sheets = WorkbookPart.Workbook.GetFirstChild(); uint sheetId = 1; if (sheets.Elements().Count() > 0) { sheetId = sheets.Elements().Select(item => item.SheetId.Value).Max() + 1; } // Append the new worksheet and associate it with the workbook. String relationshipId = WorkbookPart.GetIdOfPart(worksheetPart); sheetName = StringUtil.OnEmpty(StringUtil.TrimAll(sheetName), "Sheet" + sheetId); Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName }; sheets.Append(sheet); worksheet = new WorksheetData(WorksheetCount, worksheetPart, sheet); return (worksheet != null); } //------------------------------------------------------------------- public override bool RemoveWorksheet(uint worksheetPos) { ClearErrorState(); // Extract Sheet by position. int sheetCount = 0; Sheet sheet = null; foreach (Sheet sheetCandidate in Sheets) { if (++sheetCount == worksheetPos) { sheet = sheetCandidate; break; } } if (sheet != null) { // Extract the corresponding Worksheet Part. WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id)); // Check if the worksheet being removed is currently open. if (worksheet != null && sheet.Id == worksheet.Sheet.Id) CloseWorksheet(); // Remove the sheet from the workbook. sheet.Remove(); WorkbookPart.DeletePart(worksheetPart); return true; } return false; } //------------------------------------------------------------------- // W o r k s h e e t //------------------------------------------------------------------- public override bool OpenWorksheet(uint worksheetPos) { ClearErrorState(); CloseWorksheet(); // Extract Sheet by position. int sheetCount = 0; Sheet sheet = null; foreach (Sheet sheetCandidate in Sheets) { if (++sheetCount == worksheetPos) { sheet = sheetCandidate; break; } } if (sheet != null) { WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id)); if (worksheetPart != null && sheet != null) worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet); } if (worksheet != null) { SaLogger.Warn(SysUtil.Fn + " Failed to open worksheet " + worksheetPos); SetErrorState("Failed to open worksheet " + worksheetPos); } return (worksheet != null); } public override bool OpenWorksheet(String name) { ClearErrorState(); CloseWorksheet(); name = StringUtil.TrimWhitespace(name); // Extract Sheet by position. uint worksheetPos = 0; Sheet sheet = null; foreach (Sheet sheetCandidate in Sheets) { ++worksheetPos; if (StringUtil.TrimWhitespace(sheetCandidate.Name).EqualsCI(name)) { sheet = sheetCandidate; break; } } if (sheet != null) { WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id)); if (worksheetPart != null && sheet != null) worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet); } if (worksheet != null) { String msg = "Failed to open worksheet: " + name; SetErrorState(msg); SaLogger.Warn(SysUtil.Fn + " " + msg); } return (worksheet != null); } //------------------------------------------------------------------- public override bool CloseWorksheet() { ClearErrorState(); try { if (worksheet != null) { // No worksheet components need to be disposed - they belong to the workbook. } worksheet = null; } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } worksheet = null; activeWorksheetPos = 0; return OK; } //------------------------------------------------------------------- public override bool IsWorksheetValid() { return (worksheet != null); } //------------------------------------------------------------------- public override uint WorksheetPos { get { return activeWorksheetPos; } } public override String WorksheetName { get { return worksheet.Sheet.Name; } set { worksheet.Sheet.Name = StringUtil.Left(value, 31); } } //------------------------------------------------------------------- public override bool SetWorksheetAttr(SaMsExcelStyleAttr attr) { ClearErrorState(); try { // ToDo OpenXml SetWorksheetAttr } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- // Worksheet Page Setup. public override bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig) { //--------------------------------------------------------------- // Page setup options: // ActiveSheet.PageSetup // .PrintTitleRows = "$4:$4" // .PrintTitleColumns = "" // .PrintArea = "" // .LeftHeader = "" // .CenterHeader = "" // .RightHeader = "" // .LeftFooter = "" // .CenterFooter = "" // .RightFooter = "" // .LeftMargin = Application.InchesToPoints(0.708661417322835) // .RightMargin = Application.InchesToPoints(0.708661417322835) // .TopMargin = Application.InchesToPoints(0.748031496062992) // .BottomMargin = Application.InchesToPoints(0.748031496062992) // .HeaderMargin = Application.InchesToPoints(0.31496062992126) // .FooterMargin = Application.InchesToPoints(0.31496062992126) // .PrintHeadings = False // .PrintGridlines = False // .PrintComments = xlPrintNoComments // .PrintQuality = 600 // .CenterHorizontally = False // .CenterVertically = False // .Orientation = xlPortrait // .Draft = False // .PaperSize = xlPaperA4 // .FirstPageNumber = xlAutomatic // .Order = xlDownThenOver // .BlackAndWhite = False // .Zoom = 100 // .PrintErrors = xlPrintErrorsDisplayed // .OddAndEvenPagesHeaderFooter = False // .DifferentFirstPageHeaderFooter = False // .ScaleWithDocHeaderFooter = True // .AlignMarginsHeaderFooter = True // .EvenPage.LeftHeader.Text = "" // .EvenPage.CenterHeader.Text = "" // .EvenPage.RightHeader.Text = "" // .EvenPage.LeftFooter.Text = "" // .EvenPage.CenterFooter.Text = "" // .EvenPage.RightFooter.Text = "" // .FirstPage.LeftHeader.Text = "" // .FirstPage.CenterHeader.Text = "" // .FirstPage.RightHeader.Text = "" // .FirstPage.LeftFooter.Text = "" // .FirstPage.CenterFooter.Text = "" // .FirstPage.RightFooter.Text = "" //--------------------------------------------------------------- // Negative values leave current value. ClearErrorState(); if (worksheet == null) return false; try { // Page margins - must be before the Page Setup in the worksheet. PageMargins pageMargins = worksheet.WorksheetPart.Worksheet.GetFirstChild(); if (pageMargins == null) { pageMargins = new PageMargins(); worksheet.WorksheetPart.Worksheet.AppendChild(pageMargins); } // Page Setup. PageSetupProperties pageSetupProperties = worksheet.WorksheetPart.Worksheet.SheetProperties.PageSetupProperties; PageSetup pageSetup = worksheet.WorksheetPart.Worksheet.GetFirstChild(); if (pageSetup == null) { pageSetup = new PageSetup(); worksheet.WorksheetPart.Worksheet.AppendChild(pageSetup); } if (pageSetupConfig.Orientation == SaXlPageOrientation.xlLandscape) pageSetup.Orientation = OrientationValues.Landscape; else if (pageSetupConfig.Orientation == SaXlPageOrientation.xlPortrait) pageSetup.Orientation = OrientationValues.Portrait; // ToDo OpenXML Headers and footers. //pageSetup.LeftHeader = pageSetupConfig.HeaderLeft; //pageSetup.CenterHeader = pageSetupConfig.HeaderCenter; //pageSetup.RightHeader = pageSetupConfig.HeaderRight; //pageSetup.LeftFooter = pageSetupConfig.FooterLeft; //pageSetup.CenterFooter = pageSetupConfig.FooterCenter; //pageSetup.RightFooter = pageSetupConfig.FooterRight; // Margins. if (pageSetupConfig.MarginLeft > 0) pageMargins.Left = ToPoints(pageSetupConfig.MarginLeft, pageSetupConfig.Unit, false); if (pageSetupConfig.MarginRight > 0) pageMargins.Right = ToPoints(pageSetupConfig.MarginRight, pageSetupConfig.Unit, false); if (pageSetupConfig.MarginTop > 0) pageMargins.Top = ToPoints(pageSetupConfig.MarginTop, pageSetupConfig.Unit, true); if (pageSetupConfig.MarginBottom > 0) pageMargins.Bottom = ToPoints(pageSetupConfig.MarginBottom, pageSetupConfig.Unit, true); if (pageSetupConfig.MarginHeader > 0) pageMargins.Header = ToPoints(pageSetupConfig.MarginHeader, pageSetupConfig.Unit, true); if (pageSetupConfig.MarginFooter > 0) pageMargins.Footer = ToPoints(pageSetupConfig.MarginFooter, pageSetupConfig.Unit, true); /* * ToDo OpenXML PrintTitleRows/Columns // Print Title Rows. if (pageSetupConfig.PrintTitleRowFrom > 0 && pageSetupConfig.PrintTitleRowTo > 0) // Prefix with '$' to fix row value.(?) pageSetup.PrintTitleRows = "$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowFrom) + ":$" + GetRowSuffix((uint)pageSetupConfig.PrintTitleRowTo); else if (pageSetupConfig.PrintTitleRowFrom == 0 && pageSetupConfig.PrintTitleRowTo == 0) pageSetup.PrintTitleRows = ""; // Print Title Columns. if (pageSetupConfig.PrintTitleColFrom > 0 && pageSetupConfig.PrintTitleColTo > 0) pageSetup.PrintTitleColumns = "$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColFrom) + ":$" + GetColumnPrefix((uint)pageSetupConfig.PrintTitleColTo); else if (pageSetupConfig.PrintTitleColFrom == 0 && pageSetupConfig.PrintTitleColTo == 0) pageSetup.PrintTitleColumns = ""; */ /* // ToDo OpenXML Zoom and 'Fit to' options. if (pageSetupConfig.Zoom > 0) pageSetup.Zoom = pageSetupConfig.Zoom; else if (pageSetupConfig.FitToPagesTall > 0 || pageSetupConfig.FitToPagesWide > 0) { pageSetup.FitToPagesWide = Math.Min(0, pageSetupConfig.FitToPagesWide); pageSetup.FitToPagesTall = Math.Min(0, pageSetupConfig.FitToPagesTall); pageSetup.Zoom = 0; } */ } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } public override bool SetPageBreak(uint colPos, uint rowPos) { ClearErrorState(); if (worksheet == null) return false; try { /* * ToDo OpenXML Set page break String cellId = GetCellId(colPos, rowPos); Range range = worksheet.get_Range(cellId); worksheet.HPageBreaks.Add(range); worksheet.VPageBreaks.Add(range); */ } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- public bool SelectRange() { // ToDo OpenXML Is SelectRange even relevant? return false; } //------------------------------------------------------------------- // C o l u m n s //------------------------------------------------------------------- private Column GetColumnByPos(uint columnPos) { if (worksheet.ActiveColumnPos != columnPos) { // ToDo OpenXML GetColumnByPos. //Column column = worksheet.WorksheetPart.col } return worksheet.ActiveColumn; } public override uint ActiveColPos { get { if (worksheet == null) return 0; try { return worksheet.ActiveColumnPos; } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return 0; } } public override double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) { double columnWidth = 0.0; try { // ToDo OpenXML GetColWidth. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return columnWidth; } public override bool SetColWidth(uint colPos, double columnWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) { ClearErrorState(); try { // ToDo OpenXML SetColWidth. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- // R o w s //------------------------------------------------------------------- public override uint FirstRowPos { get { return (uint)(0); } } public override uint LastRowPos { get { return (uint)(0); } } //------------------------------------------------------------------- public override uint ActiveRowPos { get { try { // ToDo OpenXML GetActiveRowPos. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return 0; } } public override List GetRowValues(uint rowPos, int maxColumns = 0) { List values = new List(); return values; } public override double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) { double rowHeight = 0.0; try { // ToDo OpenXML GetRowHeight. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return rowHeight; } public override bool SetRowHeight(uint rowPos, double rowHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) { ClearErrorState(); try { // ToDo OpenXML SetRowHeight. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- // C e l l s //------------------------------------------------------------------- public override void SetActiveCell(uint colPos, uint rowPos) { // ToDo OpenXML SetActiveCell. } public override String GetCellFormula(uint colPos, uint rowPos) { // ToDo OpenXML GetCellFormula. return ""; } public override String GetCellText(uint colPos, uint rowPos, bool trimWhitespace = true) { // ToDo OpenXML GetCellText. return ""; } public override DataValue GetCellValue(uint colPos, uint rowPos) { // ToDo OpenXML GetCellDataValue. return new DataValue(); } //------------------------------------------------------------------- public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelStyleAttr attr) { // ToDo OpenXML SetCellFormula. return true; } public override bool SetCellValue(uint colPos, uint rowPos, DataValue value, SaMsExcelStyleAttr attr) { // ToDo OpenXML SetCellValue. return true; } //------------------------------------------------------------------- // Cell attributes. public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelStyleAttr attr) { ClearErrorState(); try { // ToDo OpenXML SetRangeAttr. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } private bool SetRangeAttr(Range oRange, SaMsExcelStyleAttr attr) { ClearErrorState(); try { // ToDo OpenXML SetRangeAttr. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- // I m a g e s //------------------------------------------------------------------- // Add image to sheet. public override bool InsertImage(SaMsExcelImage_Config imageConfig) { ClearErrorState(); if (worksheet == null) return false; try { // ToDo OpenXML InsertImage. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- public override bool FreezePanes(uint colPos, uint rowPos) { ClearErrorState(); try { // ToDo OpenXML FreezePanes. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- public override bool AutoFitRows(SaMsExcelRange range) { ClearErrorState(); try { // ToDo OpenXML AutoFit. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- public override bool SelectRange(SaMsExcelRange range) { ClearErrorState(); try { // ToDo OpenXML SelectRange. } catch (Exception exc) { HandleException(SysUtil.Fn, exc); } return OK; } //------------------------------------------------------------------- } //======================================================================= }